KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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.ast.ASTNode;
14 import org.eclipse.jdt.internal.compiler.impl.Constant;
15 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
16 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
17 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
18 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
19
20 /**
21  * Record initialization status during definite assignment analysis
22  *
23  * No caching of pre-allocated instances.
24  */

25 public class UnconditionalFlowInfo extends FlowInfo {
26     // Coverage tests
27
/**
28      * Exception raised when unexpected behavior is detected during coverage
29      * tests.
30      */

31     public static class AssertionFailedException extends RuntimeException JavaDoc {
32         private static final long serialVersionUID = 1827352841030089703L;
33         
34     public AssertionFailedException(String JavaDoc message) {
35         super(message);
36     }
37     }
38     
39     // Coverage tests need that the code be instrumented. The following flag
40
// controls whether the instrumented code is compiled in or not, and whether
41
// the coverage tests methods run or not.
42
public final static boolean coverageTestFlag = false;
43     // never release with the coverageTestFlag set to true
44
public static int coverageTestId;
45
46     // assignment bits - first segment
47
public long definiteInits;
48     public long potentialInits;
49     
50     // null bits - first segment
51
public long
52         nullBit1,
53         nullBit2,
54         nullBit3,
55         nullBit4;
56 /*
57         nullBit1
58          nullBit2...
59         0000 start
60         0001 pot. unknown
61         0010 pot. non null
62         0011 pot. nn & pot. un
63         0100 pot. null
64         0101 pot. n & pot. un
65         0110 pot. n & pot. nn
66         1001 def. unknown
67         1010 def. non null
68         1011 pot. nn & prot. nn
69         1100 def. null
70         1101 pot. n & prot. n
71         1110 prot. null
72         1111 prot. non null
73  */

74         
75     // extra segments
76
public static final int extraLength = 6;
77     public long extra[][];
78         // extra bit fields for larger numbers of fields/variables
79
// extra[0] holds definiteInits values, extra[1] potentialInits, etc.
80
// lifecycle is extra == null or else all extra[]'s are allocated
81
// arrays which have the same size
82

83     public int maxFieldCount; // limit between fields and locals
84

85     // Constants
86
public static final int BitCacheSize = 64; // 64 bits in a long.
87

88 public FlowInfo addInitializationsFrom(FlowInfo inits) {
89     if (this == DEAD_END)
90         return this;
91     if (inits == DEAD_END)
92         return this;
93     UnconditionalFlowInfo otherInits = inits.unconditionalInits();
94
95     // union of definitely assigned variables,
96
this.definiteInits |= otherInits.definiteInits;
97     // union of potentially set ones
98
this.potentialInits |= otherInits.potentialInits;
99     // combine null information
100
boolean thisHadNulls = (this.tagBits & NULL_FLAG_MASK) != 0,
101         otherHasNulls = (otherInits.tagBits & NULL_FLAG_MASK) != 0;
102     long
103         a1, a2, a3, a4,
104         na1, na2, na3, na4,
105         b1, b2, b3, b4,
106         nb1, nb2, nb3, nb4;
107     if (otherHasNulls) {
108         if (!thisHadNulls) {
109             this.nullBit1 = otherInits.nullBit1;
110             this.nullBit2 = otherInits.nullBit2;
111             this.nullBit3 = otherInits.nullBit3;
112             this.nullBit4 = otherInits.nullBit4;
113             if (coverageTestFlag && coverageTestId == 1) {
114               this.nullBit4 = ~0;
115             }
116         }
117         else {
118             this.nullBit1 = (b1 = otherInits.nullBit1)
119                                 | (a1 = this.nullBit1) & ((a3 = this.nullBit3)
120                                     & (a4 = this.nullBit4) & (nb2 = ~(b2 = otherInits.nullBit2))
121                                     & (nb4 = ~(b4 = otherInits.nullBit4))
122                                 | ((na4 = ~a4) | (na3 = ~a3))
123                                     & ((na2 = ~(a2 = this.nullBit2)) & nb2
124                                         | a2 & (nb3 = ~(b3 = otherInits.nullBit3)) & nb4));
125             this.nullBit2 = b2 & (nb4 | nb3)
126                                 | na3 & na4 & b2
127                                 | a2 & (nb3 & nb4
128                                             | (nb1 = ~b1) & (na3 | (na1 = ~a1))
129                                             | a1 & b2);
130             this.nullBit3 = b3 & (nb1 & (b2 | a2 | na1)
131                                     | b1 & (b4 | nb2 | a1 & a3)
132                                     | na1 & na2 & na4)
133                                 | a3 & nb2 & nb4
134                                 | nb1 & ((na2 & a4 | na1) & a3
135                                             | a1 & na2 & na4 & b2);
136             this.nullBit4 = nb1 & (a4 & (na3 & nb3 | (a3 | na2) & nb2)
137                                 | a1 & (a3 & nb2 & b4
138                                         | a2 & b2 & (b4 | a3 & na4 & nb3)))
139                                 | b1 & (a3 & a4 & b4
140                                     | na2 & na4 & nb3 & b4
141                                     | a2 & ((b3 | a4) & b4
142                                                 | na3 & a4 & b2 & b3)
143                                     | na1 & (b4 | (a4 | a2) & b2 & b3))
144                                 | (na1 & (na3 & nb3 | na2 & nb2)
145                                     | a1 & (nb2 & nb3 | a2 & a3)) & b4;
146             if (coverageTestFlag && coverageTestId == 2) {
147               this.nullBit4 = ~0;
148             }
149         }
150         this.tagBits |= NULL_FLAG_MASK; // in all cases - avoid forgetting extras
151
}
152     // treating extra storage
153
if (this.extra != null || otherInits.extra != null) {
154         int mergeLimit = 0, copyLimit = 0;
155         if (this.extra != null) {
156             if (otherInits.extra != null) {
157                 // both sides have extra storage
158
int length, otherLength;
159                 if ((length = this.extra[0].length) <
160                         (otherLength = otherInits.extra[0].length)) {
161                     // current storage is shorter -> grow current
162
for (int j = 0; j < extraLength; j++) {
163                         System.arraycopy(this.extra[j], 0,
164                             (this.extra[j] = new long[otherLength]), 0, length);
165                     }
166                     mergeLimit = length;
167                     copyLimit = otherLength;
168                     if (coverageTestFlag && coverageTestId == 3) {
169                         throw new AssertionFailedException("COVERAGE 3"); //$NON-NLS-1$
170
}
171                 } else {
172                     // current storage is longer
173
mergeLimit = otherLength;
174                     if (coverageTestFlag && coverageTestId == 4) {
175                         throw new AssertionFailedException("COVERAGE 4"); //$NON-NLS-1$
176
}
177                 }
178             }
179         } else if (otherInits.extra != null) {
180             // no storage here, but other has extra storage.
181
// shortcut regular copy because array copy is better
182
int otherLength;
183             this.extra = new long[extraLength][];
184             System.arraycopy(otherInits.extra[0], 0,
185                 (this.extra[0] = new long[otherLength =
186                     otherInits.extra[0].length]), 0, otherLength);
187             System.arraycopy(otherInits.extra[1], 0,
188                 (this.extra[1] = new long[otherLength]), 0, otherLength);
189             if (otherHasNulls) {
190                 for (int j = 2; j < extraLength; j++) {
191                     System.arraycopy(otherInits.extra[j], 0,
192                         (this.extra[j] = new long[otherLength]), 0, otherLength);
193                 }
194                 if (coverageTestFlag && coverageTestId == 5) {
195                     this.extra[5][otherLength - 1] = ~0;
196                 }
197             }
198             else {
199                 for (int j = 2; j < extraLength; j++) {
200                     this.extra[j] = new long[otherLength];
201                 }
202                 if (coverageTestFlag && coverageTestId == 6) {
203                     throw new AssertionFailedException("COVERAGE 6"); //$NON-NLS-1$
204
}
205             }
206         }
207         int i;
208         // manage definite assignment info
209
for (i = 0; i < mergeLimit; i++) {
210             this.extra[0][i] |= otherInits.extra[0][i];
211             this.extra[1][i] |= otherInits.extra[1][i];
212         }
213         for (; i < copyLimit; i++) {
214             this.extra[0][i] = otherInits.extra[0][i];
215             this.extra[1][i] = otherInits.extra[1][i];
216         }
217         // tweak limits for nulls
218
if (!thisHadNulls) {
219             if (copyLimit < mergeLimit) {
220                 copyLimit = mergeLimit;
221             }
222             mergeLimit = 0;
223         }
224         if (!otherHasNulls) {
225             copyLimit = 0;
226             mergeLimit = 0;
227         }
228         for (i = 0; i < mergeLimit; i++) {
229             this.extra[1 + 1][i] = (b1 = otherInits.extra[1 + 1][i])
230                                 | (a1 = this.extra[1 + 1][i]) & ((a3 = this.extra[3 + 1][i])
231                                     & (a4 = this.extra[4 + 1][i]) & (nb2 = ~(b2 = otherInits.extra[2 + 1][i]))
232                                     & (nb4 = ~(b4 = otherInits.extra[4 + 1][i]))
233                                 | ((na4 = ~a4) | (na3 = ~a3))
234                                     & ((na2 = ~(a2 = this.extra[2 + 1][i])) & nb2
235                                         | a2 & (nb3 = ~(b3 = otherInits.extra[3 + 1][i])) & nb4));
236             this.extra[2 + 1][i] = b2 & (nb4 | nb3)
237                                 | na3 & na4 & b2
238                                 | a2 & (nb3 & nb4
239                                             | (nb1 = ~b1) & (na3 | (na1 = ~a1))
240                                             | a1 & b2);
241             this.extra[3 + 1][i] = b3 & (nb1 & (b2 | a2 | na1)
242                                     | b1 & (b4 | nb2 | a1 & a3)
243                                     | na1 & na2 & na4)
244                                 | a3 & nb2 & nb4
245                                 | nb1 & ((na2 & a4 | na1) & a3
246                                             | a1 & na2 & na4 & b2);
247             this.extra[4 + 1][i] = nb1 & (a4 & (na3 & nb3 | (a3 | na2) & nb2)
248                                 | a1 & (a3 & nb2 & b4
249                                         | a2 & b2 & (b4 | a3 & na4 & nb3)))
250                                 | b1 & (a3 & a4 & b4
251                                     | na2 & na4 & nb3 & b4
252                                     | a2 & ((b3 | a4) & b4
253                                                 | na3 & a4 & b2 & b3)
254                                     | na1 & (b4 | (a4 | a2) & b2 & b3))
255                                 | (na1 & (na3 & nb3 | na2 & nb2)
256                                     | a1 & (nb2 & nb3 | a2 & a3)) & b4;
257             if (coverageTestFlag && coverageTestId == 7) {
258               this.extra[5][i] = ~0;
259             }
260         }
261         for (; i < copyLimit; i++) {
262             for (int j = 2; j < extraLength; j++) {
263                 this.extra[j][i] = otherInits.extra[j][i];
264             }
265             if (coverageTestFlag && coverageTestId == 8) {
266               this.extra[5][i] = ~0;
267             }
268         }
269     }
270     return this;
271 }
272
273 public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) {
274     if (this == DEAD_END){
275         return this;
276     }
277     if (inits == DEAD_END){
278         return this;
279     }
280     UnconditionalFlowInfo otherInits = inits.unconditionalInits();
281     // union of potentially set ones
282
this.potentialInits |= otherInits.potentialInits;
283     // treating extra storage
284
if (this.extra != null) {
285         if (otherInits.extra != null) {
286             // both sides have extra storage
287
int i = 0, length, otherLength;
288             if ((length = this.extra[0].length) < (otherLength = otherInits.extra[0].length)) {
289                 // current storage is shorter -> grow current
290
for (int j = 0; j < extraLength; j++) {
291                     System.arraycopy(this.extra[j], 0,
292                         (this.extra[j] = new long[otherLength]), 0, length);
293                 }
294                 for (; i < length; i++) {
295                     this.extra[1][i] |= otherInits.extra[1][i];
296                 }
297                 for (; i < otherLength; i++) {
298                     this.extra[1][i] = otherInits.extra[1][i];
299                 }
300             }
301             else {
302                 // current storage is longer
303
for (; i < otherLength; i++) {
304                     this.extra[1][i] |= otherInits.extra[1][i];
305                 }
306             }
307         }
308     }
309     else if (otherInits.extra != null) {
310         // no storage here, but other has extra storage.
311
int otherLength = otherInits.extra[0].length;
312         this.extra = new long[extraLength][];
313         for (int j = 0; j < extraLength; j++) {
314             this.extra[j] = new long[otherLength];
315         }
316         System.arraycopy(otherInits.extra[1], 0, this.extra[1], 0,
317             otherLength);
318     }
319     this.addPotentialNullInfoFrom(otherInits);
320     return this;
321 }
322
323 /**
324  * Compose other inits over this flow info, then return this. The operation
325  * semantics are to wave into this flow info the consequences upon null
326  * information of a possible path into the operations that resulted into
327  * otherInits. The fact that this path may be left unexecuted under peculiar
328  * conditions results into less specific results than
329  * {@link #addInitializationsFrom(FlowInfo) addInitializationsFrom}; moreover,
330  * only the null information is affected.
331  * @param otherInits other null inits to compose over this
332  * @return this, modified according to otherInits information
333  */

334 public UnconditionalFlowInfo addPotentialNullInfoFrom(
335         UnconditionalFlowInfo otherInits) {
336     if ((this.tagBits & UNREACHABLE) != 0 ||
337             (otherInits.tagBits & UNREACHABLE) != 0 ||
338             (otherInits.tagBits & NULL_FLAG_MASK) == 0) {
339         return this;
340     }
341     // if we get here, otherInits has some null info
342
boolean thisHadNulls = (this.tagBits & NULL_FLAG_MASK) != 0,
343         thisHasNulls = false;
344     long a1, a2, a3, a4,
345         na1, na2, na3, na4,
346         b1, b2, b3, b4,
347         nb1, nb2, nb3, nb4;
348     if (thisHadNulls) {
349         this.nullBit1 = (a1 = this.nullBit1)
350                                 & ((a3 = this.nullBit3) & (a4 = this.nullBit4)
351                                     & ((nb2 = ~(b2 = otherInits.nullBit2))
352                                         & (nb4 = ~(b4 = otherInits.nullBit4))
353                                             | (b1 = otherInits.nullBit1) & (b3 = otherInits.nullBit3))
354                             | (na2 = ~(a2 = this.nullBit2))
355                                 & (b1 & b3 | ((na4 = ~a4) | (na3 = ~a3)) & nb2)
356                             | a2 & ((na4 | na3) & ((nb3 = ~b3) & nb4 | b1 & b2)));
357         this.nullBit2 = b2 & (nb3 | (nb1 = ~b1))
358                 | a2 & (nb3 & nb4 | b2 | na3 | (na1 = ~a1));
359         this.nullBit3 = b3 & (nb1 & b2
360                     | a2 & (nb2 | a3)
361                     | na1 & nb2
362                     | a1 & na2 & na4 & b1)
363                 | a3 & (nb2 & nb4 | na2 & a4 | na1)
364                 | a1 & na2 & na4 & b2;
365         this.nullBit4 = na3 & (nb1 & nb3 & b4
366                     | a4 & (nb3 | b1 & b2))
367                 | nb2 & (na3 & b1 & nb3 | na2 & (nb1 & b4 | b1 & nb3 | a4))
368                 | a3 & (a4 & (nb2 | b1 & b3)
369                         | a1 & a2 & (nb1 & b4 | na4 & (b2 | b1) & nb3));
370         if (coverageTestFlag && coverageTestId == 9) {
371           this.nullBit4 = ~0;
372         }
373         if ((this.nullBit2 | this.nullBit3 | this.nullBit4) != 0) { // bit1 is redundant
374
thisHasNulls = true;
375         }
376     } else {
377         this.nullBit1 = 0;
378         this.nullBit2 = (b2 = otherInits.nullBit2)
379                             & ((nb3 = ~(b3 = otherInits.nullBit3)) |
380                                 (nb1 = ~(b1 = otherInits.nullBit1)));
381         this.nullBit3 = b3 & (nb1 | (nb2 = ~b2));
382         this.nullBit4 = ~b1 & ~b3 & (b4 = otherInits.nullBit4) | ~b2 & (b1 & ~b3 | ~b1 & b4);
383         if (coverageTestFlag && coverageTestId == 10) {
384           this.nullBit4 = ~0;
385         }
386         if ((this.nullBit2 | this.nullBit3 | this.nullBit4) != 0) { // bit1 is redundant
387
thisHasNulls = true;
388         }
389     }
390     // extra storage management
391
if (otherInits.extra != null) {
392         int mergeLimit = 0, copyLimit = otherInits.extra[0].length;
393         if (this.extra == null) {
394             this.extra = new long[extraLength][];
395             for (int j = 0; j < extraLength; j++) {
396                 this.extra[j] = new long[copyLimit];
397             }
398             if (coverageTestFlag && coverageTestId == 11) {
399                 throw new AssertionFailedException("COVERAGE 11"); //$NON-NLS-1$
400
}
401         } else {
402             mergeLimit = copyLimit;
403             if (mergeLimit > this.extra[0].length) {
404                 mergeLimit = this.extra[0].length;
405                 for (int j = 0; j < extraLength; j++) {
406                     System.arraycopy(this.extra[j], 0,
407                             this.extra[j] = new long[copyLimit], 0,
408                             mergeLimit);
409                 }
410                 if (! thisHadNulls) {
411                     mergeLimit = 0;
412                     // will do with a copy -- caveat: only valid because definite assignment bits copied above
413
if (coverageTestFlag && coverageTestId == 12) {
414                         throw new AssertionFailedException("COVERAGE 12"); //$NON-NLS-1$
415
}
416                 }
417             }
418         }
419         // PREMATURE skip operations for fields
420
int i;
421         for (i = 0 ; i < mergeLimit ; i++) {
422             this.extra[1 + 1][i] = (a1 = this.extra[1 + 1][i])
423                                     & ((a3 = this.extra[3 + 1][i]) & (a4 = this.extra[4 + 1][i])
424                                         & ((nb2 = ~(b2 = otherInits.extra[2 + 1][i]))
425                                             & (nb4 = ~(b4 = otherInits.extra[4 + 1][i]))
426                                                 | (b1 = otherInits.extra[1 + 1][i]) & (b3 = otherInits.extra[3 + 1][i]))
427                                 | (na2 = ~(a2 = this.extra[2 + 1][i]))
428                                     & (b1 & b3 | ((na4 = ~a4) | (na3 = ~a3)) & nb2)
429                                 | a2 & ((na4 | na3) & ((nb3 = ~b3) & nb4 | b1 & b2)));
430             this.extra[2 + 1][i] = b2 & (nb3 | (nb1 = ~b1))
431                     | a2 & (nb3 & nb4 | b2 | na3 | (na1 = ~a1));
432             this.extra[3 + 1][i] = b3 & (nb1 & b2
433                         | a2 & (nb2 | a3)
434                         | na1 & nb2
435                         | a1 & na2 & na4 & b1)
436                     | a3 & (nb2 & nb4 | na2 & a4 | na1)
437                     | a1 & na2 & na4 & b2;
438             this.extra[4 + 1][i] = na3 & (nb1 & nb3 & b4
439                         | a4 & (nb3 | b1 & b2))
440                     | nb2 & (na3 & b1 & nb3 | na2 & (nb1 & b4 | b1 & nb3 | a4))
441                     | a3 & (a4 & (nb2 | b1 & b3)
442                             | a1 & a2 & (nb1 & b4 | na4 & (b2 | b1) & nb3));
443             if ((this.extra[2 + 1][i] | this.extra[3 + 1][i] | this.extra[4 + 1][i]) != 0) { // bit1 is redundant
444
thisHasNulls = true;
445             }
446             if (coverageTestFlag && coverageTestId == 13) {
447               this.nullBit4 = ~0;
448             }
449         }
450         for (; i < copyLimit; i++) {
451             this.extra[1 + 1][i] = 0;
452             this.extra[2 + 1][i] = (b2 = otherInits.extra[2 + 1][i])
453                                 & ((nb3 = ~(b3 = otherInits.extra[3 + 1][i])) |
454                                     (nb1 = ~(b1 = otherInits.extra[1 + 1][i])));
455             this.extra[3 + 1][i] = b3 & (nb1 | (nb2 = ~b2));
456             this.extra[4 + 1][i] = ~b1 & ~b3 & (b4 = otherInits.extra[4 + 1][i]) | ~b2 & (b1 & ~b3 | ~b1 & b4);
457             if ((this.extra[2 + 1][i] | this.extra[3 + 1][i] | this.extra[4 + 1][i]) != 0) { // bit1 is redundant
458
thisHasNulls = true;
459             }
460             if (coverageTestFlag && coverageTestId == 14) {
461               this.extra[5][i] = ~0;
462             }
463         }
464     }
465     if (thisHasNulls) {
466         this.tagBits |= NULL_FLAG_MASK;
467     }
468     else {
469         this.tagBits &= NULL_FLAG_MASK;
470     }
471     return this;
472 }
473
474 final public boolean cannotBeDefinitelyNullOrNonNull(LocalVariableBinding local) {
475     if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
476             (local.type.tagBits & TagBits.IsBaseType) != 0) {
477         return false;
478     }
479     int position;
480     if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
481         // use bits
482
return (
483             (~this.nullBit1
484                     & (this.nullBit2 & this.nullBit3 | this.nullBit4)
485                 | ~this.nullBit2 & ~this.nullBit3 & this.nullBit4)
486             & (1L << position)) != 0;
487     }
488     // use extra vector
489
if (this.extra == null) {
490         return false; // if vector not yet allocated, then not initialized
491
}
492     int vectorIndex;
493     if ((vectorIndex = (position / BitCacheSize) - 1) >=
494             this.extra[0].length) {
495         return false; // if not enough room in vector, then not initialized
496
}
497     long a2, a3, a4;
498     return (
499             (~this.extra[2][vectorIndex]
500                     & ((a2 = this.extra[3][vectorIndex]) & (a3 = this.extra[4][vectorIndex]) | (a4 = this.extra[5][vectorIndex]))
501                 | ~a2 & ~a3 & a4)
502             & (1L << (position % BitCacheSize))) != 0;
503 }
504
505 final public boolean cannotBeNull(LocalVariableBinding local) {
506     if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
507             (local.type.tagBits & TagBits.IsBaseType) != 0) {
508         return false;
509     }
510     int position;
511     if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
512         // use bits
513
return (this.nullBit1 & this.nullBit3
514             & ((this.nullBit2 & this.nullBit4) | ~this.nullBit2)
515             & (1L << position)) != 0;
516     }
517     // use extra vector
518
if (this.extra == null) {
519         return false; // if vector not yet allocated, then not initialized
520
}
521     int vectorIndex;
522     if ((vectorIndex = (position / BitCacheSize) - 1) >=
523             this.extra[0].length) {
524         return false; // if not enough room in vector, then not initialized
525
}
526     return (this.extra[2][vectorIndex] & this.extra[4][vectorIndex]
527             & ((this.extra[3][vectorIndex] & this.extra[5][vectorIndex]) |
528                     ~this.extra[3][vectorIndex])
529             & (1L << (position % BitCacheSize))) != 0;
530 }
531
532 final public boolean canOnlyBeNull(LocalVariableBinding local) {
533     if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
534             (local.type.tagBits & TagBits.IsBaseType) != 0) {
535         return false;
536     }
537     int position;
538     if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
539         // use bits
540
return (this.nullBit1 & this.nullBit2
541             & (~this.nullBit3 | ~this.nullBit4)
542             & (1L << position)) != 0;
543     }
544     // use extra vector
545
if (this.extra == null) {
546         return false; // if vector not yet allocated, then not initialized
547
}
548     int vectorIndex;
549     if ((vectorIndex = (position / BitCacheSize) - 1) >=
550             this.extra[0].length) {
551         return false; // if not enough room in vector, then not initialized
552
}
553     return (this.extra[2][vectorIndex] & this.extra[3][vectorIndex]
554             & (~this.extra[4][vectorIndex] | ~this.extra[5][vectorIndex])
555             & (1L << (position % BitCacheSize))) != 0;
556 }
557
558 public FlowInfo copy() {
559     // do not clone the DeadEnd
560
if (this == DEAD_END) {
561         return this;
562     }
563     UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
564     // copy slots
565
copy.definiteInits = this.definiteInits;
566     copy.potentialInits = this.potentialInits;
567     boolean hasNullInfo = (this.tagBits & NULL_FLAG_MASK) != 0;
568     if (hasNullInfo) {
569         copy.nullBit1 = this.nullBit1;
570         copy.nullBit2 = this.nullBit2;
571         copy.nullBit3 = this.nullBit3;
572         copy.nullBit4 = this.nullBit4;
573     }
574     copy.tagBits = this.tagBits;
575     copy.maxFieldCount = this.maxFieldCount;
576     if (this.extra != null) {
577         int length;
578         copy.extra = new long[extraLength][];
579         System.arraycopy(this.extra[0], 0,
580             (copy.extra[0] = new long[length = this.extra[0].length]), 0,
581             length);
582         System.arraycopy(this.extra[1], 0,
583             (copy.extra[1] = new long[length]), 0, length);
584         if (hasNullInfo) {
585             for (int j = 2; j < extraLength; j++) {
586                 System.arraycopy(this.extra[j], 0,
587                     (copy.extra[j] = new long[length]), 0, length);
588             }
589         }
590         else {
591             for (int j = 2; j < extraLength; j++) {
592                 copy.extra[j] = new long[length];
593             }
594         }
595     }
596     return copy;
597 }
598
599 /**
600  * Discard definite inits and potential inits from this, then return this.
601  * The returned flow info only holds null related information.
602  * @return this flow info, minus definite inits and potential inits
603  */

604 public UnconditionalFlowInfo discardInitializationInfo() {
605     if (this == DEAD_END) {
606         return this;
607     }
608     this.definiteInits =
609         this.potentialInits = 0;
610     if (this.extra != null) {
611         for (int i = 0, length = this.extra[0].length; i < length; i++) {
612             this.extra[0][i] = this.extra[1][i] = 0;
613         }
614     }
615     return this;
616 }
617
618 /**
619  * Remove local variables information from this flow info and return this.
620  * @return this, deprived from any local variable information
621  */

622 public UnconditionalFlowInfo discardNonFieldInitializations() {
623     int limit = this.maxFieldCount;
624     if (limit < BitCacheSize) {
625         long mask = (1L << limit)-1;
626         this.definiteInits &= mask;
627         this.potentialInits &= mask;
628         this.nullBit1 &= mask;
629         this.nullBit2 &= mask;
630         this.nullBit3 &= mask;
631         this.nullBit4 &= mask;
632     }
633     // use extra vector
634
if (this.extra == null) {
635         return this; // if vector not yet allocated, then not initialized
636
}
637     int vectorIndex, length = this.extra[0].length;
638     if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
639         return this; // not enough room yet
640
}
641     if (vectorIndex >= 0) {
642         // else we only have complete non field array items left
643
long mask = (1L << (limit % BitCacheSize))-1;
644         for (int j = 0; j < extraLength; j++) {
645             this.extra[j][vectorIndex] &= mask;
646         }
647     }
648     for (int i = vectorIndex + 1; i < length; i++) {
649         for (int j = 0; j < extraLength; j++) {
650             this.extra[j][i] = 0;
651         }
652     }
653     return this;
654 }
655
656 public FlowInfo initsWhenFalse() {
657     return this;
658 }
659
660 public FlowInfo initsWhenTrue() {
661     return this;
662 }
663
664 /**
665  * Check status of definite assignment at a given position.
666  * It deals with the dual representation of the InitializationInfo2:
667  * bits for the first 64 entries, then an array of booleans.
668  */

669 final private boolean isDefinitelyAssigned(int position) {
670     if (position < BitCacheSize) {
671         // use bits
672
return (this.definiteInits & (1L << position)) != 0;
673     }
674     // use extra vector
675
if (this.extra == null)
676         return false; // if vector not yet allocated, then not initialized
677
int vectorIndex;
678     if ((vectorIndex = (position / BitCacheSize) - 1)
679             >= this.extra[0].length) {
680         return false; // if not enough room in vector, then not initialized
681
}
682     return ((this.extra[0][vectorIndex]) &
683                 (1L << (position % BitCacheSize))) != 0;
684 }
685
686 final public boolean isDefinitelyAssigned(FieldBinding field) {
687     // Mirrored in CodeStream.isDefinitelyAssigned(..)
688
// do not want to complain in unreachable code
689
if ((this.tagBits & UNREACHABLE) != 0) {
690         return true;
691     }
692     return isDefinitelyAssigned(field.id);
693 }
694
695 final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
696     // do not want to complain in unreachable code if local declared in reachable code
697
if ((this.tagBits & UNREACHABLE) != 0 && (local.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0) {
698         return true;
699     }
700     return isDefinitelyAssigned(local.id + this.maxFieldCount);
701 }
702
703 final public boolean isDefinitelyNonNull(LocalVariableBinding local) {
704     // do not want to complain in unreachable code
705
if ((this.tagBits & UNREACHABLE) != 0 ||
706             (this.tagBits & NULL_FLAG_MASK) == 0) {
707         return false;
708     }
709     if ((local.type.tagBits & TagBits.IsBaseType) != 0 ||
710             local.constant() != Constant.NotAConstant) { // String instances
711
return true;
712     }
713     int position = local.id + this.maxFieldCount;
714     if (position < BitCacheSize) { // use bits
715
return ((this.nullBit1 & this.nullBit3 & (~this.nullBit2 | this.nullBit4))
716                 & (1L << position)) != 0;
717     }
718     // use extra vector
719
if (this.extra == null) {
720         return false; // if vector not yet allocated, then not initialized
721
}
722     int vectorIndex;
723     if ((vectorIndex = (position / BitCacheSize) - 1)
724             >= this.extra[0].length) {
725         return false; // if not enough room in vector, then not initialized
726
}
727     return ((this.extra[2][vectorIndex] & this.extra[4][vectorIndex]
728                 & (~this.extra[3][vectorIndex] | this.extra[5][vectorIndex]))
729             & (1L << (position % BitCacheSize))) != 0;
730 }
731
732 final public boolean isDefinitelyNull(LocalVariableBinding local) {
733     // do not want to complain in unreachable code
734
if ((this.tagBits & UNREACHABLE) != 0 ||
735             (this.tagBits & NULL_FLAG_MASK) == 0 ||
736             (local.type.tagBits & TagBits.IsBaseType) != 0) {
737         return false;
738     }
739     int position = local.id + this.maxFieldCount;
740     if (position < BitCacheSize) { // use bits
741
return ((this.nullBit1 & this.nullBit2
742                     & (~this.nullBit3 | ~this.nullBit4))
743                 & (1L << position)) != 0;
744     }
745     // use extra vector
746
if (this.extra == null) {
747         return false; // if vector not yet allocated, then not initialized
748
}
749     int vectorIndex;
750     if ((vectorIndex = (position / BitCacheSize) - 1) >=
751             this.extra[0].length) {
752         return false; // if not enough room in vector, then not initialized
753
}
754     return ((this.extra[2][vectorIndex] & this.extra[3][vectorIndex]
755                 & (~this.extra[4][vectorIndex] | ~this.extra[5][vectorIndex]))
756             & (1L << (position % BitCacheSize))) != 0;
757 }
758
759 final public boolean isDefinitelyUnknown(LocalVariableBinding local) {
760     // do not want to complain in unreachable code
761
if ((this.tagBits & UNREACHABLE) != 0 ||
762             (this.tagBits & NULL_FLAG_MASK) == 0) {
763         return false;
764     }
765     int position = local.id + this.maxFieldCount;
766     if (position < BitCacheSize) { // use bits
767
return ((this.nullBit1 & this.nullBit4
768                 & ~this.nullBit2 & ~this.nullBit3) & (1L << position)) != 0;
769     }
770     // use extra vector
771
if (this.extra == null) {
772         return false; // if vector not yet allocated, then not initialized
773
}
774     int vectorIndex;
775     if ((vectorIndex = (position / BitCacheSize) - 1) >=
776             this.extra[0].length) {
777         return false; // if not enough room in vector, then not initialized
778
}
779     return ((this.extra[2][vectorIndex] & this.extra[5][vectorIndex]
780         & ~this.extra[3][vectorIndex] & ~this.extra[4][vectorIndex])
781             & (1L << (position % BitCacheSize))) != 0;
782 }
783
784 /**
785  * Check status of potential assignment at a given position.
786  */

787 final private boolean isPotentiallyAssigned(int position) {
788     // id is zero-based
789
if (position < BitCacheSize) {
790         // use bits
791
return (this.potentialInits & (1L << position)) != 0;
792     }
793     // use extra vector
794
if (this.extra == null) {
795         return false; // if vector not yet allocated, then not initialized
796
}
797     int vectorIndex;
798     if ((vectorIndex = (position / BitCacheSize) - 1)
799             >= this.extra[0].length) {
800         return false; // if not enough room in vector, then not initialized
801
}
802     return ((this.extra[1][vectorIndex]) &
803             (1L << (position % BitCacheSize))) != 0;
804 }
805
806 final public boolean isPotentiallyAssigned(FieldBinding field) {
807     return isPotentiallyAssigned(field.id);
808 }
809
810 final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
811     // final constants are inlined, and thus considered as always initialized
812
if (local.constant() != Constant.NotAConstant) {
813         return true;
814     }
815     return isPotentiallyAssigned(local.id + this.maxFieldCount);
816 }
817
818 final public boolean isPotentiallyNonNull(LocalVariableBinding local) {
819     if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
820             (local.type.tagBits & TagBits.IsBaseType) != 0) {
821         return false;
822     }
823     int position;
824     if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
825         // use bits
826
return ((this.nullBit3 & (~this.nullBit1 | ~this.nullBit2))
827                 & (1L << position)) != 0;
828     }
829     // use extra vector
830
if (this.extra == null) {
831         return false; // if vector not yet allocated, then not initialized
832
}
833     int vectorIndex;
834     if ((vectorIndex = (position / BitCacheSize) - 1) >=
835             this.extra[0].length) {
836         return false; // if not enough room in vector, then not initialized
837
}
838     return ((this.extra[4][vectorIndex]
839                 & (~this.extra[2][vectorIndex] | ~this.extra[3][vectorIndex]))
840             & (1L << (position % BitCacheSize))) != 0;
841 }
842
843 final public boolean isPotentiallyNull(LocalVariableBinding local) {
844     if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
845             (local.type.tagBits & TagBits.IsBaseType) != 0) {
846         return false;
847     }
848     int position;
849     if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
850         // use bits
851
return ((this.nullBit2 & (~this.nullBit1 | ~this.nullBit3))
852                 & (1L << position)) != 0;
853     }
854     // use extra vector
855
if (this.extra == null) {
856         return false; // if vector not yet allocated, then not initialized
857
}
858     int vectorIndex;
859     if ((vectorIndex = (position / BitCacheSize) - 1) >=
860             this.extra[0].length) {
861         return false; // if not enough room in vector, then not initialized
862
}
863     return ((this.extra[3][vectorIndex]
864                 & (~this.extra[2][vectorIndex] | ~this.extra[4][vectorIndex]))
865             & (1L << (position % BitCacheSize))) != 0;
866 }
867
868 final public boolean isPotentiallyUnknown(LocalVariableBinding local) {
869     // do not want to complain in unreachable code
870
if ((this.tagBits & UNREACHABLE) != 0 ||
871             (this.tagBits & NULL_FLAG_MASK) == 0) {
872         return false;
873     }
874     int position = local.id + this.maxFieldCount;
875     if (position < BitCacheSize) { // use bits
876
return (this.nullBit4
877             & (~this.nullBit1 | ~this.nullBit2 & ~this.nullBit3)
878             & (1L << position)) != 0;
879     }
880     // use extra vector
881
if (this.extra == null) {
882         return false; // if vector not yet allocated, then not initialized
883
}
884     int vectorIndex;
885     if ((vectorIndex = (position / BitCacheSize) - 1) >=
886             this.extra[0].length) {
887         return false; // if not enough room in vector, then not initialized
888
}
889     return (this.extra[5][vectorIndex]
890             & (~this.extra[2][vectorIndex]
891                 | ~this.extra[3][vectorIndex] & ~this.extra[4][vectorIndex])
892             & (1L << (position % BitCacheSize))) != 0;
893 }
894
895 final public boolean isProtectedNonNull(LocalVariableBinding local) {
896     if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
897             (local.type.tagBits & TagBits.IsBaseType) != 0) {
898         return false;
899     }
900     int position;
901     if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
902         // use bits
903
return (this.nullBit1 & this.nullBit3 & this.nullBit4 & (1L << position)) != 0;
904     }
905     // use extra vector
906
if (this.extra == null) {
907         return false; // if vector not yet allocated, then not initialized
908
}
909     int vectorIndex;
910     if ((vectorIndex = (position / BitCacheSize) - 1) >=
911         this.extra[0].length) {
912         return false; // if not enough room in vector, then not initialized
913
}
914     return (this.extra[2][vectorIndex]
915                 & this.extra[4][vectorIndex]
916                 & this.extra[5][vectorIndex]
917             & (1L << (position % BitCacheSize))) != 0;
918 }
919
920 final public boolean isProtectedNull(LocalVariableBinding local) {
921     if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
922             (local.type.tagBits & TagBits.IsBaseType) != 0) {
923         return false;
924     }
925     int position;
926     if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
927         // use bits
928
return (this.nullBit1 & this.nullBit2
929             & (this.nullBit3 ^ this.nullBit4)
930             & (1L << position)) != 0;
931     }
932     // use extra vector
933
if (this.extra == null) {
934         return false; // if vector not yet allocated, then not initialized
935
}
936     int vectorIndex;
937     if ((vectorIndex = (position / BitCacheSize) - 1) >=
938             this.extra[0].length) {
939         return false; // if not enough room in vector, then not initialized
940
}
941     return (this.extra[2][vectorIndex] & this.extra[3][vectorIndex]
942             & (this.extra[4][vectorIndex] ^ this.extra[5][vectorIndex])
943             & (1L << (position % BitCacheSize))) != 0;
944 }
945
946 public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
947     // protected from non-object locals in calling methods
948
if (this != DEAD_END) {
949         this.tagBits |= NULL_FLAG_MASK;
950         int position;
951         long mask;
952         long a1, a2, a3, a4, na2;
953         // position is zero-based
954
if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
955             // use bits
956
if (((mask = 1L << position)
957                 & (a1 = this.nullBit1)
958                 & (na2 = ~(a2 = this.nullBit2))
959                 & ~(a3 = this.nullBit3)
960                 & (a4 = this.nullBit4))
961                     != 0) {
962                 this.nullBit4 &= ~mask;
963             } else if ((mask & a1 & na2 & a3) == 0) {
964                 this.nullBit4 |= mask;
965                 if ((mask & a1) == 0) {
966                     if ((mask & a2 & (a3 ^ a4)) != 0) {
967                         this.nullBit2 &= ~mask;
968                     }
969                     else if ((mask & (a2 | a3 | a4)) == 0) {
970                         this.nullBit2 |= mask;
971                     }
972                 }
973             }
974             this.nullBit1 |= mask;
975             this.nullBit3 |= mask;
976             if (coverageTestFlag && coverageTestId == 15) {
977                 this.nullBit4 = ~0;
978             }
979         }
980         else {
981             // use extra vector
982
int vectorIndex = (position / BitCacheSize) - 1;
983             if (this.extra == null) {
984                 int length = vectorIndex + 1;
985                 this.extra = new long[extraLength][];
986                 for (int j = 0; j < extraLength; j++) {
987                     this.extra[j] = new long[length];
988                 }
989                 if (coverageTestFlag && coverageTestId == 16) {
990                     throw new AssertionFailedException("COVERAGE 16"); //$NON-NLS-1$
991
}
992             }
993             else {
994                 int oldLength;
995                 if (vectorIndex >= (oldLength = this.extra[0].length)) {
996                     int newLength = vectorIndex + 1;
997                     for (int j = 0; j < extraLength; j++) {
998                         System.arraycopy(this.extra[j], 0,
999                             (this.extra[j] = new long[newLength]), 0,
1000                            oldLength);
1001                    }
1002                    if (coverageTestFlag && coverageTestId == 17) {
1003                        throw new AssertionFailedException("COVERAGE 17"); //$NON-NLS-1$
1004
}
1005                }
1006            }
1007            // MACRO :'b,'es/nullBit\(.\)/extra[\1 + 1][vectorIndex]/gc
1008
if (((mask = 1L << (position % BitCacheSize))
1009                & (a1 = this.extra[1 + 1][vectorIndex])
1010                & (na2 = ~(a2 = this.extra[2 + 1][vectorIndex]))
1011                & ~(a3 = this.extra[3 + 1][vectorIndex])
1012                & (a4 = this.extra[4 + 1][vectorIndex]))
1013                    != 0) {
1014                this.extra[4 + 1][vectorIndex] &= ~mask;
1015            } else if ((mask & a1 & na2 & a3) == 0) {
1016                this.extra[4 + 1][vectorIndex] |= mask;
1017                if ((mask & a1) == 0) {
1018                    if ((mask & a2 & (a3 ^ a4)) != 0) {
1019                        this.extra[2 + 1][vectorIndex] &= ~mask;
1020                    }
1021                    else if ((mask & (a2 | a3 | a4)) == 0) {
1022                        this.extra[2 + 1][vectorIndex] |= mask;
1023                    }
1024                }
1025            }
1026            this.extra[1 + 1][vectorIndex] |= mask;
1027            this.extra[3 + 1][vectorIndex] |= mask;
1028            if (coverageTestFlag && coverageTestId == 18) {
1029                this.extra[5][vectorIndex] = ~0;
1030            }
1031        }
1032    }
1033}
1034
1035public void markAsComparedEqualToNull(LocalVariableBinding local) {
1036    // protected from non-object locals in calling methods
1037
if (this != DEAD_END) {
1038        this.tagBits |= NULL_FLAG_MASK;
1039        int position;
1040        long mask;
1041        // position is zero-based
1042
if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1043            // use bits
1044
if (((mask = 1L << position) & this.nullBit1) != 0) {
1045                if ((mask
1046                    & (~this.nullBit2 | this.nullBit3
1047                        | ~this.nullBit4)) != 0) {
1048                    this.nullBit4 &= ~mask;
1049                }
1050            } else if ((mask & this.nullBit4) != 0) {
1051                  this.nullBit3 &= ~mask;
1052            } else {
1053                if ((mask & this.nullBit2) != 0) {
1054                    this.nullBit3 &= ~mask;
1055                    this.nullBit4 |= mask;
1056                } else {
1057                    this.nullBit3 |= mask;
1058                }
1059            }
1060            this.nullBit1 |= mask;
1061            this.nullBit2 |= mask;
1062            if (coverageTestFlag && coverageTestId == 19) {
1063                this.nullBit4 = ~0;
1064            }
1065        }
1066        else {
1067            // use extra vector
1068
int vectorIndex = (position / BitCacheSize) - 1;
1069            mask = 1L << (position % BitCacheSize);
1070            if (this.extra == null) {
1071                int length = vectorIndex + 1;
1072                this.extra = new long[extraLength][];
1073                for (int j = 0; j < extraLength; j++) {
1074                    this.extra[j] = new long[length ];
1075                }
1076                if (coverageTestFlag && coverageTestId == 20) {
1077                    throw new AssertionFailedException("COVERAGE 20"); //$NON-NLS-1$
1078
}
1079            }
1080            else {
1081                int oldLength;
1082                if (vectorIndex >= (oldLength = this.extra[0].length)) {
1083                    int newLength = vectorIndex + 1;
1084                    for (int j = 0; j < extraLength; j++) {
1085                        System.arraycopy(this.extra[j], 0,
1086                            (this.extra[j] = new long[newLength]), 0,
1087                            oldLength);
1088                    }
1089                    if (coverageTestFlag && coverageTestId == 21) {
1090                        throw new AssertionFailedException("COVERAGE 21"); //$NON-NLS-1$
1091
}
1092                }
1093            }
1094            if ((mask & this.extra[1 + 1][vectorIndex]) != 0) {
1095                if ((mask
1096                    & (~this.extra[2 + 1][vectorIndex] | this.extra[3 + 1][vectorIndex]
1097                        | ~this.extra[4 + 1][vectorIndex])) != 0) {
1098                    this.extra[4 + 1][vectorIndex] &= ~mask;
1099                }
1100            } else if ((mask & this.extra[4 + 1][vectorIndex]) != 0) {
1101                  this.extra[3 + 1][vectorIndex] &= ~mask;
1102            } else {
1103                if ((mask & this.extra[2 + 1][vectorIndex]) != 0) {
1104                    this.extra[3 + 1][vectorIndex] &= ~mask;
1105                    this.extra[4 + 1][vectorIndex] |= mask;
1106                } else {
1107                    this.extra[3 + 1][vectorIndex] |= mask;
1108                }
1109            }
1110            this.extra[1 + 1][vectorIndex] |= mask;
1111            this.extra[2 + 1][vectorIndex] |= mask;
1112        }
1113    }
1114}
1115
1116/**
1117 * Record a definite assignment at a given position.
1118 */

1119final private void markAsDefinitelyAssigned(int position) {
1120    
1121    if (this != DEAD_END) {
1122        // position is zero-based
1123
if (position < BitCacheSize) {
1124            // use bits
1125
long mask;
1126            this.definiteInits |= (mask = 1L << position);
1127            this.potentialInits |= mask;
1128        }
1129        else {
1130            // use extra vector
1131
int vectorIndex = (position / BitCacheSize) - 1;
1132            if (this.extra == null) {
1133                int length = vectorIndex + 1;
1134                this.extra = new long[extraLength][];
1135                for (int j = 0; j < extraLength; j++) {
1136                    this.extra[j] = new long[length];
1137                }
1138            }
1139            else {
1140                int oldLength; // might need to grow the arrays
1141
if (vectorIndex >= (oldLength = this.extra[0].length)) {
1142                    for (int j = 0; j < extraLength; j++) {
1143                        System.arraycopy(this.extra[j], 0,
1144                            (this.extra[j] = new long[vectorIndex + 1]), 0,
1145                            oldLength);
1146                    }
1147                }
1148            }
1149            long mask;
1150            this.extra[0][vectorIndex] |=
1151                (mask = 1L << (position % BitCacheSize));
1152            this.extra[1][vectorIndex] |= mask;
1153        }
1154    }
1155}
1156
1157public void markAsDefinitelyAssigned(FieldBinding field) {
1158    if (this != DEAD_END)
1159        markAsDefinitelyAssigned(field.id);
1160}
1161
1162public void markAsDefinitelyAssigned(LocalVariableBinding local) {
1163    if (this != DEAD_END)
1164        markAsDefinitelyAssigned(local.id + this.maxFieldCount);
1165}
1166
1167public void markAsDefinitelyNonNull(LocalVariableBinding local) {
1168    // protected from non-object locals in calling methods
1169
if (this != DEAD_END) {
1170        this.tagBits |= NULL_FLAG_MASK;
1171        long mask;
1172        int position;
1173        // position is zero-based
1174
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
1175
// set assigned non null
1176
this.nullBit1 |= (mask = 1L << position);
1177            this.nullBit3 |= mask;
1178            // clear others
1179
this.nullBit2 &= (mask = ~mask);
1180            this.nullBit4 &= mask;
1181            if (coverageTestFlag && coverageTestId == 22) {
1182                this.nullBit1 = 0;
1183            }
1184        }
1185        else {
1186            // use extra vector
1187
int vectorIndex ;
1188            this.extra[2][vectorIndex = (position / BitCacheSize) - 1]
1189                |= (mask = 1L << (position % BitCacheSize));
1190            this.extra[4][vectorIndex] |= mask;
1191            this.extra[3][vectorIndex] &= (mask = ~mask);
1192            this.extra[5][vectorIndex] &= mask;
1193            if (coverageTestFlag && coverageTestId == 23) {
1194                this.extra[2][vectorIndex] = 0;
1195            }
1196        }
1197    }
1198}
1199
1200public void markAsDefinitelyNull(LocalVariableBinding local) {
1201    // protected from non-object locals in calling methods
1202
if (this != DEAD_END) {
1203        this.tagBits |= NULL_FLAG_MASK;
1204        long mask;
1205        int position;
1206        // position is zero-based
1207
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
1208
// mark assigned null
1209
this.nullBit1 |= (mask = 1L << position);
1210            this.nullBit2 |= mask;
1211            // clear others
1212
this.nullBit3 &= (mask = ~mask);
1213            this.nullBit4 &= mask;
1214            if (coverageTestFlag && coverageTestId == 24) {
1215                this.nullBit4 = ~0;
1216            }
1217        }
1218        else {
1219            // use extra vector
1220
int vectorIndex ;
1221            this.extra[2][vectorIndex = (position / BitCacheSize) - 1]
1222                |= (mask = 1L << (position % BitCacheSize));
1223            this.extra[3][vectorIndex] |= mask;
1224            this.extra[4][vectorIndex] &= (mask = ~mask);
1225            this.extra[5][vectorIndex] &= mask;
1226            if (coverageTestFlag && coverageTestId == 25) {
1227                this.extra[5][vectorIndex] = ~0;
1228            }
1229        }
1230    }
1231}
1232
1233/**
1234 * Mark a local as having been assigned to an unknown value.
1235 * @param local the local to mark
1236 */

1237// PREMATURE may try to get closer to markAsDefinitelyAssigned, but not
1238
// obvious
1239
public void markAsDefinitelyUnknown(LocalVariableBinding local) {
1240    // protected from non-object locals in calling methods
1241
if (this != DEAD_END) {
1242        this.tagBits |= NULL_FLAG_MASK;
1243        long mask;
1244        int position;
1245        // position is zero-based
1246
if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1247            // use bits
1248
// mark assigned null
1249
this.nullBit1 |= (mask = 1L << position);
1250            this.nullBit4 |= mask;
1251            // clear others
1252
this.nullBit2 &= (mask = ~mask);
1253            this.nullBit3 &= mask;
1254            if (coverageTestFlag && coverageTestId == 26) {
1255                this.nullBit4 = 0;
1256            }
1257        }
1258        else {
1259            // use extra vector
1260
int vectorIndex ;
1261            this.extra[2][vectorIndex = (position / BitCacheSize) - 1]
1262                |= (mask = 1L << (position % BitCacheSize));
1263            this.extra[5][vectorIndex] |= mask;
1264            this.extra[3][vectorIndex] &= (mask = ~mask);
1265            this.extra[4][vectorIndex] &= mask;
1266            if (coverageTestFlag && coverageTestId == 27) {
1267                this.extra[5][vectorIndex] = 0;
1268            }
1269        }
1270    }
1271}
1272
1273public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
1274    if ((otherInits.tagBits & UNREACHABLE) != 0 && this != DEAD_END) {
1275        if (coverageTestFlag && coverageTestId == 28) {
1276            throw new AssertionFailedException("COVERAGE 28"); //$NON-NLS-1$
1277
}
1278        return this;
1279    }
1280    if ((this.tagBits & UNREACHABLE) != 0) {
1281        if (coverageTestFlag && coverageTestId == 29) {
1282            throw new AssertionFailedException("COVERAGE 29"); //$NON-NLS-1$
1283
}
1284        return (UnconditionalFlowInfo) otherInits.copy(); // make sure otherInits won't be affected
1285
}
1286    
1287    // intersection of definitely assigned variables,
1288
this.definiteInits &= otherInits.definiteInits;
1289    // union of potentially set ones
1290
this.potentialInits |= otherInits.potentialInits;
1291
1292    // null combinations
1293
boolean
1294        thisHasNulls = (this.tagBits & NULL_FLAG_MASK) != 0,
1295        otherHasNulls = (otherInits.tagBits & NULL_FLAG_MASK) != 0,
1296        thisHadNulls = thisHasNulls;
1297    long
1298        a1, a2, a3, a4,
1299        na1, na2, na3, na4,
1300        nb1, nb2, nb3, nb4,
1301        b1, b2, b3, b4;
1302    if (thisHadNulls) {
1303        if (otherHasNulls) {
1304            this.nullBit1 = (a2 = this.nullBit2) & (a3 = this.nullBit3)
1305                                & (a4 = this.nullBit4) & (b1 = otherInits.nullBit1)
1306                                & (nb2 = ~(b2 = otherInits.nullBit2))
1307                            | (a1 = this.nullBit1) & (b1 & (a3 & a4 & (b3 = otherInits.nullBit3)
1308                                                                    & (b4 = otherInits.nullBit4)
1309                                                                | (na2 = ~a2) & nb2
1310                                                                    & ((nb4 = ~b4) | (na4 = ~a4)
1311                                                                            | (na3 = ~a3) & (nb3 = ~b3))
1312                                                                | a2 & b2 & ((na4 | na3) & (nb4 | nb3)))
1313                                                            | na2 & b2 & b3 & b4);
1314            this.nullBit2 = b2 & (nb3 | (nb1 = ~b1) | a3 & (a4 | (na1 = ~a1)) & nb4)
1315                    | a2 & (b2 | na4 & b3 & (b4 | nb1) | na3 | na1);
1316            this.nullBit3 = b3 & (nb2 & b4 | nb1 | a3 & (na4 & nb4 | a4 & b4))
1317                    | a3 & (na2 & a4 | na1)
1318                    | (a2 | na1) & b1 & nb2 & nb4
1319                    | a1 & na2 & na4 & (b2 | nb1);
1320            this.nullBit4 = na3 & (nb1 & nb3 & b4
1321                        | b1 & (nb2 & nb3 | a4 & b2 & nb4)
1322                        | na1 & a4 & (nb3 | b1 & b2))
1323                    | a3 & a4 & (b3 & b4 | b1 & nb2)
1324                    | na2 & (nb1 & b4 | b1 & nb3 | na1 & a4) & nb2
1325                    | a1 & (na3 & (nb3 & b4
1326                                    | b1 & b2 & b3 & nb4
1327                                    | na2 & (nb3 | nb2))
1328                            | na2 & b3 & b4
1329                            | a2 & (nb1 & b4 | a3 & na4 & b1) & nb3);
1330            if (coverageTestFlag && coverageTestId == 30) {
1331                this.nullBit4 = ~0;
1332            }
1333        } else { // other has no null info
1334
a1 = this.nullBit1;
1335            this.nullBit1 = 0;
1336            this.nullBit2 = (a2 = this.nullBit2) & (na3 = ~(a3 = this.nullBit3) | (na1 = ~a1));
1337            this.nullBit3 = a3 & ((na2 = ~a2) & (a4 = this.nullBit4) | na1) | a1 & na2 & ~a4;
1338            this.nullBit4 = (na3 | na2) & na1 & a4 | a1 & na3 & na2;
1339            if (coverageTestFlag && coverageTestId == 31) {
1340                this.nullBit4 = ~0;
1341            }
1342        }
1343    } else if (otherHasNulls) { // only other had nulls
1344
this.nullBit1 = 0;
1345        this.nullBit2 = (b2 = otherInits.nullBit2) & (nb3 = ~(b3 = otherInits.nullBit3) | (nb1 = ~(b1 = otherInits.nullBit1)));
1346        this.nullBit3 = b3 & ((nb2 = ~b2) & (b4 = otherInits.nullBit4) | nb1) | b1 & nb2 & ~b4;
1347        this.nullBit4 = (nb3 | nb2) & nb1 & b4 | b1 & nb3 & nb2;
1348        if (coverageTestFlag && coverageTestId == 32) {
1349            this.nullBit4 = ~0;
1350        }
1351        thisHasNulls =
1352            // redundant with the three following ones
1353
this.nullBit2 != 0 ||
1354            this.nullBit3 != 0 ||
1355            this.nullBit4 != 0;
1356    }
1357
1358    // treating extra storage
1359
if (this.extra != null || otherInits.extra != null) {
1360        int mergeLimit = 0, copyLimit = 0, resetLimit = 0;
1361        int i;
1362        if (this.extra != null) {
1363            if (otherInits.extra != null) {
1364                // both sides have extra storage
1365
int length, otherLength;
1366                if ((length = this.extra[0].length) <
1367                        (otherLength = otherInits.extra[0].length)) {
1368                    // current storage is shorter -> grow current
1369
for (int j = 0; j < extraLength; j++) {
1370                        System.arraycopy(this.extra[j], 0,
1371                            (this.extra[j] = new long[otherLength]), 0, length);
1372                    }
1373                    mergeLimit = length;
1374                    copyLimit = otherLength;
1375                    if (coverageTestFlag && coverageTestId == 33) {
1376                        throw new AssertionFailedException("COVERAGE 33"); //$NON-NLS-1$
1377
}
1378                }
1379                else {
1380                    // current storage is longer
1381
mergeLimit = otherLength;
1382                    resetLimit = length;
1383                    if (coverageTestFlag && coverageTestId == 34) {
1384                        throw new AssertionFailedException("COVERAGE 34"); //$NON-NLS-1$
1385
}
1386                }
1387            }
1388            else {
1389                resetLimit = this.extra[0].length;
1390                if (coverageTestFlag && coverageTestId == 35) {
1391                    throw new AssertionFailedException("COVERAGE 35"); //$NON-NLS-1$
1392
}
1393            }
1394        }
1395        else if (otherInits.extra != null) {
1396            // no storage here, but other has extra storage.
1397
int otherLength = otherInits.extra[0].length;
1398            this.extra = new long[extraLength][];
1399            for (int j = 0; j < extraLength; j++) {
1400                this.extra[j] = new long[otherLength];
1401            }
1402            System.arraycopy(otherInits.extra[1], 0,
1403                this.extra[1], 0, otherLength);
1404            copyLimit = otherLength;
1405            if (coverageTestFlag && coverageTestId == 36) {
1406                throw new AssertionFailedException("COVERAGE 36"); //$NON-NLS-1$
1407
}
1408        }
1409        // MACRO :'b,'es/nullBit\(.\)/extra[\1 + 1][i]/g
1410
// manage definite assignment
1411
for (i = 0; i < mergeLimit; i++) {
1412            this.extra[0][i] &= otherInits.extra[0][i];
1413            this.extra[1][i] |= otherInits.extra[1][i];
1414        }
1415        for (; i < copyLimit; i++) {
1416            this.extra[1][i] = otherInits.extra[1][i];
1417        }
1418        for (; i < resetLimit; i++) {
1419            this.extra[0][i] = 0;
1420        }
1421        // refine null bits requirements
1422
if (!otherHasNulls) {
1423          if (resetLimit < mergeLimit) {
1424            resetLimit = mergeLimit;
1425          }
1426          copyLimit = 0; // no need to carry inexisting nulls
1427
mergeLimit = 0;
1428        }
1429        if (!thisHadNulls) {
1430          resetLimit = 0; // no need to reset anything
1431
}
1432        // compose nulls
1433
for (i = 0; i < mergeLimit; i++) {
1434            this.extra[1 + 1][i] = (a2 = this.extra[2 + 1][i]) & (a3 = this.extra[3 + 1][i])
1435                                & (a4 = this.extra[4 + 1][i]) & (b1 = otherInits.extra[1 + 1][i])
1436                                & (nb2 = ~(b2 = otherInits.extra[2 + 1][i]))
1437                            | (a1 = this.extra[1 + 1][i]) & (b1 & (a3 & a4 & (b3 = otherInits.extra[3 + 1][i])
1438                                                                    & (b4 = otherInits.extra[4 + 1][i])
1439                                                                | (na2 = ~a2) & nb2
1440                                                                    & ((nb4 = ~b4) | (na4 = ~a4)
1441                                                                            | (na3 = ~a3) & (nb3 = ~b3))
1442                                                                | a2 & b2 & ((na4 | na3) & (nb4 | nb3)))
1443                                                            | na2 & b2 & b3 & b4);
1444            this.extra[2 + 1][i] = b2 & (nb3 | (nb1 = ~b1) | a3 & (a4 | (na1 = ~a1)) & nb4)
1445                    | a2 & (b2 | na4 & b3 & (b4 | nb1) | na3 | na1);
1446            this.extra[3 + 1][i] = b3 & (nb2 & b4 | nb1 | a3 & (na4 & nb4 | a4 & b4))
1447                    | a3 & (na2 & a4 | na1)
1448                    | (a2 | na1) & b1 & nb2 & nb4
1449                    | a1 & na2 & na4 & (b2 | nb1);
1450            this.extra[4 + 1][i] = na3 & (nb1 & nb3 & b4
1451                        | b1 & (nb2 & nb3 | a4 & b2 & nb4)
1452                        | na1 & a4 & (nb3 | b1 & b2))
1453                    | a3 & a4 & (b3 & b4 | b1 & nb2)
1454                    | na2 & (nb1 & b4 | b1 & nb3 | na1 & a4) & nb2
1455                    | a1 & (na3 & (nb3 & b4
1456                                    | b1 & b2 & b3 & nb4
1457                                    | na2 & (nb3 | nb2))
1458                            | na2 & b3 & b4
1459                            | a2 & (nb1 & b4 | a3 & na4 & b1) & nb3);
1460            thisHasNulls = thisHasNulls ||
1461                this.extra[3][i] != 0 ||
1462                this.extra[4][i] != 0 ||
1463                this.extra[5][i] != 0 ;
1464            if (coverageTestFlag && coverageTestId == 37) {
1465                this.extra[5][i] = ~0;
1466            }
1467        }
1468        for (; i < copyLimit; i++) {
1469            this.extra[1 + 1][i] = 0;
1470            this.extra[2 + 1][i] = (b2 = otherInits.extra[2 + 1][i]) & (nb3 = ~(b3 = otherInits.extra[3 + 1][i]) | (nb1 = ~(b1 = otherInits.extra[1 + 1][i])));
1471            this.extra[3 + 1][i] = b3 & ((nb2 = ~b2) & (b4 = otherInits.extra[4 + 1][i]) | nb1) | b1 & nb2 & ~b4;
1472            this.extra[4 + 1][i] = (nb3 | nb2) & nb1 & b4 | b1 & nb3 & nb2;
1473            thisHasNulls = thisHasNulls ||
1474                this.extra[3][i] != 0 ||
1475                this.extra[4][i] != 0 ||
1476                this.extra[5][i] != 0;
1477            if (coverageTestFlag && coverageTestId == 38) {
1478                this.extra[5][i] = ~0;
1479            }
1480        }
1481        for (; i < resetLimit; i++) {
1482            a1 = this.extra[1 + 1][i];
1483            this.extra[1 + 1][i] = 0;
1484            this.extra[2 + 1][i] = (a2 = this.extra[2 + 1][i]) & (na3 = ~(a3 = this.extra[3 + 1][i]) | (na1 = ~a1));
1485            this.extra[3 + 1][i] = a3 & ((na2 = ~a2) & (a4 = this.extra[4 + 1][i]) | na1) | a1 & na2 & ~a4;
1486            this.extra[4 + 1][i] = (na3 | na2) & na1 & a4 | a1 & na3 & na2;
1487            thisHasNulls = thisHasNulls ||
1488                this.extra[3][i] != 0 ||
1489                this.extra[4][i] != 0 ||
1490                this.extra[5][i] != 0;
1491            if (coverageTestFlag && coverageTestId == 39) {
1492                this.extra[5][i] = ~0;
1493            }
1494        }
1495    }
1496    if (thisHasNulls) {
1497        this.tagBits |= NULL_FLAG_MASK;
1498    }
1499    else {
1500        this.tagBits &= ~NULL_FLAG_MASK;
1501    }
1502    return this;
1503}
1504
1505/*
1506 * Answer the total number of fields in enclosing types of a given type
1507 */

1508static int numberOfEnclosingFields(ReferenceBinding type){
1509    int count = 0;
1510    type = type.enclosingType();
1511    while(type != null) {
1512        count += type.fieldCount();
1513        type = type.enclosingType();
1514    }
1515    return count;
1516}
1517
1518public UnconditionalFlowInfo nullInfoLessUnconditionalCopy() {
1519    if (this == DEAD_END) {
1520        return this;
1521    }
1522    UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
1523    copy.definiteInits = this.definiteInits;
1524    copy.potentialInits = this.potentialInits;
1525    copy.tagBits = this.tagBits & ~NULL_FLAG_MASK;
1526    copy.maxFieldCount = this.maxFieldCount;
1527    if (this.extra != null) {
1528        int length;
1529        copy.extra = new long[extraLength][];
1530        System.arraycopy(this.extra[0], 0,
1531            (copy.extra[0] =
1532                new long[length = this.extra[0].length]), 0, length);
1533        System.arraycopy(this.extra[1], 0,
1534            (copy.extra[1] = new long[length]), 0, length);
1535        for (int j = 2; j < extraLength; j++) {
1536            copy.extra[j] = new long[length];
1537        }
1538    }
1539    return copy;
1540}
1541
1542public FlowInfo safeInitsWhenTrue() {
1543    return copy();
1544}
1545
1546public FlowInfo setReachMode(int reachMode) {
1547    if (reachMode == REACHABLE && this != DEAD_END) { // cannot modify DEAD_END
1548
this.tagBits &= ~UNREACHABLE;
1549    }
1550    else {
1551        if ((this.tagBits & UNREACHABLE) == 0) {
1552            // reset optional inits when becoming unreachable
1553
// see InitializationTest#test090 (and others)
1554
this.potentialInits = 0;
1555            if (this.extra != null) {
1556                for (int i = 0, length = this.extra[0].length;
1557                        i < length; i++) {
1558                    this.extra[1][i] = 0;
1559                }
1560            }
1561        }
1562        this.tagBits |= UNREACHABLE;
1563    }
1564    return this;
1565}
1566
1567public String JavaDoc toString(){
1568    // PREMATURE consider printing bit fields as 0001 0001 1000 0001...
1569
if (this == DEAD_END){
1570        return "FlowInfo.DEAD_END"; //$NON-NLS-1$
1571
}
1572    if ((this.tagBits & NULL_FLAG_MASK) != 0) {
1573        if (this.extra == null) {
1574            return "FlowInfo<def: " + this.definiteInits //$NON-NLS-1$
1575
+", pot: " + this.potentialInits //$NON-NLS-1$
1576
+ ", reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
1577
+", null: " + this.nullBit1 //$NON-NLS-1$
1578
+ this.nullBit2 + this.nullBit3 + this.nullBit4
1579                +">"; //$NON-NLS-1$
1580
}
1581        else {
1582            String JavaDoc def = "FlowInfo<def:[" + this.definiteInits, //$NON-NLS-1$
1583
pot = "], pot:[" + this.potentialInits, //$NON-NLS-1$
1584
nullS = ", null:[" + this.nullBit1 //$NON-NLS-1$
1585
+ this.nullBit2 + this.nullBit3 + this.nullBit4;
1586            int i, ceil;
1587            for (i = 0, ceil = this.extra[0].length > 3 ?
1588                                3 :
1589                                this.extra[0].length;
1590                i < ceil; i++) {
1591                def += "," + this.extra[0][i]; //$NON-NLS-1$
1592
pot += "," + this.extra[1][i]; //$NON-NLS-1$
1593
nullS += "," + this.extra[2][i] //$NON-NLS-1$
1594
+ this.extra[3][i] + this.extra[4][i] + this.extra[5][i];
1595            }
1596            if (ceil < this.extra[0].length) {
1597                def += ",..."; //$NON-NLS-1$
1598
pot += ",..."; //$NON-NLS-1$
1599
nullS += ",..."; //$NON-NLS-1$
1600
}
1601            return def + pot
1602                + "], reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
1603
+ nullS
1604                + "]>"; //$NON-NLS-1$
1605
}
1606    }
1607    else {
1608        if (this.extra == null) {
1609            return "FlowInfo<def: " + this.definiteInits //$NON-NLS-1$
1610
+", pot: " + this.potentialInits //$NON-NLS-1$
1611
+ ", reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
1612
+", no null info>"; //$NON-NLS-1$
1613
}
1614        else {
1615            String JavaDoc def = "FlowInfo<def:[" + this.definiteInits, //$NON-NLS-1$
1616
pot = "], pot:[" + this.potentialInits; //$NON-NLS-1$
1617
int i, ceil;
1618            for (i = 0, ceil = this.extra[0].length > 3 ?
1619                                3 :
1620                                this.extra[0].length;
1621                i < ceil; i++) {
1622                def += "," + this.extra[0][i]; //$NON-NLS-1$
1623
pot += "," + this.extra[1][i]; //$NON-NLS-1$
1624
}
1625            if (ceil < this.extra[0].length) {
1626                def += ",..."; //$NON-NLS-1$
1627
pot += ",..."; //$NON-NLS-1$
1628
}
1629            return def + pot
1630                + "], reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
1631
+ ", no null info>"; //$NON-NLS-1$
1632
}
1633    }
1634}
1635
1636public UnconditionalFlowInfo unconditionalCopy() {
1637    return (UnconditionalFlowInfo) copy();
1638}
1639    
1640public UnconditionalFlowInfo unconditionalFieldLessCopy() {
1641    // TODO (maxime) may consider leveraging null contribution verification as it is done in copy
1642
UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
1643    copy.tagBits = this.tagBits;
1644    copy.maxFieldCount = this.maxFieldCount;
1645    int limit = this.maxFieldCount;
1646    if (limit < BitCacheSize) {
1647        long mask;
1648        copy.definiteInits = this.definiteInits & (mask = ~((1L << limit)-1));
1649        copy.potentialInits = this.potentialInits & mask;
1650        copy.nullBit1 = this.nullBit1 & mask;
1651        copy.nullBit2 = this.nullBit2 & mask;
1652        copy.nullBit3 = this.nullBit3 & mask;
1653        copy.nullBit4 = this.nullBit4 & mask;
1654    }
1655    // use extra vector
1656
if (this.extra == null) {
1657        return copy; // if vector not yet allocated, then not initialized
1658
}
1659    int vectorIndex, length, copyStart;
1660    if ((vectorIndex = (limit / BitCacheSize) - 1) >=
1661            (length = this.extra[0].length)) {
1662        return copy; // not enough room yet
1663
}
1664    long mask;
1665    copy.extra = new long[extraLength][];
1666    if ((copyStart = vectorIndex + 1) < length) {
1667        int copyLength = length - copyStart;
1668        for (int j = 0; j < extraLength; j++) {
1669            System.arraycopy(this.extra[j], copyStart,
1670                (copy.extra[j] = new long[length]), copyStart,
1671                copyLength);
1672        }
1673    }
1674    else if (vectorIndex >= 0) {
1675        for (int j = 0; j < extraLength; j++) {
1676            copy.extra[j] = new long[length];
1677        }
1678    }
1679    if (vectorIndex >= 0) {
1680        mask = ~((1L << (limit % BitCacheSize))-1);
1681        for (int j = 0; j < extraLength; j++) {
1682            copy.extra[j][vectorIndex] =
1683                this.extra[j][vectorIndex] & mask;
1684        }
1685    }
1686    return copy;
1687}
1688
1689public UnconditionalFlowInfo unconditionalInits() {
1690    // also see conditional inits, where it requests them to merge
1691
return this;
1692}
1693
1694public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect() {
1695    return this;
1696}
1697}
1698
1699
Popular Tags