PageRenderTime 890ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/com/alibaba/fastjson/asm/MethodWriter.java

https://bitbucket.org/xiejuntao/xdesktop
Java | 393 lines | 164 code | 48 blank | 181 comment | 43 complexity | 8ba7af5218d1718bfe5e0ea8156bf9a1 MD5 | raw file
  1. /***
  2. * ASM: a very small and fast Java bytecode manipulation framework
  3. * Copyright (c) 2000-2007 INRIA, France Telecom
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the copyright holders nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  22. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  23. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  24. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  25. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  26. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  28. * THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. package com.alibaba.fastjson.asm;
  31. /**
  32. * A {@link MethodVisitor} that generates methods in bytecode form. Each visit method of this class appends the bytecode
  33. * corresponding to the visited instruction to a byte vector, in the order these methods are called.
  34. *
  35. * @author Eric Bruneton
  36. * @author Eugene Kuleshov
  37. */
  38. class MethodWriter implements MethodVisitor {
  39. /**
  40. * Pseudo access flag used to denote constructors.
  41. */
  42. static final int ACC_CONSTRUCTOR = 262144;
  43. /**
  44. * Frame has exactly the same locals as the previous stack map frame and number of stack items is zero.
  45. */
  46. static final int SAME_FRAME = 0; // to 63 (0-3f)
  47. /**
  48. * Frame has exactly the same locals as the previous stack map frame and number of stack items is 1
  49. */
  50. static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
  51. /**
  52. * Reserved for future use
  53. */
  54. static final int RESERVED = 128;
  55. /**
  56. * Frame has exactly the same locals as the previous stack map frame and number of stack items is 1. Offset is
  57. * bigger then 63;
  58. */
  59. static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
  60. /**
  61. * Frame where current locals are the same as the locals in the previous frame, except that the k last locals are
  62. * absent. The value of k is given by the formula 251-frame_type.
  63. */
  64. static final int CHOP_FRAME = 248; // to 250 (f8-fA)
  65. /**
  66. * Frame has exactly the same locals as the previous stack map frame and number of stack items is zero. Offset is
  67. * bigger then 63;
  68. */
  69. static final int SAME_FRAME_EXTENDED = 251; // fb
  70. /**
  71. * Frame where current locals are the same as the locals in the previous frame, except that k additional locals are
  72. * defined. The value of k is given by the formula frame_type-251.
  73. */
  74. static final int APPEND_FRAME = 252; // to 254 // fc-fe
  75. /**
  76. * Full frame
  77. */
  78. static final int FULL_FRAME = 255; // ff
  79. /**
  80. * Next method writer (see {@link ClassWriter#firstMethod firstMethod}).
  81. */
  82. MethodWriter next;
  83. /**
  84. * The class writer to which this method must be added.
  85. */
  86. final ClassWriter cw;
  87. /**
  88. * Access flags of this method.
  89. */
  90. private int access;
  91. /**
  92. * The index of the constant pool item that contains the name of this method.
  93. */
  94. private final int name;
  95. /**
  96. * The index of the constant pool item that contains the descriptor of this method.
  97. */
  98. private final int desc;
  99. /**
  100. * If not zero, indicates that the code of this method must be copied from the ClassReader associated to this writer
  101. * in <code>cw.cr</code>. More precisely, this field gives the number of bytes to copied from <code>cw.cr.b</code>.
  102. */
  103. int classReaderLength;
  104. /**
  105. * Number of exceptions that can be thrown by this method.
  106. */
  107. int exceptionCount;
  108. /**
  109. * The exceptions that can be thrown by this method. More precisely, this array contains the indexes of the constant
  110. * pool items that contain the internal names of these exception classes.
  111. */
  112. int[] exceptions;
  113. /**
  114. * The bytecode of this method.
  115. */
  116. private ByteVector code = new ByteVector();
  117. /**
  118. * Maximum stack size of this method.
  119. */
  120. private int maxStack;
  121. /**
  122. * Maximum number of local variables for this method.
  123. */
  124. private int maxLocals;
  125. /**
  126. * Indicates if some jump instructions are too small and need to be resized.
  127. */
  128. private boolean resize;
  129. // ------------------------------------------------------------------------
  130. /*
  131. * Fields for the control flow graph analysis algorithm (used to compute the maximum stack size). A control flow
  132. * graph contains one node per "basic block", and one edge per "jump" from one basic block to another. Each node
  133. * (i.e., each basic block) is represented by the Label object that corresponds to the first instruction of this
  134. * basic block. Each node also stores the list of its successors in the graph, as a linked list of Edge objects.
  135. */
  136. // ------------------------------------------------------------------------
  137. // Constructor
  138. // ------------------------------------------------------------------------
  139. /**
  140. * Constructs a new {@link MethodWriter}.
  141. *
  142. * @param cw the class writer in which the method must be added.
  143. * @param access the method's access flags (see {@link Opcodes}).
  144. * @param name the method's name.
  145. * @param desc the method's descriptor (see {@link Type}).
  146. * @param signature the method's signature. May be <tt>null</tt>.
  147. * @param exceptions the internal names of the method's exceptions. May be <tt>null</tt>.
  148. * @param computeMaxs <tt>true</tt> if the maximum stack size and number of local variables must be automatically
  149. * computed.
  150. * @param computeFrames <tt>true</tt> if the stack map tables must be recomputed from scratch.
  151. */
  152. MethodWriter(final ClassWriter cw, final int access, final String name, final String desc, final String signature, final String[] exceptions){
  153. if (cw.firstMethod == null) {
  154. cw.firstMethod = this;
  155. } else {
  156. cw.lastMethod.next = this;
  157. }
  158. cw.lastMethod = this;
  159. this.cw = cw;
  160. this.access = access;
  161. this.name = cw.newUTF8(name);
  162. this.desc = cw.newUTF8(desc);
  163. if (exceptions != null && exceptions.length > 0) {
  164. exceptionCount = exceptions.length;
  165. this.exceptions = new int[exceptionCount];
  166. for (int i = 0; i < exceptionCount; ++i) {
  167. this.exceptions[i] = cw.newClass(exceptions[i]);
  168. }
  169. }
  170. }
  171. // ------------------------------------------------------------------------
  172. // Implementation of the MethodVisitor interface
  173. // ------------------------------------------------------------------------
  174. public void visitInsn(final int opcode) {
  175. // adds the instruction to the bytecode of the method
  176. code.putByte(opcode);
  177. // update currentBlock
  178. // Label currentBlock = this.currentBlock;
  179. }
  180. public void visitIntInsn(final int opcode, final int operand) {
  181. // Label currentBlock = this.currentBlock;
  182. // adds the instruction to the bytecode of the method
  183. // if (opcode == Opcodes.SIPUSH) {
  184. // code.put12(opcode, operand);
  185. // } else { // BIPUSH or NEWARRAY
  186. code.put11(opcode, operand);
  187. // }
  188. }
  189. public void visitVarInsn(final int opcode, final int var) {
  190. // Label currentBlock = this.currentBlock;
  191. // adds the instruction to the bytecode of the method
  192. if (var < 4 && opcode != Opcodes.RET) {
  193. int opt;
  194. if (opcode < Opcodes.ISTORE) {
  195. /* ILOAD_0 */
  196. opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
  197. } else {
  198. /* ISTORE_0 */
  199. opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
  200. }
  201. code.putByte(opt);
  202. } else if (var >= 256) {
  203. code.putByte(196 /* WIDE */).put12(opcode, var);
  204. } else {
  205. code.put11(opcode, var);
  206. }
  207. }
  208. public void visitTypeInsn(final int opcode, final String type) {
  209. Item i = cw.newClassItem(type);
  210. // Label currentBlock = this.currentBlock;
  211. // adds the instruction to the bytecode of the method
  212. code.put12(opcode, i.index);
  213. }
  214. public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
  215. Item i = cw.newFieldItem(owner, name, desc);
  216. // Label currentBlock = this.currentBlock;
  217. // adds the instruction to the bytecode of the method
  218. code.put12(opcode, i.index);
  219. }
  220. public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
  221. boolean itf = opcode == Opcodes.INVOKEINTERFACE;
  222. Item i = cw.newMethodItem(owner, name, desc, itf);
  223. int argSize = i.intVal;
  224. // Label currentBlock = this.currentBlock;
  225. // adds the instruction to the bytecode of the method
  226. if (itf) {
  227. if (argSize == 0) {
  228. argSize = Type.getArgumentsAndReturnSizes(desc);
  229. i.intVal = argSize;
  230. }
  231. code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
  232. } else {
  233. code.put12(opcode, i.index);
  234. }
  235. }
  236. public void visitJumpInsn(final int opcode, final Label label) {
  237. // Label currentBlock = this.currentBlock;
  238. // adds the instruction to the bytecode of the method
  239. if ((label.status & Label.RESOLVED) != 0 && label.position - code.length < Short.MIN_VALUE) {
  240. throw new UnsupportedOperationException();
  241. } else {
  242. /*
  243. * case of a backward jump with an offset >= -32768, or of a forward jump with, of course, an unknown
  244. * offset. In these cases we store the offset in 2 bytes (which will be increased in resizeInstructions, if
  245. * needed).
  246. */
  247. code.putByte(opcode);
  248. label.put(this, code, code.length - 1);
  249. }
  250. }
  251. public void visitLabel(final Label label) {
  252. // resolves previous forward references to label, if any
  253. resize |= label.resolve(this, code.length, code.data);
  254. }
  255. public void visitLdcInsn(final Object cst) {
  256. Item i = cw.newConstItem(cst);
  257. // Label currentBlock = this.currentBlock;
  258. // adds the instruction to the bytecode of the method
  259. int index = i.index;
  260. if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
  261. code.put12(20 /* LDC2_W */, index);
  262. } else if (index >= 256) {
  263. code.put12(19 /* LDC_W */, index);
  264. } else {
  265. code.put11(Opcodes.LDC, index);
  266. }
  267. }
  268. public void visitIincInsn(final int var, final int increment) {
  269. // adds the instruction to the bytecode of the method
  270. if ((var > 255) || (increment > 127) || (increment < -128)) {
  271. code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var).putShort(increment);
  272. } else {
  273. code.putByte(Opcodes.IINC).put11(var, increment);
  274. }
  275. }
  276. public void visitMaxs(final int maxStack, final int maxLocals) {
  277. this.maxStack = maxStack;
  278. this.maxLocals = maxLocals;
  279. }
  280. public void visitEnd() {
  281. }
  282. // ------------------------------------------------------------------------
  283. // Utility methods: control flow analysis algorithm
  284. // ------------------------------------------------------------------------
  285. // ------------------------------------------------------------------------
  286. // Utility methods: stack map frames
  287. // ------------------------------------------------------------------------
  288. // ------------------------------------------------------------------------
  289. // Utility methods: dump bytecode array
  290. // ------------------------------------------------------------------------
  291. /**
  292. * Returns the size of the bytecode of this method.
  293. *
  294. * @return the size of the bytecode of this method.
  295. */
  296. final int getSize() {
  297. if (resize) {
  298. // replaces the temporary jump opcodes introduced by Label.resolve.
  299. throw new UnsupportedOperationException();
  300. }
  301. int size = 8;
  302. if (code.length > 0) {
  303. cw.newUTF8("Code");
  304. size += 18 + code.length + 8 * 0;
  305. }
  306. if (exceptionCount > 0) {
  307. cw.newUTF8("Exceptions");
  308. size += 8 + 2 * exceptionCount;
  309. }
  310. return size;
  311. }
  312. /**
  313. * Puts the bytecode of this method in the given byte vector.
  314. *
  315. * @param out the byte vector into which the bytecode of this method must be copied.
  316. */
  317. final void put(final ByteVector out) {
  318. int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC));
  319. out.putShort(access & ~mask).putShort(name).putShort(desc);
  320. int attributeCount = 0;
  321. if (code.length > 0) {
  322. ++attributeCount;
  323. }
  324. if (exceptionCount > 0) {
  325. ++attributeCount;
  326. }
  327. out.putShort(attributeCount);
  328. if (code.length > 0) {
  329. int size = 12 + code.length + 8 * 0; // handlerCount
  330. out.putShort(cw.newUTF8("Code")).putInt(size);
  331. out.putShort(maxStack).putShort(maxLocals);
  332. out.putInt(code.length).putByteArray(code.data, 0, code.length);
  333. out.putShort(0); // handlerCount
  334. attributeCount = 0;
  335. out.putShort(attributeCount);
  336. }
  337. if (exceptionCount > 0) {
  338. out.putShort(cw.newUTF8("Exceptions")).putInt(2 * exceptionCount + 2);
  339. out.putShort(exceptionCount);
  340. for (int i = 0; i < exceptionCount; ++i) {
  341. out.putShort(exceptions[i]);
  342. }
  343. }
  344. }
  345. }