📄 gen.java
字号:
CondItem result = genCond(tree.truepart, CRT_FLOW_TARGET);
if (markBranches)
result.tree = tree.truepart;
return result;
}
if (cond.isFalse()) {
code.resolve(cond.falseJumps);
CondItem result = genCond(tree.falsepart, CRT_FLOW_TARGET);
if (markBranches)
result.tree = tree.falsepart;
return result;
}
Chain secondJumps = cond.jumpFalse();
code.resolve(cond.trueJumps);
CondItem first = genCond(tree.truepart, CRT_FLOW_TARGET);
if (markBranches)
first.tree = tree.truepart;
Chain falseJumps = first.jumpFalse();
code.resolve(first.trueJumps);
Chain trueJumps = code.branch(goto_);
code.resolve(secondJumps);
CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET);
CondItem result = items.makeCondItem(second.opcode,
code.mergeChains(trueJumps, second.trueJumps),
code.mergeChains(falseJumps, second.falseJumps));
if (markBranches)
result.tree = tree.falsepart;
return result;
} else {
CondItem result = genExpr(_tree, syms.booleanType).mkCond();
if (markBranches)
result.tree = _tree;
return result;
}
}
/**
* Visitor method: generate code for an expression, catching and reporting
* any completion failures.
* @param tree The expression to be visited.
* @param pt The expression's expected type (proto-type).
*/
public Item genExpr(Tree tree, Type pt) {
Type prevPt = this.pt;
try {
if (tree.type.constValue != null) {
checkStringConstant(tree.pos, tree.type.constValue);
result = items.makeImmediateItem(tree.type, tree.type.constValue);
} else {
this.pt = pt;
tree.accept(this);
}
return result.coerce(pt);
} catch (CompletionFailure ex) {
chk.completionError(tree.pos, ex);
return items.makeStackItem(pt);
}
finally { this.pt = prevPt;
} }
/**
* Derived visitor method: generate code for a list of method arguments.
* @param trees The argument expressions to be visited.
* @param pts The expression's expected types (i.e. the formal parameter
* types of the invoked method).
*/
public void genArgs(List trees, List pts) {
for (List l = trees; l.nonEmpty(); l = l.tail) {
genExpr((Tree) l.head, (Type) pts.head).load();
pts = pts.tail;
}
assert pts.isEmpty();
}
public void visitMethodDef(MethodDef tree) {
Env localEnv = env.dup(tree);
localEnv.enclMethod = tree;
this.pt = tree.sym.erasure().restype();
checkDimension(tree.pos, tree.sym.erasure());
genMethod(tree, localEnv, false);
}
/**
* Generate code for a method.
* @param tree The tree representing the method definition.
* @param env The environment current for the method body.
* @param fatcode A flag that indicates whether all jumps are within 32K.
* We first invoke this method under the assumption
* that fatcode == false, i.e. all jumps are within 32K.
* If this fails, fatcode is set to true and we try again.
*/
void genMethod(MethodDef tree, Env env, boolean fatcode) {
MethodSymbol meth = tree.sym;
if (Code.width(env.enclMethod.sym.type.erasure().argtypes()) +
(((tree.flags & STATIC) == 0 || meth.isConstructor()) ? 1 : 0) >
ClassFile.MAX_PARAMETERS) {
log.error(tree.pos, "limit.parameters");
nerrs++;
} else if (tree.body != null) {
meth.code = code = new Code(fatcode, lineDebugInfo, varDebugInfo,
genCrt ? new CRTable(tree, env.toplevel.endPositions) : null);
items = new Items(pool, code, syms);
if (Code.debugCode)
System.err.println(meth);
if ((tree.flags & STATIC) == 0)
code.setDefined( code.newLocal(
new VarSymbol(FINAL, names._this, meth.owner.type,
meth.owner)));
for (List l = tree.params; l.nonEmpty(); l = l.tail) {
checkDimension(((Tree.VarDef) l.head).pos,
((Tree.VarDef) l.head).sym.type);
code.setDefined(code.newLocal(((Tree.VarDef) l.head).sym));
}
int startpcCrt = genCrt ? code.curPc() : 0;
genStat(tree.body, env);
assert code.stacksize == 0;
if (code.isAlive()) {
code.statBegin(TreeInfo.endPos(tree.body));
if (env.enclMethod == null ||
env.enclMethod.sym.type.restype().tag == VOID) {
code.emitop(return_);
} else {
int startpc = code.entryPoint();
CondItem c = items.makeCondItem(goto_);
code.resolve(c.jumpTrue(), startpc);
}
}
if (genCrt) {
code.crt.put(tree.body, CRT_BLOCK, startpcCrt, code.curPc());
}
code.endScopes(0);
if (code.checkLimits(tree.pos, log)) {
nerrs++;
return;
}
if (!fatcode && code.fatcode)
genMethod(tree, env, true);
}
}
public void visitVarDef(VarDef tree) {
VarSymbol v = tree.sym;
code.newLocal(v);
if (tree.init != null) {
checkStringConstant(tree.init.pos, v.constValue);
if (v.constValue == null || varDebugInfo) {
genExpr(tree.init, v.erasure()).load();
items.makeLocalItem(v).store();
}
}
checkDimension(tree.pos, v.type);
}
public void visitSkip(Skip tree) {
}
public void visitBlock(Block tree) {
int limit = code.nextreg;
Env localEnv = env.dup(tree, new GenContext());
genStats(tree.stats, localEnv);
if (env.tree.tag != Tree.METHODDEF)
code.endScopes(limit);
}
public void visitDoLoop(DoLoop tree) {
genLoop(tree, tree.body, tree.cond, Tree.emptyList, false);
}
public void visitWhileLoop(WhileLoop tree) {
genLoop(tree, tree.body, tree.cond, Tree.emptyList, true);
}
public void visitForLoop(ForLoop tree) {
int limit = code.nextreg;
genStats(tree.init, env);
genLoop(tree, tree.body, tree.cond, tree.step, true);
code.endScopes(limit);
}
/**
* Generate code for a loop.
* @param loop The tree representing the loop.
* @param body The loop's body.
* @param cond The loop's controling condition.
* @param step "Step" statements to be inserted at end of
* each iteration.
* @param testFirst True if the loop test belongs before the body.
*/
private void genLoop(Tree loop, Tree body, Tree cond, List step,
boolean testFirst) {
Env loopEnv = env.dup(loop, new GenContext());
int startpc = code.entryPoint();
if (testFirst) {
CondItem c;
if (cond != null) {
code.statBegin(cond.pos);
c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
} else {
c = items.makeCondItem(goto_);
}
Chain loopDone = c.jumpFalse();
code.resolve(c.trueJumps);
genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
code.resolve(((Gen.GenContext) loopEnv.info).cont);
genStats(step, loopEnv);
code.resolve(code.branch(goto_), startpc);
code.resolve(loopDone);
} else {
genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
code.resolve(((Gen.GenContext) loopEnv.info).cont);
genStats(step, loopEnv);
CondItem c;
if (cond != null) {
code.statBegin(cond.pos);
c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
} else {
c = items.makeCondItem(goto_);
}
code.resolve(c.jumpTrue(), startpc);
code.resolve(c.falseJumps);
}
code.resolve(((Gen.GenContext) loopEnv.info).exit);
}
public void visitLabelled(Labelled tree) {
Env localEnv = env.dup(tree, new GenContext());
genStat(tree.body, localEnv, CRT_STATEMENT);
code.resolve(((Gen.GenContext) localEnv.info).exit);
}
public void visitSwitch(Switch tree) {
int limit = code.nextreg;
int startpcCrt = genCrt ? code.curPc() : 0;
Item sel = genExpr(tree.selector, syms.intType);
Bits definedSwitch = varDebugInfo ? code.defined.dup() : null;
List cases = tree.cases;
if (cases.isEmpty()) {
sel.load().drop();
if (genCrt)
code.crt.put(TreeInfo.skipParens(tree.selector),
CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
} else {
sel.load();
if (genCrt)
code.crt.put(TreeInfo.skipParens(tree.selector),
CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
Env switchEnv = env.dup(tree, new GenContext());
((Gen.GenContext) switchEnv.info).isSwitch = true;
int lo = Integer.MAX_VALUE;
int hi = Integer.MIN_VALUE;
int nlabels = 0;
int[] labels = new int[cases.length()];
int defaultIndex = -1;
List l = cases;
for (int i = 0; i < labels.length; i++) {
if (((Tree.Case) l.head).pat != null) {
int val = ((Number)((Tree.Case) l.head).pat.type.constValue).
intValue();
labels[i] = val;
if (val < lo)
lo = val;
if (hi < val)
hi = val;
nlabels++;
} else {
assert defaultIndex == -1;
defaultIndex = i;
}
l = l.tail;
}
long table_space_cost = 4 + ((long) hi - lo + 1);
long table_time_cost = 3;
long lookup_space_cost = 3 + 2 * (long) nlabels;
long lookup_time_cost = nlabels;
int opcode = nlabels > 0 && table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost ? tableswitch :
lookupswitch;
int startpc = code.curPc();
code.emitop(opcode);
code.align(4);
int tableBase = code.curPc();
int[] offsets = null;
code.emit4(-1);
if (opcode == tableswitch) {
code.emit4(lo);
code.emit4(hi);
for (long i = lo; i <= hi; i++) {
code.emit4(-1);
}
} else {
code.emit4(nlabels);
for (int i = 0; i < nlabels; i++) {
code.emit4(-1);
code.emit4(-1);
}
offsets = new int[labels.length];
}
code.markDead();
l = cases;
for (int i = 0; i < labels.length; i++) {
Case c = (Tree.Case) l.head;
l = l.tail;
int pc = code.entryPoint();
if (i != defaultIndex) {
if (opcode == tableswitch) {
code.put4(tableBase + 4 * (labels[i] - lo + 3), pc - startpc);
} else {
offsets[i] = pc - startpc;
}
} else {
code.put4(tableBase, pc - startpc);
}
code.setDefined(definedSwitch);
genStats(c.stats, switchEnv, CRT_FLOW_TARGET);
}
code.resolve(((Gen.GenContext) switchEnv.info).exit);
if (code.get4(tableBase) == -1) {
code.put4(tableBase, code.entryPoint() - startpc);
}
if (opcode == tableswitch) {
int defaultOffset = code.get4(tableBase);
for (long i = lo; i <= hi; i++) {
int t = (int)(tableBase + 4 * (i - lo + 3));
if (code.get4(t) == -1)
code.put4(t, defaultOffset);
}
} else {
if (defaultIndex >= 0)
for (int i = defaultIndex; i < labels.length - 1; i++) {
labels[i] = labels[i + 1];
offsets[i] = offsets[i + 1];
}
if (nlabels > 0)
qsort2(labels, offsets, 0, nlabels - 1);
for (int i = 0; i < nlabels; i++) {
int caseidx = tableBase + 8 * (i + 1);
code.put4(caseidx, labels[i]);
code.put4(caseidx + 4, offsets[i]);
}
}
}
code.endScopes(limit);
}
/**
* Sort (int) arrays of keys and values
*/
static void qsort2(int[] keys, int[] values, int lo, int hi) {
int i = lo;
int j = hi;
int pivot = keys[(i + j) / 2];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -