implements the visitor to look for calls to wait, on java.util.concurrent classes that define await.

@param seen
the opcode of the currently visited instruction
422575
@Override
    public void sawOpcode(int seen) {
        try {
            stack.precomputation(this);

            if ((seen != Const.INVOKEVIRTUAL) || !"wait".equals(getNameConstantOperand()) || stack.getStackDepth() == 0) {
                return;
            }
            JavaClass cls = stack.getStackItem(0).getJavaClass();
            if (cls != null) {
                String clsName = cls.getClassName();
                if (concurrentAwaitClasses.contains(clsName)) {
                    bugReporter.reportBug(new BugInstance(this, BugType.SWCO_SUSPICIOUS_WAIT_ON_CONCURRENT_OBJECT.name(), NORMAL_PRIORITY).addClass(this)
                            .addMethod(this).addSourceLine(this));
                }
            }
        } catch (ClassNotFoundException cnfe) {
            bugReporter.reportMissingClass(cnfe);
        } finally {
            stack.sawOpcode(this, seen);
        }
    }
595207
@Override
    public void sawOpcode(int seen) {
        try {
            stack.precomputation(this);

            if (seen == Const.INVOKEINTERFACE) {
                processInvokeInterface();

            } else if (seen == Const.INVOKESPECIAL) {
                processInvokeSpecial();
            }
        } finally {
            stack.sawOpcode(this, seen);
        }
    }
735711
@Override
    public void sawOpcode(int seen) {
        if (seen == Const.INVOKEVIRTUAL) {
            if ("equals".equals(getNameConstantOperand()) && "(Ljava/lang/Object;)Z".equals(getSigConstantOperand())) {
                OpcodeStack.Item item = stack.getStackItem(1);
                ClassDescriptor c = DescriptorFactory.createClassDescriptorFromSignature(item.getSignature());
                check(c);

            } else if ("java/lang/Class".equals(getClassConstantOperand())
                    && ("isInstance".equals(getNameConstantOperand()) || "cast".equals(getNameConstantOperand()))) {
                OpcodeStack.Item item = stack.getStackItem(1);
                if ("Ljava/lang/Class;".equals(item.getSignature())) {
                    Object value = item.getConstant();
                    if (value instanceof String) {
                        ClassDescriptor c = DescriptorFactory.createClassDescriptor((String) value);
                        check(c);
                    }
                }

            }

        } else if (seen == Const.INSTANCEOF || seen == Const.CHECKCAST) {
            check(getClassDescriptorOperand());
        }

    }
958838
@Override
    public void sawOpcode(int seen) {
        try {
            if ((seen == Const.ATHROW) && (stack.getStackDepth() > 0)) {
                OpcodeStack.Item item = stack.getStackItem(0);
                if ("Ljava/lang/CloneNotSupportedException;".equals(item.getSignature())) {
                    throwsCNFE = true;
                }
            }
        } finally {
            stack.sawOpcode(this, seen);
        }
    }
268794
@Override
	public void sawOpcode(final int seen) {
		try {
			stack.precomputation(this);

			if (seen == Const.INVOKEINTERFACE) {
				processInvokeInterface();
			} else if (seen == Const.INVOKEVIRTUAL) {
				processInvokeVirtual();
			} else if ((seen == Const.ARETURN) && (stack.getStackDepth() > 0)) {
				OpcodeStack.Item item = stack.getStackItem(0);
				XField field = item.getXField();
				if (field != null) {
					String fieldName = field.getName();
					fieldsReported.remove(fieldName);
					if (fieldsReported.isEmpty()) {
						throw new StopOpcodeParsingException();
					}
				}
			}
		} finally {
			stack.sawOpcode(this, seen);
		}
	}
753132
@Override
    public void sawOpcode(int seen) {
        if (downwardBranchTarget == -1) {
            switch (state) {
                case SAW_NOTHING:
                    sawOpcodeAfterNothing(seen);
                break;

                case SAW_LOAD:
                    sawOpcodeAfterLoad(seen);
                break;

                case SAW_CHECKCAST:
                    sawOpcodeAfterCheckCast(seen);
                break;
            }

            int insTarget = -1;
            if (((seen >= Const.IFEQ) && (seen <= Const.IF_ACMPNE)) || (seen == Const.GOTO) || (seen == Const.GOTO_W)) {
                insTarget = getBranchTarget();
                if (insTarget < getPC()) {
                    insTarget = -1;
                }
            } else if ((seen == Const.LOOKUPSWITCH) || (seen == Const.TABLESWITCH)) {
                insTarget = this.getDefaultSwitchOffset() + getPC();
            }

            if (insTarget > downwardBranchTarget) {
                downwardBranchTarget = insTarget;
            }
        } else {
            state = State.SAW_NOTHING;
            if (getPC() >= downwardBranchTarget) {
                downwardBranchTarget = -1;
            }
        }
    }
1011865
@Override
    public void sawOpcode(final int seen) {
        Object hashCodedStringRef = null;
        try {
            stack.precomputation(this);

            switch (seen) {
                case Const.INVOKEVIRTUAL:
                    if (Values.SLASHED_JAVA_LANG_STRING.equals(getClassConstantOperand())) {
                        String calledMethodName = getNameConstantOperand();
                        String calledMethodSig = getSigConstantOperand();

                        if (("equals".equals(calledMethodName) && SignatureBuilder.SIG_OBJECT_TO_BOOLEAN.equals(calledMethodSig))
                                || ("compareTo".equals(calledMethodName) && SignatureBuilder.SIG_STRING_TO_INT.equals(calledMethodSig))
                                || ("equalsIgnoreCase".equals(calledMethodName) && SignatureBuilder.SIG_STRING_TO_BOOLEAN.equals(calledMethodSig))) {

                            if (stack.getStackDepth() > 0) {
                                OpcodeStack.Item itm = stack.getStackItem(0);
                                Object constant = itm.getConstant();
                                if ((constant != null) && constant.getClass().equals(String.class) && !lookupSwitchOnString()) {
                                    bugReporter.reportBug(new BugInstance(this, "LSC_LITERAL_STRING_COMPARISON", HIGH_PRIORITY) // very
                                                                                                                                // confident
                                            .addClass(this).addMethod(this).addSourceLine(this));
                                }
                            }
                        } else if (Values.HASHCODE.equals(calledMethodName) && (stack.getStackDepth() > 0)) {
                            OpcodeStack.Item item = stack.getStackItem(0);
                            int reg = item.getRegisterNumber();
                            if (reg >= 0) {
                                hashCodedStringRef = String.valueOf(reg);
                            } else {
                                XField xf = item.getXField();
                                if (xf != null) {
                                    hashCodedStringRef = xf.getName();
                                } else {
                                    XMethod xm = item.getReturnValueOf();
                                    if (xm != null) {
                                        hashCodedStringRef = xm.toString();
                                    }
                                }

                            }
                        }
                    }
                break;

                case Const.TABLESWITCH:
                case Const.LOOKUPSWITCH:
                    if (stack.getStackDepth() > 0) {
                        OpcodeStack.Item item = stack.getStackItem(0);
                        String stringRef = (String) item.getUserValue();
                        if (stringRef != null) {
                            int[] offsets = getSwitchOffsets();
                            BitSet bs = new BitSet();
                            int pc = getPC();
                            for (int offset : offsets) {
                                bs.set(pc + offset);
                            }
                            bs.set(pc + getDefaultSwitchOffset());
                            lookupSwitches.add(new LookupDetails(stringRef, bs));
                        }
                    }
                break;
                default:
                break;
            }

        } finally {
            stack.sawOpcode(this, seen);
            if ((hashCodedStringRef != null) && (stack.getStackDepth() > 0)) {
                OpcodeStack.Item item = stack.getStackItem(0);
                item.setUserValue(hashCodedStringRef);
            }

            if (!lookupSwitches.isEmpty()) {
                int innerMostSwitch = lookupSwitches.size() - 1;
                LookupDetails details = lookupSwitches.get(innerMostSwitch);
                if (details.getSwitchTargets().get(getPC()) && (stack.getStackDepth() > 0)) {
                    OpcodeStack.Item item = stack.getStackItem(0);
                    item.setUserValue(details.getStringReference());
                }

                // previousSetBit is a jdk1.7 api - gonna cheat cause findbugs
                // runs on 1.7
                if (getPC() >= details.getSwitchTargets().previousSetBit(Integer.MAX_VALUE)) {
                    lookupSwitches.remove(innerMostSwitch);
                }
            }
        }
    }
221478
private void sawOpcodeBug(final int seen) {
        try {
            stack.precomputation(this);

            Iterator<ForLoop> it = possibleForLoops.iterator();
            while (it.hasNext()) {
                ForLoop fl = it.next();
                switch (fl.getLoopState()) {
                    case LOOP_NOT_STARTED:
                        if (getPC() == fl.getLoopStart()) {
                            if (OpcodeUtils.isILoad(seen) && (RegisterUtils.getLoadReg(this, seen) == fl.getLoopReg())) {
                                fl.setLoopState(LoopState.LOOP_INDEX_LOADED_FOR_TEST);
                                continue;
                            }

                            it.remove();
                        }
                    break;

                    case LOOP_INDEX_LOADED_FOR_TEST:
                        if (getPC() >= fl.getLoopEnd()) {
                            it.remove();
                            continue;
                        }
                        if (seen == Const.IF_ICMPGE) {
                            if (stack.getStackDepth() > 1) {
                                OpcodeStack.Item itm = stack.getStackItem(0);
                                if (itm.getConstant() != null) {
                                    it.remove();
                                    continue;
                                }
                                XMethod constantSource = itm.getReturnValueOf();
                                if (constantSource != null) {
                                    if (!"size".equals(constantSource.getMethodDescriptor().getName())) {
                                        it.remove();
                                        continue;
                                    }
                                } else if (getPrevOpcode(1) != Const.ARRAYLENGTH) {
                                    it.remove();
                                    continue;
                                }
                            }
                            int branchTarget = getBranchTarget();
                            if ((branchTarget >= (fl.getLoopEnd() + 3)) && (branchTarget <= (fl.getLoopEnd() + 5))) {
                                fl.setLoopState(LoopState.LOOP_IN_BODY);
                                continue;
                            }
                        }
                    break;

                    case LOOP_IN_BODY:
                    case LOOP_IN_BODY_WITH_GET:
                        if ((getPC() == fl.getLoopEnd()) && (fl.getLoopState() == LoopState.LOOP_IN_BODY_WITH_GET)) {
                            bugReporter.reportBug(new BugInstance(this, "LII_LIST_INDEXED_ITERATING", NORMAL_PRIORITY).addClass(this).addMethod(this)
                                    .addSourceLineRange(this, fl.getLoopStart(), fl.getLoopEnd()));
                            it.remove();
                        }
                        if (getPC() > fl.getLoopEnd()) {
                            it.remove();
                        }

                        if (OpcodeUtils.isILoad(seen)) {
                            loopReg = RegisterUtils.getLoadReg(this, seen);
                            if (loopReg == fl.getLoopReg()) {
                                fl.setLoopRegLoaded(true);
                            }
                        } else if (fl.getLoopRegLoaded()) {
                            boolean sawGet = ((seen == Const.INVOKEINTERFACE) && Values.SLASHED_JAVA_UTIL_LIST.equals(getClassConstantOperand())
                                    && "get".equals(getNameConstantOperand()) && SignatureBuilder.SIG_INT_TO_OBJECT.equals(getSigConstantOperand()));
                            if (!sawGet) {
                                it.remove();
                            } else {
                                fl.setLoopState(LoopState.LOOP_IN_BODY_WITH_GET);
                                if (stack.getStackDepth() > 1) {
                                    OpcodeStack.Item itm = stack.getStackItem(0);
                                    if (!itm.couldBeZero()) {
                                        it.remove();
                                    } else {
                                        itm = stack.getStackItem(1);
                                        if (fl.isSecondItem(itm)) {
                                            it.remove();
                                        }
                                    }
                                }
                                fl.setLoopRegLoaded(false);
                            }
                        }
                    break;
                }
            }

        } finally {
            stack.sawOpcode(this, seen);
        }
    }
928085
@Override
    public void sawOpcode(int seen) {
        boolean allConstantStrings = false;
        boolean sawConstant = false;
        try {
            stack.precomputation(this);

            if (seen == Const.ATHROW) {
                checkForWEM();
            } else if ((seen == Const.LDC) || (seen == Const.LDC_W)) {
                if (getConstantRefOperand() instanceof ConstantString) {
                    sawConstant = true;
                }
            } else if ((seen == Const.INVOKESPECIAL) && Values.CONSTRUCTOR.equals(getNameConstantOperand())) {
                String clsName = getClassConstantOperand();
                if (clsName.indexOf("Exception") < 0) {
                    return;
                }
                JavaClass exCls = Repository.lookupClass(clsName);
                if (!exCls.instanceOf(exceptionClass)) {
                    return;
                }
                String sig = getSigConstantOperand();
                List<String> argTypes = SignatureUtils.getParameterSignatures(sig);
                int stringParms = 0;
                for (int t = 0; t < argTypes.size(); t++) {
                    if (!Values.SIG_JAVA_LANG_STRING.equals(argTypes.get(t))) {
                        continue;
                    }
                    stringParms++;
                    int stackOffset = argTypes.size() - t - 1;
                    if ((stack.getStackDepth() > stackOffset) && (stack.getStackItem(stackOffset).getUserValue() == null)) {
                        return;
                    }
                }
                if (Values.SLASHED_JAVA_LANG_EXCEPTION.equals(clsName) && SignatureBuilder.SIG_THROWABLE_TO_VOID.equals(getSigConstantOperand())) {
                    bugReporter.reportBug(
                            new BugInstance(this, BugType.WEM_OBSCURING_EXCEPTION.name(), LOW_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                }
                allConstantStrings = stringParms > 0;
            }
        } catch (ClassNotFoundException cnfe) {
            bugReporter.reportMissingClass(cnfe);
        } finally {
            TernaryPatcher.pre(stack, seen);
            stack.sawOpcode(this, seen);
            TernaryPatcher.post(stack, seen);
            if ((sawConstant || allConstantStrings) && (stack.getStackDepth() > 0)) {
                OpcodeStack.Item item = stack.getStackItem(0);
                item.setUserValue(Boolean.TRUE);
            }
        }
    }
42718
@Override
    public void sawOpcode(int seen) {
        try {
            stack.precomputation(this);

            if (seen == Const.INVOKEVIRTUAL) {
                String clsName = getClassConstantOperand();
                if ("java/io/ObjectOutputStream".equals(clsName)) {
                    String name = getNameConstantOperand();
                    if ("writeObject".equals(name) && (stack.getStackDepth() > 0)) {
                        OpcodeStack.Item item = stack.getStackItem(0);
                        JavaClass cls = item.getJavaClass();

                        if ((cls != null) && (cls.getClassName().indexOf(Values.INNER_CLASS_SEPARATOR) >= 0) && hasOuterClassSyntheticReference(cls)) {
                            bugReporter.reportBug(new BugInstance(this, BugType.PUS_POSSIBLE_UNSUSPECTED_SERIALIZATION.name(), NORMAL_PRIORITY).addClass(this)
                                    .addMethod(this).addSourceLine(this));
                        }
                    }
                }
            }
        } catch (ClassNotFoundException cnfe) {
            bugReporter.reportMissingClass(cnfe);
        } finally {
            stack.sawOpcode(this, seen);
        }
    }
1010391
@Override
    public void sawOpcode(int seen) {
        try {
            stack.precomputation(this);

            if ((seen == Const.CHECKCAST) && (stack.getStackDepth() > 0)) {
                OpcodeStack.Item item = stack.getStackItem(0);
                if (item.getRegisterNumber() == 1) {
                    String thisCls = getClassName();
                    String equalsCls = getClassConstantOperand();
                    if (!thisCls.equals(equalsCls)) {
                        JavaClass thisJavaClass = getClassContext().getJavaClass();
                        JavaClass equalsJavaClass = Repository.lookupClass(equalsCls);
                        boolean inheritance = thisJavaClass.instanceOf(equalsJavaClass) || equalsJavaClass.instanceOf(thisJavaClass);

                        BugInstance bug = new BugInstance(this, BugType.NSE_NON_SYMMETRIC_EQUALS.name(), inheritance ? LOW_PRIORITY : NORMAL_PRIORITY)
                                .addClass(this).addMethod(this).addSourceLine(this).addString(equalsCls);
                        Map<String, BugInstance> bugs = possibleBugs.get(thisCls);
                        if (bugs == null) {
                            bugs = new HashMap<>();
                            possibleBugs.put(thisCls, bugs);
                        }
                        bugs.put(equalsCls, bug);
                    }
                }
            }
        } catch (ClassNotFoundException cnfe) {
            bugReporter.reportMissingClass(cnfe);
        } finally {
            stack.sawOpcode(this, seen);
        }
    }
754522
@Override
    public void sawOpcode(int seen) {
        try {
            stack.precomputation(this);

            if (seen == Const.INVOKEINTERFACE) {
                KeyType type = isKeyAccessMethod(seen);
                if (type != null) {
                    int numParms = SignatureUtils.getNumParameters(getSigConstantOperand());
                    if (stack.getStackDepth() >= numParms) {
                        OpcodeStack.Item item = stack.getStackItem(numParms - 1);
                        String parmName = (String) item.getConstant();
                        if (parmName != null) {
                            String upperParmName = parmName.toUpperCase(Locale.getDefault());
                            Map<String, Map<String, List<SourceInfo>>> typeMap = parmInfo.get(KeyType.PARAMETER);
                            Map<String, List<SourceInfo>> parmCaseInfo = typeMap.get(upperParmName);
                            if (parmCaseInfo == null) {
                                parmCaseInfo = new HashMap<>();
                                typeMap.put(upperParmName, parmCaseInfo);
                            }

                            List<SourceInfo> annotations = parmCaseInfo.get(parmName);
                            if (annotations == null) {
                                annotations = new ArrayList<>();
                                parmCaseInfo.put(parmName, annotations);
                            }

                            annotations.add(new SourceInfo(getClassName(), getMethodName(), getMethodSig(), getMethod().isStatic(),
                                    SourceLineAnnotation.fromVisitedInstruction(getClassContext(), this, getPC())));
                        }
                    }
                }
            }
        } finally {
            stack.sawOpcode(this, seen);
        }
    }
869163
@Override
    public void sawOpcode(int seen) {
        switch (state) {
            case COLLECT:
                if ((seen == Const.INVOKESTATIC) || (seen == Const.INVOKEVIRTUAL) || (seen == Const.INVOKEINTERFACE) || (seen == Const.INVOKESPECIAL)) {
                    refClasses.add(getClassConstantOperand());
                    String signature = getSigConstantOperand();
                    Type[] argTypes = Type.getArgumentTypes(signature);
                    for (Type t : argTypes) {
                        addType(t);
                    }
                    Type resultType = Type.getReturnType(signature);
                    addType(resultType);
                }
            break;

            case SEEN_NOTHING:
                if ((seen == Const.LDC) || (seen == Const.LDC_W)) {
                    Constant c = getConstantRefOperand();
                    if (c instanceof ConstantString) {
                        clsName = ((ConstantString) c).getBytes(getConstantPool());
                        state = State.SEEN_LDC;
                    }
                }
            break;

            case SEEN_LDC:
                if ((seen == Const.INVOKESTATIC) && "forName".equals(getNameConstantOperand()) && "java/lang/Class".equals(getClassConstantOperand())
                        && refClasses.contains(clsName)) {
                    bugReporter.reportBug(new BugInstance(this, BugType.SCR_SLOPPY_CLASS_REFLECTION.name(), NORMAL_PRIORITY).addClass(this).addMethod(this)
                            .addSourceLine(this));
                }
                state = State.SEEN_NOTHING;
            break;
        }
    }
1071352
@Override
    public void sawOpcode(int seen) {
        String methodInfo = null;
        try {
            stack.precomputation(this);

            switch (seen) {
                case Const.INVOKEVIRTUAL:
                case Const.INVOKEINTERFACE:
                case Const.INVOKESTATIC:
                    String sig = getSigConstantOperand();
                    if (!sig.endsWith(Values.SIG_VOID)) {
                        methodInfo = getClassConstantOperand() + '@' + getNameConstantOperand() + getSigConstantOperand();
                    }
                break;

                case Const.POP:
                case Const.POP2:
                    if (stack.getStackDepth() > 0) {
                        OpcodeStack.Item item = stack.getStackItem(0);
                        String mInfo = (String) item.getUserValue();
                        if (mInfo != null) {
                            for (Pattern p : IMMUTABLE_METHODS) {
                                Matcher m = p.matcher(mInfo);

                                if (m.matches()) {
                                    bugReporter.reportBug(new BugInstance(this, BugType.NPMC_NON_PRODUCTIVE_METHOD_CALL.name(), NORMAL_PRIORITY).addClass(this)
                                            .addMethod(this).addSourceLine(this).addString(mInfo));
                                    break;
                                }
                            }
                        }
                    }
                break;
            }

        } finally {
            stack.sawOpcode(this, seen);
            if ((methodInfo != null) && (stack.getStackDepth() > 0)) {
                OpcodeStack.Item item = stack.getStackItem(0);
                item.setUserValue(methodInfo);
            }
        }
    }
478600
@Override
    public void sawOpcode(int seen) {
        int groupId = -1;

        try {
            stack.precomputation(this);

            if (seen == Const.INVOKEINTERFACE) {
                String className = getClassConstantOperand();
                String methodName = getNameConstantOperand();
                String signature = getSigConstantOperand();
                QMethod methodInfo = new QMethod(methodName, signature);

                if (isCollection(className)) {
                    if (collectionMethods.contains(methodInfo) || ITERATOR.equals(methodInfo)) {
                        if (stack.getStackDepth() > 0) {
                            OpcodeStack.Item itm = stack.getStackItem(0);
                            groupId = findCollectionGroup(itm, true);
                        }
                    } else if (REMOVE.equals(methodInfo)) {
                        if (stack.getStackDepth() > 1) {
                            OpcodeStack.Item itm = stack.getStackItem(1);
                            int id = findCollectionGroup(itm, true);
                            if ((id >= 0) && collectionGroups.get(id).isStandardCollection()) {
                                Integer it = groupToIterator.get(Integer.valueOf(id));
                                Loop loop = loops.get(it);
                                if (loop != null) {
                                    int pc = getPC();
                                    if (loop.hasPC(pc)) {
                                        boolean needPop = !Values.SIG_VOID.equals(SignatureUtils.getReturnSignature(signature));

                                        if (!breakFollows(loop, needPop) && !returnFollows(needPop)) {
                                            bugReporter.reportBug(new BugInstance(this, BugType.DWI_DELETING_WHILE_ITERATING.name(), NORMAL_PRIORITY)
                                                    .addClass(this).addMethod(this).addSourceLine(this));
                                        }
                                    }
                                }
                            }
                        }
                    } else {
                        Integer numArgs = modifyingMethods.get(methodInfo);
                        if ((numArgs != null) && (stack.getStackDepth() > numArgs.intValue())) {
                            OpcodeStack.Item itm = stack.getStackItem(numArgs.intValue());
                            int id = findCollectionGroup(itm, true);
                            if (id >= 0) {
                                Integer it = groupToIterator.get(Integer.valueOf(id));
                                if (it != null) {
                                    Loop loop = loops.get(it);
                                    if (loop != null) {
                                        int pc = getPC();
                                        if (loop.hasPC(pc)) {
                                            boolean needPop = !Values.SIG_VOID.equals(SignatureUtils.getReturnSignature(signature));
                                            boolean breakFollows = breakFollows(loop, needPop);
                                            boolean returnFollows = !breakFollows && returnFollows(needPop);

                                            if (!breakFollows && !returnFollows) {
                                                bugReporter.reportBug(new BugInstance(this, BugType.DWI_MODIFYING_WHILE_ITERATING.name(), NORMAL_PRIORITY)
                                                        .addClass(this).addMethod(this).addSourceLine(this));
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                } else if ("java/util/Iterator".equals(className) && HASNEXT.equals(methodInfo) && (stack.getStackDepth() > 0)) {
                    OpcodeStack.Item itm = stack.getStackItem(0);
                    Integer id = (Integer) itm.getUserValue();
                    if (id != null) {
                        groupId = id.intValue();
                    }
                }
            } else if ((seen == Const.PUTFIELD) || (seen == Const.PUTSTATIC)) {
                if (stack.getStackDepth() > 1) {
                    OpcodeStack.Item itm = stack.getStackItem(0);

                    Integer id = (Integer) itm.getUserValue();
                    if (id == null) {
                        FieldAnnotation fa = FieldAnnotation
                                .fromFieldDescriptor(new FieldDescriptor(getClassConstantOperand(), getNameConstantOperand(), getSigConstantOperand(), false));
                        itm = new OpcodeStack.Item(itm.getSignature(), fa, stack.getStackItem(1).getRegisterNumber());
                        removeFromCollectionGroup(itm);
                        groupId = findCollectionGroup(itm, true);
                    }
                }
            } else if (OpcodeUtils.isAStore(seen)) {
                if (stack.getStackDepth() > 0) {
                    OpcodeStack.Item itm = stack.getStackItem(0);
                    Integer id = (Integer) itm.getUserValue();
                    if (id != null) {
                        int reg = RegisterUtils.getAStoreReg(this, seen);

                        try {
                            JavaClass cls = itm.getJavaClass();
                            if ((cls != null) && cls.implementationOf(iteratorClass)) {
                                Integer regIt = Integer.valueOf(reg);
                                Iterator<Integer> curIt = groupToIterator.values().iterator();
                                while (curIt.hasNext()) {
                                    if (curIt.next().equals(regIt)) {
                                        curIt.remove();
                                    }
                                }
                                groupToIterator.put(id, regIt);
                            }

                            GroupPair pair = collectionGroups.get(id.intValue());
                            if (pair != null) {
                                pair.addMember(Integer.valueOf(reg));
                            }
                        } catch (ClassNotFoundException cnfe) {
                            bugReporter.reportMissingClass(cnfe);
                        }
                    } else {
                        String cls = itm.getSignature();
                        if ((cls != null) && cls.startsWith(Values.SIG_QUALIFIED_CLASS_PREFIX)) {
                            cls = SignatureUtils.trimSignature(cls);
                            if (isCollection(cls) || "java/util/Iterator".equals(cls)) {
                                int reg = RegisterUtils.getAStoreReg(this, seen);
                                removeFromCollectionGroup(new OpcodeStack.Item(itm, reg));
                                Iterator<Integer> it = groupToIterator.values().iterator();
                                while (it.hasNext()) {
                                    if (it.next().intValue() == reg) {
                                        it.remove();
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            } else if (OpcodeUtils.isALoad(seen)) {
                int reg = RegisterUtils.getALoadReg(this, seen);
                OpcodeStack.Item itm = new OpcodeStack.Item(new OpcodeStack.Item(), reg);
                groupId = findCollectionGroup(itm, false);
            } else if ((seen == Const.IFEQ) && (stack.getStackDepth() > 0)) {
                OpcodeStack.Item itm = stack.getStackItem(0);
                Integer id = (Integer) itm.getUserValue();
                if (id != null) {
                    int target = getBranchTarget();
                    int gotoAddr = target - 3;
                    int ins = getCode().getCode()[gotoAddr];
                    if (ins < 0) {
                        ins = 256 + ins;
                    }
                    if ((ins == Const.GOTO) || (ins == Const.GOTO_W)) {
                        Integer reg = groupToIterator.get(id);
                        if (reg != null) {
                            loops.put(reg, new Loop(getPC(), gotoAddr));
                        }
                    }
                }
            }
        } finally {
            TernaryPatcher.pre(stack, seen);
            stack.sawOpcode(this, seen);
            TernaryPatcher.post(stack, seen);
            if ((groupId >= 0) && (stack.getStackDepth() > 0)) {
                OpcodeStack.Item itm = stack.getStackItem(0);
                itm.setUserValue(Integer.valueOf(groupId));
            }

            processEndOfScopes(Integer.valueOf(getPC()));
        }
    }
291812
@Override
    public void sawOpcode(int seen) {
        XField userValue = null;
        try {
            stack.precomputation(this);

            if ((seen == Const.INVOKEVIRTUAL) || (seen == Const.INVOKEINTERFACE) || (seen == Const.INVOKEDYNAMIC)) {
                String sig = getSigConstantOperand();
                int argCount = SignatureUtils.getNumParameters(sig);
                if (stack.getStackDepth() > argCount) {
                    OpcodeStack.Item itm = stack.getStackItem(argCount);
                    XField field = itm.getXField();
                    if ((field != null) && bloatableCandidates.containsKey(field)) {
                        checkMethodAsDecreasingOrIncreasing(field);
                    }
                    String calledMethod = getNameConstantOperand();
                    if ("iterator".equals(calledMethod)) {
                        userValue = (XField) itm.getUserValue();
                        if (userValue == null) {
                            userValue = field;
                        }
                    } else {
                        if (field == null) {
                            field = (XField) itm.getUserValue();
                        }
                        if (field != null) {
                            if (mapSubsets.contains(calledMethod)) {
                                userValue = field;
                            } else if ("remove".equals(calledMethod) && "java/util/Iterator".equals(getClassConstantOperand())) {
                                bloatableCandidates.remove(field);
                                bloatableFields.remove(field);
                            }
                        }
                    }
                    
                    for (int i = 0; i < argCount; i++) {
                    	itm = stack.getStackItem(i);
                    	jaxbContextRegs.remove(itm.getRegisterNumber());
                    }
                }
            } else if (seen == Const.PUTFIELD) {
                if (stack.getStackDepth() > 0) {
                	OpcodeStack.Item item = stack.getStackItem(0);
	                jaxbContextRegs.remove(item.getRegisterNumber());
                }
            } else if (seen == Const.PUTSTATIC) {
                if (stack.getStackDepth() > 0) {
                    OpcodeStack.Item item = stack.getStackItem(0);
                    if (nonBloatableSigs.contains(item.getSignature())) {
                        XField field = item.getXField();
                        bloatableFields.remove(field);
                    }
                    
                    jaxbContextRegs.remove(item.getRegisterNumber());
                }
            }
            // Should not include private methods
            else if (seen == Const.ARETURN) {
                removeFieldsThatGetReturned();
            } else if (OpcodeUtils.isALoad(seen)) {
                userValue = userValues.get(RegisterUtils.getALoadReg(this, seen));
            } else if (OpcodeUtils.isAStore(seen)) {
                if (stack.getStackDepth() > 0) {
                    OpcodeStack.Item itm = stack.getStackItem(0);
                    userValues.put(RegisterUtils.getAStoreReg(this, seen), (XField) itm.getUserValue());
                    
            		XMethod xm = itm.getReturnValueOf();
            		if (xm != null) {
            			FQMethod calledMethod = new FQMethod(xm.getClassName().replace('.', '/'), xm.getName(), xm.getSignature());
                    	if (jaxbNewInstance.equals(calledMethod)) {
                    		jaxbContextRegs.put(RegisterUtils.getAStoreReg(this, seen), getPC());
                    	}
            		}
                }
            }
        } finally {
            stack.sawOpcode(this, seen);
            if ((userValue != null) && (stack.getStackDepth() > 0)) {
                OpcodeStack.Item itm = stack.getStackItem(0);
                itm.setUserValue(userValue);
            }
        }
    }
750084
@Override
    public void sawOpcode(int seen) {
        try {
            stack.precomputation(this);

            int pc = getPC();
            if ((loopEnd != -1) && (pc > loopEnd)) {
                loopStart = -1;
                loopEnd = -1;
                regValueType.clear();
            }

            if (OpcodeUtils.isALoad(seen)) {
                int reg = RegisterUtils.getALoadReg(this, seen);
                State type = regValueType.get(Integer.valueOf(reg));
                if (type == null) {
                    state = State.SEEN_NOTHING;
                } else {
                    state = type;
                }
                return;
            }
            if (OpcodeUtils.isAStore(seen)) {
                if (stack.getStackDepth() > 0) {
                    OpcodeStack.Item item = stack.getStackItem(0);
                    int reg = RegisterUtils.getAStoreReg(this, seen);
                    regValueType.put(Integer.valueOf(reg), (State) item.getUserValue());
                }
                state = State.SEEN_NOTHING;
                return;
            }
            if (OpcodeUtils.isILoad(seen)) {
                int reg = RegisterUtils.getLoadReg(this, seen);
                State type = regValueType.get(Integer.valueOf(reg));
                if (type == null) {
                    state = State.SEEN_NOTHING;
                } else {
                    state = type;
                }
                return;
            }
            if (OpcodeUtils.isIStore(seen)) {
                if (stack.getStackDepth() > 0) {
                    OpcodeStack.Item item = stack.getStackItem(0);
                    int reg = RegisterUtils.getStoreReg(this, seen);
                    regValueType.put(Integer.valueOf(reg), (State) item.getUserValue());
                }
                state = State.SEEN_NOTHING;
                return;
            }

            switch (state) {
                case SEEN_NOTHING:
                    if ((seen == Const.INVOKESPECIAL) && "java/util/StringTokenizer".equals(getClassConstantOperand())
                            && Values.CONSTRUCTOR.equals(getNameConstantOperand())
                            && SignatureBuilder.SIG_TWO_STRINGS_TO_VOID.equals(getSigConstantOperand())) {
                        state = State.SEEN_STRINGTOKENIZER;
                    }
                break;

                case SEEN_STRINGTOKENIZER:
                    if (seen == Const.INVOKEVIRTUAL) {
                        String methodName = getNameConstantOperand();
                        String signature = getSigConstantOperand();
                        if ("countTokens".equals(methodName) && SignatureBuilder.SIG_VOID_TO_INT.equals(signature))
                            state = State.SEEN_COUNTTOKENS;
                        else if ("hasMoreTokens".equals(methodName) || "hasMoreElements".equals(methodName))
                            state = State.SEEN_HASMORE;
                        else if ("nextToken".equals(methodName) || "nextElement".equals(methodName)) {
                            if ((pc < loopStart) || (pc > loopEnd))
                                regValueType.clear();
                            else
                                state = State.SEEN_NEXT;
                        }
                    }
                break;

                case SEEN_COUNTTOKENS:
                    if (seen == Const.ANEWARRAY)
                        state = State.SEEN_NEWARRAY;
                    else if (seen == Const.IF_ICMPGE) {
                        int target = getBranchTarget() - 3;// sizeof goto
                        byte[] code = getCode().getCode();
                        if ((code[target] & 0x000000FF) == Const.GOTO) {
                            int offset = (code[target + 1] << 1) + code[target + 2];
                            int gotoTarget = target + offset + 3;
                            if (gotoTarget < getPC()) {
                                loopStart = gotoTarget;
                                loopEnd = target;
                            }
                        }
                    }
                break;

                case SEEN_HASMORE:
                    if (seen == Const.IFEQ) {
                        int target = getBranchTarget() - 3;// sizeof goto
                        byte[] code = getCode().getCode();
                        if ((code[target] & 0x000000FF) == Const.GOTO) {
                            int offset = (code[target + 1] << 1) + code[target + 2];
                            int gotoTarget = target + offset + 3;
                            if (gotoTarget < getPC()) {
                                loopStart = gotoTarget;
                                loopEnd = target;
                            }
                        }
                    }
                    state = State.SEEN_NOTHING;
                break;

                case SEEN_NEXT:
                    if ((seen == Const.AASTORE) && (pc > loopStart) && (pc < loopEnd) && (stack.getStackDepth() > 2)) {
                        OpcodeStack.Item arrayItem = stack.getStackItem(2);
                        State arrayType = (State) arrayItem.getUserValue();
                        OpcodeStack.Item elemItem = stack.getStackItem(0);
                        State elemType = (State) elemItem.getUserValue();
                        if ((arrayType == State.SEEN_NEWARRAY) && (elemType == State.SEEN_NEXT)) {
                            bugReporter.reportBug(new BugInstance(this, BugType.USS_USE_STRING_SPLIT.name(), NORMAL_PRIORITY).addClass(this).addMethod(this)
                                    .addSourceLine(this));
                        }
                    }
                    state = State.SEEN_NOTHING;
                break;

                case SEEN_ARRAYSTORE:
                case SEEN_NEWARRAY:
                break;
            }
        } finally {
            TernaryPatcher.pre(stack, seen);
            stack.sawOpcode(this, seen);
            TernaryPatcher.post(stack, seen);
            if ((state != State.SEEN_NOTHING) && (stack.getStackDepth() > 0)) {
                OpcodeStack.Item item = stack.getStackItem(0);
                item.setUserValue(state);
            }
        }
    }