PageRenderTime 48ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/objectweb/asm/Label.java

#
Java | 279 lines | 103 code | 34 blank | 142 comment | 28 complexity | 9dbe18e31b379f4123a55ac4454cf23c MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /***
  2. * ASM: a very small and fast Java bytecode manipulation framework
  3. * Copyright (C) 2000 INRIA, France Telecom
  4. * Copyright (C) 2002 France Telecom
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. * Contact: Eric.Bruneton@rd.francetelecom.com
  21. *
  22. * Author: Eric Bruneton
  23. */
  24. package org.objectweb.asm;
  25. /**
  26. * A label represents a position in the bytecode of a method. Labels are used
  27. * for jump, goto, and switch instructions, and for try catch blocks.
  28. */
  29. public class Label {
  30. /**
  31. * The code writer to which this label belongs, or <tt>null</tt> if unknown.
  32. */
  33. CodeWriter owner;
  34. /**
  35. * Indicates if the position of this label is known.
  36. */
  37. boolean resolved;
  38. /**
  39. * The position of this label in the code, if known.
  40. */
  41. int position;
  42. /**
  43. * Number of forward references to this label, times two.
  44. */
  45. private int referenceCount;
  46. /**
  47. * Informations about forward references. Each forward reference is described
  48. * by two consecutive integers in this array: the first one is the position
  49. * of the first byte of the bytecode instruction that contains the forward
  50. * reference, while the second is the position of the first byte of the
  51. * forward reference itself. In fact the sign of the first integer indicates
  52. * if this reference uses 2 or 4 bytes, and its absolute value gives the
  53. * position of the bytecode instruction.
  54. */
  55. private int[] srcAndRefPositions;
  56. // --------------------------------------------------------------------------
  57. // Fields for the control flow graph analysis algorithm (used to compute the
  58. // maximum stack size). A control flow graph contains one node per "basic
  59. // block", and one edge per "jump" from one basic block to another. Each node
  60. // (i.e., each basic block) is represented by the Label object that
  61. // corresponds to the first instruction of this basic block. Each node also
  62. // stores the list of it successors in the graph, as a linked list of Edge
  63. // objects.
  64. // --------------------------------------------------------------------------
  65. /**
  66. * The stack size at the beginning of this basic block.
  67. * This size is initially unknown. It is computed by the control flow
  68. * analysis algorithm (see {@link CodeWriter#visitMaxs visitMaxs}).
  69. */
  70. int beginStackSize;
  71. /**
  72. * The (relative) maximum stack size corresponding to this basic block. This
  73. * size is relative to the stack size at the beginning of the basic block,
  74. * i.e., the true maximum stack size is equal to {@link #beginStackSize
  75. * beginStackSize} + {@link #maxStackSize maxStackSize}.
  76. */
  77. int maxStackSize;
  78. /**
  79. * The successors of this node in the control flow graph. These successors
  80. * are stored in a linked list of {@link Edge Edge} objects, linked to each
  81. * other by their {@link Edge#next} field.
  82. */
  83. Edge successors;
  84. /**
  85. * The next basic block in the basic block stack.
  86. * See {@link CodeWriter#visitMaxs visitMaxs}.
  87. */
  88. Label next;
  89. /**
  90. * <tt>true</tt> if this basic block has been pushed in the basic block stack.
  91. * See {@link CodeWriter#visitMaxs visitMaxs}.
  92. */
  93. boolean pushed;
  94. // --------------------------------------------------------------------------
  95. // Constructor
  96. // --------------------------------------------------------------------------
  97. /**
  98. * Constructs a new label.
  99. */
  100. public Label () {
  101. }
  102. // --------------------------------------------------------------------------
  103. // Methods to compute offsets and to manage forward references
  104. // --------------------------------------------------------------------------
  105. /**
  106. * Puts a reference to this label in the bytecode of a method. If the position
  107. * of the label is known, the offset is computed and written directly.
  108. * Otherwise, a null offset is written and a new forward reference is declared
  109. * for this label.
  110. *
  111. * @param owner the code writer that calls this method.
  112. * @param out the bytecode of the method.
  113. * @param source the position of first byte of the bytecode instruction that
  114. * contains this label.
  115. * @param wideOffset <tt>true</tt> if the reference must be stored in 4 bytes,
  116. * or <tt>false</tt> if it must be stored with 2 bytes.
  117. * @throws IllegalArgumentException if this label has not been created by the
  118. * given code writer.
  119. */
  120. void put (
  121. final CodeWriter owner,
  122. final ByteVector out,
  123. final int source,
  124. final boolean wideOffset)
  125. {
  126. if (CodeWriter.CHECK) {
  127. if (this.owner == null) {
  128. this.owner = owner;
  129. } else if (this.owner != owner) {
  130. throw new IllegalArgumentException();
  131. }
  132. }
  133. if (resolved) {
  134. if (wideOffset) {
  135. out.put4(position - source);
  136. } else {
  137. out.put2(position - source);
  138. }
  139. } else {
  140. if (wideOffset) {
  141. addReference(-1 - source, out.length);
  142. out.put4(-1);
  143. } else {
  144. addReference(source, out.length);
  145. out.put2(-1);
  146. }
  147. }
  148. }
  149. /**
  150. * Adds a forward reference to this label. This method must be called only for
  151. * a true forward reference, i.e. only if this label is not resolved yet. For
  152. * backward references, the offset of the reference can be, and must be,
  153. * computed and stored directly.
  154. *
  155. * @param sourcePosition the position of the referencing instruction. This
  156. * position will be used to compute the offset of this forward reference.
  157. * @param referencePosition the position where the offset for this forward
  158. * reference must be stored.
  159. */
  160. private void addReference (
  161. final int sourcePosition,
  162. final int referencePosition)
  163. {
  164. if (srcAndRefPositions == null) {
  165. srcAndRefPositions = new int[6];
  166. }
  167. if (referenceCount >= srcAndRefPositions.length) {
  168. int[] a = new int[srcAndRefPositions.length + 6];
  169. System.arraycopy(srcAndRefPositions, 0, a, 0, srcAndRefPositions.length);
  170. srcAndRefPositions = a;
  171. }
  172. srcAndRefPositions[referenceCount++] = sourcePosition;
  173. srcAndRefPositions[referenceCount++] = referencePosition;
  174. }
  175. /**
  176. * Resolves all forward references to this label. This method must be called
  177. * when this label is added to the bytecode of the method, i.e. when its
  178. * position becomes known. This method fills in the blanks that where left in
  179. * the bytecode by each forward reference previously added to this label.
  180. *
  181. * @param owner the code writer that calls this method.
  182. * @param position the position of this label in the bytecode.
  183. * @param data the bytecode of the method.
  184. * @return <tt>true</tt> if a blank that was left for this label was to small
  185. * to store the offset. In such a case the corresponding jump instruction
  186. * is replaced with a pseudo instruction (using unused opcodes) using an
  187. * unsigned two bytes offset. These pseudo instructions will need to be
  188. * replaced with true instructions with wider offsets (4 bytes instead of
  189. * 2). This is done in {@link CodeWriter#resizeInstructions}.
  190. * @throws IllegalArgumentException if this label has already been resolved,
  191. * or if it has not been created by the given code writer.
  192. */
  193. boolean resolve (
  194. final CodeWriter owner,
  195. final int position,
  196. final byte[] data)
  197. {
  198. if (CodeWriter.CHECK) {
  199. if (this.owner == null) {
  200. this.owner = owner;
  201. }
  202. if (resolved || this.owner != owner) {
  203. throw new IllegalArgumentException();
  204. }
  205. }
  206. boolean needUpdate = false;
  207. this.resolved = true;
  208. this.position = position;
  209. int i = 0;
  210. while (i < referenceCount) {
  211. int source = srcAndRefPositions[i++];
  212. int reference = srcAndRefPositions[i++];
  213. int offset;
  214. if (source >= 0) {
  215. offset = position - source;
  216. if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
  217. // changes the opcode of the jump instruction, in order to be able to
  218. // find it later (see resizeInstructions in CodeWriter). These
  219. // temporary opcodes are similar to jump instruction opcodes, except
  220. // that the 2 bytes offset is unsigned (and can therefore represent
  221. // values from 0 to 65535, which is sufficient since the size of a
  222. // method is limited to 65535 bytes).
  223. int opcode = data[reference - 1] & 0xFF;
  224. if (opcode <= Constants.JSR) {
  225. // changes IFEQ ... JSR to opcodes 202 to 217 (inclusive)
  226. data[reference - 1] = (byte)(opcode + 49);
  227. } else {
  228. // changes IFNULL and IFNONNULL to opcodes 218 and 219 (inclusive)
  229. data[reference - 1] = (byte)(opcode + 20);
  230. }
  231. needUpdate = true;
  232. }
  233. data[reference++] = (byte)(offset >>> 8);
  234. data[reference] = (byte)offset;
  235. } else {
  236. offset = position + source + 1;
  237. data[reference++] = (byte)(offset >>> 24);
  238. data[reference++] = (byte)(offset >>> 16);
  239. data[reference++] = (byte)(offset >>> 8);
  240. data[reference] = (byte)offset;
  241. }
  242. }
  243. return needUpdate;
  244. }
  245. }