Home | History | Annotate | Download | only in optimizing
      1 /*
      2  *
      3  * Copyright (C) 2014 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 #include "builder.h"
     19 
     20 #include "class_linker.h"
     21 #include "dex_file.h"
     22 #include "dex_file-inl.h"
     23 #include "dex_instruction.h"
     24 #include "dex_instruction-inl.h"
     25 #include "driver/compiler_driver-inl.h"
     26 #include "mirror/art_field.h"
     27 #include "mirror/art_field-inl.h"
     28 #include "mirror/class_loader.h"
     29 #include "mirror/dex_cache.h"
     30 #include "nodes.h"
     31 #include "primitive.h"
     32 #include "scoped_thread_state_change.h"
     33 #include "thread.h"
     34 
     35 namespace art {
     36 
     37 /**
     38  * Helper class to add HTemporary instructions. This class is used when
     39  * converting a DEX instruction to multiple HInstruction, and where those
     40  * instructions do not die at the following instruction, but instead spans
     41  * multiple instructions.
     42  */
     43 class Temporaries : public ValueObject {
     44  public:
     45   Temporaries(HGraph* graph, size_t count) : graph_(graph), count_(count), index_(0) {
     46     graph_->UpdateNumberOfTemporaries(count_);
     47   }
     48 
     49   void Add(HInstruction* instruction) {
     50     // We currently only support vreg size temps.
     51     DCHECK(instruction->GetType() != Primitive::kPrimLong
     52            && instruction->GetType() != Primitive::kPrimDouble);
     53     HInstruction* temp = new (graph_->GetArena()) HTemporary(index_++);
     54     instruction->GetBlock()->AddInstruction(temp);
     55     DCHECK(temp->GetPrevious() == instruction);
     56   }
     57 
     58  private:
     59   HGraph* const graph_;
     60 
     61   // The total number of temporaries that will be used.
     62   const size_t count_;
     63 
     64   // Current index in the temporary stack, updated by `Add`.
     65   size_t index_;
     66 };
     67 
     68 static bool IsTypeSupported(Primitive::Type type) {
     69   return type != Primitive::kPrimFloat && type != Primitive::kPrimDouble;
     70 }
     71 
     72 void HGraphBuilder::InitializeLocals(uint16_t count) {
     73   graph_->SetNumberOfVRegs(count);
     74   locals_.SetSize(count);
     75   for (int i = 0; i < count; i++) {
     76     HLocal* local = new (arena_) HLocal(i);
     77     entry_block_->AddInstruction(local);
     78     locals_.Put(i, local);
     79   }
     80 }
     81 
     82 bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) {
     83   // dex_compilation_unit_ is null only when unit testing.
     84   if (dex_compilation_unit_ == nullptr) {
     85     return true;
     86   }
     87 
     88   graph_->SetNumberOfInVRegs(number_of_parameters);
     89   const char* shorty = dex_compilation_unit_->GetShorty();
     90   int locals_index = locals_.Size() - number_of_parameters;
     91   int parameter_index = 0;
     92 
     93   if (!dex_compilation_unit_->IsStatic()) {
     94     // Add the implicit 'this' argument, not expressed in the signature.
     95     HParameterValue* parameter =
     96         new (arena_) HParameterValue(parameter_index++, Primitive::kPrimNot);
     97     entry_block_->AddInstruction(parameter);
     98     HLocal* local = GetLocalAt(locals_index++);
     99     entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
    100     number_of_parameters--;
    101   }
    102 
    103   uint32_t pos = 1;
    104   for (int i = 0; i < number_of_parameters; i++) {
    105     switch (shorty[pos++]) {
    106       case 'F':
    107       case 'D': {
    108         return false;
    109       }
    110 
    111       default: {
    112         // integer and reference parameters.
    113         HParameterValue* parameter =
    114             new (arena_) HParameterValue(parameter_index++, Primitive::GetType(shorty[pos - 1]));
    115         entry_block_->AddInstruction(parameter);
    116         HLocal* local = GetLocalAt(locals_index++);
    117         // Store the parameter value in the local that the dex code will use
    118         // to reference that parameter.
    119         entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
    120         if (parameter->GetType() == Primitive::kPrimLong) {
    121           i++;
    122           locals_index++;
    123           parameter_index++;
    124         }
    125         break;
    126       }
    127     }
    128   }
    129   return true;
    130 }
    131 
    132 static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
    133   if (code_item.tries_size_ > 0) {
    134     return false;
    135   }
    136   return true;
    137 }
    138 
    139 template<typename T>
    140 void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_offset) {
    141   HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
    142   HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
    143   T* comparison = new (arena_) T(first, second);
    144   current_block_->AddInstruction(comparison);
    145   HInstruction* ifinst = new (arena_) HIf(comparison);
    146   current_block_->AddInstruction(ifinst);
    147   HBasicBlock* target = FindBlockStartingAt(dex_offset + instruction.GetTargetOffset());
    148   DCHECK(target != nullptr);
    149   current_block_->AddSuccessor(target);
    150   target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
    151   DCHECK(target != nullptr);
    152   current_block_->AddSuccessor(target);
    153   current_block_ = nullptr;
    154 }
    155 
    156 template<typename T>
    157 void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_offset) {
    158   HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
    159   T* comparison = new (arena_) T(value, GetIntConstant(0));
    160   current_block_->AddInstruction(comparison);
    161   HInstruction* ifinst = new (arena_) HIf(comparison);
    162   current_block_->AddInstruction(ifinst);
    163   HBasicBlock* target = FindBlockStartingAt(dex_offset + instruction.GetTargetOffset());
    164   DCHECK(target != nullptr);
    165   current_block_->AddSuccessor(target);
    166   target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
    167   DCHECK(target != nullptr);
    168   current_block_->AddSuccessor(target);
    169   current_block_ = nullptr;
    170 }
    171 
    172 HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
    173   if (!CanHandleCodeItem(code_item)) {
    174     return nullptr;
    175   }
    176 
    177   const uint16_t* code_ptr = code_item.insns_;
    178   const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
    179 
    180   // Setup the graph with the entry block and exit block.
    181   graph_ = new (arena_) HGraph(arena_);
    182   entry_block_ = new (arena_) HBasicBlock(graph_);
    183   graph_->AddBlock(entry_block_);
    184   exit_block_ = new (arena_) HBasicBlock(graph_);
    185   graph_->SetEntryBlock(entry_block_);
    186   graph_->SetExitBlock(exit_block_);
    187 
    188   InitializeLocals(code_item.registers_size_);
    189   graph_->UpdateMaximumNumberOfOutVRegs(code_item.outs_size_);
    190 
    191   // To avoid splitting blocks, we compute ahead of time the instructions that
    192   // start a new block, and create these blocks.
    193   ComputeBranchTargets(code_ptr, code_end);
    194 
    195   if (!InitializeParameters(code_item.ins_size_)) {
    196     return nullptr;
    197   }
    198 
    199   size_t dex_offset = 0;
    200   while (code_ptr < code_end) {
    201     // Update the current block if dex_offset starts a new block.
    202     MaybeUpdateCurrentBlock(dex_offset);
    203     const Instruction& instruction = *Instruction::At(code_ptr);
    204     if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
    205     dex_offset += instruction.SizeInCodeUnits();
    206     code_ptr += instruction.SizeInCodeUnits();
    207   }
    208 
    209   // Add the exit block at the end to give it the highest id.
    210   graph_->AddBlock(exit_block_);
    211   exit_block_->AddInstruction(new (arena_) HExit());
    212   entry_block_->AddInstruction(new (arena_) HGoto());
    213   return graph_;
    214 }
    215 
    216 void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
    217   HBasicBlock* block = FindBlockStartingAt(index);
    218   if (block == nullptr) {
    219     return;
    220   }
    221 
    222   if (current_block_ != nullptr) {
    223     // Branching instructions clear current_block, so we know
    224     // the last instruction of the current block is not a branching
    225     // instruction. We add an unconditional goto to the found block.
    226     current_block_->AddInstruction(new (arena_) HGoto());
    227     current_block_->AddSuccessor(block);
    228   }
    229   graph_->AddBlock(block);
    230   current_block_ = block;
    231 }
    232 
    233 void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
    234   // TODO: Support switch instructions.
    235   branch_targets_.SetSize(code_end - code_ptr);
    236 
    237   // Create the first block for the dex instructions, single successor of the entry block.
    238   HBasicBlock* block = new (arena_) HBasicBlock(graph_);
    239   branch_targets_.Put(0, block);
    240   entry_block_->AddSuccessor(block);
    241 
    242   // Iterate over all instructions and find branching instructions. Create blocks for
    243   // the locations these instructions branch to.
    244   size_t dex_offset = 0;
    245   while (code_ptr < code_end) {
    246     const Instruction& instruction = *Instruction::At(code_ptr);
    247     if (instruction.IsBranch()) {
    248       int32_t target = instruction.GetTargetOffset() + dex_offset;
    249       // Create a block for the target instruction.
    250       if (FindBlockStartingAt(target) == nullptr) {
    251         block = new (arena_) HBasicBlock(graph_);
    252         branch_targets_.Put(target, block);
    253       }
    254       dex_offset += instruction.SizeInCodeUnits();
    255       code_ptr += instruction.SizeInCodeUnits();
    256       if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
    257         block = new (arena_) HBasicBlock(graph_);
    258         branch_targets_.Put(dex_offset, block);
    259       }
    260     } else {
    261       code_ptr += instruction.SizeInCodeUnits();
    262       dex_offset += instruction.SizeInCodeUnits();
    263     }
    264   }
    265 }
    266 
    267 HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
    268   DCHECK_GE(index, 0);
    269   return branch_targets_.Get(index);
    270 }
    271 
    272 template<typename T>
    273 void HGraphBuilder::Binop_23x(const Instruction& instruction, Primitive::Type type) {
    274   HInstruction* first = LoadLocal(instruction.VRegB(), type);
    275   HInstruction* second = LoadLocal(instruction.VRegC(), type);
    276   current_block_->AddInstruction(new (arena_) T(type, first, second));
    277   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
    278 }
    279 
    280 template<typename T>
    281 void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type) {
    282   HInstruction* first = LoadLocal(instruction.VRegA(), type);
    283   HInstruction* second = LoadLocal(instruction.VRegB(), type);
    284   current_block_->AddInstruction(new (arena_) T(type, first, second));
    285   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
    286 }
    287 
    288 template<typename T>
    289 void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) {
    290   HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
    291   HInstruction* second = GetIntConstant(instruction.VRegC_22s());
    292   if (reverse) {
    293     std::swap(first, second);
    294   }
    295   current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
    296   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
    297 }
    298 
    299 template<typename T>
    300 void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) {
    301   HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
    302   HInstruction* second = GetIntConstant(instruction.VRegC_22b());
    303   if (reverse) {
    304     std::swap(first, second);
    305   }
    306   current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
    307   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
    308 }
    309 
    310 void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type type) {
    311   if (type == Primitive::kPrimVoid) {
    312     current_block_->AddInstruction(new (arena_) HReturnVoid());
    313   } else {
    314     HInstruction* value = LoadLocal(instruction.VRegA(), type);
    315     current_block_->AddInstruction(new (arena_) HReturn(value));
    316   }
    317   current_block_->AddSuccessor(exit_block_);
    318   current_block_ = nullptr;
    319 }
    320 
    321 bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
    322                                 uint32_t dex_offset,
    323                                 uint32_t method_idx,
    324                                 uint32_t number_of_vreg_arguments,
    325                                 bool is_range,
    326                                 uint32_t* args,
    327                                 uint32_t register_index) {
    328   const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
    329   const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(method_id.proto_idx_);
    330   const char* descriptor = dex_file_->StringDataByIdx(proto_id.shorty_idx_);
    331   Primitive::Type return_type = Primitive::GetType(descriptor[0]);
    332   bool is_instance_call =
    333       instruction.Opcode() != Instruction::INVOKE_STATIC
    334       && instruction.Opcode() != Instruction::INVOKE_STATIC_RANGE;
    335   const size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1);
    336 
    337   // Treat invoke-direct like static calls for now.
    338   HInvoke* invoke = new (arena_) HInvokeStatic(
    339       arena_, number_of_arguments, return_type, dex_offset, method_idx);
    340 
    341   size_t start_index = 0;
    342   Temporaries temps(graph_, is_instance_call ? 1 : 0);
    343   if (is_instance_call) {
    344     HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot);
    345     HNullCheck* null_check = new (arena_) HNullCheck(arg, dex_offset);
    346     current_block_->AddInstruction(null_check);
    347     temps.Add(null_check);
    348     invoke->SetArgumentAt(0, null_check);
    349     start_index = 1;
    350   }
    351 
    352   uint32_t descriptor_index = 1;
    353   uint32_t argument_index = start_index;
    354   for (size_t i = start_index; i < number_of_vreg_arguments; i++, argument_index++) {
    355     Primitive::Type type = Primitive::GetType(descriptor[descriptor_index++]);
    356     if (!IsTypeSupported(type)) {
    357       return false;
    358     }
    359     if (!is_range && type == Primitive::kPrimLong && args[i] + 1 != args[i + 1]) {
    360       LOG(WARNING) << "Non sequential register pair in " << dex_compilation_unit_->GetSymbol()
    361                    << " at " << dex_offset;
    362       // We do not implement non sequential register pair.
    363       return false;
    364     }
    365     HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type);
    366     invoke->SetArgumentAt(argument_index, arg);
    367     if (type == Primitive::kPrimLong) {
    368       i++;
    369     }
    370   }
    371 
    372   if (!IsTypeSupported(return_type)) {
    373     return false;
    374   }
    375 
    376   DCHECK_EQ(argument_index, number_of_arguments);
    377   current_block_->AddInstruction(invoke);
    378   return true;
    379 }
    380 
    381 bool HGraphBuilder::BuildFieldAccess(const Instruction& instruction,
    382                                      uint32_t dex_offset,
    383                                      bool is_put) {
    384   uint32_t source_or_dest_reg = instruction.VRegA_22c();
    385   uint32_t obj_reg = instruction.VRegB_22c();
    386   uint16_t field_index = instruction.VRegC_22c();
    387 
    388   ScopedObjectAccess soa(Thread::Current());
    389   StackHandleScope<1> hs(soa.Self());
    390   Handle<mirror::ArtField> resolved_field(hs.NewHandle(
    391       compiler_driver_->ComputeInstanceFieldInfo(field_index, dex_compilation_unit_, is_put, soa)));
    392 
    393   if (resolved_field.Get() == nullptr) {
    394     return false;
    395   }
    396   if (resolved_field->IsVolatile()) {
    397     return false;
    398   }
    399 
    400   Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType();
    401   if (!IsTypeSupported(field_type)) {
    402     return false;
    403   }
    404 
    405   HInstruction* object = LoadLocal(obj_reg, Primitive::kPrimNot);
    406   current_block_->AddInstruction(new (arena_) HNullCheck(object, dex_offset));
    407   if (is_put) {
    408     Temporaries temps(graph_, 1);
    409     HInstruction* null_check = current_block_->GetLastInstruction();
    410     // We need one temporary for the null check.
    411     temps.Add(null_check);
    412     HInstruction* value = LoadLocal(source_or_dest_reg, field_type);
    413     current_block_->AddInstruction(new (arena_) HInstanceFieldSet(
    414         null_check,
    415         value,
    416         resolved_field->GetOffset()));
    417   } else {
    418     current_block_->AddInstruction(new (arena_) HInstanceFieldGet(
    419         current_block_->GetLastInstruction(),
    420         field_type,
    421         resolved_field->GetOffset()));
    422 
    423     UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
    424   }
    425   return true;
    426 }
    427 
    428 void HGraphBuilder::BuildArrayAccess(const Instruction& instruction,
    429                                      uint32_t dex_offset,
    430                                      bool is_put,
    431                                      Primitive::Type anticipated_type) {
    432   uint8_t source_or_dest_reg = instruction.VRegA_23x();
    433   uint8_t array_reg = instruction.VRegB_23x();
    434   uint8_t index_reg = instruction.VRegC_23x();
    435 
    436   DCHECK(IsTypeSupported(anticipated_type));
    437 
    438   // We need one temporary for the null check, one for the index, and one for the length.
    439   Temporaries temps(graph_, 3);
    440 
    441   HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot);
    442   object = new (arena_) HNullCheck(object, dex_offset);
    443   current_block_->AddInstruction(object);
    444   temps.Add(object);
    445 
    446   HInstruction* length = new (arena_) HArrayLength(object);
    447   current_block_->AddInstruction(length);
    448   temps.Add(length);
    449   HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt);
    450   index = new (arena_) HBoundsCheck(index, length, dex_offset);
    451   current_block_->AddInstruction(index);
    452   temps.Add(index);
    453   if (is_put) {
    454     HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type);
    455     // TODO: Insert a type check node if the type is Object.
    456     current_block_->AddInstruction(new (arena_) HArraySet(object, index, value, dex_offset));
    457   } else {
    458     current_block_->AddInstruction(new (arena_) HArrayGet(object, index, anticipated_type));
    459     UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
    460   }
    461 }
    462 
    463 bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
    464   if (current_block_ == nullptr) {
    465     return true;  // Dead code
    466   }
    467 
    468   switch (instruction.Opcode()) {
    469     case Instruction::CONST_4: {
    470       int32_t register_index = instruction.VRegA();
    471       HIntConstant* constant = GetIntConstant(instruction.VRegB_11n());
    472       UpdateLocal(register_index, constant);
    473       break;
    474     }
    475 
    476     case Instruction::CONST_16: {
    477       int32_t register_index = instruction.VRegA();
    478       HIntConstant* constant = GetIntConstant(instruction.VRegB_21s());
    479       UpdateLocal(register_index, constant);
    480       break;
    481     }
    482 
    483     case Instruction::CONST: {
    484       int32_t register_index = instruction.VRegA();
    485       HIntConstant* constant = GetIntConstant(instruction.VRegB_31i());
    486       UpdateLocal(register_index, constant);
    487       break;
    488     }
    489 
    490     case Instruction::CONST_HIGH16: {
    491       int32_t register_index = instruction.VRegA();
    492       HIntConstant* constant = GetIntConstant(instruction.VRegB_21h() << 16);
    493       UpdateLocal(register_index, constant);
    494       break;
    495     }
    496 
    497     case Instruction::CONST_WIDE_16: {
    498       int32_t register_index = instruction.VRegA();
    499       // Get 16 bits of constant value, sign extended to 64 bits.
    500       int64_t value = instruction.VRegB_21s();
    501       value <<= 48;
    502       value >>= 48;
    503       HLongConstant* constant = GetLongConstant(value);
    504       UpdateLocal(register_index, constant);
    505       break;
    506     }
    507 
    508     case Instruction::CONST_WIDE_32: {
    509       int32_t register_index = instruction.VRegA();
    510       // Get 32 bits of constant value, sign extended to 64 bits.
    511       int64_t value = instruction.VRegB_31i();
    512       value <<= 32;
    513       value >>= 32;
    514       HLongConstant* constant = GetLongConstant(value);
    515       UpdateLocal(register_index, constant);
    516       break;
    517     }
    518 
    519     case Instruction::CONST_WIDE: {
    520       int32_t register_index = instruction.VRegA();
    521       HLongConstant* constant = GetLongConstant(instruction.VRegB_51l());
    522       UpdateLocal(register_index, constant);
    523       break;
    524     }
    525 
    526     case Instruction::CONST_WIDE_HIGH16: {
    527       int32_t register_index = instruction.VRegA();
    528       int64_t value = static_cast<int64_t>(instruction.VRegB_21h()) << 48;
    529       HLongConstant* constant = GetLongConstant(value);
    530       UpdateLocal(register_index, constant);
    531       break;
    532     }
    533 
    534     // TODO: these instructions are also used to move floating point values, so what is
    535     // the type (int or float)?
    536     case Instruction::MOVE:
    537     case Instruction::MOVE_FROM16:
    538     case Instruction::MOVE_16: {
    539       HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
    540       UpdateLocal(instruction.VRegA(), value);
    541       break;
    542     }
    543 
    544     // TODO: these instructions are also used to move floating point values, so what is
    545     // the type (long or double)?
    546     case Instruction::MOVE_WIDE:
    547     case Instruction::MOVE_WIDE_FROM16:
    548     case Instruction::MOVE_WIDE_16: {
    549       HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimLong);
    550       UpdateLocal(instruction.VRegA(), value);
    551       break;
    552     }
    553 
    554     case Instruction::MOVE_OBJECT:
    555     case Instruction::MOVE_OBJECT_16:
    556     case Instruction::MOVE_OBJECT_FROM16: {
    557       HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimNot);
    558       UpdateLocal(instruction.VRegA(), value);
    559       break;
    560     }
    561 
    562     case Instruction::RETURN_VOID: {
    563       BuildReturn(instruction, Primitive::kPrimVoid);
    564       break;
    565     }
    566 
    567 #define IF_XX(comparison, cond) \
    568     case Instruction::IF_##cond: If_22t<comparison>(instruction, dex_offset); break; \
    569     case Instruction::IF_##cond##Z: If_21t<comparison>(instruction, dex_offset); break
    570 
    571     IF_XX(HEqual, EQ);
    572     IF_XX(HNotEqual, NE);
    573     IF_XX(HLessThan, LT);
    574     IF_XX(HLessThanOrEqual, LE);
    575     IF_XX(HGreaterThan, GT);
    576     IF_XX(HGreaterThanOrEqual, GE);
    577 
    578     case Instruction::GOTO:
    579     case Instruction::GOTO_16:
    580     case Instruction::GOTO_32: {
    581       HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
    582       DCHECK(target != nullptr);
    583       current_block_->AddInstruction(new (arena_) HGoto());
    584       current_block_->AddSuccessor(target);
    585       current_block_ = nullptr;
    586       break;
    587     }
    588 
    589     case Instruction::RETURN: {
    590       BuildReturn(instruction, Primitive::kPrimInt);
    591       break;
    592     }
    593 
    594     case Instruction::RETURN_OBJECT: {
    595       BuildReturn(instruction, Primitive::kPrimNot);
    596       break;
    597     }
    598 
    599     case Instruction::RETURN_WIDE: {
    600       BuildReturn(instruction, Primitive::kPrimLong);
    601       break;
    602     }
    603 
    604     case Instruction::INVOKE_STATIC:
    605     case Instruction::INVOKE_DIRECT: {
    606       uint32_t method_idx = instruction.VRegB_35c();
    607       uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
    608       uint32_t args[5];
    609       instruction.GetVarArgs(args);
    610       if (!BuildInvoke(instruction, dex_offset, method_idx, number_of_vreg_arguments, false, args, -1)) {
    611         return false;
    612       }
    613       break;
    614     }
    615 
    616     case Instruction::INVOKE_STATIC_RANGE:
    617     case Instruction::INVOKE_DIRECT_RANGE: {
    618       uint32_t method_idx = instruction.VRegB_3rc();
    619       uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
    620       uint32_t register_index = instruction.VRegC();
    621       if (!BuildInvoke(instruction, dex_offset, method_idx,
    622                        number_of_vreg_arguments, true, nullptr, register_index)) {
    623         return false;
    624       }
    625       break;
    626     }
    627 
    628     case Instruction::ADD_INT: {
    629       Binop_23x<HAdd>(instruction, Primitive::kPrimInt);
    630       break;
    631     }
    632 
    633     case Instruction::ADD_LONG: {
    634       Binop_23x<HAdd>(instruction, Primitive::kPrimLong);
    635       break;
    636     }
    637 
    638     case Instruction::SUB_INT: {
    639       Binop_23x<HSub>(instruction, Primitive::kPrimInt);
    640       break;
    641     }
    642 
    643     case Instruction::SUB_LONG: {
    644       Binop_23x<HSub>(instruction, Primitive::kPrimLong);
    645       break;
    646     }
    647 
    648     case Instruction::ADD_INT_2ADDR: {
    649       Binop_12x<HAdd>(instruction, Primitive::kPrimInt);
    650       break;
    651     }
    652 
    653     case Instruction::ADD_LONG_2ADDR: {
    654       Binop_12x<HAdd>(instruction, Primitive::kPrimLong);
    655       break;
    656     }
    657 
    658     case Instruction::SUB_INT_2ADDR: {
    659       Binop_12x<HSub>(instruction, Primitive::kPrimInt);
    660       break;
    661     }
    662 
    663     case Instruction::SUB_LONG_2ADDR: {
    664       Binop_12x<HSub>(instruction, Primitive::kPrimLong);
    665       break;
    666     }
    667 
    668     case Instruction::ADD_INT_LIT16: {
    669       Binop_22s<HAdd>(instruction, false);
    670       break;
    671     }
    672 
    673     case Instruction::RSUB_INT: {
    674       Binop_22s<HSub>(instruction, true);
    675       break;
    676     }
    677 
    678     case Instruction::ADD_INT_LIT8: {
    679       Binop_22b<HAdd>(instruction, false);
    680       break;
    681     }
    682 
    683     case Instruction::RSUB_INT_LIT8: {
    684       Binop_22b<HSub>(instruction, true);
    685       break;
    686     }
    687 
    688     case Instruction::NEW_INSTANCE: {
    689       current_block_->AddInstruction(
    690           new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c()));
    691       UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
    692       break;
    693     }
    694 
    695     case Instruction::MOVE_RESULT:
    696     case Instruction::MOVE_RESULT_WIDE:
    697     case Instruction::MOVE_RESULT_OBJECT:
    698       UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
    699       break;
    700 
    701     case Instruction::CMP_LONG: {
    702       Binop_23x<HCompare>(instruction, Primitive::kPrimLong);
    703       break;
    704     }
    705 
    706     case Instruction::NOP:
    707       break;
    708 
    709     case Instruction::IGET:
    710     case Instruction::IGET_WIDE:
    711     case Instruction::IGET_OBJECT:
    712     case Instruction::IGET_BOOLEAN:
    713     case Instruction::IGET_BYTE:
    714     case Instruction::IGET_CHAR:
    715     case Instruction::IGET_SHORT: {
    716       if (!BuildFieldAccess(instruction, dex_offset, false)) {
    717         return false;
    718       }
    719       break;
    720     }
    721 
    722     case Instruction::IPUT:
    723     case Instruction::IPUT_WIDE:
    724     case Instruction::IPUT_OBJECT:
    725     case Instruction::IPUT_BOOLEAN:
    726     case Instruction::IPUT_BYTE:
    727     case Instruction::IPUT_CHAR:
    728     case Instruction::IPUT_SHORT: {
    729       if (!BuildFieldAccess(instruction, dex_offset, true)) {
    730         return false;
    731       }
    732       break;
    733     }
    734 
    735 #define ARRAY_XX(kind, anticipated_type)                                          \
    736     case Instruction::AGET##kind: {                                               \
    737       BuildArrayAccess(instruction, dex_offset, false, anticipated_type);         \
    738       break;                                                                      \
    739     }                                                                             \
    740     case Instruction::APUT##kind: {                                               \
    741       BuildArrayAccess(instruction, dex_offset, true, anticipated_type);          \
    742       break;                                                                      \
    743     }
    744 
    745     ARRAY_XX(, Primitive::kPrimInt);
    746     ARRAY_XX(_WIDE, Primitive::kPrimLong);
    747     ARRAY_XX(_OBJECT, Primitive::kPrimNot);
    748     ARRAY_XX(_BOOLEAN, Primitive::kPrimBoolean);
    749     ARRAY_XX(_BYTE, Primitive::kPrimByte);
    750     ARRAY_XX(_CHAR, Primitive::kPrimChar);
    751     ARRAY_XX(_SHORT, Primitive::kPrimShort);
    752 
    753     default:
    754       return false;
    755   }
    756   return true;
    757 }
    758 
    759 HIntConstant* HGraphBuilder::GetIntConstant0() {
    760   if (constant0_ != nullptr) {
    761     return constant0_;
    762   }
    763   constant0_ = new(arena_) HIntConstant(0);
    764   entry_block_->AddInstruction(constant0_);
    765   return constant0_;
    766 }
    767 
    768 HIntConstant* HGraphBuilder::GetIntConstant1() {
    769   if (constant1_ != nullptr) {
    770     return constant1_;
    771   }
    772   constant1_ = new(arena_) HIntConstant(1);
    773   entry_block_->AddInstruction(constant1_);
    774   return constant1_;
    775 }
    776 
    777 HIntConstant* HGraphBuilder::GetIntConstant(int32_t constant) {
    778   switch (constant) {
    779     case 0: return GetIntConstant0();
    780     case 1: return GetIntConstant1();
    781     default: {
    782       HIntConstant* instruction = new (arena_) HIntConstant(constant);
    783       entry_block_->AddInstruction(instruction);
    784       return instruction;
    785     }
    786   }
    787 }
    788 
    789 HLongConstant* HGraphBuilder::GetLongConstant(int64_t constant) {
    790   HLongConstant* instruction = new (arena_) HLongConstant(constant);
    791   entry_block_->AddInstruction(instruction);
    792   return instruction;
    793 }
    794 
    795 HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
    796   return locals_.Get(register_index);
    797 }
    798 
    799 void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
    800   HLocal* local = GetLocalAt(register_index);
    801   current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
    802 }
    803 
    804 HInstruction* HGraphBuilder::LoadLocal(int register_index, Primitive::Type type) const {
    805   HLocal* local = GetLocalAt(register_index);
    806   current_block_->AddInstruction(new (arena_) HLoadLocal(local, type));
    807   return current_block_->GetLastInstruction();
    808 }
    809 
    810 }  // namespace art
    811