1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21package proguard.classfile.instruction; 22 23import proguard.classfile.*; 24import proguard.classfile.attribute.CodeAttribute; 25import proguard.classfile.instruction.visitor.InstructionVisitor; 26 27/** 28 * This Instruction represents a simple instruction without variable arguments 29 * or constant pool references. 30 * 31 * @author Eric Lafortune 32 */ 33public class SimpleInstruction extends Instruction 34{ 35 public int constant; 36 37 38 /** 39 * Creates an uninitialized SimpleInstruction. 40 */ 41 public SimpleInstruction() {} 42 43 44 /** 45 * Creates a new SimpleInstruction with the given opcode. 46 */ 47 public SimpleInstruction(byte opcode) 48 { 49 this(opcode, embeddedConstant(opcode)); 50 } 51 52 53 /** 54 * Creates a new SimpleInstruction with the given opcode and constant. 55 */ 56 public SimpleInstruction(byte opcode, int constant) 57 { 58 this.opcode = opcode; 59 this.constant = constant; 60 } 61 62 63 /** 64 * Copies the given instruction into this instruction. 65 * @param simpleInstruction the instruction to be copied. 66 * @return this instruction. 67 */ 68 public SimpleInstruction copy(SimpleInstruction simpleInstruction) 69 { 70 this.opcode = simpleInstruction.opcode; 71 this.constant = simpleInstruction.constant; 72 73 return this; 74 } 75 76 77 /** 78 * Return the embedded constant of the given opcode, or 0 if the opcode 79 * doesn't have one. 80 */ 81 private static int embeddedConstant(byte opcode) 82 { 83 switch (opcode) 84 { 85 case InstructionConstants.OP_ICONST_M1: return -1; 86 87 case InstructionConstants.OP_ICONST_1: 88 case InstructionConstants.OP_LCONST_1: 89 case InstructionConstants.OP_FCONST_1: 90 case InstructionConstants.OP_DCONST_1: return 1; 91 92 case InstructionConstants.OP_ICONST_2: 93 case InstructionConstants.OP_FCONST_2: return 2; 94 95 case InstructionConstants.OP_ICONST_3: return 3; 96 97 case InstructionConstants.OP_ICONST_4: return 4; 98 99 case InstructionConstants.OP_ICONST_5: return 5; 100 101 default: return 0; 102 } 103 } 104 105 106 // Implementations for Instruction. 107 108 public byte canonicalOpcode() 109 { 110 // Replace any _1, _2, _3,... extension by _0. 111 switch (opcode) 112 { 113 case InstructionConstants.OP_ICONST_M1: 114 case InstructionConstants.OP_ICONST_0: 115 case InstructionConstants.OP_ICONST_1: 116 case InstructionConstants.OP_ICONST_2: 117 case InstructionConstants.OP_ICONST_3: 118 case InstructionConstants.OP_ICONST_4: 119 case InstructionConstants.OP_ICONST_5: 120 case InstructionConstants.OP_BIPUSH: 121 case InstructionConstants.OP_SIPUSH: return InstructionConstants.OP_ICONST_0; 122 123 case InstructionConstants.OP_LCONST_0: 124 case InstructionConstants.OP_LCONST_1: return InstructionConstants.OP_LCONST_0; 125 126 case InstructionConstants.OP_FCONST_0: 127 case InstructionConstants.OP_FCONST_1: 128 case InstructionConstants.OP_FCONST_2: return InstructionConstants.OP_FCONST_0; 129 130 case InstructionConstants.OP_DCONST_0: 131 case InstructionConstants.OP_DCONST_1: return InstructionConstants.OP_DCONST_0; 132 133 default: return opcode; 134 } 135 } 136 137 public Instruction shrink() 138 { 139 // Reconstruct the opcode of the shortest instruction, if there are 140 // any alternatives. 141 switch (opcode) 142 { 143 case InstructionConstants.OP_ICONST_M1: 144 case InstructionConstants.OP_ICONST_0: 145 case InstructionConstants.OP_ICONST_1: 146 case InstructionConstants.OP_ICONST_2: 147 case InstructionConstants.OP_ICONST_3: 148 case InstructionConstants.OP_ICONST_4: 149 case InstructionConstants.OP_ICONST_5: 150 case InstructionConstants.OP_BIPUSH: 151 case InstructionConstants.OP_SIPUSH: 152 switch (requiredConstantSize()) 153 { 154 case 0: 155 opcode = (byte)(InstructionConstants.OP_ICONST_0 + constant); 156 break; 157 case 1: 158 opcode = InstructionConstants.OP_BIPUSH; 159 break; 160 case 2: 161 opcode = InstructionConstants.OP_SIPUSH; 162 break; 163 } 164 break; 165 166 case InstructionConstants.OP_LCONST_0: 167 case InstructionConstants.OP_LCONST_1: 168 opcode = (byte)(InstructionConstants.OP_LCONST_0 + constant); 169 break; 170 171 case InstructionConstants.OP_FCONST_0: 172 case InstructionConstants.OP_FCONST_1: 173 case InstructionConstants.OP_FCONST_2: 174 opcode = (byte)(InstructionConstants.OP_FCONST_0 + constant); 175 break; 176 177 case InstructionConstants.OP_DCONST_0: 178 case InstructionConstants.OP_DCONST_1: 179 opcode = (byte)(InstructionConstants.OP_DCONST_0 + constant); 180 break; 181 } 182 183 return this; 184 } 185 186 protected void readInfo(byte[] code, int offset) 187 { 188 int constantSize = constantSize(); 189 190 // Also initialize embedded constants that are different from 0. 191 constant = constantSize == 0 ? 192 embeddedConstant(opcode) : 193 readSignedValue(code, offset, constantSize); 194 } 195 196 197 protected void writeInfo(byte[] code, int offset) 198 { 199 int constantSize = constantSize(); 200 201 if (requiredConstantSize() > constantSize) 202 { 203 throw new IllegalArgumentException("Instruction has invalid constant size ("+this.toString(offset)+")"); 204 } 205 206 writeSignedValue(code, offset, constant, constantSize); 207 } 208 209 210 public int length(int offset) 211 { 212 return 1 + constantSize(); 213 } 214 215 216 public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor) 217 { 218 instructionVisitor.visitSimpleInstruction(clazz, method, codeAttribute, offset, this); 219 } 220 221 222 // Implementations for Object. 223 224 public String toString() 225 { 226 return getName() + 227 (constantSize() > 0 ? " "+constant : ""); 228 } 229 230 231 // Small utility methods. 232 233 /** 234 * Returns the constant size for this instruction. 235 */ 236 private int constantSize() 237 { 238 return opcode == InstructionConstants.OP_BIPUSH || 239 opcode == InstructionConstants.OP_NEWARRAY ? 1 : 240 opcode == InstructionConstants.OP_SIPUSH ? 2 : 241 0; 242 } 243 244 245 /** 246 * Computes the required constant size for this instruction. 247 */ 248 private int requiredConstantSize() 249 { 250 return constant >= -1 && constant <= 5 ? 0 : 251 (byte)constant == constant ? 1 : 252 (short)constant == constant ? 2 : 253 4; 254 } 255} 256