KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > flow > NullInfoRegistry


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.flow;
12
13 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
14
15 /**
16  * A degenerate form of UnconditionalFlowInfo explicitly meant to capture
17  * the effects of null related operations within try blocks. Given the fact
18  * that a try block might exit at any time, a null related operation that
19  * occurs within such a block mitigates whatever we know about the previous
20  * null status of involved variables. NullInfoRegistry handles that
21  * by negating upstream definite information that clashes with what a given
22  * statement contends about the same variable. It also implements
23  * {@link #mitigateNullInfoOf(FlowInfo) mitigateNullInfo} so as to elaborate the
24  * flow info presented in input of finally blocks.
25  */

26 public class NullInfoRegistry extends UnconditionalFlowInfo {
27     // significant states at this level:
28
// def. non null, def. null, def. unknown, prot. non null
29

30 // PREMATURE implement coverage and low level tests
31

32 /**
33  * Make a new null info registry, using an upstream flow info. All definite
34  * assignments of the upstream are carried forward, since a try block may
35  * exit before its first statement.
36  * @param upstream - UnconditionalFlowInfo: the flow info before we enter the
37  * try block; only definite assignments are considered; this parameter is
38  * not modified by this constructor
39  */

40 public NullInfoRegistry(UnconditionalFlowInfo upstream) {
41     this.maxFieldCount = upstream.maxFieldCount;
42     if ((upstream.tagBits & NULL_FLAG_MASK) != 0) {
43         long u1, u2, u3, u4, nu2, nu3, nu4;
44         this.nullBit2 = (u1 = upstream.nullBit1)
45             & (u2 = upstream.nullBit2)
46             & (nu3 = ~(u3 = upstream.nullBit3))
47             & (nu4 = ~(u4 = upstream.nullBit4));
48         this.nullBit3 = u1 & (nu2 = ~u2) & u3 & nu4;
49         this.nullBit4 = u1 & nu2 &nu3 & u4;
50         if ((this.nullBit2 | this.nullBit3 | this.nullBit4) != 0) {
51             this.tagBits |= NULL_FLAG_MASK;
52         }
53         if (upstream.extra != null) {
54             this.extra = new long[extraLength][];
55             int length = upstream.extra[2].length;
56             for (int i = 2; i < extraLength; i++) {
57                 this.extra[i] = new long[length];
58             }
59             for (int i = 0; i < length; i++) {
60                 this.extra[2 + 1][i] = (u1 = upstream.extra[1 + 1][i])
61                     & (u2 = upstream.extra[2 + 1][i])
62                     & (nu3 = ~(u3 = upstream.extra[3 + 1][i]))
63                     & (nu4 = ~(u4 = upstream.extra[4 + 1][i]));
64                 this.extra[3 + 1][i] = u1 & (nu2 = ~u2) & u3 & nu4;
65                 this.extra[4 + 1][i] = u1 & nu2 &nu3 & u4;
66                 if ((this.extra[2 + 1][i] | this.extra[3 + 1][i] | this.extra[4 + 1][i]) != 0) {
67                     this.tagBits |= NULL_FLAG_MASK;
68                 }
69             }
70         }
71     }
72 }
73
74 /**
75  * Add the information held by another NullInfoRegistry instance to this,
76  * then return this.
77  * @param other - NullInfoRegistry: the information to add to this
78  * @return this, modified to carry the information held by other
79  */

80 public NullInfoRegistry add(NullInfoRegistry other) {
81     if ((other.tagBits & NULL_FLAG_MASK) == 0) {
82         return this;
83     }
84     this.tagBits |= NULL_FLAG_MASK;
85     this.nullBit1 |= other.nullBit1;
86     this.nullBit2 |= other.nullBit2;
87     this.nullBit3 |= other.nullBit3;
88     this.nullBit4 |= other.nullBit4;
89     if (other.extra != null) {
90         if (this.extra == null) {
91             this.extra = new long[extraLength][];
92             for (int i = 2, length = other.extra[2].length; i < extraLength; i++) {
93                 System.arraycopy(other.extra[i], 0,
94                     (this.extra[i] = new long[length]), 0, length);
95             }
96         } else {
97             int length = this.extra[2].length, otherLength = other.extra[2].length;
98             if (otherLength > length) {
99                 for (int i = 2; i < extraLength; i++) {
100                     System.arraycopy(this.extra[i], 0,
101                         (this.extra[i] = new long[otherLength]), 0, length);
102                     System.arraycopy(other.extra[i], length,
103                         this.extra[i], length, otherLength - length);
104                 }
105             } else if (otherLength < length) {
106                 length = otherLength;
107             }
108             for (int i = 2; i < extraLength; i++) {
109                 for (int j = 0; j < length; j++) {
110                     this.extra[i][j] |= other.extra[i][j];
111                 }
112             }
113         }
114     }
115     return this;
116 }
117
118 public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
119     // protected from non-object locals in calling methods
120
if (this != DEAD_END) {
121         this.tagBits |= NULL_FLAG_MASK;
122         int position;
123         // position is zero-based
124
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
125
// set protected non null
126
this.nullBit1 |= (1L << position);
127             if (coverageTestFlag && coverageTestId == 290) {
128                 this.nullBit1 = 0;
129             }
130         }
131         else {
132             // use extra vector
133
int vectorIndex = (position / BitCacheSize) - 1;
134             if (this.extra == null) {
135                 int length = vectorIndex + 1;
136                 this.extra = new long[extraLength][];
137                 for (int j = 2; j < extraLength; j++) {
138                     this.extra[j] = new long[length];
139                 }
140             }
141             else {
142                 int oldLength; // might need to grow the arrays
143
if (vectorIndex >= (oldLength = this.extra[2].length)) {
144                     for (int j = 2; j < extraLength; j++) {
145                         System.arraycopy(this.extra[j], 0,
146                             (this.extra[j] = new long[vectorIndex + 1]), 0,
147                             oldLength);
148                     }
149                 }
150             }
151             this.extra[2][vectorIndex] |= (1L << (position % BitCacheSize));
152             if (coverageTestFlag && coverageTestId == 300) {
153                 this.extra[5][vectorIndex] = ~0;
154             }
155         }
156     }
157 }
158
159 public void markAsDefinitelyNonNull(LocalVariableBinding local) {
160     // protected from non-object locals in calling methods
161
if (this != DEAD_END) {
162         this.tagBits |= NULL_FLAG_MASK;
163         int position;
164         // position is zero-based
165
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
166
// set assigned non null
167
this.nullBit3 |= (1L << position);
168             if (coverageTestFlag && coverageTestId == 290) {
169                 this.nullBit1 = 0;
170             }
171         }
172         else {
173             // use extra vector
174
int vectorIndex = (position / BitCacheSize) - 1;
175             if (this.extra == null) {
176                 int length = vectorIndex + 1;
177                 this.extra = new long[extraLength][];
178                 for (int j = 2; j < extraLength; j++) {
179                     this.extra[j] = new long[length];
180                 }
181             }
182             else {
183                 int oldLength; // might need to grow the arrays
184
if (vectorIndex >= (oldLength = this.extra[2].length)) {
185                     for (int j = 2; j < extraLength; j++) {
186                         System.arraycopy(this.extra[j], 0,
187                             (this.extra[j] = new long[vectorIndex + 1]), 0,
188                             oldLength);
189                     }
190                 }
191             }
192             this.extra[4][vectorIndex] |= (1L << (position % BitCacheSize));
193             if (coverageTestFlag && coverageTestId == 300) {
194                 this.extra[5][vectorIndex] = ~0;
195             }
196         }
197     }
198 }
199 // PREMATURE consider ignoring extra 0 to 2 included - means a1 should not be used either
200
// PREMATURE project protected non null onto something else
201
public void markAsDefinitelyNull(LocalVariableBinding local) {
202     // protected from non-object locals in calling methods
203
if (this != DEAD_END) {
204         this.tagBits |= NULL_FLAG_MASK;
205         int position;
206         // position is zero-based
207
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
208
// set assigned null
209
this.nullBit2 |= (1L << position);
210             if (coverageTestFlag && coverageTestId == 290) {
211                 this.nullBit1 = 0;
212             }
213         }
214         else {
215             // use extra vector
216
int vectorIndex = (position / BitCacheSize) - 1;
217             if (this.extra == null) {
218                 int length = vectorIndex + 1;
219                 this.extra = new long[extraLength][];
220                 for (int j = 2; j < extraLength; j++) {
221                     this.extra[j] = new long[length];
222                 }
223             }
224             else {
225                 int oldLength; // might need to grow the arrays
226
if (vectorIndex >= (oldLength = this.extra[2].length)) {
227                     for (int j = 2; j < extraLength; j++) {
228                         System.arraycopy(this.extra[j], 0,
229                             (this.extra[j] = new long[vectorIndex + 1]), 0,
230                             oldLength);
231                     }
232                 }
233             }
234             this.extra[3][vectorIndex] |= (1L << (position % BitCacheSize));
235             if (coverageTestFlag && coverageTestId == 300) {
236                 this.extra[5][vectorIndex] = ~0;
237             }
238         }
239     }
240 }
241
242 public void markAsDefinitelyUnknown(LocalVariableBinding local) {
243     // protected from non-object locals in calling methods
244
if (this != DEAD_END) {
245         this.tagBits |= NULL_FLAG_MASK;
246         int position;
247         // position is zero-based
248
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
249
// set assigned unknown
250
this.nullBit4 |= (1L << position);
251             if (coverageTestFlag && coverageTestId == 290) {
252                 this.nullBit1 = 0;
253             }
254         }
255         else {
256             // use extra vector
257
int vectorIndex = (position / BitCacheSize) - 1;
258             if (this.extra == null) {
259                 int length = vectorIndex + 1;
260                 this.extra = new long[extraLength][];
261                 for (int j = 2; j < extraLength; j++) {
262                     this.extra[j] = new long[length];
263                 }
264             }
265             else {
266                 int oldLength; // might need to grow the arrays
267
if (vectorIndex >= (oldLength = this.extra[2].length)) {
268                     for (int j = 2; j < extraLength; j++) {
269                         System.arraycopy(this.extra[j], 0,
270                             (this.extra[j] = new long[vectorIndex + 1]), 0,
271                             oldLength);
272                     }
273                 }
274             }
275             this.extra[5][vectorIndex] |= (1L << (position % BitCacheSize));
276             if (coverageTestFlag && coverageTestId == 300) {
277                 this.extra[5][vectorIndex] = ~0;
278             }
279         }
280     }
281 }
282
283 /**
284  * Mitigate the definite and protected info of flowInfo, depending on what
285  * this null info registry knows about potential assignments and messages
286  * sends involving locals. May return flowInfo unchanged, or a modified,
287  * fresh copy of flowInfo.
288  * @param flowInfo - FlowInfo: the flow information that this null info
289  * registry may mitigate
290  * @return a copy of flowInfo carrying mitigated information, or else
291  * flowInfo unchanged
292  */

293 public UnconditionalFlowInfo mitigateNullInfoOf(FlowInfo flowInfo) {
294     if ((this.tagBits & NULL_FLAG_MASK) == 0) {
295         return flowInfo.unconditionalInits();
296     }
297     long m, m1, nm1, m2, nm2, m3, a2, a3, a4, s1, s2, ns2, s3, ns3, s4, ns4;
298     boolean newCopy = false;
299     UnconditionalFlowInfo source = flowInfo.unconditionalInits();
300     // clear incompatible protections
301
m1 = (s1 = source.nullBit1) & (s3 = source.nullBit3)
302                 & (s4 = source.nullBit4)
303             // prot. non null
304
& ((a2 = this.nullBit2) | (a4 = this.nullBit4));
305             // null or unknown
306
m2 = s1 & (s2 = this.nullBit2) & (s3 ^ s4)
307             // prot. null
308
& ((a3 = this.nullBit3) | a4);
309             // non null or unknown
310
// clear incompatible assignments
311
// PREMATURE check effect of protected non null (no NPE on call)
312
// TODO (maxime) code extensive implementation tests
313
m3 = s1 & (s2 & (ns3 = ~s3) & (ns4 = ~s4) & (a3 | a4)
314                 | (ns2 = ~s2) & s3 & ns4 & (a2 | a4)
315                 | ns2 & ns3 & s4 & (a2 | a3));
316     if ((m = (m1 | m2 | m3)) != 0) {
317         newCopy = true;
318         source = source.unconditionalCopy();
319         source.nullBit1 &= ~m;
320         source.nullBit2 &= (nm1 = ~m1) & ((nm2 = ~m2) | a4);
321         source.nullBit3 &= (nm1 | a2) & nm2;
322         source.nullBit4 &= nm1 & nm2;
323     }
324     if (this.extra != null && source.extra != null) {
325         int length = this.extra[2].length, sourceLength = source.extra[0].length;
326         if (sourceLength < length) {
327             length = sourceLength;
328         }
329         for (int i = 0; i < length; i++) {
330             m1 = (s1 = source.extra[1 + 1][i]) & (s3 = source.extra[3 + 1][i])
331                         & (s4 = source.extra[4 + 1][i])
332                 & ((a2 = this.extra[2 + 1][i]) | (a4 = this.extra[4 + 1][i]));
333             m2 = s1 & (s2 = this.extra[2 + 1][i]) & (s3 ^ s4)
334                 & ((a3 = this.extra[3 + 1][i]) | a4);
335             m3 = s1 & (s2 & (ns3 = ~s3) & (ns4 = ~s4) & (a3 | a4)
336                         | (ns2 = ~s2) & s3 & ns4 & (a2 | a4)
337                         | ns2 & ns3 & s4 & (a2 | a3));
338             if ((m = (m1 | m2 | m3)) != 0) {
339                 if (! newCopy) {
340                     newCopy = true;
341                     source = source.unconditionalCopy();
342                 }
343                 source.extra[1 + 1][i] &= ~m;
344                 source.extra[2 + 1][i] &= (nm1 = ~m1) & ((nm2 = ~m2) | a4);
345                 source.extra[3 + 1][i] &= (nm1 | a2) & nm2;
346                 source.extra[4 + 1][i] &= nm1 & nm2;
347             }
348         }
349     }
350     return source;
351 }
352
353 public String JavaDoc toString(){
354     if (this.extra == null) {
355         return "NullInfoRegistry<" + this.nullBit1 //$NON-NLS-1$
356
+ this.nullBit2 + this.nullBit3 + this.nullBit4
357             + ">"; //$NON-NLS-1$
358
}
359     else {
360         String JavaDoc nullS = "NullInfoRegistry<[" + this.nullBit1 //$NON-NLS-1$
361
+ this.nullBit2 + this.nullBit3 + this.nullBit4;
362             int i, ceil;
363             for (i = 0, ceil = this.extra[0].length > 3 ?
364                                 3 :
365                                 this.extra[0].length;
366                 i < ceil; i++) {
367                 nullS += "," + this.extra[2][i] //$NON-NLS-1$
368
+ this.extra[3][i] + this.extra[4][i] + this.extra[5][i];
369             }
370             if (ceil < this.extra[0].length) {
371                 nullS += ",..."; //$NON-NLS-1$
372
}
373             return nullS + "]>"; //$NON-NLS-1$
374
}
375 }
376 }
377
378
Popular Tags