• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
19 #include <algorithm>
20 #include <sstream>
21 #include <string>
22 
23 #include "android-base/stringprintf.h"
24 
25 #include "base/bit_vector-inl.h"
26 #include "base/scoped_arena_allocator.h"
27 #include "base/scoped_arena_containers.h"
28 #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"
33 
34 namespace art {
35 
36 using android::base::StringPrintf;
37 
IsAllowedToJumpToExitBlock(HInstruction * instruction)38 static bool IsAllowedToJumpToExitBlock(HInstruction* instruction) {
39   // 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();
48 }
49 
IsExitTryBoundaryIntoExitBlock(HBasicBlock * block)50 static 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 
61 
Run(bool pass_change,size_t last_size)62 size_t GraphChecker::Run(bool pass_change, size_t last_size) {
63   size_t current_size = GetGraph()->GetReversePostOrder().size();
64   if (!pass_change) {
65     // Nothing changed for certain. Do a quick sanity check on that assertion
66     // for anything other than the first call (when last size was still 0).
67     if (last_size != 0) {
68       if (current_size != last_size) {
69         AddError(StringPrintf("Incorrect no-change assertion, "
70                               "last graph size %zu vs current graph size %zu",
71                               last_size, current_size));
72       }
73     }
74     // TODO: if we would trust the "false" value of the flag completely, we
75     // could skip checking the graph at this point.
76   }
77 
78   // VisitReversePostOrder is used instead of VisitInsertionOrder,
79   // as the latter might visit dead blocks removed by the dominator
80   // computation.
81   VisitReversePostOrder();
82   return current_size;
83 }
84 
VisitBasicBlock(HBasicBlock * block)85 void GraphChecker::VisitBasicBlock(HBasicBlock* block) {
86   current_block_ = block;
87 
88   // Use local allocator for allocating memory.
89   ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
90 
91   // Check consistency with respect to predecessors of `block`.
92   // Note: Counting duplicates with a sorted vector uses up to 6x less memory
93   // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
94   ScopedArenaVector<HBasicBlock*> sorted_predecessors(allocator.Adapter(kArenaAllocGraphChecker));
95   sorted_predecessors.assign(block->GetPredecessors().begin(), block->GetPredecessors().end());
96   std::sort(sorted_predecessors.begin(), sorted_predecessors.end());
97   for (auto it = sorted_predecessors.begin(), end = sorted_predecessors.end(); it != end; ) {
98     HBasicBlock* p = *it++;
99     size_t p_count_in_block_predecessors = 1u;
100     for (; it != end && *it == p; ++it) {
101       ++p_count_in_block_predecessors;
102     }
103     size_t block_count_in_p_successors =
104         std::count(p->GetSuccessors().begin(), p->GetSuccessors().end(), block);
105     if (p_count_in_block_predecessors != block_count_in_p_successors) {
106       AddError(StringPrintf(
107           "Block %d lists %zu occurrences of block %d in its predecessors, whereas "
108           "block %d lists %zu occurrences of block %d in its successors.",
109           block->GetBlockId(), p_count_in_block_predecessors, p->GetBlockId(),
110           p->GetBlockId(), block_count_in_p_successors, block->GetBlockId()));
111     }
112   }
113 
114   // Check consistency with respect to successors of `block`.
115   // Note: Counting duplicates with a sorted vector uses up to 6x less memory
116   // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
117   ScopedArenaVector<HBasicBlock*> sorted_successors(allocator.Adapter(kArenaAllocGraphChecker));
118   sorted_successors.assign(block->GetSuccessors().begin(), block->GetSuccessors().end());
119   std::sort(sorted_successors.begin(), sorted_successors.end());
120   for (auto it = sorted_successors.begin(), end = sorted_successors.end(); it != end; ) {
121     HBasicBlock* s = *it++;
122     size_t s_count_in_block_successors = 1u;
123     for (; it != end && *it == s; ++it) {
124       ++s_count_in_block_successors;
125     }
126     size_t block_count_in_s_predecessors =
127         std::count(s->GetPredecessors().begin(), s->GetPredecessors().end(), block);
128     if (s_count_in_block_successors != block_count_in_s_predecessors) {
129       AddError(StringPrintf(
130           "Block %d lists %zu occurrences of block %d in its successors, whereas "
131           "block %d lists %zu occurrences of block %d in its predecessors.",
132           block->GetBlockId(), s_count_in_block_successors, s->GetBlockId(),
133           s->GetBlockId(), block_count_in_s_predecessors, block->GetBlockId()));
134     }
135   }
136 
137   // Ensure `block` ends with a branch instruction.
138   // This invariant is not enforced on non-SSA graphs. Graph built from DEX with
139   // dead code that falls out of the method will not end with a control-flow
140   // instruction. Such code is removed during the SSA-building DCE phase.
141   if (GetGraph()->IsInSsaForm() && !block->EndsWithControlFlowInstruction()) {
142     AddError(StringPrintf("Block %d does not end with a branch instruction.",
143                           block->GetBlockId()));
144   }
145 
146   // Ensure that only Return(Void) and Throw jump to Exit. An exiting TryBoundary
147   // may be between the instructions if the Throw/Return(Void) is in a try block.
148   if (block->IsExitBlock()) {
149     for (HBasicBlock* predecessor : block->GetPredecessors()) {
150       HInstruction* last_instruction = IsExitTryBoundaryIntoExitBlock(predecessor) ?
151         predecessor->GetSinglePredecessor()->GetLastInstruction() :
152         predecessor->GetLastInstruction();
153       if (!IsAllowedToJumpToExitBlock(last_instruction)) {
154         AddError(StringPrintf("Unexpected instruction %s:%d jumps into the exit block.",
155                               last_instruction->DebugName(),
156                               last_instruction->GetId()));
157       }
158     }
159   }
160 
161   // Visit this block's list of phis.
162   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
163     HInstruction* current = it.Current();
164     // Ensure this block's list of phis contains only phis.
165     if (!current->IsPhi()) {
166       AddError(StringPrintf("Block %d has a non-phi in its phi list.",
167                             current_block_->GetBlockId()));
168     }
169     if (current->GetNext() == nullptr && current != block->GetLastPhi()) {
170       AddError(StringPrintf("The recorded last phi of block %d does not match "
171                             "the actual last phi %d.",
172                             current_block_->GetBlockId(),
173                             current->GetId()));
174     }
175     current->Accept(this);
176   }
177 
178   // Visit this block's list of instructions.
179   for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
180     HInstruction* current = it.Current();
181     // Ensure this block's list of instructions does not contains phis.
182     if (current->IsPhi()) {
183       AddError(StringPrintf("Block %d has a phi in its non-phi list.",
184                             current_block_->GetBlockId()));
185     }
186     if (current->GetNext() == nullptr && current != block->GetLastInstruction()) {
187       AddError(StringPrintf("The recorded last instruction of block %d does not match "
188                             "the actual last instruction %d.",
189                             current_block_->GetBlockId(),
190                             current->GetId()));
191     }
192     current->Accept(this);
193   }
194 
195   // Ensure that catch blocks are not normal successors, and normal blocks are
196   // never exceptional successors.
197   for (HBasicBlock* successor : block->GetNormalSuccessors()) {
198     if (successor->IsCatchBlock()) {
199       AddError(StringPrintf("Catch block %d is a normal successor of block %d.",
200                             successor->GetBlockId(),
201                             block->GetBlockId()));
202     }
203   }
204   for (HBasicBlock* successor : block->GetExceptionalSuccessors()) {
205     if (!successor->IsCatchBlock()) {
206       AddError(StringPrintf("Normal block %d is an exceptional successor of block %d.",
207                             successor->GetBlockId(),
208                             block->GetBlockId()));
209     }
210   }
211 
212   // Ensure dominated blocks have `block` as the dominator.
213   for (HBasicBlock* dominated : block->GetDominatedBlocks()) {
214     if (dominated->GetDominator() != block) {
215       AddError(StringPrintf("Block %d should be the dominator of %d.",
216                             block->GetBlockId(),
217                             dominated->GetBlockId()));
218     }
219   }
220 
221   // Ensure there is no critical edge (i.e., an edge connecting a
222   // block with multiple successors to a block with multiple
223   // predecessors). Exceptional edges are synthesized and hence
224   // not accounted for.
225   if (block->GetSuccessors().size() > 1) {
226     if (IsExitTryBoundaryIntoExitBlock(block)) {
227       // Allowed critical edge (Throw/Return/ReturnVoid)->TryBoundary->Exit.
228     } else {
229       for (HBasicBlock* successor : block->GetNormalSuccessors()) {
230         if (successor->GetPredecessors().size() > 1) {
231           AddError(StringPrintf("Critical edge between blocks %d and %d.",
232                                 block->GetBlockId(),
233                                 successor->GetBlockId()));
234         }
235       }
236     }
237   }
238 
239   // Ensure try membership information is consistent.
240   if (block->IsCatchBlock()) {
241     if (block->IsTryBlock()) {
242       const HTryBoundary& try_entry = block->GetTryCatchInformation()->GetTryEntry();
243       AddError(StringPrintf("Catch blocks should not be try blocks but catch block %d "
244                             "has try entry %s:%d.",
245                             block->GetBlockId(),
246                             try_entry.DebugName(),
247                             try_entry.GetId()));
248     }
249 
250     if (block->IsLoopHeader()) {
251       AddError(StringPrintf("Catch blocks should not be loop headers but catch block %d is.",
252                             block->GetBlockId()));
253     }
254   } else {
255     for (HBasicBlock* predecessor : block->GetPredecessors()) {
256       const HTryBoundary* incoming_try_entry = predecessor->ComputeTryEntryOfSuccessors();
257       if (block->IsTryBlock()) {
258         const HTryBoundary& stored_try_entry = block->GetTryCatchInformation()->GetTryEntry();
259         if (incoming_try_entry == nullptr) {
260           AddError(StringPrintf("Block %d has try entry %s:%d but no try entry follows "
261                                 "from predecessor %d.",
262                                 block->GetBlockId(),
263                                 stored_try_entry.DebugName(),
264                                 stored_try_entry.GetId(),
265                                 predecessor->GetBlockId()));
266         } else if (!incoming_try_entry->HasSameExceptionHandlersAs(stored_try_entry)) {
267           AddError(StringPrintf("Block %d has try entry %s:%d which is not consistent "
268                                 "with %s:%d that follows from predecessor %d.",
269                                 block->GetBlockId(),
270                                 stored_try_entry.DebugName(),
271                                 stored_try_entry.GetId(),
272                                 incoming_try_entry->DebugName(),
273                                 incoming_try_entry->GetId(),
274                                 predecessor->GetBlockId()));
275         }
276       } else if (incoming_try_entry != nullptr) {
277         AddError(StringPrintf("Block %d is not a try block but try entry %s:%d follows "
278                               "from predecessor %d.",
279                               block->GetBlockId(),
280                               incoming_try_entry->DebugName(),
281                               incoming_try_entry->GetId(),
282                               predecessor->GetBlockId()));
283       }
284     }
285   }
286 
287   if (block->IsLoopHeader()) {
288     HandleLoop(block);
289   }
290 }
291 
VisitBoundsCheck(HBoundsCheck * check)292 void GraphChecker::VisitBoundsCheck(HBoundsCheck* check) {
293   if (!GetGraph()->HasBoundsChecks()) {
294     AddError(StringPrintf("Instruction %s:%d is a HBoundsCheck, "
295                           "but HasBoundsChecks() returns false",
296                           check->DebugName(),
297                           check->GetId()));
298   }
299 
300   // Perform the instruction base checks too.
301   VisitInstruction(check);
302 }
303 
VisitDeoptimize(HDeoptimize * deopt)304 void GraphChecker::VisitDeoptimize(HDeoptimize* deopt) {
305   if (GetGraph()->IsCompilingOsr()) {
306     AddError(StringPrintf("A graph compiled OSR cannot have a HDeoptimize instruction"));
307   }
308 
309   // Perform the instruction base checks too.
310   VisitInstruction(deopt);
311 }
312 
VisitTryBoundary(HTryBoundary * try_boundary)313 void GraphChecker::VisitTryBoundary(HTryBoundary* try_boundary) {
314   ArrayRef<HBasicBlock* const> handlers = try_boundary->GetExceptionHandlers();
315 
316   // Ensure that all exception handlers are catch blocks.
317   // Note that a normal-flow successor may be a catch block before CFG
318   // simplification. We only test normal-flow successors in GraphChecker.
319   for (HBasicBlock* handler : handlers) {
320     if (!handler->IsCatchBlock()) {
321       AddError(StringPrintf("Block %d with %s:%d has exceptional successor %d which "
322                             "is not a catch block.",
323                             current_block_->GetBlockId(),
324                             try_boundary->DebugName(),
325                             try_boundary->GetId(),
326                             handler->GetBlockId()));
327     }
328   }
329 
330   // Ensure that handlers are not listed multiple times.
331   for (size_t i = 0, e = handlers.size(); i < e; ++i) {
332     if (ContainsElement(handlers, handlers[i], i + 1)) {
333         AddError(StringPrintf("Exception handler block %d of %s:%d is listed multiple times.",
334                             handlers[i]->GetBlockId(),
335                             try_boundary->DebugName(),
336                             try_boundary->GetId()));
337     }
338   }
339 
340   VisitInstruction(try_boundary);
341 }
342 
VisitLoadException(HLoadException * load)343 void GraphChecker::VisitLoadException(HLoadException* load) {
344   // Ensure that LoadException is the first instruction in a catch block.
345   if (!load->GetBlock()->IsCatchBlock()) {
346     AddError(StringPrintf("%s:%d is in a non-catch block %d.",
347                           load->DebugName(),
348                           load->GetId(),
349                           load->GetBlock()->GetBlockId()));
350   } else if (load->GetBlock()->GetFirstInstruction() != load) {
351     AddError(StringPrintf("%s:%d is not the first instruction in catch block %d.",
352                           load->DebugName(),
353                           load->GetId(),
354                           load->GetBlock()->GetBlockId()));
355   }
356 }
357 
VisitInstruction(HInstruction * instruction)358 void GraphChecker::VisitInstruction(HInstruction* instruction) {
359   if (seen_ids_.IsBitSet(instruction->GetId())) {
360     AddError(StringPrintf("Instruction id %d is duplicate in graph.",
361                           instruction->GetId()));
362   } else {
363     seen_ids_.SetBit(instruction->GetId());
364   }
365 
366   // Ensure `instruction` is associated with `current_block_`.
367   if (instruction->GetBlock() == nullptr) {
368     AddError(StringPrintf("%s %d in block %d not associated with any block.",
369                           instruction->IsPhi() ? "Phi" : "Instruction",
370                           instruction->GetId(),
371                           current_block_->GetBlockId()));
372   } else if (instruction->GetBlock() != current_block_) {
373     AddError(StringPrintf("%s %d in block %d associated with block %d.",
374                           instruction->IsPhi() ? "Phi" : "Instruction",
375                           instruction->GetId(),
376                           current_block_->GetBlockId(),
377                           instruction->GetBlock()->GetBlockId()));
378   }
379 
380   // Ensure the inputs of `instruction` are defined in a block of the graph.
381   for (HInstruction* input : instruction->GetInputs()) {
382     if (input->GetBlock() == nullptr) {
383       AddError(StringPrintf("Input %d of instruction %d is not in any "
384                             "basic block of the control-flow graph.",
385                             input->GetId(),
386                             instruction->GetId()));
387     } else {
388       const HInstructionList& list = input->IsPhi()
389           ? input->GetBlock()->GetPhis()
390           : input->GetBlock()->GetInstructions();
391       if (!list.Contains(input)) {
392         AddError(StringPrintf("Input %d of instruction %d is not defined "
393                               "in a basic block of the control-flow graph.",
394                               input->GetId(),
395                               instruction->GetId()));
396       }
397     }
398   }
399 
400   // Ensure the uses of `instruction` are defined in a block of the graph,
401   // and the entry in the use list is consistent.
402   for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
403     HInstruction* user = use.GetUser();
404     const HInstructionList& list = user->IsPhi()
405         ? user->GetBlock()->GetPhis()
406         : user->GetBlock()->GetInstructions();
407     if (!list.Contains(user)) {
408       AddError(StringPrintf("User %s:%d of instruction %d is not defined "
409                             "in a basic block of the control-flow graph.",
410                             user->DebugName(),
411                             user->GetId(),
412                             instruction->GetId()));
413     }
414     size_t use_index = use.GetIndex();
415     HConstInputsRef user_inputs = user->GetInputs();
416     if ((use_index >= user_inputs.size()) || (user_inputs[use_index] != instruction)) {
417       AddError(StringPrintf("User %s:%d of instruction %s:%d has a wrong "
418                             "UseListNode index.",
419                             user->DebugName(),
420                             user->GetId(),
421                             instruction->DebugName(),
422                             instruction->GetId()));
423     }
424   }
425 
426   // Ensure the environment uses entries are consistent.
427   for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
428     HEnvironment* user = use.GetUser();
429     size_t use_index = use.GetIndex();
430     if ((use_index >= user->Size()) || (user->GetInstructionAt(use_index) != instruction)) {
431       AddError(StringPrintf("Environment user of %s:%d has a wrong "
432                             "UseListNode index.",
433                             instruction->DebugName(),
434                             instruction->GetId()));
435     }
436   }
437 
438   // Ensure 'instruction' has pointers to its inputs' use entries.
439   auto&& input_records = instruction->GetInputRecords();
440   for (size_t i = 0; i < input_records.size(); ++i) {
441     const HUserRecord<HInstruction*>& input_record = input_records[i];
442     HInstruction* input = input_record.GetInstruction();
443     if ((input_record.GetBeforeUseNode() == input->GetUses().end()) ||
444         (input_record.GetUseNode() == input->GetUses().end()) ||
445         !input->GetUses().ContainsNode(*input_record.GetUseNode()) ||
446         (input_record.GetUseNode()->GetIndex() != i)) {
447       AddError(StringPrintf("Instruction %s:%d has an invalid iterator before use entry "
448                             "at input %u (%s:%d).",
449                             instruction->DebugName(),
450                             instruction->GetId(),
451                             static_cast<unsigned>(i),
452                             input->DebugName(),
453                             input->GetId()));
454     }
455   }
456 
457   // Ensure an instruction dominates all its uses.
458   for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
459     HInstruction* user = use.GetUser();
460     if (!user->IsPhi() && !instruction->StrictlyDominates(user)) {
461       AddError(StringPrintf("Instruction %s:%d in block %d does not dominate "
462                             "use %s:%d in block %d.",
463                             instruction->DebugName(),
464                             instruction->GetId(),
465                             current_block_->GetBlockId(),
466                             user->DebugName(),
467                             user->GetId(),
468                             user->GetBlock()->GetBlockId()));
469     }
470   }
471 
472   if (instruction->NeedsEnvironment() && !instruction->HasEnvironment()) {
473     AddError(StringPrintf("Instruction %s:%d in block %d requires an environment "
474                           "but does not have one.",
475                           instruction->DebugName(),
476                           instruction->GetId(),
477                           current_block_->GetBlockId()));
478   }
479 
480   // Ensure an instruction having an environment is dominated by the
481   // instructions contained in the environment.
482   for (HEnvironment* environment = instruction->GetEnvironment();
483        environment != nullptr;
484        environment = environment->GetParent()) {
485     for (size_t i = 0, e = environment->Size(); i < e; ++i) {
486       HInstruction* env_instruction = environment->GetInstructionAt(i);
487       if (env_instruction != nullptr
488           && !env_instruction->StrictlyDominates(instruction)) {
489         AddError(StringPrintf("Instruction %d in environment of instruction %d "
490                               "from block %d does not dominate instruction %d.",
491                               env_instruction->GetId(),
492                               instruction->GetId(),
493                               current_block_->GetBlockId(),
494                               instruction->GetId()));
495       }
496     }
497   }
498 
499   // Ensure that reference type instructions have reference type info.
500   if (instruction->GetType() == DataType::Type::kReference) {
501     if (!instruction->GetReferenceTypeInfo().IsValid()) {
502       AddError(StringPrintf("Reference type instruction %s:%d does not have "
503                             "valid reference type information.",
504                             instruction->DebugName(),
505                             instruction->GetId()));
506     }
507   }
508 
509   if (instruction->CanThrowIntoCatchBlock()) {
510     // Find the top-level environment. This corresponds to the environment of
511     // the catch block since we do not inline methods with try/catch.
512     HEnvironment* environment = instruction->GetEnvironment();
513     while (environment->GetParent() != nullptr) {
514       environment = environment->GetParent();
515     }
516 
517     // Find all catch blocks and test that `instruction` has an environment
518     // value for each one.
519     const HTryBoundary& entry = instruction->GetBlock()->GetTryCatchInformation()->GetTryEntry();
520     for (HBasicBlock* catch_block : entry.GetExceptionHandlers()) {
521       for (HInstructionIterator phi_it(catch_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
522         HPhi* catch_phi = phi_it.Current()->AsPhi();
523         if (environment->GetInstructionAt(catch_phi->GetRegNumber()) == nullptr) {
524           AddError(StringPrintf("Instruction %s:%d throws into catch block %d "
525                                 "with catch phi %d for vreg %d but its "
526                                 "corresponding environment slot is empty.",
527                                 instruction->DebugName(),
528                                 instruction->GetId(),
529                                 catch_block->GetBlockId(),
530                                 catch_phi->GetId(),
531                                 catch_phi->GetRegNumber()));
532         }
533       }
534     }
535   }
536 }
537 
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)538 void GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
539   VisitInstruction(invoke);
540 
541   if (invoke->IsStaticWithExplicitClinitCheck()) {
542     const HInstruction* last_input = invoke->GetInputs().back();
543     if (last_input == nullptr) {
544       AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
545                             "has a null pointer as last input.",
546                             invoke->DebugName(),
547                             invoke->GetId()));
548     } else if (!last_input->IsClinitCheck() && !last_input->IsLoadClass()) {
549       AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
550                             "has a last instruction (%s:%d) which is neither a clinit check "
551                             "nor a load class instruction.",
552                             invoke->DebugName(),
553                             invoke->GetId(),
554                             last_input->DebugName(),
555                             last_input->GetId()));
556     }
557   }
558 }
559 
VisitReturn(HReturn * ret)560 void GraphChecker::VisitReturn(HReturn* ret) {
561   VisitInstruction(ret);
562   HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor();
563   if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) {
564     AddError(StringPrintf("%s:%d does not jump to the exit block.",
565                           ret->DebugName(),
566                           ret->GetId()));
567   }
568 }
569 
VisitReturnVoid(HReturnVoid * ret)570 void GraphChecker::VisitReturnVoid(HReturnVoid* ret) {
571   VisitInstruction(ret);
572   HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor();
573   if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) {
574     AddError(StringPrintf("%s:%d does not jump to the exit block.",
575                           ret->DebugName(),
576                           ret->GetId()));
577   }
578 }
579 
CheckTypeCheckBitstringInput(HTypeCheckInstruction * check,size_t input_pos,bool check_value,uint32_t expected_value,const char * name)580 void GraphChecker::CheckTypeCheckBitstringInput(HTypeCheckInstruction* check,
581                                                 size_t input_pos,
582                                                 bool check_value,
583                                                 uint32_t expected_value,
584                                                 const char* name) {
585   if (!check->InputAt(input_pos)->IsIntConstant()) {
586     AddError(StringPrintf("%s:%d (bitstring) expects a HIntConstant input %zu (%s), not %s:%d.",
587                           check->DebugName(),
588                           check->GetId(),
589                           input_pos,
590                           name,
591                           check->InputAt(2)->DebugName(),
592                           check->InputAt(2)->GetId()));
593   } else if (check_value) {
594     uint32_t actual_value =
595         static_cast<uint32_t>(check->InputAt(input_pos)->AsIntConstant()->GetValue());
596     if (actual_value != expected_value) {
597       AddError(StringPrintf("%s:%d (bitstring) has %s 0x%x, not 0x%x as expected.",
598                             check->DebugName(),
599                             check->GetId(),
600                             name,
601                             actual_value,
602                             expected_value));
603     }
604   }
605 }
606 
HandleTypeCheckInstruction(HTypeCheckInstruction * check)607 void GraphChecker::HandleTypeCheckInstruction(HTypeCheckInstruction* check) {
608   VisitInstruction(check);
609   HInstruction* input = check->InputAt(1);
610   if (check->GetTypeCheckKind() == TypeCheckKind::kBitstringCheck) {
611     if (!input->IsNullConstant()) {
612       AddError(StringPrintf("%s:%d (bitstring) expects a HNullConstant as second input, not %s:%d.",
613                             check->DebugName(),
614                             check->GetId(),
615                             input->DebugName(),
616                             input->GetId()));
617     }
618     bool check_values = false;
619     BitString::StorageType expected_path_to_root = 0u;
620     BitString::StorageType expected_mask = 0u;
621     {
622       ScopedObjectAccess soa(Thread::Current());
623       ObjPtr<mirror::Class> klass = check->GetClass().Get();
624       MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
625       SubtypeCheckInfo::State state = SubtypeCheck<ObjPtr<mirror::Class>>::GetState(klass);
626       if (state == SubtypeCheckInfo::kAssigned) {
627         expected_path_to_root =
628             SubtypeCheck<ObjPtr<mirror::Class>>::GetEncodedPathToRootForTarget(klass);
629         expected_mask = SubtypeCheck<ObjPtr<mirror::Class>>::GetEncodedPathToRootMask(klass);
630         check_values = true;
631       } else {
632         AddError(StringPrintf("%s:%d (bitstring) references a class with unassigned bitstring.",
633                               check->DebugName(),
634                               check->GetId()));
635       }
636     }
637     CheckTypeCheckBitstringInput(
638         check, /* input_pos= */ 2, check_values, expected_path_to_root, "path_to_root");
639     CheckTypeCheckBitstringInput(check, /* input_pos= */ 3, check_values, expected_mask, "mask");
640   } else {
641     if (!input->IsLoadClass()) {
642       AddError(StringPrintf("%s:%d (classic) expects a HLoadClass as second input, not %s:%d.",
643                             check->DebugName(),
644                             check->GetId(),
645                             input->DebugName(),
646                             input->GetId()));
647     }
648   }
649 }
650 
VisitCheckCast(HCheckCast * check)651 void GraphChecker::VisitCheckCast(HCheckCast* check) {
652   HandleTypeCheckInstruction(check);
653 }
654 
VisitInstanceOf(HInstanceOf * instruction)655 void GraphChecker::VisitInstanceOf(HInstanceOf* instruction) {
656   HandleTypeCheckInstruction(instruction);
657 }
658 
HandleLoop(HBasicBlock * loop_header)659 void GraphChecker::HandleLoop(HBasicBlock* loop_header) {
660   int id = loop_header->GetBlockId();
661   HLoopInformation* loop_information = loop_header->GetLoopInformation();
662 
663   if (loop_information->GetPreHeader()->GetSuccessors().size() != 1) {
664     AddError(StringPrintf(
665         "Loop pre-header %d of loop defined by header %d has %zu successors.",
666         loop_information->GetPreHeader()->GetBlockId(),
667         id,
668         loop_information->GetPreHeader()->GetSuccessors().size()));
669   }
670 
671   if (loop_information->GetSuspendCheck() == nullptr) {
672     AddError(StringPrintf(
673         "Loop with header %d does not have a suspend check.",
674         loop_header->GetBlockId()));
675   }
676 
677   if (loop_information->GetSuspendCheck() != loop_header->GetFirstInstructionDisregardMoves()) {
678     AddError(StringPrintf(
679         "Loop header %d does not have the loop suspend check as the first instruction.",
680         loop_header->GetBlockId()));
681   }
682 
683   // Ensure the loop header has only one incoming branch and the remaining
684   // predecessors are back edges.
685   size_t num_preds = loop_header->GetPredecessors().size();
686   if (num_preds < 2) {
687     AddError(StringPrintf(
688         "Loop header %d has less than two predecessors: %zu.",
689         id,
690         num_preds));
691   } else {
692     HBasicBlock* first_predecessor = loop_header->GetPredecessors()[0];
693     if (loop_information->IsBackEdge(*first_predecessor)) {
694       AddError(StringPrintf(
695           "First predecessor of loop header %d is a back edge.",
696           id));
697     }
698     for (size_t i = 1, e = loop_header->GetPredecessors().size(); i < e; ++i) {
699       HBasicBlock* predecessor = loop_header->GetPredecessors()[i];
700       if (!loop_information->IsBackEdge(*predecessor)) {
701         AddError(StringPrintf(
702             "Loop header %d has multiple incoming (non back edge) blocks: %d.",
703             id,
704             predecessor->GetBlockId()));
705       }
706     }
707   }
708 
709   const ArenaBitVector& loop_blocks = loop_information->GetBlocks();
710 
711   // Ensure back edges belong to the loop.
712   if (loop_information->NumberOfBackEdges() == 0) {
713     AddError(StringPrintf(
714         "Loop defined by header %d has no back edge.",
715         id));
716   } else {
717     for (HBasicBlock* back_edge : loop_information->GetBackEdges()) {
718       int back_edge_id = back_edge->GetBlockId();
719       if (!loop_blocks.IsBitSet(back_edge_id)) {
720         AddError(StringPrintf(
721             "Loop defined by header %d has an invalid back edge %d.",
722             id,
723             back_edge_id));
724       } else if (back_edge->GetLoopInformation() != loop_information) {
725         AddError(StringPrintf(
726             "Back edge %d of loop defined by header %d belongs to nested loop "
727             "with header %d.",
728             back_edge_id,
729             id,
730             back_edge->GetLoopInformation()->GetHeader()->GetBlockId()));
731       }
732     }
733   }
734 
735   // If this is a nested loop, ensure the outer loops contain a superset of the blocks.
736   for (HLoopInformationOutwardIterator it(*loop_header); !it.Done(); it.Advance()) {
737     HLoopInformation* outer_info = it.Current();
738     if (!loop_blocks.IsSubsetOf(&outer_info->GetBlocks())) {
739       AddError(StringPrintf("Blocks of loop defined by header %d are not a subset of blocks of "
740                             "an outer loop defined by header %d.",
741                             id,
742                             outer_info->GetHeader()->GetBlockId()));
743     }
744   }
745 
746   // Ensure the pre-header block is first in the list of predecessors of a loop
747   // header and that the header block is its only successor.
748   if (!loop_header->IsLoopPreHeaderFirstPredecessor()) {
749     AddError(StringPrintf(
750         "Loop pre-header is not the first predecessor of the loop header %d.",
751         id));
752   }
753 
754   // Ensure all blocks in the loop are live and dominated by the loop header in
755   // the case of natural loops.
756   for (uint32_t i : loop_blocks.Indexes()) {
757     HBasicBlock* loop_block = GetGraph()->GetBlocks()[i];
758     if (loop_block == nullptr) {
759       AddError(StringPrintf("Loop defined by header %d contains a previously removed block %d.",
760                             id,
761                             i));
762     } else if (!loop_information->IsIrreducible() && !loop_header->Dominates(loop_block)) {
763       AddError(StringPrintf("Loop block %d not dominated by loop header %d.",
764                             i,
765                             id));
766     }
767   }
768 }
769 
IsSameSizeConstant(const HInstruction * insn1,const HInstruction * insn2)770 static bool IsSameSizeConstant(const HInstruction* insn1, const HInstruction* insn2) {
771   return insn1->IsConstant()
772       && insn2->IsConstant()
773       && DataType::Is64BitType(insn1->GetType()) == DataType::Is64BitType(insn2->GetType());
774 }
775 
IsConstantEquivalent(const HInstruction * insn1,const HInstruction * insn2,BitVector * visited)776 static bool IsConstantEquivalent(const HInstruction* insn1,
777                                  const HInstruction* insn2,
778                                  BitVector* visited) {
779   if (insn1->IsPhi() &&
780       insn1->AsPhi()->IsVRegEquivalentOf(insn2)) {
781     HConstInputsRef insn1_inputs = insn1->GetInputs();
782     HConstInputsRef insn2_inputs = insn2->GetInputs();
783     if (insn1_inputs.size() != insn2_inputs.size()) {
784       return false;
785     }
786 
787     // Testing only one of the two inputs for recursion is sufficient.
788     if (visited->IsBitSet(insn1->GetId())) {
789       return true;
790     }
791     visited->SetBit(insn1->GetId());
792 
793     for (size_t i = 0; i < insn1_inputs.size(); ++i) {
794       if (!IsConstantEquivalent(insn1_inputs[i], insn2_inputs[i], visited)) {
795         return false;
796       }
797     }
798     return true;
799   } else if (IsSameSizeConstant(insn1, insn2)) {
800     return insn1->AsConstant()->GetValueAsUint64() == insn2->AsConstant()->GetValueAsUint64();
801   } else {
802     return false;
803   }
804 }
805 
VisitPhi(HPhi * phi)806 void GraphChecker::VisitPhi(HPhi* phi) {
807   VisitInstruction(phi);
808 
809   // Ensure the first input of a phi is not itself.
810   ArrayRef<HUserRecord<HInstruction*>> input_records = phi->GetInputRecords();
811   if (input_records[0].GetInstruction() == phi) {
812     AddError(StringPrintf("Loop phi %d in block %d is its own first input.",
813                           phi->GetId(),
814                           phi->GetBlock()->GetBlockId()));
815   }
816 
817   // Ensure that the inputs have the same primitive kind as the phi.
818   for (size_t i = 0; i < input_records.size(); ++i) {
819     HInstruction* input = input_records[i].GetInstruction();
820     if (DataType::Kind(input->GetType()) != DataType::Kind(phi->GetType())) {
821         AddError(StringPrintf(
822             "Input %d at index %zu of phi %d from block %d does not have the "
823             "same kind as the phi: %s versus %s",
824             input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
825             DataType::PrettyDescriptor(input->GetType()),
826             DataType::PrettyDescriptor(phi->GetType())));
827     }
828   }
829   if (phi->GetType() != HPhi::ToPhiType(phi->GetType())) {
830     AddError(StringPrintf("Phi %d in block %d does not have an expected phi type: %s",
831                           phi->GetId(),
832                           phi->GetBlock()->GetBlockId(),
833                           DataType::PrettyDescriptor(phi->GetType())));
834   }
835 
836   if (phi->IsCatchPhi()) {
837     // The number of inputs of a catch phi should be the total number of throwing
838     // instructions caught by this catch block. We do not enforce this, however,
839     // because we do not remove the corresponding inputs when we prove that an
840     // instruction cannot throw. Instead, we at least test that all phis have the
841     // same, non-zero number of inputs (b/24054676).
842     if (input_records.empty()) {
843       AddError(StringPrintf("Phi %d in catch block %d has zero inputs.",
844                             phi->GetId(),
845                             phi->GetBlock()->GetBlockId()));
846     } else {
847       HInstruction* next_phi = phi->GetNext();
848       if (next_phi != nullptr) {
849         size_t input_count_next = next_phi->InputCount();
850         if (input_records.size() != input_count_next) {
851           AddError(StringPrintf("Phi %d in catch block %d has %zu inputs, "
852                                 "but phi %d has %zu inputs.",
853                                 phi->GetId(),
854                                 phi->GetBlock()->GetBlockId(),
855                                 input_records.size(),
856                                 next_phi->GetId(),
857                                 input_count_next));
858         }
859       }
860     }
861   } else {
862     // Ensure the number of inputs of a non-catch phi is the same as the number
863     // of its predecessors.
864     const ArenaVector<HBasicBlock*>& predecessors = phi->GetBlock()->GetPredecessors();
865     if (input_records.size() != predecessors.size()) {
866       AddError(StringPrintf(
867           "Phi %d in block %d has %zu inputs, "
868           "but block %d has %zu predecessors.",
869           phi->GetId(), phi->GetBlock()->GetBlockId(), input_records.size(),
870           phi->GetBlock()->GetBlockId(), predecessors.size()));
871     } else {
872       // Ensure phi input at index I either comes from the Ith
873       // predecessor or from a block that dominates this predecessor.
874       for (size_t i = 0; i < input_records.size(); ++i) {
875         HInstruction* input = input_records[i].GetInstruction();
876         HBasicBlock* predecessor = predecessors[i];
877         if (!(input->GetBlock() == predecessor
878               || input->GetBlock()->Dominates(predecessor))) {
879           AddError(StringPrintf(
880               "Input %d at index %zu of phi %d from block %d is not defined in "
881               "predecessor number %zu nor in a block dominating it.",
882               input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
883               i));
884         }
885       }
886     }
887   }
888 
889   // Ensure that catch phis are sorted by their vreg number, as required by
890   // the register allocator and code generator. This does not apply to normal
891   // phis which can be constructed artifically.
892   if (phi->IsCatchPhi()) {
893     HInstruction* next_phi = phi->GetNext();
894     if (next_phi != nullptr && phi->GetRegNumber() > next_phi->AsPhi()->GetRegNumber()) {
895       AddError(StringPrintf("Catch phis %d and %d in block %d are not sorted by their "
896                             "vreg numbers.",
897                             phi->GetId(),
898                             next_phi->GetId(),
899                             phi->GetBlock()->GetBlockId()));
900     }
901   }
902 
903   // Test phi equivalents. There should not be two of the same type and they should only be
904   // created for constants which were untyped in DEX. Note that this test can be skipped for
905   // a synthetic phi (indicated by lack of a virtual register).
906   if (phi->GetRegNumber() != kNoRegNumber) {
907     for (HInstructionIterator phi_it(phi->GetBlock()->GetPhis());
908          !phi_it.Done();
909          phi_it.Advance()) {
910       HPhi* other_phi = phi_it.Current()->AsPhi();
911       if (phi != other_phi && phi->GetRegNumber() == other_phi->GetRegNumber()) {
912         if (phi->GetType() == other_phi->GetType()) {
913           std::stringstream type_str;
914           type_str << phi->GetType();
915           AddError(StringPrintf("Equivalent phi (%d) found for VReg %d with type: %s.",
916                                 phi->GetId(),
917                                 phi->GetRegNumber(),
918                                 type_str.str().c_str()));
919         } else if (phi->GetType() == DataType::Type::kReference) {
920           std::stringstream type_str;
921           type_str << other_phi->GetType();
922           AddError(StringPrintf(
923               "Equivalent non-reference phi (%d) found for VReg %d with type: %s.",
924               phi->GetId(),
925               phi->GetRegNumber(),
926               type_str.str().c_str()));
927         } else {
928           // Use local allocator for allocating memory.
929           ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
930           // If we get here, make sure we allocate all the necessary storage at once
931           // because the BitVector reallocation strategy has very bad worst-case behavior.
932           ArenaBitVector visited(&allocator,
933                                  GetGraph()->GetCurrentInstructionId(),
934                                  /* expandable= */ false,
935                                  kArenaAllocGraphChecker);
936           visited.ClearAllBits();
937           if (!IsConstantEquivalent(phi, other_phi, &visited)) {
938             AddError(StringPrintf("Two phis (%d and %d) found for VReg %d but they "
939                                   "are not equivalents of constants.",
940                                   phi->GetId(),
941                                   other_phi->GetId(),
942                                   phi->GetRegNumber()));
943           }
944         }
945       }
946     }
947   }
948 }
949 
HandleBooleanInput(HInstruction * instruction,size_t input_index)950 void GraphChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) {
951   HInstruction* input = instruction->InputAt(input_index);
952   if (input->IsIntConstant()) {
953     int32_t value = input->AsIntConstant()->GetValue();
954     if (value != 0 && value != 1) {
955       AddError(StringPrintf(
956           "%s instruction %d has a non-Boolean constant input %d whose value is: %d.",
957           instruction->DebugName(),
958           instruction->GetId(),
959           static_cast<int>(input_index),
960           value));
961     }
962   } else if (DataType::Kind(input->GetType()) != DataType::Type::kInt32) {
963     // TODO: We need a data-flow analysis to determine if an input like Phi,
964     //       Select or a binary operation is actually Boolean. Allow for now.
965     AddError(StringPrintf(
966         "%s instruction %d has a non-integer input %d whose type is: %s.",
967         instruction->DebugName(),
968         instruction->GetId(),
969         static_cast<int>(input_index),
970         DataType::PrettyDescriptor(input->GetType())));
971   }
972 }
973 
VisitPackedSwitch(HPackedSwitch * instruction)974 void GraphChecker::VisitPackedSwitch(HPackedSwitch* instruction) {
975   VisitInstruction(instruction);
976   // Check that the number of block successors matches the switch count plus
977   // one for the default block.
978   HBasicBlock* block = instruction->GetBlock();
979   if (instruction->GetNumEntries() + 1u != block->GetSuccessors().size()) {
980     AddError(StringPrintf(
981         "%s instruction %d in block %d expects %u successors to the block, but found: %zu.",
982         instruction->DebugName(),
983         instruction->GetId(),
984         block->GetBlockId(),
985         instruction->GetNumEntries() + 1u,
986         block->GetSuccessors().size()));
987   }
988 }
989 
VisitIf(HIf * instruction)990 void GraphChecker::VisitIf(HIf* instruction) {
991   VisitInstruction(instruction);
992   HandleBooleanInput(instruction, 0);
993 }
994 
VisitSelect(HSelect * instruction)995 void GraphChecker::VisitSelect(HSelect* instruction) {
996   VisitInstruction(instruction);
997   HandleBooleanInput(instruction, 2);
998 }
999 
VisitBooleanNot(HBooleanNot * instruction)1000 void GraphChecker::VisitBooleanNot(HBooleanNot* instruction) {
1001   VisitInstruction(instruction);
1002   HandleBooleanInput(instruction, 0);
1003 }
1004 
VisitCondition(HCondition * op)1005 void GraphChecker::VisitCondition(HCondition* op) {
1006   VisitInstruction(op);
1007   if (op->GetType() != DataType::Type::kBool) {
1008     AddError(StringPrintf(
1009         "Condition %s %d has a non-Boolean result type: %s.",
1010         op->DebugName(), op->GetId(),
1011         DataType::PrettyDescriptor(op->GetType())));
1012   }
1013   HInstruction* lhs = op->InputAt(0);
1014   HInstruction* rhs = op->InputAt(1);
1015   if (DataType::Kind(lhs->GetType()) != DataType::Kind(rhs->GetType())) {
1016     AddError(StringPrintf(
1017         "Condition %s %d has inputs of different kinds: %s, and %s.",
1018         op->DebugName(), op->GetId(),
1019         DataType::PrettyDescriptor(lhs->GetType()),
1020         DataType::PrettyDescriptor(rhs->GetType())));
1021   }
1022   if (!op->IsEqual() && !op->IsNotEqual()) {
1023     if ((lhs->GetType() == DataType::Type::kReference)) {
1024       AddError(StringPrintf(
1025           "Condition %s %d uses an object as left-hand side input.",
1026           op->DebugName(), op->GetId()));
1027     } else if (rhs->GetType() == DataType::Type::kReference) {
1028       AddError(StringPrintf(
1029           "Condition %s %d uses an object as right-hand side input.",
1030           op->DebugName(), op->GetId()));
1031     }
1032   }
1033 }
1034 
VisitNeg(HNeg * instruction)1035 void GraphChecker::VisitNeg(HNeg* instruction) {
1036   VisitInstruction(instruction);
1037   DataType::Type input_type = instruction->InputAt(0)->GetType();
1038   DataType::Type result_type = instruction->GetType();
1039   if (result_type != DataType::Kind(input_type)) {
1040     AddError(StringPrintf("Binary operation %s %d has a result type different "
1041                           "from its input kind: %s vs %s.",
1042                           instruction->DebugName(), instruction->GetId(),
1043                           DataType::PrettyDescriptor(result_type),
1044                           DataType::PrettyDescriptor(input_type)));
1045   }
1046 }
1047 
VisitBinaryOperation(HBinaryOperation * op)1048 void GraphChecker::VisitBinaryOperation(HBinaryOperation* op) {
1049   VisitInstruction(op);
1050   DataType::Type lhs_type = op->InputAt(0)->GetType();
1051   DataType::Type rhs_type = op->InputAt(1)->GetType();
1052   DataType::Type result_type = op->GetType();
1053 
1054   // Type consistency between inputs.
1055   if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
1056     if (DataType::Kind(rhs_type) != DataType::Type::kInt32) {
1057       AddError(StringPrintf("Shift/rotate operation %s %d has a non-int kind second input: "
1058                             "%s of type %s.",
1059                             op->DebugName(), op->GetId(),
1060                             op->InputAt(1)->DebugName(),
1061                             DataType::PrettyDescriptor(rhs_type)));
1062     }
1063   } else {
1064     if (DataType::Kind(lhs_type) != DataType::Kind(rhs_type)) {
1065       AddError(StringPrintf("Binary operation %s %d has inputs of different kinds: %s, and %s.",
1066                             op->DebugName(), op->GetId(),
1067                             DataType::PrettyDescriptor(lhs_type),
1068                             DataType::PrettyDescriptor(rhs_type)));
1069     }
1070   }
1071 
1072   // Type consistency between result and input(s).
1073   if (op->IsCompare()) {
1074     if (result_type != DataType::Type::kInt32) {
1075       AddError(StringPrintf("Compare operation %d has a non-int result type: %s.",
1076                             op->GetId(),
1077                             DataType::PrettyDescriptor(result_type)));
1078     }
1079   } else if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
1080     // Only check the first input (value), as the second one (distance)
1081     // must invariably be of kind `int`.
1082     if (result_type != DataType::Kind(lhs_type)) {
1083       AddError(StringPrintf("Shift/rotate operation %s %d has a result type different "
1084                             "from its left-hand side (value) input kind: %s vs %s.",
1085                             op->DebugName(), op->GetId(),
1086                             DataType::PrettyDescriptor(result_type),
1087                             DataType::PrettyDescriptor(lhs_type)));
1088     }
1089   } else {
1090     if (DataType::Kind(result_type) != DataType::Kind(lhs_type)) {
1091       AddError(StringPrintf("Binary operation %s %d has a result kind different "
1092                             "from its left-hand side input kind: %s vs %s.",
1093                             op->DebugName(), op->GetId(),
1094                             DataType::PrettyDescriptor(result_type),
1095                             DataType::PrettyDescriptor(lhs_type)));
1096     }
1097     if (DataType::Kind(result_type) != DataType::Kind(rhs_type)) {
1098       AddError(StringPrintf("Binary operation %s %d has a result kind different "
1099                             "from its right-hand side input kind: %s vs %s.",
1100                             op->DebugName(), op->GetId(),
1101                             DataType::PrettyDescriptor(result_type),
1102                             DataType::PrettyDescriptor(rhs_type)));
1103     }
1104   }
1105 }
1106 
VisitConstant(HConstant * instruction)1107 void GraphChecker::VisitConstant(HConstant* instruction) {
1108   HBasicBlock* block = instruction->GetBlock();
1109   if (!block->IsEntryBlock()) {
1110     AddError(StringPrintf(
1111         "%s %d should be in the entry block but is in block %d.",
1112         instruction->DebugName(),
1113         instruction->GetId(),
1114         block->GetBlockId()));
1115   }
1116 }
1117 
VisitBoundType(HBoundType * instruction)1118 void GraphChecker::VisitBoundType(HBoundType* instruction) {
1119   VisitInstruction(instruction);
1120 
1121   if (!instruction->GetUpperBound().IsValid()) {
1122     AddError(StringPrintf(
1123         "%s %d does not have a valid upper bound RTI.",
1124         instruction->DebugName(),
1125         instruction->GetId()));
1126   }
1127 }
1128 
VisitTypeConversion(HTypeConversion * instruction)1129 void GraphChecker::VisitTypeConversion(HTypeConversion* instruction) {
1130   VisitInstruction(instruction);
1131   DataType::Type result_type = instruction->GetResultType();
1132   DataType::Type input_type = instruction->GetInputType();
1133   // Invariant: We should never generate a conversion to a Boolean value.
1134   if (result_type == DataType::Type::kBool) {
1135     AddError(StringPrintf(
1136         "%s %d converts to a %s (from a %s).",
1137         instruction->DebugName(),
1138         instruction->GetId(),
1139         DataType::PrettyDescriptor(result_type),
1140         DataType::PrettyDescriptor(input_type)));
1141   }
1142 }
1143 
1144 }  // namespace art
1145