001 package edu.rice.cs.cunit.classFile.code.instructions; 002 003 import edu.rice.cs.cunit.classFile.code.Opcode; 004 import edu.rice.cs.cunit.classFile.constantPool.ConstantPool; 005 import edu.rice.cs.cunit.util.Types; 006 007 /** 008 * Instruction containing a reference to the constant pool. 009 * 010 * @author Mathias 011 */ 012 public class ReferenceInstruction extends GenericInstruction { 013 /** 014 * Size of the reference in bytes. 015 */ 016 int _refSize; 017 018 /** 019 * Constructor. 020 * 021 * @param opcode invoke opcode 022 * @param constantPoolId method id in constant pool 023 */ 024 public ReferenceInstruction(byte opcode, int constantPoolId) { 025 super(new byte[]{Opcode.NOP}); 026 027 assert(constantPoolId <= 0xFFFF); 028 checkOpcode(opcode); 029 030 _code = new byte[1+_refSize]; 031 _code[0] = opcode; 032 setReference(constantPoolId); 033 } 034 035 /** 036 * Make a new generic instruction from the bytecode stating at pc, padded using paddingPC, and use the line number 037 * table for branches. 038 * 039 * @param bytecode bytecode 040 * @param pc starting index in bytecode 041 * @param paddingPC PC for padding 042 * @param lnt line number table for branches 043 */ 044 public ReferenceInstruction(byte[] bytecode, int pc, int paddingPC, LineNumberTable lnt) { 045 super(bytecode, pc, paddingPC, lnt); 046 checkOpcode(bytecode[pc]); 047 } 048 049 /** 050 * Check the opcode to make sure it is a reference instruction. 051 * @param opcode opcode to check 052 */ 053 private void checkOpcode(byte opcode) { 054 switch(opcode) { 055 case Opcode.INVOKESTATIC: 056 case Opcode.INVOKESPECIAL: 057 case Opcode.INVOKEVIRTUAL: 058 case Opcode.CHECKCAST: 059 case Opcode.GETFIELD: 060 case Opcode.GETSTATIC: 061 case Opcode.INSTANCEOF: 062 case Opcode.NEW: 063 case Opcode.PUTFIELD: 064 case Opcode.PUTSTATIC: 065 case Opcode.ANEWARRAY: 066 case Opcode.LDC_W: 067 case Opcode.LDC2_W: 068 _refSize = 2; 069 break; 070 case Opcode.LDC: 071 _refSize = 1; 072 break; 073 default: 074 throw new IllegalArgumentException("Illegal reference instruction: " + Opcode.getOpcodeName(opcode)); 075 } 076 } 077 078 /** 079 * Set the constant pool id. 080 * 081 * @param constantPoolId new constant pool id 082 */ 083 public void setReference(int constantPoolId) { 084 assert(constantPoolId <= 0xFFFF); 085 086 if (_refSize==1) { 087 _code[1] = (byte)(0x00FF & constantPoolId); 088 } 089 else { 090 Types.bytesFromShort((short)(0xFFFF & constantPoolId), _code, 1); 091 } 092 } 093 094 /** 095 * Get the constant pool id. 096 * 097 * @return constant pool id 098 */ 099 public int getReference() { 100 if (_refSize==1) { 101 return _code[1] & 0xff; 102 } 103 else { 104 return Types.ushortFromBytes(_code, 1); 105 } 106 } 107 108 /** 109 * Return a verbose string representation. 110 * 111 * @param cp constant pool 112 * @return verbose string representation 113 */ 114 public String toStringVerbose(ConstantPool cp) { 115 StringBuilder x = new StringBuilder(); 116 x.append(Opcode.getOpcodeName(_code[0])); 117 x.append(' '); 118 int ref = getReference(); 119 assert(ref <= 0xFFFF); 120 x.append(cp.get(ref).toString()); 121 x.append(' '); 122 x.append("(CP="); 123 x.append(ref); 124 x.append(") "); 125 for(int i = 1; i < _code.length; ++i) { 126 x.append(String.format("%02x ", new Object[]{new Byte(_code[i])})); 127 } 128 129 return x.toString(); 130 } 131 }