< prev index next >
src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
Print this page
rev 3493 : Review fixes
*** 43,53 ****
import com.sun.tools.javac.tree.EndPosTable;
import com.sun.tools.javac.tree.JCTree.*;
import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Kinds.Kind.*;
- import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
import static com.sun.tools.javac.code.TypeTag.*;
import static com.sun.tools.javac.jvm.ByteCodes.*;
import static com.sun.tools.javac.jvm.CRTFlags.*;
import static com.sun.tools.javac.main.Option.*;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
--- 43,52 ----
*** 122,131 ****
--- 121,164 ----
: options.isSet(G_CUSTOM, "vars");
genCrt = options.isSet(XJCOV);
debugCode = options.isSet("debugcode");
allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
allowBetterNullChecks = target.hasObjects();
+
+ {
+ String concat = options.get("stringConcat");
+ if (target.hasStringConcatFactory()) {
+ if (concat == null) {
+ concat = "indyWithConstants";
+ }
+
+ switch (concat) {
+ case "inline":
+ allowIndyStringConcat = false;
+ indyStringConcatConstants = false;
+ break;
+ case "indy":
+ allowIndyStringConcat = true;
+ indyStringConcatConstants = false;
+ break;
+ case "indyWithConstants":
+ allowIndyStringConcat = true;
+ indyStringConcatConstants = true;
+ break;
+ default:
+ Assert.error("Unknown stringConcat: " + concat);
+ throw new IllegalStateException("Unknown stringConcat: " + concat);
+ }
+ } else {
+ if (concat != null && !"inline".equals(concat)) {
+ Assert.error("StringConcatFactory-based string concat is requested on a platform that does not support it.");
+ }
+ allowIndyStringConcat = false;
+ indyStringConcatConstants = false;
+ }
+ }
+
pool = new Pool(types);
// ignore cldc because we cannot have both stackmap formats
this.stackMap = StackMapFormat.JSR202;
*** 150,159 ****
--- 183,194 ----
private final boolean varDebugInfo;
private final boolean genCrt;
private final boolean debugCode;
private final boolean allowInvokedynamic;
private final boolean allowBetterNullChecks;
+ private final boolean allowIndyStringConcat;
+ private final boolean indyStringConcatConstants;
/** Default limit of (approximate) size of finalizer to inline.
* Zero means always use jsr. 100 or greater means never use
* jsr.
*/
*** 1893,1902 ****
--- 1928,1941 ----
public void visitAssignop(JCAssignOp tree) {
OperatorSymbol operator = (OperatorSymbol) tree.operator;
Item l;
if (operator.opcode == string_add) {
+ if (allowIndyStringConcat) {
+ l = genExpr(tree.lhs, tree.lhs.type);
+ emitIndyStringConcat(tree);
+ } else {
// Generate code to make a string buffer
makeStringBuffer(tree.pos());
// Generate code for first string, possibly save one
// copy under buffer
*** 1912,1921 ****
--- 1951,1961 ----
// Append all other strings to buffer.
appendStrings(tree.rhs);
// Convert buffer to string.
bufferToString(tree.pos());
+ }
} else {
// Generate code for first expression
l = genExpr(tree.lhs, tree.lhs.type);
// If we have an increment of -32768 to +32767 of a local
*** 2024,2039 ****
--- 2064,2084 ----
}
public void visitBinary(JCBinary tree) {
OperatorSymbol operator = (OperatorSymbol)tree.operator;
if (operator.opcode == string_add) {
+ if (allowIndyStringConcat) {
+ // Emit indified version of String concat
+ emitIndyStringConcat(tree);
+ } else {
// Create a string buffer.
makeStringBuffer(tree.pos());
// Append all strings to buffer.
appendStrings(tree);
// Convert buffer to string.
bufferToString(tree.pos());
+ }
result = items.makeStackItem(syms.stringType);
} else if (tree.hasTag(AND)) {
CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
if (!lcond.isFalse()) {
Chain falseJumps = lcond.jumpFalse();
*** 2064,2073 ****
--- 2109,2323 ----
Item od = genExpr(tree.lhs, operator.type.getParameterTypes().head);
od.load();
result = completeBinop(tree.lhs, tree.rhs, operator);
}
}
+
+ /**
+ * Maximum number of slots for String Concat call.
+ * JDK's StringConcatFactory does not support more than that.
+ */
+ private static final int MAX_INDY_CONCAT_ARG_SLOTS = 200;
+ private static final String TAG_ARG = "\u0001";
+ private static final String TAG_CONST = "\u0002";
+
+ List<JCTree> collectStringsRecursive(JCTree tree, List<JCTree> res) {
+ tree = TreeInfo.skipParens(tree);
+ if (tree.hasTag(PLUS) && tree.type.constValue() == null) {
+ JCBinary op = (JCBinary) tree;
+ if (op.operator.kind == MTH &&
+ ((OperatorSymbol) op.operator).opcode == string_add) {
+ return res
+ .appendList(collectStringsRecursive(op.lhs, res))
+ .appendList(collectStringsRecursive(op.rhs, res));
+ }
+ }
+ return res.append(tree);
+ }
+
+ /** Handle the inline assignments, collect all subtrees */
+ private void emitIndyStringConcat(JCAssignOp tree) {
+ List<JCTree> args =
+ List.<JCTree>nil()
+ .appendList(collectStringsRecursive(tree.lhs, List.nil()))
+ .appendList(collectStringsRecursive(tree.rhs, List.nil()));
+ emitIndyStringConcat(args, tree.type, tree.pos());
+ }
+
+ /** Handle the string_add operation, collect all subtrees */
+ private void emitIndyStringConcat(JCBinary tree) {
+ List<JCTree> args =
+ List.<JCTree>nil()
+ .appendList(collectStringsRecursive(tree.lhs, List.nil()))
+ .appendList(collectStringsRecursive(tree.rhs, List.nil()));
+ emitIndyStringConcat(args, tree.type, tree.pos());
+ }
+
+ /** Emit the indy concat for all these arguments, possibly peeling along the way */
+ private void emitIndyStringConcat(List<JCTree> args, Type type, DiagnosticPosition pos) {
+ int slots = 0;
+ int count = 0;
+
+ // Need to peel, so that neither call has more than acceptable number
+ // of slots for the arguments.
+ ListBuffer<JCTree> cArgs = new ListBuffer<>();
+ for (JCTree t : args) {
+ int needSlots = (t.type.getTag() == LONG || t.type.getTag() == DOUBLE) ? 2 : 1;
+ if (slots + needSlots >= MAX_INDY_CONCAT_ARG_SLOTS) {
+ emitIndyStringConcatOne(cArgs.toList(), type, pos);
+ cArgs.clear();
+ slots = 0;
+ count++;
+ }
+ cArgs.add(t);
+ slots += needSlots;
+ }
+
+ // Flush the tail slice
+ if (!cArgs.isEmpty()) {
+ emitIndyStringConcatOne(cArgs.toList(), type, pos);
+ count++;
+ }
+
+ // More that one peel slice produced: concatenate the results
+ if (count > 1) {
+ emitIndyStringConcatMerge(count, type, pos);
+ }
+ }
+
+ /**
+ * This code builds the recipe, static and dynamic arguments for calling JDK's
+ * StringConcatFactory. See the interface description there.
+ *
+ * We also bypass empty strings, because they have no meaning at this level. This
+ * captures the Java language trick to force String concat with e.g. ("" + int)-like
+ * expression. Down here, we already know we are in String concat business, and do
+ * not require these markers.
+ */
+ private void emitIndyStringConcatOne(List<JCTree> args, Type type, DiagnosticPosition pos) {
+ Assert.check(!args.isEmpty(), "Arguments list is empty");
+
+ StringBuilder recipe = new StringBuilder(args.size());
+ ListBuffer<Type> dynamicArgs = new ListBuffer<>();
+ ListBuffer<Object> staticArgs = new ListBuffer<>();
+
+ if (indyStringConcatConstants) {
+ for (JCTree arg : args) {
+ Object constVal = arg.type.constValue();
+ if ("".equals(constVal)) continue;
+ if (arg.type == syms.botType) {
+ // Concat the null into the recipe right away
+ recipe.append("null");
+ } else if (constVal != null) {
+ // Concat the String representation of the constant, except
+ // for the case it contains special tags, which requires us
+ // to expose it as detached constant.
+ String a = arg.type.stringValue();
+ if (a.contains(TAG_CONST) || a.contains(TAG_ARG)) {
+ recipe.append(TAG_CONST);
+ staticArgs.add(a);
+ } else {
+ recipe.append(a);
+ }
+ } else {
+ // Ordinary arguments come through the dynamic arguments.
+ recipe.append(TAG_ARG);
+ dynamicArgs.add(arg.type);
+ genExpr(arg, arg.type).load();
+ }
+ }
+ } else {
+ for (JCTree arg : args) {
+ Object constVal = arg.type.constValue();
+ if ("".equals(constVal)) continue;
+ if (arg.type == syms.botType) {
+ dynamicArgs.add(syms.voidClassType);
+ } else {
+ dynamicArgs.add(arg.type);
+ }
+ genExpr(arg, arg.type).load();
+ }
+ }
+
+ indyStringConcatDoCall(type, pos, recipe.toString(), staticArgs, dynamicArgs);
+ }
+
+ /** Special version for concatenating the known number of known Strings */
+ private void emitIndyStringConcatMerge(int count, Type type, DiagnosticPosition pos) {
+ Assert.check(count != 0, "Arguments list is empty");
+ Assert.check(count <= MAX_INDY_CONCAT_ARG_SLOTS, "Too many arguments for concatenation");
+
+ // All arguments are assumed to be non-constant Strings
+ StringBuilder recipe = new StringBuilder(count);
+ ListBuffer<Type> argTypes = new ListBuffer<>();
+ for (int c = 0; c < count; c++) {
+ argTypes.append(syms.stringType);
+ recipe.append(TAG_ARG);
+ }
+
+ indyStringConcatDoCall(type, pos, recipe.toString(), new ListBuffer<>(), argTypes);
+ }
+
+ /** Produce the actual invokedynamic call to StringConcatFactory */
+ private void indyStringConcatDoCall(Type type, DiagnosticPosition pos, String recipe, ListBuffer<Object> staticArgs, ListBuffer<Type> dynamicArgTypes) {
+ MethodType indyType = new MethodType(dynamicArgTypes.toList(),
+ type,
+ List.<Type>nil(),
+ syms.methodClass);
+
+ int prevPos = make.pos;
+ try {
+ make.at(pos);
+
+ DynamicMethodSymbol dynSym;
+
+ if (indyStringConcatConstants) {
+ ListBuffer<Type> constTypes = new ListBuffer<>();
+ ListBuffer<Object> constants = new ListBuffer<>();
+ for (Object t : staticArgs) {
+ constants.add(t);
+ constTypes.add(syms.stringType);
+ }
+
+ List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+ syms.stringType,
+ syms.methodTypeType)
+ .append(syms.stringType)
+ .appendList(constTypes);
+
+ Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, syms.stringConcatFactory,
+ names.makeConcatWithConstants, bsm_staticArgs, List.<Type>nil());
+
+ dynSym = new DynamicMethodSymbol(names.makeConcatWithConstants,
+ syms.noSymbol,
+ ClassFile.REF_invokeStatic,
+ (MethodSymbol)bsm,
+ indyType,
+ List.<Object>of(recipe).appendList(constants).toArray());
+ } else {
+ List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+ syms.stringType,
+ syms.methodTypeType);
+
+ Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, syms.stringConcatFactory,
+ names.makeConcat, bsm_staticArgs, List.<Type>nil());
+
+ dynSym = new DynamicMethodSymbol(names.makeConcat,
+ syms.noSymbol,
+ ClassFile.REF_invokeStatic,
+ (MethodSymbol)bsm,
+ indyType,
+ List.nil().toArray());
+ }
+
+ Item item = items.makeDynamicItem(dynSym);
+ item.invoke();
+ } finally {
+ make.at(prevPos);
+ }
+ }
+
//where
/** Make a new string buffer.
*/
void makeStringBuffer(DiagnosticPosition pos) {
code.emitop2(new_, makeRef(pos, syms.stringBuilderType));
< prev index next >