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
35namespace 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 */
43class 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
68static bool IsTypeSupported(Primitive::Type type) {
69  return type != Primitive::kPrimFloat && type != Primitive::kPrimDouble;
70}
71
72void 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
82bool 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
132static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
133  if (code_item.tries_size_ > 0) {
134    return false;
135  }
136  return true;
137}
138
139template<typename T>
140void 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
156template<typename T>
157void 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
172HGraph* 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
216void 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
233void 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
267HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
268  DCHECK_GE(index, 0);
269  return branch_targets_.Get(index);
270}
271
272template<typename T>
273void 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
280template<typename T>
281void 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
288template<typename T>
289void 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
299template<typename T>
300void 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
310void 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
321bool 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
381bool 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
428void 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
463bool 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
759HIntConstant* 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
768HIntConstant* 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
777HIntConstant* 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
789HLongConstant* HGraphBuilder::GetLongConstant(int64_t constant) {
790  HLongConstant* instruction = new (arena_) HLongConstant(constant);
791  entry_block_->AddInstruction(instruction);
792  return instruction;
793}
794
795HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
796  return locals_.Get(register_index);
797}
798
799void 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
804HInstruction* 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