builder.cc revision f12feb8e0e857f2832545b3f28d31bad5a9d3903
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
428bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
429  if (current_block_ == nullptr) {
430    return true;  // Dead code
431  }
432
433  switch (instruction.Opcode()) {
434    case Instruction::CONST_4: {
435      int32_t register_index = instruction.VRegA();
436      HIntConstant* constant = GetIntConstant(instruction.VRegB_11n());
437      UpdateLocal(register_index, constant);
438      break;
439    }
440
441    case Instruction::CONST_16: {
442      int32_t register_index = instruction.VRegA();
443      HIntConstant* constant = GetIntConstant(instruction.VRegB_21s());
444      UpdateLocal(register_index, constant);
445      break;
446    }
447
448    case Instruction::CONST: {
449      int32_t register_index = instruction.VRegA();
450      HIntConstant* constant = GetIntConstant(instruction.VRegB_31i());
451      UpdateLocal(register_index, constant);
452      break;
453    }
454
455    case Instruction::CONST_HIGH16: {
456      int32_t register_index = instruction.VRegA();
457      HIntConstant* constant = GetIntConstant(instruction.VRegB_21h() << 16);
458      UpdateLocal(register_index, constant);
459      break;
460    }
461
462    case Instruction::CONST_WIDE_16: {
463      int32_t register_index = instruction.VRegA();
464      // Get 16 bits of constant value, sign extended to 64 bits.
465      int64_t value = instruction.VRegB_21s();
466      value <<= 48;
467      value >>= 48;
468      HLongConstant* constant = GetLongConstant(value);
469      UpdateLocal(register_index, constant);
470      break;
471    }
472
473    case Instruction::CONST_WIDE_32: {
474      int32_t register_index = instruction.VRegA();
475      // Get 32 bits of constant value, sign extended to 64 bits.
476      int64_t value = instruction.VRegB_31i();
477      value <<= 32;
478      value >>= 32;
479      HLongConstant* constant = GetLongConstant(value);
480      UpdateLocal(register_index, constant);
481      break;
482    }
483
484    case Instruction::CONST_WIDE: {
485      int32_t register_index = instruction.VRegA();
486      HLongConstant* constant = GetLongConstant(instruction.VRegB_51l());
487      UpdateLocal(register_index, constant);
488      break;
489    }
490
491    case Instruction::CONST_WIDE_HIGH16: {
492      int32_t register_index = instruction.VRegA();
493      int64_t value = static_cast<int64_t>(instruction.VRegB_21h()) << 48;
494      HLongConstant* constant = GetLongConstant(value);
495      UpdateLocal(register_index, constant);
496      break;
497    }
498
499    // TODO: these instructions are also used to move floating point values, so what is
500    // the type (int or float)?
501    case Instruction::MOVE:
502    case Instruction::MOVE_FROM16:
503    case Instruction::MOVE_16: {
504      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
505      UpdateLocal(instruction.VRegA(), value);
506      break;
507    }
508
509    // TODO: these instructions are also used to move floating point values, so what is
510    // the type (long or double)?
511    case Instruction::MOVE_WIDE:
512    case Instruction::MOVE_WIDE_FROM16:
513    case Instruction::MOVE_WIDE_16: {
514      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimLong);
515      UpdateLocal(instruction.VRegA(), value);
516      break;
517    }
518
519    case Instruction::MOVE_OBJECT:
520    case Instruction::MOVE_OBJECT_16:
521    case Instruction::MOVE_OBJECT_FROM16: {
522      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimNot);
523      UpdateLocal(instruction.VRegA(), value);
524      break;
525    }
526
527    case Instruction::RETURN_VOID: {
528      BuildReturn(instruction, Primitive::kPrimVoid);
529      break;
530    }
531
532#define IF_XX(comparison, cond) \
533    case Instruction::IF_##cond: If_22t<comparison>(instruction, dex_offset); break; \
534    case Instruction::IF_##cond##Z: If_21t<comparison>(instruction, dex_offset); break
535
536    IF_XX(HEqual, EQ);
537    IF_XX(HNotEqual, NE);
538    IF_XX(HLessThan, LT);
539    IF_XX(HLessThanOrEqual, LE);
540    IF_XX(HGreaterThan, GT);
541    IF_XX(HGreaterThanOrEqual, GE);
542
543    case Instruction::GOTO:
544    case Instruction::GOTO_16:
545    case Instruction::GOTO_32: {
546      HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
547      DCHECK(target != nullptr);
548      current_block_->AddInstruction(new (arena_) HGoto());
549      current_block_->AddSuccessor(target);
550      current_block_ = nullptr;
551      break;
552    }
553
554    case Instruction::RETURN: {
555      BuildReturn(instruction, Primitive::kPrimInt);
556      break;
557    }
558
559    case Instruction::RETURN_OBJECT: {
560      BuildReturn(instruction, Primitive::kPrimNot);
561      break;
562    }
563
564    case Instruction::RETURN_WIDE: {
565      BuildReturn(instruction, Primitive::kPrimLong);
566      break;
567    }
568
569    case Instruction::INVOKE_STATIC:
570    case Instruction::INVOKE_DIRECT: {
571      uint32_t method_idx = instruction.VRegB_35c();
572      uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
573      uint32_t args[5];
574      instruction.GetVarArgs(args);
575      if (!BuildInvoke(instruction, dex_offset, method_idx, number_of_vreg_arguments, false, args, -1)) {
576        return false;
577      }
578      break;
579    }
580
581    case Instruction::INVOKE_STATIC_RANGE:
582    case Instruction::INVOKE_DIRECT_RANGE: {
583      uint32_t method_idx = instruction.VRegB_3rc();
584      uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
585      uint32_t register_index = instruction.VRegC();
586      if (!BuildInvoke(instruction, dex_offset, method_idx,
587                       number_of_vreg_arguments, true, nullptr, register_index)) {
588        return false;
589      }
590      break;
591    }
592
593    case Instruction::ADD_INT: {
594      Binop_23x<HAdd>(instruction, Primitive::kPrimInt);
595      break;
596    }
597
598    case Instruction::ADD_LONG: {
599      Binop_23x<HAdd>(instruction, Primitive::kPrimLong);
600      break;
601    }
602
603    case Instruction::SUB_INT: {
604      Binop_23x<HSub>(instruction, Primitive::kPrimInt);
605      break;
606    }
607
608    case Instruction::SUB_LONG: {
609      Binop_23x<HSub>(instruction, Primitive::kPrimLong);
610      break;
611    }
612
613    case Instruction::ADD_INT_2ADDR: {
614      Binop_12x<HAdd>(instruction, Primitive::kPrimInt);
615      break;
616    }
617
618    case Instruction::ADD_LONG_2ADDR: {
619      Binop_12x<HAdd>(instruction, Primitive::kPrimLong);
620      break;
621    }
622
623    case Instruction::SUB_INT_2ADDR: {
624      Binop_12x<HSub>(instruction, Primitive::kPrimInt);
625      break;
626    }
627
628    case Instruction::SUB_LONG_2ADDR: {
629      Binop_12x<HSub>(instruction, Primitive::kPrimLong);
630      break;
631    }
632
633    case Instruction::ADD_INT_LIT16: {
634      Binop_22s<HAdd>(instruction, false);
635      break;
636    }
637
638    case Instruction::RSUB_INT: {
639      Binop_22s<HSub>(instruction, true);
640      break;
641    }
642
643    case Instruction::ADD_INT_LIT8: {
644      Binop_22b<HAdd>(instruction, false);
645      break;
646    }
647
648    case Instruction::RSUB_INT_LIT8: {
649      Binop_22b<HSub>(instruction, true);
650      break;
651    }
652
653    case Instruction::NEW_INSTANCE: {
654      current_block_->AddInstruction(
655          new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c()));
656      UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
657      break;
658    }
659
660    case Instruction::MOVE_RESULT:
661    case Instruction::MOVE_RESULT_WIDE:
662    case Instruction::MOVE_RESULT_OBJECT:
663      UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
664      break;
665
666    case Instruction::CMP_LONG: {
667      Binop_23x<HCompare>(instruction, Primitive::kPrimLong);
668      break;
669    }
670
671    case Instruction::NOP:
672      break;
673
674    case Instruction::IGET:
675    case Instruction::IGET_WIDE:
676    case Instruction::IGET_OBJECT:
677    case Instruction::IGET_BOOLEAN:
678    case Instruction::IGET_BYTE:
679    case Instruction::IGET_CHAR:
680    case Instruction::IGET_SHORT: {
681      if (!BuildFieldAccess(instruction, dex_offset, false)) {
682        return false;
683      }
684      break;
685    }
686
687    case Instruction::IPUT:
688    case Instruction::IPUT_WIDE:
689    case Instruction::IPUT_OBJECT:
690    case Instruction::IPUT_BOOLEAN:
691    case Instruction::IPUT_BYTE:
692    case Instruction::IPUT_CHAR:
693    case Instruction::IPUT_SHORT: {
694      if (!BuildFieldAccess(instruction, dex_offset, true)) {
695        return false;
696      }
697      break;
698    }
699
700    default:
701      return false;
702  }
703  return true;
704}
705
706HIntConstant* HGraphBuilder::GetIntConstant0() {
707  if (constant0_ != nullptr) {
708    return constant0_;
709  }
710  constant0_ = new(arena_) HIntConstant(0);
711  entry_block_->AddInstruction(constant0_);
712  return constant0_;
713}
714
715HIntConstant* HGraphBuilder::GetIntConstant1() {
716  if (constant1_ != nullptr) {
717    return constant1_;
718  }
719  constant1_ = new(arena_) HIntConstant(1);
720  entry_block_->AddInstruction(constant1_);
721  return constant1_;
722}
723
724HIntConstant* HGraphBuilder::GetIntConstant(int32_t constant) {
725  switch (constant) {
726    case 0: return GetIntConstant0();
727    case 1: return GetIntConstant1();
728    default: {
729      HIntConstant* instruction = new (arena_) HIntConstant(constant);
730      entry_block_->AddInstruction(instruction);
731      return instruction;
732    }
733  }
734}
735
736HLongConstant* HGraphBuilder::GetLongConstant(int64_t constant) {
737  HLongConstant* instruction = new (arena_) HLongConstant(constant);
738  entry_block_->AddInstruction(instruction);
739  return instruction;
740}
741
742HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
743  return locals_.Get(register_index);
744}
745
746void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
747  HLocal* local = GetLocalAt(register_index);
748  current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
749}
750
751HInstruction* HGraphBuilder::LoadLocal(int register_index, Primitive::Type type) const {
752  HLocal* local = GetLocalAt(register_index);
753  current_block_->AddInstruction(new (arena_) HLoadLocal(local, type));
754  return current_block_->GetLastInstruction();
755}
756
757}  // namespace art
758