blob: 831bccc90a131f7952db0837cb808b8dd4c37a7e [file] [log] [blame]
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001/*
2 * Copyright (C) 2014 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 "prepare_for_register_allocation.h"
18
David Sehr9e734c72018-01-04 17:56:19 -080019#include "dex/dex_file_types.h"
Vladimir Markoa3ad0cd2018-05-04 10:06:38 +010020#include "jni/jni_internal.h"
Igor Murashkin6ef45672017-08-08 13:59:55 -070021#include "optimizing_compiler_stats.h"
Nicolas Geoffray5d37c152017-01-12 13:25:19 +000022#include "well_known_classes.h"
23
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +010024namespace art {
25
26void PrepareForRegisterAllocation::Run() {
27 // Order does not matter.
Vladimir Marko2c45bc92016-10-25 16:54:12 +010028 for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +010029 // No need to visit the phis.
Andreas Gampe277ccbd2014-11-03 21:36:10 -080030 for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
31 inst_it.Advance()) {
32 inst_it.Current()->Accept(this);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +010033 }
34 }
35}
36
Vladimir Marko175e7862018-03-27 09:03:13 +000037void PrepareForRegisterAllocation::VisitCheckCast(HCheckCast* check_cast) {
38 // Record only those bitstring type checks that make it to the codegen stage.
39 if (check_cast->GetTypeCheckKind() == TypeCheckKind::kBitstringCheck) {
40 MaybeRecordStat(stats_, MethodCompilationStat::kBitstringTypeCheck);
41 }
42}
43
44void PrepareForRegisterAllocation::VisitInstanceOf(HInstanceOf* instance_of) {
45 // Record only those bitstring type checks that make it to the codegen stage.
46 if (instance_of->GetTypeCheckKind() == TypeCheckKind::kBitstringCheck) {
47 MaybeRecordStat(stats_, MethodCompilationStat::kBitstringTypeCheck);
48 }
49}
50
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +010051void PrepareForRegisterAllocation::VisitNullCheck(HNullCheck* check) {
52 check->ReplaceWith(check->InputAt(0));
53}
54
Calin Juravled0d48522014-11-04 16:40:20 +000055void PrepareForRegisterAllocation::VisitDivZeroCheck(HDivZeroCheck* check) {
56 check->ReplaceWith(check->InputAt(0));
57}
58
Nicolas Geoffray6f8e2c92017-03-23 14:37:26 +000059void PrepareForRegisterAllocation::VisitDeoptimize(HDeoptimize* deoptimize) {
60 if (deoptimize->GuardsAnInput()) {
61 // Replace the uses with the actual guarded instruction.
62 deoptimize->ReplaceWith(deoptimize->GuardedInput());
63 deoptimize->RemoveGuard();
64 }
65}
66
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +010067void PrepareForRegisterAllocation::VisitBoundsCheck(HBoundsCheck* check) {
68 check->ReplaceWith(check->InputAt(0));
Vladimir Marko87f3fcb2016-04-28 15:52:11 +010069 if (check->IsStringCharAt()) {
Vladimir Marko92f7f3c2017-10-31 11:38:30 +000070 // Add a fake environment for String.charAt() inline info as we want the exception
71 // to appear as being thrown from there. Skip if we're compiling String.charAt() itself.
Nicolas Geoffray5d37c152017-01-12 13:25:19 +000072 ArtMethod* char_at_method = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt);
Vladimir Marko92f7f3c2017-10-31 11:38:30 +000073 if (GetGraph()->GetArtMethod() != char_at_method) {
74 ArenaAllocator* allocator = GetGraph()->GetAllocator();
75 HEnvironment* environment = new (allocator) HEnvironment(allocator,
76 /* number_of_vregs */ 0u,
77 char_at_method,
78 /* dex_pc */ dex::kDexNoIndex,
79 check);
80 check->InsertRawEnvironment(environment);
81 }
Vladimir Marko87f3fcb2016-04-28 15:52:11 +010082 }
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +010083}
84
Calin Juravleb1498f62015-02-16 13:13:29 +000085void PrepareForRegisterAllocation::VisitBoundType(HBoundType* bound_type) {
86 bound_type->ReplaceWith(bound_type->InputAt(0));
87 bound_type->GetBlock()->RemoveInstruction(bound_type);
88}
89
Roland Levillainb133ec62016-03-23 12:40:35 +000090void PrepareForRegisterAllocation::VisitArraySet(HArraySet* instruction) {
91 HInstruction* value = instruction->GetValue();
92 // PrepareForRegisterAllocation::VisitBoundType may have replaced a
93 // BoundType (as value input of this ArraySet) with a NullConstant.
94 // If so, this ArraySet no longer needs a type check.
95 if (value->IsNullConstant()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010096 DCHECK_EQ(value->GetType(), DataType::Type::kReference);
Roland Levillainb133ec62016-03-23 12:40:35 +000097 if (instruction->NeedsTypeCheck()) {
98 instruction->ClearNeedsTypeCheck();
99 }
100 }
101}
102
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100103void PrepareForRegisterAllocation::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray729645a2015-11-19 13:29:02 +0000104 // Try to find a static invoke or a new-instance from which this check originated.
105 HInstruction* implicit_clinit = nullptr;
Vladimir Marko46817b82016-03-29 12:21:58 +0100106 for (const HUseListNode<HInstruction*>& use : check->GetUses()) {
107 HInstruction* user = use.GetUser();
Nicolas Geoffray729645a2015-11-19 13:29:02 +0000108 if ((user->IsInvokeStaticOrDirect() || user->IsNewInstance()) &&
109 CanMoveClinitCheck(check, user)) {
110 implicit_clinit = user;
111 if (user->IsInvokeStaticOrDirect()) {
112 DCHECK(user->AsInvokeStaticOrDirect()->IsStaticWithExplicitClinitCheck());
113 user->AsInvokeStaticOrDirect()->RemoveExplicitClinitCheck(
114 HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit);
115 } else {
116 DCHECK(user->IsNewInstance());
117 // We delegate the initialization duty to the allocation.
118 if (user->AsNewInstance()->GetEntrypoint() == kQuickAllocObjectInitialized) {
119 user->AsNewInstance()->SetEntrypoint(kQuickAllocObjectResolved);
120 }
121 }
Vladimir Markofbb184a2015-11-13 14:47:00 +0000122 break;
123 }
124 }
Nicolas Geoffray729645a2015-11-19 13:29:02 +0000125 // If we found a static invoke or new-instance for merging, remove the check
126 // from dominated static invokes.
127 if (implicit_clinit != nullptr) {
Vladimir Marko46817b82016-03-29 12:21:58 +0100128 const HUseList<HInstruction*>& uses = check->GetUses();
129 for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
130 HInstruction* user = it->GetUser();
Nicolas Geoffray729645a2015-11-19 13:29:02 +0000131 // All other uses must be dominated.
132 DCHECK(implicit_clinit->StrictlyDominates(user) || (implicit_clinit == user));
Vladimir Marko46817b82016-03-29 12:21:58 +0100133 ++it; // Advance before we remove the node, reference to the next node is preserved.
Vladimir Markofbb184a2015-11-13 14:47:00 +0000134 if (user->IsInvokeStaticOrDirect()) {
135 user->AsInvokeStaticOrDirect()->RemoveExplicitClinitCheck(
136 HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
137 }
138 }
139 }
140
141 HLoadClass* load_class = check->GetLoadClass();
142 bool can_merge_with_load_class = CanMoveClinitCheck(load_class, check);
143
144 check->ReplaceWith(load_class);
145
Nicolas Geoffray729645a2015-11-19 13:29:02 +0000146 if (implicit_clinit != nullptr) {
147 // Remove the check from the graph. It has been merged into the invoke or new-instance.
Vladimir Markofbb184a2015-11-13 14:47:00 +0000148 check->GetBlock()->RemoveInstruction(check);
149 // Check if we can merge the load class as well.
150 if (can_merge_with_load_class && !load_class->HasUses()) {
151 load_class->GetBlock()->RemoveInstruction(load_class);
152 }
Nicolas Geoffray0580d962016-01-06 17:40:20 +0000153 } else if (can_merge_with_load_class && !load_class->NeedsAccessCheck()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000154 // Pass the initialization duty to the `HLoadClass` instruction,
155 // and remove the instruction from the graph.
Mathieu Chartier1ceb37c2016-08-30 10:23:01 -0700156 DCHECK(load_class->HasEnvironment());
Vladimir Markofbb184a2015-11-13 14:47:00 +0000157 load_class->SetMustGenerateClinitCheck(true);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000158 check->GetBlock()->RemoveInstruction(check);
159 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100160}
161
David Brazdilb3e773e2016-01-26 11:28:37 +0000162bool PrepareForRegisterAllocation::CanEmitConditionAt(HCondition* condition,
163 HInstruction* user) const {
164 if (condition->GetNext() != user) {
165 return false;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100166 }
David Brazdilb3e773e2016-01-26 11:28:37 +0000167
168 if (user->IsIf() || user->IsDeoptimize()) {
169 return true;
170 }
171
David Brazdil74eb1b22015-12-14 11:44:01 +0000172 if (user->IsSelect() && user->AsSelect()->GetCondition() == condition) {
Mark Mendell0c5b18e2016-02-06 13:58:35 -0500173 return true;
David Brazdil74eb1b22015-12-14 11:44:01 +0000174 }
175
David Brazdilb3e773e2016-01-26 11:28:37 +0000176 return false;
177}
178
179void PrepareForRegisterAllocation::VisitCondition(HCondition* condition) {
180 if (condition->HasOnlyOneNonEnvironmentUse()) {
Vladimir Marko46817b82016-03-29 12:21:58 +0100181 HInstruction* user = condition->GetUses().front().GetUser();
David Brazdilb3e773e2016-01-26 11:28:37 +0000182 if (CanEmitConditionAt(condition, user)) {
183 condition->MarkEmittedAtUseSite();
184 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100185 }
186}
187
Igor Murashkind01745e2017-04-05 16:40:31 -0700188void PrepareForRegisterAllocation::VisitConstructorFence(HConstructorFence* constructor_fence) {
Igor Murashkin79d8fa72017-04-18 09:37:23 -0700189 // Trivially remove redundant HConstructorFence when it immediately follows an HNewInstance
190 // to an uninitialized class. In this special case, the art_quick_alloc_object_resolved
191 // will already have the 'dmb' which is strictly stronger than an HConstructorFence.
192 //
193 // The instruction builder always emits "x = HNewInstance; HConstructorFence(x)" so this
194 // is effectively pattern-matching that particular case and undoing the redundancy the builder
195 // had introduced.
196 //
197 // TODO: Move this to a separate pass.
198 HInstruction* allocation_inst = constructor_fence->GetAssociatedAllocation();
199 if (allocation_inst != nullptr && allocation_inst->IsNewInstance()) {
200 HNewInstance* new_inst = allocation_inst->AsNewInstance();
201 // This relies on the entrypoint already being set to the more optimized version;
202 // as that happens in this pass, this redundancy removal also cannot happen any earlier.
203 if (new_inst != nullptr && new_inst->GetEntrypoint() == kQuickAllocObjectResolved) {
204 // If this was done in an earlier pass, we would want to match that `previous` was an input
205 // to the `constructor_fence`. However, since this pass removes the inputs to the fence,
206 // we can ignore the inputs and just remove the instruction from its block.
207 DCHECK_EQ(1u, constructor_fence->InputCount());
208 // TODO: GetAssociatedAllocation should not care about multiple inputs
209 // if we are in prepare_for_register_allocation pass only.
210 constructor_fence->GetBlock()->RemoveInstruction(constructor_fence);
Igor Murashkin6ef45672017-08-08 13:59:55 -0700211 MaybeRecordStat(stats_,
212 MethodCompilationStat::kConstructorFenceRemovedPFRA);
Igor Murashkin79d8fa72017-04-18 09:37:23 -0700213 return;
Igor Murashkin79d8fa72017-04-18 09:37:23 -0700214 }
215
216 // HNewArray does not need this check because the art_quick_alloc_array does not itself
217 // have a dmb in any normal situation (i.e. the array class is never exactly in the
218 // "resolved" state). If the array class is not yet loaded, it will always go from
219 // Unloaded->Initialized state.
220 }
221
222 // Remove all the inputs to the constructor fence;
Igor Murashkind01745e2017-04-05 16:40:31 -0700223 // they aren't used by the InstructionCodeGenerator and this lets us avoid creating a
224 // LocationSummary in the LocationsBuilder.
225 constructor_fence->RemoveAllInputs();
226}
227
Roland Levillain4c0eb422015-04-24 16:43:49 +0100228void PrepareForRegisterAllocation::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
229 if (invoke->IsStaticWithExplicitClinitCheck()) {
Nicolas Geoffraye8298312017-08-03 09:51:25 +0100230 HInstruction* last_input = invoke->GetInputs().back();
231 DCHECK(last_input->IsLoadClass())
Calin Juravle0ba218d2015-05-19 18:46:01 +0100232 << "Last input is not HLoadClass. It is " << last_input->DebugName();
233
Vladimir Markofbb184a2015-11-13 14:47:00 +0000234 // Detach the explicit class initialization check from the invoke.
235 // Keeping track of the initializing instruction is no longer required
236 // at this stage (i.e., after inlining has been performed).
237 invoke->RemoveExplicitClinitCheck(HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
Roland Levillain4c0eb422015-04-24 16:43:49 +0100238
Vladimir Markofbb184a2015-11-13 14:47:00 +0000239 // Merging with load class should have happened in VisitClinitCheck().
240 DCHECK(!CanMoveClinitCheck(last_input, invoke));
241 }
242}
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +0100243
David Brazdilb3e773e2016-01-26 11:28:37 +0000244bool PrepareForRegisterAllocation::CanMoveClinitCheck(HInstruction* input,
245 HInstruction* user) const {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000246 // Determine if input and user come from the same dex instruction, so that we can move
247 // the clinit check responsibility from one to the other, i.e. from HClinitCheck (user)
Vladimir Markoc7591b42016-06-29 14:59:07 +0100248 // to HLoadClass (input), or from HClinitCheck (input) to HInvokeStaticOrDirect (user),
249 // or from HLoadClass (input) to HNewInstance (user).
Vladimir Markofbb184a2015-11-13 14:47:00 +0000250
251 // Start with a quick dex pc check.
252 if (user->GetDexPc() != input->GetDexPc()) {
253 return false;
254 }
255
256 // Now do a thorough environment check that this is really coming from the same instruction in
257 // the same inlined graph. Unfortunately, we have to go through the whole environment chain.
258 HEnvironment* user_environment = user->GetEnvironment();
259 HEnvironment* input_environment = input->GetEnvironment();
260 while (user_environment != nullptr || input_environment != nullptr) {
261 if (user_environment == nullptr || input_environment == nullptr) {
262 // Different environment chain length. This happens when a method is called
263 // once directly and once indirectly through another inlined method.
264 return false;
265 }
266 if (user_environment->GetDexPc() != input_environment->GetDexPc() ||
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000267 user_environment->GetMethod() != input_environment->GetMethod()) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000268 return false;
269 }
270 user_environment = user_environment->GetParent();
271 input_environment = input_environment->GetParent();
272 }
273
274 // Check for code motion taking the input to a different block.
275 if (user->GetBlock() != input->GetBlock()) {
276 return false;
277 }
278
279 // In debug mode, check that we have not inserted a throwing instruction
280 // or an instruction with side effects between input and user.
281 if (kIsDebugBuild) {
282 for (HInstruction* between = input->GetNext(); between != user; between = between->GetNext()) {
283 CHECK(between != nullptr); // User must be after input in the same block.
284 CHECK(!between->CanThrow());
285 CHECK(!between->HasSideEffects());
Roland Levillain4c0eb422015-04-24 16:43:49 +0100286 }
287 }
Vladimir Markofbb184a2015-11-13 14:47:00 +0000288 return true;
Roland Levillain4c0eb422015-04-24 16:43:49 +0100289}
290
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +0100291} // namespace art