Merge
This commit is contained in:
commit
b5e3a7a597
@ -46,6 +46,9 @@ ciInstanceKlass* ciEnv::_Throwable;
|
||||
ciInstanceKlass* ciEnv::_Thread;
|
||||
ciInstanceKlass* ciEnv::_OutOfMemoryError;
|
||||
ciInstanceKlass* ciEnv::_String;
|
||||
ciInstanceKlass* ciEnv::_StringBuffer;
|
||||
ciInstanceKlass* ciEnv::_StringBuilder;
|
||||
ciInstanceKlass* ciEnv::_Integer;
|
||||
|
||||
ciSymbol* ciEnv::_unloaded_cisymbol = NULL;
|
||||
ciInstanceKlass* ciEnv::_unloaded_ciinstance_klass = NULL;
|
||||
@ -110,6 +113,8 @@ ciEnv::ciEnv(CompileTask* task, int system_dictionary_modification_counter) {
|
||||
_ArrayIndexOutOfBoundsException_instance = NULL;
|
||||
_ArrayStoreException_instance = NULL;
|
||||
_ClassCastException_instance = NULL;
|
||||
_the_null_string = NULL;
|
||||
_the_min_jint_string = NULL;
|
||||
}
|
||||
|
||||
ciEnv::ciEnv(Arena* arena) {
|
||||
@ -163,6 +168,8 @@ ciEnv::ciEnv(Arena* arena) {
|
||||
_ArrayIndexOutOfBoundsException_instance = NULL;
|
||||
_ArrayStoreException_instance = NULL;
|
||||
_ClassCastException_instance = NULL;
|
||||
_the_null_string = NULL;
|
||||
_the_min_jint_string = NULL;
|
||||
}
|
||||
|
||||
ciEnv::~ciEnv() {
|
||||
@ -248,6 +255,22 @@ ciInstance* ciEnv::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
|
||||
ciMethod* ciEnv::get_method_from_handle(jobject method) {
|
||||
|
@ -82,6 +82,9 @@ private:
|
||||
static ciInstanceKlass* _Thread;
|
||||
static ciInstanceKlass* _OutOfMemoryError;
|
||||
static ciInstanceKlass* _String;
|
||||
static ciInstanceKlass* _StringBuffer;
|
||||
static ciInstanceKlass* _StringBuilder;
|
||||
static ciInstanceKlass* _Integer;
|
||||
|
||||
static ciSymbol* _unloaded_cisymbol;
|
||||
static ciInstanceKlass* _unloaded_ciinstance_klass;
|
||||
@ -97,6 +100,9 @@ private:
|
||||
ciInstance* _ArrayStoreException_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).
|
||||
// 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,
|
||||
@ -310,6 +316,15 @@ public:
|
||||
ciInstanceKlass* String_klass() {
|
||||
return _String;
|
||||
}
|
||||
ciInstanceKlass* StringBuilder_klass() {
|
||||
return _StringBuilder;
|
||||
}
|
||||
ciInstanceKlass* StringBuffer_klass() {
|
||||
return _StringBuffer;
|
||||
}
|
||||
ciInstanceKlass* Integer_klass() {
|
||||
return _Integer;
|
||||
}
|
||||
ciInstance* NullPointerException_instance() {
|
||||
assert(_NullPointerException_instance != NULL, "initialization problem");
|
||||
return _NullPointerException_instance;
|
||||
@ -324,6 +339,9 @@ public:
|
||||
ciInstance* ArrayStoreException_instance();
|
||||
ciInstance* ClassCastException_instance();
|
||||
|
||||
ciInstance* the_null_string();
|
||||
ciInstance* the_min_jint_string();
|
||||
|
||||
static ciSymbol* unloaded_cisymbol() {
|
||||
return _unloaded_cisymbol;
|
||||
}
|
||||
|
@ -340,6 +340,20 @@ ciField* ciInstanceKlass::get_field_by_offset(int field_offset, bool is_static)
|
||||
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.
|
||||
|
||||
|
@ -148,6 +148,7 @@ public:
|
||||
|
||||
ciInstanceKlass* get_canonical_holder(int offset);
|
||||
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();
|
||||
|
||||
|
@ -168,6 +168,15 @@ void ciObjectFactory::init_shared_objects() {
|
||||
ciEnv::_String =
|
||||
get(SystemDictionary::string_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(); ) {
|
||||
len = _ci_objects->length();
|
||||
|
@ -150,6 +150,7 @@ class SymbolPropertyTable;
|
||||
template(vector_klass, java_util_Vector, Pre) \
|
||||
template(hashtable_klass, java_util_Hashtable, Pre) \
|
||||
template(stringBuffer_klass, java_lang_StringBuffer, Pre) \
|
||||
template(StringBuilder_klass, java_lang_StringBuilder, Pre) \
|
||||
\
|
||||
/* It's NULL in non-1.4 JDKs. */ \
|
||||
template(stackTraceElement_klass, java_lang_StackTraceElement, Opt) \
|
||||
|
@ -303,6 +303,11 @@ inline bool match_F_R(jshort flags) {
|
||||
const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED;
|
||||
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) {
|
||||
const int req = JVM_ACC_NATIVE;
|
||||
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* fname = "";
|
||||
switch (flags_for(id)) {
|
||||
case F_Y: fname = "synchronized "; break;
|
||||
case F_RN: fname = "native "; break;
|
||||
case F_SN: fname = "native static "; break;
|
||||
case F_S: fname = "static "; break;
|
||||
|
@ -84,6 +84,7 @@
|
||||
template(java_lang_reflect_Field, "java/lang/reflect/Field") \
|
||||
template(java_lang_reflect_Array, "java/lang/reflect/Array") \
|
||||
template(java_lang_StringBuffer, "java/lang/StringBuffer") \
|
||||
template(java_lang_StringBuilder, "java/lang/StringBuilder") \
|
||||
template(java_lang_CharSequence, "java/lang/CharSequence") \
|
||||
template(java_security_AccessControlContext, "java/security/AccessControlContext") \
|
||||
template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \
|
||||
@ -334,6 +335,7 @@
|
||||
template(ptypes_name, "ptypes") \
|
||||
template(form_name, "form") \
|
||||
template(erasedType_name, "erasedType") \
|
||||
template(append_name, "append") \
|
||||
\
|
||||
/* non-intrinsic name/signature pairs: */ \
|
||||
template(register_method_name, "register") \
|
||||
@ -415,6 +417,13 @@
|
||||
template(string_signature, "Ljava/lang/String;") \
|
||||
template(reference_signature, "Ljava/lang/ref/Reference;") \
|
||||
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 */ \
|
||||
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 */ \
|
||||
\
|
||||
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) \
|
||||
/* (symbol object_initializer_name defined above) */ \
|
||||
\
|
||||
\
|
||||
do_intrinsic(_StringBuilder_void, java_lang_StringBuilder, object_initializer_name, void_method_signature, F_R) \
|
||||
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) \
|
||||
/* (symbols invoke_name and invoke_signature defined above) */ \
|
||||
\
|
||||
@ -945,11 +978,12 @@ class vmIntrinsics: AllStatic {
|
||||
enum Flags {
|
||||
// AccessFlags syndromes relevant to intrinsics.
|
||||
F_none = 0,
|
||||
F_R, // !static !synchronized (R="regular")
|
||||
F_S, // static !synchronized
|
||||
F_RN, // !static native !synchronized
|
||||
F_SN, // static native !synchronized
|
||||
F_RNY // !static native synchronized
|
||||
F_R, // !static ?native !synchronized (R="regular")
|
||||
F_S, // static ?native !synchronized
|
||||
F_Y, // !static ?native synchronized
|
||||
F_RN, // !static native !synchronized
|
||||
F_SN, // static native !synchronized
|
||||
F_RNY // !static native synchronized
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -149,6 +149,7 @@ c2compiler.cpp runtime.hpp
|
||||
c2compiler.hpp abstractCompiler.hpp
|
||||
|
||||
callGenerator.cpp addnode.hpp
|
||||
callGenerator.cpp bcEscapeAnalyzer.hpp
|
||||
callGenerator.cpp callGenerator.hpp
|
||||
callGenerator.cpp callnode.hpp
|
||||
callGenerator.cpp cfgnode.hpp
|
||||
@ -321,6 +322,7 @@ compile.cpp phaseX.hpp
|
||||
compile.cpp rootnode.hpp
|
||||
compile.cpp runtime.hpp
|
||||
compile.cpp signature.hpp
|
||||
compile.cpp stringopts.hpp
|
||||
compile.cpp stubRoutines.hpp
|
||||
compile.cpp systemDictionary.hpp
|
||||
compile.cpp timer.hpp
|
||||
@ -476,12 +478,16 @@ graphKit.cpp rootnode.hpp
|
||||
graphKit.cpp runtime.hpp
|
||||
graphKit.cpp sharedRuntime.hpp
|
||||
|
||||
graphKit.hpp addnode.hpp
|
||||
graphKit.hpp callnode.hpp
|
||||
graphKit.hpp cfgnode.hpp
|
||||
graphKit.hpp ciEnv.hpp
|
||||
graphKit.hpp divnode.hpp
|
||||
graphKit.hpp compile.hpp
|
||||
graphKit.hpp deoptimization.hpp
|
||||
graphKit.hpp phaseX.hpp
|
||||
graphKit.hpp mulnode.hpp
|
||||
graphKit.hpp subnode.hpp
|
||||
graphKit.hpp type.hpp
|
||||
|
||||
idealKit.cpp addnode.hpp
|
||||
@ -490,7 +496,10 @@ idealKit.cpp cfgnode.hpp
|
||||
idealKit.cpp idealKit.hpp
|
||||
idealKit.cpp runtime.hpp
|
||||
|
||||
idealKit.hpp addnode.hpp
|
||||
idealKit.hpp cfgnode.hpp
|
||||
idealKit.hpp connode.hpp
|
||||
idealKit.hpp divnode.hpp
|
||||
idealKit.hpp mulnode.hpp
|
||||
idealKit.hpp phaseX.hpp
|
||||
idealKit.hpp subnode.hpp
|
||||
@ -641,6 +650,7 @@ macro.cpp addnode.hpp
|
||||
macro.cpp callnode.hpp
|
||||
macro.cpp cfgnode.hpp
|
||||
macro.cpp compile.hpp
|
||||
macro.cpp compileLog.hpp
|
||||
macro.cpp connode.hpp
|
||||
macro.cpp locknode.hpp
|
||||
macro.cpp loopnode.hpp
|
||||
@ -993,6 +1003,21 @@ split_if.cpp callnode.hpp
|
||||
split_if.cpp connode.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
|
||||
|
||||
stubRoutines.cpp runtime.hpp
|
||||
|
@ -570,6 +570,7 @@ ciEnv.hpp debugInfoRec.hpp
|
||||
ciEnv.hpp dependencies.hpp
|
||||
ciEnv.hpp exceptionHandlerTable.hpp
|
||||
ciEnv.hpp oopMap.hpp
|
||||
ciEnv.hpp systemDictionary.hpp
|
||||
ciEnv.hpp thread.hpp
|
||||
|
||||
ciExceptionHandler.cpp ciExceptionHandler.hpp
|
||||
|
@ -67,6 +67,8 @@ typeArrayOop Universe::_the_empty_int_array = NULL;
|
||||
objArrayOop Universe::_the_empty_system_obj_array = NULL;
|
||||
objArrayOop Universe::_the_empty_class_klass_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::_loader_addClass_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_class_klass_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);
|
||||
_loader_addClass_cache->oops_do(f);
|
||||
_reflect_invoke_cache->oops_do(f);
|
||||
@ -289,6 +293,9 @@ void Universe::genesis(TRAPS) {
|
||||
|
||||
klassOop ok = SystemDictionary::object_klass();
|
||||
|
||||
_the_null_string = StringTable::intern("null", CHECK);
|
||||
_the_min_jint_string = StringTable::intern("-2147483648", CHECK);
|
||||
|
||||
if (UseSharedSpaces) {
|
||||
// Verify shared interfaces array.
|
||||
assert(_the_array_interfaces_array->obj_at(0) ==
|
||||
|
@ -169,6 +169,8 @@ class Universe: AllStatic {
|
||||
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_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* _loader_addClass_cache; // method for registering loaded classes in class loader vector
|
||||
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_class_klass_array () { return _the_empty_class_klass_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 loader_addClass_method() { return _loader_addClass_cache->get_methodOop(); }
|
||||
static ActiveMethodOopsCache* reflect_invoke_cache() { return _reflect_invoke_cache; }
|
||||
|
@ -25,4 +25,4 @@
|
||||
# include "incls/_precompiled.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)
|
||||
|
@ -26,7 +26,7 @@
|
||||
// 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, \
|
||||
"If +ZapDeadCompiledLocals, " \
|
||||
@ -394,6 +394,12 @@
|
||||
product(bool, UseOptoBiasInlining, true, \
|
||||
"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, \
|
||||
"Recursion limit in PhaseMacroExpand::value_from_mem_phi") \
|
||||
\
|
||||
@ -413,4 +419,4 @@
|
||||
product(bool, BlockLayoutRotateLoops, true, \
|
||||
"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)
|
||||
|
@ -98,12 +98,21 @@ JVMState* ParseGenerator::generate(JVMState* jvms) {
|
||||
//---------------------------DirectCallGenerator------------------------------
|
||||
// Internal class which handles all out-of-line calls w/o receiver type checks.
|
||||
class DirectCallGenerator : public CallGenerator {
|
||||
public:
|
||||
DirectCallGenerator(ciMethod* method)
|
||||
: CallGenerator(method)
|
||||
private:
|
||||
CallStaticJavaNode* _call_node;
|
||||
// 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);
|
||||
|
||||
CallStaticJavaNode* call_node() const { return _call_node; }
|
||||
};
|
||||
|
||||
JVMState* DirectCallGenerator::generate(JVMState* jvms) {
|
||||
@ -129,9 +138,10 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) {
|
||||
call->set_optimized_virtual(true);
|
||||
}
|
||||
kit.set_arguments_for_java_call(call);
|
||||
kit.set_edges_for_java_call(call);
|
||||
Node* ret = kit.set_results_for_java_call(call);
|
||||
kit.set_edges_for_java_call(call, false, _separate_io_proj);
|
||||
Node* ret = kit.set_results_for_java_call(call, _separate_io_proj);
|
||||
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();
|
||||
}
|
||||
|
||||
@ -238,9 +248,9 @@ CallGenerator* CallGenerator::for_osr(ciMethod* m, int osr_bci) {
|
||||
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");
|
||||
return new DirectCallGenerator(m);
|
||||
return new DirectCallGenerator(m, separate_io_proj);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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--------------------------------
|
||||
// Internal class which handles initial deferral of inlining decisions.
|
||||
@ -315,70 +427,7 @@ JVMState* WarmCallGenerator::generate(JVMState* jvms) {
|
||||
}
|
||||
|
||||
void WarmCallInfo::make_hot() {
|
||||
Compile* C = Compile::current();
|
||||
// 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);
|
||||
}
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
void WarmCallInfo::make_cold() {
|
||||
|
@ -57,6 +57,13 @@ class CallGenerator : public ResourceObj {
|
||||
// is_trap: Does not return to the caller. (E.g., uncommon trap.)
|
||||
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.
|
||||
// (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);
|
||||
|
||||
// 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
|
||||
|
||||
// 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.
|
||||
static CallGenerator* for_warm_call(WarmCallInfo* ci,
|
||||
CallGenerator* if_cold,
|
||||
|
@ -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::cmp( const Node &n ) const {
|
||||
|
@ -470,6 +470,23 @@ public:
|
||||
#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---------------------------------------
|
||||
// Call nodes now subsume the function of debug nodes at callsites, so they
|
||||
// contain the functionality of a full scope chain of debug nodes.
|
||||
@ -521,6 +538,11 @@ public:
|
||||
// or returns NULL if there is no one.
|
||||
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;
|
||||
|
||||
#ifndef PRODUCT
|
||||
@ -529,6 +551,7 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
//------------------------------CallJavaNode-----------------------------------
|
||||
// Make a static or dynamic subroutine call node using Java calling
|
||||
// convention. (The "Java" calling convention is the compiler's calling
|
||||
|
@ -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.
|
||||
// Use breadth-first pass that records state in a Unique_Node_List,
|
||||
// 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());
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Remove clutter produced by parsing.
|
||||
@ -820,6 +868,7 @@ void Compile::Init(int aliaslevel) {
|
||||
_fixed_slots = 0;
|
||||
set_has_split_ifs(false);
|
||||
set_has_loops(has_method() && method()->has_loops()); // first approximation
|
||||
set_has_stringbuilder(false);
|
||||
_deopt_happens = true; // start out assuming the worst
|
||||
_trap_can_recompile = false; // no traps emitted yet
|
||||
_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;
|
||||
}
|
||||
|
||||
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:
|
||||
if (n->as_Phi()->bottom_type()->isa_narrowoop()) {
|
||||
// The EncodeP optimization may create Phi with the same edges
|
||||
|
@ -149,6 +149,7 @@ class Compile : public Phase {
|
||||
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_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
|
||||
bool _trap_can_recompile; // Have we emitted a recompiling trap?
|
||||
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
|
||||
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
|
||||
PhaseCFG* _cfg; // Results of CFG finding
|
||||
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; }
|
||||
bool has_unsafe_access() const { return _has_unsafe_access; }
|
||||
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; }
|
||||
uint trap_count(uint r) const { assert(r < trapHistLength, "oob"); return _trap_hist[r]; }
|
||||
bool trap_can_recompile() const { return _trap_can_recompile; }
|
||||
@ -475,6 +481,7 @@ class Compile : public Phase {
|
||||
// Decide how to build a call.
|
||||
// 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);
|
||||
bool should_delay_inlining(ciMethod* call_method, JVMState* jvms);
|
||||
|
||||
// Report if there were too many traps at a current method and bci.
|
||||
// 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_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 remove_useless_nodes (Unique_Node_List &useful);
|
||||
|
||||
@ -502,6 +514,9 @@ class Compile : public Phase {
|
||||
void set_warm_calls(WarmCallInfo* l) { _warm_calls = l; }
|
||||
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
|
||||
PhaseCFG* cfg() { return _cfg; }
|
||||
bool select_24_bit_instr() const { return _select_24_bit_instr; }
|
||||
|
@ -128,6 +128,12 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
||||
|
||||
if (allow_inline) {
|
||||
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) {
|
||||
// Fall through.
|
||||
} else if (require_inline || !InlineWarmCalls) {
|
||||
@ -225,10 +231,63 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
||||
} else {
|
||||
// Class Hierarchy Analysis or Type Profile reveals a unique target,
|
||||
// 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
|
||||
bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* klass) {
|
||||
|
@ -1351,8 +1351,8 @@ void GraphKit::set_all_memory(Node* newmem) {
|
||||
}
|
||||
|
||||
//------------------------------set_all_memory_call----------------------------
|
||||
void GraphKit::set_all_memory_call(Node* call) {
|
||||
Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) );
|
||||
void GraphKit::set_all_memory_call(Node* call, bool separate_io_proj) {
|
||||
Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory, separate_io_proj) );
|
||||
set_all_memory(newmem);
|
||||
}
|
||||
|
||||
@ -1573,7 +1573,7 @@ void GraphKit::set_arguments_for_java_call(CallJavaNode* call) {
|
||||
//---------------------------set_edges_for_java_call---------------------------
|
||||
// Connect a newly created call into the current JVMS.
|
||||
// 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:
|
||||
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.
|
||||
|
||||
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_all_memory_call(xcall);
|
||||
set_i_o( _gvn.transform(new (C, 1) ProjNode(call, TypeFunc::I_O , separate_io_proj)));
|
||||
set_all_memory_call(xcall, separate_io_proj);
|
||||
|
||||
//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?
|
||||
|
||||
// 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,
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -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------------------------------
|
||||
// for statistics: increment a VM counter by 1
|
||||
|
||||
@ -3459,4 +3519,3 @@ void GraphKit::g1_write_barrier_post(Node* oop_store,
|
||||
sync_kit(ideal);
|
||||
}
|
||||
#undef __
|
||||
|
||||
|
@ -279,6 +279,34 @@ class GraphKit : public Phase {
|
||||
}
|
||||
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.
|
||||
// (See macros ConvI2X, etc., in type.hpp for ConvI2X, etc.)
|
||||
Node* ConvI2L(Node* offset);
|
||||
@ -400,7 +428,7 @@ class GraphKit : public Phase {
|
||||
void set_all_memory(Node* newmem);
|
||||
|
||||
// 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.
|
||||
// (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.
|
||||
// (The next step is usually to call set_results_for_java_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.
|
||||
// Call add_exception on any throw arising from the call.
|
||||
// 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.
|
||||
void set_predefined_output_for_runtime_call(Node* call) {
|
||||
@ -559,6 +587,11 @@ class GraphKit : public Phase {
|
||||
const TypePtr* hook_mem);
|
||||
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
|
||||
void increment_counter(address counter_addr); // increment a debug counter
|
||||
void increment_counter(Node* counter_addr); // increment a debug counter
|
||||
|
@ -912,15 +912,29 @@ bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) {
|
||||
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);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (PrintEliminateAllocations) {
|
||||
if (alloc->is_AllocateArray())
|
||||
tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx);
|
||||
else
|
||||
tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx);
|
||||
}
|
||||
if (PrintEliminateAllocations) {
|
||||
if (alloc->is_AllocateArray())
|
||||
tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx);
|
||||
else
|
||||
tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@ -1639,6 +1653,18 @@ bool PhaseMacroExpand::eliminate_locking_node(AbstractLockNode *alock) {
|
||||
} // if (!oldbox->is_eliminated())
|
||||
} // 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
|
||||
if (PrintEliminateLocks) {
|
||||
if (alock->is_Lock()) {
|
||||
|
@ -1503,6 +1503,8 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
|
||||
}
|
||||
}
|
||||
} else if (tp->base() == Type::InstPtr) {
|
||||
const TypeInstPtr* tinst = tp->is_instptr();
|
||||
ciKlass* klass = tinst->klass();
|
||||
assert( off != Type::OffsetBot ||
|
||||
// arrays can be cast to Objects
|
||||
tp->is_oopptr()->klass()->is_java_lang_Object() ||
|
||||
@ -1510,6 +1512,25 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
|
||||
phase->C->has_unsafe_access(),
|
||||
"Field accesses must 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) {
|
||||
assert( off != Type::OffsetBot ||
|
||||
// arrays can be cast to Objects
|
||||
|
@ -661,18 +661,25 @@ public:
|
||||
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)
|
||||
assert((_class_id & ClassMask_Call) == Class_Call, "invalid node class");
|
||||
return (CallNode*)this;
|
||||
}
|
||||
|
||||
#define DEFINE_CLASS_QUERY(type) \
|
||||
bool is_##type() const { \
|
||||
#define DEFINE_CLASS_QUERY(type) \
|
||||
bool is_##type() const { \
|
||||
return ((_class_id & ClassMask_##type) == Class_##type); \
|
||||
} \
|
||||
type##Node *as_##type() const { \
|
||||
assert(is_##type(), "invalid node class"); \
|
||||
return (type##Node*)this; \
|
||||
} \
|
||||
type##Node *as_##type() const { \
|
||||
assert(is_##type(), "invalid node class"); \
|
||||
return (type##Node*)this; \
|
||||
} \
|
||||
type##Node* isa_##type() const { \
|
||||
return (is_##type()) ? as_##type() : NULL; \
|
||||
}
|
||||
|
||||
DEFINE_CLASS_QUERY(AbstractLock)
|
||||
@ -1249,6 +1256,24 @@ Node* Node::last_out(DUIterator_Last& i) const {
|
||||
#undef I_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.
|
||||
@ -1290,6 +1315,12 @@ class Node_List : public Node_Array {
|
||||
public:
|
||||
Node_List() : Node_Array(Thread::current()->resource_area()), _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 remove( uint i ) { Node_Array::remove(i); _cnt--; }
|
||||
void push( Node *b ) { map(_cnt++,b); }
|
||||
|
@ -221,6 +221,14 @@ void Parse::do_new() {
|
||||
|
||||
// Push resultant oop onto stack
|
||||
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
|
||||
|
@ -44,6 +44,7 @@ public:
|
||||
BlockLayout, // Linear ordering of blocks
|
||||
Register_Allocation, // Register allocation, duh
|
||||
LIVE, // Dragon-book LIVE range problem
|
||||
StringOpts, // StringBuilder related optimizations
|
||||
Interference_Graph, // Building the IFG
|
||||
Coalesce, // Coalescing copies
|
||||
Ideal_Loop, // Find idealized trip-counted loops
|
||||
|
@ -345,7 +345,11 @@ public:
|
||||
Node *hash_find(const Node *n) { return _table.hash_find(n); }
|
||||
|
||||
// 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
|
||||
|
||||
|
1395
hotspot/src/share/vm/opto/stringopts.cpp
Normal file
1395
hotspot/src/share/vm/opto/stringopts.cpp
Normal file
File diff suppressed because it is too large
Load Diff
83
hotspot/src/share/vm/opto/stringopts.hpp
Normal file
83
hotspot/src/share/vm/opto/stringopts.hpp
Normal 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);
|
||||
};
|
@ -847,9 +847,6 @@ public:
|
||||
// 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);
|
||||
|
||||
// Convenience
|
||||
static const TypeAryPtr *make(ciObject* o);
|
||||
|
||||
// Return a 'ptr' version of this type
|
||||
virtual const Type *cast_to_ptr_type(PTR ptr) const;
|
||||
|
||||
|
@ -46,7 +46,8 @@ bool Flag::is_unlocker() const {
|
||||
bool Flag::is_unlocked() const {
|
||||
if (strcmp(kind, "{diagnostic}") == 0) {
|
||||
return UnlockDiagnosticVMOptions;
|
||||
} else if (strcmp(kind, "{experimental}") == 0) {
|
||||
} else if (strcmp(kind, "{experimental}") == 0 ||
|
||||
strcmp(kind, "{C2 experimental}") == 0) {
|
||||
return UnlockExperimentalVMOptions;
|
||||
} else {
|
||||
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_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_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 experimental}", DEFAULT },
|
||||
#ifdef PRODUCT
|
||||
#define C2_DEVELOP_FLAG_STRUCT(type, name, value, 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)
|
||||
#endif
|
||||
#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
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
@ -64,6 +64,7 @@
|
||||
#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_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
|
||||
#define C2_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
|
||||
#ifdef PRODUCT
|
||||
#define C2_DEVELOP_FLAG_MEMBER(type, name, value, 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)
|
||||
#endif
|
||||
#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
|
||||
NUM_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_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_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
|
||||
#ifdef PRODUCT
|
||||
#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 */
|
||||
@ -181,6 +183,7 @@ typedef enum {
|
||||
C2_PRODUCT_FLAG_MEMBER_WITH_TYPE,
|
||||
C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
|
||||
C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
|
||||
C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
|
||||
C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE)
|
||||
#endif
|
||||
NUM_CommandLineFlagWithType
|
||||
|
@ -278,6 +278,17 @@ template<class E> class GrowableArray : public GenericGrowableArray {
|
||||
_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) {
|
||||
for (int i = 0; i < l->_len; i++) {
|
||||
raw_at_put_grow(_len, l->_data[i], 0);
|
||||
|
Loading…
Reference in New Issue
Block a user