📄 gen.java
字号:
* @param env The environment current at the non-local exit. */ Env<GenContext> unwind(JCTree target, Env<GenContext> env) { Env<GenContext> 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<GenContext> env) { if (env.info.gaps != null && env.info.gaps.length() % 2 == 1) env.info.gaps.append(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 * @param to the least deeply nested environment to mark */ void endFinalizerGaps(Env<GenContext> from, Env<GenContext> to) { Env<GenContext> 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(JCTree target, Env<GenContext> env) { while (env.tree != target) { if (env.tree.getTag() == JCTree.TRY && env.info.finalize.hasFinalizer()) return true; env = env.next; } return false; }/* ************************************************************************ * Normalizing class-members. *************************************************************************/ /** Distribute member initializer code into constructors and <clinit> * method. * @param defs The list of class member declarations. * @param c The enclosing class. */ List<JCTree> normalizeDefs(List<JCTree> defs, ClassSymbol c) { ListBuffer<JCStatement> initCode = new ListBuffer<JCStatement>(); ListBuffer<JCStatement> clinitCode = new ListBuffer<JCStatement>(); ListBuffer<JCTree> methodDefs = new ListBuffer<JCTree>(); // Sort definitions into three listbuffers: // - initCode for instance initializers // - clinitCode for class initializers // - methodDefs for method definitions for (List<JCTree> l = defs; l.nonEmpty(); l = l.tail) { JCTree def = l.head; switch (def.getTag()) { case JCTree.BLOCK: JCBlock block = (JCBlock)def; if ((block.flags & STATIC) != 0) clinitCode.append(block); else initCode.append(block); break; case JCTree.METHODDEF: methodDefs.append(def); break; case JCTree.VARDEF: JCVariableDecl vdef = (JCVariableDecl) def; VarSymbol sym = vdef.sym; checkDimension(vdef.pos(), sym.type); if (vdef.init != null) { if ((sym.flags() & STATIC) == 0) { // Always initialize instance variables. JCStatement init = make.at(vdef.pos()). Assignment(sym, vdef.init); initCode.append(init); if (endPositions != null) { Integer endPos = endPositions.remove(vdef); if (endPos != null) endPositions.put(init, endPos); } } else if (sym.getConstValue() == null) { // Initialize class (static) variables only if // they are not compile-time constants. JCStatement init = make.at(vdef.pos). Assignment(sym, vdef.init); clinitCode.append(init); if (endPositions != null) { Integer endPos = endPositions.remove(vdef); if (endPos != null) endPositions.put(init, endPos); } } else { checkStringConstant(vdef.init.pos(), sym.getConstValue()); } } break; default: assert false; } } // Insert any instance initializers into all constructors. if (initCode.length() != 0) { List<JCStatement> inits = initCode.toList(); for (JCTree t : methodDefs) { normalizeMethod((JCMethodDecl)t, inits); } } // If there are class initializers, create a <clinit> method // that contains them as its body. if (clinitCode.length() != 0) { MethodSymbol clinit = new MethodSymbol( STATIC, names.clinit, new MethodType( List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass), c); c.members().enter(clinit); List<JCStatement> clinitStats = clinitCode.toList(); JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats); block.endpos = TreeInfo.endPos(clinitStats.last()); methodDefs.append(make.MethodDef(clinit, block)); } // Return all method definitions. return methodDefs.toList(); } /** Check a constant value and report if it is a string that is * too large. */ private void checkStringConstant(DiagnosticPosition pos, Object constValue) { if (nerrs != 0 || // only complain about a long string once 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(JCMethodDecl md, List<JCStatement> initCode) { if (md.name == names.init && TreeInfo.isInitialConstructor(md)) { // We are seeing a constructor that does not call another // constructor of the same class. List<JCStatement> stats = md.body.stats; ListBuffer<JCStatement> newstats = new ListBuffer<JCStatement>(); if (stats.nonEmpty()) { // Copy initializers of synthetic variables generated in // the translation of inner classes. while (TreeInfo.isSyntheticInit(stats.head)) { newstats.append(stats.head); stats = stats.tail; } // Copy superclass constructor call newstats.append(stats.head); stats = stats.tail; // Copy remaining synthetic initializers. while (stats.nonEmpty() && TreeInfo.isSyntheticInit(stats.head)) { newstats.append(stats.head); stats = stats.tail; } // Now insert the initializer code. newstats.appendList(initCode); // And copy all remaining statements. 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(md.body.stats.last()); } }/* ******************************************************************** * Adding miranda methods *********************************************************************/ /** 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<Type> l = types.interfaces(c.type); l.nonEmpty(); l = l.tail) { ClassSymbol i = (ClassSymbol)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, types); 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, // was c.type.memberType(m), but now only !generics supported c); c.members().enter(absMeth); // add to symbol table } private void adjustAbstractMethod(ClassSymbol c, MethodSymbol pm, MethodSymbol im) { MethodType pmt = (MethodType)pm.type; Type imt = types.memberType(c.type, im); pmt.thrown = chk.intersect(pmt.getThrownTypes(), imt.getThrownTypes()); }/* ************************************************************************ * Traversal methods *************************************************************************/ /** Visitor argument: The current environment. */ Env<GenContext> 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(JCTree tree, Env<GenContext> env) { Env<GenContext> 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) * * @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(JCTree tree, Env<GenContext> env, int crtFlags) { if (!genCrt) { genStat(tree, env); return; } int startpc = code.curPc(); genStat(tree, env); if (tree.getTag() == JCTree.BLOCK) crtFlags |= CRT_BLOCK; code.crt.put(tree, crtFlags, startpc, code.curPc()); } /** Derived visitor method: generate code for a statement. */ public void genStat(JCTree tree, Env<GenContext> env) { if (code.isAlive()) { code.statBegin(tree.pos); genDef(tree, env); } else if (env.info.isSwitch && tree.getTag() == JCTree.VARDEF) { // variables whose declarations are in a switch // can be used even if the decl is unreachable. code.newLocal(((JCVariableDecl) 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, Env) * * @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<JCStatement> trees, Env<GenContext> env, int crtFlags) { if (!genCrt) { genStats(trees, env); return; } if (trees.length() == 1) { // mark one statement with the flags genStat(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<? extends JCTree> trees, Env<GenContext> env) { for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) genStat(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,boolean) * * @param tree The tree to be visited. * @param crtFlags The CharacterRangeTable flags * indicating type of the entry. */ public CondItem genCond(JCTree 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -