📄 gen.java
字号:
/* * Copyright 1999-2007 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.jvm;import java.util.*;import com.sun.tools.javac.util.*;import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;import com.sun.tools.javac.util.List;import com.sun.tools.javac.code.*;import com.sun.tools.javac.comp.*;import com.sun.tools.javac.tree.*;import com.sun.tools.javac.code.Symbol.*;import com.sun.tools.javac.code.Type.*;import com.sun.tools.javac.jvm.Code.*;import com.sun.tools.javac.jvm.Items.*;import com.sun.tools.javac.tree.JCTree.*;import static com.sun.tools.javac.code.Flags.*;import static com.sun.tools.javac.code.Kinds.*;import static com.sun.tools.javac.code.TypeTags.*;import static com.sun.tools.javac.jvm.ByteCodes.*;import static com.sun.tools.javac.jvm.CRTFlags.*;/** This pass maps flat Java (i.e. without inner classes) to bytecodes. * * <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 Gen extends JCTree.Visitor { protected static final Context.Key<Gen> genKey = new Context.Key<Gen>(); private final Log log; private final Symtab syms; private final Check chk; private final Resolve rs; private final TreeMaker make; private final Name.Table names; private final Target target; private final Type stringBufferType; private final Map<Type,Symbol> stringBufferAppend; private Name accessDollar; private final Types types; /** Switch: GJ mode? */ private final boolean allowGenerics; /** Set when Miranda method stubs are to be generated. */ private final boolean generateIproxies; /** Format of stackmap tables to be generated. */ private final Code.StackMapFormat stackMap; /** A type that serves as the expected type for all method expressions. */ private final Type methodType; public static Gen instance(Context context) { Gen instance = context.get(genKey); if (instance == null) instance = new Gen(context); return instance; } protected Gen(Context context) { context.put(genKey, this); names = Name.Table.instance(context); log = Log.instance(context); syms = Symtab.instance(context); chk = Check.instance(context); rs = Resolve.instance(context); make = TreeMaker.instance(context); target = Target.instance(context); types = Types.instance(context); methodType = new MethodType(null, null, null, syms.methodClass); allowGenerics = Source.instance(context).allowGenerics(); stringBufferType = target.useStringBuilder() ? syms.stringBuilderType : syms.stringBufferType; stringBufferAppend = new HashMap<Type,Symbol>(); accessDollar = names. fromString("access" + target.syntheticNameChar()); Options options = Options.instance(context); lineDebugInfo = options.get("-g:") == null || options.get("-g:lines") != null; varDebugInfo = options.get("-g:") == null ? options.get("-g") != null : options.get("-g:vars") != null; genCrt = options.get("-Xjcov") != null; debugCode = options.get("debugcode") != null; generateIproxies = target.requiresIproxy() || options.get("miranda") != null; if (target.generateStackMapTable()) { // ignore cldc because we cannot have both stackmap formats this.stackMap = StackMapFormat.JSR202; } else { if (target.generateCLDCStackmap()) { this.stackMap = StackMapFormat.CLDC; } else { this.stackMap = StackMapFormat.NONE; } } // by default, avoid jsr's for simple finalizers int setjsrlimit = 50; String jsrlimitString = options.get("jsrlimit"); if (jsrlimitString != null) { try { setjsrlimit = Integer.parseInt(jsrlimitString); } catch (NumberFormatException ex) { // ignore ill-formed numbers for jsrlimit } } this.jsrlimit = setjsrlimit; this.useJsrLocally = false; // reset in visitTry } /** Switches */ private final boolean lineDebugInfo; private final boolean varDebugInfo; private final boolean genCrt; private final boolean debugCode; /** Default limit of (approximate) size of finalizer to inline. * Zero means always use jsr. 100 or greater means never use * jsr. */ private final int jsrlimit; /** True if jsr is used. */ private boolean useJsrLocally; /* Constant pool, reset by genClass. */ private Pool pool = new Pool(); /** Code buffer, set by genMethod. */ private Code code; /** Items structure, set by genMethod. */ private Items items; /** Environment for symbol lookup, set by genClass */ private Env<AttrContext> attrEnv; /** The top level tree. */ private JCCompilationUnit toplevel; /** The number of code-gen errors in this class. */ private int nerrs = 0; /** A hash table mapping syntax trees to their ending source positions. */ private Map<JCTree, Integer> endPositions; /** Generate code to load an integer constant. * @param n The integer to be loaded. */ void loadIntConst(int n) { items.makeImmediateItem(syms.intType, n).load(); } /** The opcode that loads a zero constant of a given type code. * @param tc The given type code (@see ByteCode). */ public static int zero(int tc) { switch(tc) { case INTcode: case BYTEcode: case SHORTcode: case CHARcode: return iconst_0; case LONGcode: return lconst_0; case FLOATcode: return fconst_0; case DOUBLEcode: return dconst_0; default: throw new AssertionError("zero"); } } /** The opcode that loads a one constant of a given type code. * @param tc The given type code (@see ByteCode). */ public static int one(int tc) { return zero(tc) + 1; } /** Generate code to load -1 of the given type code (either int or long). * @param tc The given type code (@see ByteCode). */ void emitMinusOne(int tc) { if (tc == LONGcode) { items.makeImmediateItem(syms.longType, new Long(-1)).load(); } else { code.emitop0(iconst_m1); } } /** Construct a symbol to reflect the qualifying type that should * appear in the byte code as per JLS 13.1. * * For target >= 1.2: Clone a method with the qualifier as owner (except * for those cases where we need to work around VM bugs). * * For target <= 1.1: If qualified variable or method is defined in a * non-accessible class, clone it with the qualifier class as owner. * * @param sym The accessed symbol * @param site The qualifier's type. */ Symbol binaryQualifier(Symbol sym, Type site) { if (site.tag == ARRAY) { if (sym == syms.lengthVar || sym.owner != syms.arrayClass) return sym; // array clone can be qualified by the array type in later targets Symbol qualifier = target.arrayBinaryCompatibility() ? new ClassSymbol(Flags.PUBLIC, site.tsym.name, site, syms.noSymbol) : syms.objectType.tsym; return sym.clone(qualifier); } if (sym.owner == site.tsym || (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) { return sym; } if (!target.obeyBinaryCompatibility()) return rs.isAccessible(attrEnv, (TypeSymbol)sym.owner) ? sym : sym.clone(site.tsym); if (!target.interfaceFieldsBinaryCompatibility()) { if ((sym.owner.flags() & INTERFACE) != 0 && sym.kind == VAR) return sym; } // leave alone methods inherited from Object // JLS2 13.1. if (sym.owner == syms.objectType.tsym) return sym; if (!target.interfaceObjectOverridesBinaryCompatibility()) { if ((sym.owner.flags() & INTERFACE) != 0 && syms.objectType.tsym.members().lookup(sym.name).scope != null) return sym; } return sym.clone(site.tsym); } /** Insert a reference to given type in the constant pool, * checking for an array with too many dimensions; * return the reference's index. * @param type The type for which a reference is inserted. */ int makeRef(DiagnosticPosition pos, Type type) { checkDimension(pos, type); return pool.put(type.tag == CLASS ? (Object)type.tsym : (Object)type); } /** Check if the given type is an array with too many dimensions. */ private void checkDimension(DiagnosticPosition pos, Type t) { switch (t.tag) { case METHOD: checkDimension(pos, t.getReturnType()); for (List<Type> args = t.getParameterTypes(); args.nonEmpty(); args = args.tail) checkDimension(pos, args.head); break; case ARRAY: if (types.dimensions(t) > ClassFile.MAX_DIMENSIONS) { log.error(pos, "limit.dimensions"); nerrs++; } break; default: break; } } /** Create a tempory variable. * @param type The variable's type. */ LocalItem makeTemp(Type type) { VarSymbol v = new VarSymbol(Flags.SYNTHETIC, names.empty, type, env.enclMethod.sym); code.newLocal(v); return items.makeLocalItem(v); } /** Generate code to call a non-private method or constructor. * @param pos Position to be used for error reporting. * @param site The type of which the method is a member. * @param name The method's name. * @param argtypes The method's argument types. * @param isStatic A flag that indicates whether we call a * static or instance method. */ void callMethod(DiagnosticPosition pos, Type site, Name name, List<Type> argtypes, boolean isStatic) { Symbol msym = rs. resolveInternalMethod(pos, attrEnv, site, name, argtypes, null); if (isStatic) items.makeStaticItem(msym).invoke(); else items.makeMemberItem(msym, name == names.init).invoke(); } /** Is the given method definition an access method * resulting from a qualified super? This is signified by an odd * access code. */ private boolean isAccessSuper(JCMethodDecl enclMethod) { return (enclMethod.mods.flags & SYNTHETIC) != 0 && isOddAccessName(enclMethod.name); } /** Does given name start with "access$" and end in an odd digit? */ private boolean isOddAccessName(Name name) { return name.startsWith(accessDollar) && (name.byteAt(name.len - 1) & 1) == 1; }/* ************************************************************************ * Non-local exits *************************************************************************/ /** Generate code to invoke the finalizer associated with given * environment. * Any calls to finalizers are appended to the environments `cont' chain. * Mark beginning of gap in catch all range for finalizer. */ void genFinalizer(Env<GenContext> env) { if (code.isAlive() && env.info.finalize != null) env.info.finalize.gen(); } /** Generate code to call all finalizers of structures aborted by * a non-local * exit. Return target environment of the non-local exit. * @param target The tree representing the structure that's aborted
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -