📄 code.java
字号:
/* * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */package com.sun.tools.javac.jvm;import com.sun.tools.javac.code.*;import com.sun.tools.javac.code.Symbol.*;import com.sun.tools.javac.util.*;import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;import static com.sun.tools.javac.code.TypeTags.*;import static com.sun.tools.javac.jvm.ByteCodes.*;import static com.sun.tools.javac.jvm.UninitializedType.*;import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;/** An internal structure that corresponds to the code attribute of * methods in a classfile. The class also provides some utility operations to * generate bytecode instructions. * * <p><b>This is NOT part of any API supported by Sun Microsystems. If * you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice.</b> */public class Code { public final boolean debugCode; public final boolean needStackMap; public enum StackMapFormat { NONE, CLDC { Name getAttributeName(Name.Table names) { return names.StackMap; } }, JSR202 { Name getAttributeName(Name.Table names) { return names.StackMapTable; } }; Name getAttributeName(Name.Table names) { return names.empty; } } final Types types; final Symtab syms;/*---------- classfile fields: --------------- */ /** The maximum stack size. */ public int max_stack = 0; /** The maximum number of local variable slots. */ public int max_locals = 0; /** The code buffer. */ public byte[] code = new byte[64]; /** the current code pointer. */ public int cp = 0; /** Check the code against VM spec limits; if * problems report them and return true. */ public boolean checkLimits(DiagnosticPosition pos, Log log) { if (cp > ClassFile.MAX_CODE) { log.error(pos, "limit.code"); return true; } if (max_locals > ClassFile.MAX_LOCALS) { log.error(pos, "limit.locals"); return true; } if (max_stack > ClassFile.MAX_STACK) { log.error(pos, "limit.stack"); return true; } return false; } /** A buffer for expression catch data. Each enter is a vector * of four unsigned shorts. */ ListBuffer<char[]> catchInfo = new ListBuffer<char[]>(); /** A buffer for line number information. Each entry is a vector * of two unsigned shorts. */ List<char[]> lineInfo = List.nil(); // handled in stack fashion /** The CharacterRangeTable */ public CRTable crt;/*---------- internal fields: --------------- */ /** Are we generating code with jumps >= 32K? */ public boolean fatcode; /** Code generation enabled? */ private boolean alive = true; /** The current machine state (registers and stack). */ State state; /** Is it forbidden to compactify code, because something is * pointing to current location? */ private boolean fixedPc = false; /** The next available register. */ public int nextreg = 0; /** A chain for jumps to be resolved before the next opcode is emitted. * We do this lazily to avoid jumps to jumps. */ Chain pendingJumps = null; /** The position of the currently statement, if we are at the * start of this statement, NOPOS otherwise. * We need this to emit line numbers lazily, which we need to do * because of jump-to-jump optimization. */ int pendingStatPos = Position.NOPOS; /** Set true when a stackMap is needed at the current PC. */ boolean pendingStackMap = false; /** The stack map format to be generated. */ StackMapFormat stackMap; /** Switch: emit variable debug info. */ boolean varDebugInfo; /** Switch: emit line number info. */ boolean lineDebugInfo; /** Emit line number info if map supplied */ Position.LineMap lineMap; /** The constant pool of the current class. */ final Pool pool; final MethodSymbol meth; /** Construct a code object, given the settings of the fatcode, * debugging info switches and the CharacterRangeTable. */ public Code(MethodSymbol meth, boolean fatcode, Position.LineMap lineMap, boolean varDebugInfo, StackMapFormat stackMap, boolean debugCode, CRTable crt, Symtab syms, Types types, Pool pool) { this.meth = meth; this.fatcode = fatcode; this.lineMap = lineMap; this.lineDebugInfo = lineMap != null; this.varDebugInfo = varDebugInfo; this.crt = crt; this.syms = syms; this.types = types; this.debugCode = debugCode; this.stackMap = stackMap; switch (stackMap) { case CLDC: case JSR202: this.needStackMap = true; break; default: this.needStackMap = false; } state = new State(); lvar = new LocalVar[20]; this.pool = pool; }/* ************************************************************************** * Typecodes & related stuff ****************************************************************************/ /** Given a type, return its type code (used implicitly in the * JVM architecture). */ public static int typecode(Type type) { switch (type.tag) { case BYTE: return BYTEcode; case SHORT: return SHORTcode; case CHAR: return CHARcode; case INT: return INTcode; case LONG: return LONGcode; case FLOAT: return FLOATcode; case DOUBLE: return DOUBLEcode; case BOOLEAN: return BYTEcode; case VOID: return VOIDcode; case CLASS: case ARRAY: case METHOD: case BOT: case TYPEVAR: case UNINITIALIZED_THIS: case UNINITIALIZED_OBJECT: return OBJECTcode; default: throw new AssertionError("typecode " + type.tag); } } /** Collapse type code for subtypes of int to INTcode. */ public static int truncate(int tc) { switch (tc) { case BYTEcode: case SHORTcode: case CHARcode: return INTcode; default: return tc; } } /** The width in bytes of objects of the type. */ public static int width(int typecode) { switch (typecode) { case LONGcode: case DOUBLEcode: return 2; case VOIDcode: return 0; default: return 1; } } public static int width(Type type) { return type == null ? 1 : width(typecode(type)); } /** The total width taken up by a vector of objects. */ public static int width(List<Type> types) { int w = 0; for (List<Type> l = types; l.nonEmpty(); l = l.tail) w = w + width(l.head); return w; } /** Given a type, return its code for allocating arrays of that type. */ public static int arraycode(Type type) { switch (type.tag) { case BYTE: return 8; case BOOLEAN: return 4; case SHORT: return 9; case CHAR: return 5; case INT: return 10; case LONG: return 11; case FLOAT: return 6; case DOUBLE: return 7; case CLASS: return 0; case ARRAY: return 1; default: throw new AssertionError("arraycode " + type); } }/* ************************************************************************** * Emit code ****************************************************************************/ /** The current output code pointer. */ public int curPc() { if (pendingJumps != null) resolvePending(); if (pendingStatPos != Position.NOPOS) markStatBegin(); fixedPc = true; return cp; } /** Emit a byte of code. */ private void emit1(int od) { if (!alive) return; if (cp == code.length) { byte[] newcode = new byte[cp * 2]; System.arraycopy(code, 0, newcode, 0, cp); code = newcode; } code[cp++] = (byte)od; } /** Emit two bytes of code. */ private void emit2(int od) { if (!alive) return; if (cp + 2 > code.length) { emit1(od >> 8); emit1(od); } else { code[cp++] = (byte)(od >> 8); code[cp++] = (byte)od; } } /** Emit four bytes of code. */ public void emit4(int od) { if (!alive) return; if (cp + 4 > code.length) { emit1(od >> 24); emit1(od >> 16); emit1(od >> 8); emit1(od); } else { code[cp++] = (byte)(od >> 24); code[cp++] = (byte)(od >> 16); code[cp++] = (byte)(od >> 8); code[cp++] = (byte)od; } } /** Emit an opcode. */ private void emitop(int op) { if (pendingJumps != null) resolvePending(); if (alive) { if (pendingStatPos != Position.NOPOS) markStatBegin(); if (pendingStackMap) { pendingStackMap = false; emitStackMap(); } if (debugCode) System.err.println("emit@" + cp + " stack=" + state.stacksize + ": " + mnem(op)); emit1(op); } } void postop() { assert alive || state.stacksize == 0; } /** Emit a multinewarray instruction. */ public void emitMultianewarray(int ndims, int type, Type arrayType) { emitop(multianewarray); if (!alive) return; emit2(type); emit1(ndims); state.pop(ndims); state.push(arrayType); } /** Emit newarray. */ public void emitNewarray(int elemcode, Type arrayType) { emitop(newarray); if (!alive) return; emit1(elemcode); state.pop(1); // count state.push(arrayType); } /** Emit anewarray. */ public void emitAnewarray(int od, Type arrayType) { emitop(anewarray); if (!alive) return; emit2(od); state.pop(1); state.push(arrayType); } /** Emit an invokeinterface instruction. */ public void emitInvokeinterface(int meth, Type mtype) { int argsize = width(mtype.getParameterTypes()); emitop(invokeinterface); if (!alive) return; emit2(meth); emit1(argsize + 1); emit1(0); state.pop(argsize + 1); state.push(mtype.getReturnType()); } /** Emit an invokespecial instruction. */ public void emitInvokespecial(int meth, Type mtype) { int argsize = width(mtype.getParameterTypes()); emitop(invokespecial); if (!alive) return; emit2(meth); Symbol sym = (Symbol)pool.pool[meth]; state.pop(argsize); if (sym.isConstructor()) state.markInitialized((UninitializedType)state.peek()); state.pop(1); state.push(mtype.getReturnType()); } /** Emit an invokestatic instruction. */ public void emitInvokestatic(int meth, Type mtype) { int argsize = width(mtype.getParameterTypes()); emitop(invokestatic); if (!alive) return; emit2(meth); state.pop(argsize); state.push(mtype.getReturnType()); } /** Emit an invokevirtual instruction. */ public void emitInvokevirtual(int meth, Type mtype) { int argsize = width(mtype.getParameterTypes()); emitop(invokevirtual); if (!alive) return; emit2(meth); state.pop(argsize + 1); state.push(mtype.getReturnType()); } /** Emit an opcode with no operand field. */ public void emitop0(int op) { emitop(op); if (!alive) return; switch (op) { case aaload: { state.pop(1);// index Type a = state.stack[state.stacksize-1]; state.pop(1); state.push(types.erasure(types.elemtype(a))); } break; case goto_: markDead(); break; case nop: case ineg: case lneg: case fneg: case dneg: break; case aconst_null: state.push(syms.botType); break; case iconst_m1: case iconst_0: case iconst_1: case iconst_2: case iconst_3: case iconst_4: case iconst_5: case iload_0: case iload_1: case iload_2: case iload_3: state.push(syms.intType); break; case lconst_0: case lconst_1: case lload_0: case lload_1: case lload_2: case lload_3: state.push(syms.longType); break; case fconst_0: case fconst_1: case fconst_2: case fload_0: case fload_1: case fload_2: case fload_3: state.push(syms.floatType); break; case dconst_0: case dconst_1: case dload_0: case dload_1: case dload_2: case dload_3: state.push(syms.doubleType); break; case aload_0: state.push(lvar[0].sym.type); break; case aload_1: state.push(lvar[1].sym.type); break; case aload_2: state.push(lvar[2].sym.type); break; case aload_3: state.push(lvar[3].sym.type); break; case iaload: case baload: case caload: case saload: state.pop(2); state.push(syms.intType); break; case laload: state.pop(2); state.push(syms.longType); break; case faload: state.pop(2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -