6892658: C2 should optimize some stringbuilder patterns

Thu, 12 Nov 2009 09:24:21 -0800

author
never
date
Thu, 12 Nov 2009 09:24:21 -0800
changeset 1515
7c57aead6d3e
parent 1513
8e7adf982378
child 1516
bd12fff78df5

6892658: C2 should optimize some stringbuilder patterns
Reviewed-by: kvn, twisti

src/share/vm/ci/ciEnv.cpp file | annotate | diff | comparison | revisions
src/share/vm/ci/ciEnv.hpp file | annotate | diff | comparison | revisions
src/share/vm/ci/ciInstanceKlass.cpp file | annotate | diff | comparison | revisions
src/share/vm/ci/ciInstanceKlass.hpp file | annotate | diff | comparison | revisions
src/share/vm/ci/ciObjectFactory.cpp file | annotate | diff | comparison | revisions
src/share/vm/classfile/systemDictionary.hpp file | annotate | diff | comparison | revisions
src/share/vm/classfile/vmSymbols.cpp file | annotate | diff | comparison | revisions
src/share/vm/classfile/vmSymbols.hpp file | annotate | diff | comparison | revisions
src/share/vm/includeDB_compiler2 file | annotate | diff | comparison | revisions
src/share/vm/includeDB_core file | annotate | diff | comparison | revisions
src/share/vm/memory/universe.cpp file | annotate | diff | comparison | revisions
src/share/vm/memory/universe.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/c2_globals.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/c2_globals.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/callGenerator.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/callGenerator.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/callnode.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/callnode.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/compile.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/compile.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/doCall.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/graphKit.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/graphKit.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/macro.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/memnode.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/node.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/parseHelper.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/phase.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/phaseX.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/stringopts.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/stringopts.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/type.hpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/globals.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/globals_extension.hpp file | annotate | diff | comparison | revisions
src/share/vm/utilities/growableArray.hpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/ci/ciEnv.cpp	Fri Nov 27 07:56:58 2009 -0800
     1.2 +++ b/src/share/vm/ci/ciEnv.cpp	Thu Nov 12 09:24:21 2009 -0800
     1.3 @@ -46,6 +46,9 @@
     1.4  ciInstanceKlass* ciEnv::_Thread;
     1.5  ciInstanceKlass* ciEnv::_OutOfMemoryError;
     1.6  ciInstanceKlass* ciEnv::_String;
     1.7 +ciInstanceKlass* ciEnv::_StringBuffer;
     1.8 +ciInstanceKlass* ciEnv::_StringBuilder;
     1.9 +ciInstanceKlass* ciEnv::_Integer;
    1.10  
    1.11  ciSymbol*        ciEnv::_unloaded_cisymbol = NULL;
    1.12  ciInstanceKlass* ciEnv::_unloaded_ciinstance_klass = NULL;
    1.13 @@ -110,6 +113,8 @@
    1.14    _ArrayIndexOutOfBoundsException_instance = NULL;
    1.15    _ArrayStoreException_instance = NULL;
    1.16    _ClassCastException_instance = NULL;
    1.17 +  _the_null_string = NULL;
    1.18 +  _the_min_jint_string = NULL;
    1.19  }
    1.20  
    1.21  ciEnv::ciEnv(Arena* arena) {
    1.22 @@ -163,6 +168,8 @@
    1.23    _ArrayIndexOutOfBoundsException_instance = NULL;
    1.24    _ArrayStoreException_instance = NULL;
    1.25    _ClassCastException_instance = NULL;
    1.26 +  _the_null_string = NULL;
    1.27 +  _the_min_jint_string = NULL;
    1.28  }
    1.29  
    1.30  ciEnv::~ciEnv() {
    1.31 @@ -248,6 +255,22 @@
    1.32    return _ClassCastException_instance;
    1.33  }
    1.34  
    1.35 +ciInstance* ciEnv::the_null_string() {
    1.36 +  if (_the_null_string == NULL) {
    1.37 +    VM_ENTRY_MARK;
    1.38 +    _the_null_string = get_object(Universe::the_null_string())->as_instance();
    1.39 +  }
    1.40 +  return _the_null_string;
    1.41 +}
    1.42 +
    1.43 +ciInstance* ciEnv::the_min_jint_string() {
    1.44 +  if (_the_min_jint_string == NULL) {
    1.45 +    VM_ENTRY_MARK;
    1.46 +    _the_min_jint_string = get_object(Universe::the_min_jint_string())->as_instance();
    1.47 +  }
    1.48 +  return _the_min_jint_string;
    1.49 +}
    1.50 +
    1.51  // ------------------------------------------------------------------
    1.52  // ciEnv::get_method_from_handle
    1.53  ciMethod* ciEnv::get_method_from_handle(jobject method) {
     2.1 --- a/src/share/vm/ci/ciEnv.hpp	Fri Nov 27 07:56:58 2009 -0800
     2.2 +++ b/src/share/vm/ci/ciEnv.hpp	Thu Nov 12 09:24:21 2009 -0800
     2.3 @@ -82,6 +82,9 @@
     2.4    static ciInstanceKlass* _Thread;
     2.5    static ciInstanceKlass* _OutOfMemoryError;
     2.6    static ciInstanceKlass* _String;
     2.7 +  static ciInstanceKlass* _StringBuffer;
     2.8 +  static ciInstanceKlass* _StringBuilder;
     2.9 +  static ciInstanceKlass* _Integer;
    2.10  
    2.11    static ciSymbol*        _unloaded_cisymbol;
    2.12    static ciInstanceKlass* _unloaded_ciinstance_klass;
    2.13 @@ -97,6 +100,9 @@
    2.14    ciInstance* _ArrayStoreException_instance;
    2.15    ciInstance* _ClassCastException_instance;
    2.16  
    2.17 +  ciInstance* _the_null_string;      // The Java string "null"
    2.18 +  ciInstance* _the_min_jint_string; // The Java string "-2147483648"
    2.19 +
    2.20    // Look up a klass by name from a particular class loader (the accessor's).
    2.21    // If require_local, result must be defined in that class loader, or NULL.
    2.22    // If !require_local, a result from remote class loader may be reported,
    2.23 @@ -310,6 +316,15 @@
    2.24    ciInstanceKlass* String_klass() {
    2.25      return _String;
    2.26    }
    2.27 +  ciInstanceKlass* StringBuilder_klass() {
    2.28 +    return _StringBuilder;
    2.29 +  }
    2.30 +  ciInstanceKlass* StringBuffer_klass() {
    2.31 +    return _StringBuffer;
    2.32 +  }
    2.33 +  ciInstanceKlass* Integer_klass() {
    2.34 +    return _Integer;
    2.35 +  }
    2.36    ciInstance* NullPointerException_instance() {
    2.37      assert(_NullPointerException_instance != NULL, "initialization problem");
    2.38      return _NullPointerException_instance;
    2.39 @@ -324,6 +339,9 @@
    2.40    ciInstance* ArrayStoreException_instance();
    2.41    ciInstance* ClassCastException_instance();
    2.42  
    2.43 +  ciInstance* the_null_string();
    2.44 +  ciInstance* the_min_jint_string();
    2.45 +
    2.46    static ciSymbol* unloaded_cisymbol() {
    2.47      return _unloaded_cisymbol;
    2.48    }
     3.1 --- a/src/share/vm/ci/ciInstanceKlass.cpp	Fri Nov 27 07:56:58 2009 -0800
     3.2 +++ b/src/share/vm/ci/ciInstanceKlass.cpp	Thu Nov 12 09:24:21 2009 -0800
     3.3 @@ -341,6 +341,20 @@
     3.4  }
     3.5  
     3.6  // ------------------------------------------------------------------
     3.7 +// ciInstanceKlass::get_field_by_name
     3.8 +ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static) {
     3.9 +  VM_ENTRY_MARK;
    3.10 +  instanceKlass* k = get_instanceKlass();
    3.11 +  fieldDescriptor fd;
    3.12 +  klassOop def = k->find_field(name->get_symbolOop(), signature->get_symbolOop(), is_static, &fd);
    3.13 +  if (def == NULL) {
    3.14 +    return NULL;
    3.15 +  }
    3.16 +  ciField* field = new (CURRENT_THREAD_ENV->arena()) ciField(&fd);
    3.17 +  return field;
    3.18 +}
    3.19 +
    3.20 +// ------------------------------------------------------------------
    3.21  // ciInstanceKlass::non_static_fields.
    3.22  
    3.23  class NonStaticFieldFiller: public FieldClosure {
     4.1 --- a/src/share/vm/ci/ciInstanceKlass.hpp	Fri Nov 27 07:56:58 2009 -0800
     4.2 +++ b/src/share/vm/ci/ciInstanceKlass.hpp	Thu Nov 12 09:24:21 2009 -0800
     4.3 @@ -148,6 +148,7 @@
     4.4  
     4.5    ciInstanceKlass* get_canonical_holder(int offset);
     4.6    ciField* get_field_by_offset(int field_offset, bool is_static);
     4.7 +  ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static);
     4.8  
     4.9    GrowableArray<ciField*>* non_static_fields();
    4.10  
     5.1 --- a/src/share/vm/ci/ciObjectFactory.cpp	Fri Nov 27 07:56:58 2009 -0800
     5.2 +++ b/src/share/vm/ci/ciObjectFactory.cpp	Thu Nov 12 09:24:21 2009 -0800
     5.3 @@ -168,6 +168,15 @@
     5.4    ciEnv::_String =
     5.5      get(SystemDictionary::string_klass())
     5.6        ->as_instance_klass();
     5.7 +  ciEnv::_StringBuffer =
     5.8 +    get(SystemDictionary::stringBuffer_klass())
     5.9 +      ->as_instance_klass();
    5.10 +  ciEnv::_StringBuilder =
    5.11 +    get(SystemDictionary::StringBuilder_klass())
    5.12 +      ->as_instance_klass();
    5.13 +  ciEnv::_Integer =
    5.14 +    get(SystemDictionary::int_klass())
    5.15 +      ->as_instance_klass();
    5.16  
    5.17    for (int len = -1; len != _ci_objects->length(); ) {
    5.18      len = _ci_objects->length();
     6.1 --- a/src/share/vm/classfile/systemDictionary.hpp	Fri Nov 27 07:56:58 2009 -0800
     6.2 +++ b/src/share/vm/classfile/systemDictionary.hpp	Thu Nov 12 09:24:21 2009 -0800
     6.3 @@ -150,6 +150,7 @@
     6.4    template(vector_klass,                 java_util_Vector,               Pre) \
     6.5    template(hashtable_klass,              java_util_Hashtable,            Pre) \
     6.6    template(stringBuffer_klass,           java_lang_StringBuffer,         Pre) \
     6.7 +  template(StringBuilder_klass,          java_lang_StringBuilder,        Pre) \
     6.8                                                                                \
     6.9    /* It's NULL in non-1.4 JDKs. */                                            \
    6.10    template(stackTraceElement_klass,      java_lang_StackTraceElement,    Opt) \
     7.1 --- a/src/share/vm/classfile/vmSymbols.cpp	Fri Nov 27 07:56:58 2009 -0800
     7.2 +++ b/src/share/vm/classfile/vmSymbols.cpp	Thu Nov 12 09:24:21 2009 -0800
     7.3 @@ -303,6 +303,11 @@
     7.4    const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED;
     7.5    return (flags & (req | neg)) == req;
     7.6  }
     7.7 +inline bool match_F_Y(jshort flags) {
     7.8 +  const int req = JVM_ACC_SYNCHRONIZED;
     7.9 +  const int neg = JVM_ACC_STATIC;
    7.10 +  return (flags & (req | neg)) == req;
    7.11 +}
    7.12  inline bool match_F_RN(jshort flags) {
    7.13    const int req = JVM_ACC_NATIVE;
    7.14    const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED;
    7.15 @@ -361,6 +366,7 @@
    7.16    const char* sname = vmSymbols::name_for(signature_for(id));
    7.17    const char* fname = "";
    7.18    switch (flags_for(id)) {
    7.19 +  case F_Y:  fname = "synchronized ";  break;
    7.20    case F_RN: fname = "native ";        break;
    7.21    case F_SN: fname = "native static "; break;
    7.22    case F_S:  fname = "static ";        break;
     8.1 --- a/src/share/vm/classfile/vmSymbols.hpp	Fri Nov 27 07:56:58 2009 -0800
     8.2 +++ b/src/share/vm/classfile/vmSymbols.hpp	Thu Nov 12 09:24:21 2009 -0800
     8.3 @@ -84,6 +84,7 @@
     8.4    template(java_lang_reflect_Field,                   "java/lang/reflect/Field")                  \
     8.5    template(java_lang_reflect_Array,                   "java/lang/reflect/Array")                  \
     8.6    template(java_lang_StringBuffer,                    "java/lang/StringBuffer")                   \
     8.7 +  template(java_lang_StringBuilder,                   "java/lang/StringBuilder")                  \
     8.8    template(java_lang_CharSequence,                    "java/lang/CharSequence")                   \
     8.9    template(java_security_AccessControlContext,        "java/security/AccessControlContext")       \
    8.10    template(java_security_ProtectionDomain,            "java/security/ProtectionDomain")           \
    8.11 @@ -334,6 +335,7 @@
    8.12    template(ptypes_name,                               "ptypes")                                   \
    8.13    template(form_name,                                 "form")                                     \
    8.14    template(erasedType_name,                           "erasedType")                               \
    8.15 +  template(append_name,                               "append")                                   \
    8.16                                                                                                    \
    8.17    /* non-intrinsic name/signature pairs: */                                                       \
    8.18    template(register_method_name,                      "register")                                 \
    8.19 @@ -415,6 +417,13 @@
    8.20    template(string_signature,                          "Ljava/lang/String;")                                       \
    8.21    template(reference_signature,                       "Ljava/lang/ref/Reference;")                                \
    8.22    template(concurrenthashmap_signature,               "Ljava/util/concurrent/ConcurrentHashMap;")                 \
    8.23 +  template(String_StringBuilder_signature,            "(Ljava/lang/String;)Ljava/lang/StringBuilder;")            \
    8.24 +  template(int_StringBuilder_signature,               "(I)Ljava/lang/StringBuilder;")                             \
    8.25 +  template(char_StringBuilder_signature,              "(C)Ljava/lang/StringBuilder;")                             \
    8.26 +  template(String_StringBuffer_signature,             "(Ljava/lang/String;)Ljava/lang/StringBuffer;")             \
    8.27 +  template(int_StringBuffer_signature,                "(I)Ljava/lang/StringBuffer;")                              \
    8.28 +  template(char_StringBuffer_signature,               "(C)Ljava/lang/StringBuffer;")                              \
    8.29 +  template(int_String_signature,                      "(I)Ljava/lang/String;")                                    \
    8.30    /* signature symbols needed by intrinsics */                                                                    \
    8.31    VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE)            \
    8.32                                                                                                                    \
    8.33 @@ -814,10 +823,34 @@
    8.34      /*the compiler does have special inlining code for these; bytecode inline is just fine */                           \
    8.35                                                                                                                          \
    8.36    do_intrinsic(_fillInStackTrace,         java_lang_Throwable, fillInStackTrace_name, void_throwable_signature,  F_RNY) \
    8.37 -                                                                                                                        \
    8.38 -  do_intrinsic(_Object_init,              java_lang_Object, object_initializer_name, void_method_signature,      F_R)   \
    8.39 -  /*    (symbol object_initializer_name defined above) */                                                               \
    8.40 -                                                                                                                        \
    8.41 +                                                                                                                          \
    8.42 +  do_intrinsic(_StringBuilder_void,   java_lang_StringBuilder, object_initializer_name, void_method_signature,     F_R)   \
    8.43 +  do_intrinsic(_StringBuilder_int,    java_lang_StringBuilder, object_initializer_name, int_void_signature,        F_R)   \
    8.44 +  do_intrinsic(_StringBuilder_String, java_lang_StringBuilder, object_initializer_name, string_void_signature,     F_R)   \
    8.45 +                                                                                                                          \
    8.46 +  do_intrinsic(_StringBuilder_append_char,   java_lang_StringBuilder, append_name, char_StringBuilder_signature,   F_R)   \
    8.47 +  do_intrinsic(_StringBuilder_append_int,    java_lang_StringBuilder, append_name, int_StringBuilder_signature,    F_R)   \
    8.48 +  do_intrinsic(_StringBuilder_append_String, java_lang_StringBuilder, append_name, String_StringBuilder_signature, F_R)   \
    8.49 +                                                                                                                          \
    8.50 +  do_intrinsic(_StringBuilder_toString, java_lang_StringBuilder, toString_name, void_string_signature,             F_R)   \
    8.51 +                                                                                                                          \
    8.52 +  do_intrinsic(_StringBuffer_void,   java_lang_StringBuffer, object_initializer_name, void_method_signature,       F_R)   \
    8.53 +  do_intrinsic(_StringBuffer_int,    java_lang_StringBuffer, object_initializer_name, int_void_signature,          F_R)   \
    8.54 +  do_intrinsic(_StringBuffer_String, java_lang_StringBuffer, object_initializer_name, string_void_signature,       F_R)   \
    8.55 +                                                                                                                          \
    8.56 +  do_intrinsic(_StringBuffer_append_char,   java_lang_StringBuffer, append_name, char_StringBuffer_signature,      F_Y)   \
    8.57 +  do_intrinsic(_StringBuffer_append_int,    java_lang_StringBuffer, append_name, int_StringBuffer_signature,       F_Y)   \
    8.58 +  do_intrinsic(_StringBuffer_append_String, java_lang_StringBuffer, append_name, String_StringBuffer_signature,    F_Y)   \
    8.59 +                                                                                                                          \
    8.60 +  do_intrinsic(_StringBuffer_toString,  java_lang_StringBuffer, toString_name, void_string_signature,              F_Y)   \
    8.61 +                                                                                                                          \
    8.62 +  do_intrinsic(_Integer_toString,      java_lang_Integer, toString_name, int_String_signature,                     F_S)   \
    8.63 +                                                                                                                          \
    8.64 +  do_intrinsic(_String_String, java_lang_String, object_initializer_name, string_void_signature,                   F_R)   \
    8.65 +                                                                                                                          \
    8.66 +  do_intrinsic(_Object_init,              java_lang_Object, object_initializer_name, void_method_signature,        F_R)   \
    8.67 +  /*    (symbol object_initializer_name defined above) */                                                                 \
    8.68 +                                                                                                                          \
    8.69    do_intrinsic(_invoke,                   java_lang_reflect_Method, invoke_name, object_array_object_object_signature, F_R) \
    8.70    /*   (symbols invoke_name and invoke_signature defined above) */                                                      \
    8.71                                                                                                                          \
    8.72 @@ -945,11 +978,12 @@
    8.73    enum Flags {
    8.74      // AccessFlags syndromes relevant to intrinsics.
    8.75      F_none = 0,
    8.76 -    F_R,                        // !static        !synchronized (R="regular")
    8.77 -    F_S,                        //  static        !synchronized
    8.78 -    F_RN,                       // !static native !synchronized
    8.79 -    F_SN,                       //  static native !synchronized
    8.80 -    F_RNY                       // !static native  synchronized
    8.81 +    F_R,                        // !static ?native !synchronized (R="regular")
    8.82 +    F_S,                        //  static ?native !synchronized
    8.83 +    F_Y,                        // !static ?native  synchronized
    8.84 +    F_RN,                       // !static  native !synchronized
    8.85 +    F_SN,                       //  static  native !synchronized
    8.86 +    F_RNY                       // !static  native  synchronized
    8.87    };
    8.88  
    8.89  public:
     9.1 --- a/src/share/vm/includeDB_compiler2	Fri Nov 27 07:56:58 2009 -0800
     9.2 +++ b/src/share/vm/includeDB_compiler2	Thu Nov 12 09:24:21 2009 -0800
     9.3 @@ -149,6 +149,7 @@
     9.4  c2compiler.hpp                          abstractCompiler.hpp
     9.5  
     9.6  callGenerator.cpp                       addnode.hpp
     9.7 +callGenerator.cpp                       bcEscapeAnalyzer.hpp
     9.8  callGenerator.cpp                       callGenerator.hpp
     9.9  callGenerator.cpp                       callnode.hpp
    9.10  callGenerator.cpp                       cfgnode.hpp
    9.11 @@ -321,6 +322,7 @@
    9.12  compile.cpp                             rootnode.hpp
    9.13  compile.cpp                             runtime.hpp
    9.14  compile.cpp                             signature.hpp
    9.15 +compile.cpp                             stringopts.hpp
    9.16  compile.cpp                             stubRoutines.hpp
    9.17  compile.cpp                             systemDictionary.hpp
    9.18  compile.cpp                             timer.hpp
    9.19 @@ -476,12 +478,16 @@
    9.20  graphKit.cpp                            runtime.hpp
    9.21  graphKit.cpp                            sharedRuntime.hpp
    9.22  
    9.23 +graphKit.hpp                            addnode.hpp
    9.24  graphKit.hpp                            callnode.hpp
    9.25  graphKit.hpp                            cfgnode.hpp
    9.26  graphKit.hpp                            ciEnv.hpp
    9.27 +graphKit.hpp                            divnode.hpp
    9.28  graphKit.hpp                            compile.hpp
    9.29  graphKit.hpp                            deoptimization.hpp
    9.30  graphKit.hpp                            phaseX.hpp
    9.31 +graphKit.hpp                            mulnode.hpp
    9.32 +graphKit.hpp                            subnode.hpp
    9.33  graphKit.hpp                            type.hpp
    9.34  
    9.35  idealKit.cpp                            addnode.hpp
    9.36 @@ -490,7 +496,10 @@
    9.37  idealKit.cpp                            idealKit.hpp
    9.38  idealKit.cpp				runtime.hpp
    9.39  
    9.40 +idealKit.hpp                            addnode.hpp
    9.41 +idealKit.hpp                            cfgnode.hpp
    9.42  idealKit.hpp                            connode.hpp
    9.43 +idealKit.hpp                            divnode.hpp
    9.44  idealKit.hpp                            mulnode.hpp
    9.45  idealKit.hpp                            phaseX.hpp
    9.46  idealKit.hpp                            subnode.hpp
    9.47 @@ -641,6 +650,7 @@
    9.48  macro.cpp                               callnode.hpp
    9.49  macro.cpp                               cfgnode.hpp
    9.50  macro.cpp                               compile.hpp
    9.51 +macro.cpp                              compileLog.hpp
    9.52  macro.cpp                               connode.hpp
    9.53  macro.cpp                               locknode.hpp
    9.54  macro.cpp                               loopnode.hpp
    9.55 @@ -993,6 +1003,21 @@
    9.56  split_if.cpp                            connode.hpp
    9.57  split_if.cpp                            loopnode.hpp
    9.58  
    9.59 +stringopts.hpp                          phaseX.hpp
    9.60 +stringopts.hpp                          node.hpp
    9.61 +
    9.62 +stringopts.cpp                          addnode.hpp
    9.63 +stringopts.cpp                          callnode.hpp
    9.64 +stringopts.cpp                          callGenerator.hpp
    9.65 +stringopts.cpp                          compileLog.hpp
    9.66 +stringopts.cpp                          divnode.hpp
    9.67 +stringopts.cpp                          idealKit.hpp
    9.68 +stringopts.cpp                          graphKit.hpp
    9.69 +stringopts.cpp                          rootnode.hpp
    9.70 +stringopts.cpp                          runtime.hpp
    9.71 +stringopts.cpp                          subnode.hpp
    9.72 +stringopts.cpp                          stringopts.hpp
    9.73 +
    9.74  stubGenerator_<arch_model>.cpp          runtime.hpp
    9.75  
    9.76  stubRoutines.cpp                        runtime.hpp
    10.1 --- a/src/share/vm/includeDB_core	Fri Nov 27 07:56:58 2009 -0800
    10.2 +++ b/src/share/vm/includeDB_core	Thu Nov 12 09:24:21 2009 -0800
    10.3 @@ -570,6 +570,7 @@
    10.4  ciEnv.hpp                               dependencies.hpp
    10.5  ciEnv.hpp                               exceptionHandlerTable.hpp
    10.6  ciEnv.hpp                               oopMap.hpp
    10.7 +ciEnv.hpp                               systemDictionary.hpp
    10.8  ciEnv.hpp                               thread.hpp
    10.9  
   10.10  ciExceptionHandler.cpp                  ciExceptionHandler.hpp
    11.1 --- a/src/share/vm/memory/universe.cpp	Fri Nov 27 07:56:58 2009 -0800
    11.2 +++ b/src/share/vm/memory/universe.cpp	Thu Nov 12 09:24:21 2009 -0800
    11.3 @@ -67,6 +67,8 @@
    11.4  objArrayOop Universe::_the_empty_system_obj_array     = NULL;
    11.5  objArrayOop Universe::_the_empty_class_klass_array    = NULL;
    11.6  objArrayOop Universe::_the_array_interfaces_array     = NULL;
    11.7 +oop Universe::_the_null_string                        = NULL;
    11.8 +oop Universe::_the_min_jint_string                   = NULL;
    11.9  LatestMethodOopCache* Universe::_finalizer_register_cache = NULL;
   11.10  LatestMethodOopCache* Universe::_loader_addClass_cache    = NULL;
   11.11  ActiveMethodOopsCache* Universe::_reflect_invoke_cache    = NULL;
   11.12 @@ -187,6 +189,8 @@
   11.13    f->do_oop((oop*)&_the_empty_system_obj_array);
   11.14    f->do_oop((oop*)&_the_empty_class_klass_array);
   11.15    f->do_oop((oop*)&_the_array_interfaces_array);
   11.16 +  f->do_oop((oop*)&_the_null_string);
   11.17 +  f->do_oop((oop*)&_the_min_jint_string);
   11.18    _finalizer_register_cache->oops_do(f);
   11.19    _loader_addClass_cache->oops_do(f);
   11.20    _reflect_invoke_cache->oops_do(f);
   11.21 @@ -289,6 +293,9 @@
   11.22  
   11.23      klassOop ok = SystemDictionary::object_klass();
   11.24  
   11.25 +    _the_null_string            = StringTable::intern("null", CHECK);
   11.26 +    _the_min_jint_string       = StringTable::intern("-2147483648", CHECK);
   11.27 +
   11.28      if (UseSharedSpaces) {
   11.29        // Verify shared interfaces array.
   11.30        assert(_the_array_interfaces_array->obj_at(0) ==
    12.1 --- a/src/share/vm/memory/universe.hpp	Fri Nov 27 07:56:58 2009 -0800
    12.2 +++ b/src/share/vm/memory/universe.hpp	Thu Nov 12 09:24:21 2009 -0800
    12.3 @@ -169,6 +169,8 @@
    12.4    static objArrayOop  _the_empty_system_obj_array;    // Canonicalized system obj array
    12.5    static objArrayOop  _the_empty_class_klass_array;   // Canonicalized obj array of type java.lang.Class
    12.6    static objArrayOop  _the_array_interfaces_array;    // Canonicalized 2-array of cloneable & serializable klasses
    12.7 +  static oop          _the_null_string;               // A cache of "null" as a Java string
    12.8 +  static oop          _the_min_jint_string;          // A cache of "-2147483648" as a Java string
    12.9    static LatestMethodOopCache* _finalizer_register_cache; // static method for registering finalizable objects
   12.10    static LatestMethodOopCache* _loader_addClass_cache;    // method for registering loaded classes in class loader vector
   12.11    static ActiveMethodOopsCache* _reflect_invoke_cache;    // method for security checks
   12.12 @@ -310,6 +312,8 @@
   12.13    static objArrayOop  the_empty_system_obj_array ()   { return _the_empty_system_obj_array;    }
   12.14    static objArrayOop  the_empty_class_klass_array ()  { return _the_empty_class_klass_array;   }
   12.15    static objArrayOop  the_array_interfaces_array()    { return _the_array_interfaces_array;    }
   12.16 +  static oop          the_null_string()               { return _the_null_string;               }
   12.17 +  static oop          the_min_jint_string()          { return _the_min_jint_string;          }
   12.18    static methodOop    finalizer_register_method()     { return _finalizer_register_cache->get_methodOop(); }
   12.19    static methodOop    loader_addClass_method()        { return _loader_addClass_cache->get_methodOop(); }
   12.20    static ActiveMethodOopsCache* reflect_invoke_cache() { return _reflect_invoke_cache; }
    13.1 --- a/src/share/vm/opto/c2_globals.cpp	Fri Nov 27 07:56:58 2009 -0800
    13.2 +++ b/src/share/vm/opto/c2_globals.cpp	Thu Nov 12 09:24:21 2009 -0800
    13.3 @@ -25,4 +25,4 @@
    13.4  # include "incls/_precompiled.incl"
    13.5  # include "incls/_c2_globals.cpp.incl"
    13.6  
    13.7 -C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_NOTPRODUCT_FLAG)
    13.8 +C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_EXPERIMENTAL_FLAG, MATERIALIZE_NOTPRODUCT_FLAG)
    14.1 --- a/src/share/vm/opto/c2_globals.hpp	Fri Nov 27 07:56:58 2009 -0800
    14.2 +++ b/src/share/vm/opto/c2_globals.hpp	Thu Nov 12 09:24:21 2009 -0800
    14.3 @@ -26,7 +26,7 @@
    14.4  // Defines all globals flags used by the server compiler.
    14.5  //
    14.6  
    14.7 -#define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \
    14.8 +#define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct) \
    14.9                                                                              \
   14.10    notproduct(intx, CompileZapFirst, 0,                                      \
   14.11            "If +ZapDeadCompiledLocals, "                                     \
   14.12 @@ -394,6 +394,12 @@
   14.13    product(bool, UseOptoBiasInlining, true,                                  \
   14.14            "Generate biased locking code in C2 ideal graph")                 \
   14.15                                                                              \
   14.16 +  experimental(bool, OptimizeStringConcat, false,                           \
   14.17 +          "Optimize the construction of Strings by StringBuilder")          \
   14.18 +                                                                            \
   14.19 +  notproduct(bool, PrintOptimizeStringConcat, false,                        \
   14.20 +          "Print information about transformations performed on Strings")   \
   14.21 +                                                                            \
   14.22    product(intx, ValueSearchLimit, 1000,                                     \
   14.23            "Recursion limit in PhaseMacroExpand::value_from_mem_phi")        \
   14.24                                                                              \
   14.25 @@ -413,4 +419,4 @@
   14.26    product(bool, BlockLayoutRotateLoops, true,                               \
   14.27            "Allow back branches to be fall throughs in the block layour")    \
   14.28  
   14.29 -C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG)
   14.30 +C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG)
    15.1 --- a/src/share/vm/opto/callGenerator.cpp	Fri Nov 27 07:56:58 2009 -0800
    15.2 +++ b/src/share/vm/opto/callGenerator.cpp	Thu Nov 12 09:24:21 2009 -0800
    15.3 @@ -98,12 +98,21 @@
    15.4  //---------------------------DirectCallGenerator------------------------------
    15.5  // Internal class which handles all out-of-line calls w/o receiver type checks.
    15.6  class DirectCallGenerator : public CallGenerator {
    15.7 -public:
    15.8 -  DirectCallGenerator(ciMethod* method)
    15.9 -    : CallGenerator(method)
   15.10 + private:
   15.11 +  CallStaticJavaNode* _call_node;
   15.12 +  // Force separate memory and I/O projections for the exceptional
   15.13 +  // paths to facilitate late inlinig.
   15.14 +  bool                _separate_io_proj;
   15.15 +
   15.16 + public:
   15.17 +  DirectCallGenerator(ciMethod* method, bool separate_io_proj)
   15.18 +    : CallGenerator(method),
   15.19 +      _separate_io_proj(separate_io_proj)
   15.20    {
   15.21    }
   15.22    virtual JVMState* generate(JVMState* jvms);
   15.23 +
   15.24 +  CallStaticJavaNode* call_node() const { return _call_node; }
   15.25  };
   15.26  
   15.27  JVMState* DirectCallGenerator::generate(JVMState* jvms) {
   15.28 @@ -129,9 +138,10 @@
   15.29      call->set_optimized_virtual(true);
   15.30    }
   15.31    kit.set_arguments_for_java_call(call);
   15.32 -  kit.set_edges_for_java_call(call);
   15.33 -  Node* ret = kit.set_results_for_java_call(call);
   15.34 +  kit.set_edges_for_java_call(call, false, _separate_io_proj);
   15.35 +  Node* ret = kit.set_results_for_java_call(call, _separate_io_proj);
   15.36    kit.push_node(method()->return_type()->basic_type(), ret);
   15.37 +  _call_node = call;  // Save the call node in case we need it later
   15.38    return kit.transfer_exceptions_into_jvms();
   15.39  }
   15.40  
   15.41 @@ -238,9 +248,9 @@
   15.42    return new ParseGenerator(m, expected_uses, true);
   15.43  }
   15.44  
   15.45 -CallGenerator* CallGenerator::for_direct_call(ciMethod* m) {
   15.46 +CallGenerator* CallGenerator::for_direct_call(ciMethod* m, bool separate_io_proj) {
   15.47    assert(!m->is_abstract(), "for_direct_call mismatch");
   15.48 -  return new DirectCallGenerator(m);
   15.49 +  return new DirectCallGenerator(m, separate_io_proj);
   15.50  }
   15.51  
   15.52  CallGenerator* CallGenerator::for_virtual_call(ciMethod* m, int vtable_index) {
   15.53 @@ -248,6 +258,108 @@
   15.54    return new VirtualCallGenerator(m, vtable_index);
   15.55  }
   15.56  
   15.57 +// Allow inlining decisions to be delayed
   15.58 +class LateInlineCallGenerator : public DirectCallGenerator {
   15.59 +  CallGenerator* _inline_cg;
   15.60 +
   15.61 + public:
   15.62 +  LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
   15.63 +    DirectCallGenerator(method, true), _inline_cg(inline_cg) {}
   15.64 +
   15.65 +  virtual bool      is_late_inline() const { return true; }
   15.66 +
   15.67 +  // Convert the CallStaticJava into an inline
   15.68 +  virtual void do_late_inline();
   15.69 +
   15.70 +  JVMState* generate(JVMState* jvms) {
   15.71 +    // Record that this call site should be revisited once the main
   15.72 +    // parse is finished.
   15.73 +    Compile::current()->add_late_inline(this);
   15.74 +
   15.75 +    // Emit the CallStaticJava and request separate projections so
   15.76 +    // that the late inlining logic can distinguish between fall
   15.77 +    // through and exceptional uses of the memory and io projections
   15.78 +    // as is done for allocations and macro expansion.
   15.79 +    return DirectCallGenerator::generate(jvms);
   15.80 +  }
   15.81 +
   15.82 +};
   15.83 +
   15.84 +
   15.85 +void LateInlineCallGenerator::do_late_inline() {
   15.86 +  // Can't inline it
   15.87 +  if (call_node() == NULL || call_node()->outcnt() == 0 ||
   15.88 +      call_node()->in(0) == NULL || call_node()->in(0)->is_top())
   15.89 +    return;
   15.90 +
   15.91 +  CallStaticJavaNode* call = call_node();
   15.92 +
   15.93 +  // Make a clone of the JVMState that appropriate to use for driving a parse
   15.94 +  Compile* C = Compile::current();
   15.95 +  JVMState* jvms     = call->jvms()->clone_shallow(C);
   15.96 +  uint size = call->req();
   15.97 +  SafePointNode* map = new (C, size) SafePointNode(size, jvms);
   15.98 +  for (uint i1 = 0; i1 < size; i1++) {
   15.99 +    map->init_req(i1, call->in(i1));
  15.100 +  }
  15.101 +
  15.102 +  // Make sure the state is a MergeMem for parsing.
  15.103 +  if (!map->in(TypeFunc::Memory)->is_MergeMem()) {
  15.104 +    map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory)));
  15.105 +  }
  15.106 +
  15.107 +  // Make enough space for the expression stack and transfer the incoming arguments
  15.108 +  int nargs    = method()->arg_size();
  15.109 +  jvms->set_map(map);
  15.110 +  map->ensure_stack(jvms, jvms->method()->max_stack());
  15.111 +  if (nargs > 0) {
  15.112 +    for (int i1 = 0; i1 < nargs; i1++) {
  15.113 +      map->set_req(i1 + jvms->argoff(), call->in(TypeFunc::Parms + i1));
  15.114 +    }
  15.115 +  }
  15.116 +
  15.117 +  CompileLog* log = C->log();
  15.118 +  if (log != NULL) {
  15.119 +    log->head("late_inline method='%d'", log->identify(method()));
  15.120 +    JVMState* p = jvms;
  15.121 +    while (p != NULL) {
  15.122 +      log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
  15.123 +      p = p->caller();
  15.124 +    }
  15.125 +    log->tail("late_inline");
  15.126 +  }
  15.127 +
  15.128 +  // Setup default node notes to be picked up by the inlining
  15.129 +  Node_Notes* old_nn = C->default_node_notes();
  15.130 +  if (old_nn != NULL) {
  15.131 +    Node_Notes* entry_nn = old_nn->clone(C);
  15.132 +    entry_nn->set_jvms(jvms);
  15.133 +    C->set_default_node_notes(entry_nn);
  15.134 +  }
  15.135 +
  15.136 +  // Now perform the inling using the synthesized JVMState
  15.137 +  JVMState* new_jvms = _inline_cg->generate(jvms);
  15.138 +  if (new_jvms == NULL)  return;  // no change
  15.139 +  if (C->failing())      return;
  15.140 +
  15.141 +  // Capture any exceptional control flow
  15.142 +  GraphKit kit(new_jvms);
  15.143 +
  15.144 +  // Find the result object
  15.145 +  Node* result = C->top();
  15.146 +  int   result_size = method()->return_type()->size();
  15.147 +  if (result_size != 0 && !kit.stopped()) {
  15.148 +    result = (result_size == 1) ? kit.pop() : kit.pop_pair();
  15.149 +  }
  15.150 +
  15.151 +  kit.replace_call(call, result);
  15.152 +}
  15.153 +
  15.154 +
  15.155 +CallGenerator* CallGenerator::for_late_inline(ciMethod* method, CallGenerator* inline_cg) {
  15.156 +  return new LateInlineCallGenerator(method, inline_cg);
  15.157 +}
  15.158 +
  15.159  
  15.160  //---------------------------WarmCallGenerator--------------------------------
  15.161  // Internal class which handles initial deferral of inlining decisions.
  15.162 @@ -315,70 +427,7 @@
  15.163  }
  15.164  
  15.165  void WarmCallInfo::make_hot() {
  15.166 -  Compile* C = Compile::current();
  15.167 -  // Replace the callnode with something better.
  15.168 -  CallJavaNode* call = this->call()->as_CallJava();
  15.169 -  ciMethod* method   = call->method();
  15.170 -  int       nargs    = method->arg_size();
  15.171 -  JVMState* jvms     = call->jvms()->clone_shallow(C);
  15.172 -  uint size = TypeFunc::Parms + MAX2(2, nargs);
  15.173 -  SafePointNode* map = new (C, size) SafePointNode(size, jvms);
  15.174 -  for (uint i1 = 0; i1 < (uint)(TypeFunc::Parms + nargs); i1++) {
  15.175 -    map->init_req(i1, call->in(i1));
  15.176 -  }
  15.177 -  jvms->set_map(map);
  15.178 -  jvms->set_offsets(map->req());
  15.179 -  jvms->set_locoff(TypeFunc::Parms);
  15.180 -  jvms->set_stkoff(TypeFunc::Parms);
  15.181 -  GraphKit kit(jvms);
  15.182 -
  15.183 -  JVMState* new_jvms = _hot_cg->generate(kit.jvms());
  15.184 -  if (new_jvms == NULL)  return;  // no change
  15.185 -  if (C->failing())      return;
  15.186 -
  15.187 -  kit.set_jvms(new_jvms);
  15.188 -  Node* res = C->top();
  15.189 -  int   res_size = method->return_type()->size();
  15.190 -  if (res_size != 0) {
  15.191 -    kit.inc_sp(-res_size);
  15.192 -    res = kit.argument(0);
  15.193 -  }
  15.194 -  GraphKit ekit(kit.combine_and_pop_all_exception_states()->jvms());
  15.195 -
  15.196 -  // Replace the call:
  15.197 -  for (DUIterator i = call->outs(); call->has_out(i); i++) {
  15.198 -    Node* n = call->out(i);
  15.199 -    Node* nn = NULL;  // replacement
  15.200 -    if (n->is_Proj()) {
  15.201 -      ProjNode* nproj = n->as_Proj();
  15.202 -      assert(nproj->_con < (uint)(TypeFunc::Parms + (res_size ? 1 : 0)), "sane proj");
  15.203 -      if (nproj->_con == TypeFunc::Parms) {
  15.204 -        nn = res;
  15.205 -      } else {
  15.206 -        nn = kit.map()->in(nproj->_con);
  15.207 -      }
  15.208 -      if (nproj->_con == TypeFunc::I_O) {
  15.209 -        for (DUIterator j = nproj->outs(); nproj->has_out(j); j++) {
  15.210 -          Node* e = nproj->out(j);
  15.211 -          if (e->Opcode() == Op_CreateEx) {
  15.212 -            e->replace_by(ekit.argument(0));
  15.213 -          } else if (e->Opcode() == Op_Catch) {
  15.214 -            for (DUIterator k = e->outs(); e->has_out(k); k++) {
  15.215 -              CatchProjNode* p = e->out(j)->as_CatchProj();
  15.216 -              if (p->is_handler_proj()) {
  15.217 -                p->replace_by(ekit.control());
  15.218 -              } else {
  15.219 -                p->replace_by(kit.control());
  15.220 -              }
  15.221 -            }
  15.222 -          }
  15.223 -        }
  15.224 -      }
  15.225 -    }
  15.226 -    NOT_PRODUCT(if (!nn)  n->dump(2));
  15.227 -    assert(nn != NULL, "don't know what to do with this user");
  15.228 -    n->replace_by(nn);
  15.229 -  }
  15.230 +  Unimplemented();
  15.231  }
  15.232  
  15.233  void WarmCallInfo::make_cold() {
    16.1 --- a/src/share/vm/opto/callGenerator.hpp	Fri Nov 27 07:56:58 2009 -0800
    16.2 +++ b/src/share/vm/opto/callGenerator.hpp	Thu Nov 12 09:24:21 2009 -0800
    16.3 @@ -57,6 +57,13 @@
    16.4    // is_trap: Does not return to the caller.  (E.g., uncommon trap.)
    16.5    virtual bool      is_trap() const             { return false; }
    16.6  
    16.7 +  // is_late_inline: supports conversion of call into an inline
    16.8 +  virtual bool      is_late_inline() const      { return false; }
    16.9 +  // Replace the call with an inline version of the code
   16.10 +  virtual void do_late_inline() { ShouldNotReachHere(); }
   16.11 +
   16.12 +  virtual CallStaticJavaNode* call_node() const { ShouldNotReachHere(); return NULL; }
   16.13 +
   16.14    // Note:  It is possible for a CG to be both inline and virtual.
   16.15    // (The hashCode intrinsic does a vtable check and an inlined fast path.)
   16.16  
   16.17 @@ -92,9 +99,12 @@
   16.18    static CallGenerator* for_osr(ciMethod* m, int osr_bci);
   16.19  
   16.20    // How to generate vanilla out-of-line call sites:
   16.21 -  static CallGenerator* for_direct_call(ciMethod* m);   // static, special
   16.22 +  static CallGenerator* for_direct_call(ciMethod* m, bool separate_io_projs = false);   // static, special
   16.23    static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index);  // virtual, interface
   16.24  
   16.25 +  // How to generate a replace a direct call with an inline version
   16.26 +  static CallGenerator* for_late_inline(ciMethod* m, CallGenerator* inline_cg);
   16.27 +
   16.28    // How to make a call but defer the decision whether to inline or not.
   16.29    static CallGenerator* for_warm_call(WarmCallInfo* ci,
   16.30                                        CallGenerator* if_cold,
    17.1 --- a/src/share/vm/opto/callnode.cpp	Fri Nov 27 07:56:58 2009 -0800
    17.2 +++ b/src/share/vm/opto/callnode.cpp	Thu Nov 12 09:24:21 2009 -0800
    17.3 @@ -693,6 +693,84 @@
    17.4  }
    17.5  
    17.6  
    17.7 +void CallNode::extract_projections(CallProjections* projs, bool separate_io_proj) {
    17.8 +  projs->fallthrough_proj      = NULL;
    17.9 +  projs->fallthrough_catchproj = NULL;
   17.10 +  projs->fallthrough_ioproj    = NULL;
   17.11 +  projs->catchall_ioproj       = NULL;
   17.12 +  projs->catchall_catchproj    = NULL;
   17.13 +  projs->fallthrough_memproj   = NULL;
   17.14 +  projs->catchall_memproj      = NULL;
   17.15 +  projs->resproj               = NULL;
   17.16 +  projs->exobj                 = NULL;
   17.17 +
   17.18 +  for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) {
   17.19 +    ProjNode *pn = fast_out(i)->as_Proj();
   17.20 +    if (pn->outcnt() == 0) continue;
   17.21 +    switch (pn->_con) {
   17.22 +    case TypeFunc::Control:
   17.23 +      {
   17.24 +        // For Control (fallthrough) and I_O (catch_all_index) we have CatchProj -> Catch -> Proj
   17.25 +        projs->fallthrough_proj = pn;
   17.26 +        DUIterator_Fast jmax, j = pn->fast_outs(jmax);
   17.27 +        const Node *cn = pn->fast_out(j);
   17.28 +        if (cn->is_Catch()) {
   17.29 +          ProjNode *cpn = NULL;
   17.30 +          for (DUIterator_Fast kmax, k = cn->fast_outs(kmax); k < kmax; k++) {
   17.31 +            cpn = cn->fast_out(k)->as_Proj();
   17.32 +            assert(cpn->is_CatchProj(), "must be a CatchProjNode");
   17.33 +            if (cpn->_con == CatchProjNode::fall_through_index)
   17.34 +              projs->fallthrough_catchproj = cpn;
   17.35 +            else {
   17.36 +              assert(cpn->_con == CatchProjNode::catch_all_index, "must be correct index.");
   17.37 +              projs->catchall_catchproj = cpn;
   17.38 +            }
   17.39 +          }
   17.40 +        }
   17.41 +        break;
   17.42 +      }
   17.43 +    case TypeFunc::I_O:
   17.44 +      if (pn->_is_io_use)
   17.45 +        projs->catchall_ioproj = pn;
   17.46 +      else
   17.47 +        projs->fallthrough_ioproj = pn;
   17.48 +      for (DUIterator j = pn->outs(); pn->has_out(j); j++) {
   17.49 +        Node* e = pn->out(j);
   17.50 +        if (e->Opcode() == Op_CreateEx && e->in(0)->is_CatchProj()) {
   17.51 +          assert(projs->exobj == NULL, "only one");
   17.52 +          projs->exobj = e;
   17.53 +        }
   17.54 +      }
   17.55 +      break;
   17.56 +    case TypeFunc::Memory:
   17.57 +      if (pn->_is_io_use)
   17.58 +        projs->catchall_memproj = pn;
   17.59 +      else
   17.60 +        projs->fallthrough_memproj = pn;
   17.61 +      break;
   17.62 +    case TypeFunc::Parms:
   17.63 +      projs->resproj = pn;
   17.64 +      break;
   17.65 +    default:
   17.66 +      assert(false, "unexpected projection from allocation node.");
   17.67 +    }
   17.68 +  }
   17.69 +
   17.70 +  // The resproj may not exist because the result couuld be ignored
   17.71 +  // and the exception object may not exist if an exception handler
   17.72 +  // swallows the exception but all the other must exist and be found.
   17.73 +  assert(projs->fallthrough_proj      != NULL, "must be found");
   17.74 +  assert(projs->fallthrough_catchproj != NULL, "must be found");
   17.75 +  assert(projs->fallthrough_memproj   != NULL, "must be found");
   17.76 +  assert(projs->fallthrough_ioproj    != NULL, "must be found");
   17.77 +  assert(projs->catchall_catchproj    != NULL, "must be found");
   17.78 +  if (separate_io_proj) {
   17.79 +    assert(projs->catchall_memproj      != NULL, "must be found");
   17.80 +    assert(projs->catchall_ioproj       != NULL, "must be found");
   17.81 +  }
   17.82 +}
   17.83 +
   17.84 +
   17.85  //=============================================================================
   17.86  uint CallJavaNode::size_of() const { return sizeof(*this); }
   17.87  uint CallJavaNode::cmp( const Node &n ) const {
    18.1 --- a/src/share/vm/opto/callnode.hpp	Fri Nov 27 07:56:58 2009 -0800
    18.2 +++ b/src/share/vm/opto/callnode.hpp	Thu Nov 12 09:24:21 2009 -0800
    18.3 @@ -470,6 +470,23 @@
    18.4  #endif
    18.5  };
    18.6  
    18.7 +
    18.8 +// Simple container for the outgoing projections of a call.  Useful
    18.9 +// for serious surgery on calls.
   18.10 +class CallProjections : public StackObj {
   18.11 +public:
   18.12 +  Node* fallthrough_proj;
   18.13 +  Node* fallthrough_catchproj;
   18.14 +  Node* fallthrough_memproj;
   18.15 +  Node* fallthrough_ioproj;
   18.16 +  Node* catchall_catchproj;
   18.17 +  Node* catchall_memproj;
   18.18 +  Node* catchall_ioproj;
   18.19 +  Node* resproj;
   18.20 +  Node* exobj;
   18.21 +};
   18.22 +
   18.23 +
   18.24  //------------------------------CallNode---------------------------------------
   18.25  // Call nodes now subsume the function of debug nodes at callsites, so they
   18.26  // contain the functionality of a full scope chain of debug nodes.
   18.27 @@ -521,6 +538,11 @@
   18.28    // or returns NULL if there is no one.
   18.29    Node *result_cast();
   18.30  
   18.31 +  // Collect all the interesting edges from a call for use in
   18.32 +  // replacing the call by something else.  Used by macro expansion
   18.33 +  // and the late inlining support.
   18.34 +  void extract_projections(CallProjections* projs, bool separate_io_proj);
   18.35 +
   18.36    virtual uint match_edge(uint idx) const;
   18.37  
   18.38  #ifndef PRODUCT
   18.39 @@ -529,6 +551,7 @@
   18.40  #endif
   18.41  };
   18.42  
   18.43 +
   18.44  //------------------------------CallJavaNode-----------------------------------
   18.45  // Make a static or dynamic subroutine call node using Java calling
   18.46  // convention.  (The "Java" calling convention is the compiler's calling
    19.1 --- a/src/share/vm/opto/compile.cpp	Fri Nov 27 07:56:58 2009 -0800
    19.2 +++ b/src/share/vm/opto/compile.cpp	Thu Nov 12 09:24:21 2009 -0800
    19.3 @@ -224,6 +224,32 @@
    19.4  }
    19.5  
    19.6  
    19.7 +void Compile::gvn_replace_by(Node* n, Node* nn) {
    19.8 +  for (DUIterator_Last imin, i = n->last_outs(imin); i >= imin; ) {
    19.9 +    Node* use = n->last_out(i);
   19.10 +    bool is_in_table = initial_gvn()->hash_delete(use);
   19.11 +    uint uses_found = 0;
   19.12 +    for (uint j = 0; j < use->len(); j++) {
   19.13 +      if (use->in(j) == n) {
   19.14 +        if (j < use->req())
   19.15 +          use->set_req(j, nn);
   19.16 +        else
   19.17 +          use->set_prec(j, nn);
   19.18 +        uses_found++;
   19.19 +      }
   19.20 +    }
   19.21 +    if (is_in_table) {
   19.22 +      // reinsert into table
   19.23 +      initial_gvn()->hash_find_insert(use);
   19.24 +    }
   19.25 +    record_for_igvn(use);
   19.26 +    i -= uses_found;    // we deleted 1 or more copies of this edge
   19.27 +  }
   19.28 +}
   19.29 +
   19.30 +
   19.31 +
   19.32 +
   19.33  // Identify all nodes that are reachable from below, useful.
   19.34  // Use breadth-first pass that records state in a Unique_Node_List,
   19.35  // recursive traversal is slower.
   19.36 @@ -554,6 +580,28 @@
   19.37        rethrow_exceptions(kit.transfer_exceptions_into_jvms());
   19.38      }
   19.39  
   19.40 +    if (!failing() && has_stringbuilder()) {
   19.41 +      {
   19.42 +        // remove useless nodes to make the usage analysis simpler
   19.43 +        ResourceMark rm;
   19.44 +        PhaseRemoveUseless pru(initial_gvn(), &for_igvn);
   19.45 +      }
   19.46 +
   19.47 +      {
   19.48 +        ResourceMark rm;
   19.49 +        print_method("Before StringOpts", 3);
   19.50 +        PhaseStringOpts pso(initial_gvn(), &for_igvn);
   19.51 +        print_method("After StringOpts", 3);
   19.52 +      }
   19.53 +
   19.54 +      // now inline anything that we skipped the first time around
   19.55 +      while (_late_inlines.length() > 0) {
   19.56 +        CallGenerator* cg = _late_inlines.pop();
   19.57 +        cg->do_late_inline();
   19.58 +      }
   19.59 +    }
   19.60 +    assert(_late_inlines.length() == 0, "should have been processed");
   19.61 +
   19.62      print_method("Before RemoveUseless", 3);
   19.63  
   19.64      // Remove clutter produced by parsing.
   19.65 @@ -820,6 +868,7 @@
   19.66    _fixed_slots = 0;
   19.67    set_has_split_ifs(false);
   19.68    set_has_loops(has_method() && method()->has_loops()); // first approximation
   19.69 +  set_has_stringbuilder(false);
   19.70    _deopt_happens = true;  // start out assuming the worst
   19.71    _trap_can_recompile = false;  // no traps emitted yet
   19.72    _major_progress = true; // start out assuming good things will happen
   19.73 @@ -2240,6 +2289,30 @@
   19.74      break;
   19.75    }
   19.76  
   19.77 +  case Op_Proj: {
   19.78 +    if (OptimizeStringConcat) {
   19.79 +      ProjNode* p = n->as_Proj();
   19.80 +      if (p->_is_io_use) {
   19.81 +        // Separate projections were used for the exception path which
   19.82 +        // are normally removed by a late inline.  If it wasn't inlined
   19.83 +        // then they will hang around and should just be replaced with
   19.84 +        // the original one.
   19.85 +        Node* proj = NULL;
   19.86 +        // Replace with just one
   19.87 +        for (SimpleDUIterator i(p->in(0)); i.has_next(); i.next()) {
   19.88 +          Node *use = i.get();
   19.89 +          if (use->is_Proj() && p != use && use->as_Proj()->_con == p->_con) {
   19.90 +            proj = use;
   19.91 +            break;
   19.92 +          }
   19.93 +        }
   19.94 +        assert(p != NULL, "must be found");
   19.95 +        p->subsume_by(proj);
   19.96 +      }
   19.97 +    }
   19.98 +    break;
   19.99 +  }
  19.100 +
  19.101    case Op_Phi:
  19.102      if (n->as_Phi()->bottom_type()->isa_narrowoop()) {
  19.103        // The EncodeP optimization may create Phi with the same edges
    20.1 --- a/src/share/vm/opto/compile.hpp	Fri Nov 27 07:56:58 2009 -0800
    20.2 +++ b/src/share/vm/opto/compile.hpp	Thu Nov 12 09:24:21 2009 -0800
    20.3 @@ -149,6 +149,7 @@
    20.4    bool                  _has_loops;             // True if the method _may_ have some loops
    20.5    bool                  _has_split_ifs;         // True if the method _may_ have some split-if
    20.6    bool                  _has_unsafe_access;     // True if the method _may_ produce faults in unsafe loads or stores.
    20.7 +  bool                  _has_stringbuilder;     // True StringBuffers or StringBuilders are allocated
    20.8    uint                  _trap_hist[trapHistLength];  // Cumulative traps
    20.9    bool                  _trap_can_recompile;    // Have we emitted a recompiling trap?
   20.10    uint                  _decompile_count;       // Cumulative decompilation counts.
   20.11 @@ -219,6 +220,9 @@
   20.12    Unique_Node_List*     _for_igvn;              // Initial work-list for next round of Iterative GVN
   20.13    WarmCallInfo*         _warm_calls;            // Sorted work-list for heat-based inlining.
   20.14  
   20.15 +  GrowableArray<CallGenerator*> _late_inlines;  // List of CallGenerators to be revisited after
   20.16 +                                                // main parsing has finished.
   20.17 +
   20.18    // Matching, CFG layout, allocation, code generation
   20.19    PhaseCFG*             _cfg;                   // Results of CFG finding
   20.20    bool                  _select_24_bit_instr;   // We selected an instruction with a 24-bit result
   20.21 @@ -298,6 +302,8 @@
   20.22    void          set_has_split_ifs(bool z)       { _has_split_ifs = z; }
   20.23    bool              has_unsafe_access() const   { return _has_unsafe_access; }
   20.24    void          set_has_unsafe_access(bool z)   { _has_unsafe_access = z; }
   20.25 +  bool              has_stringbuilder() const   { return _has_stringbuilder; }
   20.26 +  void          set_has_stringbuilder(bool z)   { _has_stringbuilder = z; }
   20.27    void          set_trap_count(uint r, uint c)  { assert(r < trapHistLength, "oob");        _trap_hist[r] = c; }
   20.28    uint              trap_count(uint r) const    { assert(r < trapHistLength, "oob"); return _trap_hist[r]; }
   20.29    bool              trap_can_recompile() const  { return _trap_can_recompile; }
   20.30 @@ -475,6 +481,7 @@
   20.31    // Decide how to build a call.
   20.32    // The profile factor is a discount to apply to this site's interp. profile.
   20.33    CallGenerator*    call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, JVMState* jvms, bool allow_inline, float profile_factor);
   20.34 +  bool should_delay_inlining(ciMethod* call_method, JVMState* jvms);
   20.35  
   20.36    // Report if there were too many traps at a current method and bci.
   20.37    // Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded.
   20.38 @@ -495,6 +502,11 @@
   20.39    void          set_initial_gvn(PhaseGVN *gvn)           { _initial_gvn = gvn; }
   20.40    void          set_for_igvn(Unique_Node_List *for_igvn) { _for_igvn = for_igvn; }
   20.41  
   20.42 +  // Replace n by nn using initial_gvn, calling hash_delete and
   20.43 +  // record_for_igvn as needed.
   20.44 +  void gvn_replace_by(Node* n, Node* nn);
   20.45 +
   20.46 +
   20.47    void              identify_useful_nodes(Unique_Node_List &useful);
   20.48    void              remove_useless_nodes  (Unique_Node_List &useful);
   20.49  
   20.50 @@ -502,6 +514,9 @@
   20.51    void          set_warm_calls(WarmCallInfo* l) { _warm_calls = l; }
   20.52    WarmCallInfo* pop_warm_call();
   20.53  
   20.54 +  // Record this CallGenerator for inlining at the end of parsing.
   20.55 +  void              add_late_inline(CallGenerator* cg) { _late_inlines.push(cg); }
   20.56 +
   20.57    // Matching, CFG layout, allocation, code generation
   20.58    PhaseCFG*         cfg()                       { return _cfg; }
   20.59    bool              select_24_bit_instr() const { return _select_24_bit_instr; }
    21.1 --- a/src/share/vm/opto/doCall.cpp	Fri Nov 27 07:56:58 2009 -0800
    21.2 +++ b/src/share/vm/opto/doCall.cpp	Thu Nov 12 09:24:21 2009 -0800
    21.3 @@ -128,6 +128,12 @@
    21.4  
    21.5        if (allow_inline) {
    21.6          CallGenerator* cg = CallGenerator::for_inline(call_method, expected_uses);
    21.7 +        if (require_inline && cg != NULL && should_delay_inlining(call_method, jvms)) {
    21.8 +          // Delay the inlining of this method to give us the
    21.9 +          // opportunity to perform some high level optimizations
   21.10 +          // first.
   21.11 +          return CallGenerator::for_late_inline(call_method, cg);
   21.12 +        }
   21.13          if (cg == NULL) {
   21.14            // Fall through.
   21.15          } else if (require_inline || !InlineWarmCalls) {
   21.16 @@ -225,10 +231,63 @@
   21.17    } else {
   21.18      // Class Hierarchy Analysis or Type Profile reveals a unique target,
   21.19      // or it is a static or special call.
   21.20 -    return CallGenerator::for_direct_call(call_method);
   21.21 +    return CallGenerator::for_direct_call(call_method, should_delay_inlining(call_method, jvms));
   21.22    }
   21.23  }
   21.24  
   21.25 +// Return true for methods that shouldn't be inlined early so that
   21.26 +// they are easier to analyze and optimize as intrinsics.
   21.27 +bool Compile::should_delay_inlining(ciMethod* call_method, JVMState* jvms) {
   21.28 +  if (has_stringbuilder()) {
   21.29 +
   21.30 +    if ((call_method->holder() == C->env()->StringBuilder_klass() ||
   21.31 +         call_method->holder() == C->env()->StringBuffer_klass()) &&
   21.32 +        (jvms->method()->holder() == C->env()->StringBuilder_klass() ||
   21.33 +         jvms->method()->holder() == C->env()->StringBuffer_klass())) {
   21.34 +      // Delay SB calls only when called from non-SB code
   21.35 +      return false;
   21.36 +    }
   21.37 +
   21.38 +    switch (call_method->intrinsic_id()) {
   21.39 +      case vmIntrinsics::_StringBuilder_void:
   21.40 +      case vmIntrinsics::_StringBuilder_int:
   21.41 +      case vmIntrinsics::_StringBuilder_String:
   21.42 +      case vmIntrinsics::_StringBuilder_append_char:
   21.43 +      case vmIntrinsics::_StringBuilder_append_int:
   21.44 +      case vmIntrinsics::_StringBuilder_append_String:
   21.45 +      case vmIntrinsics::_StringBuilder_toString:
   21.46 +      case vmIntrinsics::_StringBuffer_void:
   21.47 +      case vmIntrinsics::_StringBuffer_int:
   21.48 +      case vmIntrinsics::_StringBuffer_String:
   21.49 +      case vmIntrinsics::_StringBuffer_append_char:
   21.50 +      case vmIntrinsics::_StringBuffer_append_int:
   21.51 +      case vmIntrinsics::_StringBuffer_append_String:
   21.52 +      case vmIntrinsics::_StringBuffer_toString:
   21.53 +      case vmIntrinsics::_Integer_toString:
   21.54 +        return true;
   21.55 +
   21.56 +      case vmIntrinsics::_String_String:
   21.57 +        {
   21.58 +          Node* receiver = jvms->map()->in(jvms->argoff() + 1);
   21.59 +          if (receiver->is_Proj() && receiver->in(0)->is_CallStaticJava()) {
   21.60 +            CallStaticJavaNode* csj = receiver->in(0)->as_CallStaticJava();
   21.61 +            ciMethod* m = csj->method();
   21.62 +            if (m != NULL &&
   21.63 +                (m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString ||
   21.64 +                 m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString))
   21.65 +              // Delay String.<init>(new SB())
   21.66 +              return true;
   21.67 +          }
   21.68 +          return false;
   21.69 +        }
   21.70 +
   21.71 +      default:
   21.72 +        return false;
   21.73 +    }
   21.74 +  }
   21.75 +  return false;
   21.76 +}
   21.77 +
   21.78  
   21.79  // uncommon-trap call-sites where callee is unloaded, uninitialized or will not link
   21.80  bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* klass) {
    22.1 --- a/src/share/vm/opto/graphKit.cpp	Fri Nov 27 07:56:58 2009 -0800
    22.2 +++ b/src/share/vm/opto/graphKit.cpp	Thu Nov 12 09:24:21 2009 -0800
    22.3 @@ -1351,8 +1351,8 @@
    22.4  }
    22.5  
    22.6  //------------------------------set_all_memory_call----------------------------
    22.7 -void GraphKit::set_all_memory_call(Node* call) {
    22.8 -  Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) );
    22.9 +void GraphKit::set_all_memory_call(Node* call, bool separate_io_proj) {
   22.10 +  Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory, separate_io_proj) );
   22.11    set_all_memory(newmem);
   22.12  }
   22.13  
   22.14 @@ -1573,7 +1573,7 @@
   22.15  //---------------------------set_edges_for_java_call---------------------------
   22.16  // Connect a newly created call into the current JVMS.
   22.17  // A return value node (if any) is returned from set_edges_for_java_call.
   22.18 -void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw) {
   22.19 +void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw, bool separate_io_proj) {
   22.20  
   22.21    // Add the predefined inputs:
   22.22    call->init_req( TypeFunc::Control, control() );
   22.23 @@ -1595,13 +1595,13 @@
   22.24    // Re-use the current map to produce the result.
   22.25  
   22.26    set_control(_gvn.transform(new (C, 1) ProjNode(call, TypeFunc::Control)));
   22.27 -  set_i_o(    _gvn.transform(new (C, 1) ProjNode(call, TypeFunc::I_O    )));
   22.28 -  set_all_memory_call(xcall);
   22.29 +  set_i_o(    _gvn.transform(new (C, 1) ProjNode(call, TypeFunc::I_O    , separate_io_proj)));
   22.30 +  set_all_memory_call(xcall, separate_io_proj);
   22.31  
   22.32    //return xcall;   // no need, caller already has it
   22.33  }
   22.34  
   22.35 -Node* GraphKit::set_results_for_java_call(CallJavaNode* call) {
   22.36 +Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_proj) {
   22.37    if (stopped())  return top();  // maybe the call folded up?
   22.38  
   22.39    // Capture the return value, if any.
   22.40 @@ -1614,8 +1614,15 @@
   22.41    // Note:  Since any out-of-line call can produce an exception,
   22.42    // we always insert an I_O projection from the call into the result.
   22.43  
   22.44 -  make_slow_call_ex(call, env()->Throwable_klass(), false);
   22.45 -
   22.46 +  make_slow_call_ex(call, env()->Throwable_klass(), separate_io_proj);
   22.47 +
   22.48 +  if (separate_io_proj) {
   22.49 +    // The caller requested separate projections be used by the fall
   22.50 +    // through and exceptional paths, so replace the projections for
   22.51 +    // the fall through path.
   22.52 +    set_i_o(_gvn.transform( new (C, 1) ProjNode(call, TypeFunc::I_O) ));
   22.53 +    set_all_memory(_gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) ));
   22.54 +  }
   22.55    return ret;
   22.56  }
   22.57  
   22.58 @@ -1678,6 +1685,59 @@
   22.59    }
   22.60  }
   22.61  
   22.62 +
   22.63 +// Replace the call with the current state of the kit.
   22.64 +void GraphKit::replace_call(CallNode* call, Node* result) {
   22.65 +  JVMState* ejvms = NULL;
   22.66 +  if (has_exceptions()) {
   22.67 +    ejvms = transfer_exceptions_into_jvms();
   22.68 +  }
   22.69 +
   22.70 +  SafePointNode* final_state = stop();
   22.71 +
   22.72 +  // Find all the needed outputs of this call
   22.73 +  CallProjections callprojs;
   22.74 +  call->extract_projections(&callprojs, true);
   22.75 +
   22.76 +  // Replace all the old call edges with the edges from the inlining result
   22.77 +  C->gvn_replace_by(callprojs.fallthrough_catchproj, final_state->in(TypeFunc::Control));
   22.78 +  C->gvn_replace_by(callprojs.fallthrough_memproj,   final_state->in(TypeFunc::Memory));
   22.79 +  C->gvn_replace_by(callprojs.fallthrough_ioproj,    final_state->in(TypeFunc::I_O));
   22.80 +
   22.81 +  // Replace the result with the new result if it exists and is used
   22.82 +  if (callprojs.resproj != NULL && result != NULL) {
   22.83 +    C->gvn_replace_by(callprojs.resproj, result);
   22.84 +  }
   22.85 +
   22.86 +  if (ejvms == NULL) {
   22.87 +    // No exception edges to simply kill off those paths
   22.88 +    C->gvn_replace_by(callprojs.catchall_catchproj, C->top());
   22.89 +    C->gvn_replace_by(callprojs.catchall_memproj,   C->top());
   22.90 +    C->gvn_replace_by(callprojs.catchall_ioproj,    C->top());
   22.91 +  } else {
   22.92 +    GraphKit ekit(ejvms);
   22.93 +
   22.94 +    // Load my combined exception state into the kit, with all phis transformed:
   22.95 +    SafePointNode* ex_map = ekit.combine_and_pop_all_exception_states();
   22.96 +
   22.97 +    Node* ex_oop = ekit.use_exception_state(ex_map);
   22.98 +
   22.99 +    C->gvn_replace_by(callprojs.catchall_catchproj, ekit.control());
  22.100 +    C->gvn_replace_by(callprojs.catchall_memproj,   ekit.reset_memory());
  22.101 +    C->gvn_replace_by(callprojs.catchall_ioproj,    ekit.i_o());
  22.102 +
  22.103 +    // Replace the old exception object with the newly created one
  22.104 +    if (callprojs.exobj != NULL) {
  22.105 +      C->gvn_replace_by(callprojs.exobj, ex_oop);
  22.106 +    }
  22.107 +  }
  22.108 +
  22.109 +  // Disconnect the call from the graph
  22.110 +  call->disconnect_inputs(NULL);
  22.111 +  C->gvn_replace_by(call, C->top());
  22.112 +}
  22.113 +
  22.114 +
  22.115  //------------------------------increment_counter------------------------------
  22.116  // for statistics: increment a VM counter by 1
  22.117  
  22.118 @@ -3459,4 +3519,3 @@
  22.119    sync_kit(ideal);
  22.120  }
  22.121  #undef __
  22.122 -
    23.1 --- a/src/share/vm/opto/graphKit.hpp	Fri Nov 27 07:56:58 2009 -0800
    23.2 +++ b/src/share/vm/opto/graphKit.hpp	Thu Nov 12 09:24:21 2009 -0800
    23.3 @@ -279,6 +279,34 @@
    23.4    }
    23.5    Node* basic_plus_adr(Node* base, Node* ptr, Node* offset);
    23.6  
    23.7 +
    23.8 +  // Some convenient shortcuts for common nodes
    23.9 +  Node* IfTrue(IfNode* iff)                   { return _gvn.transform(new (C,1) IfTrueNode(iff));      }
   23.10 +  Node* IfFalse(IfNode* iff)                  { return _gvn.transform(new (C,1) IfFalseNode(iff));     }
   23.11 +
   23.12 +  Node* AddI(Node* l, Node* r)                { return _gvn.transform(new (C,3) AddINode(l, r));       }
   23.13 +  Node* SubI(Node* l, Node* r)                { return _gvn.transform(new (C,3) SubINode(l, r));       }
   23.14 +  Node* MulI(Node* l, Node* r)                { return _gvn.transform(new (C,3) MulINode(l, r));       }
   23.15 +  Node* DivI(Node* ctl, Node* l, Node* r)     { return _gvn.transform(new (C,3) DivINode(ctl, l, r));  }
   23.16 +
   23.17 +  Node* AndI(Node* l, Node* r)                { return _gvn.transform(new (C,3) AndINode(l, r));       }
   23.18 +  Node* OrI(Node* l, Node* r)                 { return _gvn.transform(new (C,3) OrINode(l, r));        }
   23.19 +  Node* XorI(Node* l, Node* r)                { return _gvn.transform(new (C,3) XorINode(l, r));       }
   23.20 +
   23.21 +  Node* MaxI(Node* l, Node* r)                { return _gvn.transform(new (C,3) MaxINode(l, r));       }
   23.22 +  Node* MinI(Node* l, Node* r)                { return _gvn.transform(new (C,3) MinINode(l, r));       }
   23.23 +
   23.24 +  Node* LShiftI(Node* l, Node* r)             { return _gvn.transform(new (C,3) LShiftINode(l, r));    }
   23.25 +  Node* RShiftI(Node* l, Node* r)             { return _gvn.transform(new (C,3) RShiftINode(l, r));    }
   23.26 +  Node* URShiftI(Node* l, Node* r)            { return _gvn.transform(new (C,3) URShiftINode(l, r));   }
   23.27 +
   23.28 +  Node* CmpI(Node* l, Node* r)                { return _gvn.transform(new (C,3) CmpINode(l, r));       }
   23.29 +  Node* CmpL(Node* l, Node* r)                { return _gvn.transform(new (C,3) CmpLNode(l, r));       }
   23.30 +  Node* CmpP(Node* l, Node* r)                { return _gvn.transform(new (C,3) CmpPNode(l, r));       }
   23.31 +  Node* Bool(Node* cmp, BoolTest::mask relop) { return _gvn.transform(new (C,2) BoolNode(cmp, relop)); }
   23.32 +
   23.33 +  Node* AddP(Node* b, Node* a, Node* o)       { return _gvn.transform(new (C,4) AddPNode(b, a, o));    }
   23.34 +
   23.35    // Convert between int and long, and size_t.
   23.36    // (See macros ConvI2X, etc., in type.hpp for ConvI2X, etc.)
   23.37    Node* ConvI2L(Node* offset);
   23.38 @@ -400,7 +428,7 @@
   23.39    void set_all_memory(Node* newmem);
   23.40  
   23.41    // Create a memory projection from the call, then set_all_memory.
   23.42 -  void set_all_memory_call(Node* call);
   23.43 +  void set_all_memory_call(Node* call, bool separate_io_proj = false);
   23.44  
   23.45    // Create a LoadNode, reading from the parser's memory state.
   23.46    // (Note:  require_atomic_access is useful only with T_LONG.)
   23.47 @@ -543,12 +571,12 @@
   23.48    // Transform the call, and update the basics: control, i_o, memory.
   23.49    // (The next step is usually to call set_results_for_java_call.)
   23.50    void set_edges_for_java_call(CallJavaNode* call,
   23.51 -                               bool must_throw = false);
   23.52 +                               bool must_throw = false, bool separate_io_proj = false);
   23.53  
   23.54    // Finish up a java call that was started by set_edges_for_java_call.
   23.55    // Call add_exception on any throw arising from the call.
   23.56    // Return the call result (transformed).
   23.57 -  Node* set_results_for_java_call(CallJavaNode* call);
   23.58 +  Node* set_results_for_java_call(CallJavaNode* call, bool separate_io_proj = false);
   23.59  
   23.60    // Similar to set_edges_for_java_call, but simplified for runtime calls.
   23.61    void  set_predefined_output_for_runtime_call(Node* call) {
   23.62 @@ -559,6 +587,11 @@
   23.63                                                 const TypePtr* hook_mem);
   23.64    Node* set_predefined_input_for_runtime_call(SafePointNode* call);
   23.65  
   23.66 +  // Replace the call with the current state of the kit.  Requires
   23.67 +  // that the call was generated with separate io_projs so that
   23.68 +  // exceptional control flow can be handled properly.
   23.69 +  void replace_call(CallNode* call, Node* result);
   23.70 +
   23.71    // helper functions for statistics
   23.72    void increment_counter(address counter_addr);   // increment a debug counter
   23.73    void increment_counter(Node*   counter_addr);   // increment a debug counter
    24.1 --- a/src/share/vm/opto/macro.cpp	Fri Nov 27 07:56:58 2009 -0800
    24.2 +++ b/src/share/vm/opto/macro.cpp	Thu Nov 12 09:24:21 2009 -0800
    24.3 @@ -912,15 +912,29 @@
    24.4      return false;
    24.5    }
    24.6  
    24.7 +  CompileLog* log = C->log();
    24.8 +  if (log != NULL) {
    24.9 +    Node* klass = alloc->in(AllocateNode::KlassNode);
   24.10 +    const TypeKlassPtr* tklass = _igvn.type(klass)->is_klassptr();
   24.11 +    log->head("eliminate_allocation type='%d'",
   24.12 +              log->identify(tklass->klass()));
   24.13 +    JVMState* p = alloc->jvms();
   24.14 +    while (p != NULL) {
   24.15 +      log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
   24.16 +      p = p->caller();
   24.17 +    }
   24.18 +    log->tail("eliminate_allocation");
   24.19 +  }
   24.20 +
   24.21    process_users_of_allocation(alloc);
   24.22  
   24.23  #ifndef PRODUCT
   24.24 -if (PrintEliminateAllocations) {
   24.25 -  if (alloc->is_AllocateArray())
   24.26 -    tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx);
   24.27 -  else
   24.28 -    tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx);
   24.29 -}
   24.30 +  if (PrintEliminateAllocations) {
   24.31 +    if (alloc->is_AllocateArray())
   24.32 +      tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx);
   24.33 +    else
   24.34 +      tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx);
   24.35 +  }
   24.36  #endif
   24.37  
   24.38    return true;
   24.39 @@ -1639,6 +1653,18 @@
   24.40        } // if (!oldbox->is_eliminated())
   24.41    } // if (alock->is_Lock() && !lock->is_coarsened())
   24.42  
   24.43 +  CompileLog* log = C->log();
   24.44 +  if (log != NULL) {
   24.45 +    log->head("eliminate_lock lock='%d'",
   24.46 +              alock->is_Lock());
   24.47 +    JVMState* p = alock->jvms();
   24.48 +    while (p != NULL) {
   24.49 +      log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
   24.50 +      p = p->caller();
   24.51 +    }
   24.52 +    log->tail("eliminate_lock");
   24.53 +  }
   24.54 +
   24.55    #ifndef PRODUCT
   24.56    if (PrintEliminateLocks) {
   24.57      if (alock->is_Lock()) {
    25.1 --- a/src/share/vm/opto/memnode.cpp	Fri Nov 27 07:56:58 2009 -0800
    25.2 +++ b/src/share/vm/opto/memnode.cpp	Thu Nov 12 09:24:21 2009 -0800
    25.3 @@ -1503,6 +1503,8 @@
    25.4        }
    25.5      }
    25.6    } else if (tp->base() == Type::InstPtr) {
    25.7 +    const TypeInstPtr* tinst = tp->is_instptr();
    25.8 +    ciKlass* klass = tinst->klass();
    25.9      assert( off != Type::OffsetBot ||
   25.10              // arrays can be cast to Objects
   25.11              tp->is_oopptr()->klass()->is_java_lang_Object() ||
   25.12 @@ -1510,6 +1512,25 @@
   25.13              phase->C->has_unsafe_access(),
   25.14              "Field accesses must be precise" );
   25.15      // For oop loads, we expect the _type to be precise
   25.16 +    if (OptimizeStringConcat && klass == phase->C->env()->String_klass() &&
   25.17 +        adr->is_AddP() && off != Type::OffsetBot) {
   25.18 +      // For constant Strings treat the fields as compile time constants.
   25.19 +      Node* base = adr->in(AddPNode::Base);
   25.20 +      if (base->Opcode() == Op_ConP) {
   25.21 +        const TypeOopPtr* t = phase->type(base)->isa_oopptr();
   25.22 +        ciObject* string = t->const_oop();
   25.23 +        ciConstant constant = string->as_instance()->field_value_by_offset(off);
   25.24 +        if (constant.basic_type() == T_INT) {
   25.25 +          return TypeInt::make(constant.as_int());
   25.26 +        } else if (constant.basic_type() == T_ARRAY) {
   25.27 +          if (adr->bottom_type()->is_ptr_to_narrowoop()) {
   25.28 +            return TypeNarrowOop::make_from_constant(constant.as_object());
   25.29 +          } else {
   25.30 +            return TypeOopPtr::make_from_constant(constant.as_object());
   25.31 +          }
   25.32 +        }
   25.33 +      }
   25.34 +    }
   25.35    } else if (tp->base() == Type::KlassPtr) {
   25.36      assert( off != Type::OffsetBot ||
   25.37              // arrays can be cast to Objects
    26.1 --- a/src/share/vm/opto/node.hpp	Fri Nov 27 07:56:58 2009 -0800
    26.2 +++ b/src/share/vm/opto/node.hpp	Thu Nov 12 09:24:21 2009 -0800
    26.3 @@ -661,18 +661,25 @@
    26.4      return (_flags & Flag_is_Call) != 0;
    26.5    }
    26.6  
    26.7 +  CallNode* isa_Call() const {
    26.8 +    return is_Call() ? as_Call() : NULL;
    26.9 +  }
   26.10 +
   26.11    CallNode *as_Call() const { // Only for CallNode (not for MachCallNode)
   26.12      assert((_class_id & ClassMask_Call) == Class_Call, "invalid node class");
   26.13      return (CallNode*)this;
   26.14    }
   26.15  
   26.16 -  #define DEFINE_CLASS_QUERY(type) \
   26.17 -  bool is_##type() const { \
   26.18 +  #define DEFINE_CLASS_QUERY(type)                           \
   26.19 +  bool is_##type() const {                                   \
   26.20      return ((_class_id & ClassMask_##type) == Class_##type); \
   26.21 -  } \
   26.22 -  type##Node *as_##type() const { \
   26.23 -    assert(is_##type(), "invalid node class"); \
   26.24 -    return (type##Node*)this; \
   26.25 +  }                                                          \
   26.26 +  type##Node *as_##type() const {                            \
   26.27 +    assert(is_##type(), "invalid node class");               \
   26.28 +    return (type##Node*)this;                                \
   26.29 +  }                                                          \
   26.30 +  type##Node* isa_##type() const {                           \
   26.31 +    return (is_##type()) ? as_##type() : NULL;               \
   26.32    }
   26.33  
   26.34    DEFINE_CLASS_QUERY(AbstractLock)
   26.35 @@ -1249,6 +1256,24 @@
   26.36  #undef I_VDUI_ONLY
   26.37  #undef VDUI_ONLY
   26.38  
   26.39 +// An Iterator that truly follows the iterator pattern.  Doesn't
   26.40 +// support deletion but could be made to.
   26.41 +//
   26.42 +//   for (SimpleDUIterator i(n); i.has_next(); i.next()) {
   26.43 +//     Node* m = i.get();
   26.44 +//
   26.45 +class SimpleDUIterator : public StackObj {
   26.46 + private:
   26.47 +  Node* node;
   26.48 +  DUIterator_Fast i;
   26.49 +  DUIterator_Fast imax;
   26.50 + public:
   26.51 +  SimpleDUIterator(Node* n): node(n), i(n->fast_outs(imax)) {}
   26.52 +  bool has_next() { return i < imax; }
   26.53 +  void next() { i++; }
   26.54 +  Node* get() { return node->fast_out(i); }
   26.55 +};
   26.56 +
   26.57  
   26.58  //-----------------------------------------------------------------------------
   26.59  // Map dense integer indices to Nodes.  Uses classic doubling-array trick.
   26.60 @@ -1290,6 +1315,12 @@
   26.61  public:
   26.62    Node_List() : Node_Array(Thread::current()->resource_area()), _cnt(0) {}
   26.63    Node_List(Arena *a) : Node_Array(a), _cnt(0) {}
   26.64 +  bool contains(Node* n) {
   26.65 +    for (uint e = 0; e < size(); e++) {
   26.66 +      if (at(e) == n) return true;
   26.67 +    }
   26.68 +    return false;
   26.69 +  }
   26.70    void insert( uint i, Node *n ) { Node_Array::insert(i,n); _cnt++; }
   26.71    void remove( uint i ) { Node_Array::remove(i); _cnt--; }
   26.72    void push( Node *b ) { map(_cnt++,b); }
    27.1 --- a/src/share/vm/opto/parseHelper.cpp	Fri Nov 27 07:56:58 2009 -0800
    27.2 +++ b/src/share/vm/opto/parseHelper.cpp	Thu Nov 12 09:24:21 2009 -0800
    27.3 @@ -221,6 +221,14 @@
    27.4  
    27.5    // Push resultant oop onto stack
    27.6    push(obj);
    27.7 +
    27.8 +  // Keep track of whether opportunities exist for StringBuilder
    27.9 +  // optimizations.
   27.10 +  if (OptimizeStringConcat &&
   27.11 +      (klass == C->env()->StringBuilder_klass() ||
   27.12 +       klass == C->env()->StringBuffer_klass())) {
   27.13 +    C->set_has_stringbuilder(true);
   27.14 +  }
   27.15  }
   27.16  
   27.17  #ifndef PRODUCT
    28.1 --- a/src/share/vm/opto/phase.hpp	Fri Nov 27 07:56:58 2009 -0800
    28.2 +++ b/src/share/vm/opto/phase.hpp	Thu Nov 12 09:24:21 2009 -0800
    28.3 @@ -44,6 +44,7 @@
    28.4      BlockLayout,                // Linear ordering of blocks
    28.5      Register_Allocation,        // Register allocation, duh
    28.6      LIVE,                       // Dragon-book LIVE range problem
    28.7 +    StringOpts,                 // StringBuilder related optimizations
    28.8      Interference_Graph,         // Building the IFG
    28.9      Coalesce,                   // Coalescing copies
   28.10      Ideal_Loop,                 // Find idealized trip-counted loops
    29.1 --- a/src/share/vm/opto/phaseX.hpp	Fri Nov 27 07:56:58 2009 -0800
    29.2 +++ b/src/share/vm/opto/phaseX.hpp	Thu Nov 12 09:24:21 2009 -0800
    29.3 @@ -345,7 +345,11 @@
    29.4    Node  *hash_find(const Node *n) { return _table.hash_find(n); }
    29.5  
    29.6    // Used after parsing to eliminate values that are no longer in program
    29.7 -  void   remove_useless_nodes(VectorSet &useful) { _table.remove_useless_nodes(useful); }
    29.8 +  void   remove_useless_nodes(VectorSet &useful) {
    29.9 +    _table.remove_useless_nodes(useful);
   29.10 +    // this may invalidate cached cons so reset the cache
   29.11 +    init_con_caches();
   29.12 +  }
   29.13  
   29.14    virtual ConNode* uncached_makecon(const Type* t);  // override from PhaseTransform
   29.15  
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/share/vm/opto/stringopts.cpp	Thu Nov 12 09:24:21 2009 -0800
    30.3 @@ -0,0 +1,1395 @@
    30.4 +/*
    30.5 + * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
    30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    30.7 + *
    30.8 + * This code is free software; you can redistribute it and/or modify it
    30.9 + * under the terms of the GNU General Public License version 2 only, as
   30.10 + * published by the Free Software Foundation.
   30.11 + *
   30.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   30.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   30.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   30.15 + * version 2 for more details (a copy is included in the LICENSE file that
   30.16 + * accompanied this code).
   30.17 + *
   30.18 + * You should have received a copy of the GNU General Public License version
   30.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   30.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   30.21 + *
   30.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   30.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
   30.24 + * have any questions.
   30.25 + *
   30.26 + */
   30.27 +
   30.28 +#include "incls/_precompiled.incl"
   30.29 +#include "incls/_stringopts.cpp.incl"
   30.30 +
   30.31 +#define __ kit.
   30.32 +
   30.33 +class StringConcat : public ResourceObj {
   30.34 + private:
   30.35 +  PhaseStringOpts*    _stringopts;
   30.36 +  Node*               _string_alloc;
   30.37 +  AllocateNode*       _begin;          // The allocation the begins the pattern
   30.38 +  CallStaticJavaNode* _end;            // The final call of the pattern.  Will either be
   30.39 +                                       // SB.toString or or String.<init>(SB.toString)
   30.40 +  bool                _multiple;       // indicates this is a fusion of two or more
   30.41 +                                       // separate StringBuilders
   30.42 +
   30.43 +  Node*               _arguments;      // The list of arguments to be concatenated
   30.44 +  GrowableArray<int>  _mode;           // into a String along with a mode flag
   30.45 +                                       // indicating how to treat the value.
   30.46 +
   30.47 +  Node_List           _control;        // List of control nodes that will be deleted
   30.48 +  Node_List           _uncommon_traps; // Uncommon traps that needs to be rewritten
   30.49 +                                       // to restart at the initial JVMState.
   30.50 + public:
   30.51 +  // Mode for converting arguments to Strings
   30.52 +  enum {
   30.53 +    StringMode,
   30.54 +    IntMode,
   30.55 +    CharMode
   30.56 +  };
   30.57 +
   30.58 +  StringConcat(PhaseStringOpts* stringopts, CallStaticJavaNode* end):
   30.59 +    _end(end),
   30.60 +    _begin(NULL),
   30.61 +    _multiple(false),
   30.62 +    _string_alloc(NULL),
   30.63 +    _stringopts(stringopts) {
   30.64 +    _arguments = new (_stringopts->C, 1) Node(1);
   30.65 +    _arguments->del_req(0);
   30.66 +  }
   30.67 +
   30.68 +  bool validate_control_flow();
   30.69 +
   30.70 +  void merge_add() {
   30.71 +#if 0
   30.72 +    // XXX This is place holder code for reusing an existing String
   30.73 +    // allocation but the logic for checking the state safety is
   30.74 +    // probably inadequate at the moment.
   30.75 +    CallProjections endprojs;
   30.76 +    sc->end()->extract_projections(&endprojs, false);
   30.77 +    if (endprojs.resproj != NULL) {
   30.78 +      for (SimpleDUIterator i(endprojs.resproj); i.has_next(); i.next()) {
   30.79 +        CallStaticJavaNode *use = i.get()->isa_CallStaticJava();
   30.80 +        if (use != NULL && use->method() != NULL &&
   30.81 +            use->method()->holder() == C->env()->String_klass() &&
   30.82 +            use->method()->name() == ciSymbol::object_initializer_name() &&
   30.83 +            use->in(TypeFunc::Parms + 1) == endprojs.resproj) {
   30.84 +          // Found useless new String(sb.toString()) so reuse the newly allocated String
   30.85 +          // when creating the result instead of allocating a new one.
   30.86 +          sc->set_string_alloc(use->in(TypeFunc::Parms));
   30.87 +          sc->set_end(use);
   30.88 +        }
   30.89 +      }
   30.90 +    }
   30.91 +#endif
   30.92 +  }
   30.93 +
   30.94 +  StringConcat* merge(StringConcat* other, Node* arg);
   30.95 +
   30.96 +  void set_allocation(AllocateNode* alloc) {
   30.97 +    _begin = alloc;
   30.98 +  }
   30.99 +
  30.100 +  void append(Node* value, int mode) {
  30.101 +    _arguments->add_req(value);
  30.102 +    _mode.append(mode);
  30.103 +  }
  30.104 +  void push(Node* value, int mode) {
  30.105 +    _arguments->ins_req(0, value);
  30.106 +    _mode.insert_before(0, mode);
  30.107 +  }
  30.108 +  void push_string(Node* value) {
  30.109 +    push(value, StringMode);
  30.110 +  }
  30.111 +  void push_int(Node* value) {
  30.112 +    push(value, IntMode);
  30.113 +  }
  30.114 +  void push_char(Node* value) {
  30.115 +    push(value, CharMode);
  30.116 +  }
  30.117 +
  30.118 +  Node* argument(int i) {
  30.119 +    return _arguments->in(i);
  30.120 +  }
  30.121 +  void set_argument(int i, Node* value) {
  30.122 +    _arguments->set_req(i, value);
  30.123 +  }
  30.124 +  int num_arguments() {
  30.125 +    return _mode.length();
  30.126 +  }
  30.127 +  int mode(int i) {
  30.128 +    return _mode.at(i);
  30.129 +  }
  30.130 +  void add_control(Node* ctrl) {
  30.131 +    assert(!_control.contains(ctrl), "only push once");
  30.132 +    _control.push(ctrl);
  30.133 +  }
  30.134 +  CallStaticJavaNode* end() { return _end; }
  30.135 +  AllocateNode* begin() { return _begin; }
  30.136 +  Node* string_alloc() { return _string_alloc; }
  30.137 +
  30.138 +  void eliminate_unneeded_control();
  30.139 +  void eliminate_initialize(InitializeNode* init);
  30.140 +  void eliminate_call(CallNode* call);
  30.141 +
  30.142 +  void maybe_log_transform() {
  30.143 +    CompileLog* log = _stringopts->C->log();
  30.144 +    if (log != NULL) {
  30.145 +      log->head("replace_string_concat arguments='%d' string_alloc='%d' multiple='%d'",
  30.146 +                num_arguments(),
  30.147 +                _string_alloc != NULL,
  30.148 +                _multiple);
  30.149 +      JVMState* p = _begin->jvms();
  30.150 +      while (p != NULL) {
  30.151 +        log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
  30.152 +        p = p->caller();
  30.153 +      }
  30.154 +      log->tail("replace_string_concat");
  30.155 +    }
  30.156 +  }
  30.157 +
  30.158 +  void convert_uncommon_traps(GraphKit& kit, const JVMState* jvms) {
  30.159 +    for (uint u = 0; u < _uncommon_traps.size(); u++) {
  30.160 +      Node* uct = _uncommon_traps.at(u);
  30.161 +
  30.162 +      // Build a new call using the jvms state of the allocate
  30.163 +      address call_addr = SharedRuntime::uncommon_trap_blob()->instructions_begin();
  30.164 +      const TypeFunc* call_type = OptoRuntime::uncommon_trap_Type();
  30.165 +      int size = call_type->domain()->cnt();
  30.166 +      const TypePtr* no_memory_effects = NULL;
  30.167 +      Compile* C = _stringopts->C;
  30.168 +      CallStaticJavaNode* call = new (C, size) CallStaticJavaNode(call_type, call_addr, "uncommon_trap",
  30.169 +                                                                  jvms->bci(), no_memory_effects);
  30.170 +      for (int e = 0; e < TypeFunc::Parms; e++) {
  30.171 +        call->init_req(e, uct->in(e));
  30.172 +      }
  30.173 +      // Set the trap request to record intrinsic failure if this trap
  30.174 +      // is taken too many times.  Ideally we would handle then traps by
  30.175 +      // doing the original bookkeeping in the MDO so that if it caused
  30.176 +      // the code to be thrown out we could still recompile and use the
  30.177 +      // optimization.  Failing the uncommon traps doesn't really mean
  30.178 +      // that the optimization is a bad idea but there's no other way to
  30.179 +      // do the MDO updates currently.
  30.180 +      int trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_intrinsic,
  30.181 +                                                           Deoptimization::Action_make_not_entrant);
  30.182 +      call->init_req(TypeFunc::Parms, __ intcon(trap_request));
  30.183 +      kit.add_safepoint_edges(call);
  30.184 +
  30.185 +      _stringopts->gvn()->transform(call);
  30.186 +      C->gvn_replace_by(uct, call);
  30.187 +      uct->disconnect_inputs(NULL);
  30.188 +    }
  30.189 +  }
  30.190 +
  30.191 +  void cleanup() {
  30.192 +    // disconnect the hook node
  30.193 +    _arguments->disconnect_inputs(NULL);
  30.194 +  }
  30.195 +};
  30.196 +
  30.197 +
  30.198 +void StringConcat::eliminate_unneeded_control() {
  30.199 +  eliminate_initialize(begin()->initialization());
  30.200 +  for (uint i = 0; i < _control.size(); i++) {
  30.201 +    Node* n = _control.at(i);
  30.202 +    if (n->is_Call()) {
  30.203 +      if (n != _end) {
  30.204 +        eliminate_call(n->as_Call());
  30.205 +      }
  30.206 +    } else if (n->is_IfTrue()) {
  30.207 +      Compile* C = _stringopts->C;
  30.208 +      C->gvn_replace_by(n, n->in(0)->in(0));
  30.209 +      C->gvn_replace_by(n->in(0), C->top());
  30.210 +    }
  30.211 +  }
  30.212 +}
  30.213 +
  30.214 +
  30.215 +StringConcat* StringConcat::merge(StringConcat* other, Node* arg) {
  30.216 +  StringConcat* result = new StringConcat(_stringopts, _end);
  30.217 +  for (uint x = 0; x < _control.size(); x++) {
  30.218 +    Node* n = _control.at(x);
  30.219 +    if (n->is_Call()) {
  30.220 +      result->_control.push(n);
  30.221 +    }
  30.222 +  }
  30.223 +  for (uint x = 0; x < other->_control.size(); x++) {
  30.224 +    Node* n = other->_control.at(x);
  30.225 +    if (n->is_Call()) {
  30.226 +      result->_control.push(n);
  30.227 +    }
  30.228 +  }
  30.229 +  assert(result->_control.contains(other->_end), "what?");
  30.230 +  assert(result->_control.contains(_begin), "what?");
  30.231 +  for (int x = 0; x < num_arguments(); x++) {
  30.232 +    if (argument(x) == arg) {
  30.233 +      // replace the toString result with the all the arguments that
  30.234 +      // made up the other StringConcat
  30.235 +      for (int y = 0; y < other->num_arguments(); y++) {
  30.236 +        result->append(other->argument(y), other->mode(y));
  30.237 +      }
  30.238 +    } else {
  30.239 +      result->append(argument(x), mode(x));
  30.240 +    }
  30.241 +  }
  30.242 +  result->set_allocation(other->_begin);
  30.243 +  result->_multiple = true;
  30.244 +  return result;
  30.245 +}
  30.246 +
  30.247 +
  30.248 +void StringConcat::eliminate_call(CallNode* call) {
  30.249 +  Compile* C = _stringopts->C;
  30.250 +  CallProjections projs;
  30.251 +  call->extract_projections(&projs, false);
  30.252 +  if (projs.fallthrough_catchproj != NULL) {
  30.253 +    C->gvn_replace_by(projs.fallthrough_catchproj, call->in(TypeFunc::Control));
  30.254 +  }
  30.255 +  if (projs.fallthrough_memproj != NULL) {
  30.256 +    C->gvn_replace_by(projs.fallthrough_memproj, call->in(TypeFunc::Memory));
  30.257 +  }
  30.258 +  if (projs.catchall_memproj != NULL) {
  30.259 +    C->gvn_replace_by(projs.catchall_memproj, C->top());
  30.260 +  }
  30.261 +  if (projs.fallthrough_ioproj != NULL) {
  30.262 +    C->gvn_replace_by(projs.fallthrough_ioproj, call->in(TypeFunc::I_O));
  30.263 +  }
  30.264 +  if (projs.catchall_ioproj != NULL) {
  30.265 +    C->gvn_replace_by(projs.catchall_ioproj, C->top());
  30.266 +  }
  30.267 +  if (projs.catchall_catchproj != NULL) {
  30.268 +    // EA can't cope with the partially collapsed graph this
  30.269 +    // creates so put it on the worklist to be collapsed later.
  30.270 +    for (SimpleDUIterator i(projs.catchall_catchproj); i.has_next(); i.next()) {
  30.271 +      Node *use = i.get();
  30.272 +      int opc = use->Opcode();
  30.273 +      if (opc == Op_CreateEx || opc == Op_Region) {
  30.274 +        _stringopts->record_dead_node(use);
  30.275 +      }
  30.276 +    }
  30.277 +    C->gvn_replace_by(projs.catchall_catchproj, C->top());
  30.278 +  }
  30.279 +  if (projs.resproj != NULL) {
  30.280 +    C->gvn_replace_by(projs.resproj, C->top());
  30.281 +  }
  30.282 +  C->gvn_replace_by(call, C->top());
  30.283 +}
  30.284 +
  30.285 +void StringConcat::eliminate_initialize(InitializeNode* init) {
  30.286 +  Compile* C = _stringopts->C;
  30.287 +
  30.288 +  // Eliminate Initialize node.
  30.289 +  assert(init->outcnt() <= 2, "only a control and memory projection expected");
  30.290 +  assert(init->req() <= InitializeNode::RawStores, "no pending inits");
  30.291 +  Node *ctrl_proj = init->proj_out(TypeFunc::Control);
  30.292 +  if (ctrl_proj != NULL) {
  30.293 +    C->gvn_replace_by(ctrl_proj, init->in(TypeFunc::Control));
  30.294 +  }
  30.295 +  Node *mem_proj = init->proj_out(TypeFunc::Memory);
  30.296 +  if (mem_proj != NULL) {
  30.297 +    Node *mem = init->in(TypeFunc::Memory);
  30.298 +    C->gvn_replace_by(mem_proj, mem);
  30.299 +  }
  30.300 +  C->gvn_replace_by(init, C->top());
  30.301 +  init->disconnect_inputs(NULL);
  30.302 +}
  30.303 +
  30.304 +Node_List PhaseStringOpts::collect_toString_calls() {
  30.305 +  Node_List string_calls;
  30.306 +  Node_List worklist;
  30.307 +
  30.308 +  _visited.Clear();
  30.309 +
  30.310 +  // Prime the worklist
  30.311 +  for (uint i = 1; i < C->root()->len(); i++) {
  30.312 +    Node* n = C->root()->in(i);
  30.313 +    if (n != NULL && !_visited.test_set(n->_idx)) {
  30.314 +      worklist.push(n);
  30.315 +    }
  30.316 +  }
  30.317 +
  30.318 +  while (worklist.size() > 0) {
  30.319 +    Node* ctrl = worklist.pop();
  30.320 +    if (ctrl->is_CallStaticJava()) {
  30.321 +      CallStaticJavaNode* csj = ctrl->as_CallStaticJava();
  30.322 +      ciMethod* m = csj->method();
  30.323 +      if (m != NULL &&
  30.324 +          (m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString ||
  30.325 +           m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) {
  30.326 +        string_calls.push(csj);
  30.327 +      }
  30.328 +    }
  30.329 +    if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) {
  30.330 +      worklist.push(ctrl->in(0));
  30.331 +    }
  30.332 +    if (ctrl->is_Region()) {
  30.333 +      for (uint i = 1; i < ctrl->len(); i++) {
  30.334 +        if (ctrl->in(i) != NULL && !_visited.test_set(ctrl->in(i)->_idx)) {
  30.335 +          worklist.push(ctrl->in(i));
  30.336 +        }
  30.337 +      }
  30.338 +    }
  30.339 +  }
  30.340 +  return string_calls;
  30.341 +}
  30.342 +
  30.343 +
  30.344 +StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
  30.345 +  ciMethod* m = call->method();
  30.346 +  ciSymbol* string_sig;
  30.347 +  ciSymbol* int_sig;
  30.348 +  ciSymbol* char_sig;
  30.349 +  if (m->holder() == C->env()->StringBuilder_klass()) {
  30.350 +    string_sig = ciSymbol::String_StringBuilder_signature();
  30.351 +    int_sig = ciSymbol::int_StringBuilder_signature();
  30.352 +    char_sig = ciSymbol::char_StringBuilder_signature();
  30.353 +  } else if (m->holder() == C->env()->StringBuffer_klass()) {
  30.354 +    string_sig = ciSymbol::String_StringBuffer_signature();
  30.355 +    int_sig = ciSymbol::int_StringBuffer_signature();
  30.356 +    char_sig = ciSymbol::char_StringBuffer_signature();
  30.357 +  } else {
  30.358 +    return NULL;
  30.359 +  }
  30.360 +#ifndef PRODUCT
  30.361 +  if (PrintOptimizeStringConcat) {
  30.362 +    tty->print("considering toString call in ");
  30.363 +    call->jvms()->dump_spec(tty); tty->cr();
  30.364 +  }
  30.365 +#endif
  30.366 +
  30.367 +  StringConcat* sc = new StringConcat(this, call);
  30.368 +
  30.369 +  AllocateNode* alloc = NULL;
  30.370 +  InitializeNode* init = NULL;
  30.371 +
  30.372 +  // possible opportunity for StringBuilder fusion
  30.373 +  CallStaticJavaNode* cnode = call;
  30.374 +  while (cnode) {
  30.375 +    Node* recv = cnode->in(TypeFunc::Parms)->uncast();
  30.376 +    if (recv->is_Proj()) {
  30.377 +      recv = recv->in(0);
  30.378 +    }
  30.379 +    cnode = recv->isa_CallStaticJava();
  30.380 +    if (cnode == NULL) {
  30.381 +      alloc = recv->isa_Allocate();
  30.382 +      if (alloc == NULL) {
  30.383 +        break;
  30.384 +      }
  30.385 +      // Find the constructor call
  30.386 +      Node* result = alloc->result_cast();
  30.387 +      if (result == NULL || !result->is_CheckCastPP()) {
  30.388 +        // strange looking allocation
  30.389 +#ifndef PRODUCT
  30.390 +        if (PrintOptimizeStringConcat) {
  30.391 +          tty->print("giving up because allocation looks strange ");
  30.392 +          alloc->jvms()->dump_spec(tty); tty->cr();
  30.393 +        }
  30.394 +#endif
  30.395 +        break;
  30.396 +      }
  30.397 +      Node* constructor = NULL;
  30.398 +      for (SimpleDUIterator i(result); i.has_next(); i.next()) {
  30.399 +        CallStaticJavaNode *use = i.get()->isa_CallStaticJava();
  30.400 +        if (use != NULL && use->method() != NULL &&
  30.401 +            use->method()->name() == ciSymbol::object_initializer_name() &&
  30.402 +            use->method()->holder() == m->holder()) {
  30.403 +          // Matched the constructor.
  30.404 +          ciSymbol* sig = use->method()->signature()->as_symbol();
  30.405 +          if (sig == ciSymbol::void_method_signature() ||
  30.406 +              sig == ciSymbol::int_void_signature() ||
  30.407 +              sig == ciSymbol::string_void_signature()) {
  30.408 +            if (sig == ciSymbol::string_void_signature()) {
  30.409 +              // StringBuilder(String) so pick this up as the first argument
  30.410 +              assert(use->in(TypeFunc::Parms + 1) != NULL, "what?");
  30.411 +              sc->push_string(use->in(TypeFunc::Parms + 1));
  30.412 +            }
  30.413 +            // The int variant takes an initial size for the backing
  30.414 +            // array so just treat it like the void version.
  30.415 +            constructor = use;
  30.416 +          } else {
  30.417 +#ifndef PRODUCT
  30.418 +            if (PrintOptimizeStringConcat) {
  30.419 +              tty->print("unexpected constructor signature: %s", sig->as_utf8());
  30.420 +            }
  30.421 +#endif
  30.422 +          }
  30.423 +          break;
  30.424 +        }
  30.425 +      }
  30.426 +      if (constructor == NULL) {
  30.427 +        // couldn't find constructor
  30.428 +#ifndef PRODUCT
  30.429 +        if (PrintOptimizeStringConcat) {
  30.430 +          tty->print("giving up because couldn't find constructor ");
  30.431 +          alloc->jvms()->dump_spec(tty);
  30.432 +        }
  30.433 +#endif
  30.434 +        break;
  30.435 +      }
  30.436 +
  30.437 +      // Walked all the way back and found the constructor call so see
  30.438 +      // if this call converted into a direct string concatenation.
  30.439 +      sc->add_control(call);
  30.440 +      sc->add_control(constructor);
  30.441 +      sc->add_control(alloc);
  30.442 +      sc->set_allocation(alloc);
  30.443 +      if (sc->validate_control_flow()) {
  30.444 +        return sc;
  30.445 +      } else {
  30.446 +        return NULL;
  30.447 +      }
  30.448 +    } else if (cnode->method() == NULL) {
  30.449 +      break;
  30.450 +    } else if (cnode->method()->holder() == m->holder() &&
  30.451 +               cnode->method()->name() == ciSymbol::append_name() &&
  30.452 +               (cnode->method()->signature()->as_symbol() == string_sig ||
  30.453 +                cnode->method()->signature()->as_symbol() == char_sig ||
  30.454 +                cnode->method()->signature()->as_symbol() == int_sig)) {
  30.455 +      sc->add_control(cnode);
  30.456 +      Node* arg = cnode->in(TypeFunc::Parms + 1);
  30.457 +      if (cnode->method()->signature()->as_symbol() == int_sig) {
  30.458 +        sc->push_int(arg);
  30.459 +      } else if (cnode->method()->signature()->as_symbol() == char_sig) {
  30.460 +        sc->push_char(arg);
  30.461 +      } else {
  30.462 +        if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) {
  30.463 +          CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava();
  30.464 +          if (csj->method() != NULL &&
  30.465 +              csj->method()->holder() == C->env()->Integer_klass() &&
  30.466 +              csj->method()->name() == ciSymbol::toString_name()) {
  30.467 +            sc->add_control(csj);
  30.468 +            sc->push_int(csj->in(TypeFunc::Parms));
  30.469 +            continue;
  30.470 +          }
  30.471 +        }
  30.472 +        sc->push_string(arg);
  30.473 +      }
  30.474 +      continue;
  30.475 +    } else {
  30.476 +      // some unhandled signature
  30.477 +#ifndef PRODUCT
  30.478 +      if (PrintOptimizeStringConcat) {
  30.479 +        tty->print("giving up because encountered unexpected signature ");
  30.480 +        cnode->tf()->dump(); tty->cr();
  30.481 +        cnode->in(TypeFunc::Parms + 1)->dump();
  30.482 +      }
  30.483 +#endif
  30.484 +      break;
  30.485 +    }
  30.486 +  }
  30.487 +  return NULL;
  30.488 +}
  30.489 +
  30.490 +
  30.491 +PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*):
  30.492 +  Phase(StringOpts),
  30.493 +  _gvn(gvn),
  30.494 +  _visited(Thread::current()->resource_area()) {
  30.495 +
  30.496 +  assert(OptimizeStringConcat, "shouldn't be here");
  30.497 +
  30.498 +  size_table_field = C->env()->Integer_klass()->get_field_by_name(ciSymbol::make("sizeTable"),
  30.499 +                                                                  ciSymbol::make("[I"), true);
  30.500 +  if (size_table_field == NULL) {
  30.501 +    // Something wrong so give up.
  30.502 +    assert(false, "why can't we find Integer.sizeTable?");
  30.503 +    return;
  30.504 +  }
  30.505 +
  30.506 +  // Collect the types needed to talk about the various slices of memory
  30.507 +  const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
  30.508 +                                                     false, NULL, 0);
  30.509 +
  30.510 +  const TypePtr* value_field_type = string_type->add_offset(java_lang_String::value_offset_in_bytes());
  30.511 +  const TypePtr* offset_field_type = string_type->add_offset(java_lang_String::offset_offset_in_bytes());
  30.512 +  const TypePtr* count_field_type = string_type->add_offset(java_lang_String::count_offset_in_bytes());
  30.513 +
  30.514 +  value_field_idx = C->get_alias_index(value_field_type);
  30.515 +  count_field_idx = C->get_alias_index(count_field_type);
  30.516 +  offset_field_idx = C->get_alias_index(offset_field_type);
  30.517 +  char_adr_idx = C->get_alias_index(TypeAryPtr::CHARS);
  30.518 +
  30.519 +  // For each locally allocated StringBuffer see if the usages can be
  30.520 +  // collapsed into a single String construction.
  30.521 +
  30.522 +  // Run through the list of allocation looking for SB.toString to see
  30.523 +  // if it's possible to fuse the usage of the SB into a single String
  30.524 +  // construction.
  30.525 +  GrowableArray<StringConcat*> concats;
  30.526 +  Node_List toStrings = collect_toString_calls();
  30.527 +  while (toStrings.size() > 0) {
  30.528 +    StringConcat* sc = build_candidate(toStrings.pop()->as_CallStaticJava());
  30.529 +    if (sc != NULL) {
  30.530 +      concats.push(sc);
  30.531 +    }
  30.532 +  }
  30.533 +
  30.534 +  // try to coalesce separate concats
  30.535 + restart:
  30.536 +  for (int c = 0; c < concats.length(); c++) {
  30.537 +    StringConcat* sc = concats.at(c);
  30.538 +    for (int i = 0; i < sc->num_arguments(); i++) {
  30.539 +      Node* arg = sc->argument(i);
  30.540 +      if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) {
  30.541 +        CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava();
  30.542 +        if (csj->method() != NULL &&
  30.543 +            (csj->method()->holder() == C->env()->StringBuffer_klass() ||
  30.544 +             csj->method()->holder() == C->env()->StringBuilder_klass()) &&
  30.545 +            csj->method()->name() == ciSymbol::toString_name()) {
  30.546 +          for (int o = 0; o < concats.length(); o++) {
  30.547 +            if (c == o) continue;
  30.548 +            StringConcat* other = concats.at(o);
  30.549 +            if (other->end() == csj) {
  30.550 +#ifndef PRODUCT
  30.551 +              if (PrintOptimizeStringConcat) {
  30.552 +                tty->print_cr("considering stacked concats");
  30.553 +              }
  30.554 +#endif
  30.555 +
  30.556 +              StringConcat* merged = sc->merge(other, arg);
  30.557 +              if (merged->validate_control_flow()) {
  30.558 +#ifndef PRODUCT
  30.559 +                if (PrintOptimizeStringConcat) {
  30.560 +                  tty->print_cr("stacking would succeed");
  30.561 +                }
  30.562 +#endif
  30.563 +                if (c < o) {
  30.564 +                  concats.remove_at(o);
  30.565 +                  concats.at_put(c, merged);
  30.566 +                } else {
  30.567 +                  concats.remove_at(c);
  30.568 +                  concats.at_put(o, merged);
  30.569 +                }
  30.570 +                goto restart;
  30.571 +              } else {
  30.572 +#ifndef PRODUCT
  30.573 +                if (PrintOptimizeStringConcat) {
  30.574 +                  tty->print_cr("stacking would fail");
  30.575 +                }
  30.576 +#endif
  30.577 +              }
  30.578 +            }
  30.579 +          }
  30.580 +        }
  30.581 +      }
  30.582 +    }
  30.583 +  }
  30.584 +
  30.585 +
  30.586 +  for (int c = 0; c < concats.length(); c++) {
  30.587 +    StringConcat* sc = concats.at(c);
  30.588 +    replace_string_concat(sc);
  30.589 +  }
  30.590 +
  30.591 +  remove_dead_nodes();
  30.592 +}
  30.593 +
  30.594 +void PhaseStringOpts::record_dead_node(Node* dead) {
  30.595 +  dead_worklist.push(dead);
  30.596 +}
  30.597 +
  30.598 +void PhaseStringOpts::remove_dead_nodes() {
  30.599 +  // Delete any dead nodes to make things clean enough that escape
  30.600 +  // analysis doesn't get unhappy.
  30.601 +  while (dead_worklist.size() > 0) {
  30.602 +    Node* use = dead_worklist.pop();
  30.603 +    int opc = use->Opcode();
  30.604 +    switch (opc) {
  30.605 +      case Op_Region: {
  30.606 +        uint i = 1;
  30.607 +        for (i = 1; i < use->req(); i++) {
  30.608 +          if (use->in(i) != C->top()) {
  30.609 +            break;
  30.610 +          }
  30.611 +        }
  30.612 +        if (i >= use->req()) {
  30.613 +          for (SimpleDUIterator i(use); i.has_next(); i.next()) {
  30.614 +            Node* m = i.get();
  30.615 +            if (m->is_Phi()) {
  30.616 +              dead_worklist.push(m);
  30.617 +            }
  30.618 +          }
  30.619 +          C->gvn_replace_by(use, C->top());
  30.620 +        }
  30.621 +        break;
  30.622 +      }
  30.623 +      case Op_AddP:
  30.624 +      case Op_CreateEx: {
  30.625 +        // Recurisvely clean up references to CreateEx so EA doesn't
  30.626 +        // get unhappy about the partially collapsed graph.
  30.627 +        for (SimpleDUIterator i(use); i.has_next(); i.next()) {
  30.628 +          Node* m = i.get();
  30.629 +          if (m->is_AddP()) {
  30.630 +            dead_worklist.push(m);
  30.631 +          }
  30.632 +        }
  30.633 +        C->gvn_replace_by(use, C->top());
  30.634 +        break;
  30.635 +      }
  30.636 +      case Op_Phi:
  30.637 +        if (use->in(0) == C->top()) {
  30.638 +          C->gvn_replace_by(use, C->top());
  30.639 +        }
  30.640 +        break;
  30.641 +    }
  30.642 +  }
  30.643 +}
  30.644 +
  30.645 +
  30.646 +bool StringConcat::validate_control_flow() {
  30.647 +  // We found all the calls and arguments now lets see if it's
  30.648 +  // safe to transform the graph as we would expect.
  30.649 +
  30.650 +  // Check to see if this resulted in too many uncommon traps previously
  30.651 +  if (Compile::current()->too_many_traps(_begin->jvms()->method(), _begin->jvms()->bci(),
  30.652 +                        Deoptimization::Reason_intrinsic)) {
  30.653 +    return false;
  30.654 +  }
  30.655 +
  30.656 +  // Walk backwards over the control flow from toString to the
  30.657 +  // allocation and make sure all the control flow is ok.  This
  30.658 +  // means it's either going to be eliminated once the calls are
  30.659 +  // removed or it can safely be transformed into an uncommon
  30.660 +  // trap.
  30.661 +
  30.662 +  int null_check_count = 0;
  30.663 +  Unique_Node_List ctrl_path;
  30.664 +
  30.665 +  assert(_control.contains(_begin), "missing");
  30.666 +  assert(_control.contains(_end), "missing");
  30.667 +
  30.668 +  // Collect the nodes that we know about and will eliminate into ctrl_path
  30.669 +  for (uint i = 0; i < _control.size(); i++) {
  30.670 +    // Push the call and it's control projection
  30.671 +    Node* n = _control.at(i);
  30.672 +    if (n->is_Allocate()) {
  30.673 +      AllocateNode* an = n->as_Allocate();
  30.674 +      InitializeNode* init = an->initialization();
  30.675 +      ctrl_path.push(init);
  30.676 +      ctrl_path.push(init->as_Multi()->proj_out(0));
  30.677 +    }
  30.678 +    if (n->is_Call()) {
  30.679 +      CallNode* cn = n->as_Call();
  30.680 +      ctrl_path.push(cn);
  30.681 +      ctrl_path.push(cn->proj_out(0));
  30.682 +      ctrl_path.push(cn->proj_out(0)->unique_out());
  30.683 +      ctrl_path.push(cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0));
  30.684 +    } else {
  30.685 +      ShouldNotReachHere();
  30.686 +    }
  30.687 +  }
  30.688 +
  30.689 +  // Skip backwards through the control checking for unexpected contro flow
  30.690 +  Node* ptr = _end;
  30.691 +  bool fail = false;
  30.692 +  while (ptr != _begin) {
  30.693 +    if (ptr->is_Call() && ctrl_path.member(ptr)) {
  30.694 +      ptr = ptr->in(0);
  30.695 +    } else if (ptr->is_CatchProj() && ctrl_path.member(ptr)) {
  30.696 +      ptr = ptr->in(0)->in(0)->in(0);
  30.697 +      assert(ctrl_path.member(ptr), "should be a known piece of control");
  30.698 +    } else if (ptr->is_IfTrue()) {
  30.699 +      IfNode* iff = ptr->in(0)->as_If();
  30.700 +      BoolNode* b = iff->in(1)->isa_Bool();
  30.701 +      Node* cmp = b->in(1);
  30.702 +      Node* v1 = cmp->in(1);
  30.703 +      Node* v2 = cmp->in(2);
  30.704 +      Node* otherproj = iff->proj_out(1 - ptr->as_Proj()->_con);
  30.705 +
  30.706 +      // Null check of the return of append which can simply be eliminated
  30.707 +      if (b->_test._test == BoolTest::ne &&
  30.708 +          v2->bottom_type() == TypePtr::NULL_PTR &&
  30.709 +          v1->is_Proj() && ctrl_path.member(v1->in(0))) {
  30.710 +        // NULL check of the return value of the append
  30.711 +        null_check_count++;
  30.712 +        if (otherproj->outcnt() == 1) {
  30.713 +          CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava();
  30.714 +          if (call != NULL && call->_name != NULL && strcmp(call->_name, "uncommon_trap") == 0) {
  30.715 +            ctrl_path.push(call);
  30.716 +          }
  30.717 +        }
  30.718 +        _control.push(ptr);
  30.719 +        ptr = ptr->in(0)->in(0);
  30.720 +        continue;
  30.721 +      }
  30.722 +
  30.723 +      // A test which leads to an uncommon trap which should be safe.
  30.724 +      // Later this trap will be converted into a trap that restarts
  30.725 +      // at the beginning.
  30.726 +      if (otherproj->outcnt() == 1) {
  30.727 +        CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava();
  30.728 +        if (call != NULL && call->_name != NULL && strcmp(call->_name, "uncommon_trap") == 0) {
  30.729 +          // control flow leads to uct so should be ok
  30.730 +          _uncommon_traps.push(call);
  30.731 +          ctrl_path.push(call);
  30.732 +          ptr = ptr->in(0)->in(0);
  30.733 +          continue;
  30.734 +        }
  30.735 +      }
  30.736 +
  30.737 +#ifndef PRODUCT
  30.738 +      // Some unexpected control flow we don't know how to handle.
  30.739 +      if (PrintOptimizeStringConcat) {
  30.740 +        tty->print_cr("failing with unknown test");
  30.741 +        b->dump();
  30.742 +        cmp->dump();
  30.743 +        v1->dump();
  30.744 +        v2->dump();
  30.745 +        tty->cr();
  30.746 +      }
  30.747 +#endif
  30.748 +      break;
  30.749 +    } else if (ptr->is_Proj() && ptr->in(0)->is_Initialize()) {
  30.750 +      ptr = ptr->in(0)->in(0);
  30.751 +    } else if (ptr->is_Region()) {
  30.752 +      Node* copy = ptr->as_Region()->is_copy();
  30.753 +      if (copy != NULL) {
  30.754 +        ptr = copy;
  30.755 +        continue;
  30.756 +      }
  30.757 +      if (ptr->req() == 3 &&
  30.758 +          ptr->in(1) != NULL && ptr->in(1)->is_Proj() &&
  30.759 +          ptr->in(2) != NULL && ptr->in(2)->is_Proj() &&
  30.760 +          ptr->in(1)->in(0) == ptr->in(2)->in(0) &&
  30.761 +          ptr->in(1)->in(0) != NULL && ptr->in(1)->in(0)->is_If()) {
  30.762 +        // Simple diamond.
  30.763 +        // XXX should check for possibly merging stores.  simple data merges are ok.
  30.764 +        ptr = ptr->in(1)->in(0)->in(0);
  30.765 +        continue;
  30.766 +      }
  30.767 +#ifndef PRODUCT
  30.768 +      if (PrintOptimizeStringConcat) {
  30.769 +        tty->print_cr("fusion would fail for region");
  30.770 +        _begin->dump();
  30.771 +        ptr->dump(2);
  30.772 +      }
  30.773 +#endif
  30.774 +      fail = true;
  30.775 +      break;
  30.776 +    } else {
  30.777 +      // other unknown control
  30.778 +      if (!fail) {
  30.779 +#ifndef PRODUCT
  30.780 +        if (PrintOptimizeStringConcat) {
  30.781 +          tty->print_cr("fusion would fail for");
  30.782 +          _begin->dump();
  30.783 +        }
  30.784 +#endif
  30.785 +        fail = true;
  30.786 +      }
  30.787 +#ifndef PRODUCT
  30.788 +      if (PrintOptimizeStringConcat) {
  30.789 +        ptr->dump();
  30.790 +      }
  30.791 +#endif
  30.792 +      ptr = ptr->in(0);
  30.793 +    }
  30.794 +  }
  30.795 +#ifndef PRODUCT
  30.796 +  if (PrintOptimizeStringConcat && fail) {
  30.797 +    tty->cr();
  30.798 +  }
  30.799 +#endif
  30.800 +  if (fail) return !fail;
  30.801 +
  30.802 +  // Validate that all these results produced are contained within
  30.803 +  // this cluster of objects.  First collect all the results produced
  30.804 +  // by calls in the region.
  30.805 +  _stringopts->_visited.Clear();
  30.806 +  Node_List worklist;
  30.807 +  Node* final_result = _end->proj_out(TypeFunc::Parms);
  30.808 +  for (uint i = 0; i < _control.size(); i++) {
  30.809 +    CallNode* cnode = _control.at(i)->isa_Call();
  30.810 +    if (cnode != NULL) {
  30.811 +      _stringopts->_visited.test_set(cnode->_idx);
  30.812 +    }
  30.813 +    Node* result = cnode != NULL ? cnode->proj_out(TypeFunc::Parms) : NULL;
  30.814 +    if (result != NULL && result != final_result) {
  30.815 +      worklist.push(result);
  30.816 +    }
  30.817 +  }
  30.818 +
  30.819 +  Node* last_result = NULL;
  30.820 +  while (worklist.size() > 0) {
  30.821 +    Node* result = worklist.pop();
  30.822 +    if (_stringopts->_visited.test_set(result->_idx))
  30.823 +      continue;
  30.824 +    for (SimpleDUIterator i(result); i.has_next(); i.next()) {
  30.825 +      Node *use = i.get();
  30.826 +      if (ctrl_path.member(use)) {
  30.827 +        // already checked this
  30.828 +        continue;
  30.829 +      }
  30.830 +      int opc = use->Opcode();
  30.831 +      if (opc == Op_CmpP || opc == Op_Node) {
  30.832 +        ctrl_path.push(use);
  30.833 +        continue;
  30.834 +      }
  30.835 +      if (opc == Op_CastPP || opc == Op_CheckCastPP) {
  30.836 +        for (SimpleDUIterator j(use); j.has_next(); j.next()) {
  30.837 +          worklist.push(j.get());
  30.838 +        }
  30.839 +        worklist.push(use->in(1));
  30.840 +        ctrl_path.push(use);
  30.841 +        continue;
  30.842 +      }
  30.843 +#ifndef PRODUCT
  30.844 +      if (PrintOptimizeStringConcat) {
  30.845 +        if (result != last_result) {
  30.846 +          last_result = result;
  30.847 +          tty->print_cr("extra uses for result:");
  30.848 +          last_result->dump();
  30.849 +        }
  30.850 +        use->dump();
  30.851 +      }
  30.852 +#endif
  30.853 +      fail = true;
  30.854 +      break;
  30.855 +    }
  30.856 +  }
  30.857 +
  30.858 +#ifndef PRODUCT
  30.859 +  if (PrintOptimizeStringConcat && !fail) {
  30.860 +    ttyLocker ttyl;
  30.861 +    tty->cr();
  30.862 +    tty->print("fusion would succeed (%d %d) for ", null_check_count, _uncommon_traps.size());
  30.863 +    _begin->jvms()->dump_spec(tty); tty->cr();
  30.864 +    for (int i = 0; i < num_arguments(); i++) {
  30.865 +      argument(i)->dump();
  30.866 +    }
  30.867 +    _control.dump();
  30.868 +    tty->cr();
  30.869 +  }
  30.870 +#endif
  30.871 +
  30.872 +  return !fail;
  30.873 +}
  30.874 +
  30.875 +Node* PhaseStringOpts::fetch_static_field(GraphKit& kit, ciField* field) {
  30.876 +  const TypeKlassPtr* klass_type = TypeKlassPtr::make(field->holder());
  30.877 +  Node* klass_node = __ makecon(klass_type);
  30.878 +  BasicType bt = field->layout_type();
  30.879 +  ciType* field_klass = field->type();
  30.880 +
  30.881 +  const Type *type;
  30.882 +  if( bt == T_OBJECT ) {
  30.883 +    if (!field->type()->is_loaded()) {
  30.884 +      type = TypeInstPtr::BOTTOM;
  30.885 +    } else if (field->is_constant()) {
  30.886 +      // This can happen if the constant oop is non-perm.
  30.887 +      ciObject* con = field->constant_value().as_object();
  30.888 +      // Do not "join" in the previous type; it doesn't add value,
  30.889 +      // and may yield a vacuous result if the field is of interface type.
  30.890 +      type = TypeOopPtr::make_from_constant(con)->isa_oopptr();
  30.891 +      assert(type != NULL, "field singleton type must be consistent");
  30.892 +    } else {
  30.893 +      type = TypeOopPtr::make_from_klass(field_klass->as_klass());
  30.894 +    }
  30.895 +  } else {
  30.896 +    type = Type::get_const_basic_type(bt);
  30.897 +  }
  30.898 +
  30.899 +  return kit.make_load(NULL, kit.basic_plus_adr(klass_node, field->offset_in_bytes()),
  30.900 +                       type, T_OBJECT,
  30.901 +                       C->get_alias_index(klass_type->add_offset(field->offset_in_bytes())));
  30.902 +}
  30.903 +
  30.904 +Node* PhaseStringOpts::int_stringSize(GraphKit& kit, Node* arg) {
  30.905 +  RegionNode *final_merge = new (C, 3) RegionNode(3);
  30.906 +  kit.gvn().set_type(final_merge, Type::CONTROL);
  30.907 +  Node* final_size = new (C, 3) PhiNode(final_merge, TypeInt::INT);
  30.908 +  kit.gvn().set_type(final_size, TypeInt::INT);
  30.909 +
  30.910 +  IfNode* iff = kit.create_and_map_if(kit.control(),
  30.911 +                                      __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne),
  30.912 +                                      PROB_FAIR, COUNT_UNKNOWN);
  30.913 +  Node* is_min = __ IfFalse(iff);
  30.914 +  final_merge->init_req(1, is_min);
  30.915 +  final_size->init_req(1, __ intcon(11));
  30.916 +
  30.917 +  kit.set_control(__ IfTrue(iff));
  30.918 +  if (kit.stopped()) {
  30.919 +    final_merge->init_req(2, C->top());
  30.920 +    final_size->init_req(2, C->top());
  30.921 +  } else {
  30.922 +
  30.923 +    // int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
  30.924 +    RegionNode *r = new (C, 3) RegionNode(3);
  30.925 +    kit.gvn().set_type(r, Type::CONTROL);
  30.926 +    Node *phi = new (C, 3) PhiNode(r, TypeInt::INT);
  30.927 +    kit.gvn().set_type(phi, TypeInt::INT);
  30.928 +    Node *size = new (C, 3) PhiNode(r, TypeInt::INT);
  30.929 +    kit.gvn().set_type(size, TypeInt::INT);
  30.930 +    Node* chk = __ CmpI(arg, __ intcon(0));
  30.931 +    Node* p = __ Bool(chk, BoolTest::lt);
  30.932 +    IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_FAIR, COUNT_UNKNOWN);
  30.933 +    Node* lessthan = __ IfTrue(iff);
  30.934 +    Node* greaterequal = __ IfFalse(iff);
  30.935 +    r->init_req(1, lessthan);
  30.936 +    phi->init_req(1, __ SubI(__ intcon(0), arg));
  30.937 +    size->init_req(1, __ intcon(1));
  30.938 +    r->init_req(2, greaterequal);
  30.939 +    phi->init_req(2, arg);
  30.940 +    size->init_req(2, __ intcon(0));
  30.941 +    kit.set_control(r);
  30.942 +    C->record_for_igvn(r);
  30.943 +    C->record_for_igvn(phi);
  30.944 +    C->record_for_igvn(size);
  30.945 +
  30.946 +    // for (int i=0; ; i++)
  30.947 +    //   if (x <= sizeTable[i])
  30.948 +    //     return i+1;
  30.949 +    RegionNode *loop = new (C, 3) RegionNode(3);
  30.950 +    loop->init_req(1, kit.control());
  30.951 +    kit.gvn().set_type(loop, Type::CONTROL);
  30.952 +
  30.953 +    Node *index = new (C, 3) PhiNode(loop, TypeInt::INT);
  30.954 +    index->init_req(1, __ intcon(0));
  30.955 +    kit.gvn().set_type(index, TypeInt::INT);
  30.956 +    kit.set_control(loop);
  30.957 +    Node* sizeTable = fetch_static_field(kit, size_table_field);
  30.958 +
  30.959 +    Node* value = kit.load_array_element(NULL, sizeTable, index, TypeAryPtr::INTS);
  30.960 +    C->record_for_igvn(value);
  30.961 +    Node* limit = __ CmpI(phi, value);
  30.962 +    Node* limitb = __ Bool(limit, BoolTest::le);
  30.963 +    IfNode* iff2 = kit.create_and_map_if(kit.control(), limitb, PROB_MIN, COUNT_UNKNOWN);
  30.964 +    Node* lessEqual = __ IfTrue(iff2);
  30.965 +    Node* greater = __ IfFalse(iff2);
  30.966 +
  30.967 +    loop->init_req(2, greater);
  30.968 +    index->init_req(2, __ AddI(index, __ intcon(1)));
  30.969 +
  30.970 +    kit.set_control(lessEqual);
  30.971 +    C->record_for_igvn(loop);
  30.972 +    C->record_for_igvn(index);
  30.973 +
  30.974 +    final_merge->init_req(2, kit.control());
  30.975 +    final_size->init_req(2, __ AddI(__ AddI(index, size), __ intcon(1)));
  30.976 +  }
  30.977 +
  30.978 +  kit.set_control(final_merge);
  30.979 +  C->record_for_igvn(final_merge);
  30.980 +  C->record_for_igvn(final_size);
  30.981 +
  30.982 +  return final_size;
  30.983 +}
  30.984 +
  30.985 +void PhaseStringOpts::int_getChars(GraphKit& kit, Node* arg, Node* char_array, Node* start, Node* end) {
  30.986 +  RegionNode *final_merge = new (C, 4) RegionNode(4);
  30.987 +  kit.gvn().set_type(final_merge, Type::CONTROL);
  30.988 +  Node *final_mem = PhiNode::make(final_merge, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS);
  30.989 +  kit.gvn().set_type(final_mem, Type::MEMORY);
  30.990 +
  30.991 +  // need to handle Integer.MIN_VALUE specially because negating doesn't make it positive
  30.992 +  {
  30.993 +    // i == MIN_VALUE
  30.994 +    IfNode* iff = kit.create_and_map_if(kit.control(),
  30.995 +                                        __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne),
  30.996 +                                        PROB_FAIR, COUNT_UNKNOWN);
  30.997 +
  30.998 +    Node* old_mem = kit.memory(char_adr_idx);
  30.999 +
 30.1000 +    kit.set_control(__ IfFalse(iff));
 30.1001 +    if (kit.stopped()) {
 30.1002 +      // Statically not equal to MIN_VALUE so this path is dead
 30.1003 +      final_merge->init_req(3, kit.control());
 30.1004 +    } else {
 30.1005 +      copy_string(kit, __ makecon(TypeInstPtr::make(C->env()->the_min_jint_string())),
 30.1006 +                  char_array, start);
 30.1007 +      final_merge->init_req(3, kit.control());
 30.1008 +      final_mem->init_req(3, kit.memory(char_adr_idx));
 30.1009 +    }
 30.1010 +
 30.1011 +    kit.set_control(__ IfTrue(iff));
 30.1012 +    kit.set_memory(old_mem, char_adr_idx);
 30.1013 +  }
 30.1014 +
 30.1015 +
 30.1016 +  // Simplified version of Integer.getChars
 30.1017 +
 30.1018 +  // int q, r;
 30.1019 +  // int charPos = index;
 30.1020 +  Node* charPos = end;
 30.1021 +
 30.1022 +  // char sign = 0;
 30.1023 +
 30.1024 +  Node* i = arg;
 30.1025 +  Node* sign = __ intcon(0);
 30.1026 +
 30.1027 +  // if (i < 0) {
 30.1028 +  //     sign = '-';
 30.1029 +  //     i = -i;
 30.1030 +  // }
 30.1031 +  {
 30.1032 +    IfNode* iff = kit.create_and_map_if(kit.control(),
 30.1033 +                                        __ Bool(__ CmpI(arg, __ intcon(0)), BoolTest::lt),
 30.1034 +                                        PROB_FAIR, COUNT_UNKNOWN);
 30.1035 +
 30.1036 +    RegionNode *merge = new (C, 3) RegionNode(3);
 30.1037 +    kit.gvn().set_type(merge, Type::CONTROL);
 30.1038 +    i = new (C, 3) PhiNode(merge, TypeInt::INT);
 30.1039 +    kit.gvn().set_type(i, TypeInt::INT);
 30.1040 +    sign = new (C, 3) PhiNode(merge, TypeInt::INT);
 30.1041 +    kit.gvn().set_type(sign, TypeInt::INT);
 30.1042 +
 30.1043 +    merge->init_req(1, __ IfTrue(iff));
 30.1044 +    i->init_req(1, __ SubI(__ intcon(0), arg));
 30.1045 +    sign->init_req(1, __ intcon('-'));
 30.1046 +    merge->init_req(2, __ IfFalse(iff));
 30.1047 +    i->init_req(2, arg);
 30.1048 +    sign->init_req(2, __ intcon(0));
 30.1049 +
 30.1050 +    kit.set_control(merge);
 30.1051 +
 30.1052 +    C->record_for_igvn(merge);
 30.1053 +    C->record_for_igvn(i);
 30.1054 +    C->record_for_igvn(sign);
 30.1055 +  }
 30.1056 +
 30.1057 +  // for (;;) {
 30.1058 +  //     q = i / 10;
 30.1059 +  //     r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
 30.1060 +  //     buf [--charPos] = digits [r];
 30.1061 +  //     i = q;
 30.1062 +  //     if (i == 0) break;
 30.1063 +  // }
 30.1064 +
 30.1065 +  {
 30.1066 +    RegionNode *head = new (C, 3) RegionNode(3);
 30.1067 +    head->init_req(1, kit.control());
 30.1068 +    kit.gvn().set_type(head, Type::CONTROL);
 30.1069 +    Node *i_phi = new (C, 3) PhiNode(head, TypeInt::INT);
 30.1070 +    i_phi->init_req(1, i);
 30.1071 +    kit.gvn().set_type(i_phi, TypeInt::INT);
 30.1072 +    charPos = PhiNode::make(head, charPos);
 30.1073 +    kit.gvn().set_type(charPos, TypeInt::INT);
 30.1074 +    Node *mem = PhiNode::make(head, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS);
 30.1075 +    kit.gvn().set_type(mem, Type::MEMORY);
 30.1076 +    kit.set_control(head);
 30.1077 +    kit.set_memory(mem, char_adr_idx);
 30.1078 +
 30.1079 +    Node* q = __ DivI(kit.null(), i_phi, __ intcon(10));
 30.1080 +    Node* r = __ SubI(i_phi, __ AddI(__ LShiftI(q, __ intcon(3)),
 30.1081 +                                     __ LShiftI(q, __ intcon(1))));
 30.1082 +    Node* m1 = __ SubI(charPos, __ intcon(1));
 30.1083 +    Node* ch = __ AddI(r, __ intcon('0'));
 30.1084 +
 30.1085 +    Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR),
 30.1086 +                                  ch, T_CHAR, char_adr_idx);
 30.1087 +
 30.1088 +
 30.1089 +    IfNode* iff = kit.create_and_map_if(head, __ Bool(__ CmpI(q, __ intcon(0)), BoolTest::ne),
 30.1090 +                                        PROB_FAIR, COUNT_UNKNOWN);
 30.1091 +    Node* ne = __ IfTrue(iff);
 30.1092 +    Node* eq = __ IfFalse(iff);
 30.1093 +
 30.1094 +    head->init_req(2, ne);
 30.1095 +    mem->init_req(2, st);
 30.1096 +    i_phi->init_req(2, q);
 30.1097 +    charPos->init_req(2, m1);
 30.1098 +
 30.1099 +    charPos = m1;
 30.1100 +
 30.1101 +    kit.set_control(eq);
 30.1102 +    kit.set_memory(st, char_adr_idx);
 30.1103 +
 30.1104 +    C->record_for_igvn(head);
 30.1105 +    C->record_for_igvn(mem);
 30.1106 +    C->record_for_igvn(i_phi);
 30.1107 +    C->record_for_igvn(charPos);
 30.1108 +  }
 30.1109 +
 30.1110 +  {
 30.1111 +    // if (sign != 0) {
 30.1112 +    //     buf [--charPos] = sign;
 30.1113 +    // }
 30.1114 +    IfNode* iff = kit.create_and_map_if(kit.control(),
 30.1115 +                                        __ Bool(__ CmpI(sign, __ intcon(0)), BoolTest::ne),
 30.1116 +                                        PROB_FAIR, COUNT_UNKNOWN);
 30.1117 +
 30.1118 +    final_merge->init_req(2, __ IfFalse(iff));
 30.1119 +    final_mem->init_req(2, kit.memory(char_adr_idx));
 30.1120 +
 30.1121 +    kit.set_control(__ IfTrue(iff));
 30.1122 +    if (kit.stopped()) {
 30.1123 +      final_merge->init_req(1, C->top());
 30.1124 +      final_mem->init_req(1, C->top());
 30.1125 +    } else {
 30.1126 +      Node* m1 = __ SubI(charPos, __ intcon(1));
 30.1127 +      Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR),
 30.1128 +                                    sign, T_CHAR, char_adr_idx);
 30.1129 +
 30.1130 +      final_merge->init_req(1, kit.control());
 30.1131 +      final_mem->init_req(1, st);
 30.1132 +    }
 30.1133 +
 30.1134 +    kit.set_control(final_merge);
 30.1135 +    kit.set_memory(final_mem, char_adr_idx);
 30.1136 +
 30.1137 +    C->record_for_igvn(final_merge);
 30.1138 +    C->record_for_igvn(final_mem);
 30.1139 +  }
 30.1140 +}
 30.1141 +
 30.1142 +
 30.1143 +Node* PhaseStringOpts::copy_string(GraphKit& kit, Node* str, Node* char_array, Node* start) {
 30.1144 +  Node* string = str;
 30.1145 +  Node* offset = kit.make_load(NULL,
 30.1146 +                               kit.basic_plus_adr(string, string, java_lang_String::offset_offset_in_bytes()),
 30.1147 +                               TypeInt::INT, T_INT, offset_field_idx);
 30.1148 +  Node* count = kit.make_load(NULL,
 30.1149 +                              kit.basic_plus_adr(string, string, java_lang_String::count_offset_in_bytes()),
 30.1150 +                              TypeInt::INT, T_INT, count_field_idx);
 30.1151 +  const TypeAryPtr*  value_type = TypeAryPtr::make(TypePtr::NotNull,
 30.1152 +                                                   TypeAry::make(TypeInt::CHAR,TypeInt::POS),
 30.1153 +                                                   ciTypeArrayKlass::make(T_CHAR), true, 0);
 30.1154 +  Node* value = kit.make_load(NULL,
 30.1155 +                              kit.basic_plus_adr(string, string, java_lang_String::value_offset_in_bytes()),
 30.1156 +                              value_type, T_OBJECT, value_field_idx);
 30.1157 +
 30.1158 +  // copy the contents
 30.1159 +  if (offset->is_Con() && count->is_Con() && value->is_Con() && count->get_int() < unroll_string_copy_length) {
 30.1160 +    // For small constant strings just emit individual stores.
 30.1161 +    // A length of 6 seems like a good space/speed tradeof.
 30.1162 +    int c = count->get_int();
 30.1163 +    int o = offset->get_int();
 30.1164 +    const TypeOopPtr* t = kit.gvn().type(value)->isa_oopptr();
 30.1165 +    ciTypeArray* value_array = t->const_oop()->as_type_array();
 30.1166 +    for (int e = 0; e < c; e++) {
 30.1167 +      __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR),
 30.1168 +                         __ intcon(value_array->char_at(o + e)), T_CHAR, char_adr_idx);
 30.1169 +      start = __ AddI(start, __ intcon(1));
 30.1170 +    }
 30.1171 +  } else {
 30.1172 +    Node* src_ptr = kit.array_element_address(value, offset, T_CHAR);
 30.1173 +    Node* dst_ptr = kit.array_element_address(char_array, start, T_CHAR);
 30.1174 +    Node* c = count;
 30.1175 +    Node* extra = NULL;
 30.1176 +#ifdef _LP64
 30.1177 +    c = __ ConvI2L(c);
 30.1178 +    extra = C->top();
 30.1179 +#endif
 30.1180 +    Node* call = kit.make_runtime_call(GraphKit::RC_LEAF|GraphKit::RC_NO_FP,
 30.1181 +                                       OptoRuntime::fast_arraycopy_Type(),
 30.1182 +                                       CAST_FROM_FN_PTR(address, StubRoutines::jshort_disjoint_arraycopy()),
 30.1183 +                                       "jshort_disjoint_arraycopy", TypeAryPtr::CHARS,
 30.1184 +                                       src_ptr, dst_ptr, c, extra);
 30.1185 +    start = __ AddI(start, count);
 30.1186 +  }
 30.1187 +  return start;
 30.1188 +}
 30.1189 +
 30.1190 +
 30.1191 +void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
 30.1192 +  // Log a little info about the transformation
 30.1193 +  sc->maybe_log_transform();
 30.1194 +
 30.1195 +  // pull the JVMState of the allocation into a SafePointNode to serve as
 30.1196 +  // as a shim for the insertion of the new code.
 30.1197 +  JVMState* jvms     = sc->begin()->jvms()->clone_shallow(C);
 30.1198 +  uint size = sc->begin()->req();
 30.1199 +  SafePointNode* map = new (C, size) SafePointNode(size, jvms);
 30.1200 +
 30.1201 +  // copy the control and memory state from the final call into our
 30.1202 +  // new starting state.  This allows any preceeding tests to feed
 30.1203 +  // into the new section of code.
 30.1204 +  for (uint i1 = 0; i1 < TypeFunc::Parms; i1++) {
 30.1205 +    map->init_req(i1, sc->end()->in(i1));
 30.1206 +  }
 30.1207 +  // blow away old allocation arguments
 30.1208 +  for (uint i1 = TypeFunc::Parms; i1 < jvms->debug_start(); i1++) {
 30.1209 +    map->init_req(i1, C->top());
 30.1210 +  }
 30.1211 +  // Copy the rest of the inputs for the JVMState
 30.1212 +  for (uint i1 = jvms->debug_start(); i1 < sc->begin()->req(); i1++) {
 30.1213 +    map->init_req(i1, sc->begin()->in(i1));
 30.1214 +  }
 30.1215 +  // Make sure the memory state is a MergeMem for parsing.
 30.1216 +  if (!map->in(TypeFunc::Memory)->is_MergeMem()) {
 30.1217 +    map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory)));
 30.1218 +  }
 30.1219 +
 30.1220 +  jvms->set_map(map);
 30.1221 +  map->ensure_stack(jvms, jvms->method()->max_stack());
 30.1222 +
 30.1223 +
 30.1224 +  // disconnect all the old StringBuilder calls from the graph
 30.1225 +  sc->eliminate_unneeded_control();
 30.1226 +
 30.1227 +  // At this point all the old work has been completely removed from
 30.1228 +  // the graph and the saved JVMState exists at the point where the
 30.1229 +  // final toString call used to be.
 30.1230 +  GraphKit kit(jvms);
 30.1231 +
 30.1232 +  // There may be uncommon traps which are still using the
 30.1233 +  // intermediate states and these need to be rewritten to point at
 30.1234 +  // the JVMState at the beginning of the transformation.
 30.1235 +  sc->convert_uncommon_traps(kit, jvms);
 30.1236 +
 30.1237 +  // Now insert the logic to compute the size of the string followed
 30.1238 +  // by all the logic to construct array and resulting string.
 30.1239 +
 30.1240 +  Node* null_string = __ makecon(TypeInstPtr::make(C->env()->the_null_string()));
 30.1241 +
 30.1242 +  // Create a region for the overflow checks to merge into.
 30.1243 +  int args = MAX2(sc->num_arguments(), 1);
 30.1244 +  RegionNode* overflow = new (C, args) RegionNode(args);
 30.1245 +  kit.gvn().set_type(overflow, Type::CONTROL);
 30.1246 +
 30.1247 +  // Create a hook node to hold onto the individual sizes since they
 30.1248 +  // are need for the copying phase.
 30.1249 +  Node* string_sizes = new (C, args) Node(args);
 30.1250 +
 30.1251 +  Node* length = __ intcon(0);
 30.1252 +  for (int argi = 0; argi < sc->num_arguments(); argi++) {
 30.1253 +    Node* arg = sc->argument(argi);
 30.1254 +    switch (sc->mode(argi)) {
 30.1255 +      case StringConcat::IntMode: {
 30.1256 +        Node* string_size = int_stringSize(kit, arg);
 30.1257 +
 30.1258 +        // accumulate total
 30.1259 +        length = __ AddI(length, string_size);
 30.1260 +
 30.1261 +        // Cache this value for the use by int_toString
 30.1262 +        string_sizes->init_req(argi, string_size);
 30.1263 +        break;
 30.1264 +      }
 30.1265 +      case StringConcat::StringMode: {
 30.1266 +        const Type* type = kit.gvn().type(arg);
 30.1267 +        if (type == TypePtr::NULL_PTR) {
 30.1268 +          // replace the argument with the null checked version
 30.1269 +          arg = null_string;
 30.1270 +          sc->set_argument(argi, arg);
 30.1271 +        } else if (!type->higher_equal(TypeInstPtr::NOTNULL)) {
 30.1272 +          // s = s != null ? s : "null";
 30.1273 +          // length = length + (s.count - s.offset);
 30.1274 +          RegionNode *r = new (C, 3) RegionNode(3);
 30.1275 +          kit.gvn().set_type(r, Type::CONTROL);
 30.1276 +          Node *phi = new (C, 3) PhiNode(r, type->join(TypeInstPtr::NOTNULL));
 30.1277 +          kit.gvn().set_type(phi, phi->bottom_type());
 30.1278 +          Node* p = __ Bool(__ CmpP(arg, kit.null()), BoolTest::ne);
 30.1279 +          IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_MIN, COUNT_UNKNOWN);
 30.1280 +          Node* notnull = __ IfTrue(iff);
 30.1281 +          Node* isnull =  __ IfFalse(iff);
 30.1282 +          r->init_req(1, notnull);
 30.1283 +          phi->init_req(1, arg);
 30.1284 +          r->init_req(2, isnull);
 30.1285 +          phi->init_req(2, null_string);
 30.1286 +          kit.set_control(r);
 30.1287 +          C->record_for_igvn(r);
 30.1288 +          C->record_for_igvn(phi);
 30.1289 +          // replace the argument with the null checked version
 30.1290 +          arg = phi;
 30.1291 +          sc->set_argument(argi, arg);
 30.1292 +        }
 30.1293 +        //         Node* offset = kit.make_load(NULL, kit.basic_plus_adr(arg, arg, offset_offset),
 30.1294 +        //                                      TypeInt::INT, T_INT, offset_field_idx);
 30.1295 +        Node* count = kit.make_load(NULL, kit.basic_plus_adr(arg, arg, java_lang_String::count_offset_in_bytes()),
 30.1296 +                                    TypeInt::INT, T_INT, count_field_idx);
 30.1297 +        length = __ AddI(length, count);
 30.1298 +        string_sizes->init_req(argi, NULL);
 30.1299 +        break;
 30.1300 +      }
 30.1301 +      case StringConcat::CharMode: {
 30.1302 +        // one character only
 30.1303 +        length = __ AddI(length, __ intcon(1));
 30.1304 +        break;
 30.1305 +      }
 30.1306 +      default:
 30.1307 +        ShouldNotReachHere();
 30.1308 +    }
 30.1309 +    if (argi > 0) {
 30.1310 +      // Check that the sum hasn't overflowed
 30.1311 +      IfNode* iff = kit.create_and_map_if(kit.control(),
 30.1312 +                                          __ Bool(__ CmpI(length, __ intcon(0)), BoolTest::lt),
 30.1313 +                                          PROB_MIN, COUNT_UNKNOWN);
 30.1314 +      kit.set_control(__ IfFalse(iff));
 30.1315 +      overflow->set_req(argi, __ IfTrue(iff));
 30.1316 +    }
 30.1317 +  }
 30.1318 +
 30.1319 +  {
 30.1320 +    // Hook
 30.1321 +    PreserveJVMState pjvms(&kit);
 30.1322 +    kit.set_control(overflow);
 30.1323 +    kit.uncommon_trap(Deoptimization::Reason_intrinsic,
 30.1324 +                      Deoptimization::Action_make_not_entrant);
 30.1325 +  }
 30.1326 +
 30.1327 +  // length now contains the number of characters needed for the
 30.1328 +  // char[] so create a new AllocateArray for the char[]
 30.1329 +  Node* char_array = NULL;
 30.1330 +  {
 30.1331 +    PreserveReexecuteState preexecs(&kit);
 30.1332 +    // The original jvms is for an allocation of either a String or
 30.1333 +    // StringBuffer so no stack adjustment is necessary for proper
 30.1334 +    // reexecution.  If we deoptimize in the slow path the bytecode
 30.1335 +    // will be reexecuted and the char[] allocation will be thrown away.
 30.1336 +    kit.jvms()->set_should_reexecute(true);
 30.1337 +    char_array = kit.new_array(__ makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_CHAR))),
 30.1338 +                               length, 1);
 30.1339 +  }
 30.1340 +
 30.1341 +  // Mark the allocation so that zeroing is skipped since the code
 30.1342 +  // below will overwrite the entire array
 30.1343 +  AllocateArrayNode* char_alloc = AllocateArrayNode::Ideal_array_allocation(char_array, _gvn);
 30.1344 +  char_alloc->maybe_set_complete(_gvn);
 30.1345 +
 30.1346 +  // Now copy the string representations into the final char[]
 30.1347 +  Node* start = __ intcon(0);
 30.1348 +  for (int argi = 0; argi < sc->num_arguments(); argi++) {
 30.1349 +    Node* arg = sc->argument(argi);
 30.1350 +    switch (sc->mode(argi)) {
 30.1351 +      case StringConcat::IntMode: {
 30.1352 +        Node* end = __ AddI(start, string_sizes->in(argi));
 30.1353 +        // getChars words backwards so pass the ending point as well as the start
 30.1354 +        int_getChars(kit, arg, char_array, start, end);
 30.1355 +        start = end;
 30.1356 +        break;
 30.1357 +      }
 30.1358 +      case StringConcat::StringMode: {
 30.1359 +        start = copy_string(kit, arg, char_array, start);
 30.1360 +        break;
 30.1361 +      }
 30.1362 +      case StringConcat::CharMode: {
 30.1363 +        __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR),
 30.1364 +                           arg, T_CHAR, char_adr_idx);
 30.1365 +        start = __ AddI(start, __ intcon(1));
 30.1366 +        break;
 30.1367 +      }
 30.1368 +      default:
 30.1369 +        ShouldNotReachHere();
 30.1370 +    }
 30.1371 +  }
 30.1372 +
 30.1373 +  // If we're not reusing an existing String allocation then allocate one here.
 30.1374 +  Node* result = sc->string_alloc();
 30.1375 +  if (result == NULL) {
 30.1376 +    PreserveReexecuteState preexecs(&kit);
 30.1377 +    // The original jvms is for an allocation of either a String or
 30.1378 +    // StringBuffer so no stack adjustment is necessary for proper
 30.1379 +    // reexecution.
 30.1380 +    kit.jvms()->set_should_reexecute(true);
 30.1381 +    result = kit.new_instance(__ makecon(TypeKlassPtr::make(C->env()->String_klass())));
 30.1382 +  }
 30.1383 +
 30.1384 +  // Intialize the string
 30.1385 +  kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::offset_offset_in_bytes()),
 30.1386 +                      __ intcon(0), T_INT, offset_field_idx);
 30.1387 +  kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::count_offset_in_bytes()),
 30.1388 +                      length, T_INT, count_field_idx);
 30.1389 +  kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::value_offset_in_bytes()),
 30.1390 +                      char_array, T_OBJECT, value_field_idx);
 30.1391 +
 30.1392 +  // hook up the outgoing control and result
 30.1393 +  kit.replace_call(sc->end(), result);
 30.1394 +
 30.1395 +  // Unhook any hook nodes
 30.1396 +  string_sizes->disconnect_inputs(NULL);
 30.1397 +  sc->cleanup();
 30.1398 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/share/vm/opto/stringopts.hpp	Thu Nov 12 09:24:21 2009 -0800
    31.3 @@ -0,0 +1,83 @@
    31.4 +/*
    31.5 + * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
    31.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    31.7 + *
    31.8 + * This code is free software; you can redistribute it and/or modify it
    31.9 + * under the terms of the GNU General Public License version 2 only, as
   31.10 + * published by the Free Software Foundation.
   31.11 + *
   31.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   31.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   31.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   31.15 + * version 2 for more details (a copy is included in the LICENSE file that
   31.16 + * accompanied this code).
   31.17 + *
   31.18 + * You should have received a copy of the GNU General Public License version
   31.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   31.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   31.21 + *
   31.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   31.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
   31.24 + * have any questions.
   31.25 + *
   31.26 + */
   31.27 +
   31.28 +class StringConcat;
   31.29 +
   31.30 +class PhaseStringOpts : public Phase {
   31.31 +  friend class StringConcat;
   31.32 +
   31.33 + private:
   31.34 +  PhaseGVN* _gvn;
   31.35 +
   31.36 +  // List of dead nodes to clean up aggressively at the end
   31.37 +  Unique_Node_List dead_worklist;
   31.38 +
   31.39 +  // Memory slices needed for code gen
   31.40 +  int char_adr_idx;
   31.41 +  int value_field_idx;
   31.42 +  int count_field_idx;
   31.43 +  int offset_field_idx;
   31.44 +
   31.45 +  // Integer.sizeTable - used for int to String conversion
   31.46 +  ciField* size_table_field;
   31.47 +
   31.48 +  // A set for use by various stages
   31.49 +  VectorSet _visited;
   31.50 +
   31.51 +  // Collect a list of all SB.toString calls
   31.52 +  Node_List collect_toString_calls();
   31.53 +
   31.54 +  // Examine the use of the SB alloc to see if it can be replace with
   31.55 +  // a single string construction.
   31.56 +  StringConcat* build_candidate(CallStaticJavaNode* call);
   31.57 +
   31.58 +  // Replace all the SB calls in concat with an optimization String allocation
   31.59 +  void replace_string_concat(StringConcat* concat);
   31.60 +
   31.61 +  // Load the value of a static field, performing any constant folding.
   31.62 +  Node* fetch_static_field(GraphKit& kit, ciField* field);
   31.63 +
   31.64 +  // Compute the number of characters required to represent the int value
   31.65 +  Node* int_stringSize(GraphKit& kit, Node* value);
   31.66 +
   31.67 +  // Copy the characters representing value into char_array starting at start
   31.68 +  void int_getChars(GraphKit& kit, Node* value, Node* char_array, Node* start, Node* end);
   31.69 +
   31.70 +  // Copy of the contents of the String str into char_array starting at index start.
   31.71 +  Node* copy_string(GraphKit& kit, Node* str, Node* char_array, Node* start);
   31.72 +
   31.73 +  // Clean up any leftover nodes
   31.74 +  void record_dead_node(Node* node);
   31.75 +  void remove_dead_nodes();
   31.76 +
   31.77 +  PhaseGVN* gvn() { return _gvn; }
   31.78 +
   31.79 +  enum {
   31.80 +    // max length of constant string copy unrolling in copy_string
   31.81 +    unroll_string_copy_length = 6
   31.82 +  };
   31.83 +
   31.84 + public:
   31.85 +  PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List* worklist);
   31.86 +};
    32.1 --- a/src/share/vm/opto/type.hpp	Fri Nov 27 07:56:58 2009 -0800
    32.2 +++ b/src/share/vm/opto/type.hpp	Thu Nov 12 09:24:21 2009 -0800
    32.3 @@ -847,9 +847,6 @@
    32.4    // Constant pointer to array
    32.5    static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot);
    32.6  
    32.7 -  // Convenience
    32.8 -  static const TypeAryPtr *make(ciObject* o);
    32.9 -
   32.10    // Return a 'ptr' version of this type
   32.11    virtual const Type *cast_to_ptr_type(PTR ptr) const;
   32.12  
    33.1 --- a/src/share/vm/runtime/globals.cpp	Fri Nov 27 07:56:58 2009 -0800
    33.2 +++ b/src/share/vm/runtime/globals.cpp	Thu Nov 12 09:24:21 2009 -0800
    33.3 @@ -46,7 +46,8 @@
    33.4  bool Flag::is_unlocked() const {
    33.5    if (strcmp(kind, "{diagnostic}") == 0) {
    33.6      return UnlockDiagnosticVMOptions;
    33.7 -  } else if (strcmp(kind, "{experimental}") == 0) {
    33.8 +  } else if (strcmp(kind, "{experimental}") == 0 ||
    33.9 +             strcmp(kind, "{C2 experimental}") == 0) {
   33.10      return UnlockExperimentalVMOptions;
   33.11    } else {
   33.12      return true;
   33.13 @@ -169,6 +170,7 @@
   33.14  #define C2_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 product}", DEFAULT },
   33.15  #define C2_PD_PRODUCT_FLAG_STRUCT(type, name, doc)     { #type, XSTR(name), &name, "{C2 pd product}", DEFAULT },
   33.16  #define C2_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 diagnostic}", DEFAULT },
   33.17 +#define C2_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 experimental}", DEFAULT },
   33.18  #ifdef PRODUCT
   33.19    #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */
   33.20    #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc)     /* flag is constant */
   33.21 @@ -190,7 +192,7 @@
   33.22   C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, C1_PD_DEVELOP_FLAG_STRUCT, C1_PRODUCT_FLAG_STRUCT, C1_PD_PRODUCT_FLAG_STRUCT, C1_NOTPRODUCT_FLAG_STRUCT)
   33.23  #endif
   33.24  #ifdef COMPILER2
   33.25 - C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, C2_PD_DEVELOP_FLAG_STRUCT, C2_PRODUCT_FLAG_STRUCT, C2_PD_PRODUCT_FLAG_STRUCT, C2_DIAGNOSTIC_FLAG_STRUCT, C2_NOTPRODUCT_FLAG_STRUCT)
   33.26 + C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, C2_PD_DEVELOP_FLAG_STRUCT, C2_PRODUCT_FLAG_STRUCT, C2_PD_PRODUCT_FLAG_STRUCT, C2_DIAGNOSTIC_FLAG_STRUCT, C2_EXPERIMENTAL_FLAG_STRUCT, C2_NOTPRODUCT_FLAG_STRUCT)
   33.27  #endif
   33.28   {0, NULL, NULL}
   33.29  };
    34.1 --- a/src/share/vm/runtime/globals_extension.hpp	Fri Nov 27 07:56:58 2009 -0800
    34.2 +++ b/src/share/vm/runtime/globals_extension.hpp	Thu Nov 12 09:24:21 2009 -0800
    34.3 @@ -64,6 +64,7 @@
    34.4  #define C2_PRODUCT_FLAG_MEMBER(type, name, value, doc)         FLAG_MEMBER(name),
    34.5  #define C2_PD_PRODUCT_FLAG_MEMBER(type, name, doc)             FLAG_MEMBER(name),
    34.6  #define C2_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc)      FLAG_MEMBER(name),
    34.7 +#define C2_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc)    FLAG_MEMBER(name),
    34.8  #ifdef PRODUCT
    34.9    #define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc)       /* flag is constant */
   34.10    #define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc)           /* flag is constant */
   34.11 @@ -84,7 +85,7 @@
   34.12   C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER)
   34.13  #endif
   34.14  #ifdef COMPILER2
   34.15 - C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, C2_PD_DEVELOP_FLAG_MEMBER, C2_PRODUCT_FLAG_MEMBER, C2_PD_PRODUCT_FLAG_MEMBER, C2_DIAGNOSTIC_FLAG_MEMBER, C2_NOTPRODUCT_FLAG_MEMBER)
   34.16 + C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, C2_PD_DEVELOP_FLAG_MEMBER, C2_PRODUCT_FLAG_MEMBER, C2_PD_PRODUCT_FLAG_MEMBER, C2_DIAGNOSTIC_FLAG_MEMBER, C2_EXPERIMENTAL_FLAG_MEMBER, C2_NOTPRODUCT_FLAG_MEMBER)
   34.17  #endif
   34.18   NUM_CommandLineFlag
   34.19  } CommandLineFlag;
   34.20 @@ -130,6 +131,7 @@
   34.21  #define C2_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc)         FLAG_MEMBER_WITH_TYPE(name,type),
   34.22  #define C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc)             FLAG_MEMBER_WITH_TYPE(name,type),
   34.23  #define C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc)      FLAG_MEMBER_WITH_TYPE(name,type),
   34.24 +#define C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc)      FLAG_MEMBER_WITH_TYPE(name,type),
   34.25  #ifdef PRODUCT
   34.26    #define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc)       /* flag is constant */
   34.27    #define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc)           /* flag is constant */
   34.28 @@ -181,6 +183,7 @@
   34.29            C2_PRODUCT_FLAG_MEMBER_WITH_TYPE,
   34.30            C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
   34.31            C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
   34.32 +          C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
   34.33            C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE)
   34.34  #endif
   34.35   NUM_CommandLineFlagWithType
    35.1 --- a/src/share/vm/utilities/growableArray.hpp	Fri Nov 27 07:56:58 2009 -0800
    35.2 +++ b/src/share/vm/utilities/growableArray.hpp	Thu Nov 12 09:24:21 2009 -0800
    35.3 @@ -278,6 +278,17 @@
    35.4      _len--;
    35.5    }
    35.6  
    35.7 +  // inserts the given element before the element at index i
    35.8 +  void insert_before(const int idx, const E& elem) {
    35.9 +    check_nesting();
   35.10 +    if (_len == _max) grow(_len);
   35.11 +    for (int j = _len - 1; j >= idx; j--) {
   35.12 +      _data[j + 1] = _data[j];
   35.13 +    }
   35.14 +    _len++;
   35.15 +    _data[idx] = elem;
   35.16 +  }
   35.17 +
   35.18    void appendAll(const GrowableArray<E>* l) {
   35.19      for (int i = 0; i < l->_len; i++) {
   35.20        raw_at_put_grow(_len, l->_data[i], 0);

mercurial