public String toString() {
            return "immediate(" + value + ")";
        }
    }

    /** An item representing an assignment expressions.
     */
    class AssignItem extends Item {

        /** The item representing the assignment's left hand side.
         */
        Item lhs;

        AssignItem(Item lhs) {
            super(lhs.typecode);
            this.lhs = lhs;
        }

        Item load() {
            lhs.stash(typecode);
            lhs.store();
            return stackItem[typecode];
        }

        void duplicate() {
            load().duplicate();
        }

        void drop() {
            lhs.store();
        }

        void stash(int toscode) {
            Assert.error();
        }

        int width() {
            return lhs.width() + Code.width(typecode);
        }

        public String toString() {
            return "assign(lhs = " + lhs + ")";
        }
    }

    /** An item representing a conditional or unconditional jump.
     */
    class CondItem extends Item {

        /** A chain encomassing all jumps that can be taken
         *  if the condition evaluates to true.
         */
        Chain trueJumps;

        /** A chain encomassing all jumps that can be taken
         *  if the condition evaluates to false.
         */
        Chain falseJumps;

        /** The jump's opcode.
         */
        int opcode;

        /*
         *  An abstract syntax tree of this item. It is needed
         *  for branch entries in 'CharacterRangeTable' attribute.
         */
        JCTree tree;

        CondItem(int opcode, Chain truejumps, Chain falsejumps) {
            super(BYTEcode);
            this.opcode = opcode;
            this.trueJumps = truejumps;
            this.falseJumps = falsejumps;
        }

        Item load() {
            Chain trueChain = null;
            Chain falseChain = jumpFalse();
            if (!isFalse()) {
                code.resolve(trueJumps);
                code.emitop0(iconst_1);
                trueChain = code.branch(goto_);
            }
            if (falseChain != null) {
                code.resolve(falseChain);
                code.emitop0(iconst_0);
            }
            code.resolve(trueChain);
            return stackItem[typecode];
        }

        void duplicate() {
            load().duplicate();
        }

        void drop() {
            load().drop();
        }

        void stash(int toscode) {
            Assert.error();
        }

        CondItem mkCond() {
            return this;
        }

        Chain jumpTrue() {
            if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode));
            // we should proceed further in -Xjcov mode only
            int startpc = code.curPc();
            Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
            code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
            return c;
        }

        Chain jumpFalse() {
            if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
            // we should proceed further in -Xjcov mode only
            int startpc = code.curPc();
            Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
            code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
            return c;
        }

        CondItem negate() {
            CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps);
            c.tree = tree;
            return c;
        }

        int width() {
            // a CondItem doesn't have a size on the stack per se.
            throw new AssertionError();
        }

        boolean isTrue() {
            return falseJumps == null && opcode == goto_;
        }

        boolean isFalse() {
            return trueJumps == null && opcode == dontgoto;
        }

        public String toString() {
            return "cond(" + Code.mnem(opcode) + ")";
        }