📄 lower.java
字号:
*/ class EnumMapping { EnumMapping(DiagnosticPosition pos, TypeSymbol forEnum) { this.forEnum = forEnum; this.values = new LinkedHashMap<VarSymbol,Integer>(); this.pos = pos; Name varName = names .fromString(target.syntheticNameChar() + "SwitchMap" + target.syntheticNameChar() + writer.xClassName(forEnum.type).toString() .replace('/', '.') .replace('.', target.syntheticNameChar())); ClassSymbol outerCacheClass = outerCacheClass(); this.mapVar = new VarSymbol(STATIC | SYNTHETIC | FINAL, varName, new ArrayType(syms.intType, syms.arrayClass), outerCacheClass); enterSynthetic(pos, mapVar, outerCacheClass.members()); } DiagnosticPosition pos = null; // the next value to use int next = 1; // 0 (unused map elements) go to the default label // the enum for which this is a map final TypeSymbol forEnum; // the field containing the map final VarSymbol mapVar; // the mapped values final Map<VarSymbol,Integer> values; JCLiteral forConstant(VarSymbol v) { Integer result = values.get(v); if (result == null) values.put(v, result = next++); return make.Literal(result); } // generate the field initializer for the map void translate() { make.at(pos.getStartPosition()); JCClassDecl owner = classDef((ClassSymbol)mapVar.owner); // synthetic static final int[] $SwitchMap$Color = new int[Color.values().length]; MethodSymbol valuesMethod = lookupMethod(pos, names.values, forEnum.type, List.<Type>nil()); JCExpression size = make // Color.values().length .Select(make.App(make.QualIdent(valuesMethod)), syms.lengthVar); JCExpression mapVarInit = make .NewArray(make.Type(syms.intType), List.of(size), null) .setType(new ArrayType(syms.intType, syms.arrayClass)); // try { $SwitchMap$Color[red.ordinal()] = 1; } catch (java.lang.NoSuchFieldError ex) {} ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>(); Symbol ordinalMethod = lookupMethod(pos, names.ordinal, forEnum.type, List.<Type>nil()); List<JCCatch> catcher = List.<JCCatch>nil() .prepend(make.Catch(make.VarDef(new VarSymbol(PARAMETER, names.ex, syms.noSuchFieldErrorType, syms.noSymbol), null), make.Block(0, List.<JCStatement>nil()))); for (Map.Entry<VarSymbol,Integer> e : values.entrySet()) { VarSymbol enumerator = e.getKey(); Integer mappedValue = e.getValue(); JCExpression assign = make .Assign(make.Indexed(mapVar, make.App(make.Select(make.QualIdent(enumerator), ordinalMethod))), make.Literal(mappedValue)) .setType(syms.intType); JCStatement exec = make.Exec(assign); JCStatement _try = make.Try(make.Block(0, List.of(exec)), catcher, null); stmts.append(_try); } owner.defs = owner.defs .prepend(make.Block(STATIC, stmts.toList())) .prepend(make.VarDef(mapVar, mapVarInit)); } }/************************************************************************** * Tree building blocks *************************************************************************/ /** Equivalent to make.at(pos.getStartPosition()) with side effect of caching * pos as make_pos, for use in diagnostics. **/ TreeMaker make_at(DiagnosticPosition 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) { return make.Literal(type.tag, value).setType(type.constType(value)); } /** 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) { JCNewClass tree = make.NewClass(null, null, make.QualIdent(ctype.tsym), 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 >= CLASS) { return tree; } else { Symbol valueOfSym = lookupMethod(tree.pos(), names.valueOf, syms.stringType, 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 *************************************************************************/ /** Report a conflict between a user symbol and a synthetic symbol. */ private void duplicateError(DiagnosticPosition pos, Symbol sym) { if (!sym.type.isErroneous()) { log.error(pos, "synthetic.name.conflict", sym, sym.location()); } } /** 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. */ private void enterSynthetic(DiagnosticPosition pos, Symbol sym, Scope s) { if (sym.name != names.error && sym.name != names.empty) { for (Scope.Entry e = s.lookup(sym.name); e.scope == s; e = e.next()) { if (sym != e.sym && sym.kind == e.sym.kind) { // VM allows methods and variables with differing types if ((sym.kind & (MTH|VAR)) != 0 && !types.erasure(sym.type).equals(types.erasure(e.sym.type))) continue; duplicateError(pos, e.sym); break; } } } s.enter(sym); } /** 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; return (sym==null || (sym.flags()&SYNTHETIC)==0) ? null : sym; } /** Look up a method in a given scope. */ private MethodSymbol lookupMethod(DiagnosticPosition pos, Name name, Type qual, List<Type> args) { return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, null); } /** Look up a constructor. */ private MethodSymbol lookupConstructor(DiagnosticPosition pos, Type qual, List<Type> args) { return rs.resolveInternalConstructor(pos, attrEnv, qual, args, null); } /** Look up a field. */ private VarSymbol lookupField(DiagnosticPosition pos, Type qual, Name name) { return rs.resolveInternalField(pos, attrEnv, qual, name); }/************************************************************************** * 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. * * @see Gen.visitSelect(Select tree) */ private static final int DEREFcode = 0, ASSIGNcode = 2, PREINCcode = 4, PREDECcode = 6, POSTINCcode = 8, POSTDECcode = 10, FIRSTASGOPcode = 12; /** Number of access codes */ private static final int NCODES = accessCode(ByteCodes.lushrl) + 2; /** 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 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 && bytecode <= ByteCodes.lxor) return (bytecode - iadd) * 2 + FIRSTASGOPcode; else if (bytecode == ByteCodes.string_add) return (ByteCodes.lxor + 1 - iadd) * 2 + FIRSTASGOPcode; else if (ByteCodes.ishll <= bytecode && bytecode <= ByteCodes.lushrl) 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)) return accessCode(((OperatorSymbol) ((JCAssignOp) enclOp).operator).opcode); else return DEREFcode; } /** Return binary operator that corresponds to given access code. */ private OperatorSymbol binaryAccessOperator(int acode) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -