blob: 45b3df008b005caaea50f925bbe7900a428bf94d [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 Juravle2e768302015-07-28 14:41:11 +000028 RTPVisitor(HGraph* graph,
29 StackHandleScopeCollection* handles,
30 GrowableArray<HInstruction*>* worklist,
31 ReferenceTypeInfo::TypeHandle object_class_handle,
32 ReferenceTypeInfo::TypeHandle class_class_handle,
David Brazdilbbd733e2015-08-18 17:48:17 +010033 ReferenceTypeInfo::TypeHandle string_class_handle,
34 ReferenceTypeInfo::TypeHandle throwable_class_handle)
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010035 : HGraphDelegateVisitor(graph),
Calin Juravle2e768302015-07-28 14:41:11 +000036 handles_(handles),
37 object_class_handle_(object_class_handle),
38 class_class_handle_(class_class_handle),
39 string_class_handle_(string_class_handle),
David Brazdilbbd733e2015-08-18 17:48:17 +010040 throwable_class_handle_(throwable_class_handle),
Calin Juravle2e768302015-07-28 14:41:11 +000041 worklist_(worklist) {}
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010042
Calin Juravle2e768302015-07-28 14:41:11 +000043 void VisitNullConstant(HNullConstant* null_constant) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010044 void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
45 void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000046 void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
47 void VisitLoadString(HLoadString* instr) OVERRIDE;
David Brazdilbbd733e2015-08-18 17:48:17 +010048 void VisitLoadException(HLoadException* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010049 void VisitNewArray(HNewArray* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000050 void VisitParameterValue(HParameterValue* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010051 void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
52 void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact);
53 void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
54 void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
55 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010056 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Calin Juravlea5ae3c32015-07-28 14:40:50 +000057 void VisitCheckCast(HCheckCast* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000058 void VisitNullCheck(HNullCheck* instr) OVERRIDE;
59 void VisitFakeString(HFakeString* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010060 void UpdateReferenceTypeInfo(HInstruction* instr,
61 uint16_t type_idx,
62 const DexFile& dex_file,
63 bool is_exact);
64
65 private:
66 StackHandleScopeCollection* handles_;
Calin Juravle2e768302015-07-28 14:41:11 +000067 ReferenceTypeInfo::TypeHandle object_class_handle_;
68 ReferenceTypeInfo::TypeHandle class_class_handle_;
69 ReferenceTypeInfo::TypeHandle string_class_handle_;
David Brazdilbbd733e2015-08-18 17:48:17 +010070 ReferenceTypeInfo::TypeHandle throwable_class_handle_;
Calin Juravle2e768302015-07-28 14:41:11 +000071 GrowableArray<HInstruction*>* worklist_;
72
73 static constexpr size_t kDefaultWorklistSize = 8;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010074};
75
Calin Juravle2e768302015-07-28 14:41:11 +000076ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
77 StackHandleScopeCollection* handles,
78 const char* name)
79 : HOptimization(graph, name),
80 handles_(handles),
81 worklist_(graph->GetArena(), kDefaultWorklistSize) {
82 ClassLinker* linker = Runtime::Current()->GetClassLinker();
83 object_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject));
84 string_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangString));
85 class_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangClass));
David Brazdilbbd733e2015-08-18 17:48:17 +010086 throwable_class_handle_ =
87 handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangThrowable));
Calin Juravle2e768302015-07-28 14:41:11 +000088
89 if (kIsDebugBuild) {
90 ScopedObjectAccess soa(Thread::Current());
91 DCHECK(ReferenceTypeInfo::IsValidHandle(object_class_handle_));
92 DCHECK(ReferenceTypeInfo::IsValidHandle(class_class_handle_));
93 DCHECK(ReferenceTypeInfo::IsValidHandle(string_class_handle_));
David Brazdilbbd733e2015-08-18 17:48:17 +010094 DCHECK(ReferenceTypeInfo::IsValidHandle(throwable_class_handle_));
Calin Juravle2e768302015-07-28 14:41:11 +000095 }
96}
97
Calin Juravleacf735c2015-02-12 15:25:22 +000098void ReferenceTypePropagation::Run() {
99 // To properly propagate type info we need to visit in the dominator-based order.
Calin Juravle10e244f2015-01-26 18:54:32 +0000100 // Reverse post order guarantees a node's dominators are visited first.
101 // We take advantage of this order in `VisitBasicBlock`.
Calin Juravle6c0c4f22015-06-12 15:40:42 +0000102 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000103 VisitBasicBlock(it.Current());
104 }
105 ProcessWorklist();
Calin Juravle2e768302015-07-28 14:41:11 +0000106
107 if (kIsDebugBuild) {
108 // TODO: move this to the graph checker.
109 ScopedObjectAccess soa(Thread::Current());
110 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
111 HBasicBlock* block = it.Current();
112 for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
113 HInstruction* instr = iti.Current();
114 if (instr->GetType() == Primitive::kPrimNot) {
115 DCHECK(instr->GetReferenceTypeInfo().IsValid())
116 << "Invalid RTI for instruction: " << instr->DebugName();
117 if (instr->IsBoundType()) {
118 DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
119 } else if (instr->IsLoadClass()) {
120 DCHECK(instr->AsLoadClass()->GetReferenceTypeInfo().IsExact());
121 DCHECK(instr->AsLoadClass()->GetLoadedClassRTI().IsValid());
122 } else if (instr->IsNullCheck()) {
123 DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
124 << "NullCheck " << instr->GetReferenceTypeInfo()
125 << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo();
126 }
127 }
128 }
129 }
130 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000131}
132
Calin Juravleb1498f62015-02-16 13:13:29 +0000133void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Calin Juravle2e768302015-07-28 14:41:11 +0000134 RTPVisitor visitor(graph_,
135 handles_,
136 &worklist_,
137 object_class_handle_,
138 class_class_handle_,
David Brazdilbbd733e2015-08-18 17:48:17 +0100139 string_class_handle_,
140 throwable_class_handle_);
Calin Juravle2e768302015-07-28 14:41:11 +0000141 // Handle Phis first as there might be instructions in the same block who depend on them.
142 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
143 VisitPhi(it.Current()->AsPhi());
144 }
Calin Juravlebeba9302015-07-08 15:57:18 +0000145
Calin Juravle2e768302015-07-28 14:41:11 +0000146 // Handle instructions.
Calin Juravleb1498f62015-02-16 13:13:29 +0000147 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
148 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100149 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +0000150 }
151
Calin Juravleb1498f62015-02-16 13:13:29 +0000152 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +0000153 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +0000154 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +0000155}
156
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000157// Create a bound type for the given object narrowing the type as much as possible.
158// The BoundType upper values for the super type and can_be_null will be taken from
159// load_class.GetLoadedClassRTI() and upper_can_be_null.
160static HBoundType* CreateBoundType(ArenaAllocator* arena,
161 HInstruction* obj,
162 HLoadClass* load_class,
163 bool upper_can_be_null)
164 SHARED_REQUIRES(Locks::mutator_lock_) {
165 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
166 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
167 HBoundType* bound_type = new (arena) HBoundType(obj, class_rti, upper_can_be_null);
168 // Narrow the type as much as possible.
Calin Juravle2e768302015-07-28 14:41:11 +0000169 if (class_rti.GetTypeHandle()->IsFinal()) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000170 bound_type->SetReferenceTypeInfo(
171 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000172 } else if (obj_rti.IsValid() && class_rti.IsSupertypeOf(obj_rti)) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000173 bound_type->SetReferenceTypeInfo(obj_rti);
174 } else {
175 bound_type->SetReferenceTypeInfo(
176 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
177 }
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700178 if (upper_can_be_null) {
179 bound_type->SetCanBeNull(obj->CanBeNull());
180 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000181 return bound_type;
182}
183
184// Check if we should create a bound type for the given object at the specified
185// position. Because of inlining and the fact we run RTP more than once and we
186// might have a HBoundType already. If we do, we should not create a new one.
187// In this case we also assert that there are no other uses of the object (except
188// the bound type) dominated by the specified dominator_instr or dominator_block.
189static bool ShouldCreateBoundType(HInstruction* position,
190 HInstruction* obj,
191 ReferenceTypeInfo upper_bound,
192 HInstruction* dominator_instr,
193 HBasicBlock* dominator_block)
194 SHARED_REQUIRES(Locks::mutator_lock_) {
195 // If the position where we should insert the bound type is not already a
196 // a bound type then we need to create one.
197 if (position == nullptr || !position->IsBoundType()) {
198 return true;
199 }
200
201 HBoundType* existing_bound_type = position->AsBoundType();
202 if (existing_bound_type->GetUpperBound().IsSupertypeOf(upper_bound)) {
203 if (kIsDebugBuild) {
204 // Check that the existing HBoundType dominates all the uses.
205 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
206 HInstruction* user = it.Current()->GetUser();
207 if (dominator_instr != nullptr) {
208 DCHECK(!dominator_instr->StrictlyDominates(user)
209 || user == existing_bound_type
210 || existing_bound_type->StrictlyDominates(user));
211 } else if (dominator_block != nullptr) {
212 DCHECK(!dominator_block->Dominates(user->GetBlock())
213 || user == existing_bound_type
214 || existing_bound_type->StrictlyDominates(user));
215 }
216 }
217 }
218 } else {
219 // TODO: if the current bound type is a refinement we could update the
220 // existing_bound_type with the a new upper limit. However, we also need to
221 // update its users and have access to the work list.
222 }
223 return false;
224}
225
Calin Juravle61d544b2015-02-23 16:46:57 +0000226void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100227 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
228 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000229 return;
230 }
Calin Juravleb3306642015-04-20 18:30:42 +0100231 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +0000232 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
233 return;
234 }
235 HInstruction* input0 = ifInput->InputAt(0);
236 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +0100237 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000238
Calin Juravleedad8ad2015-04-23 14:34:33 +0100239 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000240 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +0100241 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000242 obj = input1;
243 } else {
244 return;
245 }
246
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100247 if (!obj->CanBeNull() || obj->IsNullConstant()) {
248 // Null check is dead code and will be removed by DCE.
249 return;
250 }
251 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
252
Calin Juravleb3306642015-04-20 18:30:42 +0100253 // We only need to bound the type if we have uses in the relevant block.
254 // So start with null and create the HBoundType lazily, only if it's needed.
255 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000256 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +0100257 ? ifInstruction->IfTrueSuccessor()
258 : ifInstruction->IfFalseSuccessor();
259
Calin Juravle61d544b2015-02-23 16:46:57 +0000260 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
261 HInstruction* user = it.Current()->GetUser();
262 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100263 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000264 ScopedObjectAccess soa(Thread::Current());
265 HInstruction* insert_point = notNullBlock->GetFirstInstruction();
Calin Juravle2e768302015-07-28 14:41:11 +0000266 ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
267 object_class_handle_, /* is_exact */ true);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000268 if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
269 bound_type = new (graph_->GetArena()) HBoundType(
270 obj, object_rti, /* bound_can_be_null */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000271 if (obj->GetReferenceTypeInfo().IsValid()) {
272 bound_type->SetReferenceTypeInfo(obj->GetReferenceTypeInfo());
273 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000274 notNullBlock->InsertInstructionBefore(bound_type, insert_point);
275 } else {
276 // We already have a bound type on the position we would need to insert
277 // the new one. The existing bound type should dominate all the users
278 // (dchecked) so there's no need to continue.
279 break;
280 }
Calin Juravleb3306642015-04-20 18:30:42 +0100281 }
Calin Juravle61d544b2015-02-23 16:46:57 +0000282 user->ReplaceInput(bound_type, it.Current()->GetIndex());
283 }
284 }
285}
286
Calin Juravleb1498f62015-02-16 13:13:29 +0000287// Detects if `block` is the True block for the pattern
288// `if (x instanceof ClassX) { }`
289// If that's the case insert an HBoundType instruction to bound the type of `x`
290// to `ClassX` in the scope of the dominated blocks.
291void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100292 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
293 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000294 return;
295 }
Calin Juravleb3306642015-04-20 18:30:42 +0100296 HInstruction* ifInput = ifInstruction->InputAt(0);
297 HInstruction* instanceOf = nullptr;
298 HBasicBlock* instanceOfTrueBlock = nullptr;
David Brazdil0d13fee2015-04-17 14:52:19 +0100299
Calin Juravleb3306642015-04-20 18:30:42 +0100300 // The instruction simplifier has transformed:
301 // - `if (a instanceof A)` into an HIf with an HInstanceOf input
302 // - `if (!(a instanceof A)` into an HIf with an HBooleanNot input (which in turn
303 // has an HInstanceOf input)
304 // So we should not see the usual HEqual here.
David Brazdil0d13fee2015-04-17 14:52:19 +0100305 if (ifInput->IsInstanceOf()) {
306 instanceOf = ifInput;
Calin Juravleb3306642015-04-20 18:30:42 +0100307 instanceOfTrueBlock = ifInstruction->IfTrueSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100308 } else if (ifInput->IsBooleanNot() && ifInput->InputAt(0)->IsInstanceOf()) {
309 instanceOf = ifInput->InputAt(0);
Calin Juravleb3306642015-04-20 18:30:42 +0100310 instanceOfTrueBlock = ifInstruction->IfFalseSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100311 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000312 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000313 }
314
Calin Juravleb3306642015-04-20 18:30:42 +0100315 // We only need to bound the type if we have uses in the relevant block.
316 // So start with null and create the HBoundType lazily, only if it's needed.
317 HBoundType* bound_type = nullptr;
318
Calin Juravleb1498f62015-02-16 13:13:29 +0000319 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100320 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
321 // This method is being called while doing a fixed-point calculation
322 // over phis. Non-phis instruction whose type is already known do
323 // not need to be bound to another type.
324 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
325 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
326 // input.
327 return;
328 }
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100329 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
Calin Juravleb1498f62015-02-16 13:13:29 +0000330 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
331 HInstruction* user = it.Current()->GetUser();
332 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100333 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000334 ScopedObjectAccess soa(Thread::Current());
Calin Juravleb3306642015-04-20 18:30:42 +0100335 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
Calin Juravleb3306642015-04-20 18:30:42 +0100336 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000337 HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
338 if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
339 bound_type = CreateBoundType(
340 graph_->GetArena(),
341 obj,
342 load_class,
343 false /* InstanceOf ensures the object is not null. */);
344 instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point);
345 } else {
346 // We already have a bound type on the position we would need to insert
347 // the new one. The existing bound type should dominate all the users
348 // (dchecked) so there's no need to continue.
349 break;
Calin Juravleb3306642015-04-20 18:30:42 +0100350 }
Calin Juravleb3306642015-04-20 18:30:42 +0100351 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000352 user->ReplaceInput(bound_type, it.Current()->GetIndex());
353 }
354 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000355}
356
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100357void RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
358 mirror::Class* klass,
359 bool is_exact) {
Calin Juravle2e768302015-07-28 14:41:11 +0000360 if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
361 // Calls to String.<init> are replaced with a StringFactory.
362 if (kIsDebugBuild) {
363 ScopedObjectAccess soa(Thread::Current());
364 ClassLinker* cl = Runtime::Current()->GetClassLinker();
365 mirror::DexCache* dex_cache = cl->FindDexCache(instr->AsInvoke()->GetDexFile());
366 ArtMethod* method = dex_cache->GetResolvedMethod(
367 instr->AsInvoke()->GetDexMethodIndex(), cl->GetImagePointerSize());
368 DCHECK(method != nullptr);
369 mirror::Class* declaring_class = method->GetDeclaringClass();
370 DCHECK(declaring_class != nullptr);
371 DCHECK(declaring_class->IsStringClass())
372 << "Expected String class: " << PrettyDescriptor(declaring_class);
373 DCHECK(method->IsConstructor())
374 << "Expected String.<init>: " << PrettyMethod(method);
375 }
376 instr->SetReferenceTypeInfo(
377 ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
378 } else if (klass != nullptr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100379 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000380 ReferenceTypeInfo::TypeHandle handle = handles_->NewHandle(klass);
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100381 is_exact = is_exact || klass->IsFinal();
382 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000383 } else {
384 instr->SetReferenceTypeInfo(
385 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100386 }
387}
388
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100389void RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
390 uint16_t type_idx,
391 const DexFile& dex_file,
392 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100393 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
394
Calin Juravleacf735c2015-02-12 15:25:22 +0000395 ScopedObjectAccess soa(Thread::Current());
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100396 mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
Calin Juravleacf735c2015-02-12 15:25:22 +0000397 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100398 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000399}
400
Calin Juravle2e768302015-07-28 14:41:11 +0000401void RTPVisitor::VisitNullConstant(HNullConstant* instr) {
402 // TODO: The null constant could be bound contextually (e.g. based on return statements)
403 // to a more precise type.
404 instr->SetReferenceTypeInfo(
405 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
406}
407
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100408void RTPVisitor::VisitNewInstance(HNewInstance* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100409 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100410}
411
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100412void RTPVisitor::VisitNewArray(HNewArray* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100413 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100414}
415
Calin Juravle2e768302015-07-28 14:41:11 +0000416void RTPVisitor::VisitParameterValue(HParameterValue* instr) {
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700417 ScopedObjectAccess soa(Thread::Current());
418 // We check if the existing type is valid: the inliner may have set it.
419 if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
Calin Juravle2e768302015-07-28 14:41:11 +0000420 // TODO: parse the signature and add precise types for the parameters.
421 SetClassAsTypeInfo(instr, nullptr, /* is_exact */ false);
422 }
423}
424
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100425void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
426 const FieldInfo& info) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100427 // The field index is unknown only during tests.
428 if (instr->GetType() != Primitive::kPrimNot || info.GetFieldIndex() == kUnknownFieldIndex) {
429 return;
430 }
431
432 ScopedObjectAccess soa(Thread::Current());
433 ClassLinker* cl = Runtime::Current()->GetClassLinker();
434 mirror::DexCache* dex_cache = cl->FindDexCache(info.GetDexFile());
435 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), dex_cache);
Calin Juravle2e768302015-07-28 14:41:11 +0000436 // TODO: There are certain cases where we can't resolve the field.
437 // b/21914925 is open to keep track of a repro case for this issue.
438 mirror::Class* klass = (field == nullptr) ? nullptr : field->GetType<false>();
439 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100440}
441
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100442void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100443 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
444}
445
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100446void RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100447 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
448}
449
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100450void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000451 ScopedObjectAccess soa(Thread::Current());
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100452 mirror::DexCache* dex_cache =
453 Runtime::Current()->GetClassLinker()->FindDexCache(instr->GetDexFile());
Calin Juravleacf735c2015-02-12 15:25:22 +0000454 // Get type from dex cache assuming it was populated by the verifier.
455 mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
Calin Juravle51d135f2015-07-29 19:25:24 +0100456 // TODO: investigating why we are still getting unresolved classes: b/22821472.
457 ReferenceTypeInfo::TypeHandle handle = (resolved_class != nullptr)
458 ? handles_->NewHandle(resolved_class)
459 : object_class_handle_;
Calin Juravle2e768302015-07-28 14:41:11 +0000460 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(handle, /* is_exact */ true));
461 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_class_handle_, /* is_exact */ true));
462}
463
464void RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
465 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
466}
467
468void RTPVisitor::VisitLoadString(HLoadString* instr) {
469 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
470}
471
David Brazdilbbd733e2015-08-18 17:48:17 +0100472void RTPVisitor::VisitLoadException(HLoadException* instr) {
473 DCHECK(instr->GetBlock()->IsCatchBlock());
474 TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
475
476 if (catch_info->IsCatchAllTypeIndex()) {
477 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(throwable_class_handle_,
478 /* is_exact */ false));
479 } else {
480 UpdateReferenceTypeInfo(instr,
481 catch_info->GetCatchTypeIndex(),
482 catch_info->GetCatchDexFile(),
483 /* is_exact */ false);
484 }
485}
486
Calin Juravle2e768302015-07-28 14:41:11 +0000487void RTPVisitor::VisitNullCheck(HNullCheck* instr) {
488 ScopedObjectAccess soa(Thread::Current());
489 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
490 DCHECK(parent_rti.IsValid());
491 instr->SetReferenceTypeInfo(parent_rti);
492}
493
494void RTPVisitor::VisitFakeString(HFakeString* instr) {
495 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000496}
Calin Juravle10e244f2015-01-26 18:54:32 +0000497
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000498void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
499 HInstruction* obj = check_cast->InputAt(0);
500 HBoundType* bound_type = nullptr;
501 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
502 HInstruction* user = it.Current()->GetUser();
503 if (check_cast->StrictlyDominates(user)) {
504 if (bound_type == nullptr) {
505 ScopedObjectAccess soa(Thread::Current());
506 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
507 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
508 if (ShouldCreateBoundType(check_cast->GetNext(), obj, class_rti, check_cast, nullptr)) {
509 bound_type = CreateBoundType(
510 GetGraph()->GetArena(),
511 obj,
512 load_class,
513 true /* CheckCast succeeds for nulls. */);
514 check_cast->GetBlock()->InsertInstructionAfter(bound_type, check_cast);
515 } else {
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700516 // Update nullability of the existing bound type, which may not have known
517 // that its input was not null when it was being created.
518 bound_type = check_cast->GetNext()->AsBoundType();
519 bound_type->SetCanBeNull(obj->CanBeNull());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000520 // We already have a bound type on the position we would need to insert
521 // the new one. The existing bound type should dominate all the users
522 // (dchecked) so there's no need to continue.
523 break;
524 }
525 }
526 user->ReplaceInput(bound_type, it.Current()->GetIndex());
527 }
528 }
529}
530
Calin Juravleb1498f62015-02-16 13:13:29 +0000531void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
532 if (phi->GetType() != Primitive::kPrimNot) {
533 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000534 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000535
536 if (phi->GetBlock()->IsLoopHeader()) {
537 // Set the initial type for the phi. Use the non back edge input for reaching
538 // a fixed point faster.
539 AddToWorklist(phi);
540 phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
541 phi->SetReferenceTypeInfo(phi->InputAt(0)->GetReferenceTypeInfo());
Calin Juravle10e244f2015-01-26 18:54:32 +0000542 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000543 // Eagerly compute the type of the phi, for quicker convergence. Note
544 // that we don't need to add users to the worklist because we are
545 // doing a reverse post-order visit, therefore either the phi users are
546 // non-loop phi and will be visited later in the visit, or are loop-phis,
547 // and they are already in the work list.
548 UpdateNullability(phi);
549 UpdateReferenceTypeInfo(phi);
550 }
551}
552
553ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
554 const ReferenceTypeInfo& b) {
Calin Juravle2e768302015-07-28 14:41:11 +0000555 if (!b.IsValid()) {
556 return a;
557 }
558 if (!a.IsValid()) {
559 return b;
Calin Juravle20e60712015-07-01 18:41:04 +0100560 }
561
Calin Juravle2e768302015-07-28 14:41:11 +0000562 bool is_exact = a.IsExact() && b.IsExact();
563 Handle<mirror::Class> type_handle;
564
565 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
566 type_handle = a.GetTypeHandle();
567 } else if (a.IsSupertypeOf(b)) {
568 type_handle = a.GetTypeHandle();
569 is_exact = false;
570 } else if (b.IsSupertypeOf(a)) {
571 type_handle = b.GetTypeHandle();
572 is_exact = false;
573 } else {
574 // TODO: Find the first common super class.
575 type_handle = object_class_handle_;
576 is_exact = false;
577 }
578
579 return ReferenceTypeInfo::Create(type_handle, is_exact);
580}
581
582static void UpdateArrayGet(HArrayGet* instr,
583 StackHandleScopeCollection* handles,
584 ReferenceTypeInfo::TypeHandle object_class_handle)
585 SHARED_REQUIRES(Locks::mutator_lock_) {
586 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
587
588 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
589 DCHECK(parent_rti.IsValid());
590
591 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
592 if (handle->IsObjectArrayClass()) {
593 ReferenceTypeInfo::TypeHandle component_handle = handles->NewHandle(handle->GetComponentType());
594 instr->SetReferenceTypeInfo(
595 ReferenceTypeInfo::Create(component_handle, /* is_exact */ false));
596 } else {
597 // We don't know what the parent actually is, so we fallback to object.
598 instr->SetReferenceTypeInfo(
599 ReferenceTypeInfo::Create(object_class_handle, /* is_exact */ false));
600 }
601
602 return;
Calin Juravleb1498f62015-02-16 13:13:29 +0000603}
604
605bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
606 ScopedObjectAccess soa(Thread::Current());
607
608 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
609 if (instr->IsBoundType()) {
610 UpdateBoundType(instr->AsBoundType());
611 } else if (instr->IsPhi()) {
612 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000613 } else if (instr->IsNullCheck()) {
614 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
615 if (parent_rti.IsValid()) {
616 instr->SetReferenceTypeInfo(parent_rti);
617 }
618 } else if (instr->IsArrayGet()) {
619 // TODO: consider if it's worth "looking back" and bounding the input object
620 // to an array type.
621 UpdateArrayGet(instr->AsArrayGet(), handles_, object_class_handle_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000622 } else {
623 LOG(FATAL) << "Invalid instruction (should not get here)";
624 }
625
626 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
627}
628
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100629void RTPVisitor::VisitInvoke(HInvoke* instr) {
630 if (instr->GetType() != Primitive::kPrimNot) {
631 return;
632 }
633
634 ScopedObjectAccess soa(Thread::Current());
635 ClassLinker* cl = Runtime::Current()->GetClassLinker();
636 mirror::DexCache* dex_cache = cl->FindDexCache(instr->GetDexFile());
637 ArtMethod* method = dex_cache->GetResolvedMethod(
638 instr->GetDexMethodIndex(), cl->GetImagePointerSize());
Calin Juravle2e768302015-07-28 14:41:11 +0000639 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false);
640 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100641}
642
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100643void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
644 if (instr->GetType() != Primitive::kPrimNot) {
645 return;
646 }
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100647 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000648 UpdateArrayGet(instr, handles_, object_class_handle_);
649 if (!instr->GetReferenceTypeInfo().IsValid()) {
650 worklist_->Add(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100651 }
652}
653
Calin Juravleb1498f62015-02-16 13:13:29 +0000654void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
655 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000656 if (!new_rti.IsValid()) {
657 return; // No new info yet.
658 }
659
660 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000661 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
662 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
663 new_rti = upper_bound_rti;
Calin Juravleb1498f62015-02-16 13:13:29 +0000664 }
665 instr->SetReferenceTypeInfo(new_rti);
666}
667
668void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
669 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000670 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
671 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000672 instr->SetReferenceTypeInfo(new_rti);
673 return;
674 }
675 for (size_t i = 1; i < instr->InputCount(); i++) {
676 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000677 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000678 if (!new_rti.IsExact()) {
679 break;
680 } else {
681 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000682 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000683 }
684 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000685 instr->SetReferenceTypeInfo(new_rti);
686}
687
688// Re-computes and updates the nullability of the instruction. Returns whether or
689// not the nullability was changed.
690bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000691 DCHECK(instr->IsPhi()
692 || instr->IsBoundType()
693 || instr->IsNullCheck()
694 || instr->IsArrayGet());
695
696 if (!instr->IsPhi() && !instr->IsBoundType()) {
697 return false;
698 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000699
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000700 bool existing_can_be_null = instr->CanBeNull();
701 if (instr->IsPhi()) {
702 HPhi* phi = instr->AsPhi();
703 bool new_can_be_null = false;
704 for (size_t i = 0; i < phi->InputCount(); i++) {
705 if (phi->InputAt(i)->CanBeNull()) {
706 new_can_be_null = true;
707 break;
708 }
709 }
710 phi->SetCanBeNull(new_can_be_null);
711 } else if (instr->IsBoundType()) {
712 HBoundType* bound_type = instr->AsBoundType();
713 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000714 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000715 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000716}
717
718void ReferenceTypePropagation::ProcessWorklist() {
719 while (!worklist_.IsEmpty()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000720 HInstruction* instruction = worklist_.Pop();
Calin Juravleacf735c2015-02-12 15:25:22 +0000721 if (UpdateNullability(instruction) || UpdateReferenceTypeInfo(instruction)) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000722 AddDependentInstructionsToWorklist(instruction);
723 }
724 }
725}
726
Calin Juravleb1498f62015-02-16 13:13:29 +0000727void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000728 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
729 << instruction->DebugName() << ":" << instruction->GetType();
Calin Juravle10e244f2015-01-26 18:54:32 +0000730 worklist_.Add(instruction);
731}
732
Calin Juravleb1498f62015-02-16 13:13:29 +0000733void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000734 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000735 HInstruction* user = it.Current()->GetUser();
Calin Juravle2e768302015-07-28 14:41:11 +0000736 if (user->IsPhi()
737 || user->IsBoundType()
738 || user->IsNullCheck()
739 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000740 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000741 }
742 }
743}
Calin Juravle10e244f2015-01-26 18:54:32 +0000744} // namespace art