Makefile fixup
[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.impl.Constant;
14 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
15 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
16 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
17
18 /**
19  * Record initialization status during definite assignment analysis
20  *
21  * No caching of pre-allocated instances.
22  */
23 public class UnconditionalFlowInfo extends FlowInfo {
24
25         
26         public long definiteInits;
27         public long potentialInits;
28         public long extraDefiniteInits[];
29         public long extraPotentialInits[];
30         
31         public int reachMode; // by default
32
33         public int maxFieldCount;
34         
35         // Constants
36         public static final int BitCacheSize = 64; // 64 bits in a long.
37
38         UnconditionalFlowInfo() {
39                 this.reachMode = REACHABLE;
40         }
41
42         // unions of both sets of initialization - used for try/finally
43         public FlowInfo addInitializationsFrom(FlowInfo inits) {
44
45                 if (this == DEAD_END)
46                         return this;
47
48                 UnconditionalFlowInfo otherInits = inits.unconditionalInits();  
49                 if (otherInits == DEAD_END)
50                         return this;
51                         
52                 // union of definitely assigned variables, 
53                 definiteInits |= otherInits.definiteInits;
54                 // union of potentially set ones
55                 potentialInits |= otherInits.potentialInits;
56         
57                 // treating extra storage
58                 if (extraDefiniteInits != null) {
59                         if (otherInits.extraDefiniteInits != null) {
60                                 // both sides have extra storage
61                                 int i = 0, length, otherLength;
62                                 if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
63                                         // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
64                                         System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
65                                         System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
66                                         while (i < length) {
67                                                 extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
68                                                 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
69                                         }
70                                         while (i < otherLength) {
71                                                 extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
72                                         }
73                                 } else {
74                                         // current storage is longer
75                                         while (i < otherLength) {
76                                                 extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
77                                                 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
78                                         }
79                                         while (i < length)
80                                                 extraDefiniteInits[i++] = 0;
81                                 }
82                         } else {
83                                 // no extra storage on otherInits
84                         }
85                 } else
86                         if (otherInits.extraDefiniteInits != null) {
87                                 // no storage here, but other has extra storage.
88                                 int otherLength;
89                                 System.arraycopy(otherInits.extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]), 0, otherLength);                        
90                                 System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
91                         }
92                 return this;
93         }
94
95         // unions of both sets of initialization - used for try/finally
96         public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) {
97         
98                 if (this == DEAD_END){
99                         return this;
100                 }
101
102                 UnconditionalFlowInfo otherInits = inits.unconditionalInits();
103                 if (otherInits == DEAD_END){
104                         return this;
105                 }
106                 // union of potentially set ones
107                 potentialInits |= otherInits.potentialInits;
108         
109                 // treating extra storage
110                 if (extraDefiniteInits != null) {
111                         if (otherInits.extraDefiniteInits != null) {
112                                 // both sides have extra storage
113                                 int i = 0, length, otherLength;
114                                 if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
115                                         // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
116                                         System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
117                                         System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
118                                         while (i < length) {
119                                                 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
120                                         }
121                                         while (i < otherLength) {
122                                                 extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
123                                         }
124                                 } else {
125                                         // current storage is longer
126                                         while (i < otherLength) {
127                                                 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
128                                         }
129                                 }
130                         }
131                 } else
132                         if (otherInits.extraDefiniteInits != null) {
133                                 // no storage here, but other has extra storage.
134                                 int otherLength;
135                                 extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];                      
136                                 System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
137                         }
138                 return this;
139         }
140
141         /**
142          * Answers a copy of the current instance
143          */
144         public FlowInfo copy() {
145                 
146                 // do not clone the DeadEnd
147                 if (this == DEAD_END)
148                         return this;
149         
150                 // look for an unused preallocated object
151                 UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
152         
153                 // copy slots
154                 copy.definiteInits = this.definiteInits;
155                 copy.potentialInits = this.potentialInits;
156                 copy.reachMode = this.reachMode;
157                 copy.maxFieldCount = this.maxFieldCount;
158                 
159                 if (this.extraDefiniteInits != null) {
160                         int length;
161                         System.arraycopy(this.extraDefiniteInits, 0, (copy.extraDefiniteInits = new long[ (length = extraDefiniteInits.length)]), 0, length);
162                         System.arraycopy(this.extraPotentialInits, 0, (copy.extraPotentialInits = new long[length]), 0, length);
163                 }
164                 return copy;
165         }
166         
167         public UnconditionalFlowInfo discardFieldInitializations(){
168                 
169                 int limit = this.maxFieldCount;
170                 
171                 if (limit < BitCacheSize) {
172                         long mask = (1L << limit)-1;
173                         this.definiteInits &= ~mask;
174                         this.potentialInits &= ~mask;
175                         return this;
176                 } 
177
178                 this.definiteInits = 0;
179                 this.potentialInits = 0;
180
181                 // use extra vector
182                 if (extraDefiniteInits == null) {
183                         return this; // if vector not yet allocated, then not initialized
184                 }
185                 int vectorIndex, length = this.extraDefiniteInits.length;
186                 if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
187                         return this; // not enough room yet
188                 }
189                 for (int i = 0; i < vectorIndex; i++) {
190                         this.extraDefiniteInits[i] = 0L;
191                         this.extraPotentialInits[i] = 0L;
192                 }
193                 long mask = (1L << (limit % BitCacheSize))-1;
194                 this.extraDefiniteInits[vectorIndex] &= ~mask;
195                 this.extraPotentialInits[vectorIndex] &= ~mask;
196                 return this;
197         }
198
199         public UnconditionalFlowInfo discardNonFieldInitializations(){
200                 
201                 int limit = this.maxFieldCount;
202                 
203                 if (limit < BitCacheSize) {
204                         long mask = (1L << limit)-1;
205                         this.definiteInits &= mask;
206                         this.potentialInits &= mask;
207                         return this;
208                 } 
209                 // use extra vector
210                 if (extraDefiniteInits == null) {
211                         return this; // if vector not yet allocated, then not initialized
212                 }
213                 int vectorIndex, length = this.extraDefiniteInits.length;
214                 if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
215                         return this; // not enough room yet
216                 }
217                 long mask = (1L << (limit % BitCacheSize))-1;
218                 this.extraDefiniteInits[vectorIndex] &= mask;
219                 this.extraPotentialInits[vectorIndex] &= mask;
220                 for (int i = vectorIndex+1; i < length; i++) {
221                         this.extraDefiniteInits[i] = 0L;
222                         this.extraPotentialInits[i] = 0L;
223                 }
224                 return this;
225         }
226         
227         public FlowInfo initsWhenFalse() {
228                 
229                 return this;
230         }
231         
232         public FlowInfo initsWhenTrue() {
233                 
234                 return this;
235         }
236         
237         /**
238          * Check status of definite assignment at a given position.
239          * It deals with the dual representation of the InitializationInfo2:
240          * bits for the first 64 entries, then an array of booleans.
241          */
242         final private boolean isDefinitelyAssigned(int position) {
243                 
244                 // Dependant of CodeStream.isDefinitelyAssigned(..)
245                 // id is zero-based
246                 if (position < BitCacheSize) {
247                         return (definiteInits & (1L << position)) != 0; // use bits
248                 }
249                 // use extra vector
250                 if (extraDefiniteInits == null)
251                         return false; // if vector not yet allocated, then not initialized
252                 int vectorIndex;
253                 if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteInits.length)
254                         return false; // if not enough room in vector, then not initialized 
255                 return ((extraDefiniteInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
256         }
257         
258         /**
259          * Check status of definite assignment for a field.
260          */
261         final public boolean isDefinitelyAssigned(FieldBinding field) {
262                 
263                 // Dependant of CodeStream.isDefinitelyAssigned(..)
264                 // We do not want to complain in unreachable code
265                 if ((this.reachMode & UNREACHABLE) != 0)  
266                         return true;
267                 return isDefinitelyAssigned(field.id); 
268         }
269         
270         /**
271          * Check status of definite assignment for a local.
272          */
273         final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
274                 
275                 // Dependant of CodeStream.isDefinitelyAssigned(..)
276                 // We do not want to complain in unreachable code
277                 if ((this.reachMode & UNREACHABLE) != 0)
278                         return true;
279                 if (local.isArgument) {
280                         return true;
281                 }
282                 // final constants are inlined, and thus considered as always initialized
283                 if (local.constant != Constant.NotAConstant) {
284                         return true;
285                 }
286                 return isDefinitelyAssigned(local.id + maxFieldCount);
287         }
288         
289         public boolean isReachable() {
290                 
291                 return this.reachMode == REACHABLE;
292         }
293         
294         /**
295          * Check status of potential assignment at a given position.
296          * It deals with the dual representation of the InitializationInfo3:
297          * bits for the first 64 entries, then an array of booleans.
298          */
299         final private boolean isPotentiallyAssigned(int position) {
300                 
301                 // id is zero-based
302                 if (position < BitCacheSize) {
303                         // use bits
304                         return (potentialInits & (1L << position)) != 0;
305                 }
306                 // use extra vector
307                 if (extraPotentialInits == null)
308                         return false; // if vector not yet allocated, then not initialized
309                 int vectorIndex;
310                 if ((vectorIndex = (position / BitCacheSize) - 1) >= extraPotentialInits.length)
311                         return false; // if not enough room in vector, then not initialized 
312                 return ((extraPotentialInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
313         }
314         
315         /**
316          * Check status of definite assignment for a field.
317          */
318         final public boolean isPotentiallyAssigned(FieldBinding field) {
319                 
320                 return isPotentiallyAssigned(field.id); 
321         }
322         
323         /**
324          * Check status of potential assignment for a local.
325          */
326         final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
327                 
328                 if (local.isArgument) {
329                         return true;
330                 }
331                 // final constants are inlined, and thus considered as always initialized
332                 if (local.constant != Constant.NotAConstant) {
333                         return true;
334                 }
335                 return isPotentiallyAssigned(local.id + maxFieldCount);
336         }
337         
338         /**
339          * Record a definite assignment at a given position.
340          * It deals with the dual representation of the InitializationInfo2:
341          * bits for the first 64 entries, then an array of booleans.
342          */
343         final private void markAsDefinitelyAssigned(int position) {
344                 
345                 if (this != DEAD_END) {
346         
347                         // position is zero-based
348                         if (position < BitCacheSize) {
349                                 // use bits
350                                 long mask;
351                                 definiteInits |= (mask = 1L << position);
352                                 potentialInits |= mask;
353                         } else {
354                                 // use extra vector
355                                 int vectorIndex = (position / BitCacheSize) - 1;
356                                 if (extraDefiniteInits == null) {
357                                         int length;
358                                         extraDefiniteInits = new long[length = vectorIndex + 1];
359                                         extraPotentialInits = new long[length];
360                                 } else {
361                                         int oldLength; // might need to grow the arrays
362                                         if (vectorIndex >= (oldLength = extraDefiniteInits.length)) {
363                                                 System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[vectorIndex + 1]), 0, oldLength);
364                                                 System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[vectorIndex + 1]), 0, oldLength);
365                                         }
366                                 }
367                                 long mask;
368                                 extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
369                                 extraPotentialInits[vectorIndex] |= mask;
370                         }
371                 }
372         }
373         
374         /**
375          * Record a field got definitely assigned.
376          */
377         public void markAsDefinitelyAssigned(FieldBinding field) {
378                 if (this != DEAD_END)
379                         markAsDefinitelyAssigned(field.id);
380         }
381         
382         /**
383          * Record a local got definitely assigned.
384          */
385         public void markAsDefinitelyAssigned(LocalVariableBinding local) {
386                 if (this != DEAD_END)
387                         markAsDefinitelyAssigned(local.id + maxFieldCount);
388         }
389         
390         /**
391          * Clear initialization information at a given position.
392          * It deals with the dual representation of the InitializationInfo2:
393          * bits for the first 64 entries, then an array of booleans.
394          */
395         final private void markAsDefinitelyNotAssigned(int position) {
396                 if (this != DEAD_END) {
397         
398                         // position is zero-based
399                         if (position < BitCacheSize) {
400                                 // use bits
401                                 long mask;
402                                 definiteInits &= ~(mask = 1L << position);
403                                 potentialInits &= ~mask;
404                         } else {
405                                 // use extra vector
406                                 int vectorIndex = (position / BitCacheSize) - 1;
407                                 if (extraDefiniteInits == null) {
408                                         return; // nothing to do, it was not yet set 
409                                 }
410                                 // might need to grow the arrays
411                                 if (vectorIndex >= extraDefiniteInits.length) {
412                                         return; // nothing to do, it was not yet set 
413                                 }
414                                 long mask;
415                                 extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize));
416                                 extraPotentialInits[vectorIndex] &= ~mask;
417                         }
418                 }
419         }
420         
421         /**
422          * Clear the initialization info for a field
423          */
424         public void markAsDefinitelyNotAssigned(FieldBinding field) {
425                 
426                 if (this != DEAD_END)
427                         markAsDefinitelyNotAssigned(field.id);
428         }
429         
430         /**
431          * Clear the initialization info for a local variable
432          */
433         
434         public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
435                 
436                 if (this != DEAD_END)
437                         markAsDefinitelyNotAssigned(local.id + maxFieldCount);
438         }
439                 
440         /**
441          * Returns the receiver updated in the following way: <ul>
442          * <li> intersection of definitely assigned variables, 
443          * <li> union of potentially assigned variables.
444          * </ul>
445          */
446         public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
447         
448                 if (this == DEAD_END) return otherInits;
449                 if (otherInits == DEAD_END) return this;
450         
451                 if ((this.reachMode & UNREACHABLE) != (otherInits.reachMode & UNREACHABLE)){
452                         if ((this.reachMode & UNREACHABLE) != 0){
453                                 return otherInits;
454                         } 
455                         return this;
456                 }
457                 
458                 // if one branch is not fake reachable, then the merged one is reachable
459                 this.reachMode &= otherInits.reachMode;
460         
461                 // intersection of definitely assigned variables, 
462                 this.definiteInits &= otherInits.definiteInits;
463                 // union of potentially set ones
464                 this.potentialInits |= otherInits.potentialInits;
465         
466                 // treating extra storage
467                 if (this.extraDefiniteInits != null) {
468                         if (otherInits.extraDefiniteInits != null) {
469                                 // both sides have extra storage
470                                 int i = 0, length, otherLength;
471                                 if ((length = this.extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
472                                         // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
473                                         System.arraycopy(this.extraDefiniteInits, 0, (this.extraDefiniteInits = new long[otherLength]), 0, length);
474                                         System.arraycopy(this.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, length);
475                                         while (i < length) {
476                                                 this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
477                                                 this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
478                                         }
479                                         while (i < otherLength) {
480                                                 this.extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
481                                         }
482                                 } else {
483                                         // current storage is longer
484                                         while (i < otherLength) {
485                                                 this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
486                                                 this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
487                                         }
488                                         while (i < length)
489                                                 this.extraDefiniteInits[i++] = 0;
490                                 }
491                         } else {
492                                 // no extra storage on otherInits
493                                 int i = 0, length = this.extraDefiniteInits.length;
494                                 while (i < length)
495                                         this.extraDefiniteInits[i++] = 0;
496                         }
497                 } else
498                         if (otherInits.extraDefiniteInits != null) {
499                                 // no storage here, but other has extra storage.
500                                 int otherLength;
501                                 this.extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
502                                 System.arraycopy(otherInits.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, otherLength);
503                         }
504                 return this;
505         }
506         
507         /*
508          * Answer the total number of fields in enclosing types of a given type
509          */
510         static int numberOfEnclosingFields(ReferenceBinding type){
511                 
512                 int count = 0;
513                 type = type.enclosingType();
514                 while(type != null) {
515                         count += type.fieldCount();
516                         type = type.enclosingType();
517                 }
518                 return count;
519         }
520         
521         public int reachMode(){
522                 return this.reachMode;
523         }
524         
525         public FlowInfo setReachMode(int reachMode) {
526                 
527                 if (this == DEAD_END) return this; // cannot modify DEAD_END
528         
529                 // reset optional inits when becoming unreachable
530                 if ((this.reachMode & UNREACHABLE) == 0 && (reachMode & UNREACHABLE) != 0) {
531                         this.potentialInits = 0;
532                         if (this.extraPotentialInits != null){
533                                 for (int i = 0, length = this.extraPotentialInits.length; i < length; i++){
534                                         this.extraPotentialInits[i] = 0;
535                                 }
536                         }
537                 }                               
538                 this.reachMode = reachMode;
539         
540                 return this;
541         }
542
543         public String toString(){
544                 
545                 if (this == DEAD_END){
546                         return "FlowInfo.DEAD_END"; //$NON-NLS-1$
547                 }
548                 return "FlowInfo<def: "+ this.definiteInits //$NON-NLS-1$
549                         +", pot: " + this.potentialInits  //$NON-NLS-1$
550                         + ", reachable:" + ((this.reachMode & UNREACHABLE) == 0) //$NON-NLS-1$
551                         +">"; //$NON-NLS-1$
552         }
553         
554         public UnconditionalFlowInfo unconditionalInits() {
555                 
556                 // also see conditional inits, where it requests them to merge
557                 return this;
558         }
559 }