1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.dx.dex.code.form; 18 19import com.android.dx.dex.code.CstInsn; 20import com.android.dx.dex.code.DalvInsn; 21import com.android.dx.dex.code.InsnFormat; 22import com.android.dx.rop.code.RegisterSpec; 23import com.android.dx.rop.code.RegisterSpecList; 24import com.android.dx.rop.cst.Constant; 25import com.android.dx.rop.cst.CstMethodRef; 26import com.android.dx.rop.cst.CstType; 27import com.android.dx.rop.type.Type; 28import com.android.dx.util.AnnotatedOutput; 29 30import java.util.BitSet; 31 32/** 33 * Instruction format {@code 35c}. See the instruction format spec 34 * for details. 35 */ 36public final class Form35c extends InsnFormat { 37 /** {@code non-null;} unique instance of this class */ 38 public static final InsnFormat THE_ONE = new Form35c(); 39 40 /** Maximal number of operands */ 41 private static final int MAX_NUM_OPS = 5; 42 43 /** 44 * Constructs an instance. This class is not publicly 45 * instantiable. Use {@link #THE_ONE}. 46 */ 47 private Form35c() { 48 // This space intentionally left blank. 49 } 50 51 /** {@inheritDoc} */ 52 @Override 53 public String insnArgString(DalvInsn insn) { 54 RegisterSpecList regs = explicitize(insn.getRegisters()); 55 return regListString(regs) + ", " + cstString(insn); 56 } 57 58 /** {@inheritDoc} */ 59 @Override 60 public String insnCommentString(DalvInsn insn, boolean noteIndices) { 61 if (noteIndices) { 62 return cstComment(insn); 63 } else { 64 return ""; 65 } 66 } 67 68 /** {@inheritDoc} */ 69 @Override 70 public int codeSize() { 71 return 3; 72 } 73 74 /** {@inheritDoc} */ 75 @Override 76 public boolean isCompatible(DalvInsn insn) { 77 if (!(insn instanceof CstInsn)) { 78 return false; 79 } 80 81 CstInsn ci = (CstInsn) insn; 82 int cpi = ci.getIndex(); 83 84 if (! unsignedFitsInShort(cpi)) { 85 return false; 86 } 87 88 Constant cst = ci.getConstant(); 89 if (!((cst instanceof CstMethodRef) || 90 (cst instanceof CstType))) { 91 return false; 92 } 93 94 RegisterSpecList regs = ci.getRegisters(); 95 return (wordCount(regs) >= 0); 96 } 97 98 /** {@inheritDoc} */ 99 @Override 100 public BitSet compatibleRegs(DalvInsn insn) { 101 RegisterSpecList regs = insn.getRegisters(); 102 int sz = regs.size(); 103 BitSet bits = new BitSet(sz); 104 105 for (int i = 0; i < sz; i++) { 106 RegisterSpec reg = regs.get(i); 107 /* 108 * The check below adds (category - 1) to the register, to 109 * account for the fact that the second half of a 110 * category-2 register has to be represented explicitly in 111 * the result. 112 */ 113 bits.set(i, unsignedFitsInNibble(reg.getReg() + 114 reg.getCategory() - 1)); 115 } 116 117 return bits; 118 } 119 120 /** {@inheritDoc} */ 121 @Override 122 public void writeTo(AnnotatedOutput out, DalvInsn insn) { 123 int cpi = ((CstInsn) insn).getIndex(); 124 RegisterSpecList regs = explicitize(insn.getRegisters()); 125 int sz = regs.size(); 126 int r0 = (sz > 0) ? regs.get(0).getReg() : 0; 127 int r1 = (sz > 1) ? regs.get(1).getReg() : 0; 128 int r2 = (sz > 2) ? regs.get(2).getReg() : 0; 129 int r3 = (sz > 3) ? regs.get(3).getReg() : 0; 130 int r4 = (sz > 4) ? regs.get(4).getReg() : 0; 131 132 write(out, 133 opcodeUnit(insn, 134 makeByte(r4, sz)), // encode the fifth operand here 135 (short) cpi, 136 codeUnit(r0, r1, r2, r3)); 137 } 138 139 /** 140 * Gets the number of words required for the given register list, where 141 * category-2 values count as two words. Return {@code -1} if the 142 * list requires more than five words or contains registers that need 143 * more than a nibble to identify them. 144 * 145 * @param regs {@code non-null;} the register list in question 146 * @return {@code >= -1;} the number of words required, or {@code -1} 147 * if the list couldn't possibly fit in this format 148 */ 149 private static int wordCount(RegisterSpecList regs) { 150 int sz = regs.size(); 151 152 if (sz > MAX_NUM_OPS) { 153 // It can't possibly fit. 154 return -1; 155 } 156 157 int result = 0; 158 159 for (int i = 0; i < sz; i++) { 160 RegisterSpec one = regs.get(i); 161 result += one.getCategory(); 162 /* 163 * The check below adds (category - 1) to the register, to 164 * account for the fact that the second half of a 165 * category-2 register has to be represented explicitly in 166 * the result. 167 */ 168 if (!unsignedFitsInNibble(one.getReg() + one.getCategory() - 1)) { 169 return -1; 170 } 171 } 172 173 return (result <= MAX_NUM_OPS) ? result : -1; 174 } 175 176 /** 177 * Returns a register list which is equivalent to the given one, 178 * except that it splits category-2 registers into two explicit 179 * entries. This returns the original list if no modification is 180 * required 181 * 182 * @param orig {@code non-null;} the original list 183 * @return {@code non-null;} the list with the described transformation 184 */ 185 private static RegisterSpecList explicitize(RegisterSpecList orig) { 186 int wordCount = wordCount(orig); 187 int sz = orig.size(); 188 189 if (wordCount == sz) { 190 return orig; 191 } 192 193 RegisterSpecList result = new RegisterSpecList(wordCount); 194 int wordAt = 0; 195 196 for (int i = 0; i < sz; i++) { 197 RegisterSpec one = orig.get(i); 198 result.set(wordAt, one); 199 if (one.getCategory() == 2) { 200 result.set(wordAt + 1, 201 RegisterSpec.make(one.getReg() + 1, Type.VOID)); 202 wordAt += 2; 203 } else { 204 wordAt++; 205 } 206 } 207 208 result.setImmutable(); 209 return result; 210 } 211} 212