You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Instruction.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. package org.aspectj.apache.bcel.generic;
  2. /* ====================================================================
  3. * The Apache Software License, Version 1.1
  4. *
  5. * Copyright (c) 2001 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Apache" and "Apache Software Foundation" and
  28. * "Apache BCEL" must not be used to endorse or promote products
  29. * derived from this software without prior written permission. For
  30. * written permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * "Apache BCEL", nor may "Apache" appear in their name, without
  34. * prior written permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation. For more
  52. * information on the Apache Software Foundation, please see
  53. * <http://www.apache.org/>.
  54. */
  55. import java.io.DataOutputStream;
  56. import java.io.IOException;
  57. import java.io.Serializable;
  58. import org.aspectj.apache.bcel.Constants;
  59. import org.aspectj.apache.bcel.classfile.ConstantPool;
  60. import org.aspectj.apache.bcel.util.ByteSequence;
  61. /**
  62. * Abstract super class for all Java byte codes.
  63. *
  64. * @version $Id: Instruction.java,v 1.10 2011/04/05 15:15:33 aclement Exp $
  65. * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  66. */
  67. public class Instruction implements Cloneable, Serializable, Constants {
  68. public short opcode = -1;
  69. public Instruction(short opcode) {
  70. this.opcode = opcode;
  71. }
  72. public void dump(DataOutputStream out) throws IOException {
  73. out.writeByte(opcode);
  74. }
  75. public String getName() {
  76. return Constants.OPCODE_NAMES[opcode];
  77. }
  78. /**
  79. * Use with caution, since 'BranchInstruction's have a 'target' reference which is not copied correctly (only basic types are).
  80. * This also applies for 'Select' instructions with their multiple branch targets.
  81. *
  82. * @return (shallow) copy of an instruction
  83. */
  84. // GET RID OF THIS - make it throw an exception and track the callers
  85. final public Instruction copy() {
  86. // if overridden correctly can just return 'this' here
  87. if (InstructionConstants.INSTRUCTIONS[opcode] != null) { // immutable instructions do not need copying
  88. return this;
  89. } else {
  90. Instruction i = null;
  91. try {// OPTIMIZE is clone the right thing to do here? it is horrible
  92. i = (Instruction) clone();
  93. } catch (CloneNotSupportedException e) {
  94. System.err.println(e);
  95. }
  96. return i;
  97. }
  98. }
  99. /**
  100. * Read an instruction bytecode from an input stream and return the appropriate object.
  101. *
  102. * @param file file to read from
  103. * @return instruction object being read
  104. */
  105. public static final Instruction readInstruction(ByteSequence bytes) throws IOException {
  106. boolean wide = false;
  107. short opcode = (short) bytes.readUnsignedByte();
  108. if (opcode == Constants.WIDE) {
  109. wide = true;
  110. opcode = (short) bytes.readUnsignedByte();
  111. }
  112. Instruction constantInstruction = InstructionConstants.INSTRUCTIONS[opcode];
  113. if (constantInstruction != null) {
  114. return constantInstruction;
  115. }
  116. Instruction obj = null;
  117. try {
  118. switch (opcode) {
  119. case Constants.BIPUSH:
  120. obj = new InstructionByte(Constants.BIPUSH, bytes.readByte());
  121. break;
  122. case Constants.SIPUSH:
  123. obj = new InstructionShort(Constants.SIPUSH, bytes.readShort());
  124. break;
  125. case Constants.LDC:
  126. obj = new InstructionCP(Constants.LDC, bytes.readUnsignedByte());
  127. break;
  128. case Constants.LDC_W:
  129. case Constants.LDC2_W:
  130. obj = new InstructionCP(opcode, bytes.readUnsignedShort());
  131. break;
  132. case Constants.ILOAD:
  133. case Constants.LLOAD:
  134. case Constants.FLOAD:
  135. case Constants.DLOAD:
  136. case Constants.ALOAD:
  137. case Constants.ISTORE:
  138. case Constants.LSTORE:
  139. case Constants.FSTORE:
  140. case Constants.DSTORE:
  141. case Constants.ASTORE:
  142. obj = new InstructionLV(opcode, wide ? bytes.readUnsignedShort() : bytes.readUnsignedByte());
  143. break;
  144. case Constants.IINC:
  145. obj = new IINC(wide ? bytes.readUnsignedShort() : bytes.readUnsignedByte(), wide ? bytes.readShort()
  146. : bytes.readByte(), wide);
  147. break;
  148. case Constants.IFNULL:
  149. case Constants.IFNONNULL:
  150. case Constants.IFEQ:
  151. case Constants.IFNE:
  152. case Constants.IFLT:
  153. case Constants.IFGE:
  154. case Constants.IFGT:
  155. case Constants.IFLE:
  156. case Constants.IF_ICMPEQ:
  157. case Constants.IF_ICMPNE:
  158. case Constants.IF_ICMPLT:
  159. case Constants.IF_ICMPGE:
  160. case Constants.IF_ICMPGT:
  161. case Constants.IF_ICMPLE:
  162. case Constants.IF_ACMPEQ:
  163. case Constants.IF_ACMPNE:
  164. case Constants.GOTO:
  165. case Constants.JSR:
  166. obj = new InstructionBranch(opcode, bytes.readShort());
  167. break;
  168. case Constants.GOTO_W:
  169. case Constants.JSR_W:
  170. obj = new InstructionBranch(opcode, bytes.readInt());
  171. break;
  172. case Constants.TABLESWITCH:
  173. obj = new TABLESWITCH(bytes);
  174. break;
  175. case Constants.LOOKUPSWITCH:
  176. obj = new LOOKUPSWITCH(bytes);
  177. break;
  178. case Constants.RET:
  179. obj = new RET(wide ? bytes.readUnsignedShort() : bytes.readUnsignedByte(), wide);
  180. break;
  181. case Constants.NEW:
  182. obj = new InstructionCP(Constants.NEW, bytes.readUnsignedShort());
  183. break;
  184. case Constants.GETSTATIC:
  185. case Constants.PUTSTATIC:
  186. case Constants.GETFIELD:
  187. case Constants.PUTFIELD:
  188. obj = new FieldInstruction(opcode, bytes.readUnsignedShort());
  189. break;
  190. case Constants.INVOKEVIRTUAL:
  191. case Constants.INVOKESPECIAL:
  192. case Constants.INVOKESTATIC:
  193. obj = new InvokeInstruction(opcode, bytes.readUnsignedShort());
  194. break;
  195. case Constants.INVOKEINTERFACE:
  196. obj = new INVOKEINTERFACE(bytes.readUnsignedShort(), bytes.readUnsignedByte(), bytes.readByte());
  197. break;
  198. case Constants.INVOKEDYNAMIC:
  199. obj = new InvokeDynamic(bytes.readUnsignedShort(),bytes.readUnsignedShort());
  200. break;
  201. case Constants.NEWARRAY:
  202. obj = new InstructionByte(Constants.NEWARRAY, bytes.readByte());
  203. break;
  204. case Constants.ANEWARRAY:
  205. case Constants.CHECKCAST:
  206. obj = new InstructionCP(opcode, bytes.readUnsignedShort());
  207. break;
  208. case Constants.INSTANCEOF:
  209. obj = new InstructionCP(Constants.INSTANCEOF, bytes.readUnsignedShort());
  210. break;
  211. case Constants.MULTIANEWARRAY:
  212. obj = new MULTIANEWARRAY(bytes.readUnsignedShort(), bytes.readByte());
  213. break;
  214. default:
  215. throw new ClassGenException("Illegal opcode detected");
  216. }
  217. } catch (ClassGenException e) {
  218. throw e;
  219. } catch (Exception e) {
  220. throw new ClassGenException(e.toString());
  221. }
  222. return obj;
  223. }
  224. /**
  225. * @return Number of words consumed from stack by this instruction, or Constants.UNPREDICTABLE, if this can not be computed
  226. * statically
  227. */
  228. public int consumeStack(ConstantPool cpg) {
  229. return Constants.CONSUME_STACK[opcode];
  230. }
  231. /**
  232. * @return Number of words produced onto stack by this instruction, or Constants.UNPREDICTABLE, if this can not be computed
  233. * statically
  234. */
  235. public int produceStack(ConstantPool cpg) {
  236. return Constants.stackEntriesProduced[opcode];
  237. }
  238. public short getOpcode() {
  239. return opcode;
  240. }
  241. public int getLength() {
  242. // if it is zero, it should have been provided by an overriding implementation of getLength()
  243. int len = Constants.iLen[opcode];
  244. assert len != 0;
  245. // if (len == 0) {
  246. // throw new IllegalStateException("Length not right for " + getName().toUpperCase());
  247. // }
  248. return len;
  249. }
  250. /** Some instructions may be reused, so don't do anything by default */
  251. void dispose() {
  252. }
  253. @Override
  254. public boolean equals(Object other) {
  255. if (this.getClass() != Instruction.class) {
  256. throw new RuntimeException("NO WAY " + this.getClass());
  257. }
  258. if (!(other instanceof Instruction)) {
  259. return false;
  260. }
  261. return ((Instruction) other).opcode == opcode;
  262. // IMPLEMENT EQUALS AND HASHCODE IN THE SUBTYPES!
  263. // Instruction i1 = this;
  264. // Instruction i2 = (Instruction) that;
  265. // if (i1.opcode == i2.opcode) {
  266. // if (i1.isConstantInstruction()) {
  267. // return i1.getValue().equals(i2.getValue());
  268. // } else if (i1.isIndexedInstruction()) {
  269. // return i1.getIndex() == i2.getIndex();
  270. // } else if (i1.opcode == Constants.NEWARRAY) {
  271. // return ((InstructionByte) i1).getTypecode() == ((InstructionByte) i2).getTypecode();
  272. // } else {
  273. // return true;
  274. // }
  275. // }
  276. //
  277. // return false;
  278. }
  279. @Override
  280. public int hashCode() {
  281. if (this.getClass() != Instruction.class) {
  282. throw new RuntimeException("NO WAY " + this.getClass());
  283. }
  284. return opcode * 37;
  285. // int result = 17 + opcode * 37;
  286. // if (isConstantInstruction()) {
  287. // result = 37 * getValue().hashCode() + result;
  288. // } else if (isIndexedInstruction()) {
  289. // result = 37 * getIndex() + result;
  290. // } else if (opcode == Constants.NEWARRAY) {
  291. // result = 37 * ((InstructionByte) this).getTypecode() + result;
  292. // }
  293. // return result;
  294. }
  295. public Type getType() {
  296. return getType(null);
  297. }
  298. public Type getType(ConstantPool cp) {
  299. // if (types[opcode]==null) throw new RuntimeException(getName()+" is not a typed instruction");
  300. Type t = Constants.types[opcode];
  301. if (t != null) {
  302. return t;
  303. }
  304. throw new RuntimeException("Do not know type for instruction " + getName() + "(" + opcode + ")");
  305. }
  306. public Number getValue() {
  307. assert (instFlags[opcode] & CONSTANT_INST) == 0;
  308. // if ((instFlags[opcode] & CONSTANT_INST) == 0) {
  309. // throw new RuntimeException(getName() + " is not a constant instruction");
  310. // }
  311. switch (opcode) {
  312. case ICONST_M1:
  313. case ICONST_0:
  314. case ICONST_1:
  315. case ICONST_2:
  316. case ICONST_3:
  317. case ICONST_4:
  318. case ICONST_5:
  319. return opcode - ICONST_0;
  320. default:
  321. throw new IllegalStateException("Not implemented yet for " + getName());
  322. }
  323. }
  324. public int getIndex() {
  325. return -1;
  326. }
  327. public void setIndex(int i) {
  328. throw new IllegalStateException("Shouldnt be asking " + getName().toUpperCase());
  329. }
  330. public Object getValue(ConstantPool cpg) {
  331. throw new IllegalStateException("Shouldnt be asking " + getName().toUpperCase());
  332. }
  333. public boolean isLoadInstruction() {
  334. return (Constants.instFlags[opcode] & LOAD_INST) != 0;
  335. }
  336. // remove these from here, leave them in the InstructionLV
  337. public boolean isASTORE() {
  338. return false;
  339. }
  340. public boolean isALOAD() {
  341. return false;
  342. }
  343. public boolean isStoreInstruction() {
  344. return (Constants.instFlags[opcode] & STORE_INST) != 0;
  345. }
  346. // public boolean containsTarget(InstructionHandle ih) {
  347. // throw new IllegalStateException("Dont ask!!");
  348. // }
  349. public boolean isJsrInstruction() {
  350. return (Constants.instFlags[opcode] & JSR_INSTRUCTION) != 0;
  351. }
  352. public boolean isConstantInstruction() {
  353. return (Constants.instFlags[opcode] & CONSTANT_INST) != 0;
  354. }
  355. public boolean isConstantPoolInstruction() {
  356. return (Constants.instFlags[opcode] & CP_INST) != 0;
  357. }
  358. public boolean isStackProducer() {
  359. return Constants.stackEntriesProduced[opcode] != 0;
  360. }
  361. public boolean isStackConsumer() {
  362. return Constants.CONSUME_STACK[opcode] != 0;
  363. }
  364. public boolean isIndexedInstruction() {
  365. return (Constants.instFlags[opcode] & INDEXED) != 0;
  366. }
  367. public boolean isArrayCreationInstruction() {
  368. return opcode == NEWARRAY || opcode == ANEWARRAY || opcode == MULTIANEWARRAY;
  369. }
  370. public ObjectType getLoadClassType(ConstantPool cpg) {
  371. assert (Constants.instFlags[opcode] & Constants.LOADCLASS_INST) == 0;
  372. // if ((Constants.instFlags[opcode] & Constants.LOADCLASS_INST) == 0) {
  373. // throw new IllegalStateException("This opcode " + opcode + " does not have the property "
  374. // + Long.toHexString(Constants.LOADCLASS_INST));
  375. // }
  376. Type t = getType(cpg);
  377. if (t instanceof ArrayType) {
  378. t = ((ArrayType) t).getBasicType();
  379. }
  380. return t instanceof ObjectType ? (ObjectType) t : null;
  381. }
  382. public boolean isReturnInstruction() {
  383. return (Constants.instFlags[opcode] & RET_INST) != 0;
  384. }
  385. // public boolean isGoto() {
  386. // return opcode == GOTO || opcode == GOTO_W;
  387. // }
  388. public boolean isLocalVariableInstruction() {
  389. return (Constants.instFlags[opcode] & LV_INST) != 0;
  390. }
  391. /**
  392. * Long output format: 'name of opcode' "[" 'opcode number' "]" "(" 'length of instruction' ")"
  393. */
  394. public String toString(boolean verbose) {
  395. if (verbose) {
  396. StringBuilder sb = new StringBuilder();
  397. sb.append(getName()).append("[").append(opcode).append("](size").append(Constants.iLen[opcode]).append(")");
  398. return sb.toString();
  399. } else {
  400. return getName();
  401. }
  402. }
  403. @Override
  404. public String toString() {
  405. return toString(true);
  406. }
  407. }