📄 transtypes.java
字号:
/* * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */package com.sun.tools.javac.comp;import java.util.*;import com.sun.tools.javac.code.*;import com.sun.tools.javac.code.Symbol.*;import com.sun.tools.javac.tree.*;import com.sun.tools.javac.tree.JCTree.*;import com.sun.tools.javac.util.*;import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;import com.sun.tools.javac.util.List;import static com.sun.tools.javac.code.Flags.*;import static com.sun.tools.javac.code.Kinds.*;import static com.sun.tools.javac.code.TypeTags.*;/** This pass translates Generic Java to conventional Java. * * <p><b>This is NOT part of any API supported by Sun Microsystems. If * you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice.</b> */public class TransTypes extends TreeTranslator { /** The context key for the TransTypes phase. */ protected static final Context.Key<TransTypes> transTypesKey = new Context.Key<TransTypes>(); /** Get the instance for this context. */ public static TransTypes instance(Context context) { TransTypes instance = context.get(transTypesKey); if (instance == null) instance = new TransTypes(context); return instance; } private Name.Table names; private Log log; private Symtab syms; private TreeMaker make; private Enter enter; private boolean allowEnums; private Types types; private final Resolve resolve; /** * Flag to indicate whether or not to generate bridge methods. * For pre-Tiger source there is no need for bridge methods, so it * can be skipped to get better performance for -source 1.4 etc. */ private final boolean addBridges; protected TransTypes(Context context) { context.put(transTypesKey, this); names = Name.Table.instance(context); log = Log.instance(context); syms = Symtab.instance(context); enter = Enter.instance(context); overridden = new HashMap<MethodSymbol,MethodSymbol>(); Source source = Source.instance(context); allowEnums = source.allowEnums(); addBridges = source.addBridges(); types = Types.instance(context); make = TreeMaker.instance(context); resolve = Resolve.instance(context); } /** A hashtable mapping bridge methods to the methods they override after * type erasure. */ Map<MethodSymbol,MethodSymbol> overridden; /** Construct an attributed tree for a cast of expression to target type, * unless it already has precisely that type. * @param tree The expression tree. * @param target The target type. */ JCExpression cast(JCExpression tree, Type target) { int oldpos = make.pos; make.at(tree.pos); if (!types.isSameType(tree.type, target)) { if (!resolve.isAccessible(env, target.tsym)) resolve.logAccessError(env, tree, target); tree = make.TypeCast(make.Type(target), tree).setType(target); } make.pos = oldpos; return tree; } /** Construct an attributed tree to coerce an expression to some erased * target type, unless the expression is already assignable to that type. * If target type is a constant type, use its base type instead. * @param tree The expression tree. * @param target The target type. */ JCExpression coerce(JCExpression tree, Type target) { Type btarget = target.baseType(); if (tree.type.isPrimitive() == target.isPrimitive()) { return types.isAssignable(tree.type, btarget, Warner.noWarnings) ? tree : cast(tree, btarget); } return tree; } /** Given an erased reference type, assume this type as the tree's type. * Then, coerce to some given target type unless target type is null. * This operation is used in situations like the following: * * class Cell<A> { A value; } * ... * Cell<Integer> cell; * Integer x = cell.value; * * Since the erasure of Cell.value is Object, but the type * of cell.value in the assignment is Integer, we need to * adjust the original type of cell.value to Object, and insert * a cast to Integer. That is, the last assignment becomes: * * Integer x = (Integer)cell.value; * * @param tree The expression tree whose type might need adjustment. * @param erasedType The expression's type after erasure. * @param target The target type, which is usually the erasure of the * expression's original type. */ JCExpression retype(JCExpression tree, Type erasedType, Type target) {// System.err.println("retype " + tree + " to " + erasedType);//DEBUG if (erasedType.tag > lastBaseTag) { if (target != null && target.isPrimitive()) target = erasure(tree.type); tree.type = erasedType; if (target != null) return coerce(tree, target); } return tree; } /** Translate method argument list, casting each argument * to its corresponding type in a list of target types. * @param _args The method argument list. * @param parameters The list of target types. * @param varargsElement The erasure of the varargs element type, * or null if translating a non-varargs invocation */ <T extends JCTree> List<T> translateArgs(List<T> _args, List<Type> parameters, Type varargsElement) { if (parameters.isEmpty()) return _args; List<T> args = _args; while (parameters.tail.nonEmpty()) { args.head = translate(args.head, parameters.head); args = args.tail; parameters = parameters.tail; } Type parameter = parameters.head; assert varargsElement != null || args.length() == 1; if (varargsElement != null) { while (args.nonEmpty()) { args.head = translate(args.head, varargsElement); args = args.tail; } } else { args.head = translate(args.head, parameter); } return _args; } /** Add a bridge definition and enter corresponding method symbol in * local scope of origin. * * @param pos The source code position to be used for the definition. * @param meth The method for which a bridge needs to be added * @param impl That method's implementation (possibly the method itself) * @param origin The class to which the bridge will be added * @param hypothetical * True if the bridge method is not strictly necessary in the * binary, but is represented in the symbol table to detect * erasure clashes. * @param bridges The list buffer to which the bridge will be added */ void addBridge(DiagnosticPosition pos, MethodSymbol meth, MethodSymbol impl, ClassSymbol origin, boolean hypothetical, ListBuffer<JCTree> bridges) { make.at(pos); Type origType = types.memberType(origin.type, meth); Type origErasure = erasure(origType); // Create a bridge method symbol and a bridge definition without a body. Type bridgeType = meth.erasure(types); long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE; if (hypothetical) flags |= HYPOTHETICAL; MethodSymbol bridge = new MethodSymbol(flags, meth.name, bridgeType, origin); if (!hypothetical) { JCMethodDecl md = make.MethodDef(bridge, null); // The bridge calls this.impl(..), if we have an implementation // in the current class, super.impl(...) otherwise. JCExpression receiver = (impl.owner == origin) ? make.This(origin.erasure(types)) : make.Super(types.supertype(origin.type).tsym.erasure(types), origin); // The type returned from the original method. Type calltype = erasure(impl.type.getReturnType()); // Construct a call of this.impl(params), or super.impl(params), // casting params and possibly results as needed. JCExpression call = make.Apply( null, make.Select(receiver, impl).setType(calltype), translateArgs(make.Idents(md.params), origErasure.getParameterTypes(), null)) .setType(calltype); JCStatement stat = (origErasure.getReturnType().tag == VOID) ? make.Exec(call) : make.Return(coerce(call, bridgeType.getReturnType())); md.body = make.Block(0, List.of(stat)); // Add bridge to `bridges' buffer bridges.append(md); } // Add bridge to scope of enclosing class and `overridden' table. origin.members().enter(bridge); overridden.put(bridge, meth); } /** Add bridge if given symbol is a non-private, non-static member * of the given class, which is either defined in the class or non-final * inherited, and one of the two following conditions holds: * 1. The method's type changes in the given class, as compared to the * class where the symbol was defined, (in this case * we have extended a parameterized class with non-trivial parameters). * 2. The method has an implementation with a different erased return type. * (in this case we have used co-variant returns).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -