private void generateAppend(Expression expr, int estimate) {
            if (!(expr instanceof ConcatenateExpression)) {
                generate(expr);
                return;
            }

            ConcatenateExpression concat = (ConcatenateExpression)expr;
            Expression left = concat.getLeftExpression();
            Expression right = concat.getRightExpression();

            Type leftType = left.getType();
            Type rightType = right.getType();

            if (left instanceof ConcatenateExpression) {
                generateAppend(left, estimate);
            }
            else {
                // Construct the StringBuffer, but be smart with respect to
                // its initial capacity.
                mBuilder.newObject(cStringBuilderDesc);
                mBuilder.dup();

                if (left.isValueKnown()) {
                    // If the value of left is known, don't adjust estimate
                    // at runtime. Construct the StringBuffer immediately.
                    mBuilder.loadConstant(estimate);
                    mBuilder.invokeConstructor
                        ("java.lang.StringBuilder", cIntParam);

                    if (left instanceof StringLiteral) {
                        String val = (String)((StringLiteral)left).getValue();
                        if (val.length() == 1) {
                            mBuilder.loadConstant(val.charAt(0));
                            leftType = new Type(char.class);
                        }
                        else {
                            generate(left);
                        }
                    }
                    else {
                        generate(left);
                    }
                }
                else {
                    // Increase the size of the estimate at runtime, based on
                    // the length of the left result.

                    // Subtract the length estimate of the unknown left result.
                    if ((estimate -= LENGTH_ESTIMATE) < 0) {
                        estimate += LENGTH_ESTIMATE;
                    }

                    mBuilder.loadConstant(estimate);

                    LocalVariable leftResult =
                        mBuilder.createLocalVariable("left", TypeDesc.STRING);
                    generate(left);
                    mBuilder.storeLocal(leftResult);

                    Label ctor = mBuilder.createLabel();

                    if (leftType.isNullable()) {
                        // If left could be null, test for it. If it is null,
                        // don't adjust estimate.
                        mBuilder.loadLocal(leftResult);
                        mBuilder.ifNullBranch(ctor, true);
                    }

                    mBuilder.loadLocal(leftResult);
                    mBuilder.invokeVirtual("java.lang.String", "length",
                                           TypeDesc.INT);
                    mBuilder.math(Opcode.IADD);

                    ctor.setLocation();
                    mBuilder.invokeConstructor
                        ("java.lang.StringBuilder",cIntParam);

                    mBuilder.loadLocal(leftResult);
                }

                // Constructed StringBuffer and first append argument is on
                // the stack, so perform first append operation.
                append(leftType);
            }

            if (right instanceof StringLiteral) {
                String val = (String)((StringLiteral)right).getValue();
                if (val.length() == 1) {
                    mBuilder.loadConstant(val.charAt(0));
                    rightType = new Type(char.class);
                }
                else {
                    generate(right);
                }
            }
            else {
                generate(right);
            }

            setLineNumber(concat.getOperator().getSourceInfo());

            append(rightType);
        }