added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / flow / UnconditionalFlowInfo.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-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.FieldBinding;
14 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
15 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
16
17 /**
18  * Record initialization status during definite assignment analysis
19  *
20  * No caching of pre-allocated instances.
21  */
22 public class UnconditionalFlowInfo extends FlowInfo {
23
24         
25         public long definiteInits;
26         public long potentialInits;
27         public long extraDefiniteInits[];
28         public long extraPotentialInits[];
29         
30         public long definiteNulls;
31         public long definiteNonNulls;
32         public long extraDefiniteNulls[];
33         public long extraDefiniteNonNulls[];
34
35         public int reachMode; // by default
36
37         public int maxFieldCount;
38         
39         // Constants
40         public static final int BitCacheSize = 64; // 64 bits in a long.
41
42         UnconditionalFlowInfo() {
43                 this.reachMode = REACHABLE;
44         }
45
46         // unions of both sets of initialization - used for try/finally
47         public FlowInfo addInitializationsFrom(FlowInfo inits) {
48
49                 if (this == DEAD_END)
50                         return this;
51
52                 UnconditionalFlowInfo otherInits = inits.unconditionalInits();  
53                 if (otherInits == DEAD_END)
54                         return this;
55                         
56                 // union of definitely assigned variables, 
57                 definiteInits |= otherInits.definiteInits;
58                 // union of potentially set ones
59                 potentialInits |= otherInits.potentialInits;
60         
61                 // union of definitely null variables, 
62                 definiteNulls = (definiteNulls | otherInits.definiteNulls) & ~otherInits.definiteNonNulls;
63                 // union of definitely non null variables,
64                 definiteNonNulls = (definiteNonNulls | otherInits.definiteNonNulls) & ~otherInits.definiteNulls;
65                 // fix-up null/non-null infos since cannot overlap: <defN1:0,defNoN1:1>  + <defN2:1,defNoN2:0>  --> <defN:0,defNon:0>
66
67                 // treating extra storage
68                 if (extraDefiniteInits != null) {
69                         if (otherInits.extraDefiniteInits != null) {
70                                 // both sides have extra storage
71                                 int i = 0, length, otherLength;
72                                 if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
73                                         // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
74                                         System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
75                                         System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
76                                         for (; i < length; i++) {
77                                                 extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
78                                                 extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
79                                                 extraDefiniteNulls[i] = (extraDefiniteNulls[i] | otherInits.extraDefiniteNulls[i]) & ~otherInits.extraDefiniteNonNulls[i];
80                                                 extraDefiniteNonNulls[i] = (extraDefiniteNonNulls[i] | otherInits.extraDefiniteNonNulls[i]) & ~otherInits.extraDefiniteNulls[i];
81                                         }
82                                         for (; i < otherLength; i++) {
83                                                 extraPotentialInits[i] = otherInits.extraPotentialInits[i];
84                                         }
85                                 } else {
86                                         // current storage is longer
87                                         for (; i < otherLength; i++) {
88                                                 extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
89                                                 extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
90                                                 extraDefiniteNulls[i] = (extraDefiniteNulls[i] | otherInits.extraDefiniteNulls[i]) & ~otherInits.extraDefiniteNonNulls[i];
91                                                 extraDefiniteNonNulls[i] = (extraDefiniteNonNulls[i] | otherInits.extraDefiniteNonNulls[i]) & ~otherInits.extraDefiniteNulls[i];
92                                         }
93                                         for (; i < length; i++) {
94                                                 extraDefiniteInits[i] = 0;
95                                                 extraDefiniteNulls[i] = 0;
96                                                 extraDefiniteNonNulls[i] = 0;
97                                         }
98                                 }
99                         } else {
100                                 // no extra storage on otherInits
101                         }
102                 } else
103                         if (otherInits.extraDefiniteInits != null) {
104                                 // no storage here, but other has extra storage.
105                                 int otherLength;
106                                 System.arraycopy(otherInits.extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]), 0, otherLength);                        
107                                 System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
108                                 System.arraycopy(otherInits.extraDefiniteNulls, 0, (extraDefiniteNulls = new long[otherLength]), 0, otherLength);                       
109                                 System.arraycopy(otherInits.extraDefiniteNonNulls, 0, (extraDefiniteNonNulls = new long[otherLength]), 0, otherLength);                 
110                         }
111                 return this;
112         }
113
114         // unions of both sets of initialization - used for try/finally
115         public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) {
116         
117                 if (this == DEAD_END){
118                         return this;
119                 }
120
121                 UnconditionalFlowInfo otherInits = inits.unconditionalInits();
122                 if (otherInits == DEAD_END){
123                         return this;
124                 }
125                 // union of potentially set ones
126                 this.potentialInits |= otherInits.potentialInits;
127                 // also merge null check information (affected by potential inits)
128                 this.definiteNulls &= otherInits.definiteNulls;
129                 this.definiteNonNulls &= otherInits.definiteNonNulls;
130         
131                 // treating extra storage
132                 if (this.extraDefiniteInits != null) {
133                         if (otherInits.extraDefiniteInits != null) {
134                                 // both sides have extra storage
135                                 int i = 0, length, otherLength;
136                                 if ((length = this.extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
137                                         // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
138                                         System.arraycopy(this.extraDefiniteInits, 0, (this.extraDefiniteInits = new long[otherLength]), 0, length);
139                                         System.arraycopy(this.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, length);
140                                         System.arraycopy(this.extraDefiniteNulls, 0, (this.extraDefiniteNulls = new long[otherLength]), 0, length);
141                                         System.arraycopy(this.extraDefiniteNonNulls, 0, (this.extraDefiniteNonNulls = new long[otherLength]), 0, length);
142                                         while (i < length) {
143                                                 this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
144                                                 this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i];
145                                                 this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++];
146                                         }
147                                         while (i < otherLength) {
148                                                 this.extraPotentialInits[i] = otherInits.extraPotentialInits[i];
149                                                 this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i];
150                                                 this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++];
151                                         }
152                                 } else {
153                                         // current storage is longer
154                                         while (i < otherLength) {
155                                                 this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
156                                                 this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i];
157                                                 this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++];
158                                         }
159                                 }
160                         }
161                 } else
162                         if (otherInits.extraDefiniteInits != null) {
163                                 // no storage here, but other has extra storage.
164                                 int otherLength;
165                                 this.extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];                 
166                                 System.arraycopy(otherInits.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, otherLength);
167                                 this.extraDefiniteNulls = new long[otherLength];                        
168                                 this.extraDefiniteNonNulls = new long[otherLength];                     
169                         }
170                 return this;
171         }
172
173         /**
174          * Answers a copy of the current instance
175          */
176         public FlowInfo copy() {
177                 
178                 // do not clone the DeadEnd
179                 if (this == DEAD_END)
180                         return this;
181         
182                 // look for an unused preallocated object
183                 UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
184         
185                 // copy slots
186                 copy.definiteInits = this.definiteInits;
187                 copy.potentialInits = this.potentialInits;
188                 copy.definiteNulls = this.definiteNulls;
189                 copy.definiteNonNulls = this.definiteNonNulls;
190                 copy.reachMode = this.reachMode;
191                 copy.maxFieldCount = this.maxFieldCount;
192                 
193                 if (this.extraDefiniteInits != null) {
194                         int length;
195                         System.arraycopy(this.extraDefiniteInits, 0, (copy.extraDefiniteInits = new long[length = extraDefiniteInits.length]), 0, length);
196                         System.arraycopy(this.extraPotentialInits, 0, (copy.extraPotentialInits = new long[length]), 0, length);
197                         System.arraycopy(this.extraDefiniteNulls, 0, (copy.extraDefiniteNulls = new long[length]), 0, length);
198                         System.arraycopy(this.extraDefiniteNonNulls, 0, (copy.extraDefiniteNonNulls = new long[length]), 0, length);
199                 }
200                 return copy;
201         }
202         
203         public UnconditionalFlowInfo discardFieldInitializations(){
204                 
205                 int limit = this.maxFieldCount;
206                 
207                 if (limit < BitCacheSize) {
208                         long mask = (1L << limit)-1;
209                         this.definiteInits &= ~mask;
210                         this.potentialInits &= ~mask;
211                         this.definiteNulls &= ~mask;
212                         this.definiteNonNulls &= ~mask;
213                         return this;
214                 } 
215
216                 this.definiteInits = 0;
217                 this.potentialInits = 0;
218                 this.definiteNulls = 0;
219                 this.definiteNonNulls = 0;
220                 
221                 // use extra vector
222                 if (extraDefiniteInits == null) {
223                         return this; // if vector not yet allocated, then not initialized
224                 }
225                 int vectorIndex, length = this.extraDefiniteInits.length;
226                 if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
227                         return this; // not enough room yet
228                 }
229                 for (int i = 0; i < vectorIndex; i++) {
230                         this.extraDefiniteInits[i] = 0L;
231                         this.extraPotentialInits[i] = 0L;
232                         this.extraDefiniteNulls[i] = 0L;
233                         this.extraDefiniteNonNulls[i] = 0L;
234                 }
235                 long mask = (1L << (limit % BitCacheSize))-1;
236                 this.extraDefiniteInits[vectorIndex] &= ~mask;
237                 this.extraPotentialInits[vectorIndex] &= ~mask;
238                 this.extraDefiniteNulls[vectorIndex] &= ~mask;
239                 this.extraDefiniteNonNulls[vectorIndex] &= ~mask;
240                 return this;
241         }
242
243         public UnconditionalFlowInfo discardNonFieldInitializations(){
244                 
245                 int limit = this.maxFieldCount;
246                 
247                 if (limit < BitCacheSize) {
248                         long mask = (1L << limit)-1;
249                         this.definiteInits &= mask;
250                         this.potentialInits &= mask;
251                         this.definiteNulls &= mask;
252                         this.definiteNonNulls &= mask;
253                         return this;
254                 } 
255                 // use extra vector
256                 if (extraDefiniteInits == null) {
257                         return this; // if vector not yet allocated, then not initialized
258                 }
259                 int vectorIndex, length = this.extraDefiniteInits.length;
260                 if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
261                         return this; // not enough room yet
262                 }
263                 long mask = (1L << (limit % BitCacheSize))-1;
264                 this.extraDefiniteInits[vectorIndex] &= mask;
265                 this.extraPotentialInits[vectorIndex] &= mask;
266                 this.extraDefiniteNulls[vectorIndex] &= mask;
267                 this.extraDefiniteNonNulls[vectorIndex] &= mask;
268                 for (int i = vectorIndex+1; i < length; i++) {
269                         this.extraDefiniteInits[i] = 0L;
270                         this.extraPotentialInits[i] = 0L;
271                         this.extraDefiniteNulls[i] = 0L;
272                         this.extraDefiniteNonNulls[i] = 0L;
273                 }
274                 return this;
275         }
276         
277         public UnconditionalFlowInfo discardNullRelatedInitializations(){
278                 
279                 this.definiteNulls = 0;
280                 this.definiteNonNulls = 0;
281                 
282                 int length = this.extraDefiniteInits == null ? 0 : this.extraDefiniteInits.length;
283                 for (int i = 0; i < length; i++) {
284                         this.extraDefiniteNulls[i] = 0L;
285                         this.extraDefiniteNonNulls[i] = 0L;
286                 }
287                 return this;
288         }
289
290         public FlowInfo initsWhenFalse() {
291                 
292                 return this;
293         }
294         
295         public FlowInfo initsWhenTrue() {
296                 
297                 return this;
298         }
299         
300         /**
301          * Check status of definite assignment at a given position.
302          * It deals with the dual representation of the InitializationInfo2:
303          * bits for the first 64 entries, then an array of booleans.
304          */
305         final private boolean isDefinitelyAssigned(int position) {
306                 
307                 // Dependant of CodeStream.isDefinitelyAssigned(..)
308                 // id is zero-based
309                 if (position < BitCacheSize) {
310                         return (definiteInits & (1L << position)) != 0; // use bits
311                 }
312                 // use extra vector
313                 if (extraDefiniteInits == null)
314                         return false; // if vector not yet allocated, then not initialized
315                 int vectorIndex;
316                 if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteInits.length)
317                         return false; // if not enough room in vector, then not initialized 
318                 return ((extraDefiniteInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
319         }
320         
321         /**
322          * Check status of definite non-null assignment at a given position.
323          * It deals with the dual representation of the InitializationInfo2:
324          * bits for the first 64 entries, then an array of booleans.
325          */
326         final private boolean isDefinitelyNonNull(int position) {
327                 
328                 // Dependant of CodeStream.isDefinitelyAssigned(..)
329                 // id is zero-based
330                 if (position < BitCacheSize) {
331                         return (definiteNonNulls & (1L << position)) != 0; // use bits
332                 }
333                 // use extra vector
334                 if (extraDefiniteNonNulls == null)
335                         return false; // if vector not yet allocated, then not initialized
336                 int vectorIndex;
337                 if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteNonNulls.length)
338                         return false; // if not enough room in vector, then not initialized 
339                 return ((extraDefiniteNonNulls[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
340         }
341
342         /**
343          * Check status of definite null assignment at a given position.
344          * It deals with the dual representation of the InitializationInfo2:
345          * bits for the first 64 entries, then an array of booleans.
346          */
347         final private boolean isDefinitelyNull(int position) {
348                 
349                 // Dependant of CodeStream.isDefinitelyAssigned(..)
350                 // id is zero-based
351                 if (position < BitCacheSize) {
352                         return (definiteNulls & (1L << position)) != 0; // use bits
353                 }
354                 // use extra vector
355                 if (extraDefiniteNulls == null)
356                         return false; // if vector not yet allocated, then not initialized
357                 int vectorIndex;
358                 if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteNulls.length)
359                         return false; // if not enough room in vector, then not initialized 
360                 return ((extraDefiniteNulls[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
361         }
362
363         /**
364          * Check status of definite assignment for a field.
365          */
366         final public boolean isDefinitelyAssigned(FieldBinding field) {
367                 
368                 // Dependant of CodeStream.isDefinitelyAssigned(..)
369                 // We do not want to complain in unreachable code
370                 if ((this.reachMode & UNREACHABLE) != 0)  
371                         return true;
372                 return isDefinitelyAssigned(field.id); 
373         }
374         
375         /**
376          * Check status of definite assignment for a local.
377          */
378         final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
379                 
380                 // Dependant of CodeStream.isDefinitelyAssigned(..)
381                 // We do not want to complain in unreachable code
382                 if ((this.reachMode & UNREACHABLE) != 0)
383                         return true;
384
385                 // final constants are inlined, and thus considered as always initialized
386                 if (local.isConstantValue()) {
387                         return true;
388                 }
389                 return isDefinitelyAssigned(local.id + maxFieldCount);
390         }
391         
392         /**
393          * Check status of definite non-null assignment for a field.
394          */
395         final public boolean isDefinitelyNonNull(FieldBinding field) {
396                 
397                 // Dependant of CodeStream.isDefinitelyAssigned(..)
398                 // We do not want to complain in unreachable code
399                 if ((this.reachMode & UNREACHABLE) != 0)  
400                         return false;
401                 return isDefinitelyNonNull(field.id); 
402         }
403         
404         /**
405          * Check status of definite non-null assignment for a local.
406          */
407         final public boolean isDefinitelyNonNull(LocalVariableBinding local) {
408                 
409                 // Dependant of CodeStream.isDefinitelyAssigned(..)
410                 // We do not want to complain in unreachable code
411                 if ((this.reachMode & UNREACHABLE) != 0)
412                         return false;
413                 // final constants are inlined, and thus considered as always initialized
414                 if (local.isConstantValue()) {
415                         return true;
416                 }
417                 return isDefinitelyNonNull(local.id + maxFieldCount);
418         }
419
420         /**
421          * Check status of definite null assignment for a field.
422          */
423         final public boolean isDefinitelyNull(FieldBinding field) {
424                 
425                 // Dependant of CodeStream.isDefinitelyAssigned(..)
426                 // We do not want to complain in unreachable code
427                 if ((this.reachMode & UNREACHABLE) != 0)  
428                         return false;
429                 return isDefinitelyNull(field.id); 
430         }
431         
432         /**
433          * Check status of definite null assignment for a local.
434          */
435         final public boolean isDefinitelyNull(LocalVariableBinding local) {
436                 
437                 // Dependant of CodeStream.isDefinitelyAssigned(..)
438                 // We do not want to complain in unreachable code
439                 if ((this.reachMode & UNREACHABLE) != 0)
440                         return false;
441                 return isDefinitelyNull(local.id + maxFieldCount);
442         }
443
444         public boolean isReachable() {
445                 
446                 return this.reachMode == REACHABLE;
447         }
448         
449         /**
450          * Check status of potential assignment at a given position.
451          * It deals with the dual representation of the InitializationInfo3:
452          * bits for the first 64 entries, then an array of booleans.
453          */
454         final private boolean isPotentiallyAssigned(int position) {
455                 
456                 // id is zero-based
457                 if (position < BitCacheSize) {
458                         // use bits
459                         return (potentialInits & (1L << position)) != 0;
460                 }
461                 // use extra vector
462                 if (extraPotentialInits == null)
463                         return false; // if vector not yet allocated, then not initialized
464                 int vectorIndex;
465                 if ((vectorIndex = (position / BitCacheSize) - 1) >= extraPotentialInits.length)
466                         return false; // if not enough room in vector, then not initialized 
467                 return ((extraPotentialInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
468         }
469         
470         /**
471          * Check status of definite assignment for a field.
472          */
473         final public boolean isPotentiallyAssigned(FieldBinding field) {
474                 
475                 return isPotentiallyAssigned(field.id); 
476         }
477         
478         /**
479          * Check status of potential assignment for a local.
480          */
481         final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
482                 
483                 // final constants are inlined, and thus considered as always initialized
484                 if (local.isConstantValue()) {
485                         return true;
486                 }
487                 return isPotentiallyAssigned(local.id + maxFieldCount);
488         }
489         
490         /**
491          * Record a definite assignment at a given position.
492          * It deals with the dual representation of the InitializationInfo2:
493          * bits for the first 64 entries, then an array of booleans.
494          */
495         final private void markAsDefinitelyAssigned(int position) {
496                 
497                 if (this != DEAD_END) {
498         
499                         // position is zero-based
500                         if (position < BitCacheSize) {
501                                 // use bits
502                                 long mask;
503                                 definiteInits |= (mask = 1L << position);
504                                 potentialInits |= mask;
505                                 definiteNulls &= ~mask;
506                                 definiteNonNulls &= ~mask;
507                         } else {
508                                 // use extra vector
509                                 int vectorIndex = (position / BitCacheSize) - 1;
510                                 if (extraDefiniteInits == null) {
511                                         int length;
512                                         extraDefiniteInits = new long[length = vectorIndex + 1];
513                                         extraPotentialInits = new long[length];
514                                         extraDefiniteNulls = new long[length];
515                                         extraDefiniteNonNulls = new long[length];
516                                 } else {
517                                         int oldLength; // might need to grow the arrays
518                                         if (vectorIndex >= (oldLength = extraDefiniteInits.length)) {
519                                                 System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[vectorIndex + 1]), 0, oldLength);
520                                                 System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[vectorIndex + 1]), 0, oldLength);
521                                                 System.arraycopy(extraDefiniteNulls, 0, (extraDefiniteNulls = new long[vectorIndex + 1]), 0, oldLength);
522                                                 System.arraycopy(extraDefiniteNonNulls, 0, (extraDefiniteNonNulls = new long[vectorIndex + 1]), 0, oldLength);
523                                         }
524                                 }
525                                 long mask;
526                                 extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
527                                 extraPotentialInits[vectorIndex] |= mask;
528                                 extraDefiniteNulls[vectorIndex] &= ~mask;
529                                 extraDefiniteNonNulls[vectorIndex] &= ~mask;
530                         }
531                 }
532         }
533         
534         /**
535          * Record a field got definitely assigned.
536          */
537         public void markAsDefinitelyAssigned(FieldBinding field) {
538                 if (this != DEAD_END)
539                         markAsDefinitelyAssigned(field.id);
540         }
541         
542         /**
543          * Record a local got definitely assigned.
544          */
545         public void markAsDefinitelyAssigned(LocalVariableBinding local) {
546                 if (this != DEAD_END)
547                         markAsDefinitelyAssigned(local.id + maxFieldCount);
548         }
549
550         /**
551          * Record a definite non-null assignment at a given position.
552          * It deals with the dual representation of the InitializationInfo2:
553          * bits for the first 64 entries, then an array of booleans.
554          */
555         final private void markAsDefinitelyNonNull(int position) {
556                 
557                 if (this != DEAD_END) {
558         
559                         // position is zero-based
560                         if (position < BitCacheSize) {
561                                 // use bits
562                                 long mask;
563                                 definiteNonNulls |= (mask = 1L << position);
564                                 definiteNulls &= ~mask;
565                         } else {
566                                 // use extra vector
567                                 int vectorIndex = (position / BitCacheSize) - 1;
568                                 long mask;
569                                 extraDefiniteNonNulls[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
570                                 extraDefiniteNulls[vectorIndex] &= ~mask;
571                         }
572                 }
573         }
574
575         /**
576          * Record a field got definitely assigned to non-null value.
577          */
578         public void markAsDefinitelyNonNull(FieldBinding field) {
579                 if (this != DEAD_END)
580                         markAsDefinitelyNonNull(field.id);
581         }
582         
583         /**
584          * Record a local got definitely assigned to non-null value.
585          */
586         public void markAsDefinitelyNonNull(LocalVariableBinding local) {
587                 if (this != DEAD_END)
588                         markAsDefinitelyNonNull(local.id + maxFieldCount);
589         }
590
591         /**
592          * Record a definite null assignment at a given position.
593          * It deals with the dual representation of the InitializationInfo2:
594          * bits for the first 64 entries, then an array of booleans.
595          */
596         final private void markAsDefinitelyNull(int position) {
597                 
598                 if (this != DEAD_END) {
599         
600                         // position is zero-based
601                         if (position < BitCacheSize) {
602                                 // use bits
603                                 long mask;
604                                 definiteNulls |= (mask = 1L << position);
605                                 definiteNonNulls &= ~mask;
606                         } else {
607                                 // use extra vector
608                                 int vectorIndex = (position / BitCacheSize) - 1;
609                                 long mask;
610                                 extraDefiniteNulls[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
611                                 extraDefiniteNonNulls[vectorIndex] &= ~mask;
612                         }
613                 }
614         }
615
616         /**
617          * Record a field got definitely assigned to null.
618          */
619         public void markAsDefinitelyNull(FieldBinding field) {
620                 if (this != DEAD_END)
621                         markAsDefinitelyAssigned(field.id);
622         }
623         
624         /**
625          * Record a local got definitely assigned to null.
626          */
627         public void markAsDefinitelyNull(LocalVariableBinding local) {
628                 if (this != DEAD_END)
629                         markAsDefinitelyNull(local.id + maxFieldCount);
630         }
631         
632         /**
633          * Clear initialization information at a given position.
634          * It deals with the dual representation of the InitializationInfo2:
635          * bits for the first 64 entries, then an array of booleans.
636          */
637         final private void markAsDefinitelyNotAssigned(int position) {
638                 if (this != DEAD_END) {
639         
640                         // position is zero-based
641                         if (position < BitCacheSize) {
642                                 // use bits
643                                 long mask;
644                                 definiteInits &= ~(mask = 1L << position);
645                                 potentialInits &= ~mask;
646                                 definiteNulls &= ~mask;
647                                 definiteNonNulls &= ~mask;
648                         } else {
649                                 // use extra vector
650                                 int vectorIndex = (position / BitCacheSize) - 1;
651                                 if (extraDefiniteInits == null) {
652                                         return; // nothing to do, it was not yet set 
653                                 }
654                                 // might need to grow the arrays
655                                 if (vectorIndex >= extraDefiniteInits.length) {
656                                         return; // nothing to do, it was not yet set 
657                                 }
658                                 long mask;
659                                 extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize));
660                                 extraPotentialInits[vectorIndex] &= ~mask;
661                                 extraDefiniteNulls[vectorIndex] &= ~mask;
662                                 extraDefiniteNonNulls[vectorIndex] &= ~mask;
663                         }
664                 }
665         }
666         
667         /**
668          * Clear the initialization info for a field
669          */
670         public void markAsDefinitelyNotAssigned(FieldBinding field) {
671                 
672                 if (this != DEAD_END)
673                         markAsDefinitelyNotAssigned(field.id);
674         }
675         
676         /**
677          * Clear the initialization info for a local variable
678          */
679         
680         public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
681                 
682                 if (this != DEAD_END)
683                         markAsDefinitelyNotAssigned(local.id + maxFieldCount);
684         }
685                 
686         /**
687          * Returns the receiver updated in the following way: <ul>
688          * <li> intersection of definitely assigned variables, 
689          * <li> union of potentially assigned variables.
690          * </ul>
691          */
692         public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
693         
694                 if (this == DEAD_END) return otherInits;
695                 if (otherInits == DEAD_END) return this;
696         
697                 if ((this.reachMode & UNREACHABLE) != (otherInits.reachMode & UNREACHABLE)){
698                         if ((this.reachMode & UNREACHABLE) != 0){
699                                 return otherInits;
700                         } 
701                         return this;
702                 }
703                 
704                 // if one branch is not fake reachable, then the merged one is reachable
705                 this.reachMode &= otherInits.reachMode;
706         
707                 // intersection of definitely assigned variables, 
708                 this.definiteInits &= otherInits.definiteInits;
709                 // union of potentially set ones
710                 this.potentialInits |= otherInits.potentialInits;
711                 // intersection of definitely null variables, 
712                 this.definiteNulls &= otherInits.definiteNulls;
713                 // intersection of definitely non-null variables, 
714                 this.definiteNonNulls &= otherInits.definiteNonNulls;
715         
716                 // treating extra storage
717                 if (this.extraDefiniteInits != null) {
718                         if (otherInits.extraDefiniteInits != null) {
719                                 // both sides have extra storage
720                                 int i = 0, length, otherLength;
721                                 if ((length = this.extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
722                                         // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
723                                         System.arraycopy(this.extraDefiniteInits, 0, (this.extraDefiniteInits = new long[otherLength]), 0, length);
724                                         System.arraycopy(this.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, length);
725                                         System.arraycopy(this.extraDefiniteNulls, 0, (this.extraDefiniteNulls = new long[otherLength]), 0, length);
726                                         System.arraycopy(this.extraDefiniteNonNulls, 0, (this.extraDefiniteNonNulls = new long[otherLength]), 0, length);
727                                         while (i < length) {
728                                                 this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
729                                                 this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
730                                                 this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i];
731                                                 this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++];
732                                         }
733                                         while (i < otherLength) {
734                                                 this.extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
735                                         }
736                                 } else {
737                                         // current storage is longer
738                                         while (i < otherLength) {
739                                                 this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
740                                                 this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
741                                                 this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i];
742                                                 this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++];
743                                         }
744                                         while (i < length) {
745                                                 this.extraDefiniteInits[i] = 0;
746                                                 this.extraDefiniteNulls[i] = 0;
747                                                 this.extraDefiniteNonNulls[i++] = 0;
748                                         }
749                                 }
750                         } else {
751                                 // no extra storage on otherInits
752                                 int i = 0, length = this.extraDefiniteInits.length;
753                                 while (i < length) {
754                                         this.extraDefiniteInits[i] = 0;
755                                         this.extraDefiniteNulls[i] = 0;
756                                         this.extraDefiniteNonNulls[i++] = 0;
757                                 }
758                         }
759                 } else
760                         if (otherInits.extraDefiniteInits != null) {
761                                 // no storage here, but other has extra storage.
762                                 int otherLength;
763                                 this.extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
764                                 System.arraycopy(otherInits.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, otherLength);
765                                 this.extraDefiniteNulls = new long[otherLength];
766                                 this.extraDefiniteNonNulls = new long[otherLength];
767                         }
768                 return this;
769         }
770         
771         /*
772          * Answer the total number of fields in enclosing types of a given type
773          */
774         static int numberOfEnclosingFields(ReferenceBinding type){
775                 
776                 int count = 0;
777                 type = type.enclosingType();
778                 while(type != null) {
779                         count += type.fieldCount();
780                         type = type.enclosingType();
781                 }
782                 return count;
783         }
784         
785         public int reachMode(){
786                 return this.reachMode;
787         }
788         
789         public FlowInfo setReachMode(int reachMode) {
790                 
791                 if (this == DEAD_END) return this; // cannot modify DEAD_END
792         
793                 // reset optional inits when becoming unreachable
794                 if ((this.reachMode & UNREACHABLE) == 0 && (reachMode & UNREACHABLE) != 0) {
795                         this.potentialInits = 0;
796                         if (this.extraPotentialInits != null){
797                                 for (int i = 0, length = this.extraPotentialInits.length; i < length; i++){
798                                         this.extraPotentialInits[i] = 0;
799                                 }
800                         }
801                 }                               
802                 this.reachMode = reachMode;
803         
804                 return this;
805         }
806
807         public String toString(){
808                 
809                 if (this == DEAD_END){
810                         return "FlowInfo.DEAD_END"; //$NON-NLS-1$
811                 }
812                 return "FlowInfo<def: "+ this.definiteInits //$NON-NLS-1$
813                         +", pot: " + this.potentialInits  //$NON-NLS-1$
814                         + ", reachable:" + ((this.reachMode & UNREACHABLE) == 0) //$NON-NLS-1$
815                         +", defNull: " + this.definiteNulls  //$NON-NLS-1$
816                         +", defNonNull: " + this.definiteNonNulls  //$NON-NLS-1$
817                         +">"; //$NON-NLS-1$
818         }
819         
820         public UnconditionalFlowInfo unconditionalInits() {
821                 
822                 // also see conditional inits, where it requests them to merge
823                 return this;
824         }
825 }