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
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.flow;
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;
21 * Record initialization status during definite assignment analysis
23 * No caching of pre-allocated instances.
25 public class UnconditionalFlowInfo extends FlowInfo {
26 public long definiteInits;
28 public long extraDefiniteInits[];
29 long extraPotentialInits[];
30 public boolean isFakeReachable;
31 public int maxFieldCount;
34 public static final int BitCacheSize = 64; // 64 bits in a long.
35 UnconditionalFlowInfo() {
37 public UnconditionalFlowInfo addInitializationsFrom(UnconditionalFlowInfo otherInits) {
39 // unions of both sets of initialization - used for try/finally
42 if (otherInits == DeadEnd)
45 // union of definitely assigned variables,
46 definiteInits |= otherInits.definiteInits;
47 // union of potentially set ones
48 potentialInits |= otherInits.potentialInits;
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);
60 extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
61 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
63 while (i < otherLength) {
64 extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
67 // current storage is longer
68 while (i < otherLength) {
69 extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
70 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
73 extraDefiniteInits[i++] = 0;
76 // no extra storage on otherInits
79 if (otherInits.extraDefiniteInits != null) {
80 // no storage here, but other has extra storage.
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);
87 public UnconditionalFlowInfo addPotentialInitializationsFrom(UnconditionalFlowInfo otherInits) {
89 // unions of both sets of initialization - used for try/finally
93 if (otherInits == DeadEnd){
96 // union of potentially set ones
97 potentialInits |= otherInits.potentialInits;
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);
109 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
111 while (i < otherLength) {
112 extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
115 // current storage is longer
116 while (i < otherLength) {
117 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
122 if (otherInits.extraDefiniteInits != null) {
123 // no storage here, but other has extra storage.
125 extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
126 System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
130 public boolean complainIfUnreachable(Statement statement, BlockScope scope) {
131 // Report an error if necessary
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
140 scope.problemReporter().unreachableCode(statement);
146 * Answers a copy of the current instance
148 public FlowInfo copy() {
149 // do not clone the DeadEnd
153 // look for an unused preallocated object
154 UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
157 copy.definiteInits = definiteInits;
158 copy.potentialInits = potentialInits;
159 copy.isFakeReachable = isFakeReachable;
160 copy.maxFieldCount = maxFieldCount;
162 if (extraDefiniteInits != null) {
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);
169 public FlowInfo initsWhenFalse() {
172 public FlowInfo initsWhenTrue() {
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.
180 final private boolean isDefinitelyAssigned(int position) {
181 // Dependant of CodeStream.isDefinitelyAssigned(..)
183 if (position < BitCacheSize) {
184 return (definiteInits & (1L << position)) != 0; // use bits
187 if (extraDefiniteInits == null)
188 return false; // if vector not yet allocated, then not initialized
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;
195 * Check status of definite assignment for a field.
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))
202 return isDefinitelyAssigned(field.id);
205 * Check status of definite assignment for a local.
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))
212 if (local.isArgument) {
215 return isDefinitelyAssigned(local.id + maxFieldCount);
217 public boolean isFakeReachable() {
218 return isFakeReachable;
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.
225 final private boolean isPotentiallyAssigned(int position) {
227 if (position < BitCacheSize) {
229 return (potentialInits & (1L << position)) != 0;
232 if (extraPotentialInits == null)
233 return false; // if vector not yet allocated, then not initialized
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;
240 * Check status of definite assignment for a field.
242 final public boolean isPotentiallyAssigned(FieldBinding field) {
243 // We do not want to complain in unreachable code
244 if ((this == DeadEnd) || (this.isFakeReachable))
246 return isPotentiallyAssigned(field.id);
249 * Check status of potential assignment for a local.
251 final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
252 // We do not want to complain in unreachable code
253 if ((this == DeadEnd) || (this.isFakeReachable))
255 if (local.isArgument) {
258 return isPotentiallyAssigned(local.id + maxFieldCount);
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.
265 final private void markAsDefinitelyAssigned(int position) {
266 if (this != DeadEnd) {
268 // position is zero-based
269 if (position < BitCacheSize) {
272 definiteInits |= (mask = 1L << position);
273 potentialInits |= mask;
276 int vectorIndex = (position / BitCacheSize) - 1;
277 if (extraDefiniteInits == null) {
279 extraDefiniteInits = new long[length = vectorIndex + 1];
280 extraPotentialInits = new long[length];
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);
289 extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
290 extraPotentialInits[vectorIndex] |= mask;
295 * Record a field got definitely assigned.
297 public void markAsDefinitelyAssigned(FieldBinding field) {
299 markAsDefinitelyAssigned(field.id);
302 * Record a local got definitely assigned.
304 public void markAsDefinitelyAssigned(LocalVariableBinding local) {
306 markAsDefinitelyAssigned(local.id + maxFieldCount);
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.
313 final private void markAsDefinitelyNotAssigned(int position) {
314 if (this != DeadEnd) {
316 // position is zero-based
317 if (position < BitCacheSize) {
320 definiteInits &= ~(mask = 1L << position);
321 potentialInits &= ~mask;
324 int vectorIndex = (position / BitCacheSize) - 1;
325 if (extraDefiniteInits == null) {
326 return; // nothing to do, it was not yet set
328 // might need to grow the arrays
329 if (vectorIndex >= extraDefiniteInits.length) {
330 return; // nothing to do, it was not yet set
334 extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize));
335 extraPotentialInits[vectorIndex] &= ~mask;
340 * Clear the initialization info for a field
342 public void markAsDefinitelyNotAssigned(FieldBinding field) {
344 markAsDefinitelyNotAssigned(field.id);
347 * Clear the initialization info for a local variable
350 public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
352 markAsDefinitelyNotAssigned(local.id + maxFieldCount);
354 public FlowInfo markAsFakeReachable(boolean isFakeReachable) {
355 this.isFakeReachable = isFakeReachable;
358 public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
359 // updates the receiver with:
360 // - intersection of definitely assigned variables,
361 // - union of potentially set ones
365 if (otherInits == DeadEnd)
368 // if one branch is not fake reachable, then the merged one is reachable
369 if (!otherInits.isFakeReachable())
370 markAsFakeReachable(false);
372 // intersection of definitely assigned variables,
373 definiteInits &= otherInits.definiteInits;
374 // union of potentially set ones
375 potentialInits |= otherInits.potentialInits;
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);
387 extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
388 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
390 while (i < otherLength) {
391 extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
394 // current storage is longer
395 while (i < otherLength) {
396 extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
397 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
400 extraDefiniteInits[i++] = 0;
403 // no extra storage on otherInits
404 int i = 0, length = extraDefiniteInits.length;
406 extraDefiniteInits[i++] = 0;
409 if (otherInits.extraDefiniteInits != null) {
410 // no storage here, but other has extra storage.
412 extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
413 System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
418 * Answer the total number of fields in enclosing types of a given type
420 static int numberOfEnclosingFields(ReferenceBinding type){
422 type = type.enclosingType();
423 while(type != null) {
424 count += type.fieldCount();
425 type = type.enclosingType();
429 public String toString(){
430 if (this == DeadEnd){
431 return "FlowInfo.DeadEnd"; //$NON-NLS-1$
433 return "FlowInfo<def: "+ definiteInits +", pot: " + potentialInits + ">"; //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$
435 public UnconditionalFlowInfo unconditionalInits() {
436 // also see conditional inits, where it requests them to merge