📄 gen.java
字号:
* should contain a proper tree to generate * CharacterRangeTable branches for them. */ public CondItem genCond(JCTree _tree, boolean markBranches) { JCTree inner_tree = TreeInfo.skipParens(_tree); if (inner_tree.getTag() == JCTree.CONDEXPR) { JCConditional tree = (JCConditional)inner_tree; CondItem cond = genCond(tree.cond, CRT_FLOW_CONTROLLER); if (cond.isTrue()) { code.resolve(cond.trueJumps); 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(JCTree tree, Type pt) { Type prevPt = this.pt; try { if (tree.type.constValue() != null) { // Short circuit any expressions which are constants 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); code.state.stacksize = 1; 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<JCExpression> trees, List<Type> pts) { for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail) { genExpr(l.head, pts.head).load(); pts = pts.tail; } // require lists be of same length assert pts.isEmpty(); }/* ************************************************************************ * Visitor methods for statements and definitions *************************************************************************/ /** Thrown when the byte code size exceeds limit. */ public static class CodeSizeOverflow extends RuntimeException { private static final long serialVersionUID = 0; public CodeSizeOverflow() {} } public void visitMethodDef(JCMethodDecl tree) { // Create a new local environment that points pack at method // definition. Env<GenContext> localEnv = env.dup(tree); localEnv.enclMethod = tree; // The expected type of every return statement in this method // is the method's return type. this.pt = tree.sym.erasure(types).getReturnType(); checkDimension(tree.pos(), tree.sym.erasure(types)); genMethod(tree, localEnv, false); }//where /** 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(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) { MethodSymbol meth = tree.sym;// System.err.println("Generating " + meth + " in " + meth.owner); //DEBUG if (Code.width(types.erasure(env.enclMethod.sym.type).getParameterTypes()) + (((tree.mods.flags & STATIC) == 0 || meth.isConstructor()) ? 1 : 0) > ClassFile.MAX_PARAMETERS) { log.error(tree.pos(), "limit.parameters"); nerrs++; } else if (tree.body != null) { // Create a new code structure and initialize it. int startpcCrt = initCode(tree, env, fatcode); try { genStat(tree.body, env); } catch (CodeSizeOverflow e) { // Failed due to code limit, try again with jsr/ret startpcCrt = initCode(tree, env, fatcode); genStat(tree.body, env); } if (code.state.stacksize != 0) { log.error(tree.body.pos(), "stack.sim.error", tree); throw new AssertionError(); } // If last statement could complete normally, insert a // return at the end. if (code.isAlive()) { code.statBegin(TreeInfo.endPos(tree.body)); if (env.enclMethod == null || env.enclMethod.sym.type.getReturnType().tag == VOID) { code.emitop0(return_); } else { // sometime dead code seems alive (4415991); // generate a small loop instead 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()); // End the scope of all local variables in variable info. code.endScopes(0); // If we exceeded limits, panic if (code.checkLimits(tree.pos(), log)) { nerrs++; return; } // If we generated short code but got a long jump, do it again // with fatCode = true. if (!fatcode && code.fatcode) genMethod(tree, env, true); // Clean up if(stackMap == StackMapFormat.JSR202) { code.lastFrame = null; code.frameBeforeLast = null; } } } private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) { MethodSymbol meth = tree.sym; // Create a new code structure. meth.code = code = new Code(meth, fatcode, lineDebugInfo ? toplevel.lineMap : null, varDebugInfo, stackMap, debugCode, genCrt ? new CRTable(tree, env.toplevel.endPositions) : null, syms, types, pool); items = new Items(pool, code, syms, types); if (code.debugCode) System.err.println(meth + " for body " + tree); // If method is not static, create a new local variable address // for `this'. if ((tree.mods.flags & STATIC) == 0) { Type selfType = meth.owner.type; if (meth.isConstructor() && selfType != syms.objectType) selfType = UninitializedType.uninitializedThis(selfType); code.setDefined( code.newLocal( new VarSymbol(FINAL, names._this, selfType, meth.owner))); } // Mark all parameters as defined from the beginning of // the method. for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { checkDimension(l.head.pos(), l.head.sym.type); code.setDefined(code.newLocal(l.head.sym)); } // Get ready to generate code for method body. int startpcCrt = genCrt ? code.curPc() : 0; code.entryPoint(); // Suppress initial stackmap code.pendingStackMap = false; return startpcCrt; } public void visitVarDef(JCVariableDecl tree) { VarSymbol v = tree.sym; code.newLocal(v); if (tree.init != null) { checkStringConstant(tree.init.pos(), v.getConstValue()); if (v.getConstValue() == null || varDebugInfo) { genExpr(tree.init, v.erasure(types)).load(); items.makeLocalItem(v).store(); } } checkDimension(tree.pos(), v.type); } public void visitSkip(JCSkip tree) { } public void visitBlock(JCBlock tree) { int limit = code.nextreg; Env<GenContext> localEnv = env.dup(tree, new GenContext()); genStats(tree.stats, localEnv); // End the scope of all block-local variables in variable info. if (env.tree.getTag() != JCTree.METHODDEF) { code.statBegin(tree.endpos); code.endScopes(limit); code.pendingStatPos = Position.NOPOS; } } public void visitDoLoop(JCDoWhileLoop tree) { genLoop(tree, tree.body, tree.cond, List.<JCExpressionStatement>nil(), false); } public void visitWhileLoop(JCWhileLoop tree) { genLoop(tree, tree.body, tree.cond, List.<JCExpressionStatement>nil(), true); } public void visitForLoop(JCForLoop tree) { int limit = code.nextreg; genStats(tree.init, env); genLoop(tree, tree.body, tree.cond, tree.step, true); code.endScopes(limit); } //where /** 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(JCStatement loop, JCStatement body, JCExpression cond, List<JCExpressionStatement> step, boolean testFirst) { Env<GenContext> 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(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(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(loopEnv.info.exit); } public void visitForeachLoop(JCEnhancedForLoop tree) { throw new AssertionError(); // should have been removed by Lower. } public void visitLabelled(JCLabeledStatement tree) { Env<GenContext> localEnv = env.dup(tree, new GenContext()); genStat(tree.body, localEnv, CRT_STATEMENT); code.resolve(localEnv.info.exit); } public void visitSwitch(JCSwitch tree) { int limit = code.nextreg; assert tree.selector.type.tag != CLASS; int startpcCrt = genCrt ? code.curPc() : 0; Item sel = genExpr(tree.selector, syms.intType); List<JCCase> cases = tree.cases; if (cases.isEmpty()) { // We are seeing: switch <sel> {} sel.load().drop(); if (genCrt) code.crt.put(TreeInfo.skipParens(tree.selector), CRT_FLOW_CONTROLLER, startpcCrt, code.curPc()); } else { // We are seeing a nonempty switch. sel.load(); if (genCrt) code.crt.put(TreeInfo.skipParens(tree.selector), CRT_FLOW_CONTROLLER, startpcCrt, code.curPc()); Env<GenContext> switchEnv = env.dup(tree, new GenContext()); switchEnv.info.isSwitch = true; // Compute number of labels and minimum and maximum label values. // For each case, store its label in an array. int lo = Integer.MAX_VALUE; // minimum label. int hi = Integer.MIN_VALUE; // maximum label. int nlabels = 0; // number of labels. int[] labels = new int[cases.length()]; // the label array. int defaultIndex = -1; // the index of the default clause. List<JCCase> l = cases; for (int i = 0; i < labels.length; i++) { if (l.head.pat != null) { int val = ((Number)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; } // Determine whether to issue a tableswitch or a lookupswitch // instruction. long table_space_cost = 4 + ((long) hi - lo + 1); // words long table_time_cost = 3; // comparisons 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -