📄 gen.java
字号:
int startpc = code.curPc(); // the position of the selector operation code.emitop0(opcode); code.align(4); int tableBase = code.curPc(); // the start of the jump table int[] offsets = null; // a table of offsets for a lookupswitch code.emit4(-1); // leave space for default offset if (opcode == tableswitch) { code.emit4(lo); // minimum label code.emit4(hi); // maximum label for (long i = lo; i <= hi; i++) { // leave space for jump table code.emit4(-1); } } else { code.emit4(nlabels); // number of labels for (int i = 0; i < nlabels; i++) { code.emit4(-1); code.emit4(-1); // leave space for lookup table } offsets = new int[labels.length]; } Code.State stateSwitch = code.state.dup(); code.markDead(); // For each case do: l = cases; for (int i = 0; i < labels.length; i++) { JCCase c = l.head; l = l.tail; int pc = code.entryPoint(stateSwitch); // Insert offset directly into code or else into the // offsets table. 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); } // Generate code for the statements in this case. genStats(c.stats, switchEnv, CRT_FLOW_TARGET); } // Resolve all breaks. code.resolve(switchEnv.info.exit); // If we have not set the default offset, we do so now. if (code.get4(tableBase) == -1) { code.put4(tableBase, code.entryPoint(stateSwitch) - startpc); } if (opcode == tableswitch) { // Let any unfilled slots point to the default case. 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 { // Sort non-default offsets and copy into lookup table. 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); }//where /** 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]; do { while (keys[i] < pivot) i++; while (pivot < keys[j]) j--; if (i <= j) { int temp1 = keys[i]; keys[i] = keys[j]; keys[j] = temp1; int temp2 = values[i]; values[i] = values[j]; values[j] = temp2; i++; j--; } } while (i <= j); if (lo < j) qsort2(keys, values, lo, j); if (i < hi) qsort2(keys, values, i, hi); } public void visitSynchronized(JCSynchronized tree) { int limit = code.nextreg; // Generate code to evaluate lock and save in temporary variable. final LocalItem lockVar = makeTemp(syms.objectType); genExpr(tree.lock, tree.lock.type).load().duplicate(); lockVar.store(); // Generate code to enter monitor. code.emitop0(monitorenter); code.state.lock(lockVar.reg); // Generate code for a try statement with given body, no catch clauses // in a new environment with the "exit-monitor" operation as finalizer. final Env<GenContext> syncEnv = env.dup(tree, new GenContext()); syncEnv.info.finalize = new GenFinalizer() { void gen() { genLast(); assert syncEnv.info.gaps.length() % 2 == 0; syncEnv.info.gaps.append(code.curPc()); } void genLast() { if (code.isAlive()) { lockVar.load(); code.emitop0(monitorexit); code.state.unlock(lockVar.reg); } } }; syncEnv.info.gaps = new ListBuffer<Integer>(); genTry(tree.body, List.<JCCatch>nil(), syncEnv); code.endScopes(limit); } public void visitTry(final JCTry tree) { // Generate code for a try statement with given body and catch clauses, // in a new environment which calls the finally block if there is one. final Env<GenContext> tryEnv = env.dup(tree, new GenContext()); final Env<GenContext> oldEnv = env; if (!useJsrLocally) { useJsrLocally = (stackMap == StackMapFormat.NONE) && (jsrlimit <= 0 || jsrlimit < 100 && estimateCodeComplexity(tree.finalizer)>jsrlimit); } tryEnv.info.finalize = new GenFinalizer() { void gen() { if (useJsrLocally) { if (tree.finalizer != null) { Code.State jsrState = code.state.dup(); jsrState.push(code.jsrReturnValue); tryEnv.info.cont = new Chain(code.emitJump(jsr), tryEnv.info.cont, jsrState); } assert tryEnv.info.gaps.length() % 2 == 0; tryEnv.info.gaps.append(code.curPc()); } else { assert tryEnv.info.gaps.length() % 2 == 0; tryEnv.info.gaps.append(code.curPc()); genLast(); } } void genLast() { if (tree.finalizer != null) genStat(tree.finalizer, oldEnv, CRT_BLOCK); } boolean hasFinalizer() { return tree.finalizer != null; } }; tryEnv.info.gaps = new ListBuffer<Integer>(); genTry(tree.body, tree.catchers, tryEnv); } //where /** Generate code for a try or synchronized statement * @param body The body of the try or synchronized statement. * @param catchers The lis of catch clauses. * @param env the environment current for the body. */ void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) { int limit = code.nextreg; int startpc = code.curPc(); Code.State stateTry = code.state.dup(); genStat(body, env, CRT_BLOCK); int endpc = code.curPc(); boolean hasFinalizer = env.info.finalize != null && env.info.finalize.hasFinalizer(); List<Integer> gaps = env.info.gaps.toList(); code.statBegin(TreeInfo.endPos(body)); genFinalizer(env); code.statBegin(TreeInfo.endPos(env.tree)); Chain exitChain = code.branch(goto_); endFinalizerGap(env); if (startpc != endpc) for (List<JCCatch> l = catchers; l.nonEmpty(); l = l.tail) { // start off with exception on stack code.entryPoint(stateTry, l.head.param.sym.type); genCatch(l.head, env, startpc, endpc, gaps); genFinalizer(env); if (hasFinalizer || l.tail.nonEmpty()) { code.statBegin(TreeInfo.endPos(env.tree)); exitChain = code.mergeChains(exitChain, code.branch(goto_)); } endFinalizerGap(env); } if (hasFinalizer) { // Create a new register segement to avoid allocating // the same variables in finalizers and other statements. code.newRegSegment(); // Add a catch-all clause. // start off with exception on stack int catchallpc = code.entryPoint(stateTry, syms.throwableType); // Register all exception ranges for catch all clause. // The range of the catch all clause is from the beginning // of the try or synchronized block until the present // code pointer excluding all gaps in the current // environment's GenContext. int startseg = startpc; while (env.info.gaps.nonEmpty()) { int endseg = env.info.gaps.next().intValue(); registerCatch(body.pos(), startseg, endseg, catchallpc, 0); startseg = env.info.gaps.next().intValue(); } code.statBegin(TreeInfo.finalizerPos(env.tree)); code.markStatBegin(); Item excVar = makeTemp(syms.throwableType); excVar.store(); genFinalizer(env); excVar.load(); registerCatch(body.pos(), startseg, env.info.gaps.next().intValue(), catchallpc, 0); code.emitop0(athrow); code.markDead(); // If there are jsr's to this finalizer, ... if (env.info.cont != null) { // Resolve all jsr's. code.resolve(env.info.cont); // Mark statement line number code.statBegin(TreeInfo.finalizerPos(env.tree)); code.markStatBegin(); // Save return address. LocalItem retVar = makeTemp(syms.throwableType); retVar.store(); // Generate finalizer code. env.info.finalize.genLast(); // Return. code.emitop1w(ret, retVar.reg); code.markDead(); } } // Resolve all breaks. code.resolve(exitChain); // End the scopes of all try-local variables in variable info. code.endScopes(limit); } /** Generate code for a catch clause. * @param tree The catch clause. * @param env The environment current in the enclosing try. * @param startpc Start pc of try-block. * @param endpc End pc of try-block. */ void genCatch(JCCatch tree, Env<GenContext> env, int startpc, int endpc, List<Integer> gaps) { if (startpc != endpc) { int catchType = makeRef(tree.pos(), tree.param.type); while (gaps.nonEmpty()) { int end = gaps.head.intValue(); registerCatch(tree.pos(), startpc, end, code.curPc(), catchType); gaps = gaps.tail; startpc = gaps.head.intValue(); gaps = gaps.tail; } if (startpc < endpc) registerCatch(tree.pos(), startpc, endpc, code.curPc(), catchType); VarSymbol exparam = tree.param.sym; code.statBegin(tree.pos); code.markStatBegin(); int limit = code.nextreg; int exlocal = code.newLocal(exparam); items.makeLocalItem(exparam).store(); code.statBegin(TreeInfo.firstStatPos(tree.body)); genStat(tree.body, env, CRT_BLOCK); code.endScopes(limit); code.statBegin(TreeInfo.endPos(tree.body)); } } /** Register a catch clause in the "Exceptions" code-attribute. */ void registerCatch(DiagnosticPosition pos, int startpc, int endpc, int handler_pc, int catch_type) { if (startpc != endpc) { char startpc1 = (char)startpc; char endpc1 = (char)endpc; char handler_pc1 = (char)handler_pc; if (startpc1 == startpc && endpc1 == endpc && handler_pc1 == handler_pc) { code.addCatch(startpc1, endpc1, handler_pc1, (char)catch_type); } else { if (!useJsrLocally && !target.generateStackMapTable()) { useJsrLocally = true; throw new CodeSizeOverflow(); } else { log.error(pos, "limit.code.too.large.for.try.stmt"); nerrs++; } } } } /** Very roughly estimate the number of instructions needed for * the given tree. */ int estimateCodeComplexity(JCTree tree) { if (tree == null) return 0; class ComplexityScanner extends TreeScanner { int complexity = 0; public void scan(JCTree tree) { if (complexity > jsrlimit) return; super.scan(tree); } public void visitClassDef(JCClassDecl tree) {} public void visitDoLoop(JCDoWhileLoop tree) { super.visitDoLoop(tree); complexity++; } public void visitWhileLoop(JCWhileLoop tree) { super.visitWhileLoop(tree); complexity++; } public void visitForLoop(JCForLoop tree) { super.visitForLoop(tree); complexity++; } public void visitSwitch(JCSwitch tree) { super.visitSwitch(tree); complexity+=5; } public void visitCase(JCCase tree) { super.visitCase(tree); complexity++; } public void visitSynchronized(JCSynchronized tree) { super.visitSynchronized(tree); complexity+=6; } public void visitTry(JCTry tree) { super.visitTry(tree); if (tree.finalizer != null) complexity+=6; } public void visitCatch(JCCatch tree) { super.visitCatch(tree); complexity+=2; } public void visitConditional(JCConditional tree) { super.visitConditional(tree); complexity+=2; } public void visitIf(JCIf tree) { super.visitIf(tree); complexity+=2; } // note: for break, continue, and return we don't take unwind() into account. public void visitBreak(JCBreak tree) { super.visitBreak(tree); complexity+=1; } public void visitContinue(JCContinue tree) { super.visitContinue(tree); complexity+=1; } public void visitReturn(JCReturn tree) { super.visitReturn(tree); complexity+=1; } public void visitThrow(JCThrow tree) { super.visitThrow(tree); complexity+=1; } public void visitAssert(JCAssert tree) { super.visitAssert(tree); complexity+=5; } public void visitApply(JCMethodInvocation tree)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -