1// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file 2// for details. All rights reserved. Use of this source code is governed by a 3// BSD-style license that can be found in the LICENSE file. 4package com.android.tools.r8.ir.code; 5 6import com.android.tools.r8.code.Aput; 7import com.android.tools.r8.code.AputBoolean; 8import com.android.tools.r8.code.AputByte; 9import com.android.tools.r8.code.AputChar; 10import com.android.tools.r8.code.AputObject; 11import com.android.tools.r8.code.AputShort; 12import com.android.tools.r8.code.AputWide; 13import com.android.tools.r8.dex.Constants; 14import com.android.tools.r8.errors.Unreachable; 15import com.android.tools.r8.ir.conversion.DexBuilder; 16import com.android.tools.r8.ir.regalloc.RegisterAllocator; 17import com.android.tools.r8.utils.InternalOptions; 18import java.util.List; 19 20public class ArrayPut extends Instruction { 21 22 private final MemberType type; 23 24 public ArrayPut(MemberType type, List<Value> ins) { 25 super(null, ins); 26 assert type != null; 27 this.type = type; 28 } 29 30 public Value source() { 31 return inValues.get(0); 32 } 33 34 public Value array() { 35 return inValues.get(1); 36 } 37 38 public Value index() { 39 return inValues.get(2); 40 } 41 42 @Override 43 public void buildDex(DexBuilder builder) { 44 int source = builder.allocatedRegister(source(), getNumber()); 45 int array = builder.allocatedRegister(array(), getNumber()); 46 int index = builder.allocatedRegister(index(), getNumber()); 47 com.android.tools.r8.code.Instruction instruction; 48 switch (type) { 49 case SINGLE: 50 instruction = new Aput(source, array, index); 51 break; 52 case WIDE: 53 instruction = new AputWide(source, array, index); 54 break; 55 case OBJECT: 56 instruction = new AputObject(source, array, index); 57 break; 58 case BOOLEAN: 59 instruction = new AputBoolean(source, array, index); 60 break; 61 case BYTE: 62 instruction = new AputByte(source, array, index); 63 break; 64 case CHAR: 65 instruction = new AputChar(source, array, index); 66 break; 67 case SHORT: 68 instruction = new AputShort(source, array, index); 69 break; 70 default: 71 throw new Unreachable("Unexpected type " + type); 72 } 73 builder.add(this, instruction); 74 } 75 76 @Override 77 public int maxInValueRegister() { 78 return Constants.U8BIT_MAX; 79 } 80 81 @Override 82 public int maxOutValueRegister() { 83 assert false : "ArrayPut instructions define no values."; 84 return 0; 85 } 86 87 @Override 88 public boolean instructionTypeCanThrow() { 89 return true; 90 } 91 92 @Override 93 public boolean instructionInstanceCanThrow() { 94 if (index().isConstant() && !array().isPhi() && array().definition.isNewArrayEmpty()) { 95 Value newArraySizeValue = array().definition.asNewArrayEmpty().size(); 96 if (newArraySizeValue.isConstant()) { 97 int newArraySize = newArraySizeValue.getConstInstruction().asConstNumber().getIntValue(); 98 int index = index().getConstInstruction().asConstNumber().getIntValue(); 99 return newArraySize <= 0 || index < 0 || newArraySize <= index; 100 } 101 } 102 return true; 103 } 104 105 @Override 106 public boolean canBeDeadCode(IRCode code, InternalOptions options) { 107 // ArrayPut has side-effects on input values. 108 return false; 109 } 110 111 @Override 112 public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) { 113 // We cannot share ArrayPut instructions without knowledge of the type of the array input. 114 // If multiple primitive array types flow to the same ArrayPut instruction the art verifier 115 // gets confused. 116 return false; 117 } 118 119 @Override 120 public boolean identicalNonValueParts(Instruction other) { 121 return other.asArrayPut().type == type; 122 } 123 124 @Override 125 public int compareNonValueParts(Instruction other) { 126 return type.ordinal() - other.asArrayPut().type.ordinal(); 127 } 128 129 @Override 130 public boolean isArrayPut() { 131 return true; 132 } 133 134 @Override 135 public ArrayPut asArrayPut() { 136 return this; 137 } 138} 139