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.dexgen.dex.code.form; 18 19import com.android.dexgen.dex.code.CstInsn; 20import com.android.dexgen.dex.code.DalvInsn; 21import com.android.dexgen.dex.code.InsnFormat; 22import com.android.dexgen.rop.code.RegisterSpec; 23import com.android.dexgen.rop.code.RegisterSpecList; 24import com.android.dexgen.rop.cst.Constant; 25import com.android.dexgen.rop.cst.CstMethodRef; 26import com.android.dexgen.rop.cst.CstType; 27import com.android.dexgen.rop.type.Type; 28import com.android.dexgen.util.AnnotatedOutput; 29 30/** 31 * Instruction format {@code 35c}. See the instruction format spec 32 * for details. 33 */ 34public final class Form35c extends InsnFormat { 35 /** {@code non-null;} unique instance of this class */ 36 public static final InsnFormat THE_ONE = new Form35c(); 37 38 /** Maximal number of operands */ 39 private static final int MAX_NUM_OPS = 5; 40 41 /** 42 * Constructs an instance. This class is not publicly 43 * instantiable. Use {@link #THE_ONE}. 44 */ 45 private Form35c() { 46 // This space intentionally left blank. 47 } 48 49 /** {@inheritDoc} */ 50 @Override 51 public String insnArgString(DalvInsn insn) { 52 RegisterSpecList regs = explicitize(insn.getRegisters()); 53 return regListString(regs) + ", " + cstString(insn); 54 } 55 56 /** {@inheritDoc} */ 57 @Override 58 public String insnCommentString(DalvInsn insn, boolean noteIndices) { 59 if (noteIndices) { 60 return cstComment(insn); 61 } else { 62 return ""; 63 } 64 } 65 66 /** {@inheritDoc} */ 67 @Override 68 public int codeSize() { 69 return 3; 70 } 71 72 /** {@inheritDoc} */ 73 @Override 74 public boolean isCompatible(DalvInsn insn) { 75 if (!(insn instanceof CstInsn)) { 76 return false; 77 } 78 79 CstInsn ci = (CstInsn) insn; 80 int cpi = ci.getIndex(); 81 82 if (! unsignedFitsInShort(cpi)) { 83 return false; 84 } 85 86 Constant cst = ci.getConstant(); 87 if (!((cst instanceof CstMethodRef) || 88 (cst instanceof CstType))) { 89 return false; 90 } 91 92 RegisterSpecList regs = ci.getRegisters(); 93 return (wordCount(regs) >= 0); 94 } 95 96 /** {@inheritDoc} */ 97 @Override 98 public InsnFormat nextUp() { 99 return Form3rc.THE_ONE; 100 } 101 102 /** {@inheritDoc} */ 103 @Override 104 public void writeTo(AnnotatedOutput out, DalvInsn insn) { 105 int cpi = ((CstInsn) insn).getIndex(); 106 RegisterSpecList regs = explicitize(insn.getRegisters()); 107 int sz = regs.size(); 108 int r0 = (sz > 0) ? regs.get(0).getReg() : 0; 109 int r1 = (sz > 1) ? regs.get(1).getReg() : 0; 110 int r2 = (sz > 2) ? regs.get(2).getReg() : 0; 111 int r3 = (sz > 3) ? regs.get(3).getReg() : 0; 112 int r4 = (sz > 4) ? regs.get(4).getReg() : 0; 113 114 write(out, 115 opcodeUnit(insn, 116 makeByte(r4, sz)), // encode the fifth operand here 117 (short) cpi, 118 codeUnit(r0, r1, r2, r3)); 119 } 120 121 /** 122 * Gets the number of words required for the given register list, where 123 * category-2 values count as two words. Return {@code -1} if the 124 * list requires more than five words or contains registers that need 125 * more than a nibble to identify them. 126 * 127 * @param regs {@code non-null;} the register list in question 128 * @return {@code >= -1;} the number of words required, or {@code -1} 129 * if the list couldn't possibly fit in this format 130 */ 131 private static int wordCount(RegisterSpecList regs) { 132 int sz = regs.size(); 133 134 if (sz > MAX_NUM_OPS) { 135 // It can't possibly fit. 136 return -1; 137 } 138 139 int result = 0; 140 141 for (int i = 0; i < sz; i++) { 142 RegisterSpec one = regs.get(i); 143 result += one.getCategory(); 144 /* 145 * The check below adds (category - 1) to the register, to 146 * account for the fact that the second half of a 147 * category-2 register has to be represented explicitly in 148 * the result. 149 */ 150 if (!unsignedFitsInNibble(one.getReg() + one.getCategory() - 1)) { 151 return -1; 152 } 153 } 154 155 return (result <= MAX_NUM_OPS) ? result : -1; 156 } 157 158 /** 159 * Returns a register list which is equivalent to the given one, 160 * except that it splits category-2 registers into two explicit 161 * entries. This returns the original list if no modification is 162 * required 163 * 164 * @param orig {@code non-null;} the original list 165 * @return {@code non-null;} the list with the described transformation 166 */ 167 private static RegisterSpecList explicitize(RegisterSpecList orig) { 168 int wordCount = wordCount(orig); 169 int sz = orig.size(); 170 171 if (wordCount == sz) { 172 return orig; 173 } 174 175 RegisterSpecList result = new RegisterSpecList(wordCount); 176 int wordAt = 0; 177 178 for (int i = 0; i < sz; i++) { 179 RegisterSpec one = orig.get(i); 180 result.set(wordAt, one); 181 if (one.getCategory() == 2) { 182 result.set(wordAt + 1, 183 RegisterSpec.make(one.getReg() + 1, Type.VOID)); 184 wordAt += 2; 185 } else { 186 wordAt++; 187 } 188 } 189 190 result.setImmutable(); 191 return result; 192 } 193} 194