This commit is contained in:
Igor Veresov 2009-12-01 22:11:01 -08:00
commit b5e3a7a597
35 changed files with 2245 additions and 115 deletions

View File

@ -46,6 +46,9 @@ ciInstanceKlass* ciEnv::_Throwable;
ciInstanceKlass* ciEnv::_Thread; ciInstanceKlass* ciEnv::_Thread;
ciInstanceKlass* ciEnv::_OutOfMemoryError; ciInstanceKlass* ciEnv::_OutOfMemoryError;
ciInstanceKlass* ciEnv::_String; ciInstanceKlass* ciEnv::_String;
ciInstanceKlass* ciEnv::_StringBuffer;
ciInstanceKlass* ciEnv::_StringBuilder;
ciInstanceKlass* ciEnv::_Integer;
ciSymbol* ciEnv::_unloaded_cisymbol = NULL; ciSymbol* ciEnv::_unloaded_cisymbol = NULL;
ciInstanceKlass* ciEnv::_unloaded_ciinstance_klass = NULL; ciInstanceKlass* ciEnv::_unloaded_ciinstance_klass = NULL;
@ -110,6 +113,8 @@ ciEnv::ciEnv(CompileTask* task, int system_dictionary_modification_counter) {
_ArrayIndexOutOfBoundsException_instance = NULL; _ArrayIndexOutOfBoundsException_instance = NULL;
_ArrayStoreException_instance = NULL; _ArrayStoreException_instance = NULL;
_ClassCastException_instance = NULL; _ClassCastException_instance = NULL;
_the_null_string = NULL;
_the_min_jint_string = NULL;
} }
ciEnv::ciEnv(Arena* arena) { ciEnv::ciEnv(Arena* arena) {
@ -163,6 +168,8 @@ ciEnv::ciEnv(Arena* arena) {
_ArrayIndexOutOfBoundsException_instance = NULL; _ArrayIndexOutOfBoundsException_instance = NULL;
_ArrayStoreException_instance = NULL; _ArrayStoreException_instance = NULL;
_ClassCastException_instance = NULL; _ClassCastException_instance = NULL;
_the_null_string = NULL;
_the_min_jint_string = NULL;
} }
ciEnv::~ciEnv() { ciEnv::~ciEnv() {
@ -248,6 +255,22 @@ ciInstance* ciEnv::ClassCastException_instance() {
return _ClassCastException_instance; return _ClassCastException_instance;
} }
ciInstance* ciEnv::the_null_string() {
if (_the_null_string == NULL) {
VM_ENTRY_MARK;
_the_null_string = get_object(Universe::the_null_string())->as_instance();
}
return _the_null_string;
}
ciInstance* ciEnv::the_min_jint_string() {
if (_the_min_jint_string == NULL) {
VM_ENTRY_MARK;
_the_min_jint_string = get_object(Universe::the_min_jint_string())->as_instance();
}
return _the_min_jint_string;
}
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// ciEnv::get_method_from_handle // ciEnv::get_method_from_handle
ciMethod* ciEnv::get_method_from_handle(jobject method) { ciMethod* ciEnv::get_method_from_handle(jobject method) {

View File

@ -82,6 +82,9 @@ private:
static ciInstanceKlass* _Thread; static ciInstanceKlass* _Thread;
static ciInstanceKlass* _OutOfMemoryError; static ciInstanceKlass* _OutOfMemoryError;
static ciInstanceKlass* _String; static ciInstanceKlass* _String;
static ciInstanceKlass* _StringBuffer;
static ciInstanceKlass* _StringBuilder;
static ciInstanceKlass* _Integer;
static ciSymbol* _unloaded_cisymbol; static ciSymbol* _unloaded_cisymbol;
static ciInstanceKlass* _unloaded_ciinstance_klass; static ciInstanceKlass* _unloaded_ciinstance_klass;
@ -97,6 +100,9 @@ private:
ciInstance* _ArrayStoreException_instance; ciInstance* _ArrayStoreException_instance;
ciInstance* _ClassCastException_instance; ciInstance* _ClassCastException_instance;
ciInstance* _the_null_string; // The Java string "null"
ciInstance* _the_min_jint_string; // The Java string "-2147483648"
// Look up a klass by name from a particular class loader (the accessor's). // Look up a klass by name from a particular class loader (the accessor's).
// If require_local, result must be defined in that class loader, or NULL. // If require_local, result must be defined in that class loader, or NULL.
// If !require_local, a result from remote class loader may be reported, // If !require_local, a result from remote class loader may be reported,
@ -310,6 +316,15 @@ public:
ciInstanceKlass* String_klass() { ciInstanceKlass* String_klass() {
return _String; return _String;
} }
ciInstanceKlass* StringBuilder_klass() {
return _StringBuilder;
}
ciInstanceKlass* StringBuffer_klass() {
return _StringBuffer;
}
ciInstanceKlass* Integer_klass() {
return _Integer;
}
ciInstance* NullPointerException_instance() { ciInstance* NullPointerException_instance() {
assert(_NullPointerException_instance != NULL, "initialization problem"); assert(_NullPointerException_instance != NULL, "initialization problem");
return _NullPointerException_instance; return _NullPointerException_instance;
@ -324,6 +339,9 @@ public:
ciInstance* ArrayStoreException_instance(); ciInstance* ArrayStoreException_instance();
ciInstance* ClassCastException_instance(); ciInstance* ClassCastException_instance();
ciInstance* the_null_string();
ciInstance* the_min_jint_string();
static ciSymbol* unloaded_cisymbol() { static ciSymbol* unloaded_cisymbol() {
return _unloaded_cisymbol; return _unloaded_cisymbol;
} }

View File

@ -340,6 +340,20 @@ ciField* ciInstanceKlass::get_field_by_offset(int field_offset, bool is_static)
return field; return field;
} }
// ------------------------------------------------------------------
// ciInstanceKlass::get_field_by_name
ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static) {
VM_ENTRY_MARK;
instanceKlass* k = get_instanceKlass();
fieldDescriptor fd;
klassOop def = k->find_field(name->get_symbolOop(), signature->get_symbolOop(), is_static, &fd);
if (def == NULL) {
return NULL;
}
ciField* field = new (CURRENT_THREAD_ENV->arena()) ciField(&fd);
return field;
}
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// ciInstanceKlass::non_static_fields. // ciInstanceKlass::non_static_fields.

View File

@ -148,6 +148,7 @@ public:
ciInstanceKlass* get_canonical_holder(int offset); ciInstanceKlass* get_canonical_holder(int offset);
ciField* get_field_by_offset(int field_offset, bool is_static); ciField* get_field_by_offset(int field_offset, bool is_static);
ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static);
GrowableArray<ciField*>* non_static_fields(); GrowableArray<ciField*>* non_static_fields();

View File

@ -168,6 +168,15 @@ void ciObjectFactory::init_shared_objects() {
ciEnv::_String = ciEnv::_String =
get(SystemDictionary::string_klass()) get(SystemDictionary::string_klass())
->as_instance_klass(); ->as_instance_klass();
ciEnv::_StringBuffer =
get(SystemDictionary::stringBuffer_klass())
->as_instance_klass();
ciEnv::_StringBuilder =
get(SystemDictionary::StringBuilder_klass())
->as_instance_klass();
ciEnv::_Integer =
get(SystemDictionary::int_klass())
->as_instance_klass();
for (int len = -1; len != _ci_objects->length(); ) { for (int len = -1; len != _ci_objects->length(); ) {
len = _ci_objects->length(); len = _ci_objects->length();

View File

@ -150,6 +150,7 @@ class SymbolPropertyTable;
template(vector_klass, java_util_Vector, Pre) \ template(vector_klass, java_util_Vector, Pre) \
template(hashtable_klass, java_util_Hashtable, Pre) \ template(hashtable_klass, java_util_Hashtable, Pre) \
template(stringBuffer_klass, java_lang_StringBuffer, Pre) \ template(stringBuffer_klass, java_lang_StringBuffer, Pre) \
template(StringBuilder_klass, java_lang_StringBuilder, Pre) \
\ \
/* It's NULL in non-1.4 JDKs. */ \ /* It's NULL in non-1.4 JDKs. */ \
template(stackTraceElement_klass, java_lang_StackTraceElement, Opt) \ template(stackTraceElement_klass, java_lang_StackTraceElement, Opt) \

View File

@ -303,6 +303,11 @@ inline bool match_F_R(jshort flags) {
const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED; const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED;
return (flags & (req | neg)) == req; return (flags & (req | neg)) == req;
} }
inline bool match_F_Y(jshort flags) {
const int req = JVM_ACC_SYNCHRONIZED;
const int neg = JVM_ACC_STATIC;
return (flags & (req | neg)) == req;
}
inline bool match_F_RN(jshort flags) { inline bool match_F_RN(jshort flags) {
const int req = JVM_ACC_NATIVE; const int req = JVM_ACC_NATIVE;
const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED; const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED;
@ -361,6 +366,7 @@ const char* vmIntrinsics::short_name_as_C_string(vmIntrinsics::ID id, char* buf,
const char* sname = vmSymbols::name_for(signature_for(id)); const char* sname = vmSymbols::name_for(signature_for(id));
const char* fname = ""; const char* fname = "";
switch (flags_for(id)) { switch (flags_for(id)) {
case F_Y: fname = "synchronized "; break;
case F_RN: fname = "native "; break; case F_RN: fname = "native "; break;
case F_SN: fname = "native static "; break; case F_SN: fname = "native static "; break;
case F_S: fname = "static "; break; case F_S: fname = "static "; break;

View File

@ -84,6 +84,7 @@
template(java_lang_reflect_Field, "java/lang/reflect/Field") \ template(java_lang_reflect_Field, "java/lang/reflect/Field") \
template(java_lang_reflect_Array, "java/lang/reflect/Array") \ template(java_lang_reflect_Array, "java/lang/reflect/Array") \
template(java_lang_StringBuffer, "java/lang/StringBuffer") \ template(java_lang_StringBuffer, "java/lang/StringBuffer") \
template(java_lang_StringBuilder, "java/lang/StringBuilder") \
template(java_lang_CharSequence, "java/lang/CharSequence") \ template(java_lang_CharSequence, "java/lang/CharSequence") \
template(java_security_AccessControlContext, "java/security/AccessControlContext") \ template(java_security_AccessControlContext, "java/security/AccessControlContext") \
template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \ template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \
@ -334,6 +335,7 @@
template(ptypes_name, "ptypes") \ template(ptypes_name, "ptypes") \
template(form_name, "form") \ template(form_name, "form") \
template(erasedType_name, "erasedType") \ template(erasedType_name, "erasedType") \
template(append_name, "append") \
\ \
/* non-intrinsic name/signature pairs: */ \ /* non-intrinsic name/signature pairs: */ \
template(register_method_name, "register") \ template(register_method_name, "register") \
@ -415,6 +417,13 @@
template(string_signature, "Ljava/lang/String;") \ template(string_signature, "Ljava/lang/String;") \
template(reference_signature, "Ljava/lang/ref/Reference;") \ template(reference_signature, "Ljava/lang/ref/Reference;") \
template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \ template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \
template(String_StringBuilder_signature, "(Ljava/lang/String;)Ljava/lang/StringBuilder;") \
template(int_StringBuilder_signature, "(I)Ljava/lang/StringBuilder;") \
template(char_StringBuilder_signature, "(C)Ljava/lang/StringBuilder;") \
template(String_StringBuffer_signature, "(Ljava/lang/String;)Ljava/lang/StringBuffer;") \
template(int_StringBuffer_signature, "(I)Ljava/lang/StringBuffer;") \
template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \
template(int_String_signature, "(I)Ljava/lang/String;") \
/* signature symbols needed by intrinsics */ \ /* signature symbols needed by intrinsics */ \
VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \
\ \
@ -814,10 +823,34 @@
/*the compiler does have special inlining code for these; bytecode inline is just fine */ \ /*the compiler does have special inlining code for these; bytecode inline is just fine */ \
\ \
do_intrinsic(_fillInStackTrace, java_lang_Throwable, fillInStackTrace_name, void_throwable_signature, F_RNY) \ do_intrinsic(_fillInStackTrace, java_lang_Throwable, fillInStackTrace_name, void_throwable_signature, F_RNY) \
\ \
do_intrinsic(_Object_init, java_lang_Object, object_initializer_name, void_method_signature, F_R) \ do_intrinsic(_StringBuilder_void, java_lang_StringBuilder, object_initializer_name, void_method_signature, F_R) \
/* (symbol object_initializer_name defined above) */ \ do_intrinsic(_StringBuilder_int, java_lang_StringBuilder, object_initializer_name, int_void_signature, F_R) \
\ do_intrinsic(_StringBuilder_String, java_lang_StringBuilder, object_initializer_name, string_void_signature, F_R) \
\
do_intrinsic(_StringBuilder_append_char, java_lang_StringBuilder, append_name, char_StringBuilder_signature, F_R) \
do_intrinsic(_StringBuilder_append_int, java_lang_StringBuilder, append_name, int_StringBuilder_signature, F_R) \
do_intrinsic(_StringBuilder_append_String, java_lang_StringBuilder, append_name, String_StringBuilder_signature, F_R) \
\
do_intrinsic(_StringBuilder_toString, java_lang_StringBuilder, toString_name, void_string_signature, F_R) \
\
do_intrinsic(_StringBuffer_void, java_lang_StringBuffer, object_initializer_name, void_method_signature, F_R) \
do_intrinsic(_StringBuffer_int, java_lang_StringBuffer, object_initializer_name, int_void_signature, F_R) \
do_intrinsic(_StringBuffer_String, java_lang_StringBuffer, object_initializer_name, string_void_signature, F_R) \
\
do_intrinsic(_StringBuffer_append_char, java_lang_StringBuffer, append_name, char_StringBuffer_signature, F_Y) \
do_intrinsic(_StringBuffer_append_int, java_lang_StringBuffer, append_name, int_StringBuffer_signature, F_Y) \
do_intrinsic(_StringBuffer_append_String, java_lang_StringBuffer, append_name, String_StringBuffer_signature, F_Y) \
\
do_intrinsic(_StringBuffer_toString, java_lang_StringBuffer, toString_name, void_string_signature, F_Y) \
\
do_intrinsic(_Integer_toString, java_lang_Integer, toString_name, int_String_signature, F_S) \
\
do_intrinsic(_String_String, java_lang_String, object_initializer_name, string_void_signature, F_R) \
\
do_intrinsic(_Object_init, java_lang_Object, object_initializer_name, void_method_signature, F_R) \
/* (symbol object_initializer_name defined above) */ \
\
do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_array_object_object_signature, F_R) \ do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_array_object_object_signature, F_R) \
/* (symbols invoke_name and invoke_signature defined above) */ \ /* (symbols invoke_name and invoke_signature defined above) */ \
\ \
@ -945,11 +978,12 @@ class vmIntrinsics: AllStatic {
enum Flags { enum Flags {
// AccessFlags syndromes relevant to intrinsics. // AccessFlags syndromes relevant to intrinsics.
F_none = 0, F_none = 0,
F_R, // !static !synchronized (R="regular") F_R, // !static ?native !synchronized (R="regular")
F_S, // static !synchronized F_S, // static ?native !synchronized
F_RN, // !static native !synchronized F_Y, // !static ?native synchronized
F_SN, // static native !synchronized F_RN, // !static native !synchronized
F_RNY // !static native synchronized F_SN, // static native !synchronized
F_RNY // !static native synchronized
}; };
public: public:

View File

@ -149,6 +149,7 @@ c2compiler.cpp runtime.hpp
c2compiler.hpp abstractCompiler.hpp c2compiler.hpp abstractCompiler.hpp
callGenerator.cpp addnode.hpp callGenerator.cpp addnode.hpp
callGenerator.cpp bcEscapeAnalyzer.hpp
callGenerator.cpp callGenerator.hpp callGenerator.cpp callGenerator.hpp
callGenerator.cpp callnode.hpp callGenerator.cpp callnode.hpp
callGenerator.cpp cfgnode.hpp callGenerator.cpp cfgnode.hpp
@ -321,6 +322,7 @@ compile.cpp phaseX.hpp
compile.cpp rootnode.hpp compile.cpp rootnode.hpp
compile.cpp runtime.hpp compile.cpp runtime.hpp
compile.cpp signature.hpp compile.cpp signature.hpp
compile.cpp stringopts.hpp
compile.cpp stubRoutines.hpp compile.cpp stubRoutines.hpp
compile.cpp systemDictionary.hpp compile.cpp systemDictionary.hpp
compile.cpp timer.hpp compile.cpp timer.hpp
@ -476,12 +478,16 @@ graphKit.cpp rootnode.hpp
graphKit.cpp runtime.hpp graphKit.cpp runtime.hpp
graphKit.cpp sharedRuntime.hpp graphKit.cpp sharedRuntime.hpp
graphKit.hpp addnode.hpp
graphKit.hpp callnode.hpp graphKit.hpp callnode.hpp
graphKit.hpp cfgnode.hpp graphKit.hpp cfgnode.hpp
graphKit.hpp ciEnv.hpp graphKit.hpp ciEnv.hpp
graphKit.hpp divnode.hpp
graphKit.hpp compile.hpp graphKit.hpp compile.hpp
graphKit.hpp deoptimization.hpp graphKit.hpp deoptimization.hpp
graphKit.hpp phaseX.hpp graphKit.hpp phaseX.hpp
graphKit.hpp mulnode.hpp
graphKit.hpp subnode.hpp
graphKit.hpp type.hpp graphKit.hpp type.hpp
idealKit.cpp addnode.hpp idealKit.cpp addnode.hpp
@ -490,7 +496,10 @@ idealKit.cpp cfgnode.hpp
idealKit.cpp idealKit.hpp idealKit.cpp idealKit.hpp
idealKit.cpp runtime.hpp idealKit.cpp runtime.hpp
idealKit.hpp addnode.hpp
idealKit.hpp cfgnode.hpp
idealKit.hpp connode.hpp idealKit.hpp connode.hpp
idealKit.hpp divnode.hpp
idealKit.hpp mulnode.hpp idealKit.hpp mulnode.hpp
idealKit.hpp phaseX.hpp idealKit.hpp phaseX.hpp
idealKit.hpp subnode.hpp idealKit.hpp subnode.hpp
@ -641,6 +650,7 @@ macro.cpp addnode.hpp
macro.cpp callnode.hpp macro.cpp callnode.hpp
macro.cpp cfgnode.hpp macro.cpp cfgnode.hpp
macro.cpp compile.hpp macro.cpp compile.hpp
macro.cpp compileLog.hpp
macro.cpp connode.hpp macro.cpp connode.hpp
macro.cpp locknode.hpp macro.cpp locknode.hpp
macro.cpp loopnode.hpp macro.cpp loopnode.hpp
@ -993,6 +1003,21 @@ split_if.cpp callnode.hpp
split_if.cpp connode.hpp split_if.cpp connode.hpp
split_if.cpp loopnode.hpp split_if.cpp loopnode.hpp
stringopts.hpp phaseX.hpp
stringopts.hpp node.hpp
stringopts.cpp addnode.hpp
stringopts.cpp callnode.hpp
stringopts.cpp callGenerator.hpp
stringopts.cpp compileLog.hpp
stringopts.cpp divnode.hpp
stringopts.cpp idealKit.hpp
stringopts.cpp graphKit.hpp
stringopts.cpp rootnode.hpp
stringopts.cpp runtime.hpp
stringopts.cpp subnode.hpp
stringopts.cpp stringopts.hpp
stubGenerator_<arch_model>.cpp runtime.hpp stubGenerator_<arch_model>.cpp runtime.hpp
stubRoutines.cpp runtime.hpp stubRoutines.cpp runtime.hpp

View File

@ -570,6 +570,7 @@ ciEnv.hpp debugInfoRec.hpp
ciEnv.hpp dependencies.hpp ciEnv.hpp dependencies.hpp
ciEnv.hpp exceptionHandlerTable.hpp ciEnv.hpp exceptionHandlerTable.hpp
ciEnv.hpp oopMap.hpp ciEnv.hpp oopMap.hpp
ciEnv.hpp systemDictionary.hpp
ciEnv.hpp thread.hpp ciEnv.hpp thread.hpp
ciExceptionHandler.cpp ciExceptionHandler.hpp ciExceptionHandler.cpp ciExceptionHandler.hpp

View File

@ -67,6 +67,8 @@ typeArrayOop Universe::_the_empty_int_array = NULL;
objArrayOop Universe::_the_empty_system_obj_array = NULL; objArrayOop Universe::_the_empty_system_obj_array = NULL;
objArrayOop Universe::_the_empty_class_klass_array = NULL; objArrayOop Universe::_the_empty_class_klass_array = NULL;
objArrayOop Universe::_the_array_interfaces_array = NULL; objArrayOop Universe::_the_array_interfaces_array = NULL;
oop Universe::_the_null_string = NULL;
oop Universe::_the_min_jint_string = NULL;
LatestMethodOopCache* Universe::_finalizer_register_cache = NULL; LatestMethodOopCache* Universe::_finalizer_register_cache = NULL;
LatestMethodOopCache* Universe::_loader_addClass_cache = NULL; LatestMethodOopCache* Universe::_loader_addClass_cache = NULL;
ActiveMethodOopsCache* Universe::_reflect_invoke_cache = NULL; ActiveMethodOopsCache* Universe::_reflect_invoke_cache = NULL;
@ -187,6 +189,8 @@ void Universe::oops_do(OopClosure* f, bool do_all) {
f->do_oop((oop*)&_the_empty_system_obj_array); f->do_oop((oop*)&_the_empty_system_obj_array);
f->do_oop((oop*)&_the_empty_class_klass_array); f->do_oop((oop*)&_the_empty_class_klass_array);
f->do_oop((oop*)&_the_array_interfaces_array); f->do_oop((oop*)&_the_array_interfaces_array);
f->do_oop((oop*)&_the_null_string);
f->do_oop((oop*)&_the_min_jint_string);
_finalizer_register_cache->oops_do(f); _finalizer_register_cache->oops_do(f);
_loader_addClass_cache->oops_do(f); _loader_addClass_cache->oops_do(f);
_reflect_invoke_cache->oops_do(f); _reflect_invoke_cache->oops_do(f);
@ -289,6 +293,9 @@ void Universe::genesis(TRAPS) {
klassOop ok = SystemDictionary::object_klass(); klassOop ok = SystemDictionary::object_klass();
_the_null_string = StringTable::intern("null", CHECK);
_the_min_jint_string = StringTable::intern("-2147483648", CHECK);
if (UseSharedSpaces) { if (UseSharedSpaces) {
// Verify shared interfaces array. // Verify shared interfaces array.
assert(_the_array_interfaces_array->obj_at(0) == assert(_the_array_interfaces_array->obj_at(0) ==

View File

@ -169,6 +169,8 @@ class Universe: AllStatic {
static objArrayOop _the_empty_system_obj_array; // Canonicalized system obj array static objArrayOop _the_empty_system_obj_array; // Canonicalized system obj array
static objArrayOop _the_empty_class_klass_array; // Canonicalized obj array of type java.lang.Class static objArrayOop _the_empty_class_klass_array; // Canonicalized obj array of type java.lang.Class
static objArrayOop _the_array_interfaces_array; // Canonicalized 2-array of cloneable & serializable klasses static objArrayOop _the_array_interfaces_array; // Canonicalized 2-array of cloneable & serializable klasses
static oop _the_null_string; // A cache of "null" as a Java string
static oop _the_min_jint_string; // A cache of "-2147483648" as a Java string
static LatestMethodOopCache* _finalizer_register_cache; // static method for registering finalizable objects static LatestMethodOopCache* _finalizer_register_cache; // static method for registering finalizable objects
static LatestMethodOopCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector static LatestMethodOopCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector
static ActiveMethodOopsCache* _reflect_invoke_cache; // method for security checks static ActiveMethodOopsCache* _reflect_invoke_cache; // method for security checks
@ -310,6 +312,8 @@ class Universe: AllStatic {
static objArrayOop the_empty_system_obj_array () { return _the_empty_system_obj_array; } static objArrayOop the_empty_system_obj_array () { return _the_empty_system_obj_array; }
static objArrayOop the_empty_class_klass_array () { return _the_empty_class_klass_array; } static objArrayOop the_empty_class_klass_array () { return _the_empty_class_klass_array; }
static objArrayOop the_array_interfaces_array() { return _the_array_interfaces_array; } static objArrayOop the_array_interfaces_array() { return _the_array_interfaces_array; }
static oop the_null_string() { return _the_null_string; }
static oop the_min_jint_string() { return _the_min_jint_string; }
static methodOop finalizer_register_method() { return _finalizer_register_cache->get_methodOop(); } static methodOop finalizer_register_method() { return _finalizer_register_cache->get_methodOop(); }
static methodOop loader_addClass_method() { return _loader_addClass_cache->get_methodOop(); } static methodOop loader_addClass_method() { return _loader_addClass_cache->get_methodOop(); }
static ActiveMethodOopsCache* reflect_invoke_cache() { return _reflect_invoke_cache; } static ActiveMethodOopsCache* reflect_invoke_cache() { return _reflect_invoke_cache; }

View File

@ -25,4 +25,4 @@
# include "incls/_precompiled.incl" # include "incls/_precompiled.incl"
# include "incls/_c2_globals.cpp.incl" # include "incls/_c2_globals.cpp.incl"
C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_NOTPRODUCT_FLAG) 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)

View File

@ -26,7 +26,7 @@
// Defines all globals flags used by the server compiler. // Defines all globals flags used by the server compiler.
// //
#define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \ #define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct) \
\ \
notproduct(intx, CompileZapFirst, 0, \ notproduct(intx, CompileZapFirst, 0, \
"If +ZapDeadCompiledLocals, " \ "If +ZapDeadCompiledLocals, " \
@ -394,6 +394,12 @@
product(bool, UseOptoBiasInlining, true, \ product(bool, UseOptoBiasInlining, true, \
"Generate biased locking code in C2 ideal graph") \ "Generate biased locking code in C2 ideal graph") \
\ \
product(bool, OptimizeStringConcat, false, \
"Optimize the construction of Strings by StringBuilder") \
\
notproduct(bool, PrintOptimizeStringConcat, false, \
"Print information about transformations performed on Strings") \
\
product(intx, ValueSearchLimit, 1000, \ product(intx, ValueSearchLimit, 1000, \
"Recursion limit in PhaseMacroExpand::value_from_mem_phi") \ "Recursion limit in PhaseMacroExpand::value_from_mem_phi") \
\ \
@ -413,4 +419,4 @@
product(bool, BlockLayoutRotateLoops, true, \ product(bool, BlockLayoutRotateLoops, true, \
"Allow back branches to be fall throughs in the block layour") \ "Allow back branches to be fall throughs in the block layour") \
C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG) 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)

View File

@ -98,12 +98,21 @@ JVMState* ParseGenerator::generate(JVMState* jvms) {
//---------------------------DirectCallGenerator------------------------------ //---------------------------DirectCallGenerator------------------------------
// Internal class which handles all out-of-line calls w/o receiver type checks. // Internal class which handles all out-of-line calls w/o receiver type checks.
class DirectCallGenerator : public CallGenerator { class DirectCallGenerator : public CallGenerator {
public: private:
DirectCallGenerator(ciMethod* method) CallStaticJavaNode* _call_node;
: CallGenerator(method) // Force separate memory and I/O projections for the exceptional
// paths to facilitate late inlinig.
bool _separate_io_proj;
public:
DirectCallGenerator(ciMethod* method, bool separate_io_proj)
: CallGenerator(method),
_separate_io_proj(separate_io_proj)
{ {
} }
virtual JVMState* generate(JVMState* jvms); virtual JVMState* generate(JVMState* jvms);
CallStaticJavaNode* call_node() const { return _call_node; }
}; };
JVMState* DirectCallGenerator::generate(JVMState* jvms) { JVMState* DirectCallGenerator::generate(JVMState* jvms) {
@ -129,9 +138,10 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) {
call->set_optimized_virtual(true); call->set_optimized_virtual(true);
} }
kit.set_arguments_for_java_call(call); kit.set_arguments_for_java_call(call);
kit.set_edges_for_java_call(call); kit.set_edges_for_java_call(call, false, _separate_io_proj);
Node* ret = kit.set_results_for_java_call(call); Node* ret = kit.set_results_for_java_call(call, _separate_io_proj);
kit.push_node(method()->return_type()->basic_type(), ret); kit.push_node(method()->return_type()->basic_type(), ret);
_call_node = call; // Save the call node in case we need it later
return kit.transfer_exceptions_into_jvms(); return kit.transfer_exceptions_into_jvms();
} }
@ -238,9 +248,9 @@ CallGenerator* CallGenerator::for_osr(ciMethod* m, int osr_bci) {
return new ParseGenerator(m, expected_uses, true); return new ParseGenerator(m, expected_uses, true);
} }
CallGenerator* CallGenerator::for_direct_call(ciMethod* m) { CallGenerator* CallGenerator::for_direct_call(ciMethod* m, bool separate_io_proj) {
assert(!m->is_abstract(), "for_direct_call mismatch"); assert(!m->is_abstract(), "for_direct_call mismatch");
return new DirectCallGenerator(m); return new DirectCallGenerator(m, separate_io_proj);
} }
CallGenerator* CallGenerator::for_virtual_call(ciMethod* m, int vtable_index) { CallGenerator* CallGenerator::for_virtual_call(ciMethod* m, int vtable_index) {
@ -248,6 +258,108 @@ CallGenerator* CallGenerator::for_virtual_call(ciMethod* m, int vtable_index) {
return new VirtualCallGenerator(m, vtable_index); return new VirtualCallGenerator(m, vtable_index);
} }
// Allow inlining decisions to be delayed
class LateInlineCallGenerator : public DirectCallGenerator {
CallGenerator* _inline_cg;
public:
LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
DirectCallGenerator(method, true), _inline_cg(inline_cg) {}
virtual bool is_late_inline() const { return true; }
// Convert the CallStaticJava into an inline
virtual void do_late_inline();
JVMState* generate(JVMState* jvms) {
// Record that this call site should be revisited once the main
// parse is finished.
Compile::current()->add_late_inline(this);
// Emit the CallStaticJava and request separate projections so
// that the late inlining logic can distinguish between fall
// through and exceptional uses of the memory and io projections
// as is done for allocations and macro expansion.
return DirectCallGenerator::generate(jvms);
}
};
void LateInlineCallGenerator::do_late_inline() {
// Can't inline it
if (call_node() == NULL || call_node()->outcnt() == 0 ||
call_node()->in(0) == NULL || call_node()->in(0)->is_top())
return;
CallStaticJavaNode* call = call_node();
// Make a clone of the JVMState that appropriate to use for driving a parse
Compile* C = Compile::current();
JVMState* jvms = call->jvms()->clone_shallow(C);
uint size = call->req();
SafePointNode* map = new (C, size) SafePointNode(size, jvms);
for (uint i1 = 0; i1 < size; i1++) {
map->init_req(i1, call->in(i1));
}
// Make sure the state is a MergeMem for parsing.
if (!map->in(TypeFunc::Memory)->is_MergeMem()) {
map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory)));
}
// Make enough space for the expression stack and transfer the incoming arguments
int nargs = method()->arg_size();
jvms->set_map(map);
map->ensure_stack(jvms, jvms->method()->max_stack());
if (nargs > 0) {
for (int i1 = 0; i1 < nargs; i1++) {
map->set_req(i1 + jvms->argoff(), call->in(TypeFunc::Parms + i1));
}
}
CompileLog* log = C->log();
if (log != NULL) {
log->head("late_inline method='%d'", log->identify(method()));
JVMState* p = jvms;
while (p != NULL) {
log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
p = p->caller();
}
log->tail("late_inline");
}
// Setup default node notes to be picked up by the inlining
Node_Notes* old_nn = C->default_node_notes();
if (old_nn != NULL) {
Node_Notes* entry_nn = old_nn->clone(C);
entry_nn->set_jvms(jvms);
C->set_default_node_notes(entry_nn);
}
// Now perform the inling using the synthesized JVMState
JVMState* new_jvms = _inline_cg->generate(jvms);
if (new_jvms == NULL) return; // no change
if (C->failing()) return;
// Capture any exceptional control flow
GraphKit kit(new_jvms);
// Find the result object
Node* result = C->top();
int result_size = method()->return_type()->size();
if (result_size != 0 && !kit.stopped()) {
result = (result_size == 1) ? kit.pop() : kit.pop_pair();
}
kit.replace_call(call, result);
}
CallGenerator* CallGenerator::for_late_inline(ciMethod* method, CallGenerator* inline_cg) {
return new LateInlineCallGenerator(method, inline_cg);
}
//---------------------------WarmCallGenerator-------------------------------- //---------------------------WarmCallGenerator--------------------------------
// Internal class which handles initial deferral of inlining decisions. // Internal class which handles initial deferral of inlining decisions.
@ -315,70 +427,7 @@ JVMState* WarmCallGenerator::generate(JVMState* jvms) {
} }
void WarmCallInfo::make_hot() { void WarmCallInfo::make_hot() {
Compile* C = Compile::current(); Unimplemented();
// Replace the callnode with something better.
CallJavaNode* call = this->call()->as_CallJava();
ciMethod* method = call->method();
int nargs = method->arg_size();
JVMState* jvms = call->jvms()->clone_shallow(C);
uint size = TypeFunc::Parms + MAX2(2, nargs);
SafePointNode* map = new (C, size) SafePointNode(size, jvms);
for (uint i1 = 0; i1 < (uint)(TypeFunc::Parms + nargs); i1++) {
map->init_req(i1, call->in(i1));
}
jvms->set_map(map);
jvms->set_offsets(map->req());
jvms->set_locoff(TypeFunc::Parms);
jvms->set_stkoff(TypeFunc::Parms);
GraphKit kit(jvms);
JVMState* new_jvms = _hot_cg->generate(kit.jvms());
if (new_jvms == NULL) return; // no change
if (C->failing()) return;
kit.set_jvms(new_jvms);
Node* res = C->top();
int res_size = method->return_type()->size();
if (res_size != 0) {
kit.inc_sp(-res_size);
res = kit.argument(0);
}
GraphKit ekit(kit.combine_and_pop_all_exception_states()->jvms());
// Replace the call:
for (DUIterator i = call->outs(); call->has_out(i); i++) {
Node* n = call->out(i);
Node* nn = NULL; // replacement
if (n->is_Proj()) {
ProjNode* nproj = n->as_Proj();
assert(nproj->_con < (uint)(TypeFunc::Parms + (res_size ? 1 : 0)), "sane proj");
if (nproj->_con == TypeFunc::Parms) {
nn = res;
} else {
nn = kit.map()->in(nproj->_con);
}
if (nproj->_con == TypeFunc::I_O) {
for (DUIterator j = nproj->outs(); nproj->has_out(j); j++) {
Node* e = nproj->out(j);
if (e->Opcode() == Op_CreateEx) {
e->replace_by(ekit.argument(0));
} else if (e->Opcode() == Op_Catch) {
for (DUIterator k = e->outs(); e->has_out(k); k++) {
CatchProjNode* p = e->out(j)->as_CatchProj();
if (p->is_handler_proj()) {
p->replace_by(ekit.control());
} else {
p->replace_by(kit.control());
}
}
}
}
}
}
NOT_PRODUCT(if (!nn) n->dump(2));
assert(nn != NULL, "don't know what to do with this user");
n->replace_by(nn);
}
} }
void WarmCallInfo::make_cold() { void WarmCallInfo::make_cold() {

View File

@ -57,6 +57,13 @@ class CallGenerator : public ResourceObj {
// is_trap: Does not return to the caller. (E.g., uncommon trap.) // is_trap: Does not return to the caller. (E.g., uncommon trap.)
virtual bool is_trap() const { return false; } virtual bool is_trap() const { return false; }
// is_late_inline: supports conversion of call into an inline
virtual bool is_late_inline() const { return false; }
// Replace the call with an inline version of the code
virtual void do_late_inline() { ShouldNotReachHere(); }
virtual CallStaticJavaNode* call_node() const { ShouldNotReachHere(); return NULL; }
// Note: It is possible for a CG to be both inline and virtual. // Note: It is possible for a CG to be both inline and virtual.
// (The hashCode intrinsic does a vtable check and an inlined fast path.) // (The hashCode intrinsic does a vtable check and an inlined fast path.)
@ -92,9 +99,12 @@ class CallGenerator : public ResourceObj {
static CallGenerator* for_osr(ciMethod* m, int osr_bci); static CallGenerator* for_osr(ciMethod* m, int osr_bci);
// How to generate vanilla out-of-line call sites: // How to generate vanilla out-of-line call sites:
static CallGenerator* for_direct_call(ciMethod* m); // static, special static CallGenerator* for_direct_call(ciMethod* m, bool separate_io_projs = false); // static, special
static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface
// How to generate a replace a direct call with an inline version
static CallGenerator* for_late_inline(ciMethod* m, CallGenerator* inline_cg);
// How to make a call but defer the decision whether to inline or not. // How to make a call but defer the decision whether to inline or not.
static CallGenerator* for_warm_call(WarmCallInfo* ci, static CallGenerator* for_warm_call(WarmCallInfo* ci,
CallGenerator* if_cold, CallGenerator* if_cold,

View File

@ -693,6 +693,84 @@ Node *CallNode::result_cast() {
} }
void CallNode::extract_projections(CallProjections* projs, bool separate_io_proj) {
projs->fallthrough_proj = NULL;
projs->fallthrough_catchproj = NULL;
projs->fallthrough_ioproj = NULL;
projs->catchall_ioproj = NULL;
projs->catchall_catchproj = NULL;
projs->fallthrough_memproj = NULL;
projs->catchall_memproj = NULL;
projs->resproj = NULL;
projs->exobj = NULL;
for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) {
ProjNode *pn = fast_out(i)->as_Proj();
if (pn->outcnt() == 0) continue;
switch (pn->_con) {
case TypeFunc::Control:
{
// For Control (fallthrough) and I_O (catch_all_index) we have CatchProj -> Catch -> Proj
projs->fallthrough_proj = pn;
DUIterator_Fast jmax, j = pn->fast_outs(jmax);
const Node *cn = pn->fast_out(j);
if (cn->is_Catch()) {
ProjNode *cpn = NULL;
for (DUIterator_Fast kmax, k = cn->fast_outs(kmax); k < kmax; k++) {
cpn = cn->fast_out(k)->as_Proj();
assert(cpn->is_CatchProj(), "must be a CatchProjNode");
if (cpn->_con == CatchProjNode::fall_through_index)
projs->fallthrough_catchproj = cpn;
else {
assert(cpn->_con == CatchProjNode::catch_all_index, "must be correct index.");
projs->catchall_catchproj = cpn;
}
}
}
break;
}
case TypeFunc::I_O:
if (pn->_is_io_use)
projs->catchall_ioproj = pn;
else
projs->fallthrough_ioproj = pn;
for (DUIterator j = pn->outs(); pn->has_out(j); j++) {
Node* e = pn->out(j);
if (e->Opcode() == Op_CreateEx && e->in(0)->is_CatchProj()) {
assert(projs->exobj == NULL, "only one");
projs->exobj = e;
}
}
break;
case TypeFunc::Memory:
if (pn->_is_io_use)
projs->catchall_memproj = pn;
else
projs->fallthrough_memproj = pn;
break;
case TypeFunc::Parms:
projs->resproj = pn;
break;
default:
assert(false, "unexpected projection from allocation node.");
}
}
// The resproj may not exist because the result couuld be ignored
// and the exception object may not exist if an exception handler
// swallows the exception but all the other must exist and be found.
assert(projs->fallthrough_proj != NULL, "must be found");
assert(projs->fallthrough_catchproj != NULL, "must be found");
assert(projs->fallthrough_memproj != NULL, "must be found");
assert(projs->fallthrough_ioproj != NULL, "must be found");
assert(projs->catchall_catchproj != NULL, "must be found");
if (separate_io_proj) {
assert(projs->catchall_memproj != NULL, "must be found");
assert(projs->catchall_ioproj != NULL, "must be found");
}
}
//============================================================================= //=============================================================================
uint CallJavaNode::size_of() const { return sizeof(*this); } uint CallJavaNode::size_of() const { return sizeof(*this); }
uint CallJavaNode::cmp( const Node &n ) const { uint CallJavaNode::cmp( const Node &n ) const {

View File

@ -470,6 +470,23 @@ public:
#endif #endif
}; };
// Simple container for the outgoing projections of a call. Useful
// for serious surgery on calls.
class CallProjections : public StackObj {
public:
Node* fallthrough_proj;
Node* fallthrough_catchproj;
Node* fallthrough_memproj;
Node* fallthrough_ioproj;
Node* catchall_catchproj;
Node* catchall_memproj;
Node* catchall_ioproj;
Node* resproj;
Node* exobj;
};
//------------------------------CallNode--------------------------------------- //------------------------------CallNode---------------------------------------
// Call nodes now subsume the function of debug nodes at callsites, so they // Call nodes now subsume the function of debug nodes at callsites, so they
// contain the functionality of a full scope chain of debug nodes. // contain the functionality of a full scope chain of debug nodes.
@ -521,6 +538,11 @@ public:
// or returns NULL if there is no one. // or returns NULL if there is no one.
Node *result_cast(); Node *result_cast();
// Collect all the interesting edges from a call for use in
// replacing the call by something else. Used by macro expansion
// and the late inlining support.
void extract_projections(CallProjections* projs, bool separate_io_proj);
virtual uint match_edge(uint idx) const; virtual uint match_edge(uint idx) const;
#ifndef PRODUCT #ifndef PRODUCT
@ -529,6 +551,7 @@ public:
#endif #endif
}; };
//------------------------------CallJavaNode----------------------------------- //------------------------------CallJavaNode-----------------------------------
// Make a static or dynamic subroutine call node using Java calling // Make a static or dynamic subroutine call node using Java calling
// convention. (The "Java" calling convention is the compiler's calling // convention. (The "Java" calling convention is the compiler's calling

View File

@ -224,6 +224,32 @@ bool Compile::valid_bundle_info(const Node *n) {
} }
void Compile::gvn_replace_by(Node* n, Node* nn) {
for (DUIterator_Last imin, i = n->last_outs(imin); i >= imin; ) {
Node* use = n->last_out(i);
bool is_in_table = initial_gvn()->hash_delete(use);
uint uses_found = 0;
for (uint j = 0; j < use->len(); j++) {
if (use->in(j) == n) {
if (j < use->req())
use->set_req(j, nn);
else
use->set_prec(j, nn);
uses_found++;
}
}
if (is_in_table) {
// reinsert into table
initial_gvn()->hash_find_insert(use);
}
record_for_igvn(use);
i -= uses_found; // we deleted 1 or more copies of this edge
}
}
// Identify all nodes that are reachable from below, useful. // Identify all nodes that are reachable from below, useful.
// Use breadth-first pass that records state in a Unique_Node_List, // Use breadth-first pass that records state in a Unique_Node_List,
// recursive traversal is slower. // recursive traversal is slower.
@ -554,6 +580,28 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
rethrow_exceptions(kit.transfer_exceptions_into_jvms()); rethrow_exceptions(kit.transfer_exceptions_into_jvms());
} }
if (!failing() && has_stringbuilder()) {
{
// remove useless nodes to make the usage analysis simpler
ResourceMark rm;
PhaseRemoveUseless pru(initial_gvn(), &for_igvn);
}
{
ResourceMark rm;
print_method("Before StringOpts", 3);
PhaseStringOpts pso(initial_gvn(), &for_igvn);
print_method("After StringOpts", 3);
}
// now inline anything that we skipped the first time around
while (_late_inlines.length() > 0) {
CallGenerator* cg = _late_inlines.pop();
cg->do_late_inline();
}
}
assert(_late_inlines.length() == 0, "should have been processed");
print_method("Before RemoveUseless", 3); print_method("Before RemoveUseless", 3);
// Remove clutter produced by parsing. // Remove clutter produced by parsing.
@ -820,6 +868,7 @@ void Compile::Init(int aliaslevel) {
_fixed_slots = 0; _fixed_slots = 0;
set_has_split_ifs(false); set_has_split_ifs(false);
set_has_loops(has_method() && method()->has_loops()); // first approximation set_has_loops(has_method() && method()->has_loops()); // first approximation
set_has_stringbuilder(false);
_deopt_happens = true; // start out assuming the worst _deopt_happens = true; // start out assuming the worst
_trap_can_recompile = false; // no traps emitted yet _trap_can_recompile = false; // no traps emitted yet
_major_progress = true; // start out assuming good things will happen _major_progress = true; // start out assuming good things will happen
@ -2240,6 +2289,30 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc ) {
break; break;
} }
case Op_Proj: {
if (OptimizeStringConcat) {
ProjNode* p = n->as_Proj();
if (p->_is_io_use) {
// Separate projections were used for the exception path which
// are normally removed by a late inline. If it wasn't inlined
// then they will hang around and should just be replaced with
// the original one.
Node* proj = NULL;
// Replace with just one
for (SimpleDUIterator i(p->in(0)); i.has_next(); i.next()) {
Node *use = i.get();
if (use->is_Proj() && p != use && use->as_Proj()->_con == p->_con) {
proj = use;
break;
}
}
assert(p != NULL, "must be found");
p->subsume_by(proj);
}
}
break;
}
case Op_Phi: case Op_Phi:
if (n->as_Phi()->bottom_type()->isa_narrowoop()) { if (n->as_Phi()->bottom_type()->isa_narrowoop()) {
// The EncodeP optimization may create Phi with the same edges // The EncodeP optimization may create Phi with the same edges

View File

@ -149,6 +149,7 @@ class Compile : public Phase {
bool _has_loops; // True if the method _may_ have some loops bool _has_loops; // True if the method _may_ have some loops
bool _has_split_ifs; // True if the method _may_ have some split-if bool _has_split_ifs; // True if the method _may_ have some split-if
bool _has_unsafe_access; // True if the method _may_ produce faults in unsafe loads or stores. bool _has_unsafe_access; // True if the method _may_ produce faults in unsafe loads or stores.
bool _has_stringbuilder; // True StringBuffers or StringBuilders are allocated
uint _trap_hist[trapHistLength]; // Cumulative traps uint _trap_hist[trapHistLength]; // Cumulative traps
bool _trap_can_recompile; // Have we emitted a recompiling trap? bool _trap_can_recompile; // Have we emitted a recompiling trap?
uint _decompile_count; // Cumulative decompilation counts. uint _decompile_count; // Cumulative decompilation counts.
@ -219,6 +220,9 @@ class Compile : public Phase {
Unique_Node_List* _for_igvn; // Initial work-list for next round of Iterative GVN Unique_Node_List* _for_igvn; // Initial work-list for next round of Iterative GVN
WarmCallInfo* _warm_calls; // Sorted work-list for heat-based inlining. WarmCallInfo* _warm_calls; // Sorted work-list for heat-based inlining.
GrowableArray<CallGenerator*> _late_inlines; // List of CallGenerators to be revisited after
// main parsing has finished.
// Matching, CFG layout, allocation, code generation // Matching, CFG layout, allocation, code generation
PhaseCFG* _cfg; // Results of CFG finding PhaseCFG* _cfg; // Results of CFG finding
bool _select_24_bit_instr; // We selected an instruction with a 24-bit result bool _select_24_bit_instr; // We selected an instruction with a 24-bit result
@ -298,6 +302,8 @@ class Compile : public Phase {
void set_has_split_ifs(bool z) { _has_split_ifs = z; } void set_has_split_ifs(bool z) { _has_split_ifs = z; }
bool has_unsafe_access() const { return _has_unsafe_access; } bool has_unsafe_access() const { return _has_unsafe_access; }
void set_has_unsafe_access(bool z) { _has_unsafe_access = z; } void set_has_unsafe_access(bool z) { _has_unsafe_access = z; }
bool has_stringbuilder() const { return _has_stringbuilder; }
void set_has_stringbuilder(bool z) { _has_stringbuilder = z; }
void set_trap_count(uint r, uint c) { assert(r < trapHistLength, "oob"); _trap_hist[r] = c; } void set_trap_count(uint r, uint c) { assert(r < trapHistLength, "oob"); _trap_hist[r] = c; }
uint trap_count(uint r) const { assert(r < trapHistLength, "oob"); return _trap_hist[r]; } uint trap_count(uint r) const { assert(r < trapHistLength, "oob"); return _trap_hist[r]; }
bool trap_can_recompile() const { return _trap_can_recompile; } bool trap_can_recompile() const { return _trap_can_recompile; }
@ -475,6 +481,7 @@ class Compile : public Phase {
// Decide how to build a call. // Decide how to build a call.
// The profile factor is a discount to apply to this site's interp. profile. // The profile factor is a discount to apply to this site's interp. profile.
CallGenerator* call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, JVMState* jvms, bool allow_inline, float profile_factor); CallGenerator* call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, JVMState* jvms, bool allow_inline, float profile_factor);
bool should_delay_inlining(ciMethod* call_method, JVMState* jvms);
// Report if there were too many traps at a current method and bci. // Report if there were too many traps at a current method and bci.
// Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded. // Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded.
@ -495,6 +502,11 @@ class Compile : public Phase {
void set_initial_gvn(PhaseGVN *gvn) { _initial_gvn = gvn; } void set_initial_gvn(PhaseGVN *gvn) { _initial_gvn = gvn; }
void set_for_igvn(Unique_Node_List *for_igvn) { _for_igvn = for_igvn; } void set_for_igvn(Unique_Node_List *for_igvn) { _for_igvn = for_igvn; }
// Replace n by nn using initial_gvn, calling hash_delete and
// record_for_igvn as needed.
void gvn_replace_by(Node* n, Node* nn);
void identify_useful_nodes(Unique_Node_List &useful); void identify_useful_nodes(Unique_Node_List &useful);
void remove_useless_nodes (Unique_Node_List &useful); void remove_useless_nodes (Unique_Node_List &useful);
@ -502,6 +514,9 @@ class Compile : public Phase {
void set_warm_calls(WarmCallInfo* l) { _warm_calls = l; } void set_warm_calls(WarmCallInfo* l) { _warm_calls = l; }
WarmCallInfo* pop_warm_call(); WarmCallInfo* pop_warm_call();
// Record this CallGenerator for inlining at the end of parsing.
void add_late_inline(CallGenerator* cg) { _late_inlines.push(cg); }
// Matching, CFG layout, allocation, code generation // Matching, CFG layout, allocation, code generation
PhaseCFG* cfg() { return _cfg; } PhaseCFG* cfg() { return _cfg; }
bool select_24_bit_instr() const { return _select_24_bit_instr; } bool select_24_bit_instr() const { return _select_24_bit_instr; }

View File

@ -128,6 +128,12 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
if (allow_inline) { if (allow_inline) {
CallGenerator* cg = CallGenerator::for_inline(call_method, expected_uses); CallGenerator* cg = CallGenerator::for_inline(call_method, expected_uses);
if (require_inline && cg != NULL && should_delay_inlining(call_method, jvms)) {
// Delay the inlining of this method to give us the
// opportunity to perform some high level optimizations
// first.
return CallGenerator::for_late_inline(call_method, cg);
}
if (cg == NULL) { if (cg == NULL) {
// Fall through. // Fall through.
} else if (require_inline || !InlineWarmCalls) { } else if (require_inline || !InlineWarmCalls) {
@ -225,10 +231,63 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
} else { } else {
// Class Hierarchy Analysis or Type Profile reveals a unique target, // Class Hierarchy Analysis or Type Profile reveals a unique target,
// or it is a static or special call. // or it is a static or special call.
return CallGenerator::for_direct_call(call_method); return CallGenerator::for_direct_call(call_method, should_delay_inlining(call_method, jvms));
} }
} }
// Return true for methods that shouldn't be inlined early so that
// they are easier to analyze and optimize as intrinsics.
bool Compile::should_delay_inlining(ciMethod* call_method, JVMState* jvms) {
if (has_stringbuilder()) {
if ((call_method->holder() == C->env()->StringBuilder_klass() ||
call_method->holder() == C->env()->StringBuffer_klass()) &&
(jvms->method()->holder() == C->env()->StringBuilder_klass() ||
jvms->method()->holder() == C->env()->StringBuffer_klass())) {
// Delay SB calls only when called from non-SB code
return false;
}
switch (call_method->intrinsic_id()) {
case vmIntrinsics::_StringBuilder_void:
case vmIntrinsics::_StringBuilder_int:
case vmIntrinsics::_StringBuilder_String:
case vmIntrinsics::_StringBuilder_append_char:
case vmIntrinsics::_StringBuilder_append_int:
case vmIntrinsics::_StringBuilder_append_String:
case vmIntrinsics::_StringBuilder_toString:
case vmIntrinsics::_StringBuffer_void:
case vmIntrinsics::_StringBuffer_int:
case vmIntrinsics::_StringBuffer_String:
case vmIntrinsics::_StringBuffer_append_char:
case vmIntrinsics::_StringBuffer_append_int:
case vmIntrinsics::_StringBuffer_append_String:
case vmIntrinsics::_StringBuffer_toString:
case vmIntrinsics::_Integer_toString:
return true;
case vmIntrinsics::_String_String:
{
Node* receiver = jvms->map()->in(jvms->argoff() + 1);
if (receiver->is_Proj() && receiver->in(0)->is_CallStaticJava()) {
CallStaticJavaNode* csj = receiver->in(0)->as_CallStaticJava();
ciMethod* m = csj->method();
if (m != NULL &&
(m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString ||
m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString))
// Delay String.<init>(new SB())
return true;
}
return false;
}
default:
return false;
}
}
return false;
}
// uncommon-trap call-sites where callee is unloaded, uninitialized or will not link // uncommon-trap call-sites where callee is unloaded, uninitialized or will not link
bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* klass) { bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* klass) {

View File

@ -1351,8 +1351,8 @@ void GraphKit::set_all_memory(Node* newmem) {
} }
//------------------------------set_all_memory_call---------------------------- //------------------------------set_all_memory_call----------------------------
void GraphKit::set_all_memory_call(Node* call) { void GraphKit::set_all_memory_call(Node* call, bool separate_io_proj) {
Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) ); Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory, separate_io_proj) );
set_all_memory(newmem); set_all_memory(newmem);
} }
@ -1573,7 +1573,7 @@ void GraphKit::set_arguments_for_java_call(CallJavaNode* call) {
//---------------------------set_edges_for_java_call--------------------------- //---------------------------set_edges_for_java_call---------------------------
// Connect a newly created call into the current JVMS. // Connect a newly created call into the current JVMS.
// A return value node (if any) is returned from set_edges_for_java_call. // A return value node (if any) is returned from set_edges_for_java_call.
void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw) { void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw, bool separate_io_proj) {
// Add the predefined inputs: // Add the predefined inputs:
call->init_req( TypeFunc::Control, control() ); call->init_req( TypeFunc::Control, control() );
@ -1595,13 +1595,13 @@ void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw) {
// Re-use the current map to produce the result. // Re-use the current map to produce the result.
set_control(_gvn.transform(new (C, 1) ProjNode(call, TypeFunc::Control))); set_control(_gvn.transform(new (C, 1) ProjNode(call, TypeFunc::Control)));
set_i_o( _gvn.transform(new (C, 1) ProjNode(call, TypeFunc::I_O ))); set_i_o( _gvn.transform(new (C, 1) ProjNode(call, TypeFunc::I_O , separate_io_proj)));
set_all_memory_call(xcall); set_all_memory_call(xcall, separate_io_proj);
//return xcall; // no need, caller already has it //return xcall; // no need, caller already has it
} }
Node* GraphKit::set_results_for_java_call(CallJavaNode* call) { Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_proj) {
if (stopped()) return top(); // maybe the call folded up? if (stopped()) return top(); // maybe the call folded up?
// Capture the return value, if any. // Capture the return value, if any.
@ -1614,8 +1614,15 @@ Node* GraphKit::set_results_for_java_call(CallJavaNode* call) {
// Note: Since any out-of-line call can produce an exception, // Note: Since any out-of-line call can produce an exception,
// we always insert an I_O projection from the call into the result. // we always insert an I_O projection from the call into the result.
make_slow_call_ex(call, env()->Throwable_klass(), false); make_slow_call_ex(call, env()->Throwable_klass(), separate_io_proj);
if (separate_io_proj) {
// The caller requested separate projections be used by the fall
// through and exceptional paths, so replace the projections for
// the fall through path.
set_i_o(_gvn.transform( new (C, 1) ProjNode(call, TypeFunc::I_O) ));
set_all_memory(_gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) ));
}
return ret; return ret;
} }
@ -1678,6 +1685,59 @@ void GraphKit::set_predefined_output_for_runtime_call(Node* call,
} }
} }
// Replace the call with the current state of the kit.
void GraphKit::replace_call(CallNode* call, Node* result) {
JVMState* ejvms = NULL;
if (has_exceptions()) {
ejvms = transfer_exceptions_into_jvms();
}
SafePointNode* final_state = stop();
// Find all the needed outputs of this call
CallProjections callprojs;
call->extract_projections(&callprojs, true);
// Replace all the old call edges with the edges from the inlining result
C->gvn_replace_by(callprojs.fallthrough_catchproj, final_state->in(TypeFunc::Control));
C->gvn_replace_by(callprojs.fallthrough_memproj, final_state->in(TypeFunc::Memory));
C->gvn_replace_by(callprojs.fallthrough_ioproj, final_state->in(TypeFunc::I_O));
// Replace the result with the new result if it exists and is used
if (callprojs.resproj != NULL && result != NULL) {
C->gvn_replace_by(callprojs.resproj, result);
}
if (ejvms == NULL) {
// No exception edges to simply kill off those paths
C->gvn_replace_by(callprojs.catchall_catchproj, C->top());
C->gvn_replace_by(callprojs.catchall_memproj, C->top());
C->gvn_replace_by(callprojs.catchall_ioproj, C->top());
} else {
GraphKit ekit(ejvms);
// Load my combined exception state into the kit, with all phis transformed:
SafePointNode* ex_map = ekit.combine_and_pop_all_exception_states();
Node* ex_oop = ekit.use_exception_state(ex_map);
C->gvn_replace_by(callprojs.catchall_catchproj, ekit.control());
C->gvn_replace_by(callprojs.catchall_memproj, ekit.reset_memory());
C->gvn_replace_by(callprojs.catchall_ioproj, ekit.i_o());
// Replace the old exception object with the newly created one
if (callprojs.exobj != NULL) {
C->gvn_replace_by(callprojs.exobj, ex_oop);
}
}
// Disconnect the call from the graph
call->disconnect_inputs(NULL);
C->gvn_replace_by(call, C->top());
}
//------------------------------increment_counter------------------------------ //------------------------------increment_counter------------------------------
// for statistics: increment a VM counter by 1 // for statistics: increment a VM counter by 1
@ -3459,4 +3519,3 @@ void GraphKit::g1_write_barrier_post(Node* oop_store,
sync_kit(ideal); sync_kit(ideal);
} }
#undef __ #undef __

View File

@ -279,6 +279,34 @@ class GraphKit : public Phase {
} }
Node* basic_plus_adr(Node* base, Node* ptr, Node* offset); Node* basic_plus_adr(Node* base, Node* ptr, Node* offset);
// Some convenient shortcuts for common nodes
Node* IfTrue(IfNode* iff) { return _gvn.transform(new (C,1) IfTrueNode(iff)); }
Node* IfFalse(IfNode* iff) { return _gvn.transform(new (C,1) IfFalseNode(iff)); }
Node* AddI(Node* l, Node* r) { return _gvn.transform(new (C,3) AddINode(l, r)); }
Node* SubI(Node* l, Node* r) { return _gvn.transform(new (C,3) SubINode(l, r)); }
Node* MulI(Node* l, Node* r) { return _gvn.transform(new (C,3) MulINode(l, r)); }
Node* DivI(Node* ctl, Node* l, Node* r) { return _gvn.transform(new (C,3) DivINode(ctl, l, r)); }
Node* AndI(Node* l, Node* r) { return _gvn.transform(new (C,3) AndINode(l, r)); }
Node* OrI(Node* l, Node* r) { return _gvn.transform(new (C,3) OrINode(l, r)); }
Node* XorI(Node* l, Node* r) { return _gvn.transform(new (C,3) XorINode(l, r)); }
Node* MaxI(Node* l, Node* r) { return _gvn.transform(new (C,3) MaxINode(l, r)); }
Node* MinI(Node* l, Node* r) { return _gvn.transform(new (C,3) MinINode(l, r)); }
Node* LShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) LShiftINode(l, r)); }
Node* RShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) RShiftINode(l, r)); }
Node* URShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) URShiftINode(l, r)); }
Node* CmpI(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpINode(l, r)); }
Node* CmpL(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpLNode(l, r)); }
Node* CmpP(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpPNode(l, r)); }
Node* Bool(Node* cmp, BoolTest::mask relop) { return _gvn.transform(new (C,2) BoolNode(cmp, relop)); }
Node* AddP(Node* b, Node* a, Node* o) { return _gvn.transform(new (C,4) AddPNode(b, a, o)); }
// Convert between int and long, and size_t. // Convert between int and long, and size_t.
// (See macros ConvI2X, etc., in type.hpp for ConvI2X, etc.) // (See macros ConvI2X, etc., in type.hpp for ConvI2X, etc.)
Node* ConvI2L(Node* offset); Node* ConvI2L(Node* offset);
@ -400,7 +428,7 @@ class GraphKit : public Phase {
void set_all_memory(Node* newmem); void set_all_memory(Node* newmem);
// Create a memory projection from the call, then set_all_memory. // Create a memory projection from the call, then set_all_memory.
void set_all_memory_call(Node* call); void set_all_memory_call(Node* call, bool separate_io_proj = false);
// Create a LoadNode, reading from the parser's memory state. // Create a LoadNode, reading from the parser's memory state.
// (Note: require_atomic_access is useful only with T_LONG.) // (Note: require_atomic_access is useful only with T_LONG.)
@ -543,12 +571,12 @@ class GraphKit : public Phase {
// Transform the call, and update the basics: control, i_o, memory. // Transform the call, and update the basics: control, i_o, memory.
// (The next step is usually to call set_results_for_java_call.) // (The next step is usually to call set_results_for_java_call.)
void set_edges_for_java_call(CallJavaNode* call, void set_edges_for_java_call(CallJavaNode* call,
bool must_throw = false); bool must_throw = false, bool separate_io_proj = false);
// Finish up a java call that was started by set_edges_for_java_call. // Finish up a java call that was started by set_edges_for_java_call.
// Call add_exception on any throw arising from the call. // Call add_exception on any throw arising from the call.
// Return the call result (transformed). // Return the call result (transformed).
Node* set_results_for_java_call(CallJavaNode* call); Node* set_results_for_java_call(CallJavaNode* call, bool separate_io_proj = false);
// Similar to set_edges_for_java_call, but simplified for runtime calls. // Similar to set_edges_for_java_call, but simplified for runtime calls.
void set_predefined_output_for_runtime_call(Node* call) { void set_predefined_output_for_runtime_call(Node* call) {
@ -559,6 +587,11 @@ class GraphKit : public Phase {
const TypePtr* hook_mem); const TypePtr* hook_mem);
Node* set_predefined_input_for_runtime_call(SafePointNode* call); Node* set_predefined_input_for_runtime_call(SafePointNode* call);
// Replace the call with the current state of the kit. Requires
// that the call was generated with separate io_projs so that
// exceptional control flow can be handled properly.
void replace_call(CallNode* call, Node* result);
// helper functions for statistics // helper functions for statistics
void increment_counter(address counter_addr); // increment a debug counter void increment_counter(address counter_addr); // increment a debug counter
void increment_counter(Node* counter_addr); // increment a debug counter void increment_counter(Node* counter_addr); // increment a debug counter

View File

@ -912,15 +912,29 @@ bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) {
return false; return false;
} }
CompileLog* log = C->log();
if (log != NULL) {
Node* klass = alloc->in(AllocateNode::KlassNode);
const TypeKlassPtr* tklass = _igvn.type(klass)->is_klassptr();
log->head("eliminate_allocation type='%d'",
log->identify(tklass->klass()));
JVMState* p = alloc->jvms();
while (p != NULL) {
log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
p = p->caller();
}
log->tail("eliminate_allocation");
}
process_users_of_allocation(alloc); process_users_of_allocation(alloc);
#ifndef PRODUCT #ifndef PRODUCT
if (PrintEliminateAllocations) { if (PrintEliminateAllocations) {
if (alloc->is_AllocateArray()) if (alloc->is_AllocateArray())
tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx); tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx);
else else
tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx); tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx);
} }
#endif #endif
return true; return true;
@ -1639,6 +1653,18 @@ bool PhaseMacroExpand::eliminate_locking_node(AbstractLockNode *alock) {
} // if (!oldbox->is_eliminated()) } // if (!oldbox->is_eliminated())
} // if (alock->is_Lock() && !lock->is_coarsened()) } // if (alock->is_Lock() && !lock->is_coarsened())
CompileLog* log = C->log();
if (log != NULL) {
log->head("eliminate_lock lock='%d'",
alock->is_Lock());
JVMState* p = alock->jvms();
while (p != NULL) {
log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
p = p->caller();
}
log->tail("eliminate_lock");
}
#ifndef PRODUCT #ifndef PRODUCT
if (PrintEliminateLocks) { if (PrintEliminateLocks) {
if (alock->is_Lock()) { if (alock->is_Lock()) {

View File

@ -1503,6 +1503,8 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
} }
} }
} else if (tp->base() == Type::InstPtr) { } else if (tp->base() == Type::InstPtr) {
const TypeInstPtr* tinst = tp->is_instptr();
ciKlass* klass = tinst->klass();
assert( off != Type::OffsetBot || assert( off != Type::OffsetBot ||
// arrays can be cast to Objects // arrays can be cast to Objects
tp->is_oopptr()->klass()->is_java_lang_Object() || tp->is_oopptr()->klass()->is_java_lang_Object() ||
@ -1510,6 +1512,25 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
phase->C->has_unsafe_access(), phase->C->has_unsafe_access(),
"Field accesses must be precise" ); "Field accesses must be precise" );
// For oop loads, we expect the _type to be precise // For oop loads, we expect the _type to be precise
if (OptimizeStringConcat && klass == phase->C->env()->String_klass() &&
adr->is_AddP() && off != Type::OffsetBot) {
// For constant Strings treat the fields as compile time constants.
Node* base = adr->in(AddPNode::Base);
if (base->Opcode() == Op_ConP) {
const TypeOopPtr* t = phase->type(base)->isa_oopptr();
ciObject* string = t->const_oop();
ciConstant constant = string->as_instance()->field_value_by_offset(off);
if (constant.basic_type() == T_INT) {
return TypeInt::make(constant.as_int());
} else if (constant.basic_type() == T_ARRAY) {
if (adr->bottom_type()->is_ptr_to_narrowoop()) {
return TypeNarrowOop::make_from_constant(constant.as_object());
} else {
return TypeOopPtr::make_from_constant(constant.as_object());
}
}
}
}
} else if (tp->base() == Type::KlassPtr) { } else if (tp->base() == Type::KlassPtr) {
assert( off != Type::OffsetBot || assert( off != Type::OffsetBot ||
// arrays can be cast to Objects // arrays can be cast to Objects

View File

@ -661,18 +661,25 @@ public:
return (_flags & Flag_is_Call) != 0; return (_flags & Flag_is_Call) != 0;
} }
CallNode* isa_Call() const {
return is_Call() ? as_Call() : NULL;
}
CallNode *as_Call() const { // Only for CallNode (not for MachCallNode) CallNode *as_Call() const { // Only for CallNode (not for MachCallNode)
assert((_class_id & ClassMask_Call) == Class_Call, "invalid node class"); assert((_class_id & ClassMask_Call) == Class_Call, "invalid node class");
return (CallNode*)this; return (CallNode*)this;
} }
#define DEFINE_CLASS_QUERY(type) \ #define DEFINE_CLASS_QUERY(type) \
bool is_##type() const { \ bool is_##type() const { \
return ((_class_id & ClassMask_##type) == Class_##type); \ return ((_class_id & ClassMask_##type) == Class_##type); \
} \ } \
type##Node *as_##type() const { \ type##Node *as_##type() const { \
assert(is_##type(), "invalid node class"); \ assert(is_##type(), "invalid node class"); \
return (type##Node*)this; \ return (type##Node*)this; \
} \
type##Node* isa_##type() const { \
return (is_##type()) ? as_##type() : NULL; \
} }
DEFINE_CLASS_QUERY(AbstractLock) DEFINE_CLASS_QUERY(AbstractLock)
@ -1249,6 +1256,24 @@ Node* Node::last_out(DUIterator_Last& i) const {
#undef I_VDUI_ONLY #undef I_VDUI_ONLY
#undef VDUI_ONLY #undef VDUI_ONLY
// An Iterator that truly follows the iterator pattern. Doesn't
// support deletion but could be made to.
//
// for (SimpleDUIterator i(n); i.has_next(); i.next()) {
// Node* m = i.get();
//
class SimpleDUIterator : public StackObj {
private:
Node* node;
DUIterator_Fast i;
DUIterator_Fast imax;
public:
SimpleDUIterator(Node* n): node(n), i(n->fast_outs(imax)) {}
bool has_next() { return i < imax; }
void next() { i++; }
Node* get() { return node->fast_out(i); }
};
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Map dense integer indices to Nodes. Uses classic doubling-array trick. // Map dense integer indices to Nodes. Uses classic doubling-array trick.
@ -1290,6 +1315,12 @@ class Node_List : public Node_Array {
public: public:
Node_List() : Node_Array(Thread::current()->resource_area()), _cnt(0) {} Node_List() : Node_Array(Thread::current()->resource_area()), _cnt(0) {}
Node_List(Arena *a) : Node_Array(a), _cnt(0) {} Node_List(Arena *a) : Node_Array(a), _cnt(0) {}
bool contains(Node* n) {
for (uint e = 0; e < size(); e++) {
if (at(e) == n) return true;
}
return false;
}
void insert( uint i, Node *n ) { Node_Array::insert(i,n); _cnt++; } void insert( uint i, Node *n ) { Node_Array::insert(i,n); _cnt++; }
void remove( uint i ) { Node_Array::remove(i); _cnt--; } void remove( uint i ) { Node_Array::remove(i); _cnt--; }
void push( Node *b ) { map(_cnt++,b); } void push( Node *b ) { map(_cnt++,b); }

View File

@ -221,6 +221,14 @@ void Parse::do_new() {
// Push resultant oop onto stack // Push resultant oop onto stack
push(obj); push(obj);
// Keep track of whether opportunities exist for StringBuilder
// optimizations.
if (OptimizeStringConcat &&
(klass == C->env()->StringBuilder_klass() ||
klass == C->env()->StringBuffer_klass())) {
C->set_has_stringbuilder(true);
}
} }
#ifndef PRODUCT #ifndef PRODUCT

View File

@ -44,6 +44,7 @@ public:
BlockLayout, // Linear ordering of blocks BlockLayout, // Linear ordering of blocks
Register_Allocation, // Register allocation, duh Register_Allocation, // Register allocation, duh
LIVE, // Dragon-book LIVE range problem LIVE, // Dragon-book LIVE range problem
StringOpts, // StringBuilder related optimizations
Interference_Graph, // Building the IFG Interference_Graph, // Building the IFG
Coalesce, // Coalescing copies Coalesce, // Coalescing copies
Ideal_Loop, // Find idealized trip-counted loops Ideal_Loop, // Find idealized trip-counted loops

View File

@ -345,7 +345,11 @@ public:
Node *hash_find(const Node *n) { return _table.hash_find(n); } Node *hash_find(const Node *n) { return _table.hash_find(n); }
// Used after parsing to eliminate values that are no longer in program // Used after parsing to eliminate values that are no longer in program
void remove_useless_nodes(VectorSet &useful) { _table.remove_useless_nodes(useful); } void remove_useless_nodes(VectorSet &useful) {
_table.remove_useless_nodes(useful);
// this may invalidate cached cons so reset the cache
init_con_caches();
}
virtual ConNode* uncached_makecon(const Type* t); // override from PhaseTransform virtual ConNode* uncached_makecon(const Type* t); // override from PhaseTransform

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,83 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
class StringConcat;
class PhaseStringOpts : public Phase {
friend class StringConcat;
private:
PhaseGVN* _gvn;
// List of dead nodes to clean up aggressively at the end
Unique_Node_List dead_worklist;
// Memory slices needed for code gen
int char_adr_idx;
int value_field_idx;
int count_field_idx;
int offset_field_idx;
// Integer.sizeTable - used for int to String conversion
ciField* size_table_field;
// A set for use by various stages
VectorSet _visited;
// Collect a list of all SB.toString calls
Node_List collect_toString_calls();
// Examine the use of the SB alloc to see if it can be replace with
// a single string construction.
StringConcat* build_candidate(CallStaticJavaNode* call);
// Replace all the SB calls in concat with an optimization String allocation
void replace_string_concat(StringConcat* concat);
// Load the value of a static field, performing any constant folding.
Node* fetch_static_field(GraphKit& kit, ciField* field);
// Compute the number of characters required to represent the int value
Node* int_stringSize(GraphKit& kit, Node* value);
// Copy the characters representing value into char_array starting at start
void int_getChars(GraphKit& kit, Node* value, Node* char_array, Node* start, Node* end);
// Copy of the contents of the String str into char_array starting at index start.
Node* copy_string(GraphKit& kit, Node* str, Node* char_array, Node* start);
// Clean up any leftover nodes
void record_dead_node(Node* node);
void remove_dead_nodes();
PhaseGVN* gvn() { return _gvn; }
enum {
// max length of constant string copy unrolling in copy_string
unroll_string_copy_length = 6
};
public:
PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List* worklist);
};

View File

@ -847,9 +847,6 @@ public:
// Constant pointer to array // Constant pointer to array
static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot); static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot);
// Convenience
static const TypeAryPtr *make(ciObject* o);
// Return a 'ptr' version of this type // Return a 'ptr' version of this type
virtual const Type *cast_to_ptr_type(PTR ptr) const; virtual const Type *cast_to_ptr_type(PTR ptr) const;

View File

@ -46,7 +46,8 @@ bool Flag::is_unlocker() const {
bool Flag::is_unlocked() const { bool Flag::is_unlocked() const {
if (strcmp(kind, "{diagnostic}") == 0) { if (strcmp(kind, "{diagnostic}") == 0) {
return UnlockDiagnosticVMOptions; return UnlockDiagnosticVMOptions;
} else if (strcmp(kind, "{experimental}") == 0) { } else if (strcmp(kind, "{experimental}") == 0 ||
strcmp(kind, "{C2 experimental}") == 0) {
return UnlockExperimentalVMOptions; return UnlockExperimentalVMOptions;
} else { } else {
return true; return true;
@ -169,6 +170,7 @@ void Flag::print_as_flag(outputStream* st) {
#define C2_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 product}", DEFAULT }, #define C2_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 product}", DEFAULT },
#define C2_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C2 pd product}", DEFAULT }, #define C2_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C2 pd product}", DEFAULT },
#define C2_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 diagnostic}", DEFAULT }, #define C2_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 diagnostic}", DEFAULT },
#define C2_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 experimental}", DEFAULT },
#ifdef PRODUCT #ifdef PRODUCT
#define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */
#define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */
@ -190,7 +192,7 @@ static Flag flagTable[] = {
C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, C1_PD_DEVELOP_FLAG_STRUCT, C1_PRODUCT_FLAG_STRUCT, C1_PD_PRODUCT_FLAG_STRUCT, C1_NOTPRODUCT_FLAG_STRUCT) C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, C1_PD_DEVELOP_FLAG_STRUCT, C1_PRODUCT_FLAG_STRUCT, C1_PD_PRODUCT_FLAG_STRUCT, C1_NOTPRODUCT_FLAG_STRUCT)
#endif #endif
#ifdef COMPILER2 #ifdef COMPILER2
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) 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)
#endif #endif
{0, NULL, NULL} {0, NULL, NULL}
}; };

View File

@ -64,6 +64,7 @@
#define C2_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #define C2_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
#define C2_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), #define C2_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
#define C2_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #define C2_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
#define C2_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
#ifdef PRODUCT #ifdef PRODUCT
#define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ #define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */
#define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc) /* flag is constant */ #define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc) /* flag is constant */
@ -84,7 +85,7 @@ typedef enum {
C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER) C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER)
#endif #endif
#ifdef COMPILER2 #ifdef COMPILER2
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) 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)
#endif #endif
NUM_CommandLineFlag NUM_CommandLineFlag
} CommandLineFlag; } CommandLineFlag;
@ -130,6 +131,7 @@ typedef enum {
#define C2_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C2_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
#define C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
#define C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
#define C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
#ifdef PRODUCT #ifdef PRODUCT
#define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ #define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */
#define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) /* flag is constant */ #define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) /* flag is constant */
@ -181,6 +183,7 @@ typedef enum {
C2_PRODUCT_FLAG_MEMBER_WITH_TYPE, C2_PRODUCT_FLAG_MEMBER_WITH_TYPE,
C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE, C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE, C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE) C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE)
#endif #endif
NUM_CommandLineFlagWithType NUM_CommandLineFlagWithType

View File

@ -278,6 +278,17 @@ template<class E> class GrowableArray : public GenericGrowableArray {
_len--; _len--;
} }
// inserts the given element before the element at index i
void insert_before(const int idx, const E& elem) {
check_nesting();
if (_len == _max) grow(_len);
for (int j = _len - 1; j >= idx; j--) {
_data[j + 1] = _data[j];
}
_len++;
_data[idx] = elem;
}
void appendAll(const GrowableArray<E>* l) { void appendAll(const GrowableArray<E>* l) {
for (int i = 0; i < l->_len; i++) { for (int i = 0; i < l->_len; i++) {
raw_at_put_grow(_len, l->_data[i], 0); raw_at_put_grow(_len, l->_data[i], 0);