📄 gen.java
字号:
/**
* @(#)Gen.java 1.97 03/01/23
*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.sun.tools.javac.v8.comp;
import java.io.IOException;
import com.sun.tools.javac.v8.util.*;
import com.sun.tools.javac.v8.code.*;
import com.sun.tools.javac.v8.tree.*;
import com.sun.tools.javac.v8.code.Symbol.*;
import com.sun.tools.javac.v8.code.Type.*;
import com.sun.tools.javac.v8.code.Code.*;
import com.sun.tools.javac.v8.tree.Tree.*;
import com.sun.tools.javac.v8.comp.Items.*;
/**
* This pass maps flat Java (i.e. without inner classes) to bytecodes.
*/
public class Gen extends Tree.Visitor implements Flags, Kinds, TypeTags,
ByteCodes, CRTFlags {
private static final Context.Key genKey = new Context.Key();
private final Log log;
private final Symtab syms;
private final Check chk;
private final Resolve rs;
private final TreeMaker make;
private final ClassWriter writer;
private final Name.Table names;
private final Target target;
private final boolean generateIproxies;
/**
* A type that serves as the expected type for all method expressions.
*/
private final Type methodType;
public static Gen instance(Context context) {
Gen instance = (Gen) context.get(genKey);
if (instance == null)
instance = new Gen(context);
return instance;
}
private Gen(Context context) {
super();
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);
writer = ClassWriter.instance(context);
target = Target.instance(context);
methodType = new MethodType(null, null, null, syms.methodClass);
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;
generateIproxies = target.requiresIproxy() || options.get("miranda") != null;
int setjsrlimit = 10;
String jsrlimitString = (String) options.get("jsrlimit");
if (jsrlimitString != null) {
try {
setjsrlimit = Integer.parseInt(jsrlimitString);
} catch (NumberFormatException ex) {
}
}
this.jsrlimit = setjsrlimit;
}
/**
* Switches
*/
private final boolean lineDebugInfo;
private final boolean varDebugInfo;
private final boolean genCrt;
/**
* 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;
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 attrEnv;
/**
* The top level tree.
*/
private TopLevel 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 Hashtable endPositions;
/**
* Generate code to load an integer constant.
* @param n The integer to be loaded.
*/
void loadIntConst(int n) {
items.makeImmediateItem(syms.intType, new Integer(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.emitop(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;
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;
}
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(int 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(int pos, Type t) {
switch (t.tag) {
case METHOD:
checkDimension(pos, t.restype());
for (List args = t.argtypes(); args.nonEmpty(); args = args.tail)
checkDimension(pos, (Type) args.head);
break;
case ARRAY:
if (t.dimensions() > 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) {
return (LocalItem) items.makeLocalItem(type, code.newLocal(type));
}
/**
* 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(int pos, Type site, Name name, List argtypes, boolean isStatic) {
Symbol msym = rs.resolveInternalMethod(pos, attrEnv, site, name, argtypes);
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(MethodDef enclMethod) {
return (enclMethod.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(names.accessDollar) &&
(name.byteAt(name.len - 1) & 1) == 1;
}
/**
* 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 env) {
if (code.isAlive() && ((Gen.GenContext) env.info).finalize != null)
((Gen.GenContext) 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
* @param env The environment current at the non-local exit.
*/
Env unwind(Tree target, Env env) {
Env env1 = env;
while (true) {
genFinalizer(env1);
if (env1.tree == target)
break;
env1 = env1.next;
}
return env1;
}
/**
* Mark end of gap in catch-all range for finalizer.
* @param env the environment which might contain the finalizer
* (if it does, env.info.gaps != null).
*/
void endFinalizerGap(Env env) {
if (((Gen.GenContext) env.info).gaps != null &&
((Gen.GenContext) env.info).gaps.length() % 2 == 1)
((Gen.GenContext) env.info).gaps.append(new Integer(code.curPc()));
}
/**
* Mark end of all gaps in catch-all ranges for finalizers of environments
* lying between, and including to two environments.
* @param from the most deeply nested environment to mark
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -