< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java

Print this page
rev 3493 : Review fixes


  28 import java.util.*;
  29 
  30 import com.sun.tools.javac.util.*;
  31 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  32 import com.sun.tools.javac.util.List;
  33 import com.sun.tools.javac.code.*;
  34 import com.sun.tools.javac.code.Attribute.TypeCompound;
  35 import com.sun.tools.javac.code.Symbol.VarSymbol;
  36 import com.sun.tools.javac.comp.*;
  37 import com.sun.tools.javac.tree.*;
  38 
  39 import com.sun.tools.javac.code.Symbol.*;
  40 import com.sun.tools.javac.code.Type.*;
  41 import com.sun.tools.javac.jvm.Code.*;
  42 import com.sun.tools.javac.jvm.Items.*;
  43 import com.sun.tools.javac.tree.EndPosTable;
  44 import com.sun.tools.javac.tree.JCTree.*;
  45 
  46 import static com.sun.tools.javac.code.Flags.*;
  47 import static com.sun.tools.javac.code.Kinds.Kind.*;
  48 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
  49 import static com.sun.tools.javac.code.TypeTag.*;
  50 import static com.sun.tools.javac.jvm.ByteCodes.*;
  51 import static com.sun.tools.javac.jvm.CRTFlags.*;
  52 import static com.sun.tools.javac.main.Option.*;
  53 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  54 
  55 /** This pass maps flat Java (i.e. without inner classes) to bytecodes.
  56  *
  57  *  <p><b>This is NOT part of any supported API.
  58  *  If you write code that depends on this, you do so at your own risk.
  59  *  This code and its internal interfaces are subject to change or
  60  *  deletion without notice.</b>
  61  */
  62 public class Gen extends JCTree.Visitor {
  63     protected static final Context.Key<Gen> genKey = new Context.Key<>();
  64 
  65     private final Log log;
  66     private final Symtab syms;
  67     private final Check chk;
  68     private final Resolve rs;


 107         types = Types.instance(context);
 108         methodType = new MethodType(null, null, null, syms.methodClass);
 109         stringBufferAppend = new HashMap<>();
 110         accessDollar = names.
 111             fromString("access" + target.syntheticNameChar());
 112         flow = Flow.instance(context);
 113         lower = Lower.instance(context);
 114 
 115         Options options = Options.instance(context);
 116         lineDebugInfo =
 117             options.isUnset(G_CUSTOM) ||
 118             options.isSet(G_CUSTOM, "lines");
 119         varDebugInfo =
 120             options.isUnset(G_CUSTOM)
 121             ? options.isSet(G)
 122             : options.isSet(G_CUSTOM, "vars");
 123         genCrt = options.isSet(XJCOV);
 124         debugCode = options.isSet("debugcode");
 125         allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
 126         allowBetterNullChecks = target.hasObjects();


































 127         pool = new Pool(types);
 128 
 129         // ignore cldc because we cannot have both stackmap formats
 130         this.stackMap = StackMapFormat.JSR202;
 131 
 132         // by default, avoid jsr's for simple finalizers
 133         int setjsrlimit = 50;
 134         String jsrlimitString = options.get("jsrlimit");
 135         if (jsrlimitString != null) {
 136             try {
 137                 setjsrlimit = Integer.parseInt(jsrlimitString);
 138             } catch (NumberFormatException ex) {
 139                 // ignore ill-formed numbers for jsrlimit
 140             }
 141         }
 142         this.jsrlimit = setjsrlimit;
 143         this.useJsrLocally = false; // reset in visitTry
 144         annotate = Annotate.instance(context);
 145     }
 146 
 147     /** Switches
 148      */
 149     private final boolean lineDebugInfo;
 150     private final boolean varDebugInfo;
 151     private final boolean genCrt;
 152     private final boolean debugCode;
 153     private final boolean allowInvokedynamic;
 154     private final boolean allowBetterNullChecks;


 155 
 156     /** Default limit of (approximate) size of finalizer to inline.
 157      *  Zero means always use jsr.  100 or greater means never use
 158      *  jsr.
 159      */
 160     private final int jsrlimit;
 161 
 162     /** True if jsr is used.
 163      */
 164     private boolean useJsrLocally;
 165 
 166     /** Code buffer, set by genMethod.
 167      */
 168     private Code code;
 169 
 170     /** Items structure, set by genMethod.
 171      */
 172     private Items items;
 173 
 174     /** Environment for symbol lookup, set by genClass


1878         result = genExpr(tree.expr, tree.expr.type);
1879     }
1880 
1881     public void visitAssign(JCAssign tree) {
1882         Item l = genExpr(tree.lhs, tree.lhs.type);
1883         genExpr(tree.rhs, tree.lhs.type).load();
1884         if (tree.rhs.type.hasTag(BOT)) {
1885             /* This is just a case of widening reference conversion that per 5.1.5 simply calls
1886                for "regarding a reference as having some other type in a manner that can be proved
1887                correct at compile time."
1888             */
1889             code.state.forceStackTop(tree.lhs.type);
1890         }
1891         result = items.makeAssignItem(l);
1892     }
1893 
1894     public void visitAssignop(JCAssignOp tree) {
1895         OperatorSymbol operator = (OperatorSymbol) tree.operator;
1896         Item l;
1897         if (operator.opcode == string_add) {




1898             // Generate code to make a string buffer
1899             makeStringBuffer(tree.pos());
1900 
1901             // Generate code for first string, possibly save one
1902             // copy under buffer
1903             l = genExpr(tree.lhs, tree.lhs.type);
1904             if (l.width() > 0) {
1905                 code.emitop0(dup_x1 + 3 * (l.width() - 1));
1906             }
1907 
1908             // Load first string and append to buffer.
1909             l.load();
1910             appendString(tree.lhs);
1911 
1912             // Append all other strings to buffer.
1913             appendStrings(tree.rhs);
1914 
1915             // Convert buffer to string.
1916             bufferToString(tree.pos());

1917         } else {
1918             // Generate code for first expression
1919             l = genExpr(tree.lhs, tree.lhs.type);
1920 
1921             // If we have an increment of -32768 to +32767 of a local
1922             // int variable we can use an incr instruction instead of
1923             // proceeding further.
1924             if ((tree.hasTag(PLUS_ASG) || tree.hasTag(MINUS_ASG)) &&
1925                 l instanceof LocalItem &&
1926                 tree.lhs.type.getTag().isSubRangeOf(INT) &&
1927                 tree.rhs.type.getTag().isSubRangeOf(INT) &&
1928                 tree.rhs.type.constValue() != null) {
1929                 int ival = ((Number) tree.rhs.type.constValue()).intValue();
1930                 if (tree.hasTag(MINUS_ASG)) ival = -ival;
1931                 ((LocalItem)l).incr(ival);
1932                 result = l;
1933                 return;
1934             }
1935             // Otherwise, duplicate expression, load one copy
1936             // and complete binary operation.


2009                 Assert.error();
2010             }
2011         }
2012     }
2013 
2014     /** Generate a null check from the object value at stack top. */
2015     private void genNullCheck(DiagnosticPosition pos) {
2016         if (allowBetterNullChecks) {
2017             callMethod(pos, syms.objectsType, names.requireNonNull,
2018                     List.of(syms.objectType), true);
2019         } else {
2020             callMethod(pos, syms.objectType, names.getClass,
2021                     List.<Type>nil(), false);
2022         }
2023         code.emitop0(pop);
2024     }
2025 
2026     public void visitBinary(JCBinary tree) {
2027         OperatorSymbol operator = (OperatorSymbol)tree.operator;
2028         if (operator.opcode == string_add) {




2029             // Create a string buffer.
2030             makeStringBuffer(tree.pos());
2031             // Append all strings to buffer.
2032             appendStrings(tree);
2033             // Convert buffer to string.
2034             bufferToString(tree.pos());

2035             result = items.makeStackItem(syms.stringType);
2036         } else if (tree.hasTag(AND)) {
2037             CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2038             if (!lcond.isFalse()) {
2039                 Chain falseJumps = lcond.jumpFalse();
2040                 code.resolve(lcond.trueJumps);
2041                 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2042                 result = items.
2043                     makeCondItem(rcond.opcode,
2044                                  rcond.trueJumps,
2045                                  Code.mergeChains(falseJumps,
2046                                                   rcond.falseJumps));
2047             } else {
2048                 result = lcond;
2049             }
2050         } else if (tree.hasTag(OR)) {
2051             CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2052             if (!lcond.isTrue()) {
2053                 Chain trueJumps = lcond.jumpTrue();
2054                 code.resolve(lcond.falseJumps);
2055                 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2056                 result = items.
2057                     makeCondItem(rcond.opcode,
2058                                  Code.mergeChains(trueJumps, rcond.trueJumps),
2059                                  rcond.falseJumps);
2060             } else {
2061                 result = lcond;
2062             }
2063         } else {
2064             Item od = genExpr(tree.lhs, operator.type.getParameterTypes().head);
2065             od.load();
2066             result = completeBinop(tree.lhs, tree.rhs, operator);
2067         }
2068     }













































































































































































































2069 //where
2070         /** Make a new string buffer.
2071          */
2072         void makeStringBuffer(DiagnosticPosition pos) {
2073             code.emitop2(new_, makeRef(pos, syms.stringBuilderType));
2074             code.emitop0(dup);
2075             callMethod(
2076                     pos, syms.stringBuilderType, names.init, List.<Type>nil(), false);
2077         }
2078 
2079         /** Append value (on tos) to string buffer (on tos - 1).
2080          */
2081         void appendString(JCTree tree) {
2082             Type t = tree.type.baseType();
2083             if (!t.isPrimitive() && t.tsym != syms.stringType.tsym) {
2084                 t = syms.objectType;
2085             }
2086             items.makeMemberItem(getStringBufferAppend(tree, t), false).invoke();
2087         }
2088         Symbol getStringBufferAppend(JCTree tree, Type t) {




  28 import java.util.*;
  29 
  30 import com.sun.tools.javac.util.*;
  31 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  32 import com.sun.tools.javac.util.List;
  33 import com.sun.tools.javac.code.*;
  34 import com.sun.tools.javac.code.Attribute.TypeCompound;
  35 import com.sun.tools.javac.code.Symbol.VarSymbol;
  36 import com.sun.tools.javac.comp.*;
  37 import com.sun.tools.javac.tree.*;
  38 
  39 import com.sun.tools.javac.code.Symbol.*;
  40 import com.sun.tools.javac.code.Type.*;
  41 import com.sun.tools.javac.jvm.Code.*;
  42 import com.sun.tools.javac.jvm.Items.*;
  43 import com.sun.tools.javac.tree.EndPosTable;
  44 import com.sun.tools.javac.tree.JCTree.*;
  45 
  46 import static com.sun.tools.javac.code.Flags.*;
  47 import static com.sun.tools.javac.code.Kinds.Kind.*;

  48 import static com.sun.tools.javac.code.TypeTag.*;
  49 import static com.sun.tools.javac.jvm.ByteCodes.*;
  50 import static com.sun.tools.javac.jvm.CRTFlags.*;
  51 import static com.sun.tools.javac.main.Option.*;
  52 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  53 
  54 /** This pass maps flat Java (i.e. without inner classes) to bytecodes.
  55  *
  56  *  <p><b>This is NOT part of any supported API.
  57  *  If you write code that depends on this, you do so at your own risk.
  58  *  This code and its internal interfaces are subject to change or
  59  *  deletion without notice.</b>
  60  */
  61 public class Gen extends JCTree.Visitor {
  62     protected static final Context.Key<Gen> genKey = new Context.Key<>();
  63 
  64     private final Log log;
  65     private final Symtab syms;
  66     private final Check chk;
  67     private final Resolve rs;


 106         types = Types.instance(context);
 107         methodType = new MethodType(null, null, null, syms.methodClass);
 108         stringBufferAppend = new HashMap<>();
 109         accessDollar = names.
 110             fromString("access" + target.syntheticNameChar());
 111         flow = Flow.instance(context);
 112         lower = Lower.instance(context);
 113 
 114         Options options = Options.instance(context);
 115         lineDebugInfo =
 116             options.isUnset(G_CUSTOM) ||
 117             options.isSet(G_CUSTOM, "lines");
 118         varDebugInfo =
 119             options.isUnset(G_CUSTOM)
 120             ? options.isSet(G)
 121             : options.isSet(G_CUSTOM, "vars");
 122         genCrt = options.isSet(XJCOV);
 123         debugCode = options.isSet("debugcode");
 124         allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
 125         allowBetterNullChecks = target.hasObjects();
 126 
 127         {
 128             String concat = options.get("stringConcat");
 129             if (target.hasStringConcatFactory()) {
 130                 if (concat == null) {
 131                     concat = "indyWithConstants";
 132                 }
 133 
 134                 switch (concat) {
 135                     case "inline":
 136                         allowIndyStringConcat = false;
 137                         indyStringConcatConstants = false;
 138                         break;
 139                     case "indy":
 140                         allowIndyStringConcat = true;
 141                         indyStringConcatConstants = false;
 142                         break;
 143                     case "indyWithConstants":
 144                         allowIndyStringConcat = true;
 145                         indyStringConcatConstants = true;
 146                         break;
 147                     default:
 148                         Assert.error("Unknown stringConcat: " + concat);
 149                         throw new IllegalStateException("Unknown stringConcat: " + concat);
 150                 }
 151             } else {
 152                 if (concat != null && !"inline".equals(concat)) {
 153                     Assert.error("StringConcatFactory-based string concat is requested on a platform that does not support it.");
 154                 }
 155                 allowIndyStringConcat = false;
 156                 indyStringConcatConstants = false;
 157             }
 158         }
 159 
 160         pool = new Pool(types);
 161 
 162         // ignore cldc because we cannot have both stackmap formats
 163         this.stackMap = StackMapFormat.JSR202;
 164 
 165         // by default, avoid jsr's for simple finalizers
 166         int setjsrlimit = 50;
 167         String jsrlimitString = options.get("jsrlimit");
 168         if (jsrlimitString != null) {
 169             try {
 170                 setjsrlimit = Integer.parseInt(jsrlimitString);
 171             } catch (NumberFormatException ex) {
 172                 // ignore ill-formed numbers for jsrlimit
 173             }
 174         }
 175         this.jsrlimit = setjsrlimit;
 176         this.useJsrLocally = false; // reset in visitTry
 177         annotate = Annotate.instance(context);
 178     }
 179 
 180     /** Switches
 181      */
 182     private final boolean lineDebugInfo;
 183     private final boolean varDebugInfo;
 184     private final boolean genCrt;
 185     private final boolean debugCode;
 186     private final boolean allowInvokedynamic;
 187     private final boolean allowBetterNullChecks;
 188     private final boolean allowIndyStringConcat;
 189     private final boolean indyStringConcatConstants;
 190 
 191     /** Default limit of (approximate) size of finalizer to inline.
 192      *  Zero means always use jsr.  100 or greater means never use
 193      *  jsr.
 194      */
 195     private final int jsrlimit;
 196 
 197     /** True if jsr is used.
 198      */
 199     private boolean useJsrLocally;
 200 
 201     /** Code buffer, set by genMethod.
 202      */
 203     private Code code;
 204 
 205     /** Items structure, set by genMethod.
 206      */
 207     private Items items;
 208 
 209     /** Environment for symbol lookup, set by genClass


1913         result = genExpr(tree.expr, tree.expr.type);
1914     }
1915 
1916     public void visitAssign(JCAssign tree) {
1917         Item l = genExpr(tree.lhs, tree.lhs.type);
1918         genExpr(tree.rhs, tree.lhs.type).load();
1919         if (tree.rhs.type.hasTag(BOT)) {
1920             /* This is just a case of widening reference conversion that per 5.1.5 simply calls
1921                for "regarding a reference as having some other type in a manner that can be proved
1922                correct at compile time."
1923             */
1924             code.state.forceStackTop(tree.lhs.type);
1925         }
1926         result = items.makeAssignItem(l);
1927     }
1928 
1929     public void visitAssignop(JCAssignOp tree) {
1930         OperatorSymbol operator = (OperatorSymbol) tree.operator;
1931         Item l;
1932         if (operator.opcode == string_add) {
1933             if (allowIndyStringConcat) {
1934                 l = genExpr(tree.lhs, tree.lhs.type);
1935                 emitIndyStringConcat(tree);
1936             } else {
1937                 // Generate code to make a string buffer
1938                 makeStringBuffer(tree.pos());
1939 
1940                 // Generate code for first string, possibly save one
1941                 // copy under buffer
1942                 l = genExpr(tree.lhs, tree.lhs.type);
1943                 if (l.width() > 0) {
1944                     code.emitop0(dup_x1 + 3 * (l.width() - 1));
1945                 }
1946 
1947                 // Load first string and append to buffer.
1948                 l.load();
1949                 appendString(tree.lhs);
1950 
1951                 // Append all other strings to buffer.
1952                 appendStrings(tree.rhs);
1953 
1954                 // Convert buffer to string.
1955                 bufferToString(tree.pos());
1956             }
1957         } else {
1958             // Generate code for first expression
1959             l = genExpr(tree.lhs, tree.lhs.type);
1960 
1961             // If we have an increment of -32768 to +32767 of a local
1962             // int variable we can use an incr instruction instead of
1963             // proceeding further.
1964             if ((tree.hasTag(PLUS_ASG) || tree.hasTag(MINUS_ASG)) &&
1965                 l instanceof LocalItem &&
1966                 tree.lhs.type.getTag().isSubRangeOf(INT) &&
1967                 tree.rhs.type.getTag().isSubRangeOf(INT) &&
1968                 tree.rhs.type.constValue() != null) {
1969                 int ival = ((Number) tree.rhs.type.constValue()).intValue();
1970                 if (tree.hasTag(MINUS_ASG)) ival = -ival;
1971                 ((LocalItem)l).incr(ival);
1972                 result = l;
1973                 return;
1974             }
1975             // Otherwise, duplicate expression, load one copy
1976             // and complete binary operation.


2049                 Assert.error();
2050             }
2051         }
2052     }
2053 
2054     /** Generate a null check from the object value at stack top. */
2055     private void genNullCheck(DiagnosticPosition pos) {
2056         if (allowBetterNullChecks) {
2057             callMethod(pos, syms.objectsType, names.requireNonNull,
2058                     List.of(syms.objectType), true);
2059         } else {
2060             callMethod(pos, syms.objectType, names.getClass,
2061                     List.<Type>nil(), false);
2062         }
2063         code.emitop0(pop);
2064     }
2065 
2066     public void visitBinary(JCBinary tree) {
2067         OperatorSymbol operator = (OperatorSymbol)tree.operator;
2068         if (operator.opcode == string_add) {
2069             if (allowIndyStringConcat) {
2070                 // Emit indified version of String concat
2071                 emitIndyStringConcat(tree);
2072             } else {
2073                 // Create a string buffer.
2074                 makeStringBuffer(tree.pos());
2075                 // Append all strings to buffer.
2076                 appendStrings(tree);
2077                 // Convert buffer to string.
2078                 bufferToString(tree.pos());
2079             }
2080             result = items.makeStackItem(syms.stringType);
2081         } else if (tree.hasTag(AND)) {
2082             CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2083             if (!lcond.isFalse()) {
2084                 Chain falseJumps = lcond.jumpFalse();
2085                 code.resolve(lcond.trueJumps);
2086                 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2087                 result = items.
2088                     makeCondItem(rcond.opcode,
2089                                  rcond.trueJumps,
2090                                  Code.mergeChains(falseJumps,
2091                                                   rcond.falseJumps));
2092             } else {
2093                 result = lcond;
2094             }
2095         } else if (tree.hasTag(OR)) {
2096             CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2097             if (!lcond.isTrue()) {
2098                 Chain trueJumps = lcond.jumpTrue();
2099                 code.resolve(lcond.falseJumps);
2100                 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2101                 result = items.
2102                     makeCondItem(rcond.opcode,
2103                                  Code.mergeChains(trueJumps, rcond.trueJumps),
2104                                  rcond.falseJumps);
2105             } else {
2106                 result = lcond;
2107             }
2108         } else {
2109             Item od = genExpr(tree.lhs, operator.type.getParameterTypes().head);
2110             od.load();
2111             result = completeBinop(tree.lhs, tree.rhs, operator);
2112         }
2113     }
2114 
2115     /**
2116      * Maximum number of slots for String Concat call.
2117      * JDK's StringConcatFactory does not support more than that.
2118      */
2119     private static final int MAX_INDY_CONCAT_ARG_SLOTS = 200;
2120     private static final String TAG_ARG   = "\u0001";
2121     private static final String TAG_CONST = "\u0002";
2122 
2123     List<JCTree> collectStringsRecursive(JCTree tree, List<JCTree> res) {
2124         tree = TreeInfo.skipParens(tree);
2125         if (tree.hasTag(PLUS) && tree.type.constValue() == null) {
2126             JCBinary op = (JCBinary) tree;
2127             if (op.operator.kind == MTH &&
2128                     ((OperatorSymbol) op.operator).opcode == string_add) {
2129                 return res
2130                         .appendList(collectStringsRecursive(op.lhs, res))
2131                         .appendList(collectStringsRecursive(op.rhs, res));
2132             }
2133         }
2134         return res.append(tree);
2135     }
2136 
2137     /** Handle the inline assignments, collect all subtrees */
2138     private void emitIndyStringConcat(JCAssignOp tree) {
2139         List<JCTree> args =
2140                 List.<JCTree>nil()
2141                         .appendList(collectStringsRecursive(tree.lhs, List.nil()))
2142                         .appendList(collectStringsRecursive(tree.rhs, List.nil()));
2143         emitIndyStringConcat(args, tree.type, tree.pos());
2144     }
2145 
2146     /** Handle the string_add operation, collect all subtrees */
2147     private void emitIndyStringConcat(JCBinary tree) {
2148         List<JCTree> args =
2149                 List.<JCTree>nil()
2150                         .appendList(collectStringsRecursive(tree.lhs, List.nil()))
2151                         .appendList(collectStringsRecursive(tree.rhs, List.nil()));
2152         emitIndyStringConcat(args, tree.type, tree.pos());
2153     }
2154 
2155     /** Emit the indy concat for all these arguments, possibly peeling along the way */
2156     private void emitIndyStringConcat(List<JCTree> args, Type type, DiagnosticPosition pos) {
2157         int slots = 0;
2158         int count = 0;
2159 
2160         // Need to peel, so that neither call has more than acceptable number
2161         // of slots for the arguments.
2162         ListBuffer<JCTree> cArgs = new ListBuffer<>();
2163         for (JCTree t : args) {
2164             int needSlots = (t.type.getTag() == LONG || t.type.getTag() == DOUBLE) ? 2 : 1;
2165             if (slots + needSlots >= MAX_INDY_CONCAT_ARG_SLOTS) {
2166                 emitIndyStringConcatOne(cArgs.toList(), type, pos);
2167                 cArgs.clear();
2168                 slots = 0;
2169                 count++;
2170             }
2171             cArgs.add(t);
2172             slots += needSlots;
2173         }
2174 
2175         // Flush the tail slice
2176         if (!cArgs.isEmpty()) {
2177             emitIndyStringConcatOne(cArgs.toList(), type, pos);
2178             count++;
2179         }
2180 
2181         // More that one peel slice produced: concatenate the results
2182         if (count > 1) {
2183             emitIndyStringConcatMerge(count, type, pos);
2184         }
2185     }
2186 
2187     /**
2188      * This code builds the recipe, static and dynamic arguments for calling JDK's
2189      * StringConcatFactory. See the interface description there.
2190      *
2191      * We also bypass empty strings, because they have no meaning at this level. This
2192      * captures the Java language trick to force String concat with e.g. ("" + int)-like
2193      * expression. Down here, we already know we are in String concat business, and do
2194      * not require these markers.
2195      */
2196     private void emitIndyStringConcatOne(List<JCTree> args, Type type, DiagnosticPosition pos) {
2197         Assert.check(!args.isEmpty(), "Arguments list is empty");
2198 
2199         StringBuilder recipe = new StringBuilder(args.size());
2200         ListBuffer<Type> dynamicArgs = new ListBuffer<>();
2201         ListBuffer<Object> staticArgs = new ListBuffer<>();
2202 
2203         if (indyStringConcatConstants) {
2204             for (JCTree arg : args) {
2205                 Object constVal = arg.type.constValue();
2206                 if ("".equals(constVal)) continue;
2207                 if (arg.type == syms.botType) {
2208                     // Concat the null into the recipe right away
2209                     recipe.append("null");
2210                 } else if (constVal != null) {
2211                     // Concat the String representation of the constant, except
2212                     // for the case it contains special tags, which requires us
2213                     // to expose it as detached constant.
2214                     String a = arg.type.stringValue();
2215                     if (a.contains(TAG_CONST) || a.contains(TAG_ARG)) {
2216                         recipe.append(TAG_CONST);
2217                         staticArgs.add(a);
2218                     } else {
2219                         recipe.append(a);
2220                     }
2221                 } else {
2222                     // Ordinary arguments come through the dynamic arguments.
2223                     recipe.append(TAG_ARG);
2224                     dynamicArgs.add(arg.type);
2225                     genExpr(arg, arg.type).load();
2226                 }
2227             }
2228         } else {
2229             for (JCTree arg : args) {
2230                 Object constVal = arg.type.constValue();
2231                 if ("".equals(constVal)) continue;
2232                 if (arg.type == syms.botType) {
2233                     dynamicArgs.add(syms.voidClassType);
2234                 } else {
2235                     dynamicArgs.add(arg.type);
2236                 }
2237                 genExpr(arg, arg.type).load();
2238             }
2239         }
2240 
2241         indyStringConcatDoCall(type, pos, recipe.toString(), staticArgs, dynamicArgs);
2242     }
2243 
2244     /** Special version for concatenating the known number of known Strings */
2245     private void emitIndyStringConcatMerge(int count, Type type, DiagnosticPosition pos) {
2246         Assert.check(count != 0, "Arguments list is empty");
2247         Assert.check(count <= MAX_INDY_CONCAT_ARG_SLOTS, "Too many arguments for concatenation");
2248 
2249         // All arguments are assumed to be non-constant Strings
2250         StringBuilder recipe = new StringBuilder(count);
2251         ListBuffer<Type> argTypes = new ListBuffer<>();
2252         for (int c = 0; c < count; c++) {
2253             argTypes.append(syms.stringType);
2254             recipe.append(TAG_ARG);
2255         }
2256 
2257         indyStringConcatDoCall(type, pos, recipe.toString(), new ListBuffer<>(), argTypes);
2258     }
2259 
2260     /** Produce the actual invokedynamic call to StringConcatFactory */
2261     private void indyStringConcatDoCall(Type type, DiagnosticPosition pos, String recipe, ListBuffer<Object> staticArgs, ListBuffer<Type> dynamicArgTypes) {
2262         MethodType indyType = new MethodType(dynamicArgTypes.toList(),
2263                 type,
2264                 List.<Type>nil(),
2265                 syms.methodClass);
2266 
2267         int prevPos = make.pos;
2268         try {
2269             make.at(pos);
2270 
2271             DynamicMethodSymbol dynSym;
2272 
2273             if (indyStringConcatConstants) {
2274                 ListBuffer<Type> constTypes = new ListBuffer<>();
2275                 ListBuffer<Object> constants = new ListBuffer<>();
2276                 for (Object t : staticArgs) {
2277                     constants.add(t);
2278                     constTypes.add(syms.stringType);
2279                 }
2280 
2281                 List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
2282                         syms.stringType,
2283                         syms.methodTypeType)
2284                         .append(syms.stringType)
2285                         .appendList(constTypes);
2286 
2287                 Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, syms.stringConcatFactory,
2288                         names.makeConcatWithConstants, bsm_staticArgs, List.<Type>nil());
2289 
2290                 dynSym = new DynamicMethodSymbol(names.makeConcatWithConstants,
2291                         syms.noSymbol,
2292                         ClassFile.REF_invokeStatic,
2293                         (MethodSymbol)bsm,
2294                         indyType,
2295                         List.<Object>of(recipe).appendList(constants).toArray());
2296             } else {
2297                 List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
2298                         syms.stringType,
2299                         syms.methodTypeType);
2300 
2301                 Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, syms.stringConcatFactory,
2302                         names.makeConcat, bsm_staticArgs, List.<Type>nil());
2303 
2304                 dynSym = new DynamicMethodSymbol(names.makeConcat,
2305                         syms.noSymbol,
2306                         ClassFile.REF_invokeStatic,
2307                         (MethodSymbol)bsm,
2308                         indyType,
2309                         List.nil().toArray());
2310             }
2311 
2312             Item item = items.makeDynamicItem(dynSym);
2313             item.invoke();
2314         } finally {
2315             make.at(prevPos);
2316         }
2317     }
2318 
2319 //where
2320         /** Make a new string buffer.
2321          */
2322         void makeStringBuffer(DiagnosticPosition pos) {
2323             code.emitop2(new_, makeRef(pos, syms.stringBuilderType));
2324             code.emitop0(dup);
2325             callMethod(
2326                     pos, syms.stringBuilderType, names.init, List.<Type>nil(), false);
2327         }
2328 
2329         /** Append value (on tos) to string buffer (on tos - 1).
2330          */
2331         void appendString(JCTree tree) {
2332             Type t = tree.type.baseType();
2333             if (!t.isPrimitive() && t.tsym != syms.stringType.tsym) {
2334                 t = syms.objectType;
2335             }
2336             items.makeMemberItem(getStringBufferAppend(tree, t), false).invoke();
2337         }
2338         Symbol getStringBufferAppend(JCTree tree, Type t) {


< prev index next >