2026:03c26c60499c | 2027:4932bb04c4b8 |
---|---|
26 package com.sun.tools.javac.jvm; | 26 package com.sun.tools.javac.jvm; |
27 | 27 |
28 import com.sun.tools.javac.code.*; | 28 import com.sun.tools.javac.code.*; |
29 import com.sun.tools.javac.code.Symbol.*; | 29 import com.sun.tools.javac.code.Symbol.*; |
30 import com.sun.tools.javac.code.Types.UniqueType; | 30 import com.sun.tools.javac.code.Types.UniqueType; |
31 import com.sun.tools.javac.tree.JCTree; | |
31 import com.sun.tools.javac.util.*; | 32 import com.sun.tools.javac.util.*; |
32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; | 33 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; |
33 | 34 |
34 import static com.sun.tools.javac.code.TypeTag.BOT; | 35 import static com.sun.tools.javac.code.TypeTag.BOT; |
35 import static com.sun.tools.javac.code.TypeTag.INT; | 36 import static com.sun.tools.javac.code.TypeTag.INT; |
179 */ | 180 */ |
180 final Pool pool; | 181 final Pool pool; |
181 | 182 |
182 final MethodSymbol meth; | 183 final MethodSymbol meth; |
183 | 184 |
185 final LVTRanges lvtRanges; | |
186 | |
184 /** Construct a code object, given the settings of the fatcode, | 187 /** Construct a code object, given the settings of the fatcode, |
185 * debugging info switches and the CharacterRangeTable. | 188 * debugging info switches and the CharacterRangeTable. |
186 */ | 189 */ |
187 public Code(MethodSymbol meth, | 190 public Code(MethodSymbol meth, |
188 boolean fatcode, | 191 boolean fatcode, |
191 StackMapFormat stackMap, | 194 StackMapFormat stackMap, |
192 boolean debugCode, | 195 boolean debugCode, |
193 CRTable crt, | 196 CRTable crt, |
194 Symtab syms, | 197 Symtab syms, |
195 Types types, | 198 Types types, |
196 Pool pool) { | 199 Pool pool, |
200 LVTRanges lvtRanges) { | |
197 this.meth = meth; | 201 this.meth = meth; |
198 this.fatcode = fatcode; | 202 this.fatcode = fatcode; |
199 this.lineMap = lineMap; | 203 this.lineMap = lineMap; |
200 this.lineDebugInfo = lineMap != null; | 204 this.lineDebugInfo = lineMap != null; |
201 this.varDebugInfo = varDebugInfo; | 205 this.varDebugInfo = varDebugInfo; |
213 this.needStackMap = false; | 217 this.needStackMap = false; |
214 } | 218 } |
215 state = new State(); | 219 state = new State(); |
216 lvar = new LocalVar[20]; | 220 lvar = new LocalVar[20]; |
217 this.pool = pool; | 221 this.pool = pool; |
222 this.lvtRanges = lvtRanges; | |
218 } | 223 } |
219 | 224 |
220 | 225 |
221 /* ************************************************************************** | 226 /* ************************************************************************** |
222 * Typecodes & related stuff | 227 * Typecodes & related stuff |
303 * Emit code | 308 * Emit code |
304 ****************************************************************************/ | 309 ****************************************************************************/ |
305 | 310 |
306 /** The current output code pointer. | 311 /** The current output code pointer. |
307 */ | 312 */ |
308 public int curPc() { | 313 public int curCP() { |
309 if (pendingJumps != null) resolvePending(); | 314 /* |
310 if (pendingStatPos != Position.NOPOS) markStatBegin(); | 315 * This method has side-effects because calling it can indirectly provoke |
316 * extra code generation, like goto instructions, depending on the context | |
317 * where it's called. | |
318 * Use with care or even better avoid using it. | |
319 */ | |
320 if (pendingJumps != null) { | |
321 resolvePending(); | |
322 } | |
323 if (pendingStatPos != Position.NOPOS) { | |
324 markStatBegin(); | |
325 } | |
311 fixedPc = true; | 326 fixedPc = true; |
312 return cp; | 327 return cp; |
313 } | 328 } |
314 | 329 |
315 /** Emit a byte of code. | 330 /** Emit a byte of code. |
1173 } | 1188 } |
1174 | 1189 |
1175 /** Declare an entry point; return current code pointer | 1190 /** Declare an entry point; return current code pointer |
1176 */ | 1191 */ |
1177 public int entryPoint() { | 1192 public int entryPoint() { |
1178 int pc = curPc(); | 1193 int pc = curCP(); |
1179 alive = true; | 1194 alive = true; |
1180 pendingStackMap = needStackMap; | 1195 pendingStackMap = needStackMap; |
1181 return pc; | 1196 return pc; |
1182 } | 1197 } |
1183 | 1198 |
1184 /** Declare an entry point with initial state; | 1199 /** Declare an entry point with initial state; |
1185 * return current code pointer | 1200 * return current code pointer |
1186 */ | 1201 */ |
1187 public int entryPoint(State state) { | 1202 public int entryPoint(State state) { |
1188 int pc = curPc(); | 1203 int pc = curCP(); |
1189 alive = true; | 1204 alive = true; |
1190 this.state = state.dup(); | 1205 this.state = state.dup(); |
1191 Assert.check(state.stacksize <= max_stack); | 1206 Assert.check(state.stacksize <= max_stack); |
1192 if (debugCode) System.err.println("entry point " + state); | 1207 if (debugCode) System.err.println("entry point " + state); |
1193 pendingStackMap = needStackMap; | 1208 pendingStackMap = needStackMap; |
1196 | 1211 |
1197 /** Declare an entry point with initial state plus a pushed value; | 1212 /** Declare an entry point with initial state plus a pushed value; |
1198 * return current code pointer | 1213 * return current code pointer |
1199 */ | 1214 */ |
1200 public int entryPoint(State state, Type pushed) { | 1215 public int entryPoint(State state, Type pushed) { |
1201 int pc = curPc(); | 1216 int pc = curCP(); |
1202 alive = true; | 1217 alive = true; |
1203 this.state = state.dup(); | 1218 this.state = state.dup(); |
1204 Assert.check(state.stacksize <= max_stack); | 1219 Assert.check(state.stacksize <= max_stack); |
1205 this.state.push(pushed); | 1220 this.state.push(pushed); |
1206 if (debugCode) System.err.println("entry point " + state); | 1221 if (debugCode) System.err.println("entry point " + state); |
1236 /** The stack map frame before the last one. */ | 1251 /** The stack map frame before the last one. */ |
1237 StackMapFrame frameBeforeLast = null; | 1252 StackMapFrame frameBeforeLast = null; |
1238 | 1253 |
1239 /** Emit a stack map entry. */ | 1254 /** Emit a stack map entry. */ |
1240 public void emitStackMap() { | 1255 public void emitStackMap() { |
1241 int pc = curPc(); | 1256 int pc = curCP(); |
1242 if (!needStackMap) return; | 1257 if (!needStackMap) return; |
1243 | 1258 |
1244 | 1259 |
1245 | 1260 |
1246 switch (stackMap) { | 1261 switch (stackMap) { |
1480 } | 1495 } |
1481 if (get1(chain.pc) == goto_ && | 1496 if (get1(chain.pc) == goto_ && |
1482 chain.pc + 3 == target && target == cp && !fixedPc) { | 1497 chain.pc + 3 == target && target == cp && !fixedPc) { |
1483 // If goto the next instruction, the jump is not needed: | 1498 // If goto the next instruction, the jump is not needed: |
1484 // compact the code. | 1499 // compact the code. |
1500 if (varDebugInfo) { | |
1501 adjustAliveRanges(cp, -3); | |
1502 } | |
1485 cp = cp - 3; | 1503 cp = cp - 3; |
1486 target = target - 3; | 1504 target = target - 3; |
1487 if (chain.next == null) { | 1505 if (chain.next == null) { |
1488 // This is the only jump to the target. Exit the loop | 1506 // This is the only jump to the target. Exit the loop |
1489 // without setting new state. The code is reachable | 1507 // without setting new state. The code is reachable |
1779 if (lv != null && lv.sym.type == old) { | 1797 if (lv != null && lv.sym.type == old) { |
1780 VarSymbol sym = lv.sym; | 1798 VarSymbol sym = lv.sym; |
1781 sym = sym.clone(sym.owner); | 1799 sym = sym.clone(sym.owner); |
1782 sym.type = newtype; | 1800 sym.type = newtype; |
1783 LocalVar newlv = lvar[i] = new LocalVar(sym); | 1801 LocalVar newlv = lvar[i] = new LocalVar(sym); |
1784 // should the following be initialized to cp? | 1802 newlv.aliveRanges = lv.aliveRanges; |
1785 newlv.start_pc = lv.start_pc; | |
1786 } | 1803 } |
1787 } | 1804 } |
1788 } | 1805 } |
1789 | 1806 |
1790 State join(State other) { | 1807 State join(State other) { |
1868 | 1885 |
1869 /** A live range of a local variable. */ | 1886 /** A live range of a local variable. */ |
1870 static class LocalVar { | 1887 static class LocalVar { |
1871 final VarSymbol sym; | 1888 final VarSymbol sym; |
1872 final char reg; | 1889 final char reg; |
1873 char start_pc = Character.MAX_VALUE; | 1890 |
1874 char length = Character.MAX_VALUE; | 1891 class Range { |
1892 char start_pc = Character.MAX_VALUE; | |
1893 char length = Character.MAX_VALUE; | |
1894 | |
1895 Range() {} | |
1896 | |
1897 Range(char start) { | |
1898 this.start_pc = start; | |
1899 } | |
1900 | |
1901 Range(char start, char length) { | |
1902 this.start_pc = start; | |
1903 this.length = length; | |
1904 } | |
1905 | |
1906 boolean closed() { | |
1907 return start_pc != Character.MAX_VALUE && length != Character.MAX_VALUE; | |
1908 } | |
1909 | |
1910 @Override | |
1911 public String toString() { | |
1912 int currentStartPC = start_pc; | |
1913 int currentLength = length; | |
1914 return "startpc = " + currentStartPC + " length " + currentLength; | |
1915 } | |
1916 } | |
1917 | |
1918 java.util.List<Range> aliveRanges = new java.util.ArrayList<>(); | |
1919 | |
1875 LocalVar(VarSymbol v) { | 1920 LocalVar(VarSymbol v) { |
1876 this.sym = v; | 1921 this.sym = v; |
1877 this.reg = (char)v.adr; | 1922 this.reg = (char)v.adr; |
1878 } | 1923 } |
1879 public LocalVar dup() { | 1924 public LocalVar dup() { |
1880 return new LocalVar(sym); | 1925 return new LocalVar(sym); |
1881 } | 1926 } |
1927 | |
1928 Range firstRange() { | |
1929 return aliveRanges.isEmpty() ? null : aliveRanges.get(0); | |
1930 } | |
1931 | |
1932 Range lastRange() { | |
1933 return aliveRanges.isEmpty() ? null : aliveRanges.get(aliveRanges.size() - 1); | |
1934 } | |
1935 | |
1936 @Override | |
1882 public String toString() { | 1937 public String toString() { |
1883 return "" + sym + " in register " + ((int)reg) + " starts at pc=" + ((int)start_pc) + " length=" + ((int)length); | 1938 if (aliveRanges == null) { |
1884 } | 1939 return "empty local var"; |
1940 } | |
1941 StringBuilder sb = new StringBuilder().append(sym) | |
1942 .append(" in register ").append((int)reg).append(" \n"); | |
1943 for (Range r : aliveRanges) { | |
1944 sb.append(" starts at pc=").append(Integer.toString(((int)r.start_pc))) | |
1945 .append(" length=").append(Integer.toString(((int)r.length))) | |
1946 .append("\n"); | |
1947 } | |
1948 return sb.toString(); | |
1949 } | |
1950 | |
1951 public void openRange(char start) { | |
1952 if (!hasOpenRange()) { | |
1953 aliveRanges.add(new Range(start)); | |
1954 } | |
1955 } | |
1956 | |
1957 public void closeRange(char end) { | |
1958 if (isLastRangeInitialized()) { | |
1959 Range range = lastRange(); | |
1960 if (range != null) { | |
1961 if (range.length == Character.MAX_VALUE) { | |
1962 range.length = end; | |
1963 } | |
1964 } | |
1965 } else { | |
1966 if (!aliveRanges.isEmpty()) { | |
1967 aliveRanges.remove(aliveRanges.size() - 1); | |
1968 } | |
1969 } | |
1970 } | |
1971 | |
1972 public boolean hasOpenRange() { | |
1973 if (aliveRanges.isEmpty()) { | |
1974 return false; | |
1975 } | |
1976 Range range = lastRange(); | |
1977 return range.length == Character.MAX_VALUE; | |
1978 } | |
1979 | |
1980 public boolean isLastRangeInitialized() { | |
1981 if (aliveRanges.isEmpty()) { | |
1982 return false; | |
1983 } | |
1984 Range range = lastRange(); | |
1985 return range.start_pc != Character.MAX_VALUE; | |
1986 } | |
1987 | |
1988 public Range getWidestRange() { | |
1989 if (aliveRanges.isEmpty()) { | |
1990 return new Range(); | |
1991 } else { | |
1992 Range firstRange = firstRange(); | |
1993 Range lastRange = lastRange(); | |
1994 char length = (char)(lastRange.length + (lastRange.start_pc - firstRange.start_pc)); | |
1995 return new Range(firstRange.start_pc, length); | |
1996 } | |
1997 } | |
1998 | |
1885 }; | 1999 }; |
1886 | 2000 |
1887 /** Local variables, indexed by register. */ | 2001 /** Local variables, indexed by register. */ |
1888 LocalVar[] lvar; | 2002 LocalVar[] lvar; |
1889 | 2003 |
1890 /** Add a new local variable. */ | 2004 /** Add a new local variable. */ |
1891 private void addLocalVar(VarSymbol v) { | 2005 private void addLocalVar(VarSymbol v) { |
1892 int adr = v.adr; | 2006 int adr = v.adr; |
1893 lvar = ArrayUtils.ensureCapacity(lvar, adr+1); | 2007 lvar = ArrayUtils.ensureCapacity(lvar, adr+1); |
1894 Assert.checkNull(lvar[adr]); | 2008 Assert.checkNull(lvar[adr]); |
1895 if (pendingJumps != null) resolvePending(); | 2009 if (pendingJumps != null) { |
2010 resolvePending(); | |
2011 } | |
1896 lvar[adr] = new LocalVar(v); | 2012 lvar[adr] = new LocalVar(v); |
1897 state.defined.excl(adr); | 2013 state.defined.excl(adr); |
2014 } | |
2015 | |
2016 | |
2017 public void closeAliveRanges(JCTree tree) { | |
2018 closeAliveRanges(tree, cp); | |
2019 } | |
2020 | |
2021 public void closeAliveRanges(JCTree tree, int closingCP) { | |
2022 List<VarSymbol> locals = lvtRanges.getVars(meth, tree); | |
2023 for (LocalVar localVar: lvar) { | |
2024 for (VarSymbol aliveLocal : locals) { | |
2025 if (localVar == null) { | |
2026 return; | |
2027 } | |
2028 if (localVar.sym == aliveLocal && localVar.lastRange() != null) { | |
2029 char length = (char)(closingCP - localVar.lastRange().start_pc); | |
2030 if (length > 0 && length < Character.MAX_VALUE) { | |
2031 localVar.closeRange(length); | |
2032 } | |
2033 } | |
2034 } | |
2035 } | |
2036 } | |
2037 | |
2038 void adjustAliveRanges(int oldCP, int delta) { | |
2039 for (LocalVar localVar: lvar) { | |
2040 if (localVar == null) { | |
2041 return; | |
2042 } | |
2043 for (LocalVar.Range range: localVar.aliveRanges) { | |
2044 if (range.closed() && range.start_pc + range.length >= oldCP) { | |
2045 range.length += delta; | |
2046 } | |
2047 } | |
2048 } | |
2049 } | |
2050 | |
2051 /** | |
2052 * Calculates the size of the LocalVariableTable. | |
2053 */ | |
2054 public int getLVTSize() { | |
2055 int result = varBufferSize; | |
2056 for (int i = 0; i < varBufferSize; i++) { | |
2057 LocalVar var = varBuffer[i]; | |
2058 result += var.aliveRanges.size() - 1; | |
2059 } | |
2060 return result; | |
1898 } | 2061 } |
1899 | 2062 |
1900 /** Set the current variable defined state. */ | 2063 /** Set the current variable defined state. */ |
1901 public void setDefined(Bits newDefined) { | 2064 public void setDefined(Bits newDefined) { |
1902 if (alive && newDefined != state.defined) { | 2065 if (alive && newDefined != state.defined) { |
1920 if (v == null) { | 2083 if (v == null) { |
1921 state.defined.excl(adr); | 2084 state.defined.excl(adr); |
1922 } else { | 2085 } else { |
1923 state.defined.incl(adr); | 2086 state.defined.incl(adr); |
1924 if (cp < Character.MAX_VALUE) { | 2087 if (cp < Character.MAX_VALUE) { |
1925 if (v.start_pc == Character.MAX_VALUE) | 2088 v.openRange((char)cp); |
1926 v.start_pc = (char)cp; | |
1927 } | 2089 } |
1928 } | 2090 } |
1929 } | 2091 } |
1930 | 2092 |
1931 /** Mark a register as being undefined. */ | 2093 /** Mark a register as being undefined. */ |
1932 public void setUndefined(int adr) { | 2094 public void setUndefined(int adr) { |
1933 state.defined.excl(adr); | 2095 state.defined.excl(adr); |
1934 if (adr < lvar.length && | 2096 if (adr < lvar.length && |
1935 lvar[adr] != null && | 2097 lvar[adr] != null && |
1936 lvar[adr].start_pc != Character.MAX_VALUE) { | 2098 lvar[adr].isLastRangeInitialized()) { |
1937 LocalVar v = lvar[adr]; | 2099 LocalVar v = lvar[adr]; |
1938 char length = (char)(curPc() - v.start_pc); | 2100 char length = (char)(curCP() - v.lastRange().start_pc); |
1939 if (length > 0 && length < Character.MAX_VALUE) { | 2101 if (length > 0 && length < Character.MAX_VALUE) { |
1940 lvar[adr] = v.dup(); | 2102 lvar[adr] = v.dup(); |
1941 v.length = length; | 2103 v.closeRange(length); |
1942 putVar(v); | 2104 putVar(v); |
1943 } else { | 2105 } else { |
1944 v.start_pc = Character.MAX_VALUE; | 2106 v.lastRange().start_pc = Character.MAX_VALUE; |
1945 } | 2107 } |
1946 } | 2108 } |
1947 } | 2109 } |
1948 | 2110 |
1949 /** End the scope of a variable. */ | 2111 /** End the scope of a variable. */ |
1950 private void endScope(int adr) { | 2112 private void endScope(int adr) { |
1951 LocalVar v = lvar[adr]; | 2113 LocalVar v = lvar[adr]; |
1952 if (v != null) { | 2114 if (v != null) { |
1953 lvar[adr] = null; | 2115 lvar[adr] = null; |
1954 if (v.start_pc != Character.MAX_VALUE) { | 2116 if (v.isLastRangeInitialized()) { |
1955 char length = (char)(curPc() - v.start_pc); | 2117 char length = (char)(curCP() - v.lastRange().start_pc); |
1956 if (length < Character.MAX_VALUE) { | 2118 if (length < Character.MAX_VALUE) { |
1957 v.length = length; | 2119 v.closeRange(length); |
1958 putVar(v); | 2120 putVar(v); |
1959 fillLocalVarPosition(v); | 2121 fillLocalVarPosition(v); |
1960 } | 2122 } |
1961 } | 2123 } |
1962 } | 2124 } |
1966 private void fillLocalVarPosition(LocalVar lv) { | 2128 private void fillLocalVarPosition(LocalVar lv) { |
1967 if (lv == null || lv.sym == null || !lv.sym.hasTypeAnnotations()) | 2129 if (lv == null || lv.sym == null || !lv.sym.hasTypeAnnotations()) |
1968 return; | 2130 return; |
1969 for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) { | 2131 for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) { |
1970 TypeAnnotationPosition p = ta.position; | 2132 TypeAnnotationPosition p = ta.position; |
1971 p.lvarOffset = new int[] { (int)lv.start_pc }; | 2133 LocalVar.Range widestRange = lv.getWidestRange(); |
1972 p.lvarLength = new int[] { (int)lv.length }; | 2134 p.lvarOffset = new int[] { (int)widestRange.start_pc }; |
2135 p.lvarLength = new int[] { (int)widestRange.length }; | |
1973 p.lvarIndex = new int[] { (int)lv.reg }; | 2136 p.lvarIndex = new int[] { (int)lv.reg }; |
1974 p.isValidOffset = true; | 2137 p.isValidOffset = true; |
1975 } | 2138 } |
1976 } | 2139 } |
1977 | 2140 |