blob: fbcbe3608e6bef1d92d57c806887c73b58bdcb92 [file] [log] [blame]
Roland Levillainccc07a92014-09-16 14:48:16 +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 "graph_checker.h"
18
Vladimir Marko655e5852015-10-12 10:38:28 +010019#include <algorithm>
Calin Juravlea4f88312015-04-16 12:57:19 +010020#include <sstream>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070021#include <string>
Roland Levillainccc07a92014-09-16 14:48:16 +010022
Andreas Gampe46ee31b2016-12-14 10:11:49 -080023#include "android-base/stringprintf.h"
24
Roland Levillain7e53b412014-09-23 10:50:22 +010025#include "base/bit_vector-inl.h"
Vladimir Marko009d1662017-10-10 13:21:15 +010026#include "base/scoped_arena_allocator.h"
27#include "base/scoped_arena_containers.h"
Vladimir Markoeb0ebed2018-01-10 18:26:38 +000028#include "handle.h"
29#include "mirror/class.h"
30#include "obj_ptr-inl.h"
31#include "scoped_thread_state_change-inl.h"
32#include "subtype_check.h"
Roland Levillain7e53b412014-09-23 10:50:22 +010033
Roland Levillainccc07a92014-09-16 14:48:16 +010034namespace art {
35
Andreas Gampe46ee31b2016-12-14 10:11:49 -080036using android::base::StringPrintf;
37
David Brazdil86ea7ee2016-02-16 09:26:07 +000038static bool IsAllowedToJumpToExitBlock(HInstruction* instruction) {
Aart Bika8b8e9b2018-01-09 11:01:02 -080039 // Anything that returns is allowed to jump into the exit block.
40 if (instruction->IsReturn() || instruction->IsReturnVoid()) {
41 return true;
42 }
43 // Anything that always throws is allowed to jump into the exit block.
44 if (instruction->IsGoto() && instruction->GetPrevious() != nullptr) {
45 instruction = instruction->GetPrevious();
46 }
47 return instruction->AlwaysThrows();
David Brazdil86ea7ee2016-02-16 09:26:07 +000048}
49
50static bool IsExitTryBoundaryIntoExitBlock(HBasicBlock* block) {
51 if (!block->IsSingleTryBoundary()) {
52 return false;
53 }
54
55 HTryBoundary* boundary = block->GetLastInstruction()->AsTryBoundary();
56 return block->GetPredecessors().size() == 1u &&
57 boundary->GetNormalFlowSuccessor()->IsExitBlock() &&
58 !boundary->IsEntry();
59}
60
Roland Levillainccc07a92014-09-16 14:48:16 +010061void GraphChecker::VisitBasicBlock(HBasicBlock* block) {
62 current_block_ = block;
63
Vladimir Marko009d1662017-10-10 13:21:15 +010064 // Use local allocator for allocating memory.
65 ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
66
Roland Levillainccc07a92014-09-16 14:48:16 +010067 // Check consistency with respect to predecessors of `block`.
Vladimir Marko0f49c822016-03-22 17:51:29 +000068 // Note: Counting duplicates with a sorted vector uses up to 6x less memory
Vladimir Marko947eb702016-03-25 15:31:35 +000069 // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
Vladimir Marko009d1662017-10-10 13:21:15 +010070 ScopedArenaVector<HBasicBlock*> sorted_predecessors(allocator.Adapter(kArenaAllocGraphChecker));
Vladimir Marko947eb702016-03-25 15:31:35 +000071 sorted_predecessors.assign(block->GetPredecessors().begin(), block->GetPredecessors().end());
Vladimir Marko0f49c822016-03-22 17:51:29 +000072 std::sort(sorted_predecessors.begin(), sorted_predecessors.end());
73 for (auto it = sorted_predecessors.begin(), end = sorted_predecessors.end(); it != end; ) {
74 HBasicBlock* p = *it++;
75 size_t p_count_in_block_predecessors = 1u;
76 for (; it != end && *it == p; ++it) {
77 ++p_count_in_block_predecessors;
Vladimir Marko655e5852015-10-12 10:38:28 +010078 }
Vladimir Marko655e5852015-10-12 10:38:28 +010079 size_t block_count_in_p_successors =
80 std::count(p->GetSuccessors().begin(), p->GetSuccessors().end(), block);
Roland Levillainccc07a92014-09-16 14:48:16 +010081 if (p_count_in_block_predecessors != block_count_in_p_successors) {
Roland Levillain5c4405e2015-01-21 11:39:58 +000082 AddError(StringPrintf(
83 "Block %d lists %zu occurrences of block %d in its predecessors, whereas "
84 "block %d lists %zu occurrences of block %d in its successors.",
85 block->GetBlockId(), p_count_in_block_predecessors, p->GetBlockId(),
86 p->GetBlockId(), block_count_in_p_successors, block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +010087 }
88 }
89
90 // Check consistency with respect to successors of `block`.
Vladimir Marko0f49c822016-03-22 17:51:29 +000091 // Note: Counting duplicates with a sorted vector uses up to 6x less memory
Vladimir Marko947eb702016-03-25 15:31:35 +000092 // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
Vladimir Marko009d1662017-10-10 13:21:15 +010093 ScopedArenaVector<HBasicBlock*> sorted_successors(allocator.Adapter(kArenaAllocGraphChecker));
Vladimir Marko947eb702016-03-25 15:31:35 +000094 sorted_successors.assign(block->GetSuccessors().begin(), block->GetSuccessors().end());
Vladimir Marko0f49c822016-03-22 17:51:29 +000095 std::sort(sorted_successors.begin(), sorted_successors.end());
96 for (auto it = sorted_successors.begin(), end = sorted_successors.end(); it != end; ) {
97 HBasicBlock* s = *it++;
98 size_t s_count_in_block_successors = 1u;
99 for (; it != end && *it == s; ++it) {
100 ++s_count_in_block_successors;
Vladimir Marko655e5852015-10-12 10:38:28 +0100101 }
Vladimir Marko655e5852015-10-12 10:38:28 +0100102 size_t block_count_in_s_predecessors =
103 std::count(s->GetPredecessors().begin(), s->GetPredecessors().end(), block);
Roland Levillainccc07a92014-09-16 14:48:16 +0100104 if (s_count_in_block_successors != block_count_in_s_predecessors) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000105 AddError(StringPrintf(
106 "Block %d lists %zu occurrences of block %d in its successors, whereas "
107 "block %d lists %zu occurrences of block %d in its predecessors.",
108 block->GetBlockId(), s_count_in_block_successors, s->GetBlockId(),
109 s->GetBlockId(), block_count_in_s_predecessors, block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100110 }
111 }
112
113 // Ensure `block` ends with a branch instruction.
David Brazdilfc6a86a2015-06-26 10:33:45 +0000114 // This invariant is not enforced on non-SSA graphs. Graph built from DEX with
115 // dead code that falls out of the method will not end with a control-flow
116 // instruction. Such code is removed during the SSA-building DCE phase.
117 if (GetGraph()->IsInSsaForm() && !block->EndsWithControlFlowInstruction()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000118 AddError(StringPrintf("Block %d does not end with a branch instruction.",
119 block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100120 }
121
David Brazdil86ea7ee2016-02-16 09:26:07 +0000122 // Ensure that only Return(Void) and Throw jump to Exit. An exiting TryBoundary
123 // may be between the instructions if the Throw/Return(Void) is in a try block.
David Brazdilb618ade2015-07-29 10:31:29 +0100124 if (block->IsExitBlock()) {
Vladimir Marko60584552015-09-03 13:35:12 +0000125 for (HBasicBlock* predecessor : block->GetPredecessors()) {
David Brazdil86ea7ee2016-02-16 09:26:07 +0000126 HInstruction* last_instruction = IsExitTryBoundaryIntoExitBlock(predecessor) ?
127 predecessor->GetSinglePredecessor()->GetLastInstruction() :
128 predecessor->GetLastInstruction();
129 if (!IsAllowedToJumpToExitBlock(last_instruction)) {
130 AddError(StringPrintf("Unexpected instruction %s:%d jumps into the exit block.",
131 last_instruction->DebugName(),
132 last_instruction->GetId()));
David Brazdilb618ade2015-07-29 10:31:29 +0100133 }
134 }
135 }
136
Roland Levillainccc07a92014-09-16 14:48:16 +0100137 // Visit this block's list of phis.
138 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
David Brazdilc3d743f2015-04-22 13:40:50 +0100139 HInstruction* current = it.Current();
Roland Levillainccc07a92014-09-16 14:48:16 +0100140 // Ensure this block's list of phis contains only phis.
David Brazdilc3d743f2015-04-22 13:40:50 +0100141 if (!current->IsPhi()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000142 AddError(StringPrintf("Block %d has a non-phi in its phi list.",
143 current_block_->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100144 }
David Brazdilc3d743f2015-04-22 13:40:50 +0100145 if (current->GetNext() == nullptr && current != block->GetLastPhi()) {
146 AddError(StringPrintf("The recorded last phi of block %d does not match "
147 "the actual last phi %d.",
148 current_block_->GetBlockId(),
149 current->GetId()));
150 }
151 current->Accept(this);
Roland Levillainccc07a92014-09-16 14:48:16 +0100152 }
153
154 // Visit this block's list of instructions.
David Brazdilc3d743f2015-04-22 13:40:50 +0100155 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
156 HInstruction* current = it.Current();
Roland Levillainccc07a92014-09-16 14:48:16 +0100157 // Ensure this block's list of instructions does not contains phis.
David Brazdilc3d743f2015-04-22 13:40:50 +0100158 if (current->IsPhi()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000159 AddError(StringPrintf("Block %d has a phi in its non-phi list.",
160 current_block_->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100161 }
David Brazdilc3d743f2015-04-22 13:40:50 +0100162 if (current->GetNext() == nullptr && current != block->GetLastInstruction()) {
163 AddError(StringPrintf("The recorded last instruction of block %d does not match "
164 "the actual last instruction %d.",
165 current_block_->GetBlockId(),
166 current->GetId()));
167 }
168 current->Accept(this);
Roland Levillainccc07a92014-09-16 14:48:16 +0100169 }
David Brazdilbadd8262016-02-02 16:28:56 +0000170
171 // Ensure that catch blocks are not normal successors, and normal blocks are
172 // never exceptional successors.
173 for (HBasicBlock* successor : block->GetNormalSuccessors()) {
174 if (successor->IsCatchBlock()) {
175 AddError(StringPrintf("Catch block %d is a normal successor of block %d.",
176 successor->GetBlockId(),
177 block->GetBlockId()));
178 }
179 }
180 for (HBasicBlock* successor : block->GetExceptionalSuccessors()) {
181 if (!successor->IsCatchBlock()) {
182 AddError(StringPrintf("Normal block %d is an exceptional successor of block %d.",
183 successor->GetBlockId(),
184 block->GetBlockId()));
185 }
186 }
187
188 // Ensure dominated blocks have `block` as the dominator.
189 for (HBasicBlock* dominated : block->GetDominatedBlocks()) {
190 if (dominated->GetDominator() != block) {
191 AddError(StringPrintf("Block %d should be the dominator of %d.",
192 block->GetBlockId(),
193 dominated->GetBlockId()));
194 }
195 }
196
197 // Ensure there is no critical edge (i.e., an edge connecting a
198 // block with multiple successors to a block with multiple
199 // predecessors). Exceptional edges are synthesized and hence
200 // not accounted for.
201 if (block->GetSuccessors().size() > 1) {
David Brazdil86ea7ee2016-02-16 09:26:07 +0000202 if (IsExitTryBoundaryIntoExitBlock(block)) {
203 // Allowed critical edge (Throw/Return/ReturnVoid)->TryBoundary->Exit.
204 } else {
205 for (HBasicBlock* successor : block->GetNormalSuccessors()) {
206 if (successor->GetPredecessors().size() > 1) {
207 AddError(StringPrintf("Critical edge between blocks %d and %d.",
208 block->GetBlockId(),
209 successor->GetBlockId()));
210 }
David Brazdilbadd8262016-02-02 16:28:56 +0000211 }
212 }
213 }
214
215 // Ensure try membership information is consistent.
216 if (block->IsCatchBlock()) {
217 if (block->IsTryBlock()) {
218 const HTryBoundary& try_entry = block->GetTryCatchInformation()->GetTryEntry();
219 AddError(StringPrintf("Catch blocks should not be try blocks but catch block %d "
220 "has try entry %s:%d.",
221 block->GetBlockId(),
222 try_entry.DebugName(),
223 try_entry.GetId()));
224 }
225
226 if (block->IsLoopHeader()) {
227 AddError(StringPrintf("Catch blocks should not be loop headers but catch block %d is.",
228 block->GetBlockId()));
229 }
230 } else {
231 for (HBasicBlock* predecessor : block->GetPredecessors()) {
232 const HTryBoundary* incoming_try_entry = predecessor->ComputeTryEntryOfSuccessors();
233 if (block->IsTryBlock()) {
234 const HTryBoundary& stored_try_entry = block->GetTryCatchInformation()->GetTryEntry();
235 if (incoming_try_entry == nullptr) {
236 AddError(StringPrintf("Block %d has try entry %s:%d but no try entry follows "
237 "from predecessor %d.",
238 block->GetBlockId(),
239 stored_try_entry.DebugName(),
240 stored_try_entry.GetId(),
241 predecessor->GetBlockId()));
242 } else if (!incoming_try_entry->HasSameExceptionHandlersAs(stored_try_entry)) {
243 AddError(StringPrintf("Block %d has try entry %s:%d which is not consistent "
244 "with %s:%d that follows from predecessor %d.",
245 block->GetBlockId(),
246 stored_try_entry.DebugName(),
247 stored_try_entry.GetId(),
248 incoming_try_entry->DebugName(),
249 incoming_try_entry->GetId(),
250 predecessor->GetBlockId()));
251 }
252 } else if (incoming_try_entry != nullptr) {
253 AddError(StringPrintf("Block %d is not a try block but try entry %s:%d follows "
254 "from predecessor %d.",
255 block->GetBlockId(),
256 incoming_try_entry->DebugName(),
257 incoming_try_entry->GetId(),
258 predecessor->GetBlockId()));
259 }
260 }
261 }
262
263 if (block->IsLoopHeader()) {
264 HandleLoop(block);
265 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100266}
267
Mark Mendell1152c922015-04-24 17:06:35 -0400268void GraphChecker::VisitBoundsCheck(HBoundsCheck* check) {
269 if (!GetGraph()->HasBoundsChecks()) {
270 AddError(StringPrintf("Instruction %s:%d is a HBoundsCheck, "
271 "but HasBoundsChecks() returns false",
272 check->DebugName(),
273 check->GetId()));
274 }
275
276 // Perform the instruction base checks too.
277 VisitInstruction(check);
278}
279
Nicolas Geoffray93a18c52016-04-22 13:16:14 +0100280void GraphChecker::VisitDeoptimize(HDeoptimize* deopt) {
281 if (GetGraph()->IsCompilingOsr()) {
282 AddError(StringPrintf("A graph compiled OSR cannot have a HDeoptimize instruction"));
283 }
284
285 // Perform the instruction base checks too.
286 VisitInstruction(deopt);
287}
288
David Brazdilffee3d32015-07-06 11:48:53 +0100289void GraphChecker::VisitTryBoundary(HTryBoundary* try_boundary) {
David Brazdild26a4112015-11-10 11:07:31 +0000290 ArrayRef<HBasicBlock* const> handlers = try_boundary->GetExceptionHandlers();
291
292 // Ensure that all exception handlers are catch blocks.
David Brazdilffee3d32015-07-06 11:48:53 +0100293 // Note that a normal-flow successor may be a catch block before CFG
David Brazdilbadd8262016-02-02 16:28:56 +0000294 // simplification. We only test normal-flow successors in GraphChecker.
David Brazdild26a4112015-11-10 11:07:31 +0000295 for (HBasicBlock* handler : handlers) {
David Brazdilffee3d32015-07-06 11:48:53 +0100296 if (!handler->IsCatchBlock()) {
297 AddError(StringPrintf("Block %d with %s:%d has exceptional successor %d which "
298 "is not a catch block.",
299 current_block_->GetBlockId(),
300 try_boundary->DebugName(),
301 try_boundary->GetId(),
302 handler->GetBlockId()));
303 }
David Brazdild26a4112015-11-10 11:07:31 +0000304 }
305
306 // Ensure that handlers are not listed multiple times.
307 for (size_t i = 0, e = handlers.size(); i < e; ++i) {
David Brazdild8ef0c62015-11-10 18:49:28 +0000308 if (ContainsElement(handlers, handlers[i], i + 1)) {
309 AddError(StringPrintf("Exception handler block %d of %s:%d is listed multiple times.",
David Brazdild26a4112015-11-10 11:07:31 +0000310 handlers[i]->GetBlockId(),
David Brazdilffee3d32015-07-06 11:48:53 +0100311 try_boundary->DebugName(),
312 try_boundary->GetId()));
313 }
314 }
315
316 VisitInstruction(try_boundary);
317}
318
David Brazdil9bc43612015-11-05 21:25:24 +0000319void GraphChecker::VisitLoadException(HLoadException* load) {
320 // Ensure that LoadException is the first instruction in a catch block.
321 if (!load->GetBlock()->IsCatchBlock()) {
322 AddError(StringPrintf("%s:%d is in a non-catch block %d.",
323 load->DebugName(),
324 load->GetId(),
325 load->GetBlock()->GetBlockId()));
326 } else if (load->GetBlock()->GetFirstInstruction() != load) {
327 AddError(StringPrintf("%s:%d is not the first instruction in catch block %d.",
328 load->DebugName(),
329 load->GetId(),
330 load->GetBlock()->GetBlockId()));
331 }
332}
333
Roland Levillainccc07a92014-09-16 14:48:16 +0100334void GraphChecker::VisitInstruction(HInstruction* instruction) {
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000335 if (seen_ids_.IsBitSet(instruction->GetId())) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000336 AddError(StringPrintf("Instruction id %d is duplicate in graph.",
337 instruction->GetId()));
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000338 } else {
339 seen_ids_.SetBit(instruction->GetId());
340 }
341
Roland Levillainccc07a92014-09-16 14:48:16 +0100342 // Ensure `instruction` is associated with `current_block_`.
Roland Levillain5c4405e2015-01-21 11:39:58 +0000343 if (instruction->GetBlock() == nullptr) {
344 AddError(StringPrintf("%s %d in block %d not associated with any block.",
345 instruction->IsPhi() ? "Phi" : "Instruction",
346 instruction->GetId(),
347 current_block_->GetBlockId()));
348 } else if (instruction->GetBlock() != current_block_) {
349 AddError(StringPrintf("%s %d in block %d associated with block %d.",
350 instruction->IsPhi() ? "Phi" : "Instruction",
351 instruction->GetId(),
352 current_block_->GetBlockId(),
353 instruction->GetBlock()->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100354 }
Roland Levillain6b469232014-09-25 10:10:38 +0100355
356 // Ensure the inputs of `instruction` are defined in a block of the graph.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100357 for (HInstruction* input : instruction->GetInputs()) {
Igor Murashkind01745e2017-04-05 16:40:31 -0700358 if (input->GetBlock() == nullptr) {
359 AddError(StringPrintf("Input %d of instruction %d is not in any "
360 "basic block of the control-flow graph.",
361 input->GetId(),
362 instruction->GetId()));
Igor Murashkin4ae432d2017-05-04 14:15:08 -0700363 } else {
364 const HInstructionList& list = input->IsPhi()
365 ? input->GetBlock()->GetPhis()
366 : input->GetBlock()->GetInstructions();
367 if (!list.Contains(input)) {
368 AddError(StringPrintf("Input %d of instruction %d is not defined "
369 "in a basic block of the control-flow graph.",
370 input->GetId(),
371 instruction->GetId()));
372 }
Roland Levillain6b469232014-09-25 10:10:38 +0100373 }
374 }
375
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100376 // Ensure the uses of `instruction` are defined in a block of the graph,
377 // and the entry in the use list is consistent.
Vladimir Marko46817b82016-03-29 12:21:58 +0100378 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
379 HInstruction* user = use.GetUser();
380 const HInstructionList& list = user->IsPhi()
381 ? user->GetBlock()->GetPhis()
382 : user->GetBlock()->GetInstructions();
383 if (!list.Contains(user)) {
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000384 AddError(StringPrintf("User %s:%d of instruction %d is not defined "
Roland Levillain5c4405e2015-01-21 11:39:58 +0000385 "in a basic block of the control-flow graph.",
Vladimir Marko46817b82016-03-29 12:21:58 +0100386 user->DebugName(),
387 user->GetId(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000388 instruction->GetId()));
Roland Levillain6b469232014-09-25 10:10:38 +0100389 }
Vladimir Marko46817b82016-03-29 12:21:58 +0100390 size_t use_index = use.GetIndex();
Vladimir Markoe9004912016-06-16 16:50:52 +0100391 HConstInputsRef user_inputs = user->GetInputs();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100392 if ((use_index >= user_inputs.size()) || (user_inputs[use_index] != instruction)) {
Vladimir Markob554b5a2015-11-06 12:57:55 +0000393 AddError(StringPrintf("User %s:%d of instruction %s:%d has a wrong "
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100394 "UseListNode index.",
Vladimir Marko46817b82016-03-29 12:21:58 +0100395 user->DebugName(),
396 user->GetId(),
Vladimir Markob554b5a2015-11-06 12:57:55 +0000397 instruction->DebugName(),
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100398 instruction->GetId()));
399 }
400 }
401
402 // Ensure the environment uses entries are consistent.
Vladimir Marko46817b82016-03-29 12:21:58 +0100403 for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
404 HEnvironment* user = use.GetUser();
405 size_t use_index = use.GetIndex();
406 if ((use_index >= user->Size()) || (user->GetInstructionAt(use_index) != instruction)) {
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100407 AddError(StringPrintf("Environment user of %s:%d has a wrong "
408 "UseListNode index.",
409 instruction->DebugName(),
410 instruction->GetId()));
411 }
Roland Levillain6b469232014-09-25 10:10:38 +0100412 }
David Brazdil1abb4192015-02-17 18:33:36 +0000413
414 // Ensure 'instruction' has pointers to its inputs' use entries.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100415 auto&& input_records = instruction->GetInputRecords();
416 for (size_t i = 0; i < input_records.size(); ++i) {
417 const HUserRecord<HInstruction*>& input_record = input_records[i];
David Brazdil1abb4192015-02-17 18:33:36 +0000418 HInstruction* input = input_record.GetInstruction();
Vladimir Marko46817b82016-03-29 12:21:58 +0100419 if ((input_record.GetBeforeUseNode() == input->GetUses().end()) ||
420 (input_record.GetUseNode() == input->GetUses().end()) ||
421 !input->GetUses().ContainsNode(*input_record.GetUseNode()) ||
422 (input_record.GetUseNode()->GetIndex() != i)) {
423 AddError(StringPrintf("Instruction %s:%d has an invalid iterator before use entry "
David Brazdil1abb4192015-02-17 18:33:36 +0000424 "at input %u (%s:%d).",
425 instruction->DebugName(),
426 instruction->GetId(),
427 static_cast<unsigned>(i),
428 input->DebugName(),
429 input->GetId()));
430 }
431 }
David Brazdilbadd8262016-02-02 16:28:56 +0000432
433 // Ensure an instruction dominates all its uses.
Vladimir Marko46817b82016-03-29 12:21:58 +0100434 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
435 HInstruction* user = use.GetUser();
436 if (!user->IsPhi() && !instruction->StrictlyDominates(user)) {
David Brazdilbadd8262016-02-02 16:28:56 +0000437 AddError(StringPrintf("Instruction %s:%d in block %d does not dominate "
438 "use %s:%d in block %d.",
439 instruction->DebugName(),
440 instruction->GetId(),
441 current_block_->GetBlockId(),
Vladimir Marko46817b82016-03-29 12:21:58 +0100442 user->DebugName(),
443 user->GetId(),
444 user->GetBlock()->GetBlockId()));
David Brazdilbadd8262016-02-02 16:28:56 +0000445 }
446 }
447
448 if (instruction->NeedsEnvironment() && !instruction->HasEnvironment()) {
449 AddError(StringPrintf("Instruction %s:%d in block %d requires an environment "
450 "but does not have one.",
451 instruction->DebugName(),
452 instruction->GetId(),
453 current_block_->GetBlockId()));
454 }
455
456 // Ensure an instruction having an environment is dominated by the
457 // instructions contained in the environment.
458 for (HEnvironment* environment = instruction->GetEnvironment();
459 environment != nullptr;
460 environment = environment->GetParent()) {
461 for (size_t i = 0, e = environment->Size(); i < e; ++i) {
462 HInstruction* env_instruction = environment->GetInstructionAt(i);
463 if (env_instruction != nullptr
464 && !env_instruction->StrictlyDominates(instruction)) {
465 AddError(StringPrintf("Instruction %d in environment of instruction %d "
466 "from block %d does not dominate instruction %d.",
467 env_instruction->GetId(),
468 instruction->GetId(),
469 current_block_->GetBlockId(),
470 instruction->GetId()));
471 }
472 }
473 }
474
475 // Ensure that reference type instructions have reference type info.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100476 if (instruction->GetType() == DataType::Type::kReference) {
David Brazdilbadd8262016-02-02 16:28:56 +0000477 if (!instruction->GetReferenceTypeInfo().IsValid()) {
478 AddError(StringPrintf("Reference type instruction %s:%d does not have "
479 "valid reference type information.",
480 instruction->DebugName(),
481 instruction->GetId()));
482 }
483 }
484
485 if (instruction->CanThrowIntoCatchBlock()) {
486 // Find the top-level environment. This corresponds to the environment of
487 // the catch block since we do not inline methods with try/catch.
488 HEnvironment* environment = instruction->GetEnvironment();
489 while (environment->GetParent() != nullptr) {
490 environment = environment->GetParent();
491 }
492
493 // Find all catch blocks and test that `instruction` has an environment
494 // value for each one.
495 const HTryBoundary& entry = instruction->GetBlock()->GetTryCatchInformation()->GetTryEntry();
496 for (HBasicBlock* catch_block : entry.GetExceptionHandlers()) {
497 for (HInstructionIterator phi_it(catch_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
498 HPhi* catch_phi = phi_it.Current()->AsPhi();
499 if (environment->GetInstructionAt(catch_phi->GetRegNumber()) == nullptr) {
500 AddError(StringPrintf("Instruction %s:%d throws into catch block %d "
501 "with catch phi %d for vreg %d but its "
502 "corresponding environment slot is empty.",
503 instruction->DebugName(),
504 instruction->GetId(),
505 catch_block->GetBlockId(),
506 catch_phi->GetId(),
507 catch_phi->GetRegNumber()));
508 }
509 }
510 }
511 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100512}
513
Roland Levillain4c0eb422015-04-24 16:43:49 +0100514void GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
515 VisitInstruction(invoke);
516
517 if (invoke->IsStaticWithExplicitClinitCheck()) {
Vladimir Markoe9004912016-06-16 16:50:52 +0100518 const HInstruction* last_input = invoke->GetInputs().back();
Roland Levillain4c0eb422015-04-24 16:43:49 +0100519 if (last_input == nullptr) {
520 AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
521 "has a null pointer as last input.",
522 invoke->DebugName(),
523 invoke->GetId()));
George Burgess IV72155d22017-04-25 15:17:16 -0700524 } else if (!last_input->IsClinitCheck() && !last_input->IsLoadClass()) {
Roland Levillain4c0eb422015-04-24 16:43:49 +0100525 AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
526 "has a last instruction (%s:%d) which is neither a clinit check "
527 "nor a load class instruction.",
528 invoke->DebugName(),
529 invoke->GetId(),
530 last_input->DebugName(),
531 last_input->GetId()));
532 }
533 }
534}
535
David Brazdilfc6a86a2015-06-26 10:33:45 +0000536void GraphChecker::VisitReturn(HReturn* ret) {
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100537 VisitInstruction(ret);
David Brazdil86ea7ee2016-02-16 09:26:07 +0000538 HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor();
539 if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) {
David Brazdilfc6a86a2015-06-26 10:33:45 +0000540 AddError(StringPrintf("%s:%d does not jump to the exit block.",
541 ret->DebugName(),
542 ret->GetId()));
543 }
544}
545
546void GraphChecker::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100547 VisitInstruction(ret);
David Brazdil86ea7ee2016-02-16 09:26:07 +0000548 HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor();
549 if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) {
David Brazdilfc6a86a2015-06-26 10:33:45 +0000550 AddError(StringPrintf("%s:%d does not jump to the exit block.",
551 ret->DebugName(),
552 ret->GetId()));
553 }
554}
555
Vladimir Markoeb0ebed2018-01-10 18:26:38 +0000556void GraphChecker::CheckTypeCheckBitstringInput(HTypeCheckInstruction* check,
557 size_t input_pos,
558 bool check_value,
559 uint32_t expected_value,
560 const char* name) {
561 if (!check->InputAt(input_pos)->IsIntConstant()) {
562 AddError(StringPrintf("%s:%d (bitstring) expects a HIntConstant input %zu (%s), not %s:%d.",
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100563 check->DebugName(),
564 check->GetId(),
Vladimir Markoeb0ebed2018-01-10 18:26:38 +0000565 input_pos,
566 name,
567 check->InputAt(2)->DebugName(),
568 check->InputAt(2)->GetId()));
569 } else if (check_value) {
570 uint32_t actual_value =
571 static_cast<uint32_t>(check->InputAt(input_pos)->AsIntConstant()->GetValue());
572 if (actual_value != expected_value) {
573 AddError(StringPrintf("%s:%d (bitstring) has %s 0x%x, not 0x%x as expected.",
574 check->DebugName(),
575 check->GetId(),
576 name,
577 actual_value,
578 expected_value));
579 }
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100580 }
581}
582
Vladimir Markoeb0ebed2018-01-10 18:26:38 +0000583void GraphChecker::HandleTypeCheckInstruction(HTypeCheckInstruction* check) {
584 VisitInstruction(check);
585 HInstruction* input = check->InputAt(1);
586 if (check->GetTypeCheckKind() == TypeCheckKind::kBitstringCheck) {
587 if (!input->IsNullConstant()) {
588 AddError(StringPrintf("%s:%d (bitstring) expects a HNullConstant as second input, not %s:%d.",
589 check->DebugName(),
590 check->GetId(),
591 input->DebugName(),
592 input->GetId()));
593 }
594 bool check_values = false;
595 BitString::StorageType expected_path_to_root = 0u;
596 BitString::StorageType expected_mask = 0u;
597 {
598 ScopedObjectAccess soa(Thread::Current());
599 ObjPtr<mirror::Class> klass = check->GetClass().Get();
600 MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
601 SubtypeCheckInfo::State state = SubtypeCheck<ObjPtr<mirror::Class>>::GetState(klass);
602 if (state == SubtypeCheckInfo::kAssigned) {
603 expected_path_to_root =
604 SubtypeCheck<ObjPtr<mirror::Class>>::GetEncodedPathToRootForTarget(klass);
605 expected_mask = SubtypeCheck<ObjPtr<mirror::Class>>::GetEncodedPathToRootMask(klass);
606 check_values = true;
607 } else {
608 AddError(StringPrintf("%s:%d (bitstring) references a class with unassigned bitstring.",
609 check->DebugName(),
610 check->GetId()));
611 }
612 }
613 CheckTypeCheckBitstringInput(
614 check, /* input_pos */ 2, check_values, expected_path_to_root, "path_to_root");
615 CheckTypeCheckBitstringInput(check, /* input_pos */ 3, check_values, expected_mask, "mask");
616 } else {
617 if (!input->IsLoadClass()) {
618 AddError(StringPrintf("%s:%d (classic) expects a HLoadClass as second input, not %s:%d.",
619 check->DebugName(),
620 check->GetId(),
621 input->DebugName(),
622 input->GetId()));
623 }
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100624 }
625}
626
Vladimir Markoeb0ebed2018-01-10 18:26:38 +0000627void GraphChecker::VisitCheckCast(HCheckCast* check) {
628 HandleTypeCheckInstruction(check);
629}
630
631void GraphChecker::VisitInstanceOf(HInstanceOf* instruction) {
632 HandleTypeCheckInstruction(instruction);
633}
634
David Brazdilbadd8262016-02-02 16:28:56 +0000635void GraphChecker::HandleLoop(HBasicBlock* loop_header) {
Roland Levillain6b879dd2014-09-22 17:13:44 +0100636 int id = loop_header->GetBlockId();
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100637 HLoopInformation* loop_information = loop_header->GetLoopInformation();
Roland Levillain6b879dd2014-09-22 17:13:44 +0100638
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000639 if (loop_information->GetPreHeader()->GetSuccessors().size() != 1) {
David Brazdildb51efb2015-11-06 01:36:20 +0000640 AddError(StringPrintf(
641 "Loop pre-header %d of loop defined by header %d has %zu successors.",
642 loop_information->GetPreHeader()->GetBlockId(),
643 id,
644 loop_information->GetPreHeader()->GetSuccessors().size()));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100645 }
646
Nicolas Geoffray09aa1472016-01-19 10:52:54 +0000647 if (loop_information->GetSuspendCheck() == nullptr) {
648 AddError(StringPrintf(
649 "Loop with header %d does not have a suspend check.",
650 loop_header->GetBlockId()));
651 }
652
653 if (loop_information->GetSuspendCheck() != loop_header->GetFirstInstructionDisregardMoves()) {
654 AddError(StringPrintf(
655 "Loop header %d does not have the loop suspend check as the first instruction.",
656 loop_header->GetBlockId()));
657 }
658
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100659 // Ensure the loop header has only one incoming branch and the remaining
660 // predecessors are back edges.
Vladimir Marko60584552015-09-03 13:35:12 +0000661 size_t num_preds = loop_header->GetPredecessors().size();
Roland Levillain5c4405e2015-01-21 11:39:58 +0000662 if (num_preds < 2) {
663 AddError(StringPrintf(
664 "Loop header %d has less than two predecessors: %zu.",
665 id,
666 num_preds));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100667 } else {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100668 HBasicBlock* first_predecessor = loop_header->GetPredecessors()[0];
David Brazdil46e2a392015-03-16 17:31:52 +0000669 if (loop_information->IsBackEdge(*first_predecessor)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000670 AddError(StringPrintf(
671 "First predecessor of loop header %d is a back edge.",
672 id));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100673 }
Vladimir Marko60584552015-09-03 13:35:12 +0000674 for (size_t i = 1, e = loop_header->GetPredecessors().size(); i < e; ++i) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100675 HBasicBlock* predecessor = loop_header->GetPredecessors()[i];
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100676 if (!loop_information->IsBackEdge(*predecessor)) {
677 AddError(StringPrintf(
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000678 "Loop header %d has multiple incoming (non back edge) blocks: %d.",
679 id,
680 predecessor->GetBlockId()));
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100681 }
Roland Levillain6b879dd2014-09-22 17:13:44 +0100682 }
683 }
684
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100685 const ArenaBitVector& loop_blocks = loop_information->GetBlocks();
David Brazdil2d7352b2015-04-20 14:52:42 +0100686
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100687 // Ensure back edges belong to the loop.
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100688 if (loop_information->NumberOfBackEdges() == 0) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000689 AddError(StringPrintf(
690 "Loop defined by header %d has no back edge.",
691 id));
David Brazdil2d7352b2015-04-20 14:52:42 +0100692 } else {
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100693 for (HBasicBlock* back_edge : loop_information->GetBackEdges()) {
694 int back_edge_id = back_edge->GetBlockId();
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100695 if (!loop_blocks.IsBitSet(back_edge_id)) {
696 AddError(StringPrintf(
697 "Loop defined by header %d has an invalid back edge %d.",
698 id,
699 back_edge_id));
David Brazdildb51efb2015-11-06 01:36:20 +0000700 } else if (back_edge->GetLoopInformation() != loop_information) {
701 AddError(StringPrintf(
702 "Back edge %d of loop defined by header %d belongs to nested loop "
703 "with header %d.",
704 back_edge_id,
705 id,
706 back_edge->GetLoopInformation()->GetHeader()->GetBlockId()));
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100707 }
David Brazdil2d7352b2015-04-20 14:52:42 +0100708 }
Roland Levillain6b879dd2014-09-22 17:13:44 +0100709 }
Roland Levillain7e53b412014-09-23 10:50:22 +0100710
David Brazdil7d275372015-04-21 16:36:35 +0100711 // If this is a nested loop, ensure the outer loops contain a superset of the blocks.
712 for (HLoopInformationOutwardIterator it(*loop_header); !it.Done(); it.Advance()) {
713 HLoopInformation* outer_info = it.Current();
714 if (!loop_blocks.IsSubsetOf(&outer_info->GetBlocks())) {
715 AddError(StringPrintf("Blocks of loop defined by header %d are not a subset of blocks of "
716 "an outer loop defined by header %d.",
David Brazdil2d7352b2015-04-20 14:52:42 +0100717 id,
David Brazdil7d275372015-04-21 16:36:35 +0100718 outer_info->GetHeader()->GetBlockId()));
719 }
720 }
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000721
722 // Ensure the pre-header block is first in the list of predecessors of a loop
723 // header and that the header block is its only successor.
724 if (!loop_header->IsLoopPreHeaderFirstPredecessor()) {
725 AddError(StringPrintf(
726 "Loop pre-header is not the first predecessor of the loop header %d.",
727 id));
728 }
729
730 // Ensure all blocks in the loop are live and dominated by the loop header in
731 // the case of natural loops.
732 for (uint32_t i : loop_blocks.Indexes()) {
733 HBasicBlock* loop_block = GetGraph()->GetBlocks()[i];
734 if (loop_block == nullptr) {
735 AddError(StringPrintf("Loop defined by header %d contains a previously removed block %d.",
736 id,
737 i));
738 } else if (!loop_information->IsIrreducible() && !loop_header->Dominates(loop_block)) {
739 AddError(StringPrintf("Loop block %d not dominated by loop header %d.",
740 i,
741 id));
742 }
743 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100744}
745
Vladimir Markoe9004912016-06-16 16:50:52 +0100746static bool IsSameSizeConstant(const HInstruction* insn1, const HInstruction* insn2) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000747 return insn1->IsConstant()
748 && insn2->IsConstant()
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100749 && DataType::Is64BitType(insn1->GetType()) == DataType::Is64BitType(insn2->GetType());
David Brazdil77a48ae2015-09-15 12:34:04 +0000750}
751
Vladimir Markoe9004912016-06-16 16:50:52 +0100752static bool IsConstantEquivalent(const HInstruction* insn1,
753 const HInstruction* insn2,
754 BitVector* visited) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000755 if (insn1->IsPhi() &&
Vladimir Marko372f10e2016-05-17 16:30:10 +0100756 insn1->AsPhi()->IsVRegEquivalentOf(insn2)) {
Vladimir Markoe9004912016-06-16 16:50:52 +0100757 HConstInputsRef insn1_inputs = insn1->GetInputs();
758 HConstInputsRef insn2_inputs = insn2->GetInputs();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100759 if (insn1_inputs.size() != insn2_inputs.size()) {
760 return false;
761 }
762
David Brazdil77a48ae2015-09-15 12:34:04 +0000763 // Testing only one of the two inputs for recursion is sufficient.
764 if (visited->IsBitSet(insn1->GetId())) {
765 return true;
766 }
767 visited->SetBit(insn1->GetId());
768
Vladimir Marko372f10e2016-05-17 16:30:10 +0100769 for (size_t i = 0; i < insn1_inputs.size(); ++i) {
770 if (!IsConstantEquivalent(insn1_inputs[i], insn2_inputs[i], visited)) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000771 return false;
772 }
773 }
774 return true;
775 } else if (IsSameSizeConstant(insn1, insn2)) {
776 return insn1->AsConstant()->GetValueAsUint64() == insn2->AsConstant()->GetValueAsUint64();
777 } else {
778 return false;
779 }
780}
781
David Brazdilbadd8262016-02-02 16:28:56 +0000782void GraphChecker::VisitPhi(HPhi* phi) {
Roland Levillain6b879dd2014-09-22 17:13:44 +0100783 VisitInstruction(phi);
784
785 // Ensure the first input of a phi is not itself.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100786 ArrayRef<HUserRecord<HInstruction*>> input_records = phi->GetInputRecords();
787 if (input_records[0].GetInstruction() == phi) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000788 AddError(StringPrintf("Loop phi %d in block %d is its own first input.",
789 phi->GetId(),
790 phi->GetBlock()->GetBlockId()));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100791 }
792
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000793 // Ensure that the inputs have the same primitive kind as the phi.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100794 for (size_t i = 0; i < input_records.size(); ++i) {
795 HInstruction* input = input_records[i].GetInstruction();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100796 if (DataType::Kind(input->GetType()) != DataType::Kind(phi->GetType())) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000797 AddError(StringPrintf(
798 "Input %d at index %zu of phi %d from block %d does not have the "
Roland Levillaina5c4a402016-03-15 15:02:50 +0000799 "same kind as the phi: %s versus %s",
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000800 input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100801 DataType::PrettyDescriptor(input->GetType()),
802 DataType::PrettyDescriptor(phi->GetType())));
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000803 }
Nicolas Geoffray31596742014-11-24 15:28:45 +0000804 }
Nicolas Geoffraye0fe7ae2015-03-09 10:02:49 +0000805 if (phi->GetType() != HPhi::ToPhiType(phi->GetType())) {
806 AddError(StringPrintf("Phi %d in block %d does not have an expected phi type: %s",
807 phi->GetId(),
808 phi->GetBlock()->GetBlockId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100809 DataType::PrettyDescriptor(phi->GetType())));
Nicolas Geoffraye0fe7ae2015-03-09 10:02:49 +0000810 }
David Brazdilffee3d32015-07-06 11:48:53 +0100811
812 if (phi->IsCatchPhi()) {
David Brazdil3eaa32f2015-09-18 10:58:32 +0100813 // The number of inputs of a catch phi should be the total number of throwing
814 // instructions caught by this catch block. We do not enforce this, however,
815 // because we do not remove the corresponding inputs when we prove that an
816 // instruction cannot throw. Instead, we at least test that all phis have the
817 // same, non-zero number of inputs (b/24054676).
Vladimir Marko372f10e2016-05-17 16:30:10 +0100818 if (input_records.empty()) {
David Brazdil3eaa32f2015-09-18 10:58:32 +0100819 AddError(StringPrintf("Phi %d in catch block %d has zero inputs.",
820 phi->GetId(),
821 phi->GetBlock()->GetBlockId()));
822 } else {
823 HInstruction* next_phi = phi->GetNext();
824 if (next_phi != nullptr) {
825 size_t input_count_next = next_phi->InputCount();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100826 if (input_records.size() != input_count_next) {
David Brazdil3eaa32f2015-09-18 10:58:32 +0100827 AddError(StringPrintf("Phi %d in catch block %d has %zu inputs, "
828 "but phi %d has %zu inputs.",
829 phi->GetId(),
830 phi->GetBlock()->GetBlockId(),
Vladimir Marko372f10e2016-05-17 16:30:10 +0100831 input_records.size(),
David Brazdil3eaa32f2015-09-18 10:58:32 +0100832 next_phi->GetId(),
833 input_count_next));
834 }
835 }
836 }
David Brazdilffee3d32015-07-06 11:48:53 +0100837 } else {
838 // Ensure the number of inputs of a non-catch phi is the same as the number
839 // of its predecessors.
Vladimir Marko60584552015-09-03 13:35:12 +0000840 const ArenaVector<HBasicBlock*>& predecessors = phi->GetBlock()->GetPredecessors();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100841 if (input_records.size() != predecessors.size()) {
David Brazdilffee3d32015-07-06 11:48:53 +0100842 AddError(StringPrintf(
843 "Phi %d in block %d has %zu inputs, "
844 "but block %d has %zu predecessors.",
Vladimir Marko372f10e2016-05-17 16:30:10 +0100845 phi->GetId(), phi->GetBlock()->GetBlockId(), input_records.size(),
Vladimir Marko60584552015-09-03 13:35:12 +0000846 phi->GetBlock()->GetBlockId(), predecessors.size()));
David Brazdilffee3d32015-07-06 11:48:53 +0100847 } else {
848 // Ensure phi input at index I either comes from the Ith
849 // predecessor or from a block that dominates this predecessor.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100850 for (size_t i = 0; i < input_records.size(); ++i) {
851 HInstruction* input = input_records[i].GetInstruction();
Vladimir Marko60584552015-09-03 13:35:12 +0000852 HBasicBlock* predecessor = predecessors[i];
David Brazdilffee3d32015-07-06 11:48:53 +0100853 if (!(input->GetBlock() == predecessor
854 || input->GetBlock()->Dominates(predecessor))) {
855 AddError(StringPrintf(
856 "Input %d at index %zu of phi %d from block %d is not defined in "
857 "predecessor number %zu nor in a block dominating it.",
858 input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
859 i));
860 }
861 }
862 }
863 }
David Brazdil77a48ae2015-09-15 12:34:04 +0000864
865 // Ensure that catch phis are sorted by their vreg number, as required by
866 // the register allocator and code generator. This does not apply to normal
867 // phis which can be constructed artifically.
868 if (phi->IsCatchPhi()) {
869 HInstruction* next_phi = phi->GetNext();
870 if (next_phi != nullptr && phi->GetRegNumber() > next_phi->AsPhi()->GetRegNumber()) {
871 AddError(StringPrintf("Catch phis %d and %d in block %d are not sorted by their "
872 "vreg numbers.",
873 phi->GetId(),
874 next_phi->GetId(),
875 phi->GetBlock()->GetBlockId()));
876 }
877 }
878
Aart Bik3fc7f352015-11-20 22:03:03 -0800879 // Test phi equivalents. There should not be two of the same type and they should only be
880 // created for constants which were untyped in DEX. Note that this test can be skipped for
881 // a synthetic phi (indicated by lack of a virtual register).
882 if (phi->GetRegNumber() != kNoRegNumber) {
Aart Bik4a342772015-11-30 10:17:46 -0800883 for (HInstructionIterator phi_it(phi->GetBlock()->GetPhis());
884 !phi_it.Done();
885 phi_it.Advance()) {
Aart Bik3fc7f352015-11-20 22:03:03 -0800886 HPhi* other_phi = phi_it.Current()->AsPhi();
887 if (phi != other_phi && phi->GetRegNumber() == other_phi->GetRegNumber()) {
888 if (phi->GetType() == other_phi->GetType()) {
889 std::stringstream type_str;
890 type_str << phi->GetType();
891 AddError(StringPrintf("Equivalent phi (%d) found for VReg %d with type: %s.",
David Brazdil77a48ae2015-09-15 12:34:04 +0000892 phi->GetId(),
Aart Bik3fc7f352015-11-20 22:03:03 -0800893 phi->GetRegNumber(),
894 type_str.str().c_str()));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100895 } else if (phi->GetType() == DataType::Type::kReference) {
Nicolas Geoffrayf5f64ef2015-12-15 14:11:59 +0000896 std::stringstream type_str;
897 type_str << other_phi->GetType();
898 AddError(StringPrintf(
899 "Equivalent non-reference phi (%d) found for VReg %d with type: %s.",
900 phi->GetId(),
901 phi->GetRegNumber(),
902 type_str.str().c_str()));
Aart Bik3fc7f352015-11-20 22:03:03 -0800903 } else {
Vladimir Marko009d1662017-10-10 13:21:15 +0100904 // Use local allocator for allocating memory.
905 ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
Vladimir Marko947eb702016-03-25 15:31:35 +0000906 // If we get here, make sure we allocate all the necessary storage at once
907 // because the BitVector reallocation strategy has very bad worst-case behavior.
Vladimir Marko009d1662017-10-10 13:21:15 +0100908 ArenaBitVector visited(&allocator,
909 GetGraph()->GetCurrentInstructionId(),
910 /* expandable */ false,
911 kArenaAllocGraphChecker);
Vladimir Marko947eb702016-03-25 15:31:35 +0000912 visited.ClearAllBits();
Aart Bik3fc7f352015-11-20 22:03:03 -0800913 if (!IsConstantEquivalent(phi, other_phi, &visited)) {
914 AddError(StringPrintf("Two phis (%d and %d) found for VReg %d but they "
915 "are not equivalents of constants.",
916 phi->GetId(),
917 other_phi->GetId(),
918 phi->GetRegNumber()));
919 }
David Brazdil77a48ae2015-09-15 12:34:04 +0000920 }
921 }
922 }
923 }
Nicolas Geoffray31596742014-11-24 15:28:45 +0000924}
925
David Brazdilbadd8262016-02-02 16:28:56 +0000926void GraphChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) {
David Brazdil13b47182015-04-15 16:29:32 +0100927 HInstruction* input = instruction->InputAt(input_index);
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000928 if (input->IsIntConstant()) {
David Brazdil13b47182015-04-15 16:29:32 +0100929 int32_t value = input->AsIntConstant()->GetValue();
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000930 if (value != 0 && value != 1) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000931 AddError(StringPrintf(
David Brazdil13b47182015-04-15 16:29:32 +0100932 "%s instruction %d has a non-Boolean constant input %d whose value is: %d.",
933 instruction->DebugName(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000934 instruction->GetId(),
David Brazdil13b47182015-04-15 16:29:32 +0100935 static_cast<int>(input_index),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000936 value));
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000937 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100938 } else if (DataType::Kind(input->GetType()) != DataType::Type::kInt32) {
David Brazdil11edec72016-03-24 12:40:52 +0000939 // TODO: We need a data-flow analysis to determine if an input like Phi,
940 // Select or a binary operation is actually Boolean. Allow for now.
Roland Levillain5c4405e2015-01-21 11:39:58 +0000941 AddError(StringPrintf(
David Brazdil11edec72016-03-24 12:40:52 +0000942 "%s instruction %d has a non-integer input %d whose type is: %s.",
David Brazdil13b47182015-04-15 16:29:32 +0100943 instruction->DebugName(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000944 instruction->GetId(),
David Brazdil13b47182015-04-15 16:29:32 +0100945 static_cast<int>(input_index),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100946 DataType::PrettyDescriptor(input->GetType())));
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000947 }
948}
949
David Brazdilbadd8262016-02-02 16:28:56 +0000950void GraphChecker::VisitPackedSwitch(HPackedSwitch* instruction) {
Mark Mendellfe57faa2015-09-18 09:26:15 -0400951 VisitInstruction(instruction);
952 // Check that the number of block successors matches the switch count plus
953 // one for the default block.
954 HBasicBlock* block = instruction->GetBlock();
955 if (instruction->GetNumEntries() + 1u != block->GetSuccessors().size()) {
956 AddError(StringPrintf(
957 "%s instruction %d in block %d expects %u successors to the block, but found: %zu.",
958 instruction->DebugName(),
959 instruction->GetId(),
960 block->GetBlockId(),
961 instruction->GetNumEntries() + 1u,
962 block->GetSuccessors().size()));
963 }
964}
965
David Brazdilbadd8262016-02-02 16:28:56 +0000966void GraphChecker::VisitIf(HIf* instruction) {
David Brazdil13b47182015-04-15 16:29:32 +0100967 VisitInstruction(instruction);
968 HandleBooleanInput(instruction, 0);
969}
970
David Brazdilbadd8262016-02-02 16:28:56 +0000971void GraphChecker::VisitSelect(HSelect* instruction) {
David Brazdil74eb1b22015-12-14 11:44:01 +0000972 VisitInstruction(instruction);
973 HandleBooleanInput(instruction, 2);
974}
975
David Brazdilbadd8262016-02-02 16:28:56 +0000976void GraphChecker::VisitBooleanNot(HBooleanNot* instruction) {
David Brazdil13b47182015-04-15 16:29:32 +0100977 VisitInstruction(instruction);
978 HandleBooleanInput(instruction, 0);
979}
980
David Brazdilbadd8262016-02-02 16:28:56 +0000981void GraphChecker::VisitCondition(HCondition* op) {
Nicolas Geoffray31596742014-11-24 15:28:45 +0000982 VisitInstruction(op);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100983 if (op->GetType() != DataType::Type::kBool) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000984 AddError(StringPrintf(
985 "Condition %s %d has a non-Boolean result type: %s.",
986 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100987 DataType::PrettyDescriptor(op->GetType())));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000988 }
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000989 HInstruction* lhs = op->InputAt(0);
990 HInstruction* rhs = op->InputAt(1);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100991 if (DataType::Kind(lhs->GetType()) != DataType::Kind(rhs->GetType())) {
Calin Juravlea4f88312015-04-16 12:57:19 +0100992 AddError(StringPrintf(
Roland Levillaina5c4a402016-03-15 15:02:50 +0000993 "Condition %s %d has inputs of different kinds: %s, and %s.",
Calin Juravlea4f88312015-04-16 12:57:19 +0100994 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100995 DataType::PrettyDescriptor(lhs->GetType()),
996 DataType::PrettyDescriptor(rhs->GetType())));
Calin Juravlea4f88312015-04-16 12:57:19 +0100997 }
998 if (!op->IsEqual() && !op->IsNotEqual()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100999 if ((lhs->GetType() == DataType::Type::kReference)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +00001000 AddError(StringPrintf(
1001 "Condition %s %d uses an object as left-hand side input.",
1002 op->DebugName(), op->GetId()));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001003 } else if (rhs->GetType() == DataType::Type::kReference) {
Roland Levillain5c4405e2015-01-21 11:39:58 +00001004 AddError(StringPrintf(
1005 "Condition %s %d uses an object as right-hand side input.",
1006 op->DebugName(), op->GetId()));
Roland Levillainaecbd262015-01-19 12:44:01 +00001007 }
Nicolas Geoffray9ee66182015-01-16 12:35:40 +00001008 }
Nicolas Geoffray31596742014-11-24 15:28:45 +00001009}
1010
Roland Levillain937e6cd2016-03-22 11:54:37 +00001011void GraphChecker::VisitNeg(HNeg* instruction) {
1012 VisitInstruction(instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001013 DataType::Type input_type = instruction->InputAt(0)->GetType();
1014 DataType::Type result_type = instruction->GetType();
1015 if (result_type != DataType::Kind(input_type)) {
Roland Levillain937e6cd2016-03-22 11:54:37 +00001016 AddError(StringPrintf("Binary operation %s %d has a result type different "
1017 "from its input kind: %s vs %s.",
1018 instruction->DebugName(), instruction->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001019 DataType::PrettyDescriptor(result_type),
1020 DataType::PrettyDescriptor(input_type)));
Roland Levillain937e6cd2016-03-22 11:54:37 +00001021 }
1022}
1023
David Brazdilbadd8262016-02-02 16:28:56 +00001024void GraphChecker::VisitBinaryOperation(HBinaryOperation* op) {
Nicolas Geoffray31596742014-11-24 15:28:45 +00001025 VisitInstruction(op);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001026 DataType::Type lhs_type = op->InputAt(0)->GetType();
1027 DataType::Type rhs_type = op->InputAt(1)->GetType();
1028 DataType::Type result_type = op->GetType();
Roland Levillain5b5b9312016-03-22 14:57:31 +00001029
1030 // Type consistency between inputs.
Scott Wakeling40a04bf2015-12-11 09:50:36 +00001031 if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001032 if (DataType::Kind(rhs_type) != DataType::Type::kInt32) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00001033 AddError(StringPrintf("Shift/rotate operation %s %d has a non-int kind second input: "
1034 "%s of type %s.",
Roland Levillaina5c4a402016-03-15 15:02:50 +00001035 op->DebugName(), op->GetId(),
1036 op->InputAt(1)->DebugName(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001037 DataType::PrettyDescriptor(rhs_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +00001038 }
1039 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001040 if (DataType::Kind(lhs_type) != DataType::Kind(rhs_type)) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00001041 AddError(StringPrintf("Binary operation %s %d has inputs of different kinds: %s, and %s.",
1042 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001043 DataType::PrettyDescriptor(lhs_type),
1044 DataType::PrettyDescriptor(rhs_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +00001045 }
1046 }
1047
Roland Levillain5b5b9312016-03-22 14:57:31 +00001048 // Type consistency between result and input(s).
Nicolas Geoffray31596742014-11-24 15:28:45 +00001049 if (op->IsCompare()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001050 if (result_type != DataType::Type::kInt32) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00001051 AddError(StringPrintf("Compare operation %d has a non-int result type: %s.",
1052 op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001053 DataType::PrettyDescriptor(result_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +00001054 }
Roland Levillain5b5b9312016-03-22 14:57:31 +00001055 } else if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
1056 // Only check the first input (value), as the second one (distance)
1057 // must invariably be of kind `int`.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001058 if (result_type != DataType::Kind(lhs_type)) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00001059 AddError(StringPrintf("Shift/rotate operation %s %d has a result type different "
1060 "from its left-hand side (value) input kind: %s vs %s.",
Roland Levillaina5c4a402016-03-15 15:02:50 +00001061 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001062 DataType::PrettyDescriptor(result_type),
1063 DataType::PrettyDescriptor(lhs_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +00001064 }
Roland Levillain5b5b9312016-03-22 14:57:31 +00001065 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001066 if (DataType::Kind(result_type) != DataType::Kind(lhs_type)) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00001067 AddError(StringPrintf("Binary operation %s %d has a result kind different "
1068 "from its left-hand side input kind: %s vs %s.",
1069 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001070 DataType::PrettyDescriptor(result_type),
1071 DataType::PrettyDescriptor(lhs_type)));
Roland Levillain5b5b9312016-03-22 14:57:31 +00001072 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001073 if (DataType::Kind(result_type) != DataType::Kind(rhs_type)) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00001074 AddError(StringPrintf("Binary operation %s %d has a result kind different "
1075 "from its right-hand side input kind: %s vs %s.",
1076 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001077 DataType::PrettyDescriptor(result_type),
1078 DataType::PrettyDescriptor(rhs_type)));
Roland Levillain5b5b9312016-03-22 14:57:31 +00001079 }
Nicolas Geoffray31596742014-11-24 15:28:45 +00001080 }
1081}
1082
David Brazdilbadd8262016-02-02 16:28:56 +00001083void GraphChecker::VisitConstant(HConstant* instruction) {
David Brazdil8d5b8b22015-03-24 10:51:52 +00001084 HBasicBlock* block = instruction->GetBlock();
1085 if (!block->IsEntryBlock()) {
1086 AddError(StringPrintf(
1087 "%s %d should be in the entry block but is in block %d.",
1088 instruction->DebugName(),
1089 instruction->GetId(),
1090 block->GetBlockId()));
1091 }
1092}
1093
David Brazdilbadd8262016-02-02 16:28:56 +00001094void GraphChecker::VisitBoundType(HBoundType* instruction) {
David Brazdilf5552582015-12-27 13:36:12 +00001095 VisitInstruction(instruction);
1096
David Brazdilf5552582015-12-27 13:36:12 +00001097 if (!instruction->GetUpperBound().IsValid()) {
1098 AddError(StringPrintf(
1099 "%s %d does not have a valid upper bound RTI.",
1100 instruction->DebugName(),
1101 instruction->GetId()));
1102 }
1103}
1104
Roland Levillainf355c3f2016-03-30 19:09:03 +01001105void GraphChecker::VisitTypeConversion(HTypeConversion* instruction) {
1106 VisitInstruction(instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001107 DataType::Type result_type = instruction->GetResultType();
1108 DataType::Type input_type = instruction->GetInputType();
Roland Levillainf355c3f2016-03-30 19:09:03 +01001109 // Invariant: We should never generate a conversion to a Boolean value.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001110 if (result_type == DataType::Type::kBool) {
Roland Levillainf355c3f2016-03-30 19:09:03 +01001111 AddError(StringPrintf(
1112 "%s %d converts to a %s (from a %s).",
1113 instruction->DebugName(),
1114 instruction->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001115 DataType::PrettyDescriptor(result_type),
1116 DataType::PrettyDescriptor(input_type)));
Roland Levillainf355c3f2016-03-30 19:09:03 +01001117 }
1118}
1119
Roland Levillainccc07a92014-09-16 14:48:16 +01001120} // namespace art