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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.flow;
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;
18 * Record initialization status during definite assignment analysis
20 * No caching of pre-allocated instances.
22 public class UnconditionalFlowInfo extends FlowInfo {
25 public long definiteInits;
26 public long potentialInits;
27 public long extraDefiniteInits[];
28 public long extraPotentialInits[];
30 public long definiteNulls;
31 public long definiteNonNulls;
32 public long extraDefiniteNulls[];
33 public long extraDefiniteNonNulls[];
35 public int reachMode; // by default
37 public int maxFieldCount;
40 public static final int BitCacheSize = 64; // 64 bits in a long.
42 UnconditionalFlowInfo() {
43 this.reachMode = REACHABLE;
46 // unions of both sets of initialization - used for try/finally
47 public FlowInfo addInitializationsFrom(FlowInfo inits) {
52 UnconditionalFlowInfo otherInits = inits.unconditionalInits();
53 if (otherInits == DEAD_END)
56 // union of definitely assigned variables,
57 definiteInits |= otherInits.definiteInits;
58 // union of potentially set ones
59 potentialInits |= otherInits.potentialInits;
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>
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];
82 for (; i < otherLength; i++) {
83 extraPotentialInits[i] = otherInits.extraPotentialInits[i];
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];
93 for (; i < length; i++) {
94 extraDefiniteInits[i] = 0;
95 extraDefiniteNulls[i] = 0;
96 extraDefiniteNonNulls[i] = 0;
100 // no extra storage on otherInits
103 if (otherInits.extraDefiniteInits != null) {
104 // no storage here, but other has extra storage.
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);
114 // unions of both sets of initialization - used for try/finally
115 public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) {
117 if (this == DEAD_END){
121 UnconditionalFlowInfo otherInits = inits.unconditionalInits();
122 if (otherInits == DEAD_END){
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;
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);
143 this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
144 this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i];
145 this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++];
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++];
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++];
162 if (otherInits.extraDefiniteInits != null) {
163 // no storage here, but other has extra storage.
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];
174 * Answers a copy of the current instance
176 public FlowInfo copy() {
178 // do not clone the DeadEnd
179 if (this == DEAD_END)
182 // look for an unused preallocated object
183 UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
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;
193 if (this.extraDefiniteInits != null) {
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);
203 public UnconditionalFlowInfo discardFieldInitializations(){
205 int limit = this.maxFieldCount;
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;
216 this.definiteInits = 0;
217 this.potentialInits = 0;
218 this.definiteNulls = 0;
219 this.definiteNonNulls = 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;
232 this.extraDefiniteNulls[i] = 0L;
233 this.extraDefiniteNonNulls[i] = 0L;
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;
243 public UnconditionalFlowInfo discardNonFieldInitializations(){
245 int limit = this.maxFieldCount;
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;
256 if (extraDefiniteInits == null) {
257 return this; // if vector not yet allocated, then not initialized
259 int vectorIndex, length = this.extraDefiniteInits.length;
260 if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
261 return this; // not enough room yet
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;
277 public UnconditionalFlowInfo discardNullRelatedInitializations(){
279 this.definiteNulls = 0;
280 this.definiteNonNulls = 0;
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;
290 public FlowInfo initsWhenFalse() {
295 public FlowInfo initsWhenTrue() {
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.
305 final private boolean isDefinitelyAssigned(int position) {
307 // Dependant of CodeStream.isDefinitelyAssigned(..)
309 if (position < BitCacheSize) {
310 return (definiteInits & (1L << position)) != 0; // use bits
313 if (extraDefiniteInits == null)
314 return false; // if vector not yet allocated, then not initialized
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;
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.
326 final private boolean isDefinitelyNonNull(int position) {
328 // Dependant of CodeStream.isDefinitelyAssigned(..)
330 if (position < BitCacheSize) {
331 return (definiteNonNulls & (1L << position)) != 0; // use bits
334 if (extraDefiniteNonNulls == null)
335 return false; // if vector not yet allocated, then not initialized
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;
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.
347 final private boolean isDefinitelyNull(int position) {
349 // Dependant of CodeStream.isDefinitelyAssigned(..)
351 if (position < BitCacheSize) {
352 return (definiteNulls & (1L << position)) != 0; // use bits
355 if (extraDefiniteNulls == null)
356 return false; // if vector not yet allocated, then not initialized
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;
364 * Check status of definite assignment for a field.
366 final public boolean isDefinitelyAssigned(FieldBinding field) {
368 // Dependant of CodeStream.isDefinitelyAssigned(..)
369 // We do not want to complain in unreachable code
370 if ((this.reachMode & UNREACHABLE) != 0)
372 return isDefinitelyAssigned(field.id);
376 * Check status of definite assignment for a local.
378 final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
380 // Dependant of CodeStream.isDefinitelyAssigned(..)
381 // We do not want to complain in unreachable code
382 if ((this.reachMode & UNREACHABLE) != 0)
385 // final constants are inlined, and thus considered as always initialized
386 if (local.isConstantValue()) {
389 return isDefinitelyAssigned(local.id + maxFieldCount);
393 * Check status of definite non-null assignment for a field.
395 final public boolean isDefinitelyNonNull(FieldBinding field) {
397 // Dependant of CodeStream.isDefinitelyAssigned(..)
398 // We do not want to complain in unreachable code
399 if ((this.reachMode & UNREACHABLE) != 0)
401 return isDefinitelyNonNull(field.id);
405 * Check status of definite non-null assignment for a local.
407 final public boolean isDefinitelyNonNull(LocalVariableBinding local) {
409 // Dependant of CodeStream.isDefinitelyAssigned(..)
410 // We do not want to complain in unreachable code
411 if ((this.reachMode & UNREACHABLE) != 0)
413 // final constants are inlined, and thus considered as always initialized
414 if (local.isConstantValue()) {
417 return isDefinitelyNonNull(local.id + maxFieldCount);
421 * Check status of definite null assignment for a field.
423 final public boolean isDefinitelyNull(FieldBinding field) {
425 // Dependant of CodeStream.isDefinitelyAssigned(..)
426 // We do not want to complain in unreachable code
427 if ((this.reachMode & UNREACHABLE) != 0)
429 return isDefinitelyNull(field.id);
433 * Check status of definite null assignment for a local.
435 final public boolean isDefinitelyNull(LocalVariableBinding local) {
437 // Dependant of CodeStream.isDefinitelyAssigned(..)
438 // We do not want to complain in unreachable code
439 if ((this.reachMode & UNREACHABLE) != 0)
441 return isDefinitelyNull(local.id + maxFieldCount);
444 public boolean isReachable() {
446 return this.reachMode == REACHABLE;
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.
454 final private boolean isPotentiallyAssigned(int position) {
457 if (position < BitCacheSize) {
459 return (potentialInits & (1L << position)) != 0;
462 if (extraPotentialInits == null)
463 return false; // if vector not yet allocated, then not initialized
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;
471 * Check status of definite assignment for a field.
473 final public boolean isPotentiallyAssigned(FieldBinding field) {
475 return isPotentiallyAssigned(field.id);
479 * Check status of potential assignment for a local.
481 final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
483 // final constants are inlined, and thus considered as always initialized
484 if (local.isConstantValue()) {
487 return isPotentiallyAssigned(local.id + maxFieldCount);
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.
495 final private void markAsDefinitelyAssigned(int position) {
497 if (this != DEAD_END) {
499 // position is zero-based
500 if (position < BitCacheSize) {
503 definiteInits |= (mask = 1L << position);
504 potentialInits |= mask;
505 definiteNulls &= ~mask;
506 definiteNonNulls &= ~mask;
509 int vectorIndex = (position / BitCacheSize) - 1;
510 if (extraDefiniteInits == null) {
512 extraDefiniteInits = new long[length = vectorIndex + 1];
513 extraPotentialInits = new long[length];
514 extraDefiniteNulls = new long[length];
515 extraDefiniteNonNulls = new long[length];
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);
526 extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
527 extraPotentialInits[vectorIndex] |= mask;
528 extraDefiniteNulls[vectorIndex] &= ~mask;
529 extraDefiniteNonNulls[vectorIndex] &= ~mask;
535 * Record a field got definitely assigned.
537 public void markAsDefinitelyAssigned(FieldBinding field) {
538 if (this != DEAD_END)
539 markAsDefinitelyAssigned(field.id);
543 * Record a local got definitely assigned.
545 public void markAsDefinitelyAssigned(LocalVariableBinding local) {
546 if (this != DEAD_END)
547 markAsDefinitelyAssigned(local.id + maxFieldCount);
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.
555 final private void markAsDefinitelyNonNull(int position) {
557 if (this != DEAD_END) {
559 // position is zero-based
560 if (position < BitCacheSize) {
563 definiteNonNulls |= (mask = 1L << position);
564 definiteNulls &= ~mask;
567 int vectorIndex = (position / BitCacheSize) - 1;
569 extraDefiniteNonNulls[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
570 extraDefiniteNulls[vectorIndex] &= ~mask;
576 * Record a field got definitely assigned to non-null value.
578 public void markAsDefinitelyNonNull(FieldBinding field) {
579 if (this != DEAD_END)
580 markAsDefinitelyNonNull(field.id);
584 * Record a local got definitely assigned to non-null value.
586 public void markAsDefinitelyNonNull(LocalVariableBinding local) {
587 if (this != DEAD_END)
588 markAsDefinitelyNonNull(local.id + maxFieldCount);
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.
596 final private void markAsDefinitelyNull(int position) {
598 if (this != DEAD_END) {
600 // position is zero-based
601 if (position < BitCacheSize) {
604 definiteNulls |= (mask = 1L << position);
605 definiteNonNulls &= ~mask;
608 int vectorIndex = (position / BitCacheSize) - 1;
610 extraDefiniteNulls[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
611 extraDefiniteNonNulls[vectorIndex] &= ~mask;
617 * Record a field got definitely assigned to null.
619 public void markAsDefinitelyNull(FieldBinding field) {
620 if (this != DEAD_END)
621 markAsDefinitelyAssigned(field.id);
625 * Record a local got definitely assigned to null.
627 public void markAsDefinitelyNull(LocalVariableBinding local) {
628 if (this != DEAD_END)
629 markAsDefinitelyNull(local.id + maxFieldCount);
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.
637 final private void markAsDefinitelyNotAssigned(int position) {
638 if (this != DEAD_END) {
640 // position is zero-based
641 if (position < BitCacheSize) {
644 definiteInits &= ~(mask = 1L << position);
645 potentialInits &= ~mask;
646 definiteNulls &= ~mask;
647 definiteNonNulls &= ~mask;
650 int vectorIndex = (position / BitCacheSize) - 1;
651 if (extraDefiniteInits == null) {
652 return; // nothing to do, it was not yet set
654 // might need to grow the arrays
655 if (vectorIndex >= extraDefiniteInits.length) {
656 return; // nothing to do, it was not yet set
659 extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize));
660 extraPotentialInits[vectorIndex] &= ~mask;
661 extraDefiniteNulls[vectorIndex] &= ~mask;
662 extraDefiniteNonNulls[vectorIndex] &= ~mask;
668 * Clear the initialization info for a field
670 public void markAsDefinitelyNotAssigned(FieldBinding field) {
672 if (this != DEAD_END)
673 markAsDefinitelyNotAssigned(field.id);
677 * Clear the initialization info for a local variable
680 public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
682 if (this != DEAD_END)
683 markAsDefinitelyNotAssigned(local.id + maxFieldCount);
687 * Returns the receiver updated in the following way: <ul>
688 * <li> intersection of definitely assigned variables,
689 * <li> union of potentially assigned variables.
692 public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
694 if (this == DEAD_END) return otherInits;
695 if (otherInits == DEAD_END) return this;
697 if ((this.reachMode & UNREACHABLE) != (otherInits.reachMode & UNREACHABLE)){
698 if ((this.reachMode & UNREACHABLE) != 0){
704 // if one branch is not fake reachable, then the merged one is reachable
705 this.reachMode &= otherInits.reachMode;
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;
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);
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++];
733 while (i < otherLength) {
734 this.extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
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++];
745 this.extraDefiniteInits[i] = 0;
746 this.extraDefiniteNulls[i] = 0;
747 this.extraDefiniteNonNulls[i++] = 0;
751 // no extra storage on otherInits
752 int i = 0, length = this.extraDefiniteInits.length;
754 this.extraDefiniteInits[i] = 0;
755 this.extraDefiniteNulls[i] = 0;
756 this.extraDefiniteNonNulls[i++] = 0;
760 if (otherInits.extraDefiniteInits != null) {
761 // no storage here, but other has extra storage.
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];
772 * Answer the total number of fields in enclosing types of a given type
774 static int numberOfEnclosingFields(ReferenceBinding type){
777 type = type.enclosingType();
778 while(type != null) {
779 count += type.fieldCount();
780 type = type.enclosingType();
785 public int reachMode(){
786 return this.reachMode;
789 public FlowInfo setReachMode(int reachMode) {
791 if (this == DEAD_END) return this; // cannot modify DEAD_END
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;
802 this.reachMode = reachMode;
807 public String toString(){
809 if (this == DEAD_END){
810 return "FlowInfo.DEAD_END"; //$NON-NLS-1$
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$
820 public UnconditionalFlowInfo unconditionalInits() {
822 // also see conditional inits, where it requests them to merge