IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
LineNumberTableAttribute.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2014 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24using System;
25
26namespace IKVM.Attributes
27{
28
29 [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor)]
30 public sealed class LineNumberTableAttribute : Attribute
31 {
32
33 private byte[] table;
34
35 public LineNumberTableAttribute(ushort lineno)
36 {
38 w.AddMapping(0, lineno);
39 table = w.ToArray();
40 }
41
42 public LineNumberTableAttribute(byte[] table)
43 {
44 this.table = table;
45 }
46
47 public sealed class LineNumberWriter
48 {
49 private System.IO.MemoryStream stream;
50 private int prevILOffset;
51 private int prevLineNum;
52 private int count;
53
54 public LineNumberWriter(int estimatedCount)
55 {
56 stream = new System.IO.MemoryStream(estimatedCount * 2);
57 }
58
59 public void AddMapping(int ilOffset, int linenumber)
60 {
61 if(count == 0)
62 {
63 if(ilOffset == 0 && linenumber != 0)
64 {
65 prevLineNum = linenumber;
66 count++;
67 WritePackedInteger(linenumber - (64 + 50));
68 return;
69 }
70 else
71 {
72 prevLineNum = linenumber & ~3;
73 WritePackedInteger(((-prevLineNum / 4) - (64 + 50)));
74 }
75 }
76 bool pc_overflow;
77 bool lineno_overflow;
78 byte lead;
79 int deltaPC = ilOffset - prevILOffset;
80 if(deltaPC >= 0 && deltaPC < 31)
81 {
82 lead = (byte)deltaPC;
83 pc_overflow = false;
84 }
85 else
86 {
87 lead = (byte)31;
88 pc_overflow = true;
89 }
90 int deltaLineNo = linenumber - prevLineNum;
91 const int bias = 2;
92 if(deltaLineNo >= -bias && deltaLineNo < 7 - bias)
93 {
94 lead |= (byte)((deltaLineNo + bias) << 5);
95 lineno_overflow = false;
96 }
97 else
98 {
99 lead |= (byte)(7 << 5);
100 lineno_overflow = true;
101 }
102 stream.WriteByte(lead);
103 if(pc_overflow)
104 {
105 WritePackedInteger(deltaPC - (64 + 31));
106 }
107 if(lineno_overflow)
108 {
109 WritePackedInteger(deltaLineNo);
110 }
111 prevILOffset = ilOffset;
112 prevLineNum = linenumber;
113 count++;
114 }
115
116 public int Count
117 {
118 get
119 {
120 return count;
121 }
122 }
123
124 public int LineNo
125 {
126 get
127 {
128 return prevLineNum;
129 }
130 }
131
132 public byte[] ToArray()
133 {
134 return stream.ToArray();
135 }
136
137 /*
138 * packed integer format:
139 * ----------------------
140 *
141 * First byte:
142 * 00 - 7F Single byte integer (-64 - 63)
143 * 80 - BF Double byte integer (-8192 - 8191)
144 * C0 - DF Triple byte integer (-1048576 - 1048576)
145 * E0 - FE Reserved
146 * FF Five byte integer
147 */
148 private void WritePackedInteger(int val)
149 {
150 if(val >= -64 && val < 64)
151 {
152 val += 64;
153 stream.WriteByte((byte)val);
154 }
155 else if(val >= -8192 && val < 8192)
156 {
157 val += 8192;
158 stream.WriteByte((byte)(0x80 + (val >> 8)));
159 stream.WriteByte((byte)val);
160 }
161 else if(val >= -1048576 && val < 1048576)
162 {
163 val += 1048576;
164 stream.WriteByte((byte)(0xC0 + (val >> 16)));
165 stream.WriteByte((byte)(val >> 8));
166 stream.WriteByte((byte)val);
167 }
168 else
169 {
170 stream.WriteByte(0xFF);
171 stream.WriteByte((byte)(val >> 24));
172 stream.WriteByte((byte)(val >> 16));
173 stream.WriteByte((byte)(val >> 8));
174 stream.WriteByte((byte)(val >> 0));
175 }
176 }
177 }
178
179 private int ReadPackedInteger(ref int position)
180 {
181 byte b = table[position++];
182 if(b < 128)
183 {
184 return b - 64;
185 }
186 else if((b & 0xC0) == 0x80)
187 {
188 return ((b & 0x7F) << 8) + table[position++] - 8192;
189 }
190 else if((b & 0xE0) == 0xC0)
191 {
192 int val = ((b & 0x3F) << 16);
193 val += (table[position++] << 8);
194 val += table[position++];
195 return val - 1048576;
196 }
197 else if(b == 0xFF)
198 {
199 int val = table[position++] << 24;
200 val += table[position++] << 16;
201 val += table[position++] << 8;
202 val += table[position++] << 0;
203 return val;
204 }
205 else
206 {
207 throw new InvalidProgramException();
208 }
209 }
210
211 public int GetLineNumber(int ilOffset)
212 {
213 int i = 0;
214 int prevILOffset = 0;
215 int prevLineNum = ReadPackedInteger(ref i) + (64 + 50);
216 int line;
217 if(prevLineNum > 0)
218 {
219 line = prevLineNum;
220 }
221 else
222 {
223 prevLineNum = 4 * -prevLineNum;
224 line = -1;
225 }
226 while(i < table.Length)
227 {
228 byte lead = table[i++];
229 int deltaPC = lead & 31;
230 int deltaLineNo = (lead >> 5) - 2;
231 if(deltaPC == 31)
232 {
233 deltaPC = ReadPackedInteger(ref i) + (64 + 31);
234 }
235 if(deltaLineNo == 5)
236 {
237 deltaLineNo = ReadPackedInteger(ref i);
238 }
239 int currILOffset = prevILOffset + deltaPC;
240 if(currILOffset > ilOffset)
241 {
242 return line;
243 }
244 line = prevLineNum + deltaLineNo;
245 prevILOffset = currILOffset;
246 prevLineNum = line;
247 }
248 return line;
249 }
250
251 }
252
253}