JCBlock classDollarSymBody(DiagnosticPosition pos, JCMethodDecl md) {
        MethodSymbol classDollarSym = md.sym;
        ClassSymbol outerCacheClass = (ClassSymbol)classDollarSym.owner;

        JCBlock returnResult;

        // in 1.4.2 and above, we use
        // Class.forName(String name, boolean init, ClassLoader loader);
        // which requires we cache the current loader in cl$
        if (target.classLiteralsNoInit()) {
            // clsym = "private static ClassLoader cl$"
            VarSymbol clsym = new VarSymbol(STATIC|SYNTHETIC,
                                            names.fromString("cl" + target.syntheticNameChar()),
                                            syms.classLoaderType,
                                            outerCacheClass);
            enterSynthetic(pos, clsym, outerCacheClass.members());

            // emit "private static ClassLoader cl$;"
            JCVariableDecl cldef = make.VarDef(clsym, null);
            JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
            outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(cldef);

            // newcache := "new cache$1[0]"
            JCNewArray newcache = make.
                NewArray(make.Type(outerCacheClass.type),
                         List.<JCExpression>of(make.Literal(INT, 0).setType(syms.intType)),
                         null);
            newcache.type = new ArrayType(types.erasure(outerCacheClass.type),
                                          syms.arrayClass);

            // forNameSym := java.lang.Class.forName(
            //     String s,boolean init,ClassLoader loader)
            Symbol forNameSym = lookupMethod(make_pos, names.forName,
                                             types.erasure(syms.classType),
                                             List.of(syms.stringType,
                                                     syms.booleanType,
                                                     syms.classLoaderType));
            // clvalue := "(cl$ == null) ?
            // $newcache.getClass().getComponentType().getClassLoader() : cl$"
            JCExpression clvalue =
                make.Conditional(
                    makeBinary(JCTree.EQ, make.Ident(clsym), makeNull()),
                    make.Assign(
                        make.Ident(clsym),
                        makeCall(
                            makeCall(makeCall(newcache,
                                              names.getClass,
                                              List.<JCExpression>nil()),
                                     names.getComponentType,
                                     List.<JCExpression>nil()),
                            names.getClassLoader,
                            List.<JCExpression>nil())).setType(syms.classLoaderType),
                    make.Ident(clsym)).setType(syms.classLoaderType);

            // returnResult := "{ return Class.forName(param1, false, cl$); }"
            List<JCExpression> args = List.of(make.Ident(md.params.head.sym),
                                              makeLit(syms.booleanType, 0),
                                              clvalue);
            returnResult = make.
                Block(0, List.<JCStatement>of(make.
                              Call(make. // return
                                   App(make.
                                       Ident(forNameSym), args))));
        } else {
            // forNameSym := java.lang.Class.forName(String s)
            Symbol forNameSym = lookupMethod(make_pos,
                                             names.forName,
                                             types.erasure(syms.classType),
                                             List.of(syms.stringType));
            // returnResult := "{ return Class.forName(param1); }"
            returnResult = make.
                Block(0, List.of(make.
                          Call(make. // return
                              App(make.
                                  QualIdent(forNameSym),
                                  List.<JCExpression>of(make.
                                                        Ident(md.params.
                                                              head.sym))))));
        }

        // catchParam := ClassNotFoundException e1
        VarSymbol catchParam =
            new VarSymbol(0, make.paramName(1),
                          syms.classNotFoundExceptionType,
                          classDollarSym);

        JCStatement rethrow;
        if (target.hasInitCause()) {
            // rethrow = "throw new NoClassDefFoundError().initCause(e);
            JCTree throwExpr =
                makeCall(makeNewClass(syms.noClassDefFoundErrorType,
                                      List.<JCExpression>nil()),
                         names.initCause,
                         List.<JCExpression>of(make.Ident(catchParam)));
            rethrow = make.Throw(throwExpr);
        } else {
            // getMessageSym := ClassNotFoundException.getMessage()
            Symbol getMessageSym = lookupMethod(make_pos,
                                                names.getMessage,
                                                syms.classNotFoundExceptionType,
                                                List.<Type>nil());
            // rethrow = "throw new NoClassDefFoundError(e.getMessage());"
            rethrow = make.
                Throw(makeNewClass(syms.noClassDefFoundErrorType,
                          List.<JCExpression>of(make.App(make.Select(make.Ident(catchParam),
                                                                     getMessageSym),
                                                         List.<JCExpression>nil()))));
        }

        // rethrowStmt := "( $rethrow )"
        JCBlock rethrowStmt = make.Block(0, List.of(rethrow));

        // catchBlock := "catch ($catchParam) $rethrowStmt"
        JCCatch catchBlock = make.Catch(make.VarDef(catchParam, null),
                                      rethrowStmt);

        // tryCatch := "try $returnResult $catchBlock"
        JCStatement tryCatch = make.Try(returnResult,
                                        List.of(catchBlock), null);

        return make.Block(0, List.of(tryCatch));
    }