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:
Temporaries(HGraph * graph,size_t count)45   Temporaries(HGraph* graph, size_t count) : graph_(graph), count_(count), index_(0) {
46     graph_->UpdateNumberOfTemporaries(count_);
47   }
48 
Add(HInstruction * instruction)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 
IsTypeSupported(Primitive::Type type)68 static bool IsTypeSupported(Primitive::Type type) {
69   return type != Primitive::kPrimFloat && type != Primitive::kPrimDouble;
70 }
71 
InitializeLocals(uint16_t count)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 
InitializeParameters(uint16_t number_of_parameters)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 
CanHandleCodeItem(const DexFile::CodeItem & code_item)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>
If_22t(const Instruction & instruction,uint32_t dex_offset)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>
If_21t(const Instruction & instruction,uint32_t dex_offset)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 
BuildGraph(const DexFile::CodeItem & code_item)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 
MaybeUpdateCurrentBlock(size_t index)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 
ComputeBranchTargets(const uint16_t * code_ptr,const uint16_t * code_end)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 
FindBlockStartingAt(int32_t index) const267 HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
268   DCHECK_GE(index, 0);
269   return branch_targets_.Get(index);
270 }
271 
272 template<typename T>
Binop_23x(const Instruction & instruction,Primitive::Type type)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>
Binop_12x(const Instruction & instruction,Primitive::Type type)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>
Binop_22s(const Instruction & instruction,bool reverse)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>
Binop_22b(const Instruction & instruction,bool reverse)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 
BuildReturn(const Instruction & instruction,Primitive::Type type)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 
BuildInvoke(const Instruction & instruction,uint32_t dex_offset,uint32_t method_idx,uint32_t number_of_vreg_arguments,bool is_range,uint32_t * args,uint32_t register_index)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 
BuildFieldAccess(const Instruction & instruction,uint32_t dex_offset,bool is_put)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 
BuildArrayAccess(const Instruction & instruction,uint32_t dex_offset,bool is_put,Primitive::Type anticipated_type)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 
AnalyzeDexInstruction(const Instruction & instruction,int32_t dex_offset)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 
GetIntConstant0()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 
GetIntConstant1()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 
GetIntConstant(int32_t constant)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 
GetLongConstant(int64_t constant)789 HLongConstant* HGraphBuilder::GetLongConstant(int64_t constant) {
790   HLongConstant* instruction = new (arena_) HLongConstant(constant);
791   entry_block_->AddInstruction(instruction);
792   return instruction;
793 }
794 
GetLocalAt(int register_index) const795 HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
796   return locals_.Get(register_index);
797 }
798 
UpdateLocal(int register_index,HInstruction * instruction) const799 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 
LoadLocal(int register_index,Primitive::Type type) const804 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