1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.flow;
13 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
14 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
15 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
16 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
19 * Record initialization status during definite assignment analysis
21 * No caching of pre-allocated instances.
23 public class UnconditionalFlowInfo extends FlowInfo {
25 public long definiteInits;
27 public long potentialInits;
29 public long extraDefiniteInits[];
31 public long extraPotentialInits[];
33 public int reachMode = REACHABLE; // by default
35 public int maxFieldCount;
38 public static final int BitCacheSize = 64; // 64 bits in a long.
40 UnconditionalFlowInfo() {
43 // unions of both sets of initialization - used for try/finally
44 public FlowInfo addInitializationsFrom(FlowInfo inits) {
49 UnconditionalFlowInfo otherInits = inits.unconditionalInits();
50 if (otherInits == DEAD_END)
53 // union of definitely assigned variables,
54 definiteInits |= otherInits.definiteInits;
55 // union of potentially set ones
56 potentialInits |= otherInits.potentialInits;
58 // treating extra storage
59 if (extraDefiniteInits != null) {
60 if (otherInits.extraDefiniteInits != null) {
61 // both sides have extra storage
62 int i = 0, length, otherLength;
63 if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
64 // current storage is shorter -> grow current (could maybe
65 // reuse otherInits extra storage?)
66 System.arraycopy(extraDefiniteInits, 0,
67 (extraDefiniteInits = new long[otherLength]), 0,
69 System.arraycopy(extraPotentialInits, 0,
70 (extraPotentialInits = new long[otherLength]), 0,
73 extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
74 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
76 while (i < otherLength) {
77 extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
80 // current storage is longer
81 while (i < otherLength) {
82 extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
83 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
86 extraDefiniteInits[i++] = 0;
89 // no extra storage on otherInits
91 } else if (otherInits.extraDefiniteInits != null) {
92 // no storage here, but other has extra storage.
96 otherInits.extraDefiniteInits,
98 (extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]),
100 System.arraycopy(otherInits.extraPotentialInits, 0,
101 (extraPotentialInits = new long[otherLength]), 0,
107 // unions of both sets of initialization - used for try/finally
108 public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) {
110 if (this == DEAD_END) {
114 UnconditionalFlowInfo otherInits = inits.unconditionalInits();
115 if (otherInits == DEAD_END) {
118 // union of potentially set ones
119 potentialInits |= otherInits.potentialInits;
121 // treating extra storage
122 if (extraDefiniteInits != null) {
123 if (otherInits.extraDefiniteInits != null) {
124 // both sides have extra storage
125 int i = 0, length, otherLength;
126 if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
127 // current storage is shorter -> grow current (could maybe
128 // reuse otherInits extra storage?)
129 System.arraycopy(extraDefiniteInits, 0,
130 (extraDefiniteInits = new long[otherLength]), 0,
132 System.arraycopy(extraPotentialInits, 0,
133 (extraPotentialInits = new long[otherLength]), 0,
136 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
138 while (i < otherLength) {
139 extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
142 // current storage is longer
143 while (i < otherLength) {
144 extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
148 } else if (otherInits.extraDefiniteInits != null) {
149 // no storage here, but other has extra storage.
151 extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
152 System.arraycopy(otherInits.extraPotentialInits, 0,
153 (extraPotentialInits = new long[otherLength]), 0,
159 // Report an error if necessary
160 // public boolean complainIfUnreachable(Statement statement, BlockScope
161 // scope, boolean didAlreadyComplain) {
163 // if ((this.reachMode & UNREACHABLE) != 0) {
164 // statement.bits &= ~ASTNode.IsReachableMASK;
165 // boolean reported = this == DEAD_END;
166 // if (!didAlreadyComplain && reported) {
167 // scope.problemReporter().unreachableCode(statement);
169 // return reported; // keep going for fake reachable
175 * Answers a copy of the current instance
177 public FlowInfo copy() {
179 // do not clone the DeadEnd
180 if (this == DEAD_END)
183 // look for an unused preallocated object
184 UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
187 copy.definiteInits = this.definiteInits;
188 copy.potentialInits = this.potentialInits;
189 copy.reachMode = this.reachMode;
190 copy.maxFieldCount = this.maxFieldCount;
192 if (this.extraDefiniteInits != null) {
196 this.extraDefiniteInits,
198 (copy.extraDefiniteInits = new long[(length = extraDefiniteInits.length)]),
200 System.arraycopy(this.extraPotentialInits, 0,
201 (copy.extraPotentialInits = new long[length]), 0, length);
207 public UnconditionalFlowInfo discardFieldInitializations() {
209 int limit = this.maxFieldCount;
211 if (limit < BitCacheSize) {
212 long mask = (1L << limit) - 1;
213 this.definiteInits &= ~mask;
214 this.potentialInits &= ~mask;
218 this.definiteInits = 0;
219 this.potentialInits = 0;
222 if (extraDefiniteInits == null) {
223 return this; // if vector not yet allocated, then not initialized
225 int vectorIndex, length = this.extraDefiniteInits.length;
226 if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
227 return this; // not enough room yet
229 for (int i = 0; i < vectorIndex; i++) {
230 this.extraDefiniteInits[i] = 0L;
231 this.extraPotentialInits[i] = 0L;
233 long mask = (1L << (limit % BitCacheSize)) - 1;
234 this.extraDefiniteInits[vectorIndex] &= ~mask;
235 this.extraPotentialInits[vectorIndex] &= ~mask;
239 public UnconditionalFlowInfo discardNonFieldInitializations() {
241 int limit = this.maxFieldCount;
243 if (limit < BitCacheSize) {
244 long mask = (1L << limit) - 1;
245 this.definiteInits &= mask;
246 this.potentialInits &= mask;
250 if (extraDefiniteInits == null) {
251 return this; // if vector not yet allocated, then not initialized
253 int vectorIndex, length = this.extraDefiniteInits.length;
254 if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
255 return this; // not enough room yet
257 long mask = (1L << (limit % BitCacheSize)) - 1;
258 this.extraDefiniteInits[vectorIndex] &= mask;
259 this.extraPotentialInits[vectorIndex] &= mask;
260 for (int i = vectorIndex + 1; i < length; i++) {
261 this.extraDefiniteInits[i] = 0L;
262 this.extraPotentialInits[i] = 0L;
267 public FlowInfo initsWhenFalse() {
272 public FlowInfo initsWhenTrue() {
278 * Check status of definite assignment at a given position. It deals with
279 * the dual representation of the InitializationInfo2: bits for the first 64
280 * entries, then an array of booleans.
282 final private boolean isDefinitelyAssigned(int position) {
284 // Dependant of CodeStream.isDefinitelyAssigned(..)
286 if (position < BitCacheSize) {
287 return (definiteInits & (1L << position)) != 0; // use bits
290 if (extraDefiniteInits == null)
291 return false; // if vector not yet allocated, then not initialized
293 if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteInits.length)
294 return false; // if not enough room in vector, then not
296 return ((extraDefiniteInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
300 * Check status of definite assignment for a field.
302 final public boolean isDefinitelyAssigned(FieldBinding field) {
304 // Dependant of CodeStream.isDefinitelyAssigned(..)
305 // We do not want to complain in unreachable code
306 if ((this.reachMode & UNREACHABLE) != 0)
308 return isDefinitelyAssigned(field.id);
312 * Check status of definite assignment for a local.
314 final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
316 // Dependant of CodeStream.isDefinitelyAssigned(..)
317 // We do not want to complain in unreachable code
318 if ((this.reachMode & UNREACHABLE) != 0)
320 if (local.isArgument) {
323 // final constants are inlined, and thus considered as always
325 if (local.constant != Constant.NotAConstant) {
328 return isDefinitelyAssigned(local.id + maxFieldCount);
331 public boolean isReachable() {
333 return this.reachMode == REACHABLE;
337 * Check status of potential assignment at a given position. It deals with
338 * the dual representation of the InitializationInfo3: bits for the first 64
339 * entries, then an array of booleans.
341 final private boolean isPotentiallyAssigned(int position) {
344 if (position < BitCacheSize) {
346 return (potentialInits & (1L << position)) != 0;
349 if (extraPotentialInits == null)
350 return false; // if vector not yet allocated, then not initialized
352 if ((vectorIndex = (position / BitCacheSize) - 1) >= extraPotentialInits.length)
353 return false; // if not enough room in vector, then not
355 return ((extraPotentialInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
359 * Check status of definite assignment for a field.
361 final public boolean isPotentiallyAssigned(FieldBinding field) {
363 return isPotentiallyAssigned(field.id);
367 * Check status of potential assignment for a local.
369 final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
371 if (local.isArgument) {
374 // final constants are inlined, and thus considered as always
376 if (local.constant != Constant.NotAConstant) {
379 return isPotentiallyAssigned(local.id + maxFieldCount);
383 * Record a definite assignment at a given position. It deals with the dual
384 * representation of the InitializationInfo2: bits for the first 64 entries,
385 * then an array of booleans.
387 final private void markAsDefinitelyAssigned(int position) {
389 if (this != DEAD_END) {
391 // position is zero-based
392 if (position < BitCacheSize) {
395 definiteInits |= (mask = 1L << position);
396 potentialInits |= mask;
399 int vectorIndex = (position / BitCacheSize) - 1;
400 if (extraDefiniteInits == null) {
402 extraDefiniteInits = new long[length = vectorIndex + 1];
403 extraPotentialInits = new long[length];
405 int oldLength; // might need to grow the arrays
406 if (vectorIndex >= (oldLength = extraDefiniteInits.length)) {
411 (extraDefiniteInits = new long[vectorIndex + 1]),
417 (extraPotentialInits = new long[vectorIndex + 1]),
422 extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
423 extraPotentialInits[vectorIndex] |= mask;
429 * Record a field got definitely assigned.
431 public void markAsDefinitelyAssigned(FieldBinding field) {
432 if (this != DEAD_END)
433 markAsDefinitelyAssigned(field.id);
437 * Record a local got definitely assigned.
439 public void markAsDefinitelyAssigned(LocalVariableBinding local) {
440 if (this != DEAD_END)
441 markAsDefinitelyAssigned(local.id + maxFieldCount);
445 * Clear initialization information at a given position. It deals with the
446 * dual representation of the InitializationInfo2: bits for the first 64
447 * entries, then an array of booleans.
449 final private void markAsDefinitelyNotAssigned(int position) {
450 if (this != DEAD_END) {
452 // position is zero-based
453 if (position < BitCacheSize) {
456 definiteInits &= ~(mask = 1L << position);
457 potentialInits &= ~mask;
460 int vectorIndex = (position / BitCacheSize) - 1;
461 if (extraDefiniteInits == null) {
462 return; // nothing to do, it was not yet set
464 // might need to grow the arrays
465 if (vectorIndex >= extraDefiniteInits.length) {
466 return; // nothing to do, it was not yet set
470 extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize));
471 extraPotentialInits[vectorIndex] &= ~mask;
477 * Clear the initialization info for a field
479 public void markAsDefinitelyNotAssigned(FieldBinding field) {
481 if (this != DEAD_END)
482 markAsDefinitelyNotAssigned(field.id);
486 * Clear the initialization info for a local variable
489 public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
491 if (this != DEAD_END)
492 markAsDefinitelyNotAssigned(local.id + maxFieldCount);
496 * Returns the receiver updated in the following way:
498 * <li> intersection of definitely assigned variables,
499 * <li> union of potentially assigned variables.
502 public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
504 if (this == DEAD_END)
506 if (otherInits == DEAD_END)
509 if ((this.reachMode & UNREACHABLE) != (otherInits.reachMode & UNREACHABLE)) {
510 if ((this.reachMode & UNREACHABLE) != 0) {
517 // if one branch is not fake reachable, then the merged one is reachable
518 this.reachMode &= otherInits.reachMode;
520 // intersection of definitely assigned variables,
521 this.definiteInits &= otherInits.definiteInits;
522 // union of potentially set ones
523 this.potentialInits |= otherInits.potentialInits;
525 // treating extra storage
526 if (this.extraDefiniteInits != null) {
527 if (otherInits.extraDefiniteInits != null) {
528 // both sides have extra storage
529 int i = 0, length, otherLength;
530 if ((length = this.extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
531 // current storage is shorter -> grow current (could maybe
532 // reuse otherInits extra storage?)
533 System.arraycopy(this.extraDefiniteInits, 0,
534 (this.extraDefiniteInits = new long[otherLength]),
536 System.arraycopy(this.extraPotentialInits, 0,
537 (this.extraPotentialInits = new long[otherLength]),
540 this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
541 this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
543 while (i < otherLength) {
544 this.extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
547 // current storage is longer
548 while (i < otherLength) {
549 this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
550 this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
553 this.extraDefiniteInits[i++] = 0;
556 // no extra storage on otherInits
557 int i = 0, length = this.extraDefiniteInits.length;
559 this.extraDefiniteInits[i++] = 0;
561 } else if (otherInits.extraDefiniteInits != null) {
562 // no storage here, but other has extra storage.
564 this.extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
565 System.arraycopy(otherInits.extraPotentialInits, 0,
566 (this.extraPotentialInits = new long[otherLength]), 0,
573 * Answer the total number of fields in enclosing types of a given type
575 static int numberOfEnclosingFields(ReferenceBinding type) {
578 type = type.enclosingType();
579 while (type != null) {
580 count += type.fieldCount();
581 type = type.enclosingType();
586 public int reachMode() {
587 return this.reachMode;
590 public FlowInfo setReachMode(int reachMode) {
592 if (this == DEAD_END)
593 return this; // cannot modify DEAD_END
595 // reset optional inits when becoming unreachable
596 if ((this.reachMode & UNREACHABLE) == 0
597 && (reachMode & UNREACHABLE) != 0) {
598 this.potentialInits = 0;
599 if (this.extraPotentialInits != null) {
600 for (int i = 0, length = this.extraPotentialInits.length; i < length; i++) {
601 this.extraPotentialInits[i] = 0;
605 this.reachMode = reachMode;
610 public String toString() {
612 if (this == DEAD_END) {
613 return "FlowInfo.DEAD_END"; //$NON-NLS-1$
615 return "FlowInfo<def: " + this.definiteInits //$NON-NLS-1$
616 + ", pot: " + this.potentialInits //$NON-NLS-1$
617 + ", reachable:" + ((this.reachMode & UNREACHABLE) == 0) //$NON-NLS-1$
621 public UnconditionalFlowInfo unconditionalInits() {
623 // also see conditional inits, where it requests them to merge