📄 gen.java
字号:
* @param to the least deeply nested environment to mark
*/
void endFinalizerGaps(Env from, Env to) {
Env last = null;
while (last != to) {
endFinalizerGap(from);
last = from;
from = from.next;
}
}
/**
* Do any of the structures aborted by a non-local exit have
* finalizers that require an empty stack?
* @param target The tree representing the structure that's aborted
* @param env The environment current at the non-local exit.
*/
boolean hasFinally(Tree target, Env env) {
while (env.tree != target) {
if (env.tree.tag == Tree.TRY &&
((Gen.GenContext) env.info).finalize.hasFinalizer())
return true;
env = env.next;
}
return false;
}
/**
* Distribute member initializer code into constructors and <clinit>
* method.
* @param defs The list of class member declarations.
* @param c The enclosing class.
*/
List normalizeDefs(List defs, ClassSymbol c) {
ListBuffer initCode = new ListBuffer();
ListBuffer clinitCode = new ListBuffer();
ListBuffer methodDefs = new ListBuffer();
for (List l = defs; l.nonEmpty(); l = l.tail) {
Tree def = (Tree) l.head;
switch (def.tag) {
case Tree.BLOCK:
Block block = (Block) def;
if ((block.flags & STATIC) != 0)
clinitCode.append(def);
else
initCode.append(def);
break;
case Tree.METHODDEF:
methodDefs.append(def);
break;
case Tree.VARDEF:
VarDef vdef = (VarDef) def;
VarSymbol sym = vdef.sym;
checkDimension(vdef.pos, sym.type);
if (vdef.init != null) {
if ((sym.flags() & STATIC) == 0) {
Tree init = make.at(vdef.pos).Assignment(sym, vdef.init);
initCode.append(init);
if (endPositions != null) {
Integer endPos = (Integer) endPositions.remove(vdef);
if (endPos != null)
endPositions.put(init, endPos);
}
} else if (sym.constValue == null) {
Tree init = make.at(vdef.pos).Assignment(sym, vdef.init);
clinitCode.append(init);
if (endPositions != null) {
Integer endPos = (Integer) endPositions.remove(vdef);
if (endPos != null)
endPositions.put(init, endPos);
}
} else {
checkStringConstant(vdef.init.pos, sym.constValue);
}
}
break;
default:
assert false;
}
}
if (initCode.length() != 0) {
List inits = initCode.toList();
for (Enumeration e = methodDefs.elements(); e.hasMoreElements();) {
normalizeMethod((MethodDef) e.nextElement(), inits);
}
}
if (clinitCode.length() != 0) {
MethodSymbol clinit = new MethodSymbol(STATIC, names.clinit,
new MethodType(Type.emptyList, syms.voidType,
Type.emptyList, syms.methodClass), c);
c.members().enter(clinit);
List clinitStats = clinitCode.toList();
Block block =
make.at(((Tree) clinitStats.head).pos).Block(0, clinitStats);
block.endpos = TreeInfo.endPos((Tree) clinitStats.last());
methodDefs.append(make.MethodDef(clinit, block));
}
return methodDefs.toList();
}
/**
* Check a constant value and report if it is a string that is
* too large.
*/
private void checkStringConstant(int pos, Object constValue) {
if (nerrs != 0 || constValue == null || !(constValue instanceof String) ||
((String) constValue).length() < Pool.MAX_STRING_LENGTH)
return;
log.error(pos, "limit.string");
nerrs++;
}
/**
* Insert instance initializer code into initial constructor.
* @param md The tree potentially representing a
* constructor's definition.
* @param initCode The list of instance initializer statements.
*/
void normalizeMethod(MethodDef md, List initCode) {
if (md.name == names.init && TreeInfo.isInitialConstructor(md)) {
List stats = md.body.stats;
ListBuffer newstats = new ListBuffer();
if (stats.nonEmpty()) {
while (TreeInfo.isSyntheticInit((Tree) stats.head)) {
newstats.append(stats.head);
stats = stats.tail;
}
newstats.append(stats.head);
stats = stats.tail;
while (stats.nonEmpty() &&
TreeInfo.isSyntheticInit((Tree) stats.head)) {
newstats.append(stats.head);
stats = stats.tail;
}
newstats.appendList(initCode);
while (stats.nonEmpty()) {
newstats.append(stats.head);
stats = stats.tail;
}
}
md.body.stats = newstats.toList();
if (md.body.endpos == Position.NOPOS)
md.body.endpos = TreeInfo.endPos((Tree) md.body.stats.last());
}
}
/**
* Add abstract methods for all methods defined in one of
* the interfaces of a given class,
* provided they are not already implemented in the class.
*
* @param c The class whose interfaces are searched for methods
* for which Miranda methods should be added.
*/
void implementInterfaceMethods(ClassSymbol c) {
implementInterfaceMethods(c, c);
}
/**
* Add abstract methods for all methods defined in one of
* the interfaces of a given class,
* provided they are not already implemented in the class.
*
* @param c The class whose interfaces are searched for methods
* for which Miranda methods should be added.
* @param site The class in which a definition may be needed.
*/
void implementInterfaceMethods(ClassSymbol c, ClassSymbol site) {
for (List l = c.type.interfaces(); l.nonEmpty(); l = l.tail) {
ClassSymbol i = (ClassSymbol)((Type) l.head).tsym;
for (Scope.Entry e = i.members().elems; e != null; e = e.sibling) {
if (e.sym.kind == MTH && (e.sym.flags() & STATIC) == 0) {
MethodSymbol absMeth = (MethodSymbol) e.sym;
MethodSymbol implMeth = absMeth.binaryImplementation(site);
if (implMeth == null)
addAbstractMethod(site, absMeth);
else if ((implMeth.flags() & IPROXY) != 0)
adjustAbstractMethod(site, implMeth, absMeth);
}
}
implementInterfaceMethods(i, site);
}
}
/**
* Add an abstract methods to a class
* which implicitly implements a method defined in some interface
* implemented by the class. These methods are called "Miranda methods".
* Enter the newly created method into its enclosing class scope.
* Note that it is not entered into the class tree, as the emitter
* doesn't need to see it there to emit an abstract method.
*
* @param c The class to which the Miranda method is added.
* @param m The interface method symbol for which a Miranda method
* is added.
*/
private void addAbstractMethod(ClassSymbol c, MethodSymbol m) {
MethodSymbol absMeth =
new MethodSymbol(m.flags() | IPROXY | SYNTHETIC, m.name, m.type, c);
c.members().enter(absMeth);
}
private void adjustAbstractMethod(ClassSymbol c, MethodSymbol pm,
MethodSymbol im) {
MethodType pmt = (MethodType) pm.type;
Type imt = c.type.memberType(im);
pmt.thrown = Check.intersect(pmt.thrown(), imt.thrown());
}
/**
* Visitor argument: The current environment.
*/
Env env;
/**
* Visitor argument: The expected type (prototype).
*/
Type pt;
/**
* Visitor result: The item representing the computed value.
*/
Item result;
/**
* Visitor method: generate code for a definition, catching and reporting
* any completion failures.
* @param tree The definition to be visited.
* @param env The environment current at the definition.
*/
public void genDef(Tree tree, Env env) {
Env prevEnv = this.env;
try {
this.env = env;
tree.accept(this);
} catch (CompletionFailure ex) {
chk.completionError(tree.pos, ex);
}
finally { this.env = prevEnv;
} }
/**
* Derived visitor method: check whether CharacterRangeTable
* should be emitted, if so, put a new entry into CRTable
* and call method to generate bytecode.
* If not, just call method to generate bytecode.
* @see #genStat(Tree, Env<GenContext>)
*
* @param tree The tree to be visited.
* @param env The environment to use.
* @param crtFlags The CharacterRangeTable flags
* indicating type of the entry.
*/
public void genStat(Tree tree, Env env, int crtFlags) {
if (!genCrt) {
genStat(tree, env);
return;
}
int startpc = code.curPc();
genStat(tree, env);
if (tree.tag == Tree.BLOCK)
crtFlags |= CRT_BLOCK;
code.crt.put(tree, crtFlags, startpc, code.curPc());
}
/**
* Derived visitor method: generate code for a statement.
*/
public void genStat(Tree tree, Env env) {
if (code.isAlive()) {
code.statBegin(tree.pos);
genDef(tree, env);
} else if (((Gen.GenContext) env.info).isSwitch && tree.tag == Tree.VARDEF) {
code.newLocal(((VarDef) tree).sym);
}
}
/**
* Derived visitor method: check whether CharacterRangeTable
* should be emitted, if so, put a new entry into CRTable
* and call method to generate bytecode.
* If not, just call method to generate bytecode.
* @see #genStats(List<Trees>, Env<GenContext>)
*
* @param trees The list of trees to be visited.
* @param env The environment to use.
* @param crtFlags The CharacterRangeTable flags
* indicating type of the entry.
*/
public void genStats(List trees, Env env, int crtFlags) {
if (!genCrt) {
genStats(trees, env);
return;
}
if (trees.length() == 1) {
genStat((Tree) trees.head, env, crtFlags | CRT_STATEMENT);
} else {
int startpc = code.curPc();
genStats(trees, env);
code.crt.put(trees, crtFlags, startpc, code.curPc());
}
}
/**
* Derived visitor method: generate code for a list of statements.
*/
public void genStats(List trees, Env env) {
for (List l = trees; l.nonEmpty(); l = l.tail)
genStat((Tree) l.head, env, CRT_STATEMENT);
}
/**
* Derived visitor method: check whether CharacterRangeTable
* should be emitted, if so, put a new entry into CRTable
* and call method to generate bytecode.
* If not, just call method to generate bytecode.
* @see #genCond(Tree)
*
* @param tree The tree to be visited.
* @param crtFlags The CharacterRangeTable flags
* indicating type of the entry.
*/
public CondItem genCond(Tree tree, int crtFlags) {
if (!genCrt)
return genCond(tree, false);
int startpc = code.curPc();
CondItem item = genCond(tree, (crtFlags & CRT_FLOW_CONTROLLER) != 0);
code.crt.put(tree, crtFlags, startpc, code.curPc());
return item;
}
/**
* Derived visitor method: generate code for a boolean
* expression in a control-flow context.
* @param tree The expression to be visited.
* @param markBranches The flag to indicate that the condition is
* a flow controller so produced conditions
* should contain a proper tree to generate
* CharacterRangeTable branches for them.
*/
public CondItem genCond(Tree _tree, boolean markBranches) {
Tree inner_tree = TreeInfo.skipParens(_tree);
if (inner_tree.tag == Tree.CONDEXPR) {
Conditional tree = (Conditional) inner_tree;
CondItem cond = genCond(tree.cond, CRT_FLOW_CONTROLLER);
if (cond.isTrue()) {
code.resolve(cond.trueJumps);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -