标签:any lte trigger follow iter efi abstract arguments 检查
package com.sun.tools.javac.lower;
import static com.sun.tools.javac.code.Flags.BLOCK;
import static com.sun.tools.javac.code.Flags.ClassFlags;
import static com.sun.tools.javac.code.Flags.ENUM;
import static com.sun.tools.javac.code.Flags.FINAL;
import static com.sun.tools.javac.code.Flags.INTERFACE;
import static com.sun.tools.javac.code.Flags.PRIVATE;
import static com.sun.tools.javac.code.Flags.PROTECTED;
import static com.sun.tools.javac.code.Flags.PUBLIC;
import static com.sun.tools.javac.code.Flags.STATIC;
import static com.sun.tools.javac.code.Flags.SYNTHETIC;
import static com.sun.tools.javac.code.Kinds.MTH16;
import static com.sun.tools.javac.code.Kinds.PCK01;
import static com.sun.tools.javac.code.Kinds.TYP02;
import static com.sun.tools.javac.code.Kinds.VAR04;
import static com.sun.tools.javac.code.TypeTags.ARRAY11;
import static com.sun.tools.javac.code.TypeTags.BOOLEAN08;
import static com.sun.tools.javac.code.TypeTags.BYTE01;
import static com.sun.tools.javac.code.TypeTags.CHAR02;
import static com.sun.tools.javac.code.TypeTags.CLASS10;
import static com.sun.tools.javac.code.TypeTags.DOUBLE07;
import static com.sun.tools.javac.code.TypeTags.FLOAT06;
import static com.sun.tools.javac.code.TypeTags.INT04;
import static com.sun.tools.javac.code.TypeTags.LONG05;
import static com.sun.tools.javac.code.TypeTags.NONE18;
import static com.sun.tools.javac.code.TypeTags.SHORT03;
import static com.sun.tools.javac.code.TypeTags.TYPEVAR14;
import static com.sun.tools.javac.code.TypeTags.VOID09;
import static com.sun.tools.javac.jvm.ByteCodes.bool_not;
import static com.sun.tools.javac.jvm.ByteCodes.iadd;
import static com.sun.tools.javac.jvm.ByteCodes.ishll;
import static com.sun.tools.javac.jvm.ByteCodes.string_add;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import com.sun.source.tree.impl.JCCatch;
import com.sun.source.tree.impl.JCCompilationUnit;
import com.sun.source.tree.impl.JCMethodDecl;
import com.sun.source.tree.impl.JCModifiers;
import com.sun.source.tree.impl.JCTree;
import com.sun.source.tree.impl.JCTypeParameter;
import com.sun.source.tree.impl.exprs.JCAnnotation;
import com.sun.source.tree.impl.exprs.JCArrayAccess;
import com.sun.source.tree.impl.exprs.JCAssign;
import com.sun.source.tree.impl.exprs.JCAssignOp;
import com.sun.source.tree.impl.exprs.JCBinary;
import com.sun.source.tree.impl.exprs.JCConditional;
import com.sun.source.tree.impl.exprs.JCExpression;
import com.sun.source.tree.impl.exprs.JCFieldAccess;
import com.sun.source.tree.impl.exprs.JCIdentifier;
import com.sun.source.tree.impl.exprs.JCLiteral;
import com.sun.source.tree.impl.exprs.JCMethodInvocation;
import com.sun.source.tree.impl.exprs.JCNewArray;
import com.sun.source.tree.impl.exprs.JCNewClass;
import com.sun.source.tree.impl.exprs.JCParens;
import com.sun.source.tree.impl.exprs.JCTypeCast;
import com.sun.source.tree.impl.exprs.JCUnary;
import com.sun.source.tree.impl.exprs.LetExpr;
import com.sun.source.tree.impl.stmts.*;
import com.sun.tools.javac.attr.Attr;
import com.sun.tools.javac.check.Check;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.scope.Scope;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.code.SymbolTable;
import com.sun.tools.javac.code.TypeTags;
import com.sun.tools.javac.code.types.Types;
import com.sun.tools.javac.code.attribute.AttrCompound;
import com.sun.tools.javac.code.attribute.RetentionPolicy;
import com.sun.tools.javac.code.symbol.ClassSymbol;
import com.sun.tools.javac.code.symbol.MethodSymbol;
import com.sun.tools.javac.code.symbol.OperatorSymbol;
import com.sun.tools.javac.code.symbol.Symbol;
import com.sun.tools.javac.code.symbol.Symbol.CompletionFailure;
import com.sun.tools.javac.code.symbol.TypeSymbol;
import com.sun.tools.javac.code.symbol.VarSymbol;
import com.sun.tools.javac.code.type.ArrayType;
import com.sun.tools.javac.code.type.ClassType;
import com.sun.tools.javac.code.type.MethodType;
import com.sun.tools.javac.code.type.Type;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.ConstFold;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.diags.JCDiagnosticPosition;
import com.sun.tools.javac.jctree.TreeInfo;
import com.sun.tools.javac.jctree.TreeMaker;
import com.sun.tools.javac.jctree.visitor.JCTreeVisitor;
import com.sun.tools.javac.jctree.visitor.TreeScanner;
import com.sun.tools.javac.jctree.visitor.TreeTranslator;
import com.sun.tools.javac.jvm.ByteCodes;
import com.sun.tools.javac.jvm.classwriter.ClassWriter;
import com.sun.tools.javac.jvm.Target;
import com.sun.tools.javac.jvm.classreader.ClassReader;
import com.sun.tools.javac.main.RecognizedOptions.PkgInfo;
import com.sun.tools.javac.resolvation.Resolve;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Convert;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import com.sun.tools.javac.util.Options;
/** This pass translates away some syntactic sugar: inner classes,
* class literals, assertions, foreach loops, etc.
*
* Global mappings
* Symbol manipulation utilities
* Access methods
* Free variables proxies and this$n
* Code for .class
* Code for enabling/disabling assertions.
* Building blocks for let expressions
* Translation methods
* main method
*
* JLS7:https://docs.oracle.com/javase/specs/jls/se7/html/index.html
* 如果使用-Xprintsource命令后,不会进入Lower这个类
*/
public class Lower extends TreeTranslator {
protected static final Context.Key<Lower> lowerKey = new Context.Key<Lower>();
public static Lower instance(Context context) {
Lower instance = context.get(lowerKey);
if (instance == null)
instance = new Lower(context);
return instance;
}
public Names names;
private Log log;
SymbolTable syms;
private Resolve rs;
private Check chk;
private Attr attr;
TreeMaker make;
private JCDiagnosticPosition make_pos;
ClassWriter writer;
private ClassReader reader;
private ConstFold cfolder;
Target target;
private Source source;
private boolean allowEnums;
private final Name dollarAssertionsDisabled;
private final Name classDollar;
private Types types;
private boolean debugLower = false;
private PkgInfo pkginfoOpt;
protected Lower(Context context) {
context.put(lowerKey, this);
names = Names.instance(context);
log = Log.instance(context);
syms = SymbolTable.instance(context);
rs = Resolve.instance(context);
chk = Check.instance(context);
attr = Attr.instance(context);
make = TreeMaker.instance(context);
writer = ClassWriter.instance(context);
reader = ClassReader.instance(context);
cfolder = ConstFold.instance(context);
target = Target.instance(context);
source = Source.instance(context);
allowEnums = source.allowEnums();
dollarAssertionsDisabled = names.fromString(target.syntheticNameChar() + "assertionsDisabled");
classDollar = names.fromString("class" + target.syntheticNameChar());
types = Types.instance(context);
Options options = Options.instance(context);
debugLower = options.isSet("debuglower");
pkginfoOpt = PkgInfo.get(options);
}
/** The currently enclosing class.
*/
ClassSymbol currentClass;
/** A queue of all translated classes.
*/
ListBuffer<JCTree> translated;
/** Environment for symbol lookup, set by translateTopLevelClass.
*/
Env<AttrContext> attrEnv;
/** A hash table mapping syntax trees to their ending source positions.
*/
Map<JCTree, Integer> endPositions;
/**************************************************************************
* Global mappings
*************************************************************************/
/** A hash table mapping local classes to their definitions.
*/
Map<ClassSymbol, JCClassDecl> classdefs;
/** A hash table mapping virtual(实际上的) accessed symbols in outer subclasses
* to the actually referred symbol in superclasses.
*/
Map<Symbol,Symbol> actualSymbols;
/** The current method definition.
*/
JCMethodDecl currentMethodDef;
/** The current method symbol.
*/
MethodSymbol currentMethodSym;
/** The currently enclosing outermost class definition.
*/
JCClassDecl outermostClassDef;
/** The currently enclosing outermost member(field、method、type) definition.
*/
JCTree outermostMemberDef;
/** A navigator class for assembling a mapping from local class symbols to class definition trees.
* There is only one case; all other cases simply traverse down the tree.
*/
class ClassMap extends TreeScanner {
// All encountered class defs are entered into classdefs table.
public void visitClassDef(JCClassDecl tree) {
classdefs.put(tree.sym, tree);
super.visitClassDef(tree);
}
}
ClassMap classMap = new ClassMap();
/** Map a class symbol to its definition.
* @param c The class symbol of which we want to determine the definition.
*/
JCClassDecl classDef(ClassSymbol c) {
// First lookup the class in the classdefs table.
JCClassDecl def = classdefs.get(c);
if (def == null && outermostMemberDef != null) {
// If this fails, traverse outermost member definition, entering all
// local classes into classdefs, and try again.
classMap.scan(outermostMemberDef);
def = classdefs.get(c);
}
if (def == null) {
// If this fails, traverse outermost class definition, entering all
// local classes into classdefs, and try again.
classMap.scan(outermostClassDef);
def = classdefs.get(c);
}
return def;
}
/** A hash table mapping class symbols to lists of free variables.
* accessed by them(就是说这些自由变量被class symbols所使用).
* Only free variables of the method immediately containing
* a class are associated with that class.
*/
Map<ClassSymbol,List<VarSymbol>> freevarCache;
/**
* Return the variables accessed from within a local class, which
* are declared in the local class‘ owner.
* (in reverse order of first access).
*/
/*
*/
List<VarSymbol> freevars(ClassSymbol c) {
if ( (c.owner.kind & (VAR04 | MTH16)) != 0 ) { // c是Local Class
List<VarSymbol> fvs = freevarCache.get(c);
if ( fvs == null ) {
FreeVarCollector collector = new FreeVarCollector(Lower.this,c);
JCClassDecl jcd = classDef(c); // 通过Symbol查找Tree
collector.scan(jcd);
fvs = collector.fvs;
freevarCache.put(c, fvs);
}
return fvs;
} else {
return List.nil();
}
}
Map<TypeSymbol,EnumMapping> enumSwitchMap = new LinkedHashMap<TypeSymbol,EnumMapping>();
EnumMapping mapForEnum(JCDiagnosticPosition pos, TypeSymbol enumClass) {
EnumMapping map = enumSwitchMap.get(enumClass);
if (map == null) {
map = new EnumMapping(Lower.this,pos, enumClass);
enumSwitchMap.put(enumClass, map);
}
return map;
}
/**************************************************************************
* Tree building blocks
*************************************************************************/
/** Equivalent to treeMaker.at(pos.getStartPosition()) with side effect of caching
* pos as make_pos, for use in diagnostics.
**/
TreeMaker make_at(JCDiagnosticPosition pos) {
make_pos = pos;
return make.at(pos);
}
/** Make an attributed tree representing a literal. This will be an
* Ident node in the case of boolean literals, a Literal node in all
* other cases.
* @param type The literal‘s type.
* @param value The literal‘s value.
*/
JCExpression makeLit(Type type, Object value) {
JCLiteral jcl = make.Literal(type.tag, value);
Type ct = type.constType(value);
return jcl.setType(ct);
}
/** Make an attributed tree representing null.
*/
JCExpression makeNull() {
return makeLit(syms.botType, null);
}
/** Make an attributed class instance creation expression.
* @param ctype The class type.
* @param args The constructor arguments.
*/
JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
JCExpression qualIdentJCE = make.QualIdent(ctype.tsym);
JCNewClass tree = make.NewClass(null,null,qualIdentJCE , args, null);
tree.constructor = rs.resolveConstructor(
make_pos, attrEnv, ctype, TreeInfo.types(args),
null, false, false);
tree.type = ctype;
return tree;
}
/** Make an attributed unary expression.
* @param optag The operators tree tag.
* @param arg The operator‘s argument.
*/
JCUnary makeUnary(int optag, JCExpression arg) {
JCUnary tree = make.Unary(optag, arg);
tree.operator = rs.resolveUnaryOperator(
make_pos, optag, attrEnv, arg.type);
tree.type = tree.operator.type.getReturnType();
return tree;
}
/** Make an attributed binary expression.
* @param optag The operators tree tag.
* @param lhs The operator‘s left argument.
* @param rhs The operator‘s right argument.
*/
JCBinary makeBinary(int optag, JCExpression lhs, JCExpression rhs) {
JCBinary tree = make.Binary(optag, lhs, rhs);
tree.operator = rs.resolveBinaryOperator(
make_pos, optag, attrEnv, lhs.type, rhs.type);
tree.type = tree.operator.type.getReturnType();
return tree;
}
/** Make an attributed assignop expression.
* @param optag The operators tree tag.
* @param lhs The operator‘s left argument.
* @param rhs The operator‘s right argument.
*/
JCAssignOp makeAssignop(int optag, JCTree lhs, JCTree rhs) {
JCAssignOp tree = make.Assignop(optag, lhs, rhs);
tree.operator = rs.resolveBinaryOperator(
make_pos, tree.getTag() - JCTree.ASGOffset, attrEnv, lhs.type, rhs.type);
tree.type = lhs.type;
return tree;
}
/** Convert tree into string object, unless it has already a
* reference type..
*/
JCExpression makeString(JCExpression tree) {
if (tree.type.tag >= CLASS10) {
return tree;
} else {
Symbol valueOfSym = lookupMethod(tree.pos(),
names.valueOf,
syms.stringType, // java.lang.String
List.of(tree.type));
return make.App(make.QualIdent(valueOfSym), List.of(tree));
}
}
/** Create an empty anonymous class definition and enter and complete
* its symbol. Return the class definition‘s symbol.
* and create
* @param flags The class symbol‘s flags
* @param owner The class symbol‘s owner
*/
ClassSymbol makeEmptyClass(long flags, ClassSymbol owner) {
// Create class symbol.
ClassSymbol c = reader.defineClass(names.empty, owner);
c.flatname = chk.localClassName(c);
c.sourcefile = owner.sourcefile;
c.completer = null;
c.members_field = new Scope(c);
c.flags_field = flags;
ClassType ctype = (ClassType) c.type;
ctype.supertype_field = syms.objectType;
ctype.interfaces_field = List.nil();
JCClassDecl odef = classDef(owner);
// Enter class symbol in owner scope and compiled table.
enterSynthetic(odef.pos(), c, owner.members());
chk.compiled.put(c.flatname, c);
// Create class definition tree.
JCClassDecl cdef = make.ClassDef(
make.Modifiers(flags), names.empty,
List.<JCTypeParameter>nil(),
null, List.<JCExpression>nil(), List.<JCTree>nil());
cdef.sym = c;
cdef.type = c.type;
// Append class definition tree to owner‘s definitions.
odef.defs = odef.defs.prepend(cdef);
return c;
}
/**************************************************************************
* Symbol manipulation utilities
*************************************************************************/
/** Enter a synthetic symbol in a given scope, but complain if there was already one there.
* @param pos Position for error reporting.
* @param sym The symbol.
* @param s The scope.
*/
void enterSynthetic(JCDiagnosticPosition pos, Symbol sym, Scope s) {
s.enter(sym);
}
/** Create a fresh synthetic name within a given scope - the unique name is
* obtained by appending ‘$‘ chars at the end of the name until no match
* is found.
*
* @param name base name
* @param s scope in which the name has to be unique
* @return fresh synthetic name
*/
private Name makeSyntheticName(Name name, Scope s) {
do {
name = name.append(target.syntheticNameChar(), names.empty);
} while (lookupSynthetic(name, s) != null);
return name;
}
/** Check whether synthetic symbols generated during lowering conflict
* with user-defined symbols.
*
* @param translatedTrees lowered class trees
*/
void checkConflicts(List<JCTree> translatedTrees) {
for (JCTree t : translatedTrees) {
t.accept(conflictsChecker);
}
}
JCTreeVisitor conflictsChecker = new TreeScanner() {
TypeSymbol currentClass;
@Override
public void visitMethodDef(JCMethodDecl that) { // 方法名称
chk.checkConflicts(that.pos(), that.sym, currentClass);
super.visitMethodDef(that);
}
@Override
public void visitVarDef(JCVariableDecl that) { // 成员变量名称
if (that.sym.owner.kind == TYP02) { // 只检查Field
chk.checkConflicts(that.pos(), that.sym, currentClass);
}
super.visitVarDef(that);
}
@Override
public void visitClassDef(JCClassDecl that) { // 访问类时更改currentClass属性的值
TypeSymbol prevCurrentClass = currentClass;
currentClass = that.sym;
try {
super.visitClassDef(that);
} finally {
currentClass = prevCurrentClass;
}
}
};
/** Look up a synthetic name in a given scope.
* @param scope The scope.
* @param name The name.
*/
private Symbol lookupSynthetic(Name name, Scope s) {
Symbol sym = s.lookup(name).sym;
if(sym==null ||
(sym.flags()&SYNTHETIC)==0){
return null;
}else{
return sym;
}
}
/** Look up a method in a given scope.
*/
public MethodSymbol lookupMethod(JCDiagnosticPosition pos, Name name, Type qual, List<Type> args) {
return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, null);
}
/** Look up a constructor.
*/
private MethodSymbol lookupConstructor(JCDiagnosticPosition pos, Type qual, List<Type> args) {
return rs.resolveInternalConstructor(pos, attrEnv, qual, args, null);
}
/** Look up a field.
*/
// private VarSymbol lookupField(JCDiagnosticPosition pos, Type qual, Name name) {
// return rs.resolveInternalField(pos, attrEnv, qual, name);
// }
/** Anonymous inner classes are used as access constructor tags.
* accessConstructorTag will use an existing anon class if one is available,
* and synthethise a class (with makeEmptyClass) if one is not available.
* However, there is a small possibility that an existing class will not
* be generated as expected if it is inside a conditional with a constant
* expression. If that is found to be the case, create an empty class here.
*/
private void checkAccessConstructorTags() {
for (List<ClassSymbol> l = accessConstrTags; l.nonEmpty(); l = l.tail) {
ClassSymbol c = l.head;
if (isTranslatedClassAvailable(c)) {
continue;
}
// Create class definition tree.
JCClassDecl cdef = make.ClassDef(
make.Modifiers(STATIC | SYNTHETIC), names.empty,
List.<JCTypeParameter>nil(),
null, List.<JCExpression>nil(), List.<JCTree>nil());
cdef.sym = c;
cdef.type = c.type;
// add it to the list of classes to be generated
translated.append(cdef);
}
}
// where
private boolean isTranslatedClassAvailable(ClassSymbol c) {
for (JCTree tree: translated) {
if (tree.getTag() == JCTree.CLASSDEF
&& ((JCClassDecl) tree).sym == c) {
return true;
}
}
return false;
}
/**************************************************************************
* Access methods
*************************************************************************/
/** Access codes for dereferencing(解引用), assignment,
* and pre/post increment/decrement.
* Access codes for assignment operations are determined
* by method accessCode below.
*
* All access codes for accesses to the current class are even. 都是偶数
* If a member of the superclass should be accessed instead (because
* access was via a qualified super), add one to the corresponding code
* for the current class, making the number odd.
* This numbering scheme is used by the backend to decide whether
* to issue an invokevirtual or invokespecial call.
* 后端使用他的编号方案来决定是否发出一个invokevirtual或invokespecial call。
* @see Gen.visitSelect(Select tree)
*/
// 关于invokevirtual与invokespecial指令相关介绍:
// https://www.cnblogs.com/extjs4/p/9103190.html
private static final int
DEREFcode = 0, // deref
ASSIGNcode = 2, // assign
PREINCcode = 4, // preinc
PREDECcode = 6, // predec
POSTINCcode = 8, // postinc
POSTDECcode = 10, // postdec
FIRSTASGOPcode = 12; // first assignment op
/** Number of access codes
*/
private static final int NCODES = accessCode(ByteCodes.lushrl) + 2; // 98
/** A mapping from symbols to their access numbers.
*/
private Map<Symbol,Integer> accessNums;
/** A mapping from symbols to an array of access symbols, indexed by
* access code.
*/
private Map<Symbol,MethodSymbol[]> accessSyms;
/** A mapping from (constructor) symbols to access constructor symbols.
*/
private Map<Symbol,MethodSymbol> accessConstrs;
/** A list of all class symbols used for access constructor tags.
*/
private List<ClassSymbol> accessConstrTags;
/** A queue for all accessed symbols.
*/
private ListBuffer<Symbol> accessed;
/** Map bytecode of binary operation to access code of corresponding
* assignment operation. This is always an even number. 偶数
*/
private static int accessCode(int bytecode) {
if (ByteCodes.iadd <= bytecode && // iadd = 96
bytecode <= ByteCodes.lxor) { // lxor = 131
return (bytecode - iadd) * 2 + FIRSTASGOPcode; // (275-96)*2 + 12 = 270
}
else if (bytecode == ByteCodes.string_add) { // string_add = 256
return (ByteCodes.lxor + 1 - iadd) * 2 + FIRSTASGOPcode; // (131 + 1 -96)*2 + 12 = 84
}
else if (ByteCodes.ishll <= bytecode && // ishll = 270
bytecode <= ByteCodes.lushrl) { // lushrl = 275
// (270 - 270 + 131 + 2 - 96)*2 + 12 = 86
return (bytecode - ishll + ByteCodes.lxor + 2 - iadd) * 2 + FIRSTASGOPcode;
}else {
return -1;
}
}
/** return access code for identifier,
* @param tree The tree representing the identifier use.
* @param enclOp The closest enclosing operation node of tree,
* null if tree is not a subtree of an operation.
*/
private static int accessCode(JCTree tree, JCTree enclOp) {
if (enclOp == null) {
return DEREFcode;
}
else if (enclOp.getTag() == JCTree.ASSIGN &&
tree == TreeInfo.skipParens(((JCAssign) enclOp).lhs)
){
return ASSIGNcode;
}
else if (JCTree.PREINC <= enclOp.getTag() &&
enclOp.getTag() <= JCTree.POSTDEC &&
tree == TreeInfo.skipParens(((JCUnary) enclOp).arg)
){
return (enclOp.getTag() - JCTree.PREINC) * 2 + PREINCcode;
}
else if ( JCTree.BITOR_ASG <= enclOp.getTag() &&
enclOp.getTag() <= JCTree.MOD_ASG &&
tree == TreeInfo.skipParens(((JCAssignOp) enclOp).lhs)
) {
OperatorSymbol s = (OperatorSymbol) ((JCAssignOp) enclOp).operator;
int opd = s.opcode;
int temp = accessCode(opd);
return temp;
}
else {
return DEREFcode;
}
}
/** Return binary operator that corresponds to given access code.
*/
private OperatorSymbol binaryAccessOperator(int acode) {
for (Scope.Entry e = syms.predefClass.members().elems;
e != null;
e = e.sibling) {
if (e.sym instanceof OperatorSymbol) {
OperatorSymbol op = (OperatorSymbol)e.sym;
if (accessCode(op.opcode) == acode) {
return op;
}
}
}
return null;
}
/** Return tree tag for assignment operation corresponding
* to given binary operator.
*/
private static int treeTag(OperatorSymbol operator) {
switch (operator.opcode) {
case ByteCodes.ior: case ByteCodes.lor: // int或者long类型按位或
return JCTree.BITOR_ASG;
case ByteCodes.ixor: case ByteCodes.lxor:
return JCTree.BITXOR_ASG;
case ByteCodes.iand: case ByteCodes.land:
return JCTree.BITAND_ASG;
case ByteCodes.ishl: case ByteCodes.lshl:
case ByteCodes.ishll: case ByteCodes.lshll:
return JCTree.SL_ASG;
case ByteCodes.ishr: case ByteCodes.lshr:
case ByteCodes.ishrl: case ByteCodes.lshrl:
return JCTree.SR_ASG;
case ByteCodes.iushr: case ByteCodes.lushr:
case ByteCodes.iushrl: case ByteCodes.lushrl:
return JCTree.USR_ASG;
case ByteCodes.iadd: case ByteCodes.ladd:
case ByteCodes.fadd: case ByteCodes.dadd:
case ByteCodes.string_add:
return JCTree.PLUS_ASG;
case ByteCodes.isub: case ByteCodes.lsub:
case ByteCodes.fsub: case ByteCodes.dsub:
return JCTree.MINUS_ASG;
case ByteCodes.imul: case ByteCodes.lmul:
case ByteCodes.fmul: case ByteCodes.dmul:
return JCTree.MUL_ASG;
case ByteCodes.idiv: case ByteCodes.ldiv:
case ByteCodes.fdiv: case ByteCodes.ddiv:
return JCTree.DIV_ASG;
case ByteCodes.imod: case ByteCodes.lmod:
case ByteCodes.fmod: case ByteCodes.dmod:
return JCTree.MOD_ASG;
default:
throw new AssertionError();
}
}
/** The name of the access method with number `anum‘ and access code `acode‘.
*/
Name accessName(int anum, int acode) {
String temp = "access" + target.syntheticNameChar() + anum + acode / 10 + acode % 10;
return names.fromString(temp);
}
/** Return access symbol for a private or protected symbol from an inner class.
* @param sym The accessed private symbol.
* @param tree The accessing tree.
* @param enclOp The closest enclosing operation node of tree,null if tree is not a subtree of an operation.
* @param protectedAccess Is access to a protected symbol in another package?
* @param refSuper Is access via a (qualified) C.super?
*/
MethodSymbol accessSymbol(Symbol sym, JCTree tree, JCTree enclOp,
boolean protectedAccess, boolean refSuper) {
ClassSymbol accOwner = null;
if(refSuper && protectedAccess){
// For access via qualified super (T.super.x), place the
// access symbol on T.
accOwner = (ClassSymbol)((JCFieldAccess) tree).selected.type.tsym;
}else{
// Otherwise pretend that the owner of an accessed
// protected symbol is the enclosing class of the current
// class which is a subclass of the symbol‘s owner.
accOwner = accessClass(sym, protectedAccess, tree);
}
Symbol vsym = sym;
if (sym.owner != accOwner) {
vsym = sym.clone(accOwner); // 会替换sym的所以owner符号
actualSymbols.put(vsym, sym);
}
// The access number of the access method.
Integer anum = accessNums.get(vsym);
if (anum == null) {
anum = accessed.length();
accessNums.put(vsym, anum);
accessSyms.put(vsym, new MethodSymbol[NCODES]);
accessed.append(vsym);
// System.out.println("accessing " + vsym + " in " + vsym.location());
}
int acode; // The access code of the access method.
List<Type> argtypes; // The argument types of the access method.
Type restype; // The result type of the access method.
List<Type> thrown; // The thrown exceptions of the access method.
switch (vsym.kind) {
case VAR04:
acode = accessCode(tree, enclOp);
if (acode >= FIRSTASGOPcode) { // first assignment op
OperatorSymbol operator = binaryAccessOperator(acode);
if (operator.opcode == string_add) {
argtypes = List.of(syms.objectType);
}else {
argtypes = operator.type.getParameterTypes().tail;
}
} else if (acode == ASSIGNcode) {
argtypes = List.of(vsym.erasure(types));
}else {
argtypes = List.nil();
}
restype = vsym.erasure(types);
thrown = List.nil();
break;
case MTH16:
acode = DEREFcode;
argtypes = vsym.erasure(types).getParameterTypes();
restype = vsym.erasure(types).getReturnType();
thrown = vsym.type.getThrownTypes();
break;
default:
throw new AssertionError();
}
// For references via qualified super, increment acode by one,making it odd.
if (protectedAccess && refSuper) {
acode++;
}
// Instance access methods get instance as first parameter.
// For protected symbols this needs to be the instance as a member
// of the type containing the accessed symbol, not the class
// containing the access method.
if ((vsym.flags() & STATIC) == 0) {
Type eratype = vsym.owner.erasure(types);
argtypes = argtypes.prepend(eratype);
}
MethodSymbol[] accessors = accessSyms.get(vsym);
MethodSymbol accessor = accessors[acode];
if (accessor == null) {
Name name = accessName(anum.intValue(), acode);
MethodType mt = new MethodType(argtypes, restype, thrown, syms.methodClass);
accessor = new MethodSymbol(STATIC | SYNTHETIC,name,mt,accOwner);
enterSynthetic(tree.pos(), accessor, accOwner.members());
accessors[acode] = accessor;
}
return accessor;
}
/** The qualifier to be used for accessing a symbol in an outer class.
* This is either C.sym or C.this.sym, depending on whether or not
* sym is static.
* @param sym The accessed symbol.
*/
JCExpression accessBase(JCDiagnosticPosition pos, Symbol sym) {
if((sym.flags() & STATIC) != 0){
JCExpression jce = make.at(pos.getStartPosition()).QualIdent(sym.owner);
return access(jce);
}else{
return makeOwnerThis(pos, sym, true);
}
}
/** Do we need an access method to reference private symbol?
*/
boolean needsPrivateAccess(Symbol sym) {
if ((sym.flags() & PRIVATE) == 0 || // 构造函数没有private修饰
sym.owner == currentClass) { // 在当前类中使用私有构造函数
return false;
} else if ( sym.name == names.init && // 是构造函数
(sym.owner.owner.kind & (VAR04 | MTH16)) != 0) {
/*
eg1:
class Outer {
public void test() {
class C{
private C(){}
}
new C();
}
}
*/
// private constructor in local class: relax protection 放松防护
sym.flags_field &= ~PRIVATE; // 去掉private修饰符
return false;
} else {
/*
eg1:
class Outer {
class C{
private C(){}
}
public void t(){ // 方法
new C(); // 访问私有方法,如果class C为top level class,那么new C()将报错
}
}
eg2:
public class Test03{
private int a = 1;
class Inner{
public void t(){
int b = a; // Test03.access$000(this$0)
}
}
}
*/
return true;
}
}
/** Do we need an access method to reference symbol in other package?
*/
boolean needsProtectedAccess(Symbol sym, JCTree tree) {
if ((sym.flags() & PROTECTED) == 0 || // 无protected修饰
sym.owner.owner == currentClass.owner || // fast special case
sym.packge() == currentClass.packge() // 在同一个包中
){
return false; // 不需要access method
}
/*
eg1:
package com.test18;
import com.test19.TestProtectedClass;
class Outer extends TestProtectedClass{
class Inner {
public void t(){
int b = a; // 访问a时需要access method
}
}
}
package com.test19;
public class TestProtectedClass {
protected int a = 0;
}
*/
if (!currentClass.isSubClass(sym.owner, types)) {
return true;
}
if ((sym.flags() & STATIC) != 0 ||
tree.getTag() != JCTree.SELECT ||
TreeInfo.name(((JCFieldAccess) tree).selected) == names._super
){
return false; // 不需要access method
}
/*
eg1:
package com.test18;
import com.test19.TestProtectedClass;
class OuterA extends TestProtectedClass{}
class OuterB extends TestProtectedClass{
Object o = new OuterA(){
public void t() {
int b = new OuterB().a; // OuterB与OuterA$1无继承关系
}
};
}
*/
TypeSymbol ts = ((JCFieldAccess) tree).selected.type.tsym;
boolean ret = ts.isSubClass(currentClass, types);
return !ret;
}
/** The class in which an access method for given symbol goes.
* @param sym The access symbol
* @param protAccess Is access to a protected symbol in another package?
*/
ClassSymbol accessClass(Symbol sym, boolean protAccess, JCTree tree) {
if (protAccess) {
Symbol qualifier = null;
ClassSymbol c = currentClass;
if (tree.getTag() == JCTree.SELECT && (sym.flags() & STATIC) == 0) {
qualifier = ((JCFieldAccess) tree).selected.type.tsym;
while (!qualifier.isSubClass(c, types)) {
c = c.owner.enclClass();
}
return c;
} else {
while (!c.isSubClass(sym.owner, types)) {
c = c.owner.enclClass();
}
}
return c;
} else {
return sym.owner.enclClass(); // the symbol is private
}
}
/** Ensure that identifier is accessible, return tree accessing the identifier.
* @param sym The accessed symbol.
* @param tree The tree referring to the symbol.
* @param enclOp The closest enclosing operation node of tree,
* null if tree is not a subtree of an operation.
* @param refSuper Is access via a (qualified) C.super?
*/
JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean refSuper) {
// Access a free variable via its proxy, or its proxy‘s proxy
while ( sym.kind == VAR04 && // 是变量
sym.owner.kind == MTH16 && // 是本地变量
sym.owner.enclClass() != currentClass //
){
// A constant is replaced by its constant value.
Object cv = ((VarSymbol)sym).getConstValue();
/*
class Outer {
public void methodFromTestScope(final a){ //
final int b = 1;
class InnerB{
public void t(){
int x = a; // a符号会往下走,
int y = b; // 将符号a替换成Literal(1)
}
}
}
}
*/
if (cv != null) {
make.at(tree.pos);
return makeLit(sym.type, cv);
}
// Otherwise replace the variable by its proxy.
sym = proxies.lookup(proxyName(sym.name)).sym;
// 符号不为空并且有final关键字修饰
Assert.check(sym != null && (sym.flags_field & FINAL) != 0);
tree = make.at(tree.pos).Ident(sym);
}
JCExpression base = null;
if(tree.getTag() == JCTree.SELECT){
base = ((JCFieldAccess) tree).selected;
}
switch (sym.kind) {
case TYP02:
if (sym.owner.kind != PCK01) {
// Convert type idents to
// <flat name> or <package name> . <flat name>
/*
package com.test18;
class Outer{
class Inner{ // n = com.test18.Outer$Inner; flatname = Outer$Inner
private Inner(){}
}
}
*/
Name n = sym.flatName();
Name flatname = Convert.shortName(n);
while (base != null &&
TreeInfo.symbol(base) != null &&
TreeInfo.symbol(base).kind != PCK01) {
if(base.getTag() == JCTree.SELECT){
base = ((JCFieldAccess) base).selected;
}else{
base = null;
}
}
// 为name属性赋值,主要是为内部类
if (tree.getTag() == JCTree.IDENT) {
((JCIdentifier) tree).name = flatname;
} else if (base == null) {
tree = make.at(tree.pos).Ident(sym);
((JCIdentifier) tree).name = flatname;
} else {
((JCFieldAccess) tree).selected = base;
((JCFieldAccess) tree).name = flatname;
}
}
break;
case MTH16: case VAR04:
if (sym.owner.kind == TYP02) {
// Access methods are required for
// - private members,
// - protected members in a superclass of an enclosing class contained in another package.
// - all non-private members accessed via a qualified super.
// 在Java中 && 比 || 优先
boolean protAccess = refSuper && !needsPrivateAccess(sym)
|| needsProtectedAccess(sym, tree);
boolean accReq = protAccess || needsPrivateAccess(sym);
// A base has to be supplied for
// - simple identifiers accessing variables in outer classes.
/*
class Outer{
final int count1 = new Integer(1);
public void t(){
class Inner{
int a = count1;// 在获取count1时,重写为this$0.count1
}
}
}
*/
boolean baseReq =
base == null && // 没有限制符
sym.owner != syms.predefClass && // 不是预定义的符号
!sym.isMemberOf(currentClass, types);// 不是当前类的成员
if (accReq || baseReq) {
make.at(tree.pos);
// Constants are replaced by their constant value.
if (sym.kind == VAR04) {
Object cv = ((VarSymbol)sym).getConstValue();
if (cv != null) {
return makeLit(sym.type, cv);
}
}
// Private variables and methods are replaced by calls
// to their access methods.
if (accReq) {
List<JCExpression> args = List.nil();
if ((sym.flags() & STATIC) == 0) {
// Instance access methods get instance
// as first parameter.
if (base == null) {
base = makeOwnerThis(tree.pos(), sym, true);
}
args = args.prepend(base);
base = null; // so we don‘t duplicate code
}
Symbol access = accessSymbol(sym, tree,enclOp, protAccess,refSuper);
JCExpression receiver = null;
if( base != null){
receiver = make.Select(base,access);
}else{
receiver = make.Select(make.QualIdent(access.owner),access);
}
return make.App(receiver, args);
// Other accesses to members of outer classes get a qualifier.
} else if (baseReq) {
JCExpression jce = accessBase(tree.pos(), sym);
JCExpression res = make.at(tree.pos).Select(jce, sym).setType(tree.type);
return res;
}
}
}// end if
}
return tree;
}
/** Ensure that identifier is accessible, return tree accessing the identifier.
* @param tree The identifier tree.
*/
JCExpression access(JCExpression tree) {
Symbol sym = TreeInfo.symbol(tree);
if(sym == null){
return tree;
}else{
return access(sym, tree, null, false);
}
}
/** Return access constructor for a private constructor,
* or the constructor itself, if no access constructor is needed.
* @param pos The position to report diagnostics, if any.
* @param constr The private constructor.
*/
Symbol accessConstructor(JCDiagnosticPosition pos, Symbol constr) {
/*
eg1:
class Outer {
// 需要为这个构造函数添加private access,最终的aconstr为
// Outer(<匿名java.lang.Object>),可以到会在形式参数的最后添加一个ClassType
// 参考:https://www.cnblogs.com/extjs4/p/9346639.html
// todo 为什么要这样做?
private Outer(){}
class AOuter extends Outer{
public AOuter(){
super();
}
}
}
*/
if (needsPrivateAccess(constr)) {
ClassSymbol accOwner = constr.owner.enclClass();
MethodSymbol aconstr = accessConstrs.get(constr);
if (aconstr == null) {
List<Type> argtypes = constr.type.getParameterTypes();
if ((accOwner.flags_field & ENUM) != 0) {
argtypes = argtypes.prepend(syms.intType).prepend(syms.stringType);
}
ClassSymbol cs = accessConstructorTag(); // 唯一调用这个方法的地方
Type eraType = cs.erasure(types);
MethodType mt = new MethodType(
argtypes.append(eraType),
constr.type.getReturnType(),
constr.type.getThrownTypes(),
syms.methodClass);
aconstr = new MethodSymbol(
SYNTHETIC, // 合成的
names.init, // 构造方法
mt, // 填充type属性
accOwner); // 填充owner属性
enterSynthetic(pos, aconstr, accOwner.members());
accessConstrs.put(constr, aconstr);
accessed.append(constr);
}
return aconstr;
} else {
return constr;
}
}
/** Return an anonymous class nested in this toplevel class.
*/
ClassSymbol accessConstructorTag() {
ClassSymbol topClass = currentClass.outermostClass();
String temp = "" + topClass.getQualifiedName() +target.syntheticNameChar() + "1";
Name flatname = names.fromString(temp);
ClassSymbol ctag = chk.compiled.get(flatname);
if (ctag == null) {
ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass);
}
// keep a record of all tags, to verify that all are generated as required
accessConstrTags = accessConstrTags.prepend(ctag);
return ctag;
}
/** Add all required access methods for a private symbol to enclosing class.
* @param sym The symbol.
*/
void makeAccessible(Symbol sym) {
JCClassDecl cdef = classDef(sym.owner.enclClass());
if (cdef == null) {
Assert.error("class def not found: " + sym + " in " + sym.owner);
}
if (sym.name == names.init) {
MethodSymbol ms = accessConstrs.get(sym);
JCTree jcTree = accessConstructorDef(cdef.pos, sym, ms);
cdef.defs = cdef.defs.prepend(jcTree);
} else {
MethodSymbol[] accessors = accessSyms.get(sym);
// for(int i=0;i<accessors.length;i++) {
// System.out.println(accessors[i]);
// }
// System.out.println(accessors.length);
for (int i = 0; i < NCODES; i++) {
if (accessors[i] != null) {
JCTree jcTree = accessDef(cdef.pos, sym, accessors[i], i);
cdef.defs = cdef.defs.prepend(jcTree);
}
}
}
}
/** Construct definition of an access method.
* @param pos The source code position of the definition.
* @param vsym The private or protected symbol.
* @param accessor The access method for the symbol.
* @param acode The access code.
*/
JCTree accessDef(int pos, Symbol vsym, MethodSymbol accessor, int acode) {
// System.err.println("access " + vsym + " with " + accessor);//DEBUG
currentClass = vsym.owner.enclClass();
make.at(pos);
JCMethodDecl md = make.MethodDef(accessor, null);
// Find actual symbol
Symbol sym = actualSymbols.get(vsym);
if (sym == null) {
sym = vsym;
}
JCExpression ref; // The tree referencing the private symbol.
List<JCExpression> args; // Any additional arguments to be passed along.
if ((sym.flags() & STATIC) != 0) {
ref = make.Ident(sym);
args = make.Idents(md.params);
} else {
ref = make.Select(make.Ident(md.params.head), sym);
args = make.Idents(md.params.tail);
}
JCStatement stat; // The statement accessing the private symbol.
if (sym.kind == VAR04) {
// Normalize out all odd access codes by taking floor modulo 2:
int acode1 = acode - (acode & 1);
JCExpression expr; // The access method‘s return value.
switch (acode1) {
case DEREFcode:
expr = ref;
break;
case ASSIGNcode:
expr = make.Assign(ref, args.head);
break;
case PREINCcode: case POSTINCcode: case PREDECcode: case POSTDECcode:
expr = makeUnary(((acode1 - PREINCcode) >> 1) + JCTree.PREINC, ref);
break;
default:
expr = make.Assignop(treeTag(binaryAccessOperator(acode1)), ref, args.head);
((JCAssignOp) expr).operator = binaryAccessOperator(acode1);
}
stat = make.Return(expr.setType(sym.type));
} else {
stat = make.Call(make.App(ref, args));
}
md.body = make.Block(0, List.of(stat));
// Make sure all parameters, result types and thrown exceptions
// are accessible.
for (List<JCVariableDecl> l = md.params; l.nonEmpty(); l = l.tail) {
l.head.vartype = access(l.head.vartype);
}
md.restype = access(md.restype);
for (List<JCExpression> l = md.thrown; l.nonEmpty(); l = l.tail) {
l.head = access(l.head);
}
return md;
}
/** Construct(构建) definition of an access constructor.
* @param pos The source code position of the definition.
* @param constr The private constructor.
* @param accessor The access method for the constructor.
*/
/*
class Outer {
private Outer(String... a) { }
class AOuter extends Outer {
public AOuter() {
super("a", "b");
}
}
}
返回的JCTree为
<init>(String[] x0, com.test18.Outer$1 x1) { // synthetic
this(x0);
}
*/
JCTree accessConstructorDef(int pos, Symbol constr, MethodSymbol accessor) {
make.at(pos);
Type exType = accessor.externalType(types);
JCMethodDecl md = make.MethodDef(accessor,exType,null);
JCIdentifier callee = make.Ident(names._this);
callee.sym = constr;
callee.type = constr.type;
List<JCExpression> list = make.Idents(md.params.reverse().tail.reverse());
JCStatement jcs = make.Call(make.App(callee,list));
md.body = make.Block(0, List.<JCStatement>of(jcs));
return md;
}
/**************************************************************************
* Free variables proxies and this$n
*************************************************************************/
/** A scope containing all free variable proxies for currently translated
* class, as well as its this$n symbol (if needed).
* Proxy scopes are nested in the same way classes are.
* Inside a constructor, proxies and any this$n symbol are duplicated
* in an additional innermost(最深的,最里面的) scope, where they represent the constructor
* parameters.
*/
Scope proxies;
/** A scope containing all unnamed resource variables/saved
* exception variables for translated TWR blocks
*/
Scope twrVars;
/** A stack containing the this$n field of the currently translated
* classes (if needed) in innermost first order.
* Inside a constructor, proxies and any this$n symbol are duplicated
* in an additional(附加的,额外的) innermost scope, where they represent the constructor
* parameters.
*/
List<VarSymbol> outerThisStack;
/** The name of a free variable proxy.
*/
Name proxyName(Name name) {
return names.fromString("val" + target.syntheticNameChar() + name);
}
/** Proxy definitions for all free variables in given list, in reverse order.
* @param pos The source code position of the definition.
* @param freevars The free variables.
* @param owner The class in which the definitions go.
*/
/*
class Outer {
public void methodFromTestScope(final int t){
final int a ;
class InnerB{
int x = t; // t最终为val$t
public void t(){
}
}
}
}
*/
List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
long flags = FINAL | SYNTHETIC;
if (owner.kind == TYP02 &&
target.usePrivateSyntheticFields()){ // 一般为false,进不了这个循环
flags |= PRIVATE;
}
List<JCVariableDecl> defs = List.nil();
for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail) {
VarSymbol v = l.head;
Name temp = proxyName(v.name); // 在name前追加"val$"字符串
VarSymbol proxy = new VarSymbol(flags, temp , v.erasure(types), owner);
proxies.enter(proxy);
// 将列表中的自由变量名称追加"val$"后定义出新的类型声明
JCVariableDecl vd = make.at(pos).VarDef(proxy, null);
vd.vartype = access(vd.vartype);
defs = defs.prepend(vd);
}
return defs;
}
/** The name of a this$n field
* @param type The class referenced by the this$n field
*/
/*
class Outer {
class AOuter{
// final Outer this$0 合成的变量
class BOuter{
// final Outer$AOuter this$1 合成的变量
}
}
}
*/
Name outerThisName(Type type, Symbol owner) {
Type t = type.getEnclosingType();
int nestingLevel = 0;
while (t.tag == CLASS10) {
t = t.getEnclosingType();
nestingLevel++;
}
Name result = names.fromString("this" + target.syntheticNameChar() + nestingLevel);
while ( owner.kind == TYP02) {
Scope sp = ((ClassSymbol)owner).members();
if( sp.lookup(result).scope == null ){ // 查询不能有重复的name
break;
}
result = names.fromString(result.toString() + target.syntheticNameChar());
}
return result;
}
/** Definition for this$n field.
* 查看:http://www.cnblogs.com/extjs4/p/7388022.html
*
* @param pos The source code position of the definition.
* @param owner The class in which the definition goes.
*/
JCVariableDecl outerThisDef(int pos, Symbol owner) {
long flags = FINAL | SYNTHETIC;
if (owner.kind == TYP02 &&
target.usePrivateSyntheticFields()) {
flags |= PRIVATE;
}
ClassSymbol enclCS = owner.enclClass();
Type enclType = enclCS.type.getEnclosingType();
Type target = types.erasure(enclType);
Name name = outerThisName(target, owner);
VarSymbol outerThis = new VarSymbol(flags,name, target, owner);
outerThisStack = outerThisStack.prepend(outerThis);
JCVariableDecl vd = make.at(pos).VarDef(outerThis, null);
vd.vartype = access(vd.vartype);
return vd;
}
/** Return a list of trees that load the free variables in given list,
* in reverse order.
* @param pos The source code position to be used for the trees.
* @param freevars The list of free variables.
*/
List<JCExpression> loadFreevars(JCDiagnosticPosition pos, List<VarSymbol> freevars) {
List<JCExpression> args = List.nil();
for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail) {
JCExpression jce = loadFreevar(pos, l.head);
args = args.prepend(jce);
}
return args;
}
//where
JCExpression loadFreevar(JCDiagnosticPosition pos, VarSymbol v) {
return access(v, make.at(pos).Ident(v), null, false);
}
/** Construct a tree simulating the expression <C.this>.
* @param pos The source code position to be used for the tree.
* @param c The qualifier class.
*/
JCExpression makeThis(JCDiagnosticPosition pos, TypeSymbol c) {
if (currentClass == c) {
// in this case, `this‘ works fine
return make.at(pos).This(c.erasure(types));
} else {
// need to go via this$n
return makeOuterThis(pos, c);
}
}
/**
* Optionally replace a try statement with the desugaring of a
* try-with-resources statement. The canonical desugaring of
*
* try ResourceSpecification
* Block
*
* is
*
* {
* final VariableModifiers_minus_final R #resource = Expression;
* Throwable #primaryException = null;
*
* try ResourceSpecificationtail
* Block
* catch (Throwable #t) {
* #primaryException = t;
* throw #t;
* } finally {
* if (#resource != null) {
* if (#primaryException != null) {
* try {
* #resource.close();
* } catch(Throwable #suppressedException) {
* #primaryException.addSuppressed(#suppressedException);
* }
* } else {
* #resource.close();
* }
* }
* }
*
* @param tree The try statement to inspect.
* @return A a desugared try-with-resources tree, or the original
* try block if there are no resources to manage.
*/
JCTree makeTwrTry(JCTry tree) {
make_at(tree.pos());
twrVars = twrVars.dup();
JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body, 0);
if (tree.catchers.isEmpty() && tree.finalizer == null) {
result = translate(twrBlock);
}else {
result = translate(make.Try(twrBlock, tree.catchers, tree.finalizer));
}
twrVars = twrVars.leave();
return result;
}
private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block, int depth) {
if (resources.isEmpty()) {
return block;
}
// Add resource declaration or expression to block statements
ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>();
JCTree resource = resources.head;
JCExpression expr = null;
if (resource instanceof JCVariableDecl) {
JCVariableDecl var = (JCVariableDecl) resource;
expr = make.Ident(var.sym).setType(resource.type);
stats.add(var);
} else {
Assert.check(resource instanceof JCExpression);
Name msn = makeSyntheticName(names.fromString("twrVar" + depth), twrVars);
VarSymbol syntheticTwrVar = new VarSymbol(SYNTHETIC | FINAL,
msn,
(resource.type.tag == TypeTags.BOT17) ?
syms.autoCloseableType : resource.type,
currentMethodSym);
twrVars.enter(syntheticTwrVar);
JCVariableDecl syntheticTwrVarDecl = make.VarDef(syntheticTwrVar, (JCExpression)resource);
expr = (JCExpression)make.Ident(syntheticTwrVar);
stats.add(syntheticTwrVarDecl);
}
// Add primaryException declaration
Name msn = makeSyntheticName(names.fromString("primaryException" + depth), twrVars);
VarSymbol primaryException = new VarSymbol(SYNTHETIC,
msn,
syms.throwableType,
currentMethodSym);
twrVars.enter(primaryException);
JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull());
stats.add(primaryExceptionTreeDecl);
// Create catch clause that saves exception and then rethrows it
VarSymbol param =
new VarSymbol(FINAL|SYNTHETIC,
names.fromString("t" + target.syntheticNameChar()),
syms.throwableType,
currentMethodSym);
JCVariableDecl paramTree = make.VarDef(param, null);
JCStatement assign = make.Assignment(primaryException, make.Ident(param));
JCStatement rethrowStat = make.Throw(make.Ident(param));
JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(assign, rethrowStat));
JCCatch catchClause = make.Catch(paramTree, catchBlock);
int oldPos = make.pos;
make.at(TreeInfo.endPos(block));
JCBlock finallyClause = makeTwrFinallyClause(primaryException, expr);
make.at(oldPos);
JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block, depth + 1),
List.<JCCatch>of(catchClause),
finallyClause);
stats.add(outerTry);
return make.Block(0L, stats.toList());
}
private JCBlock makeTwrFinallyClause(Symbol primaryException, JCExpression resource) {
// primaryException.addSuppressed(catchException);
VarSymbol catchException =
new VarSymbol(0, make.paramName(2),
syms.throwableType,
currentMethodSym);
JCStatement addSuppressionStatement =
make.Exec(makeCall(make.Ident(primaryException),
names.addSuppressed,
List.<JCExpression>of(make.Ident(catchException))));
// try { resource.close(); } catch (e) { primaryException.addSuppressed(e); }
JCBlock tryBlock = make.Block(0L, List.<JCStatement>of(makeResourceCloseInvocation(resource)));
JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null);
JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement));
List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock));
JCTry tryTree = make.Try(tryBlock, catchClauses, null);
// if (primaryException != null) {try...} else resourceClose;
JCIf closeIfStatement = make.If(makeNonNullCheck(make.Ident(primaryException)),
tryTree,
makeResourceCloseInvocation(resource));
// if (#resource != null) { if (primaryException ... }
return make.Block(0L,
List.<JCStatement>of(make.If(makeNonNullCheck(resource),
closeIfStatement,
null)));
}
private JCStatement makeResourceCloseInvocation(JCExpression resource) {
// create resource.close() method invocation
JCExpression resourceClose = makeCall(resource,
names.close,
List.<JCExpression>nil());
return make.Exec(resourceClose);
}
private JCExpression makeNonNullCheck(JCExpression expression) {
return makeBinary(JCTree.NE, expression, makeNull());
}
/** Construct a tree that represents the outer instance
* <C.this>. Never pick the current `this‘.
* @param pos The source code position to be used for the tree.
* @param c The qualifier class.
*/
JCExpression makeOuterThis(JCDiagnosticPosition pos, TypeSymbol c) {
List<VarSymbol> ots = outerThisStack;
if (ots.isEmpty()) {
log.error(pos, "no.encl.instance.of.type.in.scope", c);
Assert.error();
return makeNull();
}
VarSymbol ot = ots.head;
JCExpression tree = access(make.at(pos).Ident(ot));
TypeSymbol otc = ot.type.tsym;
while (otc != c) {
do {
ots = ots.tail;
if (ots.isEmpty()) {
// 作用域中没有类型为{0}的封闭实例
log.error(pos,"no.encl.instance.of.type.in.scope",c);
Assert.error(); // should have been caught in Attr
return tree;
}
ot = ots.head;
} while (ot.owner != otc);
if (otc.owner.kind != PCK01 && !otc.hasOuterInstance()) {
chk.earlyRefError(pos, c);
Assert.error(); // should have been caught in Attr
return makeNull();
}
tree = access(make.at(pos).Select(tree, ot));
otc = ot.type.tsym;
}
return tree;
}
/** Construct a tree that represents the closest outer instance
* <C.this> such that the given symbol is a member of C.
* @param pos The source code position to be used for the tree.
* @param sym The accessed symbol.
* @param preciseMatch should we accept a type that is a subtype of
* sym‘s owner, even if it doesn‘t contain sym
* due to hiding, overriding, or non-inheritance
* due to protection?
*/
JCExpression makeOwnerThis(JCDiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
Symbol c = sym.owner;
boolean temp;
if(preciseMatch){
temp = sym.isMemberOf(currentClass, types);
}else{
temp = currentClass.isSubClass(sym.owner, types);
}
if (temp ) {
// in this case, `this‘ works fine
return make.at(pos).This(c.erasure(types));
} else {
// need to go via this$n
return makeOwnerThisN(pos, sym, preciseMatch);
}
}
/**
* Similar to makeOwnerThis but will never pick "this".
*/
JCExpression makeOwnerThisN(JCDiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
Symbol c = sym.owner;
List<VarSymbol> ots = outerThisStack;
if (ots.isEmpty()) {
// 作用域中没有类型为{0}的封闭实例
log.error(pos, "no.encl.instance.of.type.in.scope", c);
Assert.error();
return makeNull();
}
VarSymbol ot = ots.head;
JCExpression tree = access(make.at(pos).Ident(ot));
TypeSymbol otc = ot.type.tsym;
while (
!(preciseMatch ? sym.isMemberOf(otc, types) : otc.isSubClass(sym.owner, types))
){
do {
ots = ots.tail;
if (ots.isEmpty()) {
// 作用域中没有类型为{0}的封闭实例
log.error(pos,"no.encl.instance.of.type.in.scope", c);
Assert.error();
return tree;
}
ot = ots.head;
} while (ot.owner != otc);
tree = access(make.at(pos).Select(tree, ot));
otc = ot.type.tsym;
}
return tree;
}
/** Return tree simulating the assignment <this.name = name>, where
* name is the name of a free variable.
*/
JCStatement initField(int pos, Name name) {
Scope.Entry e = proxies.lookup(name);
Symbol rhs = e.sym;
Assert.check(rhs.owner.kind == MTH16);
Symbol lhs = e.next().sym;
Assert.check(rhs.owner.owner == lhs.owner);
make.at(pos);
Type erasureType = lhs.owner.erasure(types);
JCExpression thisJCE = make.This(erasureType);
JCExpression selectJCE = make.Select(thisJCE, lhs);
JCExpression assignJCE = make.Assign(selectJCE,make.Ident(rhs));
JCExpression typeJCE = assignJCE.setType(lhs.erasure(types));
return make.Exec(typeJCE);
}
/** Return tree simulating the assignment <this.this$n = this$n>.
*/
JCStatement initOuterThis(int pos) {
VarSymbol rhs = outerThisStack.head;
Assert.check(rhs.owner.kind == MTH16);
VarSymbol lhs = outerThisStack.tail.head;
Assert.check(rhs.owner.owner == lhs.owner);
make.at(pos);
Type erasureType = lhs.owner.erasure(types);
JCExpression thisJCE = make.This(erasureType);
JCExpression selectJCE = make.Select(thisJCE, lhs);
JCExpression assignJCE = make.Assign(selectJCE,make.Ident(rhs));
JCExpression typeJCE = assignJCE.setType(lhs.erasure(types));
return make.Exec(typeJCE);
}
/**************************************************************************
* Code for .class
*************************************************************************/
/** Return the symbol of a class to contain a cache of
* compiler-generated statics such as class$ and the
* $assertionsDisabled flag. We create an anonymous nested class
* (unless one already exists) and return its symbol. However,
* for backward compatibility in 1.4 and earlier we use the
* top-level class itself.
*/
protected ClassSymbol outerCacheClass() {
ClassSymbol clazz = outermostClassDef.sym;
if ((clazz.flags() & INTERFACE) == 0 &&
!target.useInnerCacheClass()) {
return clazz; // 基本进不了这里
}
Scope s = clazz.members();
for (Scope.Entry e = s.elems; e != null; e = e.sibling)
if (e.sym.kind == TYP02 &&
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(JCDiagnosticPosition pos) {
// ClassSymbol outerCacheClass = outerCacheClass();
// MethodSymbol classDollarSym =
// (MethodSymbol)lookupSynthetic(classDollar,
// outerCacheClass.members());
// if (classDollarSym == null) {
// MethodType mt = new MethodType(
// List.of(syms.stringType),
// types.erasure(syms.classType),
// List.<Type>nil(),
// syms.methodClass);
// classDollarSym = new MethodSymbol(
// STATIC | SYNTHETIC,
// classDollar,mt, 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(JCDiagnosticPosition pos, JCMethodDecl md) {
// MethodSymbol classDollarSym = md.sym;
// ClassSymbol outerCacheClass = (ClassSymbol)classDollarSym.owner;
//
// JCBlock returnResult;
//
// // in 1.4.2 and above, we use
// // AttrClass.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(INT04, 0).setType(syms.intType)),
// null);
// newcache.type = new ArrayType(types.erasure(outerCacheClass.type),
// syms.arrayClass);
//
// // forNameSym := java.lang.AttrClass.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 AttrClass.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.AttrClass.forName(String s)
// Symbol forNameSym = lookupMethod(make_pos,
// names.forName,
// types.erasure(syms.classType),
// List.of(syms.stringType));
// // returnResult := "{ return AttrClass.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.checkNonNull(left.type);
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(JCDiagnosticPosition pos, String sig) {
// ClassSymbol outerCacheClass = outerCacheClass();
// Name cname = cacheName(sig);
// VarSymbol cacheSym = (VarSymbol)lookupSynthetic(cname, outerCacheClass.members());
// if (cacheSym == null) {
// Type eartype = types.erasure(syms.classType);
// cacheSym = new VarSymbol(STATIC | SYNTHETIC, cname,eartype , 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, JCDiagnosticPosition pos) {
switch (type.tag) {
case BYTE01: case SHORT03: case CHAR02: case INT04: case LONG05: case FLOAT06:
case DOUBLE07: case BOOLEAN08: case VOID09:
// replace with <BoxedClass>.TYPE
ClassSymbol c = types.boxedClass(type);
Symbol sb = rs.findIdentifierInType(attrEnv, c.type, names.TYPE, VAR04);
Symbol typeSym = rs.access(sb,pos, c.type, names.TYPE, true);
if (typeSym.kind == VAR04) {
((VarSymbol) typeSym).getConstValue(); // ensure initializer is evaluated
}
return make.QualIdent(typeSym);
case CLASS10: case ARRAY11:
// 由于目前的代码都为JDK5及以上,所以直接用这样的逻辑
VarSymbol sym = new VarSymbol(STATIC | PUBLIC | FINAL, names._class, syms.classType, type.tsym);
JCExpression jce = make.Type(type);
return make_at(pos).Select(jce, sym);
// if (target.hasClassLiterals()) { // JDK1.5及以后都为true
// // classType java.lang.Class
// // _class Class
// // eg:Class<Fruit> _class = Fruit.class 添加这个语句
// VarSymbol sym = new VarSymbol(STATIC | PUBLIC | FINAL, names._class, syms.classType, type.tsym);
// JCExpression jce = make.Type(type);
// return make_at(pos).Select(jce, 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(CLASS10, 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(JCDiagnosticPosition 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
*
* (
* let TYPE TEMP = RVAL;
* in (BUILDER(TEMP))
* )
*
* 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:
JCIdentifier id = (JCIdentifier) rval;
if ((id.sym.flags() & FINAL) != 0 &&
id.sym.owner.kind == MTH16) {
return builder.build(rval);
}
}
Name temp = names.fromString(target.syntheticNameChar()+ "" + rval.hashCode());
VarSymbol var = new VarSymbol(FINAL|SYNTHETIC,temp,type,currentMethodSym);
rval = convert(rval,type);
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
JCTree abstractRval(JCTree rval, TreeBuilder builder) {
return abstractRval(rval, rval.type, builder);
}
// same as above, but for an expression that may be used as either
// an rvalue or an lvalue. This requires special handling for
// Select expressions, where we place the left-hand-side of the
// select in a temporary, and for Indexed expressions, where we
// place both the indexed expression and the index value in temps.
JCTree abstractLval(JCTree lval, final TreeBuilder builder) {
lval = TreeInfo.skipParens(lval);
switch (lval.getTag()) {
case JCTree.IDENT:
return builder.build(lval);
case JCTree.SELECT: {
final JCFieldAccess s = (JCFieldAccess)lval;
// JCTree selected = TreeInfo.skipParens(s.selected);
Symbol lid = TreeInfo.symbol(s.selected);
if (lid != null && lid.kind == TYP02) {
return builder.build(lval);
}
TreeBuilder tb = new TreeBuilder() {
public JCTree build(final JCTree selected) {
JCTree temp = make.Select((JCExpression)selected, s.sym);
return builder.build(temp);
}
};
return abstractRval(s.selected, tb);
}
// 参考例子:https://www.cnblogs.com/extjs4/p/9367051.html
case JCTree.INDEXED: {
final JCArrayAccess i = (JCArrayAccess)lval;
TreeBuilder tb = new TreeBuilder() {
public JCTree build(final JCTree indexed) {
TreeBuilder tb = new TreeBuilder() {
public JCTree build(final JCTree index) {
JCTree newLval = make.Indexed((JCExpression)indexed,(JCExpression)index);
newLval.setType(i.type);
return builder.build(newLval);
}
};
return abstractRval(i.index, syms.intType, tb);
}
};
return abstractRval(i.indexed,tb );
}
case JCTree.TYPECAST: {
return abstractLval(((JCTypeCast)lval).expr, builder); // 递归
}
}
throw new AssertionError(lval);
}
// evaluate and discard the first expression, then evaluate the second.
JCTree makeComma(final JCTree expr1, final JCTree expr2) {
TreeBuilder tb = new TreeBuilder() {
public JCTree build(final JCTree discarded) {
return expr2;
}
};
return abstractRval(expr1, tb);
}
/**************************************************************************
* Translation methods
*************************************************************************/
/** AttrVisitor argument: enclosing operator node.
*/
private JCExpression enclOperator;
/** Visitor method: Translate a single node.
* Attach the source position from the old tree to its replacement tree.
*/
public <T extends JCTree> T translate(T tree) {
if (tree == null) {
return null;
} else {
make_at(tree.pos());
T result = super.translate(tree);
if (endPositions != null && result != tree) {
Integer endPos = endPositions.remove(tree);
if (endPos != null) {
endPositions.put(result, endPos);
}
}
return result;
}
}
/** AttrVisitor method: Translate a single node, boxing or unboxing if needed.
*/
public <T extends JCTree> T translate(T tree, Type type) {
if(tree == null){
return null;
}else{
T t = translate(tree);
return boxIfNeeded(t, type);
}
}
/** AttrVisitor method: Translate tree.
*/
public <T extends JCTree> T translate(T tree, JCExpression enclOp) {
JCExpression prevEnclOp = this.enclOperator;
this.enclOperator = enclOp;
T res = translate(tree);
this.enclOperator = prevEnclOp;
return res;
}
/** AttrVisitor method: Translate list of trees.
*/
public <T extends JCTree> List<T> translate(List<T> trees, JCExpression enclOp) {
JCExpression prevEnclOp = this.enclOperator;
this.enclOperator = enclOp;
List<T> res = translate(trees);
this.enclOperator = prevEnclOp;
return res;
}
/** AttrVisitor method: Translate list of trees.
*/
public <T extends JCTree> List<T> translate(List<T> trees, Type type) {
if (trees == null) {
return null;
}
for (List<T> l = trees; l.nonEmpty(); l = l.tail) {
l.head = translate(l.head, type);
}
return trees;
}
public void visitTopLevel(JCCompilationUnit tree) {
if (needPackageInfoClass(tree)) {
Name name = names.package_info; // package-info
long flags = Flags.ABSTRACT | Flags.INTERFACE;
if (target.isPackageInfoSynthetic()) {
// package-info is marked SYNTHETIC in JDK 1.6 and later releases
flags = flags | Flags.SYNTHETIC;
}
JCModifiers jcm = make.Modifiers(flags,tree.packageAnnotations);
JCClassDecl packageAnnotationsClass = make.ClassDef(jcm,
name, List.<JCTypeParameter>nil(),
null, List.<JCExpression>nil(), List.<JCTree>nil());
ClassSymbol c = tree.packge.package_info;
c.flags_field |= flags;
c.attributes_field = tree.packge.attributes_field;
ClassType ctype = (ClassType) c.type;
ctype.supertype_field = syms.objectType;
ctype.interfaces_field = List.nil();
packageAnnotationsClass.sym = c;
translated.append(packageAnnotationsClass);
}
}
// where
private boolean needPackageInfoClass(JCCompilationUnit tree) {
switch (pkginfoOpt) {
case ALWAYS:
return true;
case LEGACY:
return tree.packageAnnotations.nonEmpty();
case NONEMPTY:
for (AttrCompound a: tree.packge.attributes_field) {
RetentionPolicy p = types.getRetention(a);
if (p != RetentionPolicy.SOURCE) {
return true;
}
}
return false;
}
throw new AssertionError();
}
public void visitClassDef(JCClassDecl tree) {
ClassSymbol currentClassPrev = currentClass;
MethodSymbol currentMethodSymPrev = currentMethodSym;
currentClass = tree.sym;
currentMethodSym = null;
classdefs.put(currentClass, tree);
proxies = proxies.dup(currentClass);
List<VarSymbol> prevOuterThisStack = outerThisStack;
// If this is an enum definition
if ( (tree.mods.flags & ENUM) != 0 ) {
// 如st为java.lang.Enum<com.test19.Fruit>,而st是没有ENUM标识的
Type st = types.supertype(currentClass.type);
if((st.tsym.flags() & ENUM) == 0){
visitEnumDef(tree);
}
}
// If this is a nested class, define a this$n field for
// it and add to proxies.
JCVariableDecl otdef = null;
if (currentClass.hasOuterInstance()) {
otdef = outerThisDef(tree.pos, currentClass);
}
// If this is a local class, define proxies for all its free variables.
List<VarSymbol> fvs = freevars(currentClass);
List<JCVariableDecl> fvdefs = freevarDefs(tree.pos,fvs , currentClass);
// Recursively translate superclass, interfaces.
tree.extending = translate(tree.extending);
tree.implementing = translate(tree.implementing);
if (currentClass.isLocal()) {
ClassSymbol encl = currentClass.owner.enclClass();
if (encl.trans_local == null) {
encl.trans_local = List.nil();
}
// 为ClassSymbol的trans_local属性赋值
encl.trans_local = encl.trans_local.prepend(currentClass);
}
// Recursively translate members, taking into account that new members
// might be created during the translation and prepended to the member
// list `tree.defs‘.
List<JCTree> seen = List.nil();
while (tree.defs != seen) {
List<JCTree> unseen = tree.defs;
for (List<JCTree> l = unseen; l.nonEmpty() && l != seen; l = l.tail) {
JCTree outermostMemberDefPrev = outermostMemberDef;
if (outermostMemberDefPrev == null) {
// 从JCClassDecl的defs中取出的只可能是Class、Method或者Field
outermostMemberDef = l.head;
}
l.head = translate(l.head);
outermostMemberDef = outermostMemberDefPrev;
}
seen = unseen;
}
// Convert a protected modifier to public, mask static modifier.
if ((tree.mods.flags & PROTECTED) != 0) {
tree.mods.flags |= PUBLIC;
}
tree.mods.flags &= ClassFlags;
// Convert name to flat representation, replacing ‘.‘ by ‘$‘.
tree.name = Convert.shortName(currentClass.flatName());
// Add free variables proxy definitions to class.
for (List<JCVariableDecl> l = fvdefs; l.nonEmpty(); l = l.tail) {
tree.defs = tree.defs.prepend(l.head);
Scope sp = currentClass.members();
enterSynthetic(tree.pos(), l.head.sym, sp);
}
// Add this$n to class.
if (currentClass.hasOuterInstance()) {
tree.defs = tree.defs.prepend(otdef);
Scope sp = currentClass.members();
enterSynthetic(tree.pos(), otdef.sym, sp);
}
proxies = proxies.leave();
outerThisStack = prevOuterThisStack;
// Append translated tree to `translated‘ queue.
translated.append(tree);
currentClass = currentClassPrev;
currentMethodSym = currentMethodSymPrev;
// Return empty block {} as a placeholder for an inner class.
result = make_at(tree.pos()).Block(0, List.<JCStatement>nil());
}
/** Translate an enum class. */
private void visitEnumDef(JCClassDecl tree) {
make_at(tree.pos());
// add the supertype, if needed
if (tree.extending == null) {
Type st = types.supertype(tree.type);
tree.extending = make.Type(st);
}
// classOfType adds a cache field to tree.defs unless
// target.hasClassLiterals().
JCExpression jce = classOfType(tree.sym.type, tree.pos());
Type era = types.erasure(syms.classType);
JCExpression e_class = jce.setType(era);
// process each enumeration constant, adding implicit constructor parameters
int nextOrdinal = 0;
ListBuffer<JCExpression> values = new ListBuffer<JCExpression>();
ListBuffer<JCTree> enumDefs = new ListBuffer<JCTree>();// 处理后的枚举变量会加入这个变量
ListBuffer<JCTree> otherDefs = new ListBuffer<JCTree>(); // 如枚举类的构造函数会加入这个列表
for (List<JCTree> defs = tree.defs;defs.nonEmpty(); defs=defs.tail) {
// 如果是ENUM变量,则进行处理
if (defs.head.getTag() == JCTree.VARDEF &&
(((JCVariableDecl) defs.head).mods.flags & ENUM) != 0) {
JCVariableDecl var = (JCVariableDecl)defs.head;
visitEnumConstantDef(var, nextOrdinal++);
values.append(make.QualIdent(var.sym));
enumDefs.append(var);
} else {
otherDefs.append(defs.head);
}
}
// private static final T[] #VALUES = { a, b, c };
Name valuesName = names.fromString(target.syntheticNameChar() + "VALUES");
while (tree.sym.members().lookup(valuesName).scope != null) { // avoid name clash
valuesName = names.fromString(valuesName + "" + target.syntheticNameChar());
}
Type arrayType = new ArrayType(types.erasure(tree.type), syms.arrayClass);
VarSymbol valuesVar = new VarSymbol(PRIVATE|FINAL|STATIC|SYNTHETIC,
valuesName,
arrayType,
tree.type.tsym);
JCExpression jcep = make.Type(types.erasure(tree.type));
JCNewArray newArray = make.NewArray(jcep,List.<JCExpression>nil(),values.toList());
newArray.type = arrayType;
enumDefs.append(make.VarDef(valuesVar, newArray));
tree.sym.members().enter(valuesVar);
Symbol valuesSym = lookupMethod(tree.pos(), names.values,tree.type, List.<Type>nil());
List<JCStatement> valuesBody;
// 直接使用如下的代码,由于调用useClone()方法后返回在高版本中都为true
JCExpression sjce = make.Select(make.Ident(valuesVar),syms.arrayCloneMethod);
JCMethodInvocation jcm = make.App(sjce);
JCTypeCast valuesResult = make.TypeCast(valuesSym.type.getReturnType(),jcm);
valuesBody = List.<JCStatement>of(make.Return(valuesResult));
// if (useClone()) {
// /*
// public static Color[] values() {
// return (Color[])$VALUES.clone();
// }
// */
// // return (T[]) $VALUES.clone();
// JCExpression sjce = make.Select(make.Ident(valuesVar),syms.arrayCloneMethod);
// JCMethodInvocation jcm = make.App(sjce);
// JCTypeCast valuesResult = make.TypeCast(valuesSym.type.getReturnType(),jcm);
// valuesBody = List.<JCStatement>of(make.Return(valuesResult));
// } else {
//// public static Color[] values() {
//// /*synthetic*/ final Color[] $result = new Color[$VALUES.length];
//// System.arraycopy($VALUES, 0, $result, 0, $VALUES.length);
//// return $result;
//// }
// // template: T[] $result = new T[$values.length];
// Name resultName = names.fromString(target.syntheticNameChar() + "result");
// while (tree.sym.members().lookup(resultName).scope != null) { // avoid name clash
// resultName = names.fromString(resultName + "" + target.syntheticNameChar());
// }
// VarSymbol resultVar = new VarSymbol(FINAL|SYNTHETIC,
// resultName,
// arrayType,
// valuesSym);
// JCNewArray resultArray = make.NewArray(make.Type(types.erasure(tree.type)),
// List.of(make.Select(make.Ident(valuesVar), syms.lengthVar)),
// null);
// resultArray.type = arrayType;
// JCVariableDecl decl = make.VarDef(resultVar, resultArray);
//
// // template: System.arraycopy($VALUES, 0, $result, 0, $VALUES.length);
// if (systemArraycopyMethod == null) {
// MethodType mt = new MethodType(List.<Type>of(syms.objectType,
// syms.intType,
// syms.objectType,
// syms.intType,
// syms.intType),
// syms.voidType,
// List.<Type>nil(),
// syms.methodClass);
// systemArraycopyMethod = new MethodSymbol(PUBLIC | STATIC,names.fromString("arraycopy"),mt,syms.systemType.tsym);
// }
// JCExpression selectJCE = make.Select(make.Ident(syms.systemType.tsym),systemArraycopyMethod);
// List<JCExpression> list = List.of(make.Ident(valuesVar), make.Literal(0),
// make.Ident(resultVar), make.Literal(0),
// make.Select(make.Ident(valuesVar), syms.lengthVar));
// JCStatement copy = make.Exec(make.App(selectJCE,list));
//
// // template: return $result;
// JCStatement ret = make.Return(make.Ident(resultVar));
// valuesBody = List.<JCStatement>of(decl, copy, ret);
// }
// 为Enum枚举类生成values()方法
JCMethodDecl valuesDef = make.MethodDef((MethodSymbol)valuesSym, make.Block(0, valuesBody));
enumDefs.append(valuesDef);
if (debugLower) {
System.err.println(tree.sym + ".valuesDef = " + valuesDef);
}
/** The template for the following code is:
*
* public static E valueOf(String name) {
* return (E)Enum.valueOf(E.class, name);
* }
*
* where E is tree.sym
*/
MethodSymbol valueOfSym = lookupMethod(tree.pos(),
names.valueOf,
tree.sym.type,
List.of(syms.stringType));
Assert.check((valueOfSym.flags() & STATIC) != 0);
VarSymbol nameArgSym = valueOfSym.params.head;
JCIdentifier nameVal = make.Ident(nameArgSym);
JCMethodInvocation jcmi = makeCall(make.Ident(syms.enumSym),names.valueOf,List.of(e_class, nameVal));
JCStatement enum_ValueOf = make.Return(make.TypeCast(tree.sym.type,jcmi ));
JCMethodDecl valueOf = make.MethodDef(valueOfSym,make.Block(0, List.of(enum_ValueOf)));
nameVal.sym = valueOf.params.head.sym;
if (debugLower) {
System.err.println(tree.sym + ".valueOf = " + valueOf);
}
enumDefs.append(valueOf);
enumDefs.appendList(otherDefs.toList());
tree.defs = enumDefs.toList();
// Add the necessary members for the EnumCompatibleMode
// if (target.compilerBootstrap(tree.sym)) {
// addEnumCompatibleMembers(tree);
// }
}
// where
// private MethodSymbol systemArraycopyMethod;
// private boolean useClone() {
// try {
// // 如果Object类中有clone()方法就返回true
// Scope.Entry e = syms.objectType.tsym.members().lookup(names.clone);
// return (e.sym != null);
// }
// catch (CompletionFailure e) {
// return false;
// }
// }
/** Translate an enumeration constant and its initializer. */
private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
JCNewClass varDef = (JCNewClass)var.init;
varDef.args = varDef.args.
prepend(makeLit(syms.intType, ordinal)).
prepend(makeLit(syms.stringType, var.name.toString()));
}
public void visitMethodDef(JCMethodDecl tree) {
if ( tree.name == names.init && // 初始化函数
(currentClass.flags_field&ENUM) != 0 ){ // 是枚举类
// Add "String $enum$name, int $enum$ordinal" to the beginning of the
// argument list for each constructor of an enum.
// http://www.cnblogs.com/extjs4/p/7074091.html
// 合成的名称为$enum$name,类型为String
Name namea = names.fromString(target.syntheticNameChar() +"enum" + target.syntheticNameChar() + "name");
JCVariableDecl nameParam = make_at(tree.pos()).Param(namea,syms.stringType, tree.sym);
nameParam.mods.flags |= SYNTHETIC;
nameParam.sym.flags_field |= SYNTHETIC;
// 合成的名称为$enum$name,类型为int
Name nameb = names.fromString(target.syntheticNameChar() +"enum" + target.syntheticNameChar() + "ordinal");
JCVariableDecl ordinalParam = make.Param(nameb,syms.intType, tree.sym);
ordinalParam.mods.flags |= SYNTHETIC;
ordinalParam.sym.flags_field |= SYNTHETIC;
// 为构造函数追加如上两个新形式参数
tree.params = tree.params.prepend(ordinalParam).prepend(nameParam);
MethodSymbol m = tree.sym;
Type olderasure = m.erasure(types);
List<Type> argtypes = olderasure.getParameterTypes().prepend(syms.intType).prepend(syms.stringType);
m.erasure_field = new MethodType( // 为Symbol中的erasure_field属性赋值
argtypes,
olderasure.getReturnType(),
olderasure.getThrownTypes(),
syms.methodClass);
// 基本都返回false,只有版本是jsr14才有可能为true
if (target.compilerBootstrap(m.owner)) {
// Initialize synthetic name field
Symbol nameVarSym = lookupSynthetic(names.fromString("$name"),
tree.sym.owner.members());
JCIdentifier nameIdent = make.Ident(nameParam.sym);
JCIdentifier id1 = make.Ident(nameVarSym);
JCAssign newAssign = make.Assign(id1, nameIdent);
newAssign.type = id1.type;
JCExpressionStatement nameAssign = make.Exec(newAssign);
nameAssign.type = id1.type;
tree.body.stats = tree.body.stats.prepend(nameAssign);
// Initialize synthetic ordinal field
Symbol ordinalVarSym = lookupSynthetic(names.fromString("$ordinal"),
tree.sym.owner.members());
JCIdentifier ordIdent = make.Ident(ordinalParam.sym);
id1 = make.Ident(ordinalVarSym);
newAssign = make.Assign(id1, ordIdent);
newAssign.type = id1.type;
JCExpressionStatement ordinalAssign = make.Exec(newAssign);
ordinalAssign.type = id1.type;
tree.body.stats = tree.body.stats.prepend(ordinalAssign);
}
}
// 保存之前的全局值,以便分析完这个方法后回复
JCMethodDecl prevMethodDef = currentMethodDef;
MethodSymbol prevMethodSym = currentMethodSym;
try {
currentMethodDef = tree;
currentMethodSym = tree.sym;
visitMethodDefInternal(tree);
} finally {
currentMethodDef = prevMethodDef;
currentMethodSym = prevMethodSym;
}
}
// where
private void visitMethodDefInternal(JCMethodDecl tree) {
if (tree.name == names.init &&
(
currentClass.isInner() || // 是inner class,不是nested class
(currentClass.owner.kind & (VAR04 | MTH16)) != 0
)
){
/*
public class TestScope {
public class InnerClass{
// 调用方法后增加的代码
public <init>( final TestScope this$0) { // 其中的变量this$0是合成的
this.this$0 = this$0;
super();
}
}
}
*/
// We are seeing a constructor of an inner class.
MethodSymbol ms = tree.sym; // 内部类的初始化构造方法
// Push a new proxy scope for constructor parameters.
// and create definitions for any this$n and proxy parameters.
proxies = proxies.dup(ms);
List<VarSymbol> prevOuterThisStack = outerThisStack;
List<VarSymbol> fvs = freevars(currentClass);
JCVariableDecl otdef = null;
if (currentClass.hasOuterInstance()) {
otdef = outerThisDef(tree.pos, ms);
}
List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, ms);
// Recursively translate result type, parameters and thrown list.
tree.restype = translate(tree.restype);
tree.params = translateVarDefs(tree.params);
tree.thrown = translate(tree.thrown);
// when compiling stubs, don‘t process body
if (tree.body == null) {
result = tree;
return;
}
// Add this$n (if needed) in front of and free variables behind
// constructor parameter list.
tree.params = tree.params.appendList(fvdefs); // 后追加自由变量
if (currentClass.hasOuterInstance()) {
tree.params = tree.params.prepend(otdef); // 最前追加this$n变量
}
// If this is an initial constructor, i.e., it does not start with
// this(...), insert initializers for this$n and proxies
// before (pre-1.4, after) the call to superclass constructor.
// 就是在调用super之前初始化所有的this$n与自由变量
JCStatement selfCall = translate(tree.body.stats.head);
List<JCStatement> added = List.nil();
if (fvs.nonEmpty()) {
List<Type> addedArgtypes = List.nil();
for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
if (TreeInfo.isInitialConstructor(tree)) {
Name pN = proxyName(l.head.name); // 在name前追加"val$"字符串
JCStatement jcs = initField(tree.body.pos, pN);
added = added.prepend(jcs);
}
addedArgtypes = addedArgtypes.prepend(l.head.erasure(types));
}
Type olderasure = ms.erasure(types);
ms.erasure_field = new MethodType(
olderasure.getParameterTypes().appendList(addedArgtypes),
olderasure.getReturnType(),
olderasure.getThrownTypes(),
syms.methodClass);
}
if (currentClass.hasOuterInstance() &&
TreeInfo.isInitialConstructor(tree)
){ // 外部实例变量初始化,如this.this$0 = this$0
JCStatement jcs = initOuterThis(tree.body.pos);
added = added.prepend(jcs);
}
// pop local variables from proxy stack
proxies = proxies.leave();
// recursively translate following local statements and
// combine with this- or super-call
List<JCStatement> stats = translate(tree.body.stats.tail);
if (target.initializeFieldsBeforeSuper()) { // JDK4及以后都为true
tree.body.stats = stats.prepend(selfCall).prependList(added);
}else {
tree.body.stats = stats.prependList(added).prepend(selfCall);
}
outerThisStack = prevOuterThisStack;
} else {
super.visitMethodDef(tree);
}
result = tree;
}
/*
eg1:
Integer a = (Integer)2;
to
Integer a = Integer.valueOf(2);
*/
public void visitTypeCast(JCTypeCast tree) {
tree.clazz = translate(tree.clazz);
if (tree.type.isPrimitive() != tree.expr.type.isPrimitive()) {
tree.expr = translate(tree.expr, tree.type);
}else {
tree.expr = translate(tree.expr);
}
result = tree;
}
public void visitNewClass(JCNewClass tree) {
ClassSymbol cs = (ClassSymbol)tree.constructor.owner;
// Box arguments, if necessary
boolean isEnum = (tree.constructor.owner.flags() & ENUM) != 0;
List<Type> argTypes = tree.constructor.type.getParameterTypes();
if (isEnum) {
argTypes = argTypes.prepend(syms.intType).prepend(syms.stringType);
}
tree.args = boxArgs(argTypes, tree.args, tree.varargsElement);
tree.varargsElement = null;
// If created class is local, add free variables after
// explicit constructor arguments.
if ((cs.owner.kind & (VAR04 | MTH16)) != 0) {
List<VarSymbol> list = freevars(cs);
List<JCExpression> jces = loadFreevars(tree.pos(),list);
tree.args = tree.args.appendList(jces);
}
// If an access constructor is used, append null as a last argument.
Symbol constructor = accessConstructor(tree.pos(), tree.constructor);
if (constructor != tree.constructor) {
tree.args = tree.args.append(makeNull());
tree.constructor = constructor;
}
// If created class has an outer instance, and new is qualified, pass
// qualifier as first argument. If new is not qualified, pass the
// correct outer instance as first argument.
if (cs.hasOuterInstance()) {
JCExpression thisArg;
if (tree.encl != null) {
JCExpression jce = translate(tree.encl);
thisArg = attr.makeNullCheck(jce);
thisArg.type = tree.encl.type;
} else if ((cs.owner.kind & (MTH16 | VAR04)) != 0) { // local class
TypeSymbol ts = cs.type.getEnclosingType().tsym;
thisArg = makeThis(tree.pos(), ts);
} else { // nested class
thisArg = makeOwnerThis(tree.pos(), cs, false);
}
tree.args = tree.args.prepend(thisArg);
}
tree.encl = null;
// If we have an anonymous class, create its flat version, rather
// than the class or interface following new.
if (tree.def != null) {
translate(tree.def);
tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym));
tree.def = null;
} else {
tree.clazz = access(cs, tree.clazz, enclOperator, false);
}
result = tree;
}
// Simplify conditionals with known constant controlling expressions.
// This allows us to avoid generating supporting declarations for
// the dead code, which will not be eliminated during code generation.
// Note that Flow.isFalse and Flow.isTrue only return true
// for constant expressions in the sense of JLS 15.27, which
// are guaranteed to have no side-effects. More aggressive
// constant propagation would require that we take care to
// preserve possible side-effects in the condition expression.
/** AttrVisitor method for conditional expressions.
*/
/*
eg1:
final boolean result = true;
String a = result?"a":"b";
to
String s = "a";
*/
public void visitConditional(JCConditional tree) {
JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
if (cond.type.isTrue()) {
JCExpression jce = translate(tree.truepart, tree.type);
result = convert(jce, tree.type);
} else if (cond.type.isFalse()) {
JCExpression jce = translate(tree.falsepart, tree.type);
result = convert(jce, tree.type);
} else {
// Condition is not a compile-time constant.
tree.truepart = translate(tree.truepart, tree.type);
tree.falsepart = translate(tree.falsepart, tree.type);
result = tree;
}
}
//where
private JCTree convert(JCTree tree, Type pt) {
if (tree.type == pt ||
tree.type.tag == TypeTags.BOT17) {
return tree;
}
JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt), (JCExpression)tree);
if(tree.type.constantValue() != null) {
result.type = cfolder.coerce(tree.type, pt);
}else{
result.type = pt;
}
return result;
}
/** AttrVisitor method for if statements.
*/
/*
eg1:
if(true){
System.out.println("True");
}else{
System.out.println("False");
}
to
System.out.println("True");
*/
public void visitIf(JCIf tree) {
JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
if (cond.type.isTrue()) {
result = translate(tree.thenpart);
} else if (cond.type.isFalse()) {
if (tree.elsepart != null) {
result = translate(tree.elsepart);
} else {
result = make.Skip();
}
} else {
// Condition is not a compile-time constant.
tree.thenpart = translate(tree.thenpart);
tree.elsepart = translate(tree.elsepart);
result = tree;
}
}
/** AttrVisitor method for assert statements. Translate them away.
*/
/*
eg1:
assert false : "assert-false-message";
to
if (!$assertionsDisabled)
throw new AssertionError("assert-false-message");
else
return;
*/
public void visitAssert(JCAssert tree) {
JCDiagnosticPosition detailPos = (tree.detail == null) ? tree.pos() : tree.detail.pos();
tree.cond = translate(tree.cond, syms.booleanType);
if (!tree.cond.type.isTrue()) {
JCExpression cond = assertFlagTest(tree.pos());
List<JCExpression> exnArgs = null;
if(tree.detail == null){
exnArgs = List.<JCExpression>nil();
}else{
exnArgs = List.of(translate(tree.detail));
}
if (!tree.cond.type.isFalse()) {
cond = makeBinary(JCTree.AND,
cond,
makeUnary(JCTree.NOT, tree.cond));
}
JCNewClass jcn = makeNewClass(syms.assertionErrorType, exnArgs);
JCThrow jct = make_at(detailPos).Throw(jcn);
result = make.If(cond,jct,null);
} else {
result = make.Skip();
}
}
public void visitApply(JCMethodInvocation tree) {
Symbol meth = TreeInfo.symbol(tree.meth);
List<Type> argtypes = meth.type.getParameterTypes();
if (allowEnums &&
meth.name==names.init &&
meth.owner == syms.enumSym
){
argtypes = argtypes.tail.tail;
}
/*
eg1:
class VarialbeArgumentsDemo {
public static void doWork(int... a) { // 可变参数 }
public static void main(String[] args) {
doWork(1);
doWork(1,2,3);
}
}
to
class VarialbeArgumentsDemo {
VarialbeArgumentsDemo() { }
public static void doWork(int... var0) { }
public static void main(String[] var0) {
doWork(new int[]{1});
doWork(new int[]{1, 2, 3});
}
}
*/
tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
tree.varargsElement = null;
Name methName = TreeInfo.name(tree.meth);
if (meth.name==names.init) {
// We are seeing a this(...) or super(...) constructor call.
// If an access constructor is used, append null as a last argument.
Symbol constructor = accessConstructor(tree.pos(), meth);
if (constructor != meth) {
tree.args = tree.args.append(makeNull());
TreeInfo.setSymbol(tree.meth, constructor);
}
// If we are calling a constructor of a local class, add
// free variables after explicit constructor arguments.
ClassSymbol c = (ClassSymbol)constructor.owner;
if ((c.owner.kind & (VAR04 | MTH16)) != 0) {
List<VarSymbol> list = freevars(c);
List<JCExpression> listJCE = loadFreevars(tree.pos(), list);
tree.args = tree.args.appendList(listJCE);
}
// If we are calling a constructor of an enum class, pass
// along the name and ordinal arguments
if ( (c.flags_field&ENUM) != 0 ||
c.getQualifiedName() == names.java_lang_Enum ) {
List<JCVariableDecl> params = currentMethodDef.params;
if (currentMethodSym.owner.hasOuterInstance()) {
params = params.tail; // drop this$n
}
tree.args = tree.args
.prepend(make_at(tree.pos()).Ident(params.tail.head.sym)) // ordinal
.prepend(make.Ident(params.head.sym)); // name
}
// If we are calling a constructor of a class with an outer
// instance, and the call
// is qualified, pass qualifier as first argument in front of
// the explicit constructor arguments. If the call
// is not qualified, pass the correct outer instance as
// first argument.
if (c.hasOuterInstance()) {
JCExpression thisArg;
if (tree.meth.getTag() == JCTree.SELECT) {
JCExpression jj = ((JCFieldAccess) tree.meth).selected;
JCExpression jce = translate(jj);
thisArg = attr.makeNullCheck(jce);
tree.meth = make.Ident(constructor);
((JCIdentifier) tree.meth).name = methName;
} else if ((c.owner.kind & (MTH16 | VAR04)) != 0 || methName == names._this){
// local class or this() call
thisArg = makeThis(tree.meth.pos(), c.type.getEnclosingType().tsym);
} else {
// super() call of nested class - never pick ‘this‘
thisArg = makeOwnerThisN(tree.meth.pos(), c, false);
}
tree.args = tree.args.prepend(thisArg);
}
} else {
// We are seeing a normal method invocation; translate this as usual.
tree.meth = translate(tree.meth);
// If the translated method itself is an Apply tree, we are
// seeing an access method invocation. In this case, append
// the method arguments to the arguments of the access method.
if (tree.meth.getTag() == JCTree.APPLY) {
JCMethodInvocation app = (JCMethodInvocation)tree.meth;
app.args = tree.args.prependList(app.args);
result = app;
return;
}
}
result = tree;
}
List<JCExpression> boxArgs(List<Type> parameters, List<JCExpression> _args, Type varargsElement) {
List<JCExpression> args = _args;
if (parameters.isEmpty()) {
return args;
}
boolean anyChanges = false;
ListBuffer<JCExpression> result = new ListBuffer<JCExpression>();
while (parameters.tail.nonEmpty()) { // 由于取的是tail进行判断,所以如果长度为1时不判断
// JCExpression期望的类型Type
JCExpression arg = translate(args.head, parameters.head);
anyChanges |= (arg != args.head);
result.append(arg);
args = args.tail;
parameters = parameters.tail;
}
// 解决varargs的情况
Type parameter = parameters.head;
if (varargsElement != null) {
anyChanges = true;
ListBuffer<JCExpression> elems = new ListBuffer<JCExpression>();
while (args.nonEmpty()) {
JCExpression arg = translate(args.head, varargsElement);
elems.append(arg);
args = args.tail;
}
JCExpression jce = make.Type(varargsElement);
JCNewArray boxedArgs = make.NewArray(jce,List.<JCExpression>nil(),elems.toList());
boxedArgs.type = new ArrayType(varargsElement, syms.arrayClass);
result.append(boxedArgs);
} else { // 判断参数类型长度为1的情况
if (args.length() != 1) {
throw new AssertionError(args);
}
JCExpression arg = translate(args.head, parameter);
anyChanges |= (arg != args.head);
result.append(arg);
if (!anyChanges) { // 没有改变就返回原来的_args
return _args;
}
}
return result.toList();
}
/** Expand a boxing or unboxing conversion if needed. */
@SuppressWarnings("unchecked") // XXX unchecked
<T extends JCTree> T boxIfNeeded(T tree, Type type) {
boolean havePrimitive = tree.type.isPrimitive();
if (havePrimitive == type.isPrimitive()) {
return tree;
}
if (havePrimitive) { // 表达式的类型为基本类型,装箱
Type unboxedTarget = types.unboxedType(type);
if (unboxedTarget.tag != NONE18) {
if (!types.isSubtypeCapture(tree.type, unboxedTarget)) { //e.g. Character c = 89;
tree.type = unboxedTarget.constType(tree.type.constantValue());
}
return (T)boxPrimitive((JCExpression)tree, type);
} else {
tree = (T)boxPrimitive((JCExpression)tree);
}
} else { // 表示式的类型不为基本类型,则拆箱
tree = (T)unbox((JCExpression)tree, type);
}
return tree;
}
/** Box up a single primitive expression. */
JCExpression boxPrimitive(JCExpression tree) {
Type t = types.boxedClass(tree.type).type;
return boxPrimitive(tree, t);
}
/** Box up a single primitive expression. */
JCExpression boxPrimitive(JCExpression tree, Type box) {
make_at(tree.pos());
if (target.boxWithConstructors()) {
Symbol ctor = lookupConstructor(tree.pos(),
box,
List.<Type>nil().prepend(tree.type));
return make.Create(ctor, List.of(tree));
} else {
Symbol valueOfSym = lookupMethod(tree.pos(),
names.valueOf,
box,
List.<Type>nil().prepend(tree.type));
return make.App(make.QualIdent(valueOfSym), List.of(tree));
}
}
/** Unbox an object to a primitive value. */
JCExpression unbox(JCExpression tree, Type primitive) {
Type unboxedType = types.unboxedType(tree.type);
if (unboxedType.tag == NONE18) {
unboxedType = primitive;
if (!unboxedType.isPrimitive()) {
throw new AssertionError(unboxedType);
}
make_at(tree.pos());
Type temp = types.boxedClass(unboxedType).type;
tree = make.TypeCast(temp, tree);
} else {
// There must be a conversion from unboxedType to primitive.
if (!types.isSubtypeCapture(unboxedType, primitive)) {
throw new AssertionError(tree);
}
}
make_at(tree.pos());
// 如果是int,则name为intVale,其它类似...
Name name = unboxedType.tsym.name.append(names.Value);
Symbol valueSym = lookupMethod(tree.pos(),
name, // x.intValue()
tree.type,
List.<Type>nil());
// eg1: 将new Integer(1)变为new Integer(1).intValue(),因为目标primitive
// 要求的是int类型
return make.App(make.Select(tree, valueSym));
}
/** Visitor method for parenthesized expressions.If the subexpression has changed, omit the parens.
*/
public void visitParens(JCParens tree) {
JCTree expr = translate(tree.expr);
result = ((expr == tree.expr) ? tree : expr);
}
public void visitIndexed(JCArrayAccess tree) {
tree.indexed = translate(tree.indexed);
tree.index = translate(tree.index, syms.intType);
result = tree;
}
public void visitAssign(JCAssign tree) {
tree.lhs = translate(tree.lhs, tree);
tree.rhs = translate(tree.rhs, tree.lhs.type);
// If translated left hand side is an Apply, we are
// seeing an access method invocation. In this case, append
// right hand side as last argument of the access method.
if (tree.lhs.getTag() == JCTree.APPLY) {
JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
app.args = List.of(tree.rhs).prependList(app.args);
result = app;
} else {
result = tree;
}
}
public void visitAssignop(final JCAssignOp tree) { // todo
if (!tree.lhs.type.isPrimitive() && // 左边的类型不为基础类型
tree.operator.type.getReturnType().isPrimitive()) { // 操作符返回的是基本类型
// boxing required; need to rewrite as x = (unbox typeof x)(x op y);
// or if
// x == (typeof x)z
// then
// z = (unbox typeof x)( (typeof x)z op y)
// (but without recomputing x)
/*
eg1:
Integer a = 1;
a += 2;
最后会变为 (int)(a+2)
*/
TreeBuilder tb = new TreeBuilder() {
public JCTree build(final JCTree lhs) {
int newTag = tree.getTag() - JCTree.ASGOffset;
// Erasure (TransTypes) can change the type of
// tree.lhs. However, we can still get the
// unerased type of tree.lhs as it is stored
// in tree.type in Attr.
Symbol newOperator = rs.resolveBinaryOperator(tree.pos(),
newTag,
attrEnv,
tree.type, // left type
tree.rhs.type); // right type
JCExpression expr = (JCExpression)lhs;
if (expr.type != tree.type) {
expr = make.TypeCast(tree.type, expr);
}
JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
opResult.operator = newOperator;
opResult.type = newOperator.type.getReturnType();
Type ut = types.unboxedType(tree.type);
JCTypeCast newRhs = make.TypeCast(ut,opResult);
JCExpression jca = make.Assign((JCExpression)lhs, newRhs).setType(tree.type);
return jca;
}
};
JCTree newTree = abstractLval(tree.lhs,tb);
result = translate(newTree);
return;
}
tree.lhs = translate(tree.lhs, tree);
tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
// If translated left hand side is an Apply, we are
// seeing an access method invocation. In this case, append
// right hand side as last argument of the access method.
/*
查看例子:https://www.cnblogs.com/extjs4/p/9369601.html
*/
if (tree.lhs.getTag() == JCTree.APPLY) {
JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
// if operation is a += on strings,
// treeMaker sure to convert argument to string
JCExpression rhs = null;
if(((OperatorSymbol)tree.operator).opcode == string_add){
rhs = makeString(tree.rhs);
}else{
rhs = tree.rhs;
}
app.args = List.of(rhs).prependList(app.args);
result = app;
} else {
result = tree;
}
}
/** Lower a tree of the form e++ or e-- where e is an object type */
JCTree lowerBoxedPostop(final JCUnary tree) {
/*
translate to
tmp1=lval(e);
tmp2=tmp1;
tmp1 OP 1;
tmp2 // 返回tmp2值,表示了先用值后加值
or
translate to
tmp1=lval(e);
tmp2=tmp1;
(typeof tree)tmp1 OP 1;
tmp2
where OP is += or -=
*/
final boolean cast = TreeInfo.skipParens(tree.arg).getTag() == JCTree.TYPECAST;
TreeBuilder tb = new TreeBuilder() {
public JCTree build(final JCTree tmp1) { // 实现TreeBuilder中定义的build方法
TreeBuilder tb = new TreeBuilder() {
public JCTree build(final JCTree tmp2) { // 实现TreeBuilder中定义的build方法
int opcode = (tree.getTag() == JCTree.POSTINC) // 如e++,则opcode为 +=,否则为-=
? JCTree.PLUS_ASG : JCTree.MINUS_ASG;
JCTree lhs = cast? make.TypeCast(tree.arg.type, (JCExpression)tmp1) : tmp1;
JCTree update = makeAssignop(opcode,lhs,make.Literal(1));
return makeComma(update, tmp2);
}
};
return abstractRval(tmp1, tree.arg.type, tb);
}
};
return abstractLval(tree.arg,tb );
}
public void visitUnary(JCUnary tree) {
// tree是 ++ 或者 --
boolean isUpdateOperator = JCTree.PREINC <= tree.getTag() &&
tree.getTag() <= JCTree.POSTDEC;
if (isUpdateOperator && !tree.arg.type.isPrimitive()) {
switch(tree.getTag()) {
case JCTree.PREINC: // ++ e translate to e += 1
case JCTree.PREDEC: // -- e translate to e -= 1
{
int opcode = (tree.getTag() == JCTree.PREINC)
? JCTree.PLUS_ASG : JCTree.MINUS_ASG;
JCAssignOp newTree = makeAssignop(opcode,tree.arg,make.Literal(1));
result = translate(newTree, tree.type);
return;
}
case JCTree.POSTINC: // e ++
case JCTree.POSTDEC: // e --
{
JCTree jct = lowerBoxedPostop(tree);
result = translate(jct, tree.type);
return;
}
}
throw new AssertionError(tree);
}
JCExpression jce = translate(tree.arg, tree);
tree.arg = boxIfNeeded(jce, tree.type);
if (tree.getTag() == JCTree.NOT &&
tree.arg.type.constantValue() != null) {
tree.type = cfolder.fold1(bool_not, tree.arg.type);
}
// If translated left hand side is an Apply, we are
// seeing an access method invocation. In this case, return
// that access method invocation as result.
if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) {
result = tree.arg;
} else {
result = tree;
}
}
public void visitBinary(JCBinary tree) {
List<Type> formals = tree.operator.type.getParameterTypes();
JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
switch (tree.getTag()) {
case JCTree.OR:
if (lhs.type.isTrue()) {
result = lhs;
return;
}
if (lhs.type.isFalse()) {
result = translate(tree.rhs, formals.tail.head);
return;
}
break;
case JCTree.AND:
if (lhs.type.isFalse()) {
result = lhs;
return;
}
if (lhs.type.isTrue()) {
result = translate(tree.rhs, formals.tail.head);
return;
}
break;
}
tree.rhs = translate(tree.rhs, formals.tail.head);
result = tree;
}
public void visitIdentifier(JCIdentifier tree) {
result = access(tree.sym, tree, enclOperator, false);
}
/** Translate away the foreach loop. */
public void visitForeachLoop(JCEnhancedForLoop tree) {
if (types.elemtype(tree.expr.type) == null) {
visitIterableForeachLoop(tree);
}else {
visitArrayForeachLoop(tree);
}
}
// where
/**
* A statement of the form
*
* for ( T v : arrayexpr ) stmt;
*
* (where arrayexpr is of an array type) gets translated to
*
* for ( { arraytype #arr = arrayexpr;
* int #len = array.length;
* int #i = 0; };
* #i < #len; i$++ ) {
* T v = arr$[#i];
* stmt;
* }
*
* where #arr, #len, and #i are freshly named synthetic local variables.
*/
private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
make_at(tree.expr.pos());
VarSymbol arraycache = new VarSymbol(0,
names.fromString("arr" + target.syntheticNameChar()),
tree.expr.type,
currentMethodSym);
JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
VarSymbol lencache = new VarSymbol(0,
names.fromString("len" + target.syntheticNameChar()),
syms.intType,
currentMethodSym);
JCExpression jce = make.Select(make.Ident(arraycache), syms.lengthVar);
JCStatement lencachedef = make.VarDef(lencache, jce);
VarSymbol index = new VarSymbol(0,
names.fromString("i" + target.syntheticNameChar()),
syms.intType,
currentMethodSym);
JCVariableDecl indexdef = make.VarDef(index, make.Literal(INT04, 0));
indexdef.init.type = indexdef.type = syms.intType.constType(0);
List<JCStatement> loopinit = List.of(arraycachedef, lencachedef, indexdef);
JCBinary cond = makeBinary(JCTree.LT, make.Ident(index), make.Ident(lencache));
JCExpressionStatement step = make.Exec(makeUnary(JCTree.PREINC, make.Ident(index)));
Type elemtype = types.elemtype(tree.expr.type);
JCExpression loopvarinit = make.Indexed(make.Ident(arraycache),
make.Ident(index)).setType(elemtype);
JCVariableDecl loopvardef = (JCVariableDecl)make.VarDef(tree.var.mods,
tree.var.name,
tree.var.vartype,
loopvarinit).setType(tree.var.type);
loopvardef.sym = tree.var.sym;
JCBlock body = make.Block(0, List.of(loopvardef, tree.body));
JCForLoop jcf = make.ForLoop(loopinit,cond,List.of(step),body);
result = translate(jcf);
patchTargets(body, tree, result);
}
/** Patch up break and continue targets. */
private void patchTargets(JCTree body, final JCTree src, final JCTree dest) {
class Patcher extends TreeScanner {
public void visitBreak(JCBreak tree) {
if (tree.target == src)
tree.target = dest;
}
public void visitContinue(JCContinue tree) {
if (tree.target == src)
tree.target = dest;
}
public void visitClassDef(JCClassDecl tree) {}
}
new Patcher().scan(body);
}
/**
* A statement of the form
*
* for ( T v : coll ) stmt ;
*
* (where coll implements Iterable<? extends T>) gets translated to
*
* for ( Iterator<? extends T> #i = coll.iterator(); #i.hasNext(); ) {
* T v = (T) #i.next();
* stmt;
* }
*
* where #i is a freshly named synthetic local variable.
*/
private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
make_at(tree.expr.pos());
Type iteratorTarget = syms.objectType;
Type ub = types.upperBound(tree.expr.type);
Type iterableType = types.asSuper(ub,syms.iterableType.tsym);
if (iterableType.getTypeArguments().nonEmpty()) {
Type ht = iterableType.getTypeArguments().head;
iteratorTarget = types.erasure(ht);
}
Type eType = tree.expr.type;
tree.expr.type = types.erasure(eType);
if (eType.tag == TYPEVAR14 && eType.getUpperBound().isCompound()) {
tree.expr = make.TypeCast(types.erasure(iterableType), tree.expr);
}
Symbol iterator = lookupMethod(tree.expr.pos(),
names.iterator,
types.erasure(syms.iterableType),
List.<Type>nil());
VarSymbol itvar = new VarSymbol(0, names.fromString("i" + target.syntheticNameChar()),
types.erasure(iterator.type.getReturnType()),
currentMethodSym);
JCMethodInvocation jcmi = make.App(make.Select(tree.expr, iterator));
JCStatement init = make.VarDef(itvar,jcmi);
Symbol hasNext = lookupMethod(tree.expr.pos(),
names.hasNext,
itvar.type,
List.<Type>nil());
JCMethodInvocation cond = make.App(make.Select(make.Ident(itvar), hasNext));
Symbol next = lookupMethod(tree.expr.pos(),
names.next,
itvar.type,
List.<Type>nil());
JCExpression vardefinit = make.App(make.Select(make.Ident(itvar), next));
if (tree.var.type.isPrimitive()) {
vardefinit = make.TypeCast(types.upperBound(iteratorTarget), vardefinit);
}else {
vardefinit = make.TypeCast(tree.var.type, vardefinit);
}
JCVariableDecl indexDef = (JCVariableDecl)make.VarDef(tree.var.mods,
tree.var.name,
tree.var.vartype,
vardefinit).setType(tree.var.type);
indexDef.sym = tree.var.sym;
JCBlock body = make.Block(0, List.of(indexDef, tree.body));
body.endpos = TreeInfo.endPos(tree.body);
JCForLoop jcfl = make.ForLoop(List.of(init),
cond,
List.<JCExpressionStatement>nil(),
body);
result = translate(jcfl);
patchTargets(body, tree, result);
}
public void visitVarDef(JCVariableDecl tree) {
MethodSymbol oldMethodSym = currentMethodSym;
tree.mods = translate(tree.mods);
tree.vartype = translate(tree.vartype);
if (currentMethodSym == null) {
// A class or instance field initializer.
currentMethodSym = new MethodSymbol(
(tree.mods.flags&STATIC) | BLOCK, // flags
names.empty, // name
null, // type
currentClass); // owner
}
if (tree.init != null) {
tree.init = translate(tree.init, tree.type);
}
result = tree;
currentMethodSym = oldMethodSym;
}
public void visitBlock(JCBlock tree) {
MethodSymbol oldMethodSym = currentMethodSym;
if (currentMethodSym == null) {
// Block is a static or instance initializer.
currentMethodSym = new MethodSymbol(tree.flags | BLOCK,
names.empty, null,
currentClass);
}
super.visitBlock(tree);
currentMethodSym = oldMethodSym;
}
public void visitDoLoop(JCDoWhileLoop tree) {
tree.body = translate(tree.body);
tree.cond = translate(tree.cond, syms.booleanType);
result = tree;
}
public void visitWhileLoop(JCWhileLoop tree) {
tree.cond = translate(tree.cond, syms.booleanType);
tree.body = translate(tree.body);
result = tree;
}
public void visitForLoop(JCForLoop tree) {
tree.init = translate(tree.init);
if (tree.cond != null) {
tree.cond = translate(tree.cond, syms.booleanType);
}
tree.step = translate(tree.step);
tree.body = translate(tree.body);
result = tree;
}
public void visitReturn(JCReturn tree) {
if (tree.expr != null) {
Type era = types.erasure(currentMethodDef.restype.type);
tree.expr = translate(tree.expr,era);
}
result = tree;
}
public void visitSwitch(JCSwitch tree) {
Type selsuper = types.supertype(tree.selector.type);
boolean enumSwitch = selsuper != null &&
(tree.selector.type.tsym.flags() & ENUM) != 0;
boolean stringSwitch = selsuper != null &&
types.isSameType(tree.selector.type, syms.stringType);
// switch中的类型只能是Enum枚举类型、字符串类型或者整数int类型
Type target;
if(enumSwitch){
target = tree.selector.type;
}else if(stringSwitch){
target = syms.stringType;
}else{
target = syms.intType;
}
// Translate a single node, boxing or unboxing if needed.
tree.selector = translate(tree.selector, target);
tree.cases = translateCases(tree.cases); // translate a list of case parts of switch statements.
if (enumSwitch) {
result = visitEnumSwitch(tree);
} else if (stringSwitch) {
result = visitStringSwitch(tree);
} else {
result = tree;
}
}
public JCTree visitEnumSwitch(JCSwitch tree) {
TypeSymbol enumSym = tree.selector.type.tsym;
EnumMapping map = mapForEnum(tree.pos(), enumSym);
make_at(tree.pos());
Symbol ordinalMethod = lookupMethod(tree.pos(),
names.ordinal,
tree.selector.type,
List.<Type>nil());
JCMethodInvocation jcm = make.App(make.Select(tree.selector,ordinalMethod));
JCArrayAccess selector = make.Indexed(map.mapVar,jcm);
ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
for (JCCase c : tree.cases) {
if (c.pat != null) {
VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
JCLiteral pat = map.forConstant(label);
cases.append(make.Case(pat, c.stats));
} else { // 处理默认的分支
cases.append(c);
}
}
JCSwitch enumSwitch = make.Switch(selector, cases.toList());
patchTargets(enumSwitch, tree, enumSwitch);
return enumSwitch;
}
public JCTree visitStringSwitch(JCSwitch tree) {
List<JCCase> caseList = tree.getCases();
int alternatives = caseList.size();
if (alternatives == 0) { // Strange but legal possibility
/*
eg1:
String fruit = "";
switch (fruit) {}
*/
JCExpression jce = attr.makeNullCheck(tree.getExpression());
return make.at(tree.pos()).Exec(jce);
} else {
/*
* The general approach used is to translate a single
* string switch statement into a series of two chained
* switch statements: the first a synthesized statement
* switching on the argument string‘s hash value and
* computing a string‘s position in the list of original
* case labels, if any, followed by a second switch on the
* computed integer value. The second switch has the same
* code structure as the original string switch statement
* except that the string case labels are replaced with
* positional integer constants starting at 0.
*
* The first switch statement can be thought of as an
* inlined map from strings to their position in the case
* label list. An alternate implementation would use an
* actual Map for this purpose, as done for enum switches.
*
* With some additional effort, it would be possible to
* use a single switch statement on the hash code of the
* argument, but care would need to be taken to preserve
* the proper control flow in the presence of hash
* collisions and other complications, such as
* fallthroughs. Switch statements with one or two
* alternatives could also be specially translated into
* if-then statements to omit the computation of the hash
* code.
*
* The generated code assumes that the hashing algorithm
* of String is the same in the compilation environment as
* in the environment the code will run in. The string
* hashing algorithm in the SE JDK has been unchanged
* since at least JDK 1.2. Since the algorithm has been
* specified since that release as well, it is very
* unlikely to be changed in the future.
*
* Different hashing algorithms, such as the length of the
* strings or a perfect hashing algorithm over the
* particular set of case labels, could potentially be
* used instead of String.hashCode.
*/
ListBuffer<JCStatement> stmtList = new ListBuffer<JCStatement>();
// Map from String case labels to their original position in
// the list of case labels.
Map<String, Integer> caseLabelToPosition = new LinkedHashMap<String, Integer>(alternatives + 1, 1.0f);
// Map of hash codes to the string case labels having that hashCode.
Map<Integer, Set<String>> hashToString = new LinkedHashMap<Integer, Set<String>>(alternatives + 1, 1.0f);
int casePosition = 0;
for(JCCase oneCase : caseList) {
JCExpression expression = oneCase.getExpression();
if (expression != null) { // expression for a "default" case is null
String labelExpr = (String) expression.type.constantValue();
Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
Assert.checkNull(mapping);
int hashCode = labelExpr.hashCode();
Set<String> stringSet = hashToString.get(hashCode);
if (stringSet == null) {
stringSet = new LinkedHashSet<String>(1, 1.0f);
stringSet.add(labelExpr);
hashToString.put(hashCode, stringSet);
} else {
boolean added = stringSet.add(labelExpr);
Assert.check(added);
}
}
casePosition++;
}
// Synthesize a switch statement that has the effect of
// mapping from a string to the integer position of that
// string in the list of case labels. This is done by
// switching on the hashCode of the string followed by an
// if-then-else chain comparing the input for equality
// with all the case labels having that hash value.
/*
* s$ = top of stack;
* tmp$ = -1;
* switch($s.hashCode()) {
* case caseLabel.hashCode:
* if (s$.equals("caseLabel_1")
* tmp$ = caseLabelToPosition("caseLabel_1");
* else if (s$.equals("caseLabel_2"))
* tmp$ = caseLabelToPosition("caseLabel_2");
* ...
* break;
* ...
* }
*/
VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
names.fromString("s" + tree.pos + target.syntheticNameChar()),
syms.stringType,
currentMethodSym);
stmtList.append(make.at(tree.pos()).VarDef(dollar_s, tree.getExpression()).setType(dollar_s.type));
VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
syms.intType,
currentMethodSym);
JCVariableDecl jcv = make.VarDef(dollar_tmp, make.Literal(INT04, -1));
JCVariableDecl dollar_tmp_def = (JCVariableDecl)jcv.setType(dollar_tmp.type);
dollar_tmp_def.init.type = dollar_tmp.type = syms.intType;
stmtList.append(dollar_tmp_def);
ListBuffer<JCCase> caseBuffer = ListBuffer.lb();
// hashCode will trigger nullcheck on original switch expression
JCMethodInvocation hashCodeCall = makeCall(make.Ident(dollar_s),
names.hashCode,
List.<JCExpression>nil()).setType(syms.intType);
JCSwitch switch1 = make.Switch(hashCodeCall,
caseBuffer.toList());
for(Map.Entry<Integer, Set<String>> entry : hashToString.entrySet()) {
int hashCode = entry.getKey();
Set<String> stringsWithHashCode = entry.getValue();
Assert.check(stringsWithHashCode.size() >= 1);
JCStatement elsepart = null;
for(String caseLabel : stringsWithHashCode ) {
JCMethodInvocation stringEqualsCall = makeCall(make.Ident(dollar_s),
names.equals,
List.<JCExpression>of(make.Literal(caseLabel)));
JCLiteral jcl = make.Literal(caseLabelToPosition.get(caseLabel));
JCAssign jca = make.Assign(make.Ident(dollar_tmp),jcl);
JCExpressionStatement jces = make.Exec(jca.setType(dollar_tmp.type));
elsepart = make.If(stringEqualsCall,jces,elsepart);
}
ListBuffer<JCStatement> lb = ListBuffer.lb();
JCBreak breakStmt = make.Break(null);
breakStmt.target = switch1;
lb.append(elsepart).append(breakStmt);
caseBuffer.append(make.Case(make.Literal(hashCode), lb.toList()));
}
switch1.cases = caseBuffer.toList();
stmtList.append(switch1);
// Make isomorphic switch tree replacing string labels
// with corresponding integer ones from the label to
// position map.
ListBuffer<JCCase> lb = ListBuffer.lb();
JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
for(JCCase oneCase : caseList ) {
// Rewire up old unlabeled break statements to the
// replacement switch being created.
patchTargets(oneCase, tree, switch2);
boolean isDefault = (oneCase.getExpression() == null);
JCExpression caseExpr;
if (isDefault)
caseExpr = null;
else {
JCExpression jce = TreeInfo.skipParens(oneCase.getExpression());
Object s = caseLabelToPosition.get((String)jce.type.constantValue());
caseExpr = make.Literal(s);
}
lb.append(make.Case(caseExpr,oneCase.getStatements()));
}
switch2.cases = lb.toList();
stmtList.append(switch2);
JCBlock jcBlock = make.Block(0L, stmtList.toList());
return jcBlock;
}
}
public void visitNewArray(JCNewArray tree) {
tree.elemtype = translate(tree.elemtype);
for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail) {
if (t.head != null) {
t.head = translate(t.head, syms.intType);
}
}
Type type = types.elemtype(tree.type);
tree.elems = translate(tree.elems, type);
result = tree;
}
/*
eg1:
class Parent {
public String method1() {
return null;
}
}
class Sub extends Parent {
public String method1() {
return null;
}
class inner {
public void t() {
String a = Sub.super.method1(); // 为什么能替换成this$0 ?
String b = Sub.this.method1();
}
}
public void sm() {
String d = Sub.class.getName();
String c = Parent.class.getName();
}
}
解语法糖后如下:
class Sub extends Parent{
class inner {
final Sub this$0;
public void t(){
String s = method1();
String s1 = method1();
}
inner() { // Inner类的构造函数
this$0 = Sub.this;
super();
}
}
Sub(){ } // Sub类的构造函数
public String method1() {
return null;
}
public void sm() {
String s = com/test15/Sub.getName();
String s1 = com/test15/Parent.getName();
}
}
*/
public void visitSelect(JCFieldAccess tree) {
// need to special case-access of the form C.super.x
// these will always need an access method.
boolean qualifiedSuperAccess =
tree.selected.getTag() == JCTree.SELECT &&
TreeInfo.name(tree.selected) == names._super;
tree.selected = translate(tree.selected);
if (tree.name == names._class) {
result = classOf(tree.selected);
}else if (tree.name == names._this ||
tree.name == names._super) {
result = makeThis(tree.pos(), tree.selected.type.tsym);
}else {
result = access(tree.sym, tree, enclOperator, qualifiedSuperAccess);
}
}
// todo
public void visitLetExpr(LetExpr tree) {
tree.defs = translateVarDefs(tree.defs);
tree.expr = translate(tree.expr, tree.type);
result = tree;
}
// There ought to be nothing to rewrite here;
// we don‘t generate code.
public void visitAnnotation(JCAnnotation tree) {
result = tree;
}
@Override
public void visitTry(JCTry tree) {
if (tree.resources.isEmpty()) {
super.visitTry(tree);
} else {
result = makeTwrTry(tree);
}
}
/**************************************************************************
* main method
*************************************************************************/
/** Translate a toplevel class and return a list consisting of
* the translated class and translated versions of all inner classes.
* @param env The attribution environment current at the class definition.
* We need this for resolving some additional symbols.
* @param cdef The tree representing the class definition.
*/
public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
ListBuffer<JCTree> translated = null;
try {
attrEnv = env;
this.make = make;
endPositions = env.toplevel.endPositions;
currentClass = null;
currentMethodDef = null;
outermostClassDef = (cdef.getTag() == JCTree.CLASSDEF) ? (JCClassDecl)cdef : null;
outermostMemberDef = null;
this.translated = new ListBuffer<JCTree>();
classdefs = new HashMap<ClassSymbol,JCClassDecl>();
actualSymbols = new HashMap<Symbol,Symbol>();
freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>();
proxies = new Scope(syms.noSymbol);
twrVars = new Scope(syms.noSymbol);
outerThisStack = List.nil();
accessNums = new HashMap<Symbol,Integer>();
accessSyms = new HashMap<Symbol,MethodSymbol[]>();
accessConstrs = new HashMap<Symbol,MethodSymbol>();
accessConstrTags = List.nil();
accessed = new ListBuffer<Symbol>();
translate(cdef, (JCExpression)null);
for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail) {
makeAccessible(l.head);
}
// 调用生成与switch中使用枚举的辅助类
for (EnumMapping map : enumSwitchMap.values()) {
map.translate();
}
checkConflicts(this.translated.toList());
checkAccessConstructorTags();
translated = this.translated;
} finally {
// note that recursive invocations of this method fail hard
attrEnv = null;
this.make = null;
endPositions = null;
currentClass = null;
currentMethodDef = null;
outermostClassDef = null;
outermostMemberDef = null;
this.translated = null;
classdefs = null;
actualSymbols = null;
freevarCache = null;
proxies = null;
outerThisStack = null;
accessNums = null;
accessSyms = null;
accessConstrs = null;
accessConstrTags = null;
accessed = null;
enumSwitchMap.clear();
}
return translated.toList();
}
//////////////////////////////////////////////////////////////
// The following contributed by Borland for bootstrapping purposes
//////////////////////////////////////////////////////////////
// private void addEnumCompatibleMembers(JCClassDecl cdef) {
// make_at(null);
//
// // Add the special enum fields
// VarSymbol ordinalFieldSym = addEnumOrdinalField(cdef);
// VarSymbol nameFieldSym = addEnumNameField(cdef);
//
// // Add the accessor methods for name and ordinal
// MethodSymbol ordinalMethodSym = addEnumFieldOrdinalMethod(cdef, ordinalFieldSym);
// MethodSymbol nameMethodSym = addEnumFieldNameMethod(cdef, nameFieldSym);
//
// // Add the toString method
// addEnumToString(cdef, nameFieldSym);
//
// // Add the compareTo method
// addEnumCompareTo(cdef, ordinalFieldSym);
// }
//
// private VarSymbol addEnumOrdinalField(JCClassDecl cdef) {
// VarSymbol ordinal = new VarSymbol(PRIVATE|FINAL|SYNTHETIC,
// names.fromString("$ordinal"),
// syms.intType,
// cdef.sym);
// cdef.sym.members().enter(ordinal);
// cdef.defs = cdef.defs.prepend(make.VarDef(ordinal, null));
// return ordinal;
// }
//
// private VarSymbol addEnumNameField(JCClassDecl cdef) {
// VarSymbol name = new VarSymbol(PRIVATE|FINAL|SYNTHETIC,
// names.fromString("$name"),
// syms.stringType,
// cdef.sym);
// cdef.sym.members().enter(name);
// cdef.defs = cdef.defs.prepend(make.VarDef(name, null));
// return name;
// }
//
// private MethodSymbol addEnumFieldOrdinalMethod(JCClassDecl cdef, VarSymbol ordinalSymbol) {
// // Add the accessor methods for ordinal
// Symbol ordinalSym = lookupMethod(cdef.pos(),
// names.ordinal,
// cdef.type,
// List.<Type>nil());
//
// Assert.check(ordinalSym instanceof MethodSymbol);
//
// JCStatement ret = make.Return(make.Ident(ordinalSymbol));
// JCMethodDecl jcm = make.MethodDef((MethodSymbol)ordinalSym,
// make.Block(0L, List.of(ret)));
// cdef.defs = cdef.defs.append(jcm);
//
// return (MethodSymbol)ordinalSym;
// }
//
// private MethodSymbol addEnumFieldNameMethod(JCClassDecl cdef, VarSymbol nameSymbol) {
// // Add the accessor methods for name
// Symbol nameSym = lookupMethod(cdef.pos(),
// names._name,
// cdef.type,
// List.<Type>nil());
//
// Assert.check(nameSym instanceof MethodSymbol);
//
// JCStatement ret = make.Return(make.Ident(nameSymbol));
//
// cdef.defs = cdef.defs.append(make.MethodDef((MethodSymbol)nameSym,
// make.Block(0L, List.of(ret))));
//
// return (MethodSymbol)nameSym;
// }
//
// private MethodSymbol addEnumToString(JCClassDecl cdef,
// VarSymbol nameSymbol) {
// Symbol toStringSym = lookupMethod(cdef.pos(),
// names.toString,
// cdef.type,
// List.<Type>nil());
//
// JCTree toStringDecl = null;
// if (toStringSym != null) {
// toStringDecl = TreeInfo.declarationFor(toStringSym, cdef);
// }
//
// if (toStringDecl != null) {
// return (MethodSymbol) toStringSym;
// }
//
// JCStatement ret = make.Return(make.Ident(nameSymbol));
//
// JCTree resTypeTree = make.Type(syms.stringType);
//
// MethodType toStringType = new MethodType(List.<Type>nil(),
// syms.stringType,
// List.<Type>nil(),
// cdef.sym);
// toStringSym = new MethodSymbol(PUBLIC,
// names.toString,
// toStringType,
// cdef.type.tsym);
// toStringDecl = make.MethodDef((MethodSymbol)toStringSym,
// make.Block(0L, List.of(ret)));
//
// cdef.defs = cdef.defs.prepend(toStringDecl);
// cdef.sym.members().enter(toStringSym);
//
// return (MethodSymbol)toStringSym;
// }
//
// private MethodSymbol addEnumCompareTo(JCClassDecl cdef, VarSymbol ordinalSymbol) {
// Symbol compareToSym = lookupMethod(cdef.pos(),
// names.compareTo,
// cdef.type,
// List.of(cdef.sym.type));
//
// Assert.check(compareToSym instanceof MethodSymbol);
//
// JCMethodDecl compareToDecl = (JCMethodDecl) TreeInfo.declarationFor(compareToSym, cdef);
//
// ListBuffer<JCStatement> blockStatements = new ListBuffer<JCStatement>();
//
// JCModifiers mod1 = make.Modifiers(0L);
// Name oName = names.fromString("o");
// JCVariableDecl par1 = make.Param(oName, cdef.type, compareToSym);
//
// JCIdentifier paramId1 = make.Ident(names.java_lang_Object);
// paramId1.type = cdef.type;
// paramId1.sym = par1.sym;
//
// ((MethodSymbol)compareToSym).params = List.of(par1.sym);
//
// JCIdentifier par1UsageId = make.Ident(par1.sym);
// JCIdentifier castTargetIdent = make.Ident(cdef.sym);
// JCTypeCast cast = make.TypeCast(castTargetIdent, par1UsageId);
// cast.setType(castTargetIdent.type);
//
// Name otherName = names.fromString("other");
//
// VarSymbol otherVarSym = new VarSymbol(mod1.flags,
// otherName,
// cdef.type,
// compareToSym);
// JCVariableDecl otherVar = make.VarDef(otherVarSym, cast);
// blockStatements.append(otherVar);
//
// JCIdentifier id1 = make.Ident(ordinalSymbol);
//
// JCIdentifier fLocUsageId = make.Ident(otherVarSym);
// JCExpression sel = make.Select(fLocUsageId, ordinalSymbol);
// JCBinary bin = makeBinary(JCTree.MINUS, id1, sel);
// JCReturn ret = make.Return(bin);
// blockStatements.append(ret);
// JCMethodDecl compareToMethod = make.MethodDef((MethodSymbol)compareToSym,
// make.Block(0L,
// blockStatements.toList()));
// compareToMethod.params = List.of(par1);
// cdef.defs = cdef.defs.append(compareToMethod);
//
// return (MethodSymbol)compareToSym;
// }
//////////////////////////////////////////////////////////////
// The above contributed by Borland for bootstrapping purposes
//////////////////////////////////////////////////////////////
}
标签:any lte trigger follow iter efi abstract arguments 检查
原文地址:https://www.cnblogs.com/extjs4/p/9458715.html