• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2  *
3  * This program and the accompanying materials are made available under
4  * the terms of the Common Public License v1.0 which accompanies this distribution,
5  * and is available at http://www.eclipse.org/legal/cpl-v10.html
6  *
7  * $Id: MethodDescriptor.java,v 1.1.1.1.2.1 2004/07/10 03:34:52 vlad_r Exp $
8  */
9 package com.vladium.emma.data;
10 
11 import java.io.DataInput;
12 import java.io.DataOutput;
13 import java.io.IOException;
14 import java.io.Serializable;
15 
16 import com.vladium.util.IConstants;
17 import com.vladium.util.IntObjectMap;
18 import com.vladium.util.IntSet;
19 import com.vladium.util.asserts.$assert;
20 
21 // ----------------------------------------------------------------------------
22 /**
23  * @author Vlad Roubtsov, (C) 2003
24  */
25 public
26 final class MethodDescriptor implements IConstants, IMetadataConstants, Serializable
27 {
28     // public: ................................................................
29 
30     // need a separate 'blockCount' parm because 'blockMap' could be null
31     // and for a class that is never loaded I can't find out the number of
32     // blocks for block coverage reporting
33 
MethodDescriptor(final String name, final String descriptor, final int status, final int [] blockSizes, final int [][] blockMap, final int firstLine)34     public MethodDescriptor (final String name, final String descriptor, final int status,
35                              final int [] blockSizes, final int [][] blockMap, final int firstLine)
36     {
37         if (name == null)
38             throw new IllegalArgumentException ("null input: name");
39         if (descriptor == null)
40             throw new IllegalArgumentException ("null input: descriptor");
41 
42         if ((status & METHOD_NO_BLOCK_DATA) == 0)
43         {
44             // block metadata is available: blockCount must be positive
45 
46             final int blockCount = blockSizes.length;
47 
48             if ($assert.ENABLED) $assert.ASSERT (blockCount > 0, "blockCount must be positive: " + blockCount);
49             m_blockSizes = blockSizes;
50 
51             if ((status & METHOD_NO_LINE_DATA) == 0)
52             {
53                 // line metadata is available: blockMap must not be null or empty
54 
55                 if ($assert.ENABLED) $assert.ASSERT (firstLine > 0, "firstLine must be positive: " + firstLine);
56 
57                 if ((blockMap == null) || (blockMap.length == 0))
58                     throw new IllegalArgumentException ("null or empty input: blockMap");
59 
60                 if ($assert.ENABLED)
61                 {
62                     $assert.ASSERT (blockCount == blockMap.length, "blockCount " + blockCount + " != blockMap.length " + blockMap.length);
63 
64                     for (int i = 0; i < blockMap.length; ++ i)
65                     {
66                         $assert.ASSERT (blockMap [i] != null, "blockMap[" + i + "] is null");
67                         // note: it is legal for blockMap [i] to be empty
68                     }
69                 }
70 
71                 m_blockMap = blockMap;
72                 m_firstLine = firstLine;
73             }
74             else
75             {
76                 m_blockMap = null;
77                 m_firstLine = 0;
78             }
79         }
80         else
81         {
82             m_blockSizes = null;
83             m_blockMap = null;
84             m_firstLine = 0;
85         }
86 
87         m_name = name;
88         m_descriptor = descriptor;
89         m_status = status;
90     }
91 
92 
getName()93     public String getName ()
94     {
95         return m_name;
96     }
97 
getDescriptor()98     public String getDescriptor ()
99     {
100         return m_descriptor;
101     }
102 
getStatus()103     public int getStatus ()
104     {
105         return m_status;
106     }
107 
getBlockCount()108     public int getBlockCount ()
109     {
110         return m_blockSizes.length;
111     }
112 
getBlockSizes()113     public int [] getBlockSizes ()
114     {
115         return m_blockSizes;
116     }
117 
getBlockMap()118     public int [][] getBlockMap ()
119     {
120         return m_blockMap;
121     }
122 
getLineMap()123     public IntObjectMap /* line no->int[](blockIDs) */ getLineMap ()
124     {
125         IntObjectMap lineMap = m_lineMap;
126         if (lineMap != null)
127             return lineMap;
128         else if ((m_status & METHOD_NO_LINE_DATA) == 0)
129         {
130             // construct reverse line->block ID mapping:
131 
132             lineMap = new IntObjectMap ();
133             final int [][] blockMap = m_blockMap;
134 
135             for (int bl = 0, blCount = blockMap.length; bl < blCount; ++ bl)
136             {
137                 final int [] lines = blockMap [bl];
138                 if (lines != null)
139                 {
140                     final int lineCount = lines.length;
141 
142                     for (int l = 0; l < lineCount; ++ l)
143                     {
144                         final int line = lines [l];
145                         IntSet blockIDs = (IntSet) lineMap.get (line);
146 
147                         if (blockIDs == null)
148                         {
149                             blockIDs = new IntSet ();
150                             lineMap.put (line, blockIDs);
151                         }
152 
153                         blockIDs.add (bl);
154                     }
155                 }
156             }
157 
158             final int [] lines = lineMap.keys ();
159             for (int l = 0, lineCount = lines.length; l < lineCount; ++ l)
160             {
161                 final int line = lines [l];
162                 final int [] blockIDs = ((IntSet) lineMap.get (line)).values ();
163                 if ($assert.ENABLED) $assert.ASSERT (blockIDs != null && blockIDs.length > 0, "wrong line mapping for line #" + line);
164 
165                 lineMap.put (line, blockIDs); // overwrite IntSet as the value
166             }
167 
168             m_lineMap = lineMap;
169 
170             return lineMap;
171         }
172 
173         return null;
174     }
175 
getFirstLine()176     public int getFirstLine ()
177     {
178         return m_firstLine;
179     }
180 
hasLineNumberInfo()181     public boolean hasLineNumberInfo ()
182     {
183         return (m_status & METHOD_NO_LINE_DATA) == 0;
184     }
185 
186 
toString()187     public String toString ()
188     {
189         return toString ("");
190     }
191 
toString(final String indent)192     public String toString (final String indent)
193     {
194         StringBuffer s = new StringBuffer (indent + "method [" + m_name + "] descriptor:");
195 
196         if ((m_status & METHOD_NO_LINE_DATA) == 0)
197         {
198             for (int bl = 0; bl < m_blockMap.length; ++ bl)
199             {
200                 s.append (EOL);
201                 s.append (indent + INDENT_INCREMENT + "block " + bl + " (" + m_blockSizes [bl] + " instrs) : ");
202 
203                 final int [] lines = m_blockMap [bl];
204                 for (int l = 0; l < lines.length; ++ l)
205                 {
206                     if (l != 0) s.append (", ");
207                     s.append (lines [l]);
208                 }
209             }
210             s.append (EOL);
211             s.append (indent + INDENT_INCREMENT + "---");
212 
213             final int [] lines = m_lineMap.keys ();
214             for (int l = 0; l < lines.length; ++ l)
215             {
216                 s.append (EOL);
217                 s.append (indent + INDENT_INCREMENT + "line " + lines [l] + ": ");
218 
219                 final int [] blocks = (int []) m_lineMap.get (lines [l]);
220                 for (int bl = 0; bl < blocks.length; ++ bl)
221                 {
222                     if (bl != 0) s.append (", ");
223                     s.append (blocks [bl]);
224                 }
225             }
226         }
227         else
228         {
229             s.append (" <no line info>");
230         }
231 
232         return s.toString ();
233     }
234 
235     // protected: .............................................................
236 
237     // package: ...............................................................
238 
239 
readExternal(final DataInput in)240     static MethodDescriptor readExternal (final DataInput in)
241         throws IOException
242     {
243         final String name = in.readUTF ();
244         final String descriptor = in.readUTF ();
245 
246         final int status = in.readInt ();
247 
248         int [] blockSizes = null;
249         int [][] blockMap = null;
250         int firstLine = 0;
251 
252         if ((status & METHOD_NO_BLOCK_DATA) == 0)
253         {
254             // blockSizes must be set:
255 
256             blockSizes = DataFactory.readIntArray (in);
257 
258             if ((status & METHOD_NO_LINE_DATA) == 0)
259             {
260                 // blockMap, lineMap, firstLine must be set:
261 
262                 final int length = in.readInt ();
263                 blockMap = new int [length][];
264 
265                 for (int i = 0; i < length; ++ i)
266                 {
267                     blockMap [i] = DataFactory.readIntArray (in);
268                 }
269 
270                 firstLine = in.readInt ();
271 
272                 // [lineMap is transient data]
273             }
274         }
275 
276         return new MethodDescriptor (name, descriptor, status, blockSizes, blockMap, firstLine);
277     }
278 
writeExternal(final MethodDescriptor method, final DataOutput out)279     static void writeExternal (final MethodDescriptor method, final DataOutput out)
280         throws IOException
281     {
282         out.writeUTF (method.m_name);
283         out.writeUTF (method.m_descriptor);
284 
285         final int status = method.m_status;
286         out.writeInt (status);
287 
288         if ((status & METHOD_NO_BLOCK_DATA) == 0)
289         {
290             // blockSizes must be set:
291 
292             DataFactory.writeIntArray (method.m_blockSizes, out);
293 
294             if ((status & METHOD_NO_LINE_DATA) == 0)
295             {
296                 // blockMap, lineMap, firstLine must be set:
297 
298                 final int [][] blockMap = method.m_blockMap;
299                 final int length = blockMap.length;
300                 out.writeInt (length);
301 
302                 for (int i = 0; i < length; ++ i)
303                 {
304                     DataFactory.writeIntArray (blockMap [i], out);
305                 }
306 
307                 out.writeInt (method.m_firstLine);
308 
309                 // [lineMap is transient data]
310             }
311         }
312     }
313 
314     // private: ...............................................................
315 
316 
317     private final String m_name; // internal JVM name (<init>, <clinit> for initializers, etc) [never null]
318     private final String m_descriptor; // [never null]
319     private final int m_status; // excluded, no debug data, etc
320     private final int [] m_blockSizes; // always of positive length if ((status & METHOD_NO_BLOCK_DATA) == 0)
321     private final int [][] m_blockMap; // [never null or empty if status is ...]
322     private final int m_firstLine; // 0 if not src line info is available
323 
324     private IntObjectMap /* line no->int[](blockIDs) */  m_lineMap; // created lazily [could be empty if status ...]
325 
326 } // end of class
327 // ----------------------------------------------------------------------------
328