intial version
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / flow / UnconditionalFlowInfo.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.flow;
12
13 import net.sourceforge.phpdt.internal.compiler.ast.AstNode;
14 import net.sourceforge.phpdt.internal.compiler.ast.Statement;
15 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
16 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
17 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
18 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
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         public long definiteInits;
27         long potentialInits;
28         public long extraDefiniteInits[];
29         long extraPotentialInits[];
30         public boolean isFakeReachable;
31         public int maxFieldCount;
32         
33         // Constants
34         public static final int BitCacheSize = 64; // 64 bits in a long.
35 UnconditionalFlowInfo() {
36 }
37 public UnconditionalFlowInfo addInitializationsFrom(UnconditionalFlowInfo otherInits) {
38
39         // unions of both sets of initialization - used for try/finally
40         if (this == DeadEnd)
41                 return this;
42         if (otherInits == DeadEnd)
43                 return this;
44                 
45         // union of definitely assigned variables, 
46         definiteInits |= otherInits.definiteInits;
47         // union of potentially set ones
48         potentialInits |= otherInits.potentialInits;
49
50         // treating extra storage
51         if (extraDefiniteInits != null) {
52                 if (otherInits.extraDefiniteInits != null) {
53                         // both sides have extra storage
54                         int i = 0, length, otherLength;
55                         if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
56                                 // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
57                                 System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
58                                 System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
59                                 while (i < length) {
60                                         extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
61                                         extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
62                                 }
63                                 while (i < otherLength) {
64                                         extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
65                                 }
66                         } else {
67                                 // current storage is longer
68                                 while (i < otherLength) {
69                                         extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
70                                         extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
71                                 }
72                                 while (i < length)
73                                         extraDefiniteInits[i++] = 0;
74                         }
75                 } else {
76                         // no extra storage on otherInits
77                 }
78         } else
79                 if (otherInits.extraDefiniteInits != null) {
80                         // no storage here, but other has extra storage.
81                         int otherLength;
82                         System.arraycopy(otherInits.extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]), 0, otherLength);                        
83                         System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
84                 }
85         return this;
86 }
87 public UnconditionalFlowInfo addPotentialInitializationsFrom(UnconditionalFlowInfo otherInits) {
88
89         // unions of both sets of initialization - used for try/finally
90         if (this == DeadEnd){
91                 return this;
92         }
93         if (otherInits == DeadEnd){
94                 return this;
95         }
96         // union of potentially set ones
97         potentialInits |= otherInits.potentialInits;
98
99         // treating extra storage
100         if (extraDefiniteInits != null) {
101                 if (otherInits.extraDefiniteInits != null) {
102                         // both sides have extra storage
103                         int i = 0, length, otherLength;
104                         if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
105                                 // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
106                                 System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
107                                 System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
108                                 while (i < length) {
109                                         extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
110                                 }
111                                 while (i < otherLength) {
112                                         extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
113                                 }
114                         } else {
115                                 // current storage is longer
116                                 while (i < otherLength) {
117                                         extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
118                                 }
119                         }
120                 }
121         } else
122                 if (otherInits.extraDefiniteInits != null) {
123                         // no storage here, but other has extra storage.
124                         int otherLength;
125                         extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];                      
126                         System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
127                 }
128         return this;
129 }
130 public boolean complainIfUnreachable(Statement statement, BlockScope scope) {
131         // Report an error if necessary
132
133         boolean isDeadEnd;
134         if ((isDeadEnd = (this == DeadEnd)) || isFakeReachable) {
135                 statement.bits &= ~AstNode.IsReachableMASK;
136                 /* EXTRA REFERENCE RECORDING
137                 statement.recordUnreachableReferences(scope.referenceType()); // scopes cannot have an enclosingMethod slot since there are class scopes
138                 */
139                 if (isDeadEnd)
140                         scope.problemReporter().unreachableCode(statement);
141                 return isDeadEnd;
142         }
143         return false;
144 }
145 /**
146  * Answers a copy of the current instance
147  */
148 public FlowInfo copy() {
149         // do not clone the DeadEnd
150         if (this == DeadEnd)
151                 return this;
152
153         // look for an unused preallocated object
154         UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
155
156         // copy slots
157         copy.definiteInits = definiteInits;
158         copy.potentialInits = potentialInits;
159         copy.isFakeReachable = isFakeReachable;
160         copy.maxFieldCount = maxFieldCount;
161         
162         if (extraDefiniteInits != null) {
163                 int length;
164                 System.arraycopy(extraDefiniteInits, 0, (copy.extraDefiniteInits = new long[ (length = extraDefiniteInits.length)]), 0, length);
165                 System.arraycopy(extraPotentialInits, 0, (copy.extraPotentialInits = new long[length]), 0, length);
166         };
167         return copy;
168 }
169 public FlowInfo initsWhenFalse() {
170         return this;
171 }
172 public FlowInfo initsWhenTrue() {
173         return this;
174 }
175 /**
176  * Check status of definite assignment at a given position.
177  * It deals with the dual representation of the InitializationInfo2:
178  * bits for the first 64 entries, then an array of booleans.
179  */
180 final private boolean isDefinitelyAssigned(int position) {
181         // Dependant of CodeStream.isDefinitelyAssigned(..)
182         // id is zero-based
183         if (position < BitCacheSize) {
184                 return (definiteInits & (1L << position)) != 0; // use bits
185         }
186         // use extra vector
187         if (extraDefiniteInits == null)
188                 return false; // if vector not yet allocated, then not initialized
189         int vectorIndex;
190         if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteInits.length)
191                 return false; // if not enough room in vector, then not initialized 
192         return ((extraDefiniteInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
193 }
194 /**
195  * Check status of definite assignment for a field.
196  */
197 final public boolean isDefinitelyAssigned(FieldBinding field) {
198         // Dependant of CodeStream.isDefinitelyAssigned(..)
199         // We do not want to complain in unreachable code
200         if ((this == DeadEnd) || (this.isFakeReachable))
201                 return true;
202         return isDefinitelyAssigned(field.id); 
203 }
204 /**
205  * Check status of definite assignment for a local.
206  */
207 final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
208         // Dependant of CodeStream.isDefinitelyAssigned(..)
209         // We do not want to complain in unreachable code
210         if ((this == DeadEnd) || (this.isFakeReachable))
211                 return true;
212         if (local.isArgument) {
213                 return true;
214         }
215         return isDefinitelyAssigned(local.id + maxFieldCount);
216 }
217 public boolean isFakeReachable() {
218         return isFakeReachable;
219 }
220 /**
221  * Check status of potential assignment at a given position.
222  * It deals with the dual representation of the InitializationInfo3:
223  * bits for the first 64 entries, then an array of booleans.
224  */
225 final private boolean isPotentiallyAssigned(int position) {
226         // id is zero-based
227         if (position < BitCacheSize) {
228                 // use bits
229                 return (potentialInits & (1L << position)) != 0;
230         }
231         // use extra vector
232         if (extraPotentialInits == null)
233                 return false; // if vector not yet allocated, then not initialized
234         int vectorIndex;
235         if ((vectorIndex = (position / BitCacheSize) - 1) >= extraPotentialInits.length)
236                 return false; // if not enough room in vector, then not initialized 
237         return ((extraPotentialInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
238 }
239 /**
240  * Check status of definite assignment for a field.
241  */
242 final public boolean isPotentiallyAssigned(FieldBinding field) {
243         // We do not want to complain in unreachable code
244         if ((this == DeadEnd) || (this.isFakeReachable))
245                 return false;
246         return isPotentiallyAssigned(field.id); 
247 }
248 /**
249  * Check status of potential assignment for a local.
250  */
251 final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
252         // We do not want to complain in unreachable code
253         if ((this == DeadEnd) || (this.isFakeReachable))
254                 return false;
255         if (local.isArgument) {
256                 return true;
257         }
258         return isPotentiallyAssigned(local.id + maxFieldCount);
259 }
260 /**
261  * Record a definite assignment at a given position.
262  * It deals with the dual representation of the InitializationInfo2:
263  * bits for the first 64 entries, then an array of booleans.
264  */
265 final private void markAsDefinitelyAssigned(int position) {
266         if (this != DeadEnd) {
267
268                 // position is zero-based
269                 if (position < BitCacheSize) {
270                         // use bits
271                         long mask;
272                         definiteInits |= (mask = 1L << position);
273                         potentialInits |= mask;
274                 } else {
275                         // use extra vector
276                         int vectorIndex = (position / BitCacheSize) - 1;
277                         if (extraDefiniteInits == null) {
278                                 int length;
279                                 extraDefiniteInits = new long[length = vectorIndex + 1];
280                                 extraPotentialInits = new long[length];
281                         } else {
282                                 int oldLength; // might need to grow the arrays
283                                 if (vectorIndex >= (oldLength = extraDefiniteInits.length)) {
284                                         System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[vectorIndex + 1]), 0, oldLength);
285                                         System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[vectorIndex + 1]), 0, oldLength);
286                                 }
287                         }
288                         long mask;
289                         extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
290                         extraPotentialInits[vectorIndex] |= mask;
291                 }
292         }
293 }
294 /**
295  * Record a field got definitely assigned.
296  */
297 public void markAsDefinitelyAssigned(FieldBinding field) {
298         if (this != DeadEnd)
299                 markAsDefinitelyAssigned(field.id);
300 }
301 /**
302  * Record a local got definitely assigned.
303  */
304 public void markAsDefinitelyAssigned(LocalVariableBinding local) {
305         if (this != DeadEnd)
306                 markAsDefinitelyAssigned(local.id + maxFieldCount);
307 }
308 /**
309  * Clear initialization information at a given position.
310  * It deals with the dual representation of the InitializationInfo2:
311  * bits for the first 64 entries, then an array of booleans.
312  */
313 final private void markAsDefinitelyNotAssigned(int position) {
314         if (this != DeadEnd) {
315
316                 // position is zero-based
317                 if (position < BitCacheSize) {
318                         // use bits
319                         long mask;
320                         definiteInits &= ~(mask = 1L << position);
321                         potentialInits &= ~mask;
322                 } else {
323                         // use extra vector
324                         int vectorIndex = (position / BitCacheSize) - 1;
325                         if (extraDefiniteInits == null) {
326                                 return; // nothing to do, it was not yet set 
327                         } else {
328                                 // might need to grow the arrays
329                                 if (vectorIndex >= extraDefiniteInits.length) {
330                                         return; // nothing to do, it was not yet set 
331                                 }
332                         }
333                         long mask;
334                         extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize));
335                         extraPotentialInits[vectorIndex] &= ~mask;
336                 }
337         }
338 }
339 /**
340  * Clear the initialization info for a field
341  */
342 public void markAsDefinitelyNotAssigned(FieldBinding field) {
343         if (this != DeadEnd)
344                 markAsDefinitelyNotAssigned(field.id);
345 }
346 /**
347  * Clear the initialization info for a local variable
348  */
349
350 public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
351         if (this != DeadEnd)
352                 markAsDefinitelyNotAssigned(local.id + maxFieldCount);
353 }
354 public FlowInfo markAsFakeReachable(boolean isFakeReachable) {
355         this.isFakeReachable = isFakeReachable;
356         return this;
357 }
358 public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
359         // updates the receiver with:
360         // - intersection of definitely assigned variables, 
361         // - union of potentially set ones
362
363         if (this == DeadEnd)
364                 return otherInits;
365         if (otherInits == DeadEnd)
366                 return this;
367
368         // if one branch is not fake reachable, then the merged one is reachable
369         if (!otherInits.isFakeReachable())
370                 markAsFakeReachable(false);
371
372         // intersection of definitely assigned variables, 
373         definiteInits &= otherInits.definiteInits;
374         // union of potentially set ones
375         potentialInits |= otherInits.potentialInits;
376
377         // treating extra storage
378         if (extraDefiniteInits != null) {
379                 if (otherInits.extraDefiniteInits != null) {
380                         // both sides have extra storage
381                         int i = 0, length, otherLength;
382                         if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
383                                 // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
384                                 System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
385                                 System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
386                                 while (i < length) {
387                                         extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
388                                         extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
389                                 }
390                                 while (i < otherLength) {
391                                         extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
392                                 }
393                         } else {
394                                 // current storage is longer
395                                 while (i < otherLength) {
396                                         extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
397                                         extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
398                                 }
399                                 while (i < length)
400                                         extraDefiniteInits[i++] = 0;
401                         }
402                 } else {
403                         // no extra storage on otherInits
404                         int i = 0, length = extraDefiniteInits.length;
405                         while (i < length)
406                                 extraDefiniteInits[i++] = 0;
407                 }
408         } else
409                 if (otherInits.extraDefiniteInits != null) {
410                         // no storage here, but other has extra storage.
411                         int otherLength;
412                         extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
413                         System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
414                 }
415         return this;
416 }
417 /*
418  * Answer the total number of fields in enclosing types of a given type
419  */
420 static int numberOfEnclosingFields(ReferenceBinding type){
421         int count = 0;
422         type = type.enclosingType();
423         while(type != null) {
424                 count += type.fieldCount();
425                 type = type.enclosingType();
426         }
427         return count;
428 }
429 public String toString(){
430         if (this == DeadEnd){
431                 return "FlowInfo.DeadEnd"; //$NON-NLS-1$
432         }
433         return "FlowInfo<def: "+ definiteInits +", pot: " + potentialInits + ">"; //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$
434 }
435 public UnconditionalFlowInfo unconditionalInits() {
436         // also see conditional inits, where it requests them to merge
437         return this;
438 }
439 }