0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2006 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.flow;
0011:
0012: import org.eclipse.jdt.internal.compiler.ast.ASTNode;
0013: import org.eclipse.jdt.internal.compiler.impl.Constant;
0014: import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
0015: import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
0016: import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
0017: import org.eclipse.jdt.internal.compiler.lookup.TagBits;
0018:
0019: /**
0020: * Record initialization status during definite assignment analysis
0021: *
0022: * No caching of pre-allocated instances.
0023: */
0024: public class UnconditionalFlowInfo extends FlowInfo {
0025: // Coverage tests
0026: /**
0027: * Exception raised when unexpected behavior is detected during coverage
0028: * tests.
0029: */
0030: public static class AssertionFailedException extends
0031: RuntimeException {
0032: private static final long serialVersionUID = 1827352841030089703L;
0033:
0034: public AssertionFailedException(String message) {
0035: super (message);
0036: }
0037: }
0038:
0039: // Coverage tests need that the code be instrumented. The following flag
0040: // controls whether the instrumented code is compiled in or not, and whether
0041: // the coverage tests methods run or not.
0042: public final static boolean coverageTestFlag = false;
0043: // never release with the coverageTestFlag set to true
0044: public static int coverageTestId;
0045:
0046: // assignment bits - first segment
0047: public long definiteInits;
0048: public long potentialInits;
0049:
0050: // null bits - first segment
0051: public long nullBit1, nullBit2, nullBit3, nullBit4;
0052: /*
0053: nullBit1
0054: nullBit2...
0055: 0000 start
0056: 0001 pot. unknown
0057: 0010 pot. non null
0058: 0011 pot. nn & pot. un
0059: 0100 pot. null
0060: 0101 pot. n & pot. un
0061: 0110 pot. n & pot. nn
0062: 1001 def. unknown
0063: 1010 def. non null
0064: 1011 pot. nn & prot. nn
0065: 1100 def. null
0066: 1101 pot. n & prot. n
0067: 1110 prot. null
0068: 1111 prot. non null
0069: */
0070:
0071: // extra segments
0072: public static final int extraLength = 6;
0073: public long extra[][];
0074: // extra bit fields for larger numbers of fields/variables
0075: // extra[0] holds definiteInits values, extra[1] potentialInits, etc.
0076: // lifecycle is extra == null or else all extra[]'s are allocated
0077: // arrays which have the same size
0078:
0079: public int maxFieldCount; // limit between fields and locals
0080:
0081: // Constants
0082: public static final int BitCacheSize = 64; // 64 bits in a long.
0083:
0084: public FlowInfo addInitializationsFrom(FlowInfo inits) {
0085: if (this == DEAD_END)
0086: return this ;
0087: if (inits == DEAD_END)
0088: return this ;
0089: UnconditionalFlowInfo otherInits = inits.unconditionalInits();
0090:
0091: // union of definitely assigned variables,
0092: this .definiteInits |= otherInits.definiteInits;
0093: // union of potentially set ones
0094: this .potentialInits |= otherInits.potentialInits;
0095: // combine null information
0096: boolean this HadNulls = (this .tagBits & NULL_FLAG_MASK) != 0, otherHasNulls = (otherInits.tagBits & NULL_FLAG_MASK) != 0;
0097: long a1, a2, a3, a4, na1, na2, na3, na4, b1, b2, b3, b4, nb1, nb2, nb3, nb4;
0098: if (otherHasNulls) {
0099: if (!this HadNulls) {
0100: this .nullBit1 = otherInits.nullBit1;
0101: this .nullBit2 = otherInits.nullBit2;
0102: this .nullBit3 = otherInits.nullBit3;
0103: this .nullBit4 = otherInits.nullBit4;
0104: if (coverageTestFlag && coverageTestId == 1) {
0105: this .nullBit4 = ~0;
0106: }
0107: } else {
0108: this .nullBit1 = (b1 = otherInits.nullBit1)
0109: | (a1 = this .nullBit1)
0110: & ((a3 = this .nullBit3) & (a4 = this .nullBit4)
0111: & (nb2 = ~(b2 = otherInits.nullBit2))
0112: & (nb4 = ~(b4 = otherInits.nullBit4)) | ((na4 = ~a4) | (na3 = ~a3))
0113: & ((na2 = ~(a2 = this .nullBit2)) & nb2 | a2
0114: & (nb3 = ~(b3 = otherInits.nullBit3))
0115: & nb4));
0116: this .nullBit2 = b2
0117: & (nb4 | nb3)
0118: | na3
0119: & na4
0120: & b2
0121: | a2
0122: & (nb3 & nb4 | (nb1 = ~b1)
0123: & (na3 | (na1 = ~a1)) | a1 & b2);
0124: this .nullBit3 = b3
0125: & (nb1 & (b2 | a2 | na1) | b1
0126: & (b4 | nb2 | a1 & a3) | na1 & na2
0127: & na4) | a3 & nb2 & nb4 | nb1
0128: & ((na2 & a4 | na1) & a3 | a1 & na2 & na4 & b2);
0129: this .nullBit4 = nb1
0130: & (a4 & (na3 & nb3 | (a3 | na2) & nb2) | a1
0131: & (a3 & nb2 & b4 | a2 & b2
0132: & (b4 | a3 & na4 & nb3)))
0133: | b1
0134: & (a3 & a4 & b4 | na2 & na4 & nb3 & b4 | a2
0135: & ((b3 | a4) & b4 | na3 & a4 & b2 & b3) | na1
0136: & (b4 | (a4 | a2) & b2 & b3))
0137: | (na1 & (na3 & nb3 | na2 & nb2) | a1
0138: & (nb2 & nb3 | a2 & a3)) & b4;
0139: if (coverageTestFlag && coverageTestId == 2) {
0140: this .nullBit4 = ~0;
0141: }
0142: }
0143: this .tagBits |= NULL_FLAG_MASK; // in all cases - avoid forgetting extras
0144: }
0145: // treating extra storage
0146: if (this .extra != null || otherInits.extra != null) {
0147: int mergeLimit = 0, copyLimit = 0;
0148: if (this .extra != null) {
0149: if (otherInits.extra != null) {
0150: // both sides have extra storage
0151: int length, otherLength;
0152: if ((length = this .extra[0].length) < (otherLength = otherInits.extra[0].length)) {
0153: // current storage is shorter -> grow current
0154: for (int j = 0; j < extraLength; j++) {
0155: System
0156: .arraycopy(
0157: this .extra[j],
0158: 0,
0159: (this .extra[j] = new long[otherLength]),
0160: 0, length);
0161: }
0162: mergeLimit = length;
0163: copyLimit = otherLength;
0164: if (coverageTestFlag && coverageTestId == 3) {
0165: throw new AssertionFailedException(
0166: "COVERAGE 3"); //$NON-NLS-1$
0167: }
0168: } else {
0169: // current storage is longer
0170: mergeLimit = otherLength;
0171: if (coverageTestFlag && coverageTestId == 4) {
0172: throw new AssertionFailedException(
0173: "COVERAGE 4"); //$NON-NLS-1$
0174: }
0175: }
0176: }
0177: } else if (otherInits.extra != null) {
0178: // no storage here, but other has extra storage.
0179: // shortcut regular copy because array copy is better
0180: int otherLength;
0181: this .extra = new long[extraLength][];
0182: System
0183: .arraycopy(
0184: otherInits.extra[0],
0185: 0,
0186: (this .extra[0] = new long[otherLength = otherInits.extra[0].length]),
0187: 0, otherLength);
0188: System.arraycopy(otherInits.extra[1], 0,
0189: (this .extra[1] = new long[otherLength]), 0,
0190: otherLength);
0191: if (otherHasNulls) {
0192: for (int j = 2; j < extraLength; j++) {
0193: System
0194: .arraycopy(
0195: otherInits.extra[j],
0196: 0,
0197: (this .extra[j] = new long[otherLength]),
0198: 0, otherLength);
0199: }
0200: if (coverageTestFlag && coverageTestId == 5) {
0201: this .extra[5][otherLength - 1] = ~0;
0202: }
0203: } else {
0204: for (int j = 2; j < extraLength; j++) {
0205: this .extra[j] = new long[otherLength];
0206: }
0207: if (coverageTestFlag && coverageTestId == 6) {
0208: throw new AssertionFailedException("COVERAGE 6"); //$NON-NLS-1$
0209: }
0210: }
0211: }
0212: int i;
0213: // manage definite assignment info
0214: for (i = 0; i < mergeLimit; i++) {
0215: this .extra[0][i] |= otherInits.extra[0][i];
0216: this .extra[1][i] |= otherInits.extra[1][i];
0217: }
0218: for (; i < copyLimit; i++) {
0219: this .extra[0][i] = otherInits.extra[0][i];
0220: this .extra[1][i] = otherInits.extra[1][i];
0221: }
0222: // tweak limits for nulls
0223: if (!this HadNulls) {
0224: if (copyLimit < mergeLimit) {
0225: copyLimit = mergeLimit;
0226: }
0227: mergeLimit = 0;
0228: }
0229: if (!otherHasNulls) {
0230: copyLimit = 0;
0231: mergeLimit = 0;
0232: }
0233: for (i = 0; i < mergeLimit; i++) {
0234: this .extra[1 + 1][i] = (b1 = otherInits.extra[1 + 1][i])
0235: | (a1 = this .extra[1 + 1][i])
0236: & ((a3 = this .extra[3 + 1][i])
0237: & (a4 = this .extra[4 + 1][i])
0238: & (nb2 = ~(b2 = otherInits.extra[2 + 1][i]))
0239: & (nb4 = ~(b4 = otherInits.extra[4 + 1][i])) | ((na4 = ~a4) | (na3 = ~a3))
0240: & ((na2 = ~(a2 = this .extra[2 + 1][i]))
0241: & nb2 | a2
0242: & (nb3 = ~(b3 = otherInits.extra[3 + 1][i]))
0243: & nb4));
0244: this .extra[2 + 1][i] = b2
0245: & (nb4 | nb3)
0246: | na3
0247: & na4
0248: & b2
0249: | a2
0250: & (nb3 & nb4 | (nb1 = ~b1)
0251: & (na3 | (na1 = ~a1)) | a1 & b2);
0252: this .extra[3 + 1][i] = b3
0253: & (nb1 & (b2 | a2 | na1) | b1
0254: & (b4 | nb2 | a1 & a3) | na1 & na2
0255: & na4) | a3 & nb2 & nb4 | nb1
0256: & ((na2 & a4 | na1) & a3 | a1 & na2 & na4 & b2);
0257: this .extra[4 + 1][i] = nb1
0258: & (a4 & (na3 & nb3 | (a3 | na2) & nb2) | a1
0259: & (a3 & nb2 & b4 | a2 & b2
0260: & (b4 | a3 & na4 & nb3)))
0261: | b1
0262: & (a3 & a4 & b4 | na2 & na4 & nb3 & b4 | a2
0263: & ((b3 | a4) & b4 | na3 & a4 & b2 & b3) | na1
0264: & (b4 | (a4 | a2) & b2 & b3))
0265: | (na1 & (na3 & nb3 | na2 & nb2) | a1
0266: & (nb2 & nb3 | a2 & a3)) & b4;
0267: if (coverageTestFlag && coverageTestId == 7) {
0268: this .extra[5][i] = ~0;
0269: }
0270: }
0271: for (; i < copyLimit; i++) {
0272: for (int j = 2; j < extraLength; j++) {
0273: this .extra[j][i] = otherInits.extra[j][i];
0274: }
0275: if (coverageTestFlag && coverageTestId == 8) {
0276: this .extra[5][i] = ~0;
0277: }
0278: }
0279: }
0280: return this ;
0281: }
0282:
0283: public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) {
0284: if (this == DEAD_END) {
0285: return this ;
0286: }
0287: if (inits == DEAD_END) {
0288: return this ;
0289: }
0290: UnconditionalFlowInfo otherInits = inits.unconditionalInits();
0291: // union of potentially set ones
0292: this .potentialInits |= otherInits.potentialInits;
0293: // treating extra storage
0294: if (this .extra != null) {
0295: if (otherInits.extra != null) {
0296: // both sides have extra storage
0297: int i = 0, length, otherLength;
0298: if ((length = this .extra[0].length) < (otherLength = otherInits.extra[0].length)) {
0299: // current storage is shorter -> grow current
0300: for (int j = 0; j < extraLength; j++) {
0301: System
0302: .arraycopy(
0303: this .extra[j],
0304: 0,
0305: (this .extra[j] = new long[otherLength]),
0306: 0, length);
0307: }
0308: for (; i < length; i++) {
0309: this .extra[1][i] |= otherInits.extra[1][i];
0310: }
0311: for (; i < otherLength; i++) {
0312: this .extra[1][i] = otherInits.extra[1][i];
0313: }
0314: } else {
0315: // current storage is longer
0316: for (; i < otherLength; i++) {
0317: this .extra[1][i] |= otherInits.extra[1][i];
0318: }
0319: }
0320: }
0321: } else if (otherInits.extra != null) {
0322: // no storage here, but other has extra storage.
0323: int otherLength = otherInits.extra[0].length;
0324: this .extra = new long[extraLength][];
0325: for (int j = 0; j < extraLength; j++) {
0326: this .extra[j] = new long[otherLength];
0327: }
0328: System.arraycopy(otherInits.extra[1], 0, this .extra[1], 0,
0329: otherLength);
0330: }
0331: this .addPotentialNullInfoFrom(otherInits);
0332: return this ;
0333: }
0334:
0335: /**
0336: * Compose other inits over this flow info, then return this. The operation
0337: * semantics are to wave into this flow info the consequences upon null
0338: * information of a possible path into the operations that resulted into
0339: * otherInits. The fact that this path may be left unexecuted under peculiar
0340: * conditions results into less specific results than
0341: * {@link #addInitializationsFrom(FlowInfo) addInitializationsFrom}; moreover,
0342: * only the null information is affected.
0343: * @param otherInits other null inits to compose over this
0344: * @return this, modified according to otherInits information
0345: */
0346: public UnconditionalFlowInfo addPotentialNullInfoFrom(
0347: UnconditionalFlowInfo otherInits) {
0348: if ((this .tagBits & UNREACHABLE) != 0
0349: || (otherInits.tagBits & UNREACHABLE) != 0
0350: || (otherInits.tagBits & NULL_FLAG_MASK) == 0) {
0351: return this ;
0352: }
0353: // if we get here, otherInits has some null info
0354: boolean this HadNulls = (this .tagBits & NULL_FLAG_MASK) != 0, this HasNulls = false;
0355: long a1, a2, a3, a4, na1, na2, na3, na4, b1, b2, b3, b4, nb1, nb2, nb3, nb4;
0356: if (this HadNulls) {
0357: this .nullBit1 = (a1 = this .nullBit1)
0358: & ((a3 = this .nullBit3)
0359: & (a4 = this .nullBit4)
0360: & ((nb2 = ~(b2 = otherInits.nullBit2))
0361: & (nb4 = ~(b4 = otherInits.nullBit4)) | (b1 = otherInits.nullBit1)
0362: & (b3 = otherInits.nullBit3))
0363: | (na2 = ~(a2 = this .nullBit2))
0364: & (b1 & b3 | ((na4 = ~a4) | (na3 = ~a3))
0365: & nb2) | a2
0366: & ((na4 | na3) & ((nb3 = ~b3) & nb4 | b1
0367: & b2)));
0368: this .nullBit2 = b2 & (nb3 | (nb1 = ~b1)) | a2
0369: & (nb3 & nb4 | b2 | na3 | (na1 = ~a1));
0370: this .nullBit3 = b3
0371: & (nb1 & b2 | a2 & (nb2 | a3) | na1 & nb2 | a1
0372: & na2 & na4 & b1) | a3
0373: & (nb2 & nb4 | na2 & a4 | na1) | a1 & na2 & na4
0374: & b2;
0375: this .nullBit4 = na3
0376: & (nb1 & nb3 & b4 | a4 & (nb3 | b1 & b2))
0377: | nb2
0378: & (na3 & b1 & nb3 | na2
0379: & (nb1 & b4 | b1 & nb3 | a4))
0380: | a3
0381: & (a4 & (nb2 | b1 & b3) | a1 & a2
0382: & (nb1 & b4 | na4 & (b2 | b1) & nb3));
0383: if (coverageTestFlag && coverageTestId == 9) {
0384: this .nullBit4 = ~0;
0385: }
0386: if ((this .nullBit2 | this .nullBit3 | this .nullBit4) != 0) { // bit1 is redundant
0387: this HasNulls = true;
0388: }
0389: } else {
0390: this .nullBit1 = 0;
0391: this .nullBit2 = (b2 = otherInits.nullBit2)
0392: & ((nb3 = ~(b3 = otherInits.nullBit3)) | (nb1 = ~(b1 = otherInits.nullBit1)));
0393: this .nullBit3 = b3 & (nb1 | (nb2 = ~b2));
0394: this .nullBit4 = ~b1 & ~b3 & (b4 = otherInits.nullBit4)
0395: | ~b2 & (b1 & ~b3 | ~b1 & b4);
0396: if (coverageTestFlag && coverageTestId == 10) {
0397: this .nullBit4 = ~0;
0398: }
0399: if ((this .nullBit2 | this .nullBit3 | this .nullBit4) != 0) { // bit1 is redundant
0400: this HasNulls = true;
0401: }
0402: }
0403: // extra storage management
0404: if (otherInits.extra != null) {
0405: int mergeLimit = 0, copyLimit = otherInits.extra[0].length;
0406: if (this .extra == null) {
0407: this .extra = new long[extraLength][];
0408: for (int j = 0; j < extraLength; j++) {
0409: this .extra[j] = new long[copyLimit];
0410: }
0411: if (coverageTestFlag && coverageTestId == 11) {
0412: throw new AssertionFailedException("COVERAGE 11"); //$NON-NLS-1$
0413: }
0414: } else {
0415: mergeLimit = copyLimit;
0416: if (mergeLimit > this .extra[0].length) {
0417: mergeLimit = this .extra[0].length;
0418: for (int j = 0; j < extraLength; j++) {
0419: System.arraycopy(this .extra[j], 0,
0420: this .extra[j] = new long[copyLimit], 0,
0421: mergeLimit);
0422: }
0423: if (!this HadNulls) {
0424: mergeLimit = 0;
0425: // will do with a copy -- caveat: only valid because definite assignment bits copied above
0426: if (coverageTestFlag && coverageTestId == 12) {
0427: throw new AssertionFailedException(
0428: "COVERAGE 12"); //$NON-NLS-1$
0429: }
0430: }
0431: }
0432: }
0433: // PREMATURE skip operations for fields
0434: int i;
0435: for (i = 0; i < mergeLimit; i++) {
0436: this .extra[1 + 1][i] = (a1 = this .extra[1 + 1][i])
0437: & ((a3 = this .extra[3 + 1][i])
0438: & (a4 = this .extra[4 + 1][i])
0439: & ((nb2 = ~(b2 = otherInits.extra[2 + 1][i]))
0440: & (nb4 = ~(b4 = otherInits.extra[4 + 1][i])) | (b1 = otherInits.extra[1 + 1][i])
0441: & (b3 = otherInits.extra[3 + 1][i]))
0442: | (na2 = ~(a2 = this .extra[2 + 1][i]))
0443: & (b1 & b3 | ((na4 = ~a4) | (na3 = ~a3))
0444: & nb2) | a2
0445: & ((na4 | na3) & ((nb3 = ~b3) & nb4 | b1
0446: & b2)));
0447: this .extra[2 + 1][i] = b2 & (nb3 | (nb1 = ~b1)) | a2
0448: & (nb3 & nb4 | b2 | na3 | (na1 = ~a1));
0449: this .extra[3 + 1][i] = b3
0450: & (nb1 & b2 | a2 & (nb2 | a3) | na1 & nb2 | a1
0451: & na2 & na4 & b1) | a3
0452: & (nb2 & nb4 | na2 & a4 | na1) | a1 & na2 & na4
0453: & b2;
0454: this .extra[4 + 1][i] = na3
0455: & (nb1 & nb3 & b4 | a4 & (nb3 | b1 & b2))
0456: | nb2
0457: & (na3 & b1 & nb3 | na2
0458: & (nb1 & b4 | b1 & nb3 | a4))
0459: | a3
0460: & (a4 & (nb2 | b1 & b3) | a1 & a2
0461: & (nb1 & b4 | na4 & (b2 | b1) & nb3));
0462: if ((this .extra[2 + 1][i] | this .extra[3 + 1][i] | this .extra[4 + 1][i]) != 0) { // bit1 is redundant
0463: this HasNulls = true;
0464: }
0465: if (coverageTestFlag && coverageTestId == 13) {
0466: this .nullBit4 = ~0;
0467: }
0468: }
0469: for (; i < copyLimit; i++) {
0470: this .extra[1 + 1][i] = 0;
0471: this .extra[2 + 1][i] = (b2 = otherInits.extra[2 + 1][i])
0472: & ((nb3 = ~(b3 = otherInits.extra[3 + 1][i])) | (nb1 = ~(b1 = otherInits.extra[1 + 1][i])));
0473: this .extra[3 + 1][i] = b3 & (nb1 | (nb2 = ~b2));
0474: this .extra[4 + 1][i] = ~b1 & ~b3
0475: & (b4 = otherInits.extra[4 + 1][i]) | ~b2
0476: & (b1 & ~b3 | ~b1 & b4);
0477: if ((this .extra[2 + 1][i] | this .extra[3 + 1][i] | this .extra[4 + 1][i]) != 0) { // bit1 is redundant
0478: this HasNulls = true;
0479: }
0480: if (coverageTestFlag && coverageTestId == 14) {
0481: this .extra[5][i] = ~0;
0482: }
0483: }
0484: }
0485: if (this HasNulls) {
0486: this .tagBits |= NULL_FLAG_MASK;
0487: } else {
0488: this .tagBits &= NULL_FLAG_MASK;
0489: }
0490: return this ;
0491: }
0492:
0493: final public boolean cannotBeDefinitelyNullOrNonNull(
0494: LocalVariableBinding local) {
0495: if ((this .tagBits & NULL_FLAG_MASK) == 0
0496: || (local.type.tagBits & TagBits.IsBaseType) != 0) {
0497: return false;
0498: }
0499: int position;
0500: if ((position = local.id + this .maxFieldCount) < BitCacheSize) {
0501: // use bits
0502: return ((~this .nullBit1
0503: & (this .nullBit2 & this .nullBit3 | this .nullBit4) | ~this .nullBit2
0504: & ~this .nullBit3 & this .nullBit4) & (1L << position)) != 0;
0505: }
0506: // use extra vector
0507: if (this .extra == null) {
0508: return false; // if vector not yet allocated, then not initialized
0509: }
0510: int vectorIndex;
0511: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0512: return false; // if not enough room in vector, then not initialized
0513: }
0514: long a2, a3, a4;
0515: return ((~this .extra[2][vectorIndex]
0516: & ((a2 = this .extra[3][vectorIndex])
0517: & (a3 = this .extra[4][vectorIndex]) | (a4 = this .extra[5][vectorIndex])) | ~a2
0518: & ~a3 & a4) & (1L << (position % BitCacheSize))) != 0;
0519: }
0520:
0521: final public boolean cannotBeNull(LocalVariableBinding local) {
0522: if ((this .tagBits & NULL_FLAG_MASK) == 0
0523: || (local.type.tagBits & TagBits.IsBaseType) != 0) {
0524: return false;
0525: }
0526: int position;
0527: if ((position = local.id + this .maxFieldCount) < BitCacheSize) {
0528: // use bits
0529: return (this .nullBit1
0530: & this .nullBit3
0531: & ((this .nullBit2 & this .nullBit4) | ~this .nullBit2) & (1L << position)) != 0;
0532: }
0533: // use extra vector
0534: if (this .extra == null) {
0535: return false; // if vector not yet allocated, then not initialized
0536: }
0537: int vectorIndex;
0538: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0539: return false; // if not enough room in vector, then not initialized
0540: }
0541: return (this .extra[2][vectorIndex]
0542: & this .extra[4][vectorIndex]
0543: & ((this .extra[3][vectorIndex] & this .extra[5][vectorIndex]) | ~this .extra[3][vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
0544: }
0545:
0546: final public boolean canOnlyBeNull(LocalVariableBinding local) {
0547: if ((this .tagBits & NULL_FLAG_MASK) == 0
0548: || (local.type.tagBits & TagBits.IsBaseType) != 0) {
0549: return false;
0550: }
0551: int position;
0552: if ((position = local.id + this .maxFieldCount) < BitCacheSize) {
0553: // use bits
0554: return (this .nullBit1 & this .nullBit2
0555: & (~this .nullBit3 | ~this .nullBit4) & (1L << position)) != 0;
0556: }
0557: // use extra vector
0558: if (this .extra == null) {
0559: return false; // if vector not yet allocated, then not initialized
0560: }
0561: int vectorIndex;
0562: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0563: return false; // if not enough room in vector, then not initialized
0564: }
0565: return (this .extra[2][vectorIndex]
0566: & this .extra[3][vectorIndex]
0567: & (~this .extra[4][vectorIndex] | ~this .extra[5][vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
0568: }
0569:
0570: public FlowInfo copy() {
0571: // do not clone the DeadEnd
0572: if (this == DEAD_END) {
0573: return this ;
0574: }
0575: UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
0576: // copy slots
0577: copy.definiteInits = this .definiteInits;
0578: copy.potentialInits = this .potentialInits;
0579: boolean hasNullInfo = (this .tagBits & NULL_FLAG_MASK) != 0;
0580: if (hasNullInfo) {
0581: copy.nullBit1 = this .nullBit1;
0582: copy.nullBit2 = this .nullBit2;
0583: copy.nullBit3 = this .nullBit3;
0584: copy.nullBit4 = this .nullBit4;
0585: }
0586: copy.tagBits = this .tagBits;
0587: copy.maxFieldCount = this .maxFieldCount;
0588: if (this .extra != null) {
0589: int length;
0590: copy.extra = new long[extraLength][];
0591: System
0592: .arraycopy(
0593: this .extra[0],
0594: 0,
0595: (copy.extra[0] = new long[length = this .extra[0].length]),
0596: 0, length);
0597: System.arraycopy(this .extra[1], 0,
0598: (copy.extra[1] = new long[length]), 0, length);
0599: if (hasNullInfo) {
0600: for (int j = 2; j < extraLength; j++) {
0601: System.arraycopy(this .extra[j], 0,
0602: (copy.extra[j] = new long[length]), 0,
0603: length);
0604: }
0605: } else {
0606: for (int j = 2; j < extraLength; j++) {
0607: copy.extra[j] = new long[length];
0608: }
0609: }
0610: }
0611: return copy;
0612: }
0613:
0614: /**
0615: * Discard definite inits and potential inits from this, then return this.
0616: * The returned flow info only holds null related information.
0617: * @return this flow info, minus definite inits and potential inits
0618: */
0619: public UnconditionalFlowInfo discardInitializationInfo() {
0620: if (this == DEAD_END) {
0621: return this ;
0622: }
0623: this .definiteInits = this .potentialInits = 0;
0624: if (this .extra != null) {
0625: for (int i = 0, length = this .extra[0].length; i < length; i++) {
0626: this .extra[0][i] = this .extra[1][i] = 0;
0627: }
0628: }
0629: return this ;
0630: }
0631:
0632: /**
0633: * Remove local variables information from this flow info and return this.
0634: * @return this, deprived from any local variable information
0635: */
0636: public UnconditionalFlowInfo discardNonFieldInitializations() {
0637: int limit = this .maxFieldCount;
0638: if (limit < BitCacheSize) {
0639: long mask = (1L << limit) - 1;
0640: this .definiteInits &= mask;
0641: this .potentialInits &= mask;
0642: this .nullBit1 &= mask;
0643: this .nullBit2 &= mask;
0644: this .nullBit3 &= mask;
0645: this .nullBit4 &= mask;
0646: }
0647: // use extra vector
0648: if (this .extra == null) {
0649: return this ; // if vector not yet allocated, then not initialized
0650: }
0651: int vectorIndex, length = this .extra[0].length;
0652: if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
0653: return this ; // not enough room yet
0654: }
0655: if (vectorIndex >= 0) {
0656: // else we only have complete non field array items left
0657: long mask = (1L << (limit % BitCacheSize)) - 1;
0658: for (int j = 0; j < extraLength; j++) {
0659: this .extra[j][vectorIndex] &= mask;
0660: }
0661: }
0662: for (int i = vectorIndex + 1; i < length; i++) {
0663: for (int j = 0; j < extraLength; j++) {
0664: this .extra[j][i] = 0;
0665: }
0666: }
0667: return this ;
0668: }
0669:
0670: public FlowInfo initsWhenFalse() {
0671: return this ;
0672: }
0673:
0674: public FlowInfo initsWhenTrue() {
0675: return this ;
0676: }
0677:
0678: /**
0679: * Check status of definite assignment at a given position.
0680: * It deals with the dual representation of the InitializationInfo2:
0681: * bits for the first 64 entries, then an array of booleans.
0682: */
0683: final private boolean isDefinitelyAssigned(int position) {
0684: if (position < BitCacheSize) {
0685: // use bits
0686: return (this .definiteInits & (1L << position)) != 0;
0687: }
0688: // use extra vector
0689: if (this .extra == null)
0690: return false; // if vector not yet allocated, then not initialized
0691: int vectorIndex;
0692: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0693: return false; // if not enough room in vector, then not initialized
0694: }
0695: return ((this .extra[0][vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
0696: }
0697:
0698: final public boolean isDefinitelyAssigned(FieldBinding field) {
0699: // Mirrored in CodeStream.isDefinitelyAssigned(..)
0700: // do not want to complain in unreachable code
0701: if ((this .tagBits & UNREACHABLE) != 0) {
0702: return true;
0703: }
0704: return isDefinitelyAssigned(field.id);
0705: }
0706:
0707: final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
0708: // do not want to complain in unreachable code if local declared in reachable code
0709: if ((this .tagBits & UNREACHABLE) != 0
0710: && (local.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0) {
0711: return true;
0712: }
0713: return isDefinitelyAssigned(local.id + this .maxFieldCount);
0714: }
0715:
0716: final public boolean isDefinitelyNonNull(LocalVariableBinding local) {
0717: // do not want to complain in unreachable code
0718: if ((this .tagBits & UNREACHABLE) != 0
0719: || (this .tagBits & NULL_FLAG_MASK) == 0) {
0720: return false;
0721: }
0722: if ((local.type.tagBits & TagBits.IsBaseType) != 0
0723: || local.constant() != Constant.NotAConstant) { // String instances
0724: return true;
0725: }
0726: int position = local.id + this .maxFieldCount;
0727: if (position < BitCacheSize) { // use bits
0728: return ((this .nullBit1 & this .nullBit3 & (~this .nullBit2 | this .nullBit4)) & (1L << position)) != 0;
0729: }
0730: // use extra vector
0731: if (this .extra == null) {
0732: return false; // if vector not yet allocated, then not initialized
0733: }
0734: int vectorIndex;
0735: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0736: return false; // if not enough room in vector, then not initialized
0737: }
0738: return ((this .extra[2][vectorIndex]
0739: & this .extra[4][vectorIndex] & (~this .extra[3][vectorIndex] | this .extra[5][vectorIndex])) & (1L << (position % BitCacheSize))) != 0;
0740: }
0741:
0742: final public boolean isDefinitelyNull(LocalVariableBinding local) {
0743: // do not want to complain in unreachable code
0744: if ((this .tagBits & UNREACHABLE) != 0
0745: || (this .tagBits & NULL_FLAG_MASK) == 0
0746: || (local.type.tagBits & TagBits.IsBaseType) != 0) {
0747: return false;
0748: }
0749: int position = local.id + this .maxFieldCount;
0750: if (position < BitCacheSize) { // use bits
0751: return ((this .nullBit1 & this .nullBit2 & (~this .nullBit3 | ~this .nullBit4)) & (1L << position)) != 0;
0752: }
0753: // use extra vector
0754: if (this .extra == null) {
0755: return false; // if vector not yet allocated, then not initialized
0756: }
0757: int vectorIndex;
0758: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0759: return false; // if not enough room in vector, then not initialized
0760: }
0761: return ((this .extra[2][vectorIndex]
0762: & this .extra[3][vectorIndex] & (~this .extra[4][vectorIndex] | ~this .extra[5][vectorIndex])) & (1L << (position % BitCacheSize))) != 0;
0763: }
0764:
0765: final public boolean isDefinitelyUnknown(LocalVariableBinding local) {
0766: // do not want to complain in unreachable code
0767: if ((this .tagBits & UNREACHABLE) != 0
0768: || (this .tagBits & NULL_FLAG_MASK) == 0) {
0769: return false;
0770: }
0771: int position = local.id + this .maxFieldCount;
0772: if (position < BitCacheSize) { // use bits
0773: return ((this .nullBit1 & this .nullBit4 & ~this .nullBit2 & ~this .nullBit3) & (1L << position)) != 0;
0774: }
0775: // use extra vector
0776: if (this .extra == null) {
0777: return false; // if vector not yet allocated, then not initialized
0778: }
0779: int vectorIndex;
0780: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0781: return false; // if not enough room in vector, then not initialized
0782: }
0783: return ((this .extra[2][vectorIndex]
0784: & this .extra[5][vectorIndex]
0785: & ~this .extra[3][vectorIndex] & ~this .extra[4][vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
0786: }
0787:
0788: /**
0789: * Check status of potential assignment at a given position.
0790: */
0791: final private boolean isPotentiallyAssigned(int position) {
0792: // id is zero-based
0793: if (position < BitCacheSize) {
0794: // use bits
0795: return (this .potentialInits & (1L << position)) != 0;
0796: }
0797: // use extra vector
0798: if (this .extra == null) {
0799: return false; // if vector not yet allocated, then not initialized
0800: }
0801: int vectorIndex;
0802: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0803: return false; // if not enough room in vector, then not initialized
0804: }
0805: return ((this .extra[1][vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
0806: }
0807:
0808: final public boolean isPotentiallyAssigned(FieldBinding field) {
0809: return isPotentiallyAssigned(field.id);
0810: }
0811:
0812: final public boolean isPotentiallyAssigned(
0813: LocalVariableBinding local) {
0814: // final constants are inlined, and thus considered as always initialized
0815: if (local.constant() != Constant.NotAConstant) {
0816: return true;
0817: }
0818: return isPotentiallyAssigned(local.id + this .maxFieldCount);
0819: }
0820:
0821: final public boolean isPotentiallyNonNull(LocalVariableBinding local) {
0822: if ((this .tagBits & NULL_FLAG_MASK) == 0
0823: || (local.type.tagBits & TagBits.IsBaseType) != 0) {
0824: return false;
0825: }
0826: int position;
0827: if ((position = local.id + this .maxFieldCount) < BitCacheSize) {
0828: // use bits
0829: return ((this .nullBit3 & (~this .nullBit1 | ~this .nullBit2)) & (1L << position)) != 0;
0830: }
0831: // use extra vector
0832: if (this .extra == null) {
0833: return false; // if vector not yet allocated, then not initialized
0834: }
0835: int vectorIndex;
0836: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0837: return false; // if not enough room in vector, then not initialized
0838: }
0839: return ((this .extra[4][vectorIndex] & (~this .extra[2][vectorIndex] | ~this .extra[3][vectorIndex])) & (1L << (position % BitCacheSize))) != 0;
0840: }
0841:
0842: final public boolean isPotentiallyNull(LocalVariableBinding local) {
0843: if ((this .tagBits & NULL_FLAG_MASK) == 0
0844: || (local.type.tagBits & TagBits.IsBaseType) != 0) {
0845: return false;
0846: }
0847: int position;
0848: if ((position = local.id + this .maxFieldCount) < BitCacheSize) {
0849: // use bits
0850: return ((this .nullBit2 & (~this .nullBit1 | ~this .nullBit3)) & (1L << position)) != 0;
0851: }
0852: // use extra vector
0853: if (this .extra == null) {
0854: return false; // if vector not yet allocated, then not initialized
0855: }
0856: int vectorIndex;
0857: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0858: return false; // if not enough room in vector, then not initialized
0859: }
0860: return ((this .extra[3][vectorIndex] & (~this .extra[2][vectorIndex] | ~this .extra[4][vectorIndex])) & (1L << (position % BitCacheSize))) != 0;
0861: }
0862:
0863: final public boolean isPotentiallyUnknown(LocalVariableBinding local) {
0864: // do not want to complain in unreachable code
0865: if ((this .tagBits & UNREACHABLE) != 0
0866: || (this .tagBits & NULL_FLAG_MASK) == 0) {
0867: return false;
0868: }
0869: int position = local.id + this .maxFieldCount;
0870: if (position < BitCacheSize) { // use bits
0871: return (this .nullBit4
0872: & (~this .nullBit1 | ~this .nullBit2 & ~this .nullBit3) & (1L << position)) != 0;
0873: }
0874: // use extra vector
0875: if (this .extra == null) {
0876: return false; // if vector not yet allocated, then not initialized
0877: }
0878: int vectorIndex;
0879: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0880: return false; // if not enough room in vector, then not initialized
0881: }
0882: return (this .extra[5][vectorIndex]
0883: & (~this .extra[2][vectorIndex] | ~this .extra[3][vectorIndex]
0884: & ~this .extra[4][vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
0885: }
0886:
0887: final public boolean isProtectedNonNull(LocalVariableBinding local) {
0888: if ((this .tagBits & NULL_FLAG_MASK) == 0
0889: || (local.type.tagBits & TagBits.IsBaseType) != 0) {
0890: return false;
0891: }
0892: int position;
0893: if ((position = local.id + this .maxFieldCount) < BitCacheSize) {
0894: // use bits
0895: return (this .nullBit1 & this .nullBit3 & this .nullBit4 & (1L << position)) != 0;
0896: }
0897: // use extra vector
0898: if (this .extra == null) {
0899: return false; // if vector not yet allocated, then not initialized
0900: }
0901: int vectorIndex;
0902: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0903: return false; // if not enough room in vector, then not initialized
0904: }
0905: return (this .extra[2][vectorIndex] & this .extra[4][vectorIndex]
0906: & this .extra[5][vectorIndex] & (1L << (position % BitCacheSize))) != 0;
0907: }
0908:
0909: final public boolean isProtectedNull(LocalVariableBinding local) {
0910: if ((this .tagBits & NULL_FLAG_MASK) == 0
0911: || (local.type.tagBits & TagBits.IsBaseType) != 0) {
0912: return false;
0913: }
0914: int position;
0915: if ((position = local.id + this .maxFieldCount) < BitCacheSize) {
0916: // use bits
0917: return (this .nullBit1 & this .nullBit2
0918: & (this .nullBit3 ^ this .nullBit4) & (1L << position)) != 0;
0919: }
0920: // use extra vector
0921: if (this .extra == null) {
0922: return false; // if vector not yet allocated, then not initialized
0923: }
0924: int vectorIndex;
0925: if ((vectorIndex = (position / BitCacheSize) - 1) >= this .extra[0].length) {
0926: return false; // if not enough room in vector, then not initialized
0927: }
0928: return (this .extra[2][vectorIndex]
0929: & this .extra[3][vectorIndex]
0930: & (this .extra[4][vectorIndex] ^ this .extra[5][vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
0931: }
0932:
0933: public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
0934: // protected from non-object locals in calling methods
0935: if (this != DEAD_END) {
0936: this .tagBits |= NULL_FLAG_MASK;
0937: int position;
0938: long mask;
0939: long a1, a2, a3, a4, na2;
0940: // position is zero-based
0941: if ((position = local.id + this .maxFieldCount) < BitCacheSize) {
0942: // use bits
0943: if (((mask = 1L << position) & (a1 = this .nullBit1)
0944: & (na2 = ~(a2 = this .nullBit2))
0945: & ~(a3 = this .nullBit3) & (a4 = this .nullBit4)) != 0) {
0946: this .nullBit4 &= ~mask;
0947: } else if ((mask & a1 & na2 & a3) == 0) {
0948: this .nullBit4 |= mask;
0949: if ((mask & a1) == 0) {
0950: if ((mask & a2 & (a3 ^ a4)) != 0) {
0951: this .nullBit2 &= ~mask;
0952: } else if ((mask & (a2 | a3 | a4)) == 0) {
0953: this .nullBit2 |= mask;
0954: }
0955: }
0956: }
0957: this .nullBit1 |= mask;
0958: this .nullBit3 |= mask;
0959: if (coverageTestFlag && coverageTestId == 15) {
0960: this .nullBit4 = ~0;
0961: }
0962: } else {
0963: // use extra vector
0964: int vectorIndex = (position / BitCacheSize) - 1;
0965: if (this .extra == null) {
0966: int length = vectorIndex + 1;
0967: this .extra = new long[extraLength][];
0968: for (int j = 0; j < extraLength; j++) {
0969: this .extra[j] = new long[length];
0970: }
0971: if (coverageTestFlag && coverageTestId == 16) {
0972: throw new AssertionFailedException(
0973: "COVERAGE 16"); //$NON-NLS-1$
0974: }
0975: } else {
0976: int oldLength;
0977: if (vectorIndex >= (oldLength = this .extra[0].length)) {
0978: int newLength = vectorIndex + 1;
0979: for (int j = 0; j < extraLength; j++) {
0980: System
0981: .arraycopy(
0982: this .extra[j],
0983: 0,
0984: (this .extra[j] = new long[newLength]),
0985: 0, oldLength);
0986: }
0987: if (coverageTestFlag && coverageTestId == 17) {
0988: throw new AssertionFailedException(
0989: "COVERAGE 17"); //$NON-NLS-1$
0990: }
0991: }
0992: }
0993: // MACRO :'b,'es/nullBit\(.\)/extra[\1 + 1][vectorIndex]/gc
0994: if (((mask = 1L << (position % BitCacheSize))
0995: & (a1 = this .extra[1 + 1][vectorIndex])
0996: & (na2 = ~(a2 = this .extra[2 + 1][vectorIndex]))
0997: & ~(a3 = this .extra[3 + 1][vectorIndex]) & (a4 = this .extra[4 + 1][vectorIndex])) != 0) {
0998: this .extra[4 + 1][vectorIndex] &= ~mask;
0999: } else if ((mask & a1 & na2 & a3) == 0) {
1000: this .extra[4 + 1][vectorIndex] |= mask;
1001: if ((mask & a1) == 0) {
1002: if ((mask & a2 & (a3 ^ a4)) != 0) {
1003: this .extra[2 + 1][vectorIndex] &= ~mask;
1004: } else if ((mask & (a2 | a3 | a4)) == 0) {
1005: this .extra[2 + 1][vectorIndex] |= mask;
1006: }
1007: }
1008: }
1009: this .extra[1 + 1][vectorIndex] |= mask;
1010: this .extra[3 + 1][vectorIndex] |= mask;
1011: if (coverageTestFlag && coverageTestId == 18) {
1012: this .extra[5][vectorIndex] = ~0;
1013: }
1014: }
1015: }
1016: }
1017:
1018: public void markAsComparedEqualToNull(LocalVariableBinding local) {
1019: // protected from non-object locals in calling methods
1020: if (this != DEAD_END) {
1021: this .tagBits |= NULL_FLAG_MASK;
1022: int position;
1023: long mask;
1024: // position is zero-based
1025: if ((position = local.id + this .maxFieldCount) < BitCacheSize) {
1026: // use bits
1027: if (((mask = 1L << position) & this .nullBit1) != 0) {
1028: if ((mask & (~this .nullBit2 | this .nullBit3 | ~this .nullBit4)) != 0) {
1029: this .nullBit4 &= ~mask;
1030: }
1031: } else if ((mask & this .nullBit4) != 0) {
1032: this .nullBit3 &= ~mask;
1033: } else {
1034: if ((mask & this .nullBit2) != 0) {
1035: this .nullBit3 &= ~mask;
1036: this .nullBit4 |= mask;
1037: } else {
1038: this .nullBit3 |= mask;
1039: }
1040: }
1041: this .nullBit1 |= mask;
1042: this .nullBit2 |= mask;
1043: if (coverageTestFlag && coverageTestId == 19) {
1044: this .nullBit4 = ~0;
1045: }
1046: } else {
1047: // use extra vector
1048: int vectorIndex = (position / BitCacheSize) - 1;
1049: mask = 1L << (position % BitCacheSize);
1050: if (this .extra == null) {
1051: int length = vectorIndex + 1;
1052: this .extra = new long[extraLength][];
1053: for (int j = 0; j < extraLength; j++) {
1054: this .extra[j] = new long[length];
1055: }
1056: if (coverageTestFlag && coverageTestId == 20) {
1057: throw new AssertionFailedException(
1058: "COVERAGE 20"); //$NON-NLS-1$
1059: }
1060: } else {
1061: int oldLength;
1062: if (vectorIndex >= (oldLength = this .extra[0].length)) {
1063: int newLength = vectorIndex + 1;
1064: for (int j = 0; j < extraLength; j++) {
1065: System
1066: .arraycopy(
1067: this .extra[j],
1068: 0,
1069: (this .extra[j] = new long[newLength]),
1070: 0, oldLength);
1071: }
1072: if (coverageTestFlag && coverageTestId == 21) {
1073: throw new AssertionFailedException(
1074: "COVERAGE 21"); //$NON-NLS-1$
1075: }
1076: }
1077: }
1078: if ((mask & this .extra[1 + 1][vectorIndex]) != 0) {
1079: if ((mask & (~this .extra[2 + 1][vectorIndex]
1080: | this .extra[3 + 1][vectorIndex] | ~this .extra[4 + 1][vectorIndex])) != 0) {
1081: this .extra[4 + 1][vectorIndex] &= ~mask;
1082: }
1083: } else if ((mask & this .extra[4 + 1][vectorIndex]) != 0) {
1084: this .extra[3 + 1][vectorIndex] &= ~mask;
1085: } else {
1086: if ((mask & this .extra[2 + 1][vectorIndex]) != 0) {
1087: this .extra[3 + 1][vectorIndex] &= ~mask;
1088: this .extra[4 + 1][vectorIndex] |= mask;
1089: } else {
1090: this .extra[3 + 1][vectorIndex] |= mask;
1091: }
1092: }
1093: this .extra[1 + 1][vectorIndex] |= mask;
1094: this .extra[2 + 1][vectorIndex] |= mask;
1095: }
1096: }
1097: }
1098:
1099: /**
1100: * Record a definite assignment at a given position.
1101: */
1102: final private void markAsDefinitelyAssigned(int position) {
1103:
1104: if (this != DEAD_END) {
1105: // position is zero-based
1106: if (position < BitCacheSize) {
1107: // use bits
1108: long mask;
1109: this .definiteInits |= (mask = 1L << position);
1110: this .potentialInits |= mask;
1111: } else {
1112: // use extra vector
1113: int vectorIndex = (position / BitCacheSize) - 1;
1114: if (this .extra == null) {
1115: int length = vectorIndex + 1;
1116: this .extra = new long[extraLength][];
1117: for (int j = 0; j < extraLength; j++) {
1118: this .extra[j] = new long[length];
1119: }
1120: } else {
1121: int oldLength; // might need to grow the arrays
1122: if (vectorIndex >= (oldLength = this .extra[0].length)) {
1123: for (int j = 0; j < extraLength; j++) {
1124: System
1125: .arraycopy(
1126: this .extra[j],
1127: 0,
1128: (this .extra[j] = new long[vectorIndex + 1]),
1129: 0, oldLength);
1130: }
1131: }
1132: }
1133: long mask;
1134: this .extra[0][vectorIndex] |= (mask = 1L << (position % BitCacheSize));
1135: this .extra[1][vectorIndex] |= mask;
1136: }
1137: }
1138: }
1139:
1140: public void markAsDefinitelyAssigned(FieldBinding field) {
1141: if (this != DEAD_END)
1142: markAsDefinitelyAssigned(field.id);
1143: }
1144:
1145: public void markAsDefinitelyAssigned(LocalVariableBinding local) {
1146: if (this != DEAD_END)
1147: markAsDefinitelyAssigned(local.id + this .maxFieldCount);
1148: }
1149:
1150: public void markAsDefinitelyNonNull(LocalVariableBinding local) {
1151: // protected from non-object locals in calling methods
1152: if (this != DEAD_END) {
1153: this .tagBits |= NULL_FLAG_MASK;
1154: long mask;
1155: int position;
1156: // position is zero-based
1157: if ((position = local.id + this .maxFieldCount) < BitCacheSize) { // use bits
1158: // set assigned non null
1159: this .nullBit1 |= (mask = 1L << position);
1160: this .nullBit3 |= mask;
1161: // clear others
1162: this .nullBit2 &= (mask = ~mask);
1163: this .nullBit4 &= mask;
1164: if (coverageTestFlag && coverageTestId == 22) {
1165: this .nullBit1 = 0;
1166: }
1167: } else {
1168: // use extra vector
1169: int vectorIndex;
1170: this .extra[2][vectorIndex = (position / BitCacheSize) - 1] |= (mask = 1L << (position % BitCacheSize));
1171: this .extra[4][vectorIndex] |= mask;
1172: this .extra[3][vectorIndex] &= (mask = ~mask);
1173: this .extra[5][vectorIndex] &= mask;
1174: if (coverageTestFlag && coverageTestId == 23) {
1175: this .extra[2][vectorIndex] = 0;
1176: }
1177: }
1178: }
1179: }
1180:
1181: public void markAsDefinitelyNull(LocalVariableBinding local) {
1182: // protected from non-object locals in calling methods
1183: if (this != DEAD_END) {
1184: this .tagBits |= NULL_FLAG_MASK;
1185: long mask;
1186: int position;
1187: // position is zero-based
1188: if ((position = local.id + this .maxFieldCount) < BitCacheSize) { // use bits
1189: // mark assigned null
1190: this .nullBit1 |= (mask = 1L << position);
1191: this .nullBit2 |= mask;
1192: // clear others
1193: this .nullBit3 &= (mask = ~mask);
1194: this .nullBit4 &= mask;
1195: if (coverageTestFlag && coverageTestId == 24) {
1196: this .nullBit4 = ~0;
1197: }
1198: } else {
1199: // use extra vector
1200: int vectorIndex;
1201: this .extra[2][vectorIndex = (position / BitCacheSize) - 1] |= (mask = 1L << (position % BitCacheSize));
1202: this .extra[3][vectorIndex] |= mask;
1203: this .extra[4][vectorIndex] &= (mask = ~mask);
1204: this .extra[5][vectorIndex] &= mask;
1205: if (coverageTestFlag && coverageTestId == 25) {
1206: this .extra[5][vectorIndex] = ~0;
1207: }
1208: }
1209: }
1210: }
1211:
1212: /**
1213: * Mark a local as having been assigned to an unknown value.
1214: * @param local the local to mark
1215: */
1216: // PREMATURE may try to get closer to markAsDefinitelyAssigned, but not
1217: // obvious
1218: public void markAsDefinitelyUnknown(LocalVariableBinding local) {
1219: // protected from non-object locals in calling methods
1220: if (this != DEAD_END) {
1221: this .tagBits |= NULL_FLAG_MASK;
1222: long mask;
1223: int position;
1224: // position is zero-based
1225: if ((position = local.id + this .maxFieldCount) < BitCacheSize) {
1226: // use bits
1227: // mark assigned null
1228: this .nullBit1 |= (mask = 1L << position);
1229: this .nullBit4 |= mask;
1230: // clear others
1231: this .nullBit2 &= (mask = ~mask);
1232: this .nullBit3 &= mask;
1233: if (coverageTestFlag && coverageTestId == 26) {
1234: this .nullBit4 = 0;
1235: }
1236: } else {
1237: // use extra vector
1238: int vectorIndex;
1239: this .extra[2][vectorIndex = (position / BitCacheSize) - 1] |= (mask = 1L << (position % BitCacheSize));
1240: this .extra[5][vectorIndex] |= mask;
1241: this .extra[3][vectorIndex] &= (mask = ~mask);
1242: this .extra[4][vectorIndex] &= mask;
1243: if (coverageTestFlag && coverageTestId == 27) {
1244: this .extra[5][vectorIndex] = 0;
1245: }
1246: }
1247: }
1248: }
1249:
1250: public UnconditionalFlowInfo mergedWith(
1251: UnconditionalFlowInfo otherInits) {
1252: if ((otherInits.tagBits & UNREACHABLE) != 0 && this != DEAD_END) {
1253: if (coverageTestFlag && coverageTestId == 28) {
1254: throw new AssertionFailedException("COVERAGE 28"); //$NON-NLS-1$
1255: }
1256: return this ;
1257: }
1258: if ((this .tagBits & UNREACHABLE) != 0) {
1259: if (coverageTestFlag && coverageTestId == 29) {
1260: throw new AssertionFailedException("COVERAGE 29"); //$NON-NLS-1$
1261: }
1262: return (UnconditionalFlowInfo) otherInits.copy(); // make sure otherInits won't be affected
1263: }
1264:
1265: // intersection of definitely assigned variables,
1266: this .definiteInits &= otherInits.definiteInits;
1267: // union of potentially set ones
1268: this .potentialInits |= otherInits.potentialInits;
1269:
1270: // null combinations
1271: boolean this HasNulls = (this .tagBits & NULL_FLAG_MASK) != 0, otherHasNulls = (otherInits.tagBits & NULL_FLAG_MASK) != 0, this HadNulls = this HasNulls;
1272: long a1, a2, a3, a4, na1, na2, na3, na4, nb1, nb2, nb3, nb4, b1, b2, b3, b4;
1273: if (this HadNulls) {
1274: if (otherHasNulls) {
1275: this .nullBit1 = (a2 = this .nullBit2)
1276: & (a3 = this .nullBit3)
1277: & (a4 = this .nullBit4)
1278: & (b1 = otherInits.nullBit1)
1279: & (nb2 = ~(b2 = otherInits.nullBit2))
1280: | (a1 = this .nullBit1)
1281: & (b1
1282: & (a3
1283: & a4
1284: & (b3 = otherInits.nullBit3)
1285: & (b4 = otherInits.nullBit4)
1286: | (na2 = ~a2)
1287: & nb2
1288: & ((nb4 = ~b4) | (na4 = ~a4) | (na3 = ~a3)
1289: & (nb3 = ~b3)) | a2
1290: & b2
1291: & ((na4 | na3) & (nb4 | nb3))) | na2
1292: & b2 & b3 & b4);
1293: this .nullBit2 = b2
1294: & (nb3 | (nb1 = ~b1) | a3 & (a4 | (na1 = ~a1))
1295: & nb4) | a2
1296: & (b2 | na4 & b3 & (b4 | nb1) | na3 | na1);
1297: this .nullBit3 = b3
1298: & (nb2 & b4 | nb1 | a3 & (na4 & nb4 | a4 & b4))
1299: | a3 & (na2 & a4 | na1) | (a2 | na1) & b1 & nb2
1300: & nb4 | a1 & na2 & na4 & (b2 | nb1);
1301: this .nullBit4 = na3
1302: & (nb1 & nb3 & b4 | b1
1303: & (nb2 & nb3 | a4 & b2 & nb4) | na1
1304: & a4 & (nb3 | b1 & b2))
1305: | a3
1306: & a4
1307: & (b3 & b4 | b1 & nb2)
1308: | na2
1309: & (nb1 & b4 | b1 & nb3 | na1 & a4)
1310: & nb2
1311: | a1
1312: & (na3
1313: & (nb3 & b4 | b1 & b2 & b3 & nb4 | na2
1314: & (nb3 | nb2)) | na2 & b3 & b4 | a2
1315: & (nb1 & b4 | a3 & na4 & b1) & nb3);
1316: if (coverageTestFlag && coverageTestId == 30) {
1317: this .nullBit4 = ~0;
1318: }
1319: } else { // other has no null info
1320: a1 = this .nullBit1;
1321: this .nullBit1 = 0;
1322: this .nullBit2 = (a2 = this .nullBit2)
1323: & (na3 = ~(a3 = this .nullBit3) | (na1 = ~a1));
1324: this .nullBit3 = a3
1325: & ((na2 = ~a2) & (a4 = this .nullBit4) | na1)
1326: | a1 & na2 & ~a4;
1327: this .nullBit4 = (na3 | na2) & na1 & a4 | a1 & na3 & na2;
1328: if (coverageTestFlag && coverageTestId == 31) {
1329: this .nullBit4 = ~0;
1330: }
1331: }
1332: } else if (otherHasNulls) { // only other had nulls
1333: this .nullBit1 = 0;
1334: this .nullBit2 = (b2 = otherInits.nullBit2)
1335: & (nb3 = ~(b3 = otherInits.nullBit3)
1336: | (nb1 = ~(b1 = otherInits.nullBit1)));
1337: this .nullBit3 = b3
1338: & ((nb2 = ~b2) & (b4 = otherInits.nullBit4) | nb1)
1339: | b1 & nb2 & ~b4;
1340: this .nullBit4 = (nb3 | nb2) & nb1 & b4 | b1 & nb3 & nb2;
1341: if (coverageTestFlag && coverageTestId == 32) {
1342: this .nullBit4 = ~0;
1343: }
1344: this HasNulls =
1345: // redundant with the three following ones
1346: this .nullBit2 != 0 || this .nullBit3 != 0
1347: || this .nullBit4 != 0;
1348: }
1349:
1350: // treating extra storage
1351: if (this .extra != null || otherInits.extra != null) {
1352: int mergeLimit = 0, copyLimit = 0, resetLimit = 0;
1353: int i;
1354: if (this .extra != null) {
1355: if (otherInits.extra != null) {
1356: // both sides have extra storage
1357: int length, otherLength;
1358: if ((length = this .extra[0].length) < (otherLength = otherInits.extra[0].length)) {
1359: // current storage is shorter -> grow current
1360: for (int j = 0; j < extraLength; j++) {
1361: System
1362: .arraycopy(
1363: this .extra[j],
1364: 0,
1365: (this .extra[j] = new long[otherLength]),
1366: 0, length);
1367: }
1368: mergeLimit = length;
1369: copyLimit = otherLength;
1370: if (coverageTestFlag && coverageTestId == 33) {
1371: throw new AssertionFailedException(
1372: "COVERAGE 33"); //$NON-NLS-1$
1373: }
1374: } else {
1375: // current storage is longer
1376: mergeLimit = otherLength;
1377: resetLimit = length;
1378: if (coverageTestFlag && coverageTestId == 34) {
1379: throw new AssertionFailedException(
1380: "COVERAGE 34"); //$NON-NLS-1$
1381: }
1382: }
1383: } else {
1384: resetLimit = this .extra[0].length;
1385: if (coverageTestFlag && coverageTestId == 35) {
1386: throw new AssertionFailedException(
1387: "COVERAGE 35"); //$NON-NLS-1$
1388: }
1389: }
1390: } else if (otherInits.extra != null) {
1391: // no storage here, but other has extra storage.
1392: int otherLength = otherInits.extra[0].length;
1393: this .extra = new long[extraLength][];
1394: for (int j = 0; j < extraLength; j++) {
1395: this .extra[j] = new long[otherLength];
1396: }
1397: System.arraycopy(otherInits.extra[1], 0, this .extra[1],
1398: 0, otherLength);
1399: copyLimit = otherLength;
1400: if (coverageTestFlag && coverageTestId == 36) {
1401: throw new AssertionFailedException("COVERAGE 36"); //$NON-NLS-1$
1402: }
1403: }
1404: // MACRO :'b,'es/nullBit\(.\)/extra[\1 + 1][i]/g
1405: // manage definite assignment
1406: for (i = 0; i < mergeLimit; i++) {
1407: this .extra[0][i] &= otherInits.extra[0][i];
1408: this .extra[1][i] |= otherInits.extra[1][i];
1409: }
1410: for (; i < copyLimit; i++) {
1411: this .extra[1][i] = otherInits.extra[1][i];
1412: }
1413: for (; i < resetLimit; i++) {
1414: this .extra[0][i] = 0;
1415: }
1416: // refine null bits requirements
1417: if (!otherHasNulls) {
1418: if (resetLimit < mergeLimit) {
1419: resetLimit = mergeLimit;
1420: }
1421: copyLimit = 0; // no need to carry inexisting nulls
1422: mergeLimit = 0;
1423: }
1424: if (!this HadNulls) {
1425: resetLimit = 0; // no need to reset anything
1426: }
1427: // compose nulls
1428: for (i = 0; i < mergeLimit; i++) {
1429: this .extra[1 + 1][i] = (a2 = this .extra[2 + 1][i])
1430: & (a3 = this .extra[3 + 1][i])
1431: & (a4 = this .extra[4 + 1][i])
1432: & (b1 = otherInits.extra[1 + 1][i])
1433: & (nb2 = ~(b2 = otherInits.extra[2 + 1][i]))
1434: | (a1 = this .extra[1 + 1][i])
1435: & (b1
1436: & (a3
1437: & a4
1438: & (b3 = otherInits.extra[3 + 1][i])
1439: & (b4 = otherInits.extra[4 + 1][i])
1440: | (na2 = ~a2)
1441: & nb2
1442: & ((nb4 = ~b4) | (na4 = ~a4) | (na3 = ~a3)
1443: & (nb3 = ~b3)) | a2
1444: & b2
1445: & ((na4 | na3) & (nb4 | nb3))) | na2
1446: & b2 & b3 & b4);
1447: this .extra[2 + 1][i] = b2
1448: & (nb3 | (nb1 = ~b1) | a3 & (a4 | (na1 = ~a1))
1449: & nb4) | a2
1450: & (b2 | na4 & b3 & (b4 | nb1) | na3 | na1);
1451: this .extra[3 + 1][i] = b3
1452: & (nb2 & b4 | nb1 | a3 & (na4 & nb4 | a4 & b4))
1453: | a3 & (na2 & a4 | na1) | (a2 | na1) & b1 & nb2
1454: & nb4 | a1 & na2 & na4 & (b2 | nb1);
1455: this .extra[4 + 1][i] = na3
1456: & (nb1 & nb3 & b4 | b1
1457: & (nb2 & nb3 | a4 & b2 & nb4) | na1
1458: & a4 & (nb3 | b1 & b2))
1459: | a3
1460: & a4
1461: & (b3 & b4 | b1 & nb2)
1462: | na2
1463: & (nb1 & b4 | b1 & nb3 | na1 & a4)
1464: & nb2
1465: | a1
1466: & (na3
1467: & (nb3 & b4 | b1 & b2 & b3 & nb4 | na2
1468: & (nb3 | nb2)) | na2 & b3 & b4 | a2
1469: & (nb1 & b4 | a3 & na4 & b1) & nb3);
1470: this HasNulls = this HasNulls || this .extra[3][i] != 0
1471: || this .extra[4][i] != 0
1472: || this .extra[5][i] != 0;
1473: if (coverageTestFlag && coverageTestId == 37) {
1474: this .extra[5][i] = ~0;
1475: }
1476: }
1477: for (; i < copyLimit; i++) {
1478: this .extra[1 + 1][i] = 0;
1479: this .extra[2 + 1][i] = (b2 = otherInits.extra[2 + 1][i])
1480: & (nb3 = ~(b3 = otherInits.extra[3 + 1][i])
1481: | (nb1 = ~(b1 = otherInits.extra[1 + 1][i])));
1482: this .extra[3 + 1][i] = b3
1483: & ((nb2 = ~b2)
1484: & (b4 = otherInits.extra[4 + 1][i]) | nb1)
1485: | b1 & nb2 & ~b4;
1486: this .extra[4 + 1][i] = (nb3 | nb2) & nb1 & b4 | b1
1487: & nb3 & nb2;
1488: this HasNulls = this HasNulls || this .extra[3][i] != 0
1489: || this .extra[4][i] != 0
1490: || this .extra[5][i] != 0;
1491: if (coverageTestFlag && coverageTestId == 38) {
1492: this .extra[5][i] = ~0;
1493: }
1494: }
1495: for (; i < resetLimit; i++) {
1496: a1 = this .extra[1 + 1][i];
1497: this .extra[1 + 1][i] = 0;
1498: this .extra[2 + 1][i] = (a2 = this .extra[2 + 1][i])
1499: & (na3 = ~(a3 = this .extra[3 + 1][i])
1500: | (na1 = ~a1));
1501: this .extra[3 + 1][i] = a3
1502: & ((na2 = ~a2) & (a4 = this .extra[4 + 1][i]) | na1)
1503: | a1 & na2 & ~a4;
1504: this .extra[4 + 1][i] = (na3 | na2) & na1 & a4 | a1
1505: & na3 & na2;
1506: this HasNulls = this HasNulls || this .extra[3][i] != 0
1507: || this .extra[4][i] != 0
1508: || this .extra[5][i] != 0;
1509: if (coverageTestFlag && coverageTestId == 39) {
1510: this .extra[5][i] = ~0;
1511: }
1512: }
1513: }
1514: if (this HasNulls) {
1515: this .tagBits |= NULL_FLAG_MASK;
1516: } else {
1517: this .tagBits &= ~NULL_FLAG_MASK;
1518: }
1519: return this ;
1520: }
1521:
1522: /*
1523: * Answer the total number of fields in enclosing types of a given type
1524: */
1525: static int numberOfEnclosingFields(ReferenceBinding type) {
1526: int count = 0;
1527: type = type.enclosingType();
1528: while (type != null) {
1529: count += type.fieldCount();
1530: type = type.enclosingType();
1531: }
1532: return count;
1533: }
1534:
1535: public UnconditionalFlowInfo nullInfoLessUnconditionalCopy() {
1536: if (this == DEAD_END) {
1537: return this ;
1538: }
1539: UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
1540: copy.definiteInits = this .definiteInits;
1541: copy.potentialInits = this .potentialInits;
1542: copy.tagBits = this .tagBits & ~NULL_FLAG_MASK;
1543: copy.maxFieldCount = this .maxFieldCount;
1544: if (this .extra != null) {
1545: int length;
1546: copy.extra = new long[extraLength][];
1547: System
1548: .arraycopy(
1549: this .extra[0],
1550: 0,
1551: (copy.extra[0] = new long[length = this .extra[0].length]),
1552: 0, length);
1553: System.arraycopy(this .extra[1], 0,
1554: (copy.extra[1] = new long[length]), 0, length);
1555: for (int j = 2; j < extraLength; j++) {
1556: copy.extra[j] = new long[length];
1557: }
1558: }
1559: return copy;
1560: }
1561:
1562: public FlowInfo safeInitsWhenTrue() {
1563: return copy();
1564: }
1565:
1566: public FlowInfo setReachMode(int reachMode) {
1567: if (reachMode == REACHABLE && this != DEAD_END) { // cannot modify DEAD_END
1568: this .tagBits &= ~UNREACHABLE;
1569: } else {
1570: if ((this .tagBits & UNREACHABLE) == 0) {
1571: // reset optional inits when becoming unreachable
1572: // see InitializationTest#test090 (and others)
1573: this .potentialInits = 0;
1574: if (this .extra != null) {
1575: for (int i = 0, length = this .extra[0].length; i < length; i++) {
1576: this .extra[1][i] = 0;
1577: }
1578: }
1579: }
1580: this .tagBits |= UNREACHABLE;
1581: }
1582: return this ;
1583: }
1584:
1585: public String toString() {
1586: // PREMATURE consider printing bit fields as 0001 0001 1000 0001...
1587: if (this == DEAD_END) {
1588: return "FlowInfo.DEAD_END"; //$NON-NLS-1$
1589: }
1590: if ((this .tagBits & NULL_FLAG_MASK) != 0) {
1591: if (this .extra == null) {
1592: return "FlowInfo<def: " + this .definiteInits //$NON-NLS-1$
1593: + ", pot: " + this .potentialInits //$NON-NLS-1$
1594: + ", reachable:" + ((this .tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
1595: + ", null: " + this .nullBit1 //$NON-NLS-1$
1596: + this .nullBit2 + this .nullBit3 + this .nullBit4
1597: + ">"; //$NON-NLS-1$
1598: } else {
1599: String def = "FlowInfo<def:[" + this .definiteInits, //$NON-NLS-1$
1600: pot = "], pot:[" + this .potentialInits, //$NON-NLS-1$
1601: nullS = ", null:[" + this .nullBit1 //$NON-NLS-1$
1602: + this .nullBit2 + this .nullBit3 + this .nullBit4;
1603: int i, ceil;
1604: for (i = 0, ceil = this .extra[0].length > 3 ? 3
1605: : this .extra[0].length; i < ceil; i++) {
1606: def += "," + this .extra[0][i]; //$NON-NLS-1$
1607: pot += "," + this .extra[1][i]; //$NON-NLS-1$
1608: nullS += "," + this .extra[2][i] //$NON-NLS-1$
1609: + this .extra[3][i] + this .extra[4][i]
1610: + this .extra[5][i];
1611: }
1612: if (ceil < this .extra[0].length) {
1613: def += ",..."; //$NON-NLS-1$
1614: pot += ",..."; //$NON-NLS-1$
1615: nullS += ",..."; //$NON-NLS-1$
1616: }
1617: return def
1618: + pot
1619: + "], reachable:" + ((this .tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
1620: + nullS + "]>"; //$NON-NLS-1$
1621: }
1622: } else {
1623: if (this .extra == null) {
1624: return "FlowInfo<def: " + this .definiteInits //$NON-NLS-1$
1625: + ", pot: " + this .potentialInits //$NON-NLS-1$
1626: + ", reachable:" + ((this .tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
1627: + ", no null info>"; //$NON-NLS-1$
1628: } else {
1629: String def = "FlowInfo<def:[" + this .definiteInits, //$NON-NLS-1$
1630: pot = "], pot:[" + this .potentialInits; //$NON-NLS-1$
1631: int i, ceil;
1632: for (i = 0, ceil = this .extra[0].length > 3 ? 3
1633: : this .extra[0].length; i < ceil; i++) {
1634: def += "," + this .extra[0][i]; //$NON-NLS-1$
1635: pot += "," + this .extra[1][i]; //$NON-NLS-1$
1636: }
1637: if (ceil < this .extra[0].length) {
1638: def += ",..."; //$NON-NLS-1$
1639: pot += ",..."; //$NON-NLS-1$
1640: }
1641: return def
1642: + pot
1643: + "], reachable:" + ((this .tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
1644: + ", no null info>"; //$NON-NLS-1$
1645: }
1646: }
1647: }
1648:
1649: public UnconditionalFlowInfo unconditionalCopy() {
1650: return (UnconditionalFlowInfo) copy();
1651: }
1652:
1653: public UnconditionalFlowInfo unconditionalFieldLessCopy() {
1654: // TODO (maxime) may consider leveraging null contribution verification as it is done in copy
1655: UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
1656: copy.tagBits = this .tagBits;
1657: copy.maxFieldCount = this .maxFieldCount;
1658: int limit = this .maxFieldCount;
1659: if (limit < BitCacheSize) {
1660: long mask;
1661: copy.definiteInits = this .definiteInits
1662: & (mask = ~((1L << limit) - 1));
1663: copy.potentialInits = this .potentialInits & mask;
1664: copy.nullBit1 = this .nullBit1 & mask;
1665: copy.nullBit2 = this .nullBit2 & mask;
1666: copy.nullBit3 = this .nullBit3 & mask;
1667: copy.nullBit4 = this .nullBit4 & mask;
1668: }
1669: // use extra vector
1670: if (this .extra == null) {
1671: return copy; // if vector not yet allocated, then not initialized
1672: }
1673: int vectorIndex, length, copyStart;
1674: if ((vectorIndex = (limit / BitCacheSize) - 1) >= (length = this .extra[0].length)) {
1675: return copy; // not enough room yet
1676: }
1677: long mask;
1678: copy.extra = new long[extraLength][];
1679: if ((copyStart = vectorIndex + 1) < length) {
1680: int copyLength = length - copyStart;
1681: for (int j = 0; j < extraLength; j++) {
1682: System.arraycopy(this .extra[j], copyStart,
1683: (copy.extra[j] = new long[length]), copyStart,
1684: copyLength);
1685: }
1686: } else if (vectorIndex >= 0) {
1687: for (int j = 0; j < extraLength; j++) {
1688: copy.extra[j] = new long[length];
1689: }
1690: }
1691: if (vectorIndex >= 0) {
1692: mask = ~((1L << (limit % BitCacheSize)) - 1);
1693: for (int j = 0; j < extraLength; j++) {
1694: copy.extra[j][vectorIndex] = this .extra[j][vectorIndex]
1695: & mask;
1696: }
1697: }
1698: return copy;
1699: }
1700:
1701: public UnconditionalFlowInfo unconditionalInits() {
1702: // also see conditional inits, where it requests them to merge
1703: return this ;
1704: }
1705:
1706: public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect() {
1707: return this;
1708: }
1709: }
|