stringopts.cpp revision 4123
0N/A * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 0N/A * published by the Free Software Foundation. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 0N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 0N/A bool _multiple;
// indicates this is a fusion of two or more 0N/A // separate StringBuilders 0N/A // indicating how to treat the value. 0N/A // to restart at the initial JVMState. 0N/A // Mode for converting arguments to Strings 0N/A // XXX This is place holder code for reusing an existing String 0N/A // allocation but the logic for checking the state safety is 0N/A // probably inadequate at the moment. 0N/A // Found useless new String(sb.toString()) so reuse the newly allocated String 0N/A // when creating the result instead of allocating a new one. 0N/A // Look for a diamond shaped Null check of toString() result 0N/A // (could be code from String.valueOf()): 0N/A // (Proj == NULL) ? "null":"CastPP(Proj)#NotNULL 0N/A // phi->region->if_proj->ifnode->bool 0N/A // Null check of the return of toString which can simply be skipped. 0N/A log->
head(
"replace_string_concat arguments='%d' string_alloc='%d' multiple='%d'",
// Build a new call using the jvms state of the allocate // Set the trap request to record intrinsic failure if this trap // is taken too many times. Ideally we would handle then traps by // doing the original bookkeeping in the MDO so that if it caused // the code to be thrown out we could still recompile and use the // optimization. Failing the uncommon traps doesn't really mean // that the optimization is a bad idea but there's no other way to // do the MDO updates currently. // disconnect the hook node // replace the toString result with the all the arguments that // made up the other StringConcat // EA can't cope with the partially collapsed graph this // creates so put it on the worklist to be collapsed later. // Eliminate Initialize node. tty->
print(
"considering toString call in ");
// possible opportunity for StringBuilder fusion // Find the constructor call // strange looking allocation tty->
print(
"giving up because allocation looks strange ");
// Matched the constructor. // StringBuilder(String) so pick this up as the first argument // StringBuilder(null) throws exception. tty->
print(
"giving up because StringBuilder(null) throws exception");
// StringBuilder(str) argument needs null check. // The int variant takes an initial size for the backing // array so just treat it like the void version. // couldn't find constructor tty->
print(
"giving up because couldn't find constructor ");
// Walked all the way back and found the constructor call so see // if this call converted into a direct string concatenation. // _control is the list of StringBuilder calls nodes which // will be replaced by new String code after this optimization. // Integer::toString() call is not part of StringBuilder calls // chain. It could be eliminated only if its result is used // only by this SB calls chain. // Another limitation: it should be used only once because // it is unknown that it is used only by this SB calls chain // until all related SB calls nodes are collected. // some unhandled signature tty->
print(
"giving up because encountered unexpected signature ");
// Something wrong so give up. // Collect the types needed to talk about the various slices of memory // For each locally allocated StringBuffer see if the usages can be // collapsed into a single String construction. // Run through the list of allocation looking for SB.toString to see // if it's possible to fuse the usage of the SB into a single String // try to coalesce separate concats // Delete any dead nodes to make things clean enough that escape // analysis doesn't get unhappy. for (i =
1; i <
use->
req(); i++) {
// Recurisvely clean up references to CreateEx so EA doesn't // get unhappy about the partially collapsed graph. // We found all the calls and arguments now lets see if it's // safe to transform the graph as we would expect. // Check to see if this resulted in too many uncommon traps previously // Walk backwards over the control flow from toString to the // allocation and make sure all the control flow is ok. This // means it's either going to be eliminated once the calls are // removed or it can safely be transformed into an uncommon // Collect the nodes that we know about and will eliminate into ctrl_path // Push the call and it's control projection // Skip backwards through the control checking for unexpected contro flow // Null check of the return of append which can simply be eliminated // NULL check of the return value of the append // A test which leads to an uncommon trap which should be safe. // Later this trap will be converted into a trap that restarts // control flow leads to uct so should be ok // Some unexpected control flow we don't know how to handle. // XXX should check for possibly merging stores. simple data merges are ok. // Validate that all these results produced are contained within // this cluster of objects. First collect all the results produced // by calls in the region. // This can happen if the constant oop is non-perm. // Do not "join" in the previous type; it doesn't add value, // and may yield a vacuous result if the field is of interface type. // int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); // if (x <= sizeTable[i]) // Add loop predicate first. // need to handle Integer.MIN_VALUE specially because negating doesn't make it positive // Statically not equal to MIN_VALUE so this path is dead // Simplified version of Integer.getChars // r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... // buf [--charPos] = digits [r]; // Add loop predicate first. // buf [--charPos] = sign; // For small constant strings just emit individual stores. // A length of 6 seems like a good space/speed tradeof. for (
int e = 0; e < c; e++) {
// Log a little info about the transformation // pull the JVMState of the allocation into a SafePointNode to serve as // as a shim for the insertion of the new code. // copy the control and memory state from the final call into our // new starting state. This allows any preceeding tests to feed // into the new section of code. // blow away old allocation arguments // Copy the rest of the inputs for the JVMState // Make sure the memory state is a MergeMem for parsing. // disconnect all the old StringBuilder calls from the graph // At this point all the old work has been completely removed from // the graph and the saved JVMState exists at the point where the // final toString call used to be. // There may be uncommon traps which are still using the // intermediate states and these need to be rewritten to point at // the JVMState at the beginning of the transformation. // Now insert the logic to compute the size of the string followed // by all the logic to construct array and resulting string. // Create a region for the overflow checks to merge into. // Create a hook node to hold onto the individual sizes since they // are need for the copying phase. // Cache this value for the use by int_toString // Null check with uncommont trap since // StringBuilder(null) throws exception. // Use special uncommon trap instead of // calling normal do_null_check(). // Fallthrough to add string length. // replace the argument with the null checked version // s = s != null ? s : "null"; // length = length + (s.count - s.offset); // replace the argument with the null checked version // Check that the sum hasn't overflowed // length now contains the number of characters needed for the // char[] so create a new AllocateArray for the char[] // The original jvms is for an allocation of either a String or // StringBuffer so no stack adjustment is necessary for proper // reexecution. If we deoptimize in the slow path the bytecode // will be reexecuted and the char[] allocation will be thrown away. // Mark the allocation so that zeroing is skipped since the code // below will overwrite the entire array // Now copy the string representations into the final char[] // getChars words backwards so pass the ending point as well as the start // If we're not reusing an existing String allocation then allocate one here. // The original jvms is for an allocation of either a String or // StringBuffer so no stack adjustment is necessary for proper // hook up the outgoing control and result