001 /* 002 Copyright (C) 2002-2003 Laurent Martelli <laurent@aopsys.com> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, but 010 WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public 015 License along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 017 USA */ 018 019 package org.objectweb.jac.core.translators; 020 021 import java.io.Serializable; 022 import java.util.Arrays; 023 import java.util.HashSet; 024 import java.util.Set; 025 import java.util.Vector; 026 import org.apache.bcel.classfile.*; 027 import org.apache.bcel.generic.*; 028 import org.apache.log4j.Logger; 029 import org.objectweb.jac.util.Stack; 030 031 /** 032 * Represents the VM stack 033 */ 034 public class VMStack extends Stack { 035 static Logger logger = Logger.getLogger("translator.bytecode"); 036 037 public static final ThisPointer thisPointer = new ThisPointer(); 038 public static final DontCare dontCare = new DontCare(); 039 040 static final int UNPREDICTABLE = -1; 041 static final int UNDEFINED = -2; 042 043 Vector locals = new Vector(); // Local variables 044 045 ConstantPoolGen cp; 046 int[] exceptionHandlers; 047 int currentHandler = 0; 048 int nbArgs; 049 int localsOffest; 050 boolean isStatic; 051 public VMStack(ConstantPoolGen cp, Code code, int nbArgs, boolean isStatic) { 052 this.cp = cp; 053 this.nbArgs = nbArgs; 054 this.isStatic = isStatic; 055 this.localsOffest = nbArgs+(isStatic?1:0); 056 if (code!=null) { 057 CodeException[] exceptions = code.getExceptionTable(); 058 exceptionHandlers = new int[exceptions.length]; 059 for (int i=0; i<exceptions.length; i++) { 060 exceptionHandlers[i] = exceptions[i].getHandlerPC(); 061 logger.debug("Exception handler at "+exceptionHandlers[i]); 062 } 063 Arrays.sort(exceptionHandlers); 064 } 065 } 066 067 public void preExecute(InstructionHandle ih) { 068 if (currentHandler<exceptionHandlers.length) 069 logger.debug("position="+ih.getPosition()+", nextHandler="+exceptionHandlers[currentHandler]); 070 if ( currentHandler<exceptionHandlers.length && 071 ih.getPosition()==exceptionHandlers[currentHandler] ) { 072 logger.debug("entering exception handler"); 073 currentHandler++; 074 push(dontCare); 075 } 076 } 077 078 static Set primitiveWrapperTypes = new HashSet(); 079 static { 080 primitiveWrapperTypes.add("java.lang.Float"); 081 primitiveWrapperTypes.add("java.lang.Double"); 082 primitiveWrapperTypes.add("java.lang.Integer"); 083 primitiveWrapperTypes.add("java.lang.Long"); 084 primitiveWrapperTypes.add("java.lang.Boolean"); 085 primitiveWrapperTypes.add("java.lang.Character"); 086 primitiveWrapperTypes.add("java.lang.Byte"); 087 } 088 089 public void execute(Instruction i, InstructionHandle ih) { 090 logger.debug("execute "+i.toString(cp.getConstantPool())); 091 092 if (i instanceof SWAP) { 093 swap(); 094 } else if (i instanceof DUP || i instanceof DUP2) { 095 push(peek()); 096 } else if (i instanceof DUP_X1 || i instanceof DUP2_X2 || 097 i instanceof DUP2_X1 || i instanceof DUP_X2) { 098 swap(); 099 push(peek(1)); 100 } else if (i instanceof ALOAD && ((ALOAD)i).getIndex() == 0 101 && !isStatic) { 102 push(thisPointer); 103 } else if (i instanceof NEW) { 104 if (primitiveWrapperTypes.contains( 105 ((NEW)i).getLoadClassType(cp).getClassName())) { 106 push(new PrimitiveValue(((NEW)i).getLoadClassType(cp).getClassName())); 107 } else { 108 push(new Instance( 109 ((NEW)i).getLoadClassType(cp).getClassName(),ih)); 110 } 111 } else if (i instanceof LoadInstruction) { 112 LoadInstruction load = (LoadInstruction)i; 113 if (load.getIndex()<=nbArgs) { 114 push(new Argument(load.getIndex())); 115 } else { 116 int index = load.getIndex()-nbArgs; 117 // We must ensure the size of locals is correct 118 // because a LOAD may occur before a STORE in the 119 // bytecode (because of a JMP) 120 if (locals.size()<index+1) 121 locals.setSize(index+1); 122 push(locals.get(index)); 123 } 124 } else if (i instanceof StoreInstruction) { 125 StoreInstruction store = (StoreInstruction)i; 126 if (store.getIndex()<=nbArgs) { 127 } else { 128 int index = store.getIndex()-nbArgs; 129 if (locals.size()<store.getIndex()+1) 130 locals.setSize(store.getIndex()+1); 131 locals.set(store.getIndex(),peek()); 132 } 133 consume(i); 134 } else if (i instanceof GETFIELD) { 135 Object substance = peek(); 136 consume(i); 137 push(new FieldValue(substance, 138 ((GETFIELD)i).getIndex(), 139 ((GETFIELD)i).getFieldName(cp))); 140 } else if (i instanceof GETSTATIC) { 141 consume(i); 142 push(new FieldValue(null, 143 ((GETSTATIC)i).getIndex(), 144 ((GETSTATIC)i).getFieldName(cp))); 145 } else if (i instanceof INVOKESPECIAL && 146 ((INVOKESPECIAL)i).getMethodName(cp).equals("<init>")) { 147 Object invoked = invokedObject((INVOKESPECIAL)i); 148 if (invoked instanceof PrimitiveValue) 149 ((PrimitiveValue)invoked).wrappedValue = peek(); 150 consume(i); 151 produce(i); 152 /* 153 } else if (i instanceof InvokeInstruction) { 154 InvokeInstruction invoke = (InvokeInstruction)i; 155 if (invoke.getMethodName(cp).equals("iterator")) { 156 consume(i); 157 push(new IteratorValue(peek())); 158 } else if (invoke.getMethodName(cp).equals("next") && 159 peek() instanceof IteratorValue) { 160 consume(i); 161 push(new CollectionValue(((IteratorValue)peek()).collection)); 162 } else { 163 consume(i); 164 produce(i); 165 } 166 */ 167 } else if (i instanceof CHECKCAST || i instanceof ATHROW) { 168 // nothing 169 } else if (i instanceof ANEWARRAY) { 170 // BCEL bug workaround (ANEWARRAY is a StackProducer but not 171 // a StackConsumer) 172 pop(1); 173 push(dontCare); 174 } else { 175 consume(i); 176 produce(i); 177 } 178 logger.debug("stack: "+this); 179 } 180 181 /** 182 * Returns the stack element corresponding to the object on which 183 * the InvokeInstruction is applied. 184 */ 185 public Object invokedObject(InvokeInstruction i) { 186 return peek(i.getArgumentTypes(cp).length); 187 } 188 189 /** 190 * Consume values from the stack for the given instruction 191 */ 192 public void consume(Instruction i) { 193 if (i instanceof StackConsumer) 194 pop(getConsumed(i,cp)); 195 } 196 public void produce(Instruction i) { 197 if (i instanceof StackProducer) { 198 for(int j=0; j<getProduced(i,cp); j++) 199 push(dontCare); 200 } 201 } 202 /** 203 * Returns the number of elements from the stack consumed by an 204 * instruction 205 */ 206 public static int getConsumed(Instruction i, ConstantPoolGen cp) { 207 if (i instanceof INVOKESTATIC) 208 return ((InvokeInstruction)i).getArgumentTypes(cp).length; 209 else if (i instanceof InvokeInstruction) 210 return ((InvokeInstruction)i).getArgumentTypes(cp).length+1; 211 else if (i instanceof MULTIANEWARRAY) 212 return ((MULTIANEWARRAY)i).getDimensions(); 213 else 214 return CONSUME_STACK[i.getOpcode()]; 215 } 216 217 /** 218 * Returns the number of elements produced on the stack by an instruction 219 */ 220 public static int getProduced(Instruction i, ConstantPoolGen cp) { 221 if (i instanceof InvokeInstruction) { 222 return ((InvokeInstruction)i).getReturnType(cp)==Type.VOID ? 0 : 1; 223 } else { 224 return PRODUCE_STACK[i.getOpcode()]; 225 } 226 } 227 228 /** 229 * Gets the value on which a method is invoked 230 * @param invoke the invoke instruction 231 */ 232 public Object getSubstance(InvokeInstruction invoke) { 233 return peek(invoke.getArgumentTypes(cp).length); 234 } 235 236 static final int[] CONSUME_STACK = { 237 0/*nop*/, 0/*aconst_null*/, 0/*iconst_m1*/, 0/*iconst_0*/, 0/*iconst_1*/, 238 0/*iconst_2*/, 0/*iconst_3*/, 0/*iconst_4*/, 0/*iconst_5*/, 0/*lconst_0*/, 239 0/*lconst_1*/, 0/*fconst_0*/, 0/*fconst_1*/, 0/*fconst_2*/, 0/*dconst_0*/, 240 0/*dconst_1*/, 0/*bipush*/, 0/*sipush*/, 0/*ldc*/, 0/*ldc_w*/, 0/*ldc2_w*/, 0/*iload*/, 241 0/*lload*/, 0/*fload*/, 0/*dload*/, 0/*aload*/, 0/*iload_0*/, 0/*iload_1*/, 0/*iload_2*/, 242 0/*iload_3*/, 0/*lload_0*/, 0/*lload_1*/, 0/*lload_2*/, 0/*lload_3*/, 0/*fload_0*/, 243 0/*fload_1*/, 0/*fload_2*/, 0/*fload_3*/, 0/*dload_0*/, 0/*dload_1*/, 0/*dload_2*/, 244 0/*dload_3*/, 0/*aload_0*/, 0/*aload_1*/, 0/*aload_2*/, 0/*aload_3*/, 2/*iaload*/, 245 2/*laload*/, 2/*faload*/, 2/*daload*/, 2/*aaload*/, 2/*baload*/, 2/*caload*/, 2/*saload*/, 246 1/*istore*/, 1/*lstore*/, 1/*fstore*/, 1/*dstore*/, 1/*astore*/, 1/*istore_0*/, 247 1/*istore_1*/, 1/*istore_2*/, 1/*istore_3*/, 1/*lstore_0*/, 1/*lstore_1*/, 248 1/*lstore_2*/, 1/*lstore_3*/, 1/*fstore_0*/, 1/*fstore_1*/, 1/*fstore_2*/, 249 1/*fstore_3*/, 1/*dstore_0*/, 1/*dstore_1*/, 1/*dstore_2*/, 1/*dstore_3*/, 250 1/*astore_0*/, 1/*astore_1*/, 1/*astore_2*/, 1/*astore_3*/, 3/*iastore*/, 3/*lastore*/, 251 3/*fastore*/, 3/*dastore*/, 3/*aastore*/, 3/*bastore*/, 3/*castore*/, 3/*sastore*/, 252 1/*pop*/, 1/*pop2*/, 1/*dup*/, 2/*dup_x1*/, 3/*dup_x2*/, 1/*dup2*/, 3/*dup2_x1*/, 253 4/*dup2_x2*/, 2/*swap*/, 2/*iadd*/, 2/*ladd*/, 2/*fadd*/, 2/*dadd*/, 2/*isub*/, 2/*lsub*/, 254 2/*fsub*/, 2/*dsub*/, 2/*imul*/, 2/*lmul*/, 2/*fmul*/, 2/*dmul*/, 2/*idiv*/, 2/*ldiv*/, 255 2/*fdiv*/, 2/*ddiv*/, 2/*irem*/, 2/*lrem*/, 2/*frem*/, 2/*drem*/, 1/*ineg*/, 1/*lneg*/, 256 1/*fneg*/, 1/*dneg*/, 2/*ishl*/, 2/*lshl*/, 2/*ishr*/, 2/*lshr*/, 2/*iushr*/, 2/*lushr*/, 257 2/*iand*/, 2/*land*/, 2/*ior*/, 2/*lor*/, 2/*ixor*/, 2/*lxor*/, 0/*iinc*/, 258 1/*i2l*/, 1/*i2f*/, 1/*i2d*/, 1/*l2i*/, 1/*l2f*/, 1/*l2d*/, 1/*f2i*/, 1/*f2l*/, 259 1/*f2d*/, 1/*d2i*/, 1/*d2l*/, 1/*d2f*/, 1/*i2b*/, 1/*i2c*/, 1/*i2s*/, 260 2/*lcmp*/, 2/*fcmpl*/, 2/*fcmpg*/, 2/*dcmpl*/, 2/*dcmpg*/, 1/*ifeq*/, 1/*ifne*/, 261 1/*iflt*/, 1/*ifge*/, 1/*ifgt*/, 1/*ifle*/, 2/*if_icmpeq*/, 2/*if_icmpne*/, 2/*if_icmplt*/, 262 2 /*if_icmpge*/, 2/*if_icmpgt*/, 2/*if_icmple*/, 2/*if_acmpeq*/, 2/*if_acmpne*/, 263 0/*goto*/, 0/*jsr*/, 0/*ret*/, 1/*tableswitch*/, 1/*lookupswitch*/, 1/*ireturn*/, 264 1/*lreturn*/, 1/*freturn*/, 1/*dreturn*/, 1/*areturn*/, 0/*return*/, 0/*getstatic*/, 265 1,/*putstatic*/ 1/*getfield*/, 2/*putfield*/, 266 UNPREDICTABLE/*invokevirtual*/, UNPREDICTABLE/*invokespecial*/, 267 UNPREDICTABLE/*invokestatic*/, 268 UNPREDICTABLE/*invokeinterface*/, UNDEFINED, 0/*new*/, 1/*newarray*/, 1/*anewarray*/, 269 1/*arraylength*/, 1/*athrow*/, 1/*checkcast*/, 1/*instanceof*/, 1/*monitorenter*/, 270 1/*monitorexit*/, 0/*wide*/, UNPREDICTABLE/*multianewarray*/, 1/*ifnull*/, 1/*ifnonnull*/, 271 0/*goto_w*/, 0/*jsr_w*/, 0/*breakpoint*/, UNDEFINED, UNDEFINED, 272 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 273 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 274 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 275 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 276 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 277 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 278 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 279 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 280 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 281 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 282 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 283 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 284 UNDEFINED, UNPREDICTABLE/*impdep1*/, UNPREDICTABLE/*impdep2*/ 285 }; 286 287 public static final int[] PRODUCE_STACK = { 288 0/*nop*/, 1/*aconst_null*/, 1/*iconst_m1*/, 1/*iconst_0*/, 1/*iconst_1*/, 289 1/*iconst_2*/, 1/*iconst_3*/, 1/*iconst_4*/, 1/*iconst_5*/, 1/*lconst_0*/, 290 1/*lconst_1*/, 1/*fconst_0*/, 1/*fconst_1*/, 1/*fconst_2*/, 1/*dconst_0*/, 291 1/*dconst_1*/, 1/*bipush*/, 1/*sipush*/, 1/*ldc*/, 1/*ldc_w*/, 1/*ldc2_w*/, 1/*iload*/, 292 1/*lload*/, 1/*fload*/, 1/*dload*/, 1/*aload*/, 1/*iload_0*/, 1/*iload_1*/, 1/*iload_2*/, 293 1/*iload_3*/, 1/*lload_0*/, 1/*lload_1*/, 1/*lload_2*/, 1/*lload_3*/, 1/*fload_0*/, 294 1/*fload_1*/, 1/*fload_2*/, 1/*fload_3*/, 1/*dload_0*/, 1/*dload_1*/, 1/*dload_2*/, 295 1/*dload_3*/, 1/*aload_0*/, 1/*aload_1*/, 1/*aload_2*/, 1/*aload_3*/, 1/*iaload*/, 296 1/*laload*/, 1/*faload*/, 1/*daload*/, 1/*aaload*/, 1/*baload*/, 1/*caload*/, 1/*saload*/, 297 0/*istore*/, 0/*lstore*/, 0/*fstore*/, 0/*dstore*/, 0/*astore*/, 0/*istore_0*/, 298 0/*istore_1*/, 0/*istore_2*/, 0/*istore_3*/, 0/*lstore_0*/, 0/*lstore_1*/, 299 0/*lstore_2*/, 0/*lstore_3*/, 0/*fstore_0*/, 0/*fstore_1*/, 0/*fstore_2*/, 300 0/*fstore_3*/, 0/*dstore_0*/, 0/*dstore_1*/, 0/*dstore_2*/, 0/*dstore_3*/, 301 0/*astore_0*/, 0/*astore_1*/, 0/*astore_2*/, 0/*astore_3*/, 0/*iastore*/, 0/*lastore*/, 302 0/*fastore*/, 0/*dastore*/, 0/*aastore*/, 0/*bastore*/, 0/*castore*/, 0/*sastore*/, 303 0/*pop*/, 0/*pop2*/, 2/*dup*/, 3/*dup_x1*/, 4/*dup_x2*/, 4/*dup2*/, 5/*dup2_x1*/, 304 6/*dup2_x2*/, 2/*swap*/, 1/*iadd*/, 1/*ladd*/, 1/*fadd*/, 1/*dadd*/, 1/*isub*/, 1/*lsub*/, 305 1/*fsub*/, 1/*dsub*/, 1/*imul*/, 1/*lmul*/, 1/*fmul*/, 1/*dmul*/, 1/*idiv*/, 1/*ldiv*/, 306 1/*fdiv*/, 1/*ddiv*/, 1/*irem*/, 1/*lrem*/, 1/*frem*/, 1/*drem*/, 1/*ineg*/, 1/*lneg*/, 307 1/*fneg*/, 1/*dneg*/, 1/*ishl*/, 1/*lshl*/, 1/*ishr*/, 1/*lshr*/, 1/*iushr*/, 1/*lushr*/, 308 1/*iand*/, 1/*land*/, 1/*ior*/, 1/*lor*/, 1/*ixor*/, 1/*lxor*/, 309 0/*iinc*/, 1/*i2l*/, 1/*i2f*/, 1/*i2d*/, 1/*l2i*/, 1/*l2f*/, 1/*l2d*/, 1/*f2i*/, 310 1/*f2l*/, 1/*f2d*/, 1/*d2i*/, 1/*d2l*/, 1/*d2f*/, 311 1/*i2b*/, 1/*i2c*/, 1/*i2s*/, 1/*lcmp*/, 1/*fcmpl*/, 1/*fcmpg*/, 312 1/*dcmpl*/, 1/*dcmpg*/, 0/*ifeq*/, 0/*ifne*/, 0/*iflt*/, 0/*ifge*/, 0/*ifgt*/, 0/*ifle*/, 313 0/*if_icmpeq*/, 0/*if_icmpne*/, 0/*if_icmplt*/, 0/*if_icmpge*/, 0/*if_icmpgt*/, 314 0/*if_icmple*/, 0/*if_acmpeq*/, 0/*if_acmpne*/, 0/*goto*/, 1/*jsr*/, 0/*ret*/, 315 0/*tableswitch*/, 0/*lookupswitch*/, 0/*ireturn*/, 0/*lreturn*/, 0/*freturn*/, 316 0/*dreturn*/, 0/*areturn*/, 0/*return*/, 1/*getstatic*/, 0/*putstatic*/, 317 1/*getfield*/, 0/*putfield*/, UNPREDICTABLE/*invokevirtual*/, 318 UNPREDICTABLE/*invokespecial*/, UNPREDICTABLE/*invokestatic*/, 319 UNPREDICTABLE/*invokeinterface*/, UNDEFINED, 1/*new*/, 1/*newarray*/, 1/*anewarray*/, 320 1/*arraylength*/, 1/*athrow*/, 1/*checkcast*/, 1/*instanceof*/, 0/*monitorenter*/, 321 0/*monitorexit*/, 0/*wide*/, 1/*multianewarray*/, 0/*ifnull*/, 0/*ifnonnull*/, 322 0/*goto_w*/, 1/*jsr_w*/, 0/*breakpoint*/, UNDEFINED, UNDEFINED, 323 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 324 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 325 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 326 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 327 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 328 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 329 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 330 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 331 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 332 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 333 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 334 UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, 335 UNDEFINED, UNPREDICTABLE/*impdep1*/, UNPREDICTABLE/*impdep2*/ 336 }; 337 338 // various classes to represent values on the stack 339 public static class ThisPointer implements Serializable { 340 public String toString() { return "This"; } 341 } 342 343 /** Unknown value */ 344 public static class DontCare implements Serializable { 345 public String toString() { return "???"; } 346 } 347 348 /** Instance of a class */ 349 public static class Instance implements Serializable { 350 public String type; 351 /** the InstructionHandle who created this instance */ 352 public transient InstructionHandle newHandle; 353 public transient InstructionHandle initHandle; 354 public Instance(String type, InstructionHandle newHandle) { 355 this.type = type; 356 this.newHandle = newHandle; 357 } 358 public String toString() { return type; } 359 } 360 361 /** An argument */ 362 public static class Argument implements Serializable { 363 public int n; 364 public Argument(int n) { this.n = n; } 365 public String toString() { return "arg["+n+"]"; } 366 } 367 368 /** The value of a field */ 369 public static class FieldValue implements Serializable { 370 int index; // const pool FieldRef index 371 String field; // name of field 372 Object substance; // owner of the field 373 public FieldValue(Object substance, int index, String field) { 374 this.field = field; 375 this.index = index; 376 this.substance = substance; 377 } 378 public String toString() { return substance+"."+field; } 379 } 380 381 /** A primitive value */ 382 public static class PrimitiveValue implements Serializable { 383 public Object wrappedValue; 384 public String type; 385 public PrimitiveValue(String type) { 386 this.type = type; 387 this.wrappedValue = null; 388 } 389 public String toString() { 390 return type+"("+wrappedValue+")"; 391 } 392 } 393 394 /** An iterator on a collection */ 395 public static class IteratorValue { 396 public Object collection; 397 public IteratorValue(Object collection) { 398 this.collection = collection; 399 } 400 public String toString() { 401 return "iterator("+collection.toString()+")"; 402 } 403 } 404 405 /** An item of a collection */ 406 public static class CollectionValue { 407 public Object collection; 408 public CollectionValue(Object collection) { 409 this.collection = collection; 410 } 411 public String toString() { 412 return "iterator("+collection.toString()+")"; 413 } 414 } 415 } 416