📄 lower.java
字号:
if (e.sym.kind == TYP && e.sym.name == names.empty && (e.sym.flags() & INTERFACE) == 0) return (ClassSymbol) e.sym; return makeEmptyClass(STATIC | SYNTHETIC, clazz); } /** Return symbol for "class$" method. If there is no method definition * for class$, construct one as follows: * * class class$(String x0) { * try { * return Class.forName(x0); * } catch (ClassNotFoundException x1) { * throw new NoClassDefFoundError(x1.getMessage()); * } * } */ private MethodSymbol classDollarSym(DiagnosticPosition pos) { ClassSymbol outerCacheClass = outerCacheClass(); MethodSymbol classDollarSym = (MethodSymbol)lookupSynthetic(classDollar, outerCacheClass.members()); if (classDollarSym == null) { classDollarSym = new MethodSymbol( STATIC | SYNTHETIC, classDollar, new MethodType( List.of(syms.stringType), types.erasure(syms.classType), List.<Type>nil(), syms.methodClass), outerCacheClass); enterSynthetic(pos, classDollarSym, outerCacheClass.members()); JCMethodDecl md = make.MethodDef(classDollarSym, null); try { md.body = classDollarSymBody(pos, md); } catch (CompletionFailure ex) { md.body = make.Block(0, List.<JCStatement>nil()); chk.completionError(pos, ex); } JCClassDecl outerCacheClassDef = classDef(outerCacheClass); outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(md); } return classDollarSym; } /** Generate code for class$(String name). */ 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)); } // where /** Create an attributed tree of the form left.name(). */ private JCMethodInvocation makeCall(JCExpression left, Name name, List<JCExpression> args) { assert left.type != null; Symbol funcsym = lookupMethod(make_pos, name, left.type, TreeInfo.types(args)); return make.App(make.Select(left, funcsym), args); } /** The Name Of The variable to cache T.class values. * @param sig The signature of type T. */ private Name cacheName(String sig) { StringBuffer buf = new StringBuffer(); if (sig.startsWith("[")) { buf = buf.append("array"); while (sig.startsWith("[")) { buf = buf.append(target.syntheticNameChar()); sig = sig.substring(1); } if (sig.startsWith("L")) { sig = sig.substring(0, sig.length() - 1); } } else { buf = buf.append("class" + target.syntheticNameChar()); } buf = buf.append(sig.replace('.', target.syntheticNameChar())); return names.fromString(buf.toString()); } /** The variable symbol that caches T.class values. * If none exists yet, create a definition. * @param sig The signature of type T. * @param pos The position to report diagnostics, if any. */ private VarSymbol cacheSym(DiagnosticPosition pos, String sig) { ClassSymbol outerCacheClass = outerCacheClass(); Name cname = cacheName(sig); VarSymbol cacheSym = (VarSymbol)lookupSynthetic(cname, outerCacheClass.members()); if (cacheSym == null) { cacheSym = new VarSymbol( STATIC | SYNTHETIC, cname, types.erasure(syms.classType), outerCacheClass); enterSynthetic(pos, cacheSym, outerCacheClass.members()); JCVariableDecl cacheDef = make.VarDef(cacheSym, null); JCClassDecl outerCacheClassDef = classDef(outerCacheClass); outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(cacheDef); } return cacheSym; } /** The tree simulating a T.class expression. * @param clazz The tree identifying type T. */ private JCExpression classOf(JCTree clazz) { return classOfType(clazz.type, clazz.pos()); } private JCExpression classOfType(Type type, DiagnosticPosition pos) { switch (type.tag) { case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID: // replace with <BoxedClass>.TYPE ClassSymbol c = types.boxedClass(type); Symbol typeSym = rs.access( rs.findIdentInType(attrEnv, c.type, names.TYPE, VAR), pos, c.type, names.TYPE, true); if (typeSym.kind == VAR) ((VarSymbol)typeSym).getConstValue(); // ensure initializer is evaluated return make.QualIdent(typeSym); case CLASS: case ARRAY: if (target.hasClassLiterals()) { VarSymbol sym = new VarSymbol( STATIC | PUBLIC | FINAL, names._class, syms.classType, type.tsym); return make_at(pos).Select(make.Type(type), sym); } // replace with <cache == null ? cache = class$(tsig) : cache> // where // - <tsig> is the type signature of T, // - <cache> is the cache variable for tsig. String sig = writer.xClassName(type).toString().replace('/', '.'); Symbol cs = cacheSym(pos, sig); return make_at(pos).Conditional( makeBinary(JCTree.EQ, make.Ident(cs), makeNull()), make.Assign( make.Ident(cs), make.App( make.Ident(classDollarSym(pos)), List.<JCExpression>of(make.Literal(CLASS, sig) .setType(syms.stringType)))) .setType(types.erasure(syms.classType)), make.Ident(cs)).setType(types.erasure(syms.classType)); default: throw new AssertionError(); } }/************************************************************************** * Code for enabling/disabling assertions. *************************************************************************/ // This code is not particularly robust if the user has // previously declared a member named '$assertionsDisabled'. // The same faulty idiom also appears in the translation of // class literals above. We should report an error if a // previous declaration is not synthetic. private JCExpression assertFlagTest(DiagnosticPosition pos) { // Outermost class may be either true class or an interface. ClassSymbol outermostClass = outermostClassDef.sym; // note that this is a class, as an interface can't contain a statement. ClassSymbol container = currentClass; VarSymbol assertDisabledSym = (VarSymbol)lookupSynthetic(dollarAssertionsDisabled, container.members()); if (assertDisabledSym == null) { assertDisabledSym = new VarSymbol(STATIC | FINAL | SYNTHETIC, dollarAssertionsDisabled, syms.booleanType, container); enterSynthetic(pos, assertDisabledSym, container.members()); Symbol desiredAssertionStatusSym = lookupMethod(pos, names.desiredAssertionStatus, types.erasure(syms.classType), List.<Type>nil()); JCClassDecl containerDef = classDef(container); make_at(containerDef.pos()); JCExpression notStatus = makeUnary(JCTree.NOT, make.App(make.Select( classOfType(types.erasure(outermostClass.type), containerDef.pos()), desiredAssertionStatusSym))); JCVariableDecl assertDisabledDef = make.VarDef(assertDisabledSym, notStatus); containerDef.defs = containerDef.defs.prepend(assertDisabledDef); } make_at(pos); return makeUnary(JCTree.NOT, make.Ident(assertDisabledSym)); }/************************************************************************** * Building blocks for let expressions *************************************************************************/ interface TreeBuilder { JCTree build(JCTree arg); } /** Construct an expression using the builder, with the given rval * expression as an argument to the builder. However, the rval * expression must be computed only once, even if used multiple * times in the result of the builder. We do that by * constructing a "let" expression that saves the rvalue into a * temporary variable and then uses the temporary variable in * place of the expression built by the builder. The complete * resulting expression is of the form * <pre> * (let <b>TYPE</b> <b>TEMP</b> = <b>RVAL</b>; * in (<b>BUILDER</b>(<b>TEMP</b>))) * </pre> * where <code><b>TEMP</b></code> is a newly declared variable * in the let expression. */ JCTree abstractRval(JCTree rval, Type type, TreeBuilder builder) { rval = TreeInfo.skipParens(rval); switch (rval.getTag()) { case JCTree.LITERAL: return builder.build(rval); case JCTree.IDENT: JCIdent id = (JCIdent) rval; if ((id.sym.flags() & FINAL) != 0 && id.sym.owner.kind == MTH) return builder.build(rval); } VarSymbol var = new VarSymbol(FINAL|SYNTHETIC, Name.fromString(names, target.syntheticNameChar() + "" + rval.hashCode()), type, currentMethodSym); JCVariableDecl def = make.VarDef(var, (JCExpression)rval); // XXX cast JCTree built = builder.build(make.Ident(var)); JCTree res = make.LetExpr(def, built); res.type = built.type; return res; } // same as above, with the type of the temporary variable computed JCTr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -