6934604: enable parts of EliminateAutoBox by default
Summary: Resurrected autobox elimination code and enabled part of it by default.
Reviewed-by: roland, twisti
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Wed May 08 15:08:01 2013 -0700
@@ -211,13 +211,42 @@
// ------------------------------------------------------------------
// ciInstanceKlass::uses_default_loader
-bool ciInstanceKlass::uses_default_loader() {
+bool ciInstanceKlass::uses_default_loader() const {
// Note: We do not need to resolve the handle or enter the VM
// in order to test null-ness.
return _loader == NULL;
}
// ------------------------------------------------------------------
+
+/**
+ * Return basic type of boxed value for box klass or T_OBJECT if not.
+ */
+BasicType ciInstanceKlass::box_klass_type() const {
+ if (uses_default_loader() && is_loaded()) {
+ return SystemDictionary::box_klass_type(get_Klass());
+ } else {
+ return T_OBJECT;
+ }
+}
+
+/**
+ * Is this boxing klass?
+ */
+bool ciInstanceKlass::is_box_klass() const {
+ return is_java_primitive(box_klass_type());
+}
+
+/**
+ * Is this boxed value offset?
+ */
+bool ciInstanceKlass::is_boxed_value_offset(int offset) const {
+ BasicType bt = box_klass_type();
+ return is_java_primitive(bt) &&
+ (offset == java_lang_boxing_object::value_offset_in_bytes(bt));
+}
+
+// ------------------------------------------------------------------
// ciInstanceKlass::is_in_package
//
// Is this klass in the given package?
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Wed May 08 15:08:01 2013 -0700
@@ -217,10 +217,14 @@
ciInstanceKlass* implementor();
// Is the defining class loader of this class the default loader?
- bool uses_default_loader();
+ bool uses_default_loader() const;
bool is_java_lang_Object() const;
+ BasicType box_klass_type() const;
+ bool is_box_klass() const;
+ bool is_boxed_value_offset(int offset) const;
+
// Is this klass in the given package?
bool is_in_package(const char* packagename) {
return is_in_package(packagename, (int) strlen(packagename));
--- a/hotspot/src/share/vm/ci/ciMethod.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp Wed May 08 15:08:01 2013 -0700
@@ -1179,6 +1179,44 @@
bool ciMethod::is_accessor () const { FETCH_FLAG_FROM_VM(is_accessor); }
bool ciMethod::is_initializer () const { FETCH_FLAG_FROM_VM(is_initializer); }
+bool ciMethod::is_boxing_method() const {
+ if (holder()->is_box_klass()) {
+ switch (intrinsic_id()) {
+ case vmIntrinsics::_Boolean_valueOf:
+ case vmIntrinsics::_Byte_valueOf:
+ case vmIntrinsics::_Character_valueOf:
+ case vmIntrinsics::_Short_valueOf:
+ case vmIntrinsics::_Integer_valueOf:
+ case vmIntrinsics::_Long_valueOf:
+ case vmIntrinsics::_Float_valueOf:
+ case vmIntrinsics::_Double_valueOf:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+bool ciMethod::is_unboxing_method() const {
+ if (holder()->is_box_klass()) {
+ switch (intrinsic_id()) {
+ case vmIntrinsics::_booleanValue:
+ case vmIntrinsics::_byteValue:
+ case vmIntrinsics::_charValue:
+ case vmIntrinsics::_shortValue:
+ case vmIntrinsics::_intValue:
+ case vmIntrinsics::_longValue:
+ case vmIntrinsics::_floatValue:
+ case vmIntrinsics::_doubleValue:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
BCEscapeAnalyzer *ciMethod::get_bcea() {
#ifdef COMPILER2
if (_bcea == NULL) {
--- a/hotspot/src/share/vm/ci/ciMethod.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp Wed May 08 15:08:01 2013 -0700
@@ -298,6 +298,8 @@
bool is_initializer () const;
bool can_be_statically_bound() const { return _can_be_statically_bound; }
void dump_replay_data(outputStream* st);
+ bool is_boxing_method() const;
+ bool is_unboxing_method() const;
// Print the bytecodes of this method.
void print_codes_on(outputStream* st);
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed May 08 15:08:01 2013 -0700
@@ -68,7 +68,7 @@
template(java_lang_Float, "java/lang/Float") \
template(java_lang_Double, "java/lang/Double") \
template(java_lang_Byte, "java/lang/Byte") \
- template(java_lang_Byte_Cache, "java/lang/Byte$ByteCache") \
+ template(java_lang_Byte_ByteCache, "java/lang/Byte$ByteCache") \
template(java_lang_Short, "java/lang/Short") \
template(java_lang_Short_ShortCache, "java/lang/Short$ShortCache") \
template(java_lang_Integer, "java/lang/Integer") \
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Wed May 08 15:08:01 2013 -0700
@@ -1854,8 +1854,10 @@
tty->print("%7d ", (int) tty->time_stamp().milliseconds()); // print timestamp
tty->print("%4d ", compile_id); // print compilation number
tty->print("%s ", (is_osr ? "%" : " "));
- int code_size = (task->code() == NULL) ? 0 : task->code()->total_size();
- tty->print_cr("size: %d time: %d inlined: %d bytes", code_size, (int)time.milliseconds(), task->num_inlined_bytecodes());
+ if (task->code() != NULL) {
+ tty->print("size: %d(%d) ", task->code()->total_size(), task->code()->insts_size());
+ }
+ tty->print_cr("time: %d inlined: %d bytes", (int)time.milliseconds(), task->num_inlined_bytecodes());
}
if (PrintCodeCacheOnCompilation)
--- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp Wed May 08 15:08:01 2013 -0700
@@ -97,6 +97,11 @@
);
}
+static bool is_unboxing_method(ciMethod* callee_method, Compile* C) {
+ // Force inlining unboxing accessor.
+ return C->eliminate_boxing() && callee_method->is_unboxing_method();
+}
+
// positive filter: should callee be inlined?
bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method,
int caller_bci, ciCallProfile& profile,
@@ -144,6 +149,7 @@
// bump the max size if the call is frequent
if ((freq >= InlineFrequencyRatio) ||
(call_site_count >= InlineFrequencyCount) ||
+ is_unboxing_method(callee_method, C) ||
is_init_with_ea(callee_method, caller_method, C)) {
max_inline_size = C->freq_inline_size();
@@ -237,8 +243,25 @@
return false;
}
+ if (callee_method->should_not_inline()) {
+ set_msg("disallowed by CompilerOracle");
+ return true;
+ }
+
+#ifndef PRODUCT
+ if (ciReplay::should_not_inline(callee_method)) {
+ set_msg("disallowed by ciReplay");
+ return true;
+ }
+#endif
+
// Now perform checks which are heuristic
+ if (is_unboxing_method(callee_method, C)) {
+ // Inline unboxing methods.
+ return false;
+ }
+
if (!callee_method->force_inline()) {
if (callee_method->has_compiled_code() &&
callee_method->instructions_size() > InlineSmallCode) {
@@ -260,18 +283,6 @@
}
}
- if (callee_method->should_not_inline()) {
- set_msg("disallowed by CompilerOracle");
- return true;
- }
-
-#ifndef PRODUCT
- if (ciReplay::should_not_inline(callee_method)) {
- set_msg("disallowed by ciReplay");
- return true;
- }
-#endif
-
if (UseStringCache) {
// Do not inline StringCache::profile() method used only at the beginning.
if (callee_method->name() == ciSymbol::profile_name() &&
@@ -296,9 +307,8 @@
}
if (is_init_with_ea(callee_method, caller_method, C)) {
-
// Escape Analysis: inline all executed constructors
-
+ return false;
} else if (!callee_method->was_executed_more_than(MIN2(MinInliningThreshold,
CompileThreshold >> 1))) {
set_msg("executed < MinInliningThreshold times");
--- a/hotspot/src/share/vm/opto/c2_globals.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp Wed May 08 15:08:01 2013 -0700
@@ -442,12 +442,15 @@
notproduct(bool, PrintEliminateLocks, false, \
"Print out when locks are eliminated") \
\
- diagnostic(bool, EliminateAutoBox, false, \
- "Private flag to control optimizations for autobox elimination") \
+ product(bool, EliminateAutoBox, true, \
+ "Control optimizations for autobox elimination") \
\
product(intx, AutoBoxCacheMax, 128, \
"Sets max value cached by the java.lang.Integer autobox cache") \
\
+ experimental(bool, AggressiveUnboxing, false, \
+ "Control optimizations for aggressive boxing elimination") \
+ \
product(bool, DoEscapeAnalysis, true, \
"Perform escape analysis") \
\
--- a/hotspot/src/share/vm/opto/c2compiler.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/c2compiler.cpp Wed May 08 15:08:01 2013 -0700
@@ -125,9 +125,10 @@
bool subsume_loads = SubsumeLoads;
bool do_escape_analysis = DoEscapeAnalysis &&
!env->jvmti_can_access_local_variables();
+ bool eliminate_boxing = EliminateAutoBox;
while (!env->failing()) {
// Attempt to compile while subsuming loads into machine instructions.
- Compile C(env, this, target, entry_bci, subsume_loads, do_escape_analysis);
+ Compile C(env, this, target, entry_bci, subsume_loads, do_escape_analysis, eliminate_boxing);
// Check result and retry if appropriate.
@@ -142,6 +143,12 @@
do_escape_analysis = false;
continue; // retry
}
+ if (C.has_boxed_value()) {
+ // Recompile without boxing elimination regardless failure reason.
+ assert(eliminate_boxing, "must make progress");
+ eliminate_boxing = false;
+ continue; // retry
+ }
// Pass any other failure reason up to the ciEnv.
// Note that serious, irreversible failures are already logged
// on the ciEnv via env->record_method_not_compilable().
--- a/hotspot/src/share/vm/opto/callGenerator.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/callGenerator.cpp Wed May 08 15:08:01 2013 -0700
@@ -134,7 +134,7 @@
kit.C->log()->elem("direct_call bci='%d'", jvms->bci());
}
- CallStaticJavaNode *call = new (kit.C) CallStaticJavaNode(tf(), target, method(), kit.bci());
+ CallStaticJavaNode *call = new (kit.C) CallStaticJavaNode(kit.C, tf(), target, method(), kit.bci());
_call_node = call; // Save the call node in case we need it later
if (!is_static) {
// Make an explicit receiver null_check as part of this call.
@@ -304,29 +304,34 @@
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()) {
+ CallStaticJavaNode* call = call_node();
+ if (call == NULL || call->outcnt() == 0 ||
+ call->in(0) == NULL || call->in(0)->is_top()) {
return;
}
- const TypeTuple *r = call_node()->tf()->domain();
+ const TypeTuple *r = call->tf()->domain();
for (int i1 = 0; i1 < method()->arg_size(); i1++) {
- if (call_node()->in(TypeFunc::Parms + i1)->is_top() && r->field_at(TypeFunc::Parms + i1) != Type::HALF) {
+ if (call->in(TypeFunc::Parms + i1)->is_top() && r->field_at(TypeFunc::Parms + i1) != Type::HALF) {
assert(Compile::current()->inlining_incrementally(), "shouldn't happen during parsing");
return;
}
}
- if (call_node()->in(TypeFunc::Memory)->is_top()) {
+ if (call->in(TypeFunc::Memory)->is_top()) {
assert(Compile::current()->inlining_incrementally(), "shouldn't happen during parsing");
return;
}
- CallStaticJavaNode* call = call_node();
+ Compile* C = Compile::current();
+ // Remove inlined methods from Compiler's lists.
+ if (call->is_macro()) {
+ C->remove_macro_node(call);
+ }
// 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);
+ JVMState* old_jvms = call->jvms();
+ JVMState* jvms = old_jvms->clone_shallow(C);
uint size = call->req();
SafePointNode* map = new (C) SafePointNode(size, jvms);
for (uint i1 = 0; i1 < size; i1++) {
@@ -340,16 +345,23 @@
map->set_req(TypeFunc::Memory, mem);
}
- // Make enough space for the expression stack and transfer the incoming arguments
- int nargs = method()->arg_size();
+ uint nargs = method()->arg_size();
+ // blow away old call arguments
+ Node* top = C->top();
+ for (uint i1 = 0; i1 < nargs; i1++) {
+ map->set_req(TypeFunc::Parms + i1, top);
+ }
jvms->set_map(map);
+
+ // Make enough space in the expression stack to transfer
+ // the incoming arguments and return value.
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));
- }
+ for (uint i1 = 0; i1 < nargs; i1++) {
+ map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1));
}
+ // This check is done here because for_method_handle_inline() method
+ // needs jvms for inlined state.
if (!do_late_inline_check(jvms)) {
map->disconnect_inputs(NULL, C);
return;
@@ -480,6 +492,26 @@
return new LateInlineStringCallGenerator(method, inline_cg);
}
+class LateInlineBoxingCallGenerator : public LateInlineCallGenerator {
+
+ public:
+ LateInlineBoxingCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
+ LateInlineCallGenerator(method, inline_cg) {}
+
+ virtual JVMState* generate(JVMState* jvms) {
+ Compile *C = Compile::current();
+ C->print_inlining_skip(this);
+
+ C->add_boxing_late_inline(this);
+
+ JVMState* new_jvms = DirectCallGenerator::generate(jvms);
+ return new_jvms;
+ }
+};
+
+CallGenerator* CallGenerator::for_boxing_late_inline(ciMethod* method, CallGenerator* inline_cg) {
+ return new LateInlineBoxingCallGenerator(method, inline_cg);
+}
//---------------------------WarmCallGenerator--------------------------------
// Internal class which handles initial deferral of inlining decisions.
--- a/hotspot/src/share/vm/opto/callGenerator.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/callGenerator.hpp Wed May 08 15:08:01 2013 -0700
@@ -125,6 +125,7 @@
static CallGenerator* for_late_inline(ciMethod* m, CallGenerator* inline_cg);
static CallGenerator* for_mh_late_inline(ciMethod* caller, ciMethod* callee, bool input_not_const);
static CallGenerator* for_string_late_inline(ciMethod* m, CallGenerator* inline_cg);
+ static CallGenerator* for_boxing_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,
--- a/hotspot/src/share/vm/opto/callnode.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/callnode.cpp Wed May 08 15:08:01 2013 -0700
@@ -523,7 +523,9 @@
void JVMState::dump_on(outputStream* st) const {
- if (_map && !((uintptr_t)_map & 1)) {
+ bool print_map = _map && !((uintptr_t)_map & 1) &&
+ ((caller() == NULL) || (caller()->map() != _map));
+ if (print_map) {
if (_map->len() > _map->req()) { // _map->has_exceptions()
Node* ex = _map->in(_map->req()); // _map->next_exception()
// skip the first one; it's already being printed
@@ -532,7 +534,10 @@
ex->dump(1);
}
}
- _map->dump(2);
+ _map->dump(Verbose ? 2 : 1);
+ }
+ if (caller() != NULL) {
+ caller()->dump_on(st);
}
st->print("JVMS depth=%d loc=%d stk=%d arg=%d mon=%d scalar=%d end=%d mondepth=%d sp=%d bci=%d reexecute=%s method=",
depth(), locoff(), stkoff(), argoff(), monoff(), scloff(), endoff(), monitor_depth(), sp(), bci(), should_reexecute()?"true":"false");
@@ -546,9 +551,6 @@
_method->print_codes_on(bci(), bci()+1, st);
}
}
- if (caller() != NULL) {
- caller()->dump_on(st);
- }
}
// Extra way to dump a jvms from the debugger,
@@ -584,6 +586,15 @@
return n;
}
+/**
+ * Reset map for all callers
+ */
+void JVMState::set_map_deep(SafePointNode* map) {
+ for (JVMState* p = this; p->_caller != NULL; p = p->_caller) {
+ p->set_map(map);
+ }
+}
+
//=============================================================================
uint CallNode::cmp( const Node &n ) const
{ return _tf == ((CallNode&)n)._tf && _jvms == ((CallNode&)n)._jvms; }
@@ -663,17 +674,49 @@
// Determine whether the call could modify the field of the specified
// instance at the specified offset.
//
-bool CallNode::may_modify(const TypePtr *addr_t, PhaseTransform *phase) {
- const TypeOopPtr *adrInst_t = addr_t->isa_oopptr();
-
- // If not an OopPtr or not an instance type, assume the worst.
- // Note: currently this method is called only for instance types.
- if (adrInst_t == NULL || !adrInst_t->is_known_instance()) {
- return true;
+bool CallNode::may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) {
+ assert((t_oop != NULL), "sanity");
+ if (t_oop->is_known_instance()) {
+ // The instance_id is set only for scalar-replaceable allocations which
+ // are not passed as arguments according to Escape Analysis.
+ return false;
}
- // The instance_id is set only for scalar-replaceable allocations which
- // are not passed as arguments according to Escape Analysis.
- return false;
+ if (t_oop->is_ptr_to_boxed_value()) {
+ ciKlass* boxing_klass = t_oop->klass();
+ if (is_CallStaticJava() && as_CallStaticJava()->is_boxing_method()) {
+ // Skip unrelated boxing methods.
+ Node* proj = proj_out(TypeFunc::Parms);
+ if ((proj == NULL) || (phase->type(proj)->is_instptr()->klass() != boxing_klass)) {
+ return false;
+ }
+ }
+ if (is_CallJava() && as_CallJava()->method() != NULL) {
+ ciMethod* meth = as_CallJava()->method();
+ if (meth->is_accessor()) {
+ return false;
+ }
+ // May modify (by reflection) if an boxing object is passed
+ // as argument or returned.
+ if (returns_pointer() && (proj_out(TypeFunc::Parms) != NULL)) {
+ Node* proj = proj_out(TypeFunc::Parms);
+ const TypeInstPtr* inst_t = phase->type(proj)->isa_instptr();
+ if ((inst_t != NULL) && (!inst_t->klass_is_exact() ||
+ (inst_t->klass() == boxing_klass))) {
+ return true;
+ }
+ }
+ const TypeTuple* d = tf()->domain();
+ for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
+ const TypeInstPtr* inst_t = d->field_at(i)->isa_instptr();
+ if ((inst_t != NULL) && (!inst_t->klass_is_exact() ||
+ (inst_t->klass() == boxing_klass))) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ return true;
}
// Does this call have a direct reference to n other than debug information?
@@ -1020,6 +1063,7 @@
int scloff = jvms->scloff();
int endoff = jvms->endoff();
assert(endoff == (int)req(), "no other states or debug info after me");
+ assert(jvms->scl_size() == 0, "parsed code should not have scalar objects");
Node* top = Compile::current()->top();
for (uint i = 0; i < grow_by; i++) {
ins_req(monoff, top);
@@ -1035,6 +1079,7 @@
const int MonitorEdges = 2;
assert(JVMState::logMonitorEdges == exact_log2(MonitorEdges), "correct MonitorEdges");
assert(req() == jvms()->endoff(), "correct sizing");
+ assert((jvms()->scl_size() == 0), "parsed code should not have scalar objects");
int nextmon = jvms()->scloff();
if (GenerateSynchronizationCode) {
add_req(lock->box_node());
@@ -1050,6 +1095,7 @@
void SafePointNode::pop_monitor() {
// Delete last monitor from debug info
+ assert((jvms()->scl_size() == 0), "parsed code should not have scalar objects");
debug_only(int num_before_pop = jvms()->nof_monitors());
const int MonitorEdges = (1<<JVMState::logMonitorEdges);
int scloff = jvms()->scloff();
@@ -1154,6 +1200,7 @@
init_class_id(Class_Allocate);
init_flags(Flag_is_macro);
_is_scalar_replaceable = false;
+ _is_non_escaping = false;
Node *topnode = C->top();
init_req( TypeFunc::Control , ctrl );
@@ -1169,8 +1216,6 @@
}
//=============================================================================
-uint AllocateArrayNode::size_of() const { return sizeof(*this); }
-
Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (remove_dead_region(phase, can_reshape)) return this;
// Don't bother trying to transform a dead node
@@ -1235,6 +1280,8 @@
// - the narrow_length is 0
// - the narrow_length is not wider than length
assert(narrow_length_type == TypeInt::ZERO ||
+ length_type->is_con() && narrow_length_type->is_con() &&
+ (narrow_length_type->_hi <= length_type->_lo) ||
(narrow_length_type->_hi <= length_type->_hi &&
narrow_length_type->_lo >= length_type->_lo),
"narrow type must be narrower than length type");
--- a/hotspot/src/share/vm/opto/callnode.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/callnode.hpp Wed May 08 15:08:01 2013 -0700
@@ -49,6 +49,7 @@
class CallLeafNoFPNode;
class AllocateNode;
class AllocateArrayNode;
+class BoxLockNode;
class LockNode;
class UnlockNode;
class JVMState;
@@ -235,7 +236,6 @@
int loc_size() const { return stkoff() - locoff(); }
int stk_size() const { return monoff() - stkoff(); }
- int arg_size() const { return monoff() - argoff(); }
int mon_size() const { return scloff() - monoff(); }
int scl_size() const { return endoff() - scloff(); }
@@ -298,6 +298,7 @@
// Miscellaneous utility functions
JVMState* clone_deep(Compile* C) const; // recursively clones caller chain
JVMState* clone_shallow(Compile* C) const; // retains uncloned caller
+ void set_map_deep(SafePointNode *map);// reset map for all callers
#ifndef PRODUCT
void format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) const;
@@ -439,7 +440,7 @@
static bool needs_polling_address_input();
#ifndef PRODUCT
- virtual void dump_spec(outputStream *st) const;
+ virtual void dump_spec(outputStream *st) const;
#endif
};
@@ -554,10 +555,10 @@
virtual bool guaranteed_safepoint() { return true; }
// For macro nodes, the JVMState gets modified during expansion, so when cloning
// the node the JVMState must be cloned.
- virtual void clone_jvms() { } // default is not to clone
+ virtual void clone_jvms(Compile* C) { } // default is not to clone
// Returns true if the call may modify n
- virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase);
+ virtual bool may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase);
// Does this node have a use of n other than in debug information?
bool has_non_debug_use(Node *n);
// Returns the unique CheckCastPP of a call
@@ -630,9 +631,15 @@
virtual uint cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
public:
- CallStaticJavaNode(const TypeFunc* tf, address addr, ciMethod* method, int bci)
+ CallStaticJavaNode(Compile* C, const TypeFunc* tf, address addr, ciMethod* method, int bci)
: CallJavaNode(tf, addr, method, bci), _name(NULL) {
init_class_id(Class_CallStaticJava);
+ if (C->eliminate_boxing() && (method != NULL) && method->is_boxing_method()) {
+ init_flags(Flag_is_macro);
+ C->add_macro_node(this);
+ }
+ _is_scalar_replaceable = false;
+ _is_non_escaping = false;
}
CallStaticJavaNode(const TypeFunc* tf, address addr, const char* name, int bci,
const TypePtr* adr_type)
@@ -640,13 +647,31 @@
init_class_id(Class_CallStaticJava);
// This node calls a runtime stub, which often has narrow memory effects.
_adr_type = adr_type;
+ _is_scalar_replaceable = false;
+ _is_non_escaping = false;
}
- const char *_name; // Runtime wrapper name
+ const char *_name; // Runtime wrapper name
+
+ // Result of Escape Analysis
+ bool _is_scalar_replaceable;
+ bool _is_non_escaping;
// If this is an uncommon trap, return the request code, else zero.
int uncommon_trap_request() const;
static int extract_uncommon_trap_request(const Node* call);
+ bool is_boxing_method() const {
+ return is_macro() && (method() != NULL) && method()->is_boxing_method();
+ }
+ // Later inlining modifies the JVMState, so we need to clone it
+ // when the call node is cloned (because it is macro node).
+ virtual void clone_jvms(Compile* C) {
+ if ((jvms() != NULL) && is_boxing_method()) {
+ set_jvms(jvms()->clone_deep(C));
+ jvms()->set_map_deep(this);
+ }
+ }
+
virtual int Opcode() const;
#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
@@ -748,12 +773,12 @@
ParmLimit
};
- static const TypeFunc* alloc_type() {
+ static const TypeFunc* alloc_type(const Type* t) {
const Type** fields = TypeTuple::fields(ParmLimit - TypeFunc::Parms);
fields[AllocSize] = TypeInt::POS;
fields[KlassNode] = TypeInstPtr::NOTNULL;
fields[InitialTest] = TypeInt::BOOL;
- fields[ALength] = TypeInt::INT; // length (can be a bad length)
+ fields[ALength] = t; // length (can be a bad length)
const TypeTuple *domain = TypeTuple::make(ParmLimit, fields);
@@ -766,21 +791,26 @@
return TypeFunc::make(domain, range);
}
- bool _is_scalar_replaceable; // Result of Escape Analysis
+ // Result of Escape Analysis
+ bool _is_scalar_replaceable;
+ bool _is_non_escaping;
virtual uint size_of() const; // Size is bigger
AllocateNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio,
Node *size, Node *klass_node, Node *initial_test);
// Expansion modifies the JVMState, so we need to clone it
- virtual void clone_jvms() {
- set_jvms(jvms()->clone_deep(Compile::current()));
+ virtual void clone_jvms(Compile* C) {
+ if (jvms() != NULL) {
+ set_jvms(jvms()->clone_deep(C));
+ jvms()->set_map_deep(this);
+ }
}
virtual int Opcode() const;
virtual uint ideal_reg() const { return Op_RegP; }
virtual bool guaranteed_safepoint() { return false; }
// allocations do not modify their arguments
- virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase) { return false;}
+ virtual bool may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) { return false;}
// Pattern-match a possible usage of AllocateNode.
// Return null if no allocation is recognized.
@@ -815,10 +845,6 @@
// are defined in graphKit.cpp, which sets up the bidirectional relation.)
InitializeNode* initialization();
- // Return the corresponding storestore barrier (or null if none).
- // Walks out edges to find it...
- MemBarStoreStoreNode* storestore();
-
// Convenience for initialization->maybe_set_complete(phase)
bool maybe_set_complete(PhaseGVN* phase);
};
@@ -840,7 +866,6 @@
set_req(AllocateNode::ALength, count_val);
}
virtual int Opcode() const;
- virtual uint size_of() const; // Size is bigger
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
// Dig the length operand out of a array allocation site.
@@ -918,7 +943,7 @@
void set_nested() { _kind = Nested; set_eliminated_lock_counter(); }
// locking does not modify its arguments
- virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase){ return false;}
+ virtual bool may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase){ return false;}
#ifndef PRODUCT
void create_lock_counter(JVMState* s);
@@ -965,8 +990,11 @@
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
// Expansion modifies the JVMState, so we need to clone it
- virtual void clone_jvms() {
- set_jvms(jvms()->clone_deep(Compile::current()));
+ virtual void clone_jvms(Compile* C) {
+ if (jvms() != NULL) {
+ set_jvms(jvms()->clone_deep(C));
+ jvms()->set_map_deep(this);
+ }
}
bool is_nested_lock_region(); // Is this Lock nested?
--- a/hotspot/src/share/vm/opto/cfgnode.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/cfgnode.cpp Wed May 08 15:08:01 2013 -0700
@@ -806,7 +806,7 @@
Node *in = ophi->in(i);
if (in == NULL || igvn->type(in) == Type::TOP)
continue;
- Node *opt = MemNode::optimize_simple_memory_chain(in, at, igvn);
+ Node *opt = MemNode::optimize_simple_memory_chain(in, t_oop, NULL, igvn);
PhiNode *optphi = opt->is_Phi() ? opt->as_Phi() : NULL;
if (optphi != NULL && optphi->adr_type() == TypePtr::BOTTOM) {
opt = node_map[optphi->_idx];
@@ -1921,7 +1921,7 @@
const TypePtr* at = adr_type();
for( uint i=1; i<req(); ++i ) {// For all paths in
Node *ii = in(i);
- Node *new_in = MemNode::optimize_memory_chain(ii, at, phase);
+ Node *new_in = MemNode::optimize_memory_chain(ii, at, NULL, phase);
if (ii != new_in ) {
set_req(i, new_in);
progress = this;
--- a/hotspot/src/share/vm/opto/compile.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/compile.cpp Wed May 08 15:08:01 2013 -0700
@@ -418,6 +418,7 @@
}
// clean up the late inline lists
remove_useless_late_inlines(&_string_late_inlines, useful);
+ remove_useless_late_inlines(&_boxing_late_inlines, useful);
remove_useless_late_inlines(&_late_inlines, useful);
debug_only(verify_graph_edges(true/*check for no_dead_code*/);)
}
@@ -485,6 +486,12 @@
tty->print_cr("** Bailout: Recompile without escape analysis **");
tty->print_cr("*********************************************************");
}
+ if (_eliminate_boxing != EliminateAutoBox && PrintOpto) {
+ // Recompiling without boxing elimination
+ tty->print_cr("*********************************************************");
+ tty->print_cr("** Bailout: Recompile without boxing elimination **");
+ tty->print_cr("*********************************************************");
+ }
if (env()->break_at_compile()) {
// Open the debugger when compiling this method.
tty->print("### Breaking when compiling: ");
@@ -601,7 +608,8 @@
// the continuation bci for on stack replacement.
-Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr_bci, bool subsume_loads, bool do_escape_analysis )
+Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr_bci,
+ bool subsume_loads, bool do_escape_analysis, bool eliminate_boxing )
: Phase(Compiler),
_env(ci_env),
_log(ci_env->log()),
@@ -617,6 +625,7 @@
_warm_calls(NULL),
_subsume_loads(subsume_loads),
_do_escape_analysis(do_escape_analysis),
+ _eliminate_boxing(eliminate_boxing),
_failure_reason(NULL),
_code_buffer("Compile::Fill_buffer"),
_orig_pc_slot(0),
@@ -638,6 +647,7 @@
_congraph(NULL),
_late_inlines(comp_arena(), 2, 0, NULL),
_string_late_inlines(comp_arena(), 2, 0, NULL),
+ _boxing_late_inlines(comp_arena(), 2, 0, NULL),
_late_inlines_pos(0),
_number_of_mh_late_inlines(0),
_inlining_progress(false),
@@ -906,6 +916,7 @@
_orig_pc_slot_offset_in_bytes(0),
_subsume_loads(true),
_do_escape_analysis(false),
+ _eliminate_boxing(false),
_failure_reason(NULL),
_code_buffer("Compile::Fill_buffer"),
_has_method_handle_invokes(false),
@@ -1016,6 +1027,7 @@
set_has_split_ifs(false);
set_has_loops(has_method() && method()->has_loops()); // first approximation
set_has_stringbuilder(false);
+ set_has_boxed_value(false);
_trap_can_recompile = false; // no traps emitted yet
_major_progress = true; // start out assuming good things will happen
set_has_unsafe_access(false);
@@ -1807,6 +1819,38 @@
_string_late_inlines.trunc_to(0);
}
+// Late inlining of boxing methods
+void Compile::inline_boxing_calls(PhaseIterGVN& igvn) {
+ if (_boxing_late_inlines.length() > 0) {
+ assert(has_boxed_value(), "inconsistent");
+
+ PhaseGVN* gvn = initial_gvn();
+ set_inlining_incrementally(true);
+
+ assert( igvn._worklist.size() == 0, "should be done with igvn" );
+ for_igvn()->clear();
+ gvn->replace_with(&igvn);
+
+ while (_boxing_late_inlines.length() > 0) {
+ CallGenerator* cg = _boxing_late_inlines.pop();
+ cg->do_late_inline();
+ if (failing()) return;
+ }
+ _boxing_late_inlines.trunc_to(0);
+
+ {
+ ResourceMark rm;
+ PhaseRemoveUseless pru(gvn, for_igvn());
+ }
+
+ igvn = PhaseIterGVN(gvn);
+ igvn.optimize();
+
+ set_inlining_progress(false);
+ set_inlining_incrementally(false);
+ }
+}
+
void Compile::inline_incrementally_one(PhaseIterGVN& igvn) {
assert(IncrementalInline, "incremental inlining should be on");
PhaseGVN* gvn = initial_gvn();
@@ -1831,7 +1875,7 @@
{
ResourceMark rm;
- PhaseRemoveUseless pru(C->initial_gvn(), C->for_igvn());
+ PhaseRemoveUseless pru(gvn, for_igvn());
}
igvn = PhaseIterGVN(gvn);
@@ -1929,12 +1973,25 @@
if (failing()) return;
- inline_incrementally(igvn);
+ {
+ NOT_PRODUCT( TracePhase t2("incrementalInline", &_t_incrInline, TimeCompiler); )
+ inline_incrementally(igvn);
+ }
print_method("Incremental Inline", 2);
if (failing()) return;
+ if (eliminate_boxing()) {
+ NOT_PRODUCT( TracePhase t2("incrementalInline", &_t_incrInline, TimeCompiler); )
+ // Inline valueOf() methods now.
+ inline_boxing_calls(igvn);
+
+ print_method("Incremental Boxing Inline", 2);
+
+ if (failing()) return;
+ }
+
// No more new expensive nodes will be added to the list from here
// so keep only the actual candidates for optimizations.
cleanup_expensive_nodes(igvn);
@@ -2896,6 +2953,7 @@
}
break;
case Op_MemBarStoreStore:
+ case Op_MemBarRelease:
// Break the link with AllocateNode: it is no longer useful and
// confuses register allocation.
if (n->req() > MemBarNode::Precedent) {
--- a/hotspot/src/share/vm/opto/compile.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/compile.hpp Wed May 08 15:08:01 2013 -0700
@@ -262,6 +262,7 @@
const bool _save_argument_registers; // save/restore arg regs for trampolines
const bool _subsume_loads; // Load can be matched as part of a larger op.
const bool _do_escape_analysis; // Do escape analysis.
+ const bool _eliminate_boxing; // Do boxing elimination.
ciMethod* _method; // The method being compiled.
int _entry_bci; // entry bci for osr methods.
const TypeFunc* _tf; // My kind of signature
@@ -287,6 +288,7 @@
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
+ bool _has_boxed_value; // True if a boxed object is allocated
int _max_vector_size; // Maximum size of generated vectors
uint _trap_hist[trapHistLength]; // Cumulative traps
bool _trap_can_recompile; // Have we emitted a recompiling trap?
@@ -375,6 +377,8 @@
// main parsing has finished.
GrowableArray<CallGenerator*> _string_late_inlines; // same but for string operations
+ GrowableArray<CallGenerator*> _boxing_late_inlines; // same but for boxing operations
+
int _late_inlines_pos; // Where in the queue should the next late inlining candidate go (emulate depth first inlining)
uint _number_of_mh_late_inlines; // number of method handle late inlining still pending
@@ -486,8 +490,12 @@
// instructions that subsume a load may result in an unschedulable
// instruction sequence.
bool subsume_loads() const { return _subsume_loads; }
- // Do escape analysis.
+ /** Do escape analysis. */
bool do_escape_analysis() const { return _do_escape_analysis; }
+ /** Do boxing elimination. */
+ bool eliminate_boxing() const { return _eliminate_boxing; }
+ /** Do aggressive boxing elimination. */
+ bool aggressive_unboxing() const { return _eliminate_boxing && AggressiveUnboxing; }
bool save_argument_registers() const { return _save_argument_registers; }
@@ -527,6 +535,8 @@
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; }
+ bool has_boxed_value() const { return _has_boxed_value; }
+ void set_has_boxed_value(bool z) { _has_boxed_value = z; }
int max_vector_size() const { return _max_vector_size; }
void set_max_vector_size(int s) { _max_vector_size = s; }
void set_trap_count(uint r, uint c) { assert(r < trapHistLength, "oob"); _trap_hist[r] = c; }
@@ -579,12 +589,12 @@
#endif
}
- int macro_count() { return _macro_nodes->length(); }
- int predicate_count() { return _predicate_opaqs->length();}
- int expensive_count() { return _expensive_nodes->length(); }
- Node* macro_node(int idx) { return _macro_nodes->at(idx); }
- Node* predicate_opaque1_node(int idx) { return _predicate_opaqs->at(idx);}
- Node* expensive_node(int idx) { return _expensive_nodes->at(idx); }
+ int macro_count() const { return _macro_nodes->length(); }
+ int predicate_count() const { return _predicate_opaqs->length();}
+ int expensive_count() const { return _expensive_nodes->length(); }
+ Node* macro_node(int idx) const { return _macro_nodes->at(idx); }
+ Node* predicate_opaque1_node(int idx) const { return _predicate_opaqs->at(idx);}
+ Node* expensive_node(int idx) const { return _expensive_nodes->at(idx); }
ConnectionGraph* congraph() { return _congraph;}
void set_congraph(ConnectionGraph* congraph) { _congraph = congraph;}
void add_macro_node(Node * n) {
@@ -766,7 +776,12 @@
// 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_does_dispatch, JVMState* jvms, bool allow_inline, float profile_factor, bool allow_intrinsics = true, bool delayed_forbidden = false);
- bool should_delay_inlining(ciMethod* call_method, JVMState* jvms);
+ bool should_delay_inlining(ciMethod* call_method, JVMState* jvms) {
+ return should_delay_string_inlining(call_method, jvms) ||
+ should_delay_boxing_inlining(call_method, jvms);
+ }
+ bool should_delay_string_inlining(ciMethod* call_method, JVMState* jvms);
+ bool should_delay_boxing_inlining(ciMethod* call_method, JVMState* jvms);
// Helper functions to identify inlining potential at call-site
ciMethod* optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass,
@@ -822,6 +837,10 @@
_string_late_inlines.push(cg);
}
+ void add_boxing_late_inline(CallGenerator* cg) {
+ _boxing_late_inlines.push(cg);
+ }
+
void remove_useless_late_inlines(GrowableArray<CallGenerator*>* inlines, Unique_Node_List &useful);
void dump_inlining();
@@ -841,6 +860,7 @@
void inline_incrementally_one(PhaseIterGVN& igvn);
void inline_incrementally(PhaseIterGVN& igvn);
void inline_string_calls(bool parse_time);
+ void inline_boxing_calls(PhaseIterGVN& igvn);
// Matching, CFG layout, allocation, code generation
PhaseCFG* cfg() { return _cfg; }
@@ -913,7 +933,8 @@
// replacement, entry_bci indicates the bytecode for which to compile a
// continuation.
Compile(ciEnv* ci_env, C2Compiler* compiler, ciMethod* target,
- int entry_bci, bool subsume_loads, bool do_escape_analysis);
+ int entry_bci, bool subsume_loads, bool do_escape_analysis,
+ bool eliminate_boxing);
// Second major entry point. From the TypeFunc signature, generate code
// to pass arguments from the Java calling convention to the C calling
--- a/hotspot/src/share/vm/opto/doCall.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/doCall.cpp Wed May 08 15:08:01 2013 -0700
@@ -176,9 +176,12 @@
// Delay the inlining of this method to give us the
// opportunity to perform some high level optimizations
// first.
- if (should_delay_inlining(callee, jvms)) {
+ if (should_delay_string_inlining(callee, jvms)) {
assert(!delayed_forbidden, "strange");
return CallGenerator::for_string_late_inline(callee, cg);
+ } else if (should_delay_boxing_inlining(callee, jvms)) {
+ assert(!delayed_forbidden, "strange");
+ return CallGenerator::for_boxing_late_inline(callee, cg);
} else if ((should_delay || AlwaysIncrementalInline) && !delayed_forbidden) {
return CallGenerator::for_late_inline(callee, cg);
}
@@ -276,7 +279,7 @@
// 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) {
+bool Compile::should_delay_string_inlining(ciMethod* call_method, JVMState* jvms) {
if (has_stringbuilder()) {
if ((call_method->holder() == C->env()->StringBuilder_klass() ||
@@ -327,6 +330,13 @@
return false;
}
+bool Compile::should_delay_boxing_inlining(ciMethod* call_method, JVMState* jvms) {
+ if (eliminate_boxing() && call_method->is_boxing_method()) {
+ set_has_boxed_value(true);
+ return true;
+ }
+ 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) {
--- a/hotspot/src/share/vm/opto/escape.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/escape.cpp Wed May 08 15:08:01 2013 -0700
@@ -63,15 +63,19 @@
// EA brings benefits only when the code has allocations and/or locks which
// are represented by ideal Macro nodes.
int cnt = C->macro_count();
- for( int i=0; i < cnt; i++ ) {
+ for (int i = 0; i < cnt; i++) {
Node *n = C->macro_node(i);
- if ( n->is_Allocate() )
+ if (n->is_Allocate())
return true;
- if( n->is_Lock() ) {
+ if (n->is_Lock()) {
Node* obj = n->as_Lock()->obj_node()->uncast();
- if( !(obj->is_Parm() || obj->is_Con()) )
+ if (!(obj->is_Parm() || obj->is_Con()))
return true;
}
+ if (n->is_CallStaticJava() &&
+ n->as_CallStaticJava()->is_boxing_method()) {
+ return true;
+ }
}
return false;
}
@@ -115,7 +119,7 @@
{ Compile::TracePhase t3("connectionGraph", &Phase::_t_connectionGraph, true);
// 1. Populate Connection Graph (CG) with PointsTo nodes.
- ideal_nodes.map(C->unique(), NULL); // preallocate space
+ ideal_nodes.map(C->live_nodes(), NULL); // preallocate space
// Initialize worklist
if (C->root() != NULL) {
ideal_nodes.push(C->root());
@@ -152,8 +156,11 @@
// escape status of the associated Allocate node some of them
// may be eliminated.
storestore_worklist.append(n);
+ } else if (n->is_MemBar() && (n->Opcode() == Op_MemBarRelease) &&
+ (n->req() > MemBarNode::Precedent)) {
+ record_for_optimizer(n);
#ifdef ASSERT
- } else if(n->is_AddP()) {
+ } else if (n->is_AddP()) {
// Collect address nodes for graph verification.
addp_worklist.append(n);
#endif
@@ -206,8 +213,15 @@
int non_escaped_length = non_escaped_worklist.length();
for (int next = 0; next < non_escaped_length; next++) {
JavaObjectNode* ptn = non_escaped_worklist.at(next);
- if (ptn->escape_state() == PointsToNode::NoEscape &&
- ptn->scalar_replaceable()) {
+ bool noescape = (ptn->escape_state() == PointsToNode::NoEscape);
+ Node* n = ptn->ideal_node();
+ if (n->is_Allocate()) {
+ n->as_Allocate()->_is_non_escaping = noescape;
+ }
+ if (n->is_CallStaticJava()) {
+ n->as_CallStaticJava()->_is_non_escaping = noescape;
+ }
+ if (noescape && ptn->scalar_replaceable()) {
adjust_scalar_replaceable_state(ptn);
if (ptn->scalar_replaceable()) {
alloc_worklist.append(ptn->ideal_node());
@@ -330,8 +344,10 @@
// Don't mark as processed since call's arguments have to be processed.
delayed_worklist->push(n);
// Check if a call returns an object.
- if (n->as_Call()->returns_pointer() &&
- n->as_Call()->proj_out(TypeFunc::Parms) != NULL) {
+ if ((n->as_Call()->returns_pointer() &&
+ n->as_Call()->proj_out(TypeFunc::Parms) != NULL) ||
+ (n->is_CallStaticJava() &&
+ n->as_CallStaticJava()->is_boxing_method())) {
add_call_node(n->as_Call());
}
}
@@ -387,8 +403,8 @@
case Op_ConNKlass: {
// assume all oop constants globally escape except for null
PointsToNode::EscapeState es;
- if (igvn->type(n) == TypePtr::NULL_PTR ||
- igvn->type(n) == TypeNarrowOop::NULL_PTR) {
+ const Type* t = igvn->type(n);
+ if (t == TypePtr::NULL_PTR || t == TypeNarrowOop::NULL_PTR) {
es = PointsToNode::NoEscape;
} else {
es = PointsToNode::GlobalEscape;
@@ -797,6 +813,9 @@
// Returns a newly allocated unescaped object.
add_java_object(call, PointsToNode::NoEscape);
ptnode_adr(call_idx)->set_scalar_replaceable(false);
+ } else if (meth->is_boxing_method()) {
+ // Returns boxing object
+ add_java_object(call, PointsToNode::NoEscape);
} else {
BCEscapeAnalyzer* call_analyzer = meth->get_bcea();
call_analyzer->copy_dependencies(_compile->dependencies());
@@ -943,6 +962,9 @@
assert((name == NULL || strcmp(name, "uncommon_trap") != 0), "normal calls only");
#endif
ciMethod* meth = call->as_CallJava()->method();
+ if ((meth != NULL) && meth->is_boxing_method()) {
+ break; // Boxing methods do not modify any oops.
+ }
BCEscapeAnalyzer* call_analyzer = (meth !=NULL) ? meth->get_bcea() : NULL;
// fall-through if not a Java method or no analyzer information
if (call_analyzer != NULL) {
@@ -2744,6 +2766,11 @@
// so it could be eliminated if it has no uses.
alloc->as_Allocate()->_is_scalar_replaceable = true;
}
+ if (alloc->is_CallStaticJava()) {
+ // Set the scalar_replaceable flag for boxing method
+ // so it could be eliminated if it has no uses.
+ alloc->as_CallStaticJava()->_is_scalar_replaceable = true;
+ }
continue;
}
if (!n->is_CheckCastPP()) { // not unique CheckCastPP.
@@ -2782,6 +2809,11 @@
// so it could be eliminated.
alloc->as_Allocate()->_is_scalar_replaceable = true;
}
+ if (alloc->is_CallStaticJava()) {
+ // Set the scalar_replaceable flag for boxing method
+ // so it could be eliminated.
+ alloc->as_CallStaticJava()->_is_scalar_replaceable = true;
+ }
set_escape_state(ptnode_adr(n->_idx), es); // CheckCastPP escape state
// in order for an object to be scalar-replaceable, it must be:
// - a direct allocation (not a call returning an object)
@@ -2911,7 +2943,9 @@
// Load/store to instance's field
memnode_worklist.append_if_missing(use);
} else if (use->is_MemBar()) {
- memnode_worklist.append_if_missing(use);
+ if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge
+ memnode_worklist.append_if_missing(use);
+ }
} else if (use->is_AddP() && use->outcnt() > 0) { // No dead nodes
Node* addp2 = find_second_addp(use, n);
if (addp2 != NULL) {
@@ -3028,7 +3062,9 @@
continue;
memnode_worklist.append_if_missing(use);
} else if (use->is_MemBar()) {
- memnode_worklist.append_if_missing(use);
+ if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge
+ memnode_worklist.append_if_missing(use);
+ }
#ifdef ASSERT
} else if(use->is_Mem()) {
assert(use->in(MemNode::Memory) != n, "EA: missing memory path");
@@ -3264,7 +3300,12 @@
if (ptn == NULL || !ptn->is_JavaObject())
continue;
PointsToNode::EscapeState es = ptn->escape_state();
- if (ptn->ideal_node()->is_Allocate() && (es == PointsToNode::NoEscape || Verbose)) {
+ if ((es != PointsToNode::NoEscape) && !Verbose) {
+ continue;
+ }
+ Node* n = ptn->ideal_node();
+ if (n->is_Allocate() || (n->is_CallStaticJava() &&
+ n->as_CallStaticJava()->is_boxing_method())) {
if (first) {
tty->cr();
tty->print("======== Connection graph for ");
--- a/hotspot/src/share/vm/opto/graphKit.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/graphKit.cpp Wed May 08 15:08:01 2013 -0700
@@ -333,6 +333,7 @@
assert(ex_jvms->stkoff() == phi_map->_jvms->stkoff(), "matching locals");
assert(ex_jvms->sp() == phi_map->_jvms->sp(), "matching stack sizes");
assert(ex_jvms->monoff() == phi_map->_jvms->monoff(), "matching JVMS");
+ assert(ex_jvms->scloff() == phi_map->_jvms->scloff(), "matching scalar replaced objects");
assert(ex_map->req() == phi_map->req(), "matching maps");
uint tos = ex_jvms->stkoff() + ex_jvms->sp();
Node* hidden_merge_mark = root();
@@ -409,7 +410,7 @@
while (dst->req() > orig_width) dst->del_req(dst->req()-1);
} else {
assert(dst->is_Phi(), "nobody else uses a hidden region");
- phi = (PhiNode*)dst;
+ phi = dst->as_Phi();
}
if (add_multiple && src->in(0) == ex_control) {
// Both are phis.
@@ -1438,7 +1439,12 @@
} else {
ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt);
}
- return _gvn.transform(ld);
+ ld = _gvn.transform(ld);
+ if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) {
+ // Improve graph before escape analysis and boxing elimination.
+ record_for_igvn(ld);
+ }
+ return ld;
}
Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt,
@@ -3144,7 +3150,7 @@
set_all_memory(mem); // Create new memory state
AllocateNode* alloc
- = new (C) AllocateNode(C, AllocateNode::alloc_type(),
+ = new (C) AllocateNode(C, AllocateNode::alloc_type(Type::TOP),
control(), mem, i_o(),
size, klass_node,
initial_slow_test);
@@ -3285,7 +3291,7 @@
// Create the AllocateArrayNode and its result projections
AllocateArrayNode* alloc
- = new (C) AllocateArrayNode(C, AllocateArrayNode::alloc_type(),
+ = new (C) AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT),
control(), mem, i_o(),
size, klass_node,
initial_slow_test,
@@ -3326,10 +3332,9 @@
if (ptr == NULL) { // reduce dumb test in callers
return NULL;
}
- if (ptr->is_CheckCastPP()) { // strip a raw-to-oop cast
- ptr = ptr->in(1);
- if (ptr == NULL) return NULL;
- }
+ ptr = ptr->uncast(); // strip a raw-to-oop cast
+ if (ptr == NULL) return NULL;
+
if (ptr->is_Proj()) {
Node* allo = ptr->in(0);
if (allo != NULL && allo->is_Allocate()) {
@@ -3374,19 +3379,6 @@
return NULL;
}
-// Trace Allocate -> Proj[Parm] -> MemBarStoreStore
-MemBarStoreStoreNode* AllocateNode::storestore() {
- ProjNode* rawoop = proj_out(AllocateNode::RawAddress);
- if (rawoop == NULL) return NULL;
- for (DUIterator_Fast imax, i = rawoop->fast_outs(imax); i < imax; i++) {
- Node* storestore = rawoop->fast_out(i);
- if (storestore->is_MemBarStoreStore()) {
- return storestore->as_MemBarStoreStore();
- }
- }
- return NULL;
-}
-
//----------------------------- loop predicates ---------------------------
//------------------------------add_predicate_impl----------------------------
--- a/hotspot/src/share/vm/opto/ifnode.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/ifnode.cpp Wed May 08 15:08:01 2013 -0700
@@ -673,7 +673,7 @@
// / Region
//
Node* IfNode::fold_compares(PhaseGVN* phase) {
- if (!EliminateAutoBox || Opcode() != Op_If) return NULL;
+ if (!phase->C->eliminate_boxing() || Opcode() != Op_If) return NULL;
Node* this_cmp = in(1)->in(1);
if (this_cmp != NULL && this_cmp->Opcode() == Op_CmpI &&
--- a/hotspot/src/share/vm/opto/library_call.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/library_call.cpp Wed May 08 15:08:01 2013 -0700
@@ -3703,7 +3703,7 @@
CallJavaNode* slow_call;
if (is_static) {
assert(!is_virtual, "");
- slow_call = new(C) CallStaticJavaNode(tf,
+ slow_call = new(C) CallStaticJavaNode(C, tf,
SharedRuntime::get_resolve_static_call_stub(),
method, bci());
} else if (is_virtual) {
@@ -3722,7 +3722,7 @@
method, vtable_index, bci());
} else { // neither virtual nor static: opt_virtual
null_check_receiver();
- slow_call = new(C) CallStaticJavaNode(tf,
+ slow_call = new(C) CallStaticJavaNode(C, tf,
SharedRuntime::get_resolve_opt_virtual_call_stub(),
method, bci());
slow_call->set_optimized_virtual(true);
--- a/hotspot/src/share/vm/opto/loopPredicate.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/loopPredicate.cpp Wed May 08 15:08:01 2013 -0700
@@ -821,8 +821,8 @@
loop->dump_head();
}
#endif
- } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) {
- assert(proj->_con == predicate_proj->_con, "must match");
+ } else if ((cl != NULL) && (proj->_con == predicate_proj->_con) &&
+ loop->is_range_check_if(iff, this, invar)) {
// Range check for counted loops
const Node* cmp = bol->in(1)->as_Cmp();
--- a/hotspot/src/share/vm/opto/macro.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/macro.cpp Wed May 08 15:08:01 2013 -0700
@@ -666,7 +666,7 @@
alloc->dump();
else
res->dump();
- } else {
+ } else if (alloc->_is_scalar_replaceable) {
tty->print("NotScalar (%s)", fail_eliminate);
if (res == NULL)
alloc->dump();
@@ -845,18 +845,14 @@
// to the allocated object with "sobj"
int start = jvms->debug_start();
int end = jvms->debug_end();
- for (int i = start; i < end; i++) {
- if (sfpt->in(i) == res) {
- sfpt->set_req(i, sobj);
- }
- }
+ sfpt->replace_edges_in_range(res, sobj, start, end);
safepoints_done.append_if_missing(sfpt); // keep it for rollback
}
return true;
}
// Process users of eliminated allocation.
-void PhaseMacroExpand::process_users_of_allocation(AllocateNode *alloc) {
+void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc) {
Node* res = alloc->result_cast();
if (res != NULL) {
for (DUIterator_Last jmin, j = res->last_outs(jmin); j >= jmin; ) {
@@ -899,6 +895,17 @@
// Process other users of allocation's projections
//
if (_resproj != NULL && _resproj->outcnt() != 0) {
+ // First disconnect stores captured by Initialize node.
+ // If Initialize node is eliminated first in the following code,
+ // it will kill such stores and DUIterator_Last will assert.
+ for (DUIterator_Fast jmax, j = _resproj->fast_outs(jmax); j < jmax; j++) {
+ Node *use = _resproj->fast_out(j);
+ if (use->is_AddP()) {
+ // raw memory addresses used only by the initialization
+ _igvn.replace_node(use, C->top());
+ --j; --jmax;
+ }
+ }
for (DUIterator_Last jmin, j = _resproj->last_outs(jmin); j >= jmin; ) {
Node *use = _resproj->last_out(j);
uint oc1 = _resproj->outcnt();
@@ -923,9 +930,6 @@
#endif
_igvn.replace_node(mem_proj, mem);
}
- } else if (use->is_AddP()) {
- // raw memory addresses used only by the initialization
- _igvn.replace_node(use, C->top());
} else {
assert(false, "only Initialize or AddP expected");
}
@@ -953,8 +957,18 @@
}
bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) {
-
- if (!EliminateAllocations || !alloc->_is_scalar_replaceable) {
+ if (!EliminateAllocations || !alloc->_is_non_escaping) {
+ return false;
+ }
+ Node* klass = alloc->in(AllocateNode::KlassNode);
+ const TypeKlassPtr* tklass = _igvn.type(klass)->is_klassptr();
+ Node* res = alloc->result_cast();
+ // Eliminate boxing allocations which are not used
+ // regardless scalar replacable status.
+ bool boxing_alloc = C->eliminate_boxing() &&
+ tklass->klass()->is_instance_klass() &&
+ tklass->klass()->as_instance_klass()->is_box_klass();
+ if (!alloc->_is_scalar_replaceable && (!boxing_alloc || (res != NULL))) {
return false;
}
@@ -965,14 +979,22 @@
return false;
}
+ if (!alloc->_is_scalar_replaceable) {
+ assert(res == NULL, "sanity");
+ // We can only eliminate allocation if all debug info references
+ // are already replaced with SafePointScalarObject because
+ // we can't search for a fields value without instance_id.
+ if (safepoints.length() > 0) {
+ return false;
+ }
+ }
+
if (!scalar_replacement(alloc, safepoints)) {
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();
@@ -997,6 +1019,43 @@
return true;
}
+bool PhaseMacroExpand::eliminate_boxing_node(CallStaticJavaNode *boxing) {
+ // EA should remove all uses of non-escaping boxing node.
+ if (!C->eliminate_boxing() || boxing->proj_out(TypeFunc::Parms) != NULL) {
+ return false;
+ }
+
+ extract_call_projections(boxing);
+
+ const TypeTuple* r = boxing->tf()->range();
+ assert(r->cnt() > TypeFunc::Parms, "sanity");
+ const TypeInstPtr* t = r->field_at(TypeFunc::Parms)->isa_instptr();
+ assert(t != NULL, "sanity");
+
+ CompileLog* log = C->log();
+ if (log != NULL) {
+ log->head("eliminate_boxing type='%d'",
+ log->identify(t->klass()));
+ JVMState* p = boxing->jvms();
+ while (p != NULL) {
+ log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
+ p = p->caller();
+ }
+ log->tail("eliminate_boxing");
+ }
+
+ process_users_of_allocation(boxing);
+
+#ifndef PRODUCT
+ if (PrintEliminateAllocations) {
+ tty->print("++++ Eliminated: %d ", boxing->_idx);
+ boxing->method()->print_short_name(tty);
+ tty->cr();
+ }
+#endif
+
+ return true;
+}
//---------------------------set_eden_pointers-------------------------
void PhaseMacroExpand::set_eden_pointers(Node* &eden_top_adr, Node* &eden_end_adr) {
@@ -2384,6 +2443,9 @@
case Node::Class_AllocateArray:
success = eliminate_allocate_node(n->as_Allocate());
break;
+ case Node::Class_CallStaticJava:
+ success = eliminate_boxing_node(n->as_CallStaticJava());
+ break;
case Node::Class_Lock:
case Node::Class_Unlock:
assert(!n->as_AbstractLock()->is_eliminated(), "sanity");
@@ -2424,6 +2486,11 @@
C->remove_macro_node(n);
_igvn._worklist.push(n);
success = true;
+ } else if (n->Opcode() == Op_CallStaticJava) {
+ // Remove it from macro list and put on IGVN worklist to optimize.
+ C->remove_macro_node(n);
+ _igvn._worklist.push(n);
+ success = true;
} else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
_igvn.replace_node(n, n->in(1));
success = true;
--- a/hotspot/src/share/vm/opto/macro.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/macro.hpp Wed May 08 15:08:01 2013 -0700
@@ -86,10 +86,11 @@
Node *value_from_mem(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc);
Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc, Node_Stack *value_phis, int level);
+ bool eliminate_boxing_node(CallStaticJavaNode *boxing);
bool eliminate_allocate_node(AllocateNode *alloc);
bool can_eliminate_allocation(AllocateNode *alloc, GrowableArray <SafePointNode *>& safepoints);
bool scalar_replacement(AllocateNode *alloc, GrowableArray <SafePointNode *>& safepoints_done);
- void process_users_of_allocation(AllocateNode *alloc);
+ void process_users_of_allocation(CallNode *alloc);
void eliminate_card_mark(Node *cm);
void mark_eliminated_box(Node* box, Node* obj);
--- a/hotspot/src/share/vm/opto/memnode.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/memnode.cpp Wed May 08 15:08:01 2013 -0700
@@ -103,11 +103,15 @@
#endif
-Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypePtr *t_adr, PhaseGVN *phase) {
- const TypeOopPtr *tinst = t_adr->isa_oopptr();
- if (tinst == NULL || !tinst->is_known_instance_field())
+Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypeOopPtr *t_oop, Node *load, PhaseGVN *phase) {
+ assert((t_oop != NULL), "sanity");
+ bool is_instance = t_oop->is_known_instance_field();
+ bool is_boxed_value_load = t_oop->is_ptr_to_boxed_value() &&
+ (load != NULL) && load->is_Load() &&
+ (phase->is_IterGVN() != NULL);
+ if (!(is_instance || is_boxed_value_load))
return mchain; // don't try to optimize non-instance types
- uint instance_id = tinst->instance_id();
+ uint instance_id = t_oop->instance_id();
Node *start_mem = phase->C->start()->proj_out(TypeFunc::Memory);
Node *prev = NULL;
Node *result = mchain;
@@ -122,15 +126,24 @@
break; // hit one of our sentinels
} else if (proj_in->is_Call()) {
CallNode *call = proj_in->as_Call();
- if (!call->may_modify(t_adr, phase)) {
+ if (!call->may_modify(t_oop, phase)) { // returns false for instances
result = call->in(TypeFunc::Memory);
}
} else if (proj_in->is_Initialize()) {
AllocateNode* alloc = proj_in->as_Initialize()->allocation();
// Stop if this is the initialization for the object instance which
// which contains this memory slice, otherwise skip over it.
- if (alloc != NULL && alloc->_idx != instance_id) {
+ if ((alloc == NULL) || (alloc->_idx == instance_id)) {
+ break;
+ }
+ if (is_instance) {
result = proj_in->in(TypeFunc::Memory);
+ } else if (is_boxed_value_load) {
+ Node* klass = alloc->in(AllocateNode::KlassNode);
+ const TypeKlassPtr* tklass = phase->type(klass)->is_klassptr();
+ if (tklass->klass_is_exact() && !tklass->klass()->equals(t_oop->klass())) {
+ result = proj_in->in(TypeFunc::Memory); // not related allocation
+ }
}
} else if (proj_in->is_MemBar()) {
result = proj_in->in(TypeFunc::Memory);
@@ -138,25 +151,26 @@
assert(false, "unexpected projection");
}
} else if (result->is_ClearArray()) {
- if (!ClearArrayNode::step_through(&result, instance_id, phase)) {
+ if (!is_instance || !ClearArrayNode::step_through(&result, instance_id, phase)) {
// Can not bypass initialization of the instance
// we are looking for.
break;
}
// Otherwise skip it (the call updated 'result' value).
} else if (result->is_MergeMem()) {
- result = step_through_mergemem(phase, result->as_MergeMem(), t_adr, NULL, tty);
+ result = step_through_mergemem(phase, result->as_MergeMem(), t_oop, NULL, tty);
}
}
return result;
}
-Node *MemNode::optimize_memory_chain(Node *mchain, const TypePtr *t_adr, PhaseGVN *phase) {
- const TypeOopPtr *t_oop = t_adr->isa_oopptr();
- bool is_instance = (t_oop != NULL) && t_oop->is_known_instance_field();
+Node *MemNode::optimize_memory_chain(Node *mchain, const TypePtr *t_adr, Node *load, PhaseGVN *phase) {
+ const TypeOopPtr* t_oop = t_adr->isa_oopptr();
+ if (t_oop == NULL)
+ return mchain; // don't try to optimize non-oop types
+ Node* result = optimize_simple_memory_chain(mchain, t_oop, load, phase);
+ bool is_instance = t_oop->is_known_instance_field();
PhaseIterGVN *igvn = phase->is_IterGVN();
- Node *result = mchain;
- result = optimize_simple_memory_chain(result, t_adr, phase);
if (is_instance && igvn != NULL && result->is_Phi()) {
PhiNode *mphi = result->as_Phi();
assert(mphi->bottom_type() == Type::MEMORY, "memory phi required");
@@ -383,7 +397,7 @@
// Or Region for the check in LoadNode::Ideal();
// 'sub' should have sub->in(0) != NULL.
assert(sub->is_Allocate() || sub->is_Initialize() || sub->is_Start() ||
- sub->is_Region(), "expecting only these nodes");
+ sub->is_Region() || sub->is_Call(), "expecting only these nodes");
// Get control edge of 'sub'.
Node* orig_sub = sub;
@@ -957,11 +971,14 @@
// of aliasing.
Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const {
Node* ld_adr = in(MemNode::Address);
-
+ intptr_t ld_off = 0;
+ AllocateNode* ld_alloc = AllocateNode::Ideal_allocation(ld_adr, phase, ld_off);
const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr();
- Compile::AliasType* atp = tp != NULL ? phase->C->alias_type(tp) : NULL;
- if (EliminateAutoBox && atp != NULL && atp->index() >= Compile::AliasIdxRaw &&
- atp->field() != NULL && !atp->field()->is_volatile()) {
+ Compile::AliasType* atp = (tp != NULL) ? phase->C->alias_type(tp) : NULL;
+ // This is more general than load from boxing objects.
+ if (phase->C->eliminate_boxing() && (atp != NULL) &&
+ (atp->index() >= Compile::AliasIdxRaw) &&
+ (atp->field() != NULL) && !atp->field()->is_volatile()) {
uint alias_idx = atp->index();
bool final = atp->field()->is_final();
Node* result = NULL;
@@ -983,7 +1000,7 @@
Node* new_st = merge->memory_at(alias_idx);
if (new_st == merge->base_memory()) {
// Keep searching
- current = merge->base_memory();
+ current = new_st;
continue;
}
// Save the new memory state for the slice and fall through
@@ -1010,9 +1027,7 @@
intptr_t st_off = 0;
AllocateNode* alloc = AllocateNode::Ideal_allocation(st_adr, phase, st_off);
if (alloc == NULL) return NULL;
- intptr_t ld_off = 0;
- AllocateNode* allo2 = AllocateNode::Ideal_allocation(ld_adr, phase, ld_off);
- if (alloc != allo2) return NULL;
+ if (alloc != ld_alloc) return NULL;
if (ld_off != st_off) return NULL;
// At this point we have proven something like this setup:
// A = Allocate(...)
@@ -1029,14 +1044,12 @@
return st->in(MemNode::ValueIn);
}
- intptr_t offset = 0; // scratch
-
// A load from a freshly-created object always returns zero.
// (This can happen after LoadNode::Ideal resets the load's memory input
// to find_captured_store, which returned InitializeNode::zero_memory.)
if (st->is_Proj() && st->in(0)->is_Allocate() &&
- st->in(0) == AllocateNode::Ideal_allocation(ld_adr, phase, offset) &&
- offset >= st->in(0)->as_Allocate()->minimum_header_size()) {
+ (st->in(0) == ld_alloc) &&
+ (ld_off >= st->in(0)->as_Allocate()->minimum_header_size())) {
// return a zero value for the load's basic type
// (This is one of the few places where a generic PhaseTransform
// can create new nodes. Think of it as lazily manifesting
@@ -1048,15 +1061,27 @@
if (st->is_Proj() && st->in(0)->is_Initialize()) {
InitializeNode* init = st->in(0)->as_Initialize();
AllocateNode* alloc = init->allocation();
- if (alloc != NULL &&
- alloc == AllocateNode::Ideal_allocation(ld_adr, phase, offset)) {
+ if ((alloc != NULL) && (alloc == ld_alloc)) {
// examine a captured store value
- st = init->find_captured_store(offset, memory_size(), phase);
+ st = init->find_captured_store(ld_off, memory_size(), phase);
if (st != NULL)
continue; // take one more trip around
}
}
+ // Load boxed value from result of valueOf() call is input parameter.
+ if (this->is_Load() && ld_adr->is_AddP() &&
+ (tp != NULL) && tp->is_ptr_to_boxed_value()) {
+ intptr_t ignore = 0;
+ Node* base = AddPNode::Ideal_base_and_offset(ld_adr, phase, ignore);
+ if (base != NULL && base->is_Proj() &&
+ base->as_Proj()->_con == TypeFunc::Parms &&
+ base->in(0)->is_CallStaticJava() &&
+ base->in(0)->as_CallStaticJava()->is_boxing_method()) {
+ return base->in(0)->in(TypeFunc::Parms);
+ }
+ }
+
break;
}
@@ -1065,11 +1090,13 @@
//----------------------is_instance_field_load_with_local_phi------------------
bool LoadNode::is_instance_field_load_with_local_phi(Node* ctrl) {
- if( in(MemNode::Memory)->is_Phi() && in(MemNode::Memory)->in(0) == ctrl &&
- in(MemNode::Address)->is_AddP() ) {
- const TypeOopPtr* t_oop = in(MemNode::Address)->bottom_type()->isa_oopptr();
- // Only instances.
- if( t_oop != NULL && t_oop->is_known_instance_field() &&
+ if( in(Memory)->is_Phi() && in(Memory)->in(0) == ctrl &&
+ in(Address)->is_AddP() ) {
+ const TypeOopPtr* t_oop = in(Address)->bottom_type()->isa_oopptr();
+ // Only instances and boxed values.
+ if( t_oop != NULL &&
+ (t_oop->is_ptr_to_boxed_value() ||
+ t_oop->is_known_instance_field()) &&
t_oop->offset() != Type::OffsetBot &&
t_oop->offset() != Type::OffsetTop) {
return true;
@@ -1083,7 +1110,7 @@
Node *LoadNode::Identity( PhaseTransform *phase ) {
// If the previous store-maker is the right kind of Store, and the store is
// to the same address, then we are equal to the value stored.
- Node* mem = in(MemNode::Memory);
+ Node* mem = in(Memory);
Node* value = can_see_stored_value(mem, phase);
if( value ) {
// byte, short & char stores truncate naturally.
@@ -1105,15 +1132,22 @@
// instance's field to avoid infinite generation of phis in a loop.
Node *region = mem->in(0);
if (is_instance_field_load_with_local_phi(region)) {
- const TypePtr *addr_t = in(MemNode::Address)->bottom_type()->isa_ptr();
+ const TypeOopPtr *addr_t = in(Address)->bottom_type()->isa_oopptr();
int this_index = phase->C->get_alias_index(addr_t);
int this_offset = addr_t->offset();
- int this_id = addr_t->is_oopptr()->instance_id();
+ int this_iid = addr_t->instance_id();
+ if (!addr_t->is_known_instance() &&
+ addr_t->is_ptr_to_boxed_value()) {
+ // Use _idx of address base (could be Phi node) for boxed values.
+ intptr_t ignore = 0;
+ Node* base = AddPNode::Ideal_base_and_offset(in(Address), phase, ignore);
+ this_iid = base->_idx;
+ }
const Type* this_type = bottom_type();
for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) {
Node* phi = region->fast_out(i);
if (phi->is_Phi() && phi != mem &&
- phi->as_Phi()->is_same_inst_field(this_type, this_id, this_index, this_offset)) {
+ phi->as_Phi()->is_same_inst_field(this_type, this_iid, this_index, this_offset)) {
return phi;
}
}
@@ -1122,170 +1156,106 @@
return this;
}
-
-// Returns true if the AliasType refers to the field that holds the
-// cached box array. Currently only handles the IntegerCache case.
-static bool is_autobox_cache(Compile::AliasType* atp) {
- if (atp != NULL && atp->field() != NULL) {
- ciField* field = atp->field();
- ciSymbol* klass = field->holder()->name();
- if (field->name() == ciSymbol::cache_field_name() &&
- field->holder()->uses_default_loader() &&
- klass == ciSymbol::java_lang_Integer_IntegerCache()) {
- return true;
- }
- }
- return false;
-}
-
-// Fetch the base value in the autobox array
-static bool fetch_autobox_base(Compile::AliasType* atp, int& cache_offset) {
- if (atp != NULL && atp->field() != NULL) {
- ciField* field = atp->field();
- ciSymbol* klass = field->holder()->name();
- if (field->name() == ciSymbol::cache_field_name() &&
- field->holder()->uses_default_loader() &&
- klass == ciSymbol::java_lang_Integer_IntegerCache()) {
- assert(field->is_constant(), "what?");
- ciObjArray* array = field->constant_value().as_object()->as_obj_array();
- // Fetch the box object at the base of the array and get its value
- ciInstance* box = array->obj_at(0)->as_instance();
- ciInstanceKlass* ik = box->klass()->as_instance_klass();
- if (ik->nof_nonstatic_fields() == 1) {
- // This should be true nonstatic_field_at requires calling
- // nof_nonstatic_fields so check it anyway
- ciConstant c = box->field_value(ik->nonstatic_field_at(0));
- cache_offset = c.as_int();
- }
- return true;
- }
- }
- return false;
-}
-
-// Returns true if the AliasType refers to the value field of an
-// autobox object. Currently only handles Integer.
-static bool is_autobox_object(Compile::AliasType* atp) {
- if (atp != NULL && atp->field() != NULL) {
- ciField* field = atp->field();
- ciSymbol* klass = field->holder()->name();
- if (field->name() == ciSymbol::value_name() &&
- field->holder()->uses_default_loader() &&
- klass == ciSymbol::java_lang_Integer()) {
- return true;
- }
- }
- return false;
-}
-
-
// We're loading from an object which has autobox behaviour.
// If this object is result of a valueOf call we'll have a phi
// merging a newly allocated object and a load from the cache.
// We want to replace this load with the original incoming
// argument to the valueOf call.
Node* LoadNode::eliminate_autobox(PhaseGVN* phase) {
- Node* base = in(Address)->in(AddPNode::Base);
- if (base->is_Phi() && base->req() == 3) {
- AllocateNode* allocation = NULL;
- int allocation_index = -1;
- int load_index = -1;
- for (uint i = 1; i < base->req(); i++) {
- allocation = AllocateNode::Ideal_allocation(base->in(i), phase);
- if (allocation != NULL) {
- allocation_index = i;
- load_index = 3 - allocation_index;
- break;
- }
- }
- bool has_load = ( allocation != NULL &&
- (base->in(load_index)->is_Load() ||
- base->in(load_index)->is_DecodeN() &&
- base->in(load_index)->in(1)->is_Load()) );
- if (has_load && in(Memory)->is_Phi() && in(Memory)->in(0) == base->in(0)) {
- // Push the loads from the phi that comes from valueOf up
- // through it to allow elimination of the loads and the recovery
- // of the original value.
- Node* mem_phi = in(Memory);
- Node* offset = in(Address)->in(AddPNode::Offset);
- Node* region = base->in(0);
-
- Node* in1 = clone();
- Node* in1_addr = in1->in(Address)->clone();
- in1_addr->set_req(AddPNode::Base, base->in(allocation_index));
- in1_addr->set_req(AddPNode::Address, base->in(allocation_index));
- in1_addr->set_req(AddPNode::Offset, offset);
- in1->set_req(0, region->in(allocation_index));
- in1->set_req(Address, in1_addr);
- in1->set_req(Memory, mem_phi->in(allocation_index));
-
- Node* in2 = clone();
- Node* in2_addr = in2->in(Address)->clone();
- in2_addr->set_req(AddPNode::Base, base->in(load_index));
- in2_addr->set_req(AddPNode::Address, base->in(load_index));
- in2_addr->set_req(AddPNode::Offset, offset);
- in2->set_req(0, region->in(load_index));
- in2->set_req(Address, in2_addr);
- in2->set_req(Memory, mem_phi->in(load_index));
-
- in1_addr = phase->transform(in1_addr);
- in1 = phase->transform(in1);
- in2_addr = phase->transform(in2_addr);
- in2 = phase->transform(in2);
-
- PhiNode* result = PhiNode::make_blank(region, this);
- result->set_req(allocation_index, in1);
- result->set_req(load_index, in2);
- return result;
- }
+ assert(phase->C->eliminate_boxing(), "sanity");
+ intptr_t ignore = 0;
+ Node* base = AddPNode::Ideal_base_and_offset(in(Address), phase, ignore);
+ if ((base == NULL) || base->is_Phi()) {
+ // Push the loads from the phi that comes from valueOf up
+ // through it to allow elimination of the loads and the recovery
+ // of the original value. It is done in split_through_phi().
+ return NULL;
} else if (base->is_Load() ||
base->is_DecodeN() && base->in(1)->is_Load()) {
- if (base->is_DecodeN()) {
- // Get LoadN node which loads cached Integer object
- base = base->in(1);
- }
- // Eliminate the load of Integer.value for integers from the cache
+ // Eliminate the load of boxed value for integer types from the cache
// array by deriving the value from the index into the array.
// Capture the offset of the load and then reverse the computation.
- Node* load_base = base->in(Address)->in(AddPNode::Base);
- if (load_base->is_DecodeN()) {
- // Get LoadN node which loads IntegerCache.cache field
- load_base = load_base->in(1);
+
+ // Get LoadN node which loads a boxing object from 'cache' array.
+ if (base->is_DecodeN()) {
+ base = base->in(1);
+ }
+ if (!base->in(Address)->is_AddP()) {
+ return NULL; // Complex address
}
- if (load_base != NULL) {
- Compile::AliasType* atp = phase->C->alias_type(load_base->adr_type());
- intptr_t cache_offset;
- int shift = -1;
- Node* cache = NULL;
- if (is_autobox_cache(atp)) {
- shift = exact_log2(type2aelembytes(T_OBJECT));
- cache = AddPNode::Ideal_base_and_offset(load_base->in(Address), phase, cache_offset);
- }
- if (cache != NULL && base->in(Address)->is_AddP()) {
+ AddPNode* address = base->in(Address)->as_AddP();
+ Node* cache_base = address->in(AddPNode::Base);
+ if ((cache_base != NULL) && cache_base->is_DecodeN()) {
+ // Get ConP node which is static 'cache' field.
+ cache_base = cache_base->in(1);
+ }
+ if ((cache_base != NULL) && cache_base->is_Con()) {
+ const TypeAryPtr* base_type = cache_base->bottom_type()->isa_aryptr();
+ if ((base_type != NULL) && base_type->is_autobox_cache()) {
Node* elements[4];
- int count = base->in(Address)->as_AddP()->unpack_offsets(elements, ARRAY_SIZE(elements));
- int cache_low;
- if (count > 0 && fetch_autobox_base(atp, cache_low)) {
- int offset = arrayOopDesc::base_offset_in_bytes(memory_type()) - (cache_low << shift);
- // Add up all the offsets making of the address of the load
- Node* result = elements[0];
- for (int i = 1; i < count; i++) {
- result = phase->transform(new (phase->C) AddXNode(result, elements[i]));
+ int shift = exact_log2(type2aelembytes(T_OBJECT));
+ int count = address->unpack_offsets(elements, ARRAY_SIZE(elements));
+ if ((count > 0) && elements[0]->is_Con() &&
+ ((count == 1) ||
+ (count == 2) && elements[1]->Opcode() == Op_LShiftX &&
+ elements[1]->in(2) == phase->intcon(shift))) {
+ ciObjArray* array = base_type->const_oop()->as_obj_array();
+ // Fetch the box object cache[0] at the base of the array and get its value
+ ciInstance* box = array->obj_at(0)->as_instance();
+ ciInstanceKlass* ik = box->klass()->as_instance_klass();
+ assert(ik->is_box_klass(), "sanity");
+ assert(ik->nof_nonstatic_fields() == 1, "change following code");
+ if (ik->nof_nonstatic_fields() == 1) {
+ // This should be true nonstatic_field_at requires calling
+ // nof_nonstatic_fields so check it anyway
+ ciConstant c = box->field_value(ik->nonstatic_field_at(0));
+ BasicType bt = c.basic_type();
+ // Only integer types have boxing cache.
+ assert(bt == T_BOOLEAN || bt == T_CHAR ||
+ bt == T_BYTE || bt == T_SHORT ||
+ bt == T_INT || bt == T_LONG, err_msg_res("wrong type = %s", type2name(bt)));
+ jlong cache_low = (bt == T_LONG) ? c.as_long() : c.as_int();
+ if (cache_low != (int)cache_low) {
+ return NULL; // should not happen since cache is array indexed by value
+ }
+ jlong offset = arrayOopDesc::base_offset_in_bytes(T_OBJECT) - (cache_low << shift);
+ if (offset != (int)offset) {
+ return NULL; // should not happen since cache is array indexed by value
+ }
+ // Add up all the offsets making of the address of the load
+ Node* result = elements[0];
+ for (int i = 1; i < count; i++) {
+ result = phase->transform(new (phase->C) AddXNode(result, elements[i]));
+ }
+ // Remove the constant offset from the address and then
+ result = phase->transform(new (phase->C) AddXNode(result, phase->MakeConX(-(int)offset)));
+ // remove the scaling of the offset to recover the original index.
+ if (result->Opcode() == Op_LShiftX && result->in(2) == phase->intcon(shift)) {
+ // Peel the shift off directly but wrap it in a dummy node
+ // since Ideal can't return existing nodes
+ result = new (phase->C) RShiftXNode(result->in(1), phase->intcon(0));
+ } else if (result->is_Add() && result->in(2)->is_Con() &&
+ result->in(1)->Opcode() == Op_LShiftX &&
+ result->in(1)->in(2) == phase->intcon(shift)) {
+ // We can't do general optimization: ((X<<Z) + Y) >> Z ==> X + (Y>>Z)
+ // but for boxing cache access we know that X<<Z will not overflow
+ // (there is range check) so we do this optimizatrion by hand here.
+ Node* add_con = new (phase->C) RShiftXNode(result->in(2), phase->intcon(shift));
+ result = new (phase->C) AddXNode(result->in(1)->in(1), phase->transform(add_con));
+ } else {
+ result = new (phase->C) RShiftXNode(result, phase->intcon(shift));
+ }
+#ifdef _LP64
+ if (bt != T_LONG) {
+ result = new (phase->C) ConvL2INode(phase->transform(result));
+ }
+#else
+ if (bt == T_LONG) {
+ result = new (phase->C) ConvI2LNode(phase->transform(result));
+ }
+#endif
+ return result;
}
- // Remove the constant offset from the address and then
- // remove the scaling of the offset to recover the original index.
- result = phase->transform(new (phase->C) AddXNode(result, phase->MakeConX(-offset)));
- if (result->Opcode() == Op_LShiftX && result->in(2) == phase->intcon(shift)) {
- // Peel the shift off directly but wrap it in a dummy node
- // since Ideal can't return existing nodes
- result = new (phase->C) RShiftXNode(result->in(1), phase->intcon(0));
- } else {
- result = new (phase->C) RShiftXNode(result, phase->intcon(shift));
- }
-#ifdef _LP64
- result = new (phase->C) ConvL2INode(phase->transform(result));
-#endif
- return result;
}
}
}
@@ -1293,65 +1263,131 @@
return NULL;
}
-//------------------------------split_through_phi------------------------------
-// Split instance field load through Phi.
-Node *LoadNode::split_through_phi(PhaseGVN *phase) {
- Node* mem = in(MemNode::Memory);
- Node* address = in(MemNode::Address);
- const TypePtr *addr_t = phase->type(address)->isa_ptr();
- const TypeOopPtr *t_oop = addr_t->isa_oopptr();
-
- assert(mem->is_Phi() && (t_oop != NULL) &&
- t_oop->is_known_instance_field(), "invalide conditions");
-
- Node *region = mem->in(0);
+static bool stable_phi(PhiNode* phi, PhaseGVN *phase) {
+ Node* region = phi->in(0);
if (region == NULL) {
- return NULL; // Wait stable graph
+ return false; // Wait stable graph
}
- uint cnt = mem->req();
+ uint cnt = phi->req();
for (uint i = 1; i < cnt; i++) {
Node* rc = region->in(i);
if (rc == NULL || phase->type(rc) == Type::TOP)
- return NULL; // Wait stable graph
- Node *in = mem->in(i);
- if (in == NULL) {
+ return false; // Wait stable graph
+ Node* in = phi->in(i);
+ if (in == NULL || phase->type(in) == Type::TOP)
+ return false; // Wait stable graph
+ }
+ return true;
+}
+//------------------------------split_through_phi------------------------------
+// Split instance or boxed field load through Phi.
+Node *LoadNode::split_through_phi(PhaseGVN *phase) {
+ Node* mem = in(Memory);
+ Node* address = in(Address);
+ const TypeOopPtr *t_oop = phase->type(address)->isa_oopptr();
+
+ assert((t_oop != NULL) &&
+ (t_oop->is_known_instance_field() ||
+ t_oop->is_ptr_to_boxed_value()), "invalide conditions");
+
+ Compile* C = phase->C;
+ intptr_t ignore = 0;
+ Node* base = AddPNode::Ideal_base_and_offset(address, phase, ignore);
+ bool base_is_phi = (base != NULL) && base->is_Phi();
+ bool load_boxed_values = t_oop->is_ptr_to_boxed_value() && C->aggressive_unboxing() &&
+ (base != NULL) && (base == address->in(AddPNode::Base)) &&
+ phase->type(base)->higher_equal(TypePtr::NOTNULL);
+
+ if (!((mem->is_Phi() || base_is_phi) &&
+ (load_boxed_values || t_oop->is_known_instance_field()))) {
+ return NULL; // memory is not Phi
+ }
+
+ if (mem->is_Phi()) {
+ if (!stable_phi(mem->as_Phi(), phase)) {
return NULL; // Wait stable graph
}
- }
- // Check for loop invariant.
- if (cnt == 3) {
- for (uint i = 1; i < cnt; i++) {
- Node *in = mem->in(i);
- Node* m = MemNode::optimize_memory_chain(in, addr_t, phase);
- if (m == mem) {
- set_req(MemNode::Memory, mem->in(cnt - i)); // Skip this phi.
- return this;
+ uint cnt = mem->req();
+ // Check for loop invariant memory.
+ if (cnt == 3) {
+ for (uint i = 1; i < cnt; i++) {
+ Node* in = mem->in(i);
+ Node* m = optimize_memory_chain(in, t_oop, this, phase);
+ if (m == mem) {
+ set_req(Memory, mem->in(cnt - i));
+ return this; // made change
+ }
}
}
}
+ if (base_is_phi) {
+ if (!stable_phi(base->as_Phi(), phase)) {
+ return NULL; // Wait stable graph
+ }
+ uint cnt = base->req();
+ // Check for loop invariant memory.
+ if (cnt == 3) {
+ for (uint i = 1; i < cnt; i++) {
+ if (base->in(i) == base) {
+ return NULL; // Wait stable graph
+ }
+ }
+ }
+ }
+
+ bool load_boxed_phi = load_boxed_values && base_is_phi && (base->in(0) == mem->in(0));
+
// Split through Phi (see original code in loopopts.cpp).
- assert(phase->C->have_alias_type(addr_t), "instance should have alias type");
+ assert(C->have_alias_type(t_oop), "instance should have alias type");
// Do nothing here if Identity will find a value
// (to avoid infinite chain of value phis generation).
if (!phase->eqv(this, this->Identity(phase)))
return NULL;
- // Skip the split if the region dominates some control edge of the address.
- if (!MemNode::all_controls_dominate(address, region))
- return NULL;
+ // Select Region to split through.
+ Node* region;
+ if (!base_is_phi) {
+ assert(mem->is_Phi(), "sanity");
+ region = mem->in(0);
+ // Skip if the region dominates some control edge of the address.
+ if (!MemNode::all_controls_dominate(address, region))
+ return NULL;
+ } else if (!mem->is_Phi()) {
+ assert(base_is_phi, "sanity");
+ region = base->in(0);
+ // Skip if the region dominates some control edge of the memory.
+ if (!MemNode::all_controls_dominate(mem, region))
+ return NULL;
+ } else if (base->in(0) != mem->in(0)) {
+ assert(base_is_phi && mem->is_Phi(), "sanity");
+ if (MemNode::all_controls_dominate(mem, base->in(0))) {
+ region = base->in(0);
+ } else if (MemNode::all_controls_dominate(address, mem->in(0))) {
+ region = mem->in(0);
+ } else {
+ return NULL; // complex graph
+ }
+ } else {
+ assert(base->in(0) == mem->in(0), "sanity");
+ region = mem->in(0);
+ }
const Type* this_type = this->bottom_type();
- int this_index = phase->C->get_alias_index(addr_t);
- int this_offset = addr_t->offset();
- int this_iid = addr_t->is_oopptr()->instance_id();
- PhaseIterGVN *igvn = phase->is_IterGVN();
- Node *phi = new (igvn->C) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset);
+ int this_index = C->get_alias_index(t_oop);
+ int this_offset = t_oop->offset();
+ int this_iid = t_oop->instance_id();
+ if (!t_oop->is_known_instance() && load_boxed_values) {
+ // Use _idx of address base for boxed values.
+ this_iid = base->_idx;
+ }
+ PhaseIterGVN* igvn = phase->is_IterGVN();
+ Node* phi = new (C) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset);
for (uint i = 1; i < region->req(); i++) {
- Node *x;
+ Node* x;
Node* the_clone = NULL;
- if (region->in(i) == phase->C->top()) {
- x = phase->C->top(); // Dead path? Use a dead data op
+ if (region->in(i) == C->top()) {
+ x = C->top(); // Dead path? Use a dead data op
} else {
x = this->clone(); // Else clone up the data op
the_clone = x; // Remember for possible deletion.
@@ -1361,10 +1397,16 @@
} else {
x->set_req(0, NULL);
}
- for (uint j = 1; j < this->req(); j++) {
- Node *in = this->in(j);
- if (in->is_Phi() && in->in(0) == region)
- x->set_req(j, in->in(i)); // Use pre-Phi input for the clone
+ if (mem->is_Phi() && (mem->in(0) == region)) {
+ x->set_req(Memory, mem->in(i)); // Use pre-Phi input for the clone.
+ }
+ if (address->is_Phi() && address->in(0) == region) {
+ x->set_req(Address, address->in(i)); // Use pre-Phi input for the clone
+ }
+ if (base_is_phi && (base->in(0) == region)) {
+ Node* base_x = base->in(i); // Clone address for loads from boxed objects.
+ Node* adr_x = phase->transform(new (C) AddPNode(base_x,base_x,address->in(AddPNode::Offset)));
+ x->set_req(Address, adr_x);
}
}
// Check for a 'win' on some paths
@@ -1394,7 +1436,7 @@
if (y != x) {
x = y;
} else {
- y = igvn->hash_find(x);
+ y = igvn->hash_find_insert(x);
if (y) {
x = y;
} else {
@@ -1405,8 +1447,9 @@
}
}
}
- if (x != the_clone && the_clone != NULL)
+ if (x != the_clone && the_clone != NULL) {
igvn->remove_dead_node(the_clone);
+ }
phi->set_req(i, x);
}
// Record Phi
@@ -1445,31 +1488,23 @@
// A method-invariant, non-null address (constant or 'this' argument).
set_req(MemNode::Control, NULL);
}
-
- if (EliminateAutoBox && can_reshape) {
- assert(!phase->type(base)->higher_equal(TypePtr::NULL_PTR), "the autobox pointer should be non-null");
- Compile::AliasType* atp = phase->C->alias_type(adr_type());
- if (is_autobox_object(atp)) {
- Node* result = eliminate_autobox(phase);
- if (result != NULL) return result;
- }
- }
}
Node* mem = in(MemNode::Memory);
const TypePtr *addr_t = phase->type(address)->isa_ptr();
- if (addr_t != NULL) {
+ if (can_reshape && (addr_t != NULL)) {
// try to optimize our memory input
- Node* opt_mem = MemNode::optimize_memory_chain(mem, addr_t, phase);
+ Node* opt_mem = MemNode::optimize_memory_chain(mem, addr_t, this, phase);
if (opt_mem != mem) {
set_req(MemNode::Memory, opt_mem);
if (phase->type( opt_mem ) == Type::TOP) return NULL;
return this;
}
const TypeOopPtr *t_oop = addr_t->isa_oopptr();
- if (can_reshape && opt_mem->is_Phi() &&
- (t_oop != NULL) && t_oop->is_known_instance_field()) {
+ if ((t_oop != NULL) &&
+ (t_oop->is_known_instance_field() ||
+ t_oop->is_ptr_to_boxed_value())) {
PhaseIterGVN *igvn = phase->is_IterGVN();
if (igvn != NULL && igvn->_worklist.member(opt_mem)) {
// Delay this transformation until memory Phi is processed.
@@ -1479,6 +1514,11 @@
// Split instance field load through Phi.
Node* result = split_through_phi(phase);
if (result != NULL) return result;
+
+ if (t_oop->is_ptr_to_boxed_value()) {
+ Node* result = eliminate_autobox(phase);
+ if (result != NULL) return result;
+ }
}
}
@@ -1587,18 +1627,23 @@
// This can happen if a interface-typed array narrows to a class type.
jt = _type;
}
-
- if (EliminateAutoBox && adr->is_AddP()) {
+#ifdef ASSERT
+ if (phase->C->eliminate_boxing() && adr->is_AddP()) {
// The pointers in the autobox arrays are always non-null
Node* base = adr->in(AddPNode::Base);
- if (base != NULL &&
- !phase->type(base)->higher_equal(TypePtr::NULL_PTR)) {
- Compile::AliasType* atp = C->alias_type(base->adr_type());
- if (is_autobox_cache(atp)) {
- return jt->join(TypePtr::NOTNULL)->is_ptr();
+ if ((base != NULL) && base->is_DecodeN()) {
+ // Get LoadN node which loads IntegerCache.cache field
+ base = base->in(1);
+ }
+ if ((base != NULL) && base->is_Con()) {
+ const TypeAryPtr* base_type = base->bottom_type()->isa_aryptr();
+ if ((base_type != NULL) && base_type->is_autobox_cache()) {
+ // It could be narrow oop
+ assert(jt->make_ptr()->ptr() == TypePtr::NotNull,"sanity");
}
}
}
+#endif
return jt;
}
}
@@ -1638,6 +1683,10 @@
// Optimizations for constant objects
ciObject* const_oop = tinst->const_oop();
if (const_oop != NULL) {
+ // For constant Boxed value treat the target field as a compile time constant.
+ if (tinst->is_ptr_to_boxed_value()) {
+ return tinst->get_const_boxed_value();
+ } else
// For constant CallSites treat the target field as a compile time constant.
if (const_oop->is_call_site()) {
ciCallSite* call_site = const_oop->as_call_site();
@@ -1759,7 +1808,8 @@
// (Also allow a variable load from a fresh array to produce zero.)
const TypeOopPtr *tinst = tp->isa_oopptr();
bool is_instance = (tinst != NULL) && tinst->is_known_instance_field();
- if (ReduceFieldZeroing || is_instance) {
+ bool is_boxed_value = (tinst != NULL) && tinst->is_ptr_to_boxed_value();
+ if (ReduceFieldZeroing || is_instance || is_boxed_value) {
Node* value = can_see_stored_value(mem,phase);
if (value != NULL && value->is_Con()) {
assert(value->bottom_type()->higher_equal(_type),"sanity");
@@ -2883,24 +2933,38 @@
if (in(0) && in(0)->is_top()) return NULL;
// Eliminate volatile MemBars for scalar replaced objects.
- if (can_reshape && req() == (Precedent+1) &&
- (Opcode() == Op_MemBarAcquire || Opcode() == Op_MemBarVolatile)) {
- // Volatile field loads and stores.
- Node* my_mem = in(MemBarNode::Precedent);
- if (my_mem != NULL && my_mem->is_Mem()) {
- const TypeOopPtr* t_oop = my_mem->in(MemNode::Address)->bottom_type()->isa_oopptr();
- // Check for scalar replaced object reference.
- if( t_oop != NULL && t_oop->is_known_instance_field() &&
- t_oop->offset() != Type::OffsetBot &&
- t_oop->offset() != Type::OffsetTop) {
- // Replace MemBar projections by its inputs.
- PhaseIterGVN* igvn = phase->is_IterGVN();
- igvn->replace_node(proj_out(TypeFunc::Memory), in(TypeFunc::Memory));
- igvn->replace_node(proj_out(TypeFunc::Control), in(TypeFunc::Control));
- // Must return either the original node (now dead) or a new node
- // (Do not return a top here, since that would break the uniqueness of top.)
- return new (phase->C) ConINode(TypeInt::ZERO);
+ if (can_reshape && req() == (Precedent+1)) {
+ bool eliminate = false;
+ int opc = Opcode();
+ if ((opc == Op_MemBarAcquire || opc == Op_MemBarVolatile)) {
+ // Volatile field loads and stores.
+ Node* my_mem = in(MemBarNode::Precedent);
+ if (my_mem != NULL && my_mem->is_Mem()) {
+ const TypeOopPtr* t_oop = my_mem->in(MemNode::Address)->bottom_type()->isa_oopptr();
+ // Check for scalar replaced object reference.
+ if( t_oop != NULL && t_oop->is_known_instance_field() &&
+ t_oop->offset() != Type::OffsetBot &&
+ t_oop->offset() != Type::OffsetTop) {
+ eliminate = true;
+ }
}
+ } else if (opc == Op_MemBarRelease) {
+ // Final field stores.
+ Node* alloc = AllocateNode::Ideal_allocation(in(MemBarNode::Precedent), phase);
+ if ((alloc != NULL) && alloc->is_Allocate() &&
+ alloc->as_Allocate()->_is_non_escaping) {
+ // The allocated object does not escape.
+ eliminate = true;
+ }
+ }
+ if (eliminate) {
+ // Replace MemBar projections by its inputs.
+ PhaseIterGVN* igvn = phase->is_IterGVN();
+ igvn->replace_node(proj_out(TypeFunc::Memory), in(TypeFunc::Memory));
+ igvn->replace_node(proj_out(TypeFunc::Control), in(TypeFunc::Control));
+ // Must return either the original node (now dead) or a new node
+ // (Do not return a top here, since that would break the uniqueness of top.)
+ return new (phase->C) ConINode(TypeInt::ZERO);
}
}
return NULL;
@@ -3113,9 +3177,7 @@
// within the initialization without creating a vicious cycle, such as:
// { Foo p = new Foo(); p.next = p; }
// True for constants and parameters and small combinations thereof.
-bool InitializeNode::detect_init_independence(Node* n,
- bool st_is_pinned,
- int& count) {
+bool InitializeNode::detect_init_independence(Node* n, int& count) {
if (n == NULL) return true; // (can this really happen?)
if (n->is_Proj()) n = n->in(0);
if (n == this) return false; // found a cycle
@@ -3135,7 +3197,6 @@
// a store is never pinned *before* the availability of its inputs.
if (!MemNode::all_controls_dominate(n, this))
return false; // failed to prove a good control
-
}
// Check data edges for possible dependencies on 'this'.
@@ -3145,7 +3206,7 @@
if (m == NULL || m == n || m->is_top()) continue;
uint first_i = n->find_edge(m);
if (i != first_i) continue; // process duplicate edge just once
- if (!detect_init_independence(m, st_is_pinned, count)) {
+ if (!detect_init_independence(m, count)) {
return false;
}
}
@@ -3176,7 +3237,7 @@
return FAIL; // wrong allocation! (store needs to float up)
Node* val = st->in(MemNode::ValueIn);
int complexity_count = 0;
- if (!detect_init_independence(val, true, complexity_count))
+ if (!detect_init_independence(val, complexity_count))
return FAIL; // stored value must be 'simple enough'
// The Store can be captured only if nothing after the allocation
--- a/hotspot/src/share/vm/opto/memnode.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/memnode.hpp Wed May 08 15:08:01 2013 -0700
@@ -75,8 +75,8 @@
PhaseTransform* phase);
static bool adr_phi_is_loop_invariant(Node* adr_phi, Node* cast);
- static Node *optimize_simple_memory_chain(Node *mchain, const TypePtr *t_adr, PhaseGVN *phase);
- static Node *optimize_memory_chain(Node *mchain, const TypePtr *t_adr, PhaseGVN *phase);
+ static Node *optimize_simple_memory_chain(Node *mchain, const TypeOopPtr *t_oop, Node *load, PhaseGVN *phase);
+ static Node *optimize_memory_chain(Node *mchain, const TypePtr *t_adr, Node *load, PhaseGVN *phase);
// This one should probably be a phase-specific function:
static bool all_controls_dominate(Node* dom, Node* sub);
@@ -1099,7 +1099,7 @@
Node* make_raw_address(intptr_t offset, PhaseTransform* phase);
- bool detect_init_independence(Node* n, bool st_is_pinned, int& count);
+ bool detect_init_independence(Node* n, int& count);
void coalesce_subword_stores(intptr_t header_size, Node* size_in_bytes,
PhaseGVN* phase);
--- a/hotspot/src/share/vm/opto/multnode.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/multnode.cpp Wed May 08 15:08:01 2013 -0700
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "opto/callnode.hpp"
#include "opto/matcher.hpp"
#include "opto/multnode.hpp"
#include "opto/opcodes.hpp"
@@ -73,13 +74,26 @@
return (_con == TypeFunc::Control && def->is_CFG());
}
+const Type* ProjNode::proj_type(const Type* t) const {
+ if (t == Type::TOP) {
+ return Type::TOP;
+ }
+ if (t == Type::BOTTOM) {
+ return Type::BOTTOM;
+ }
+ t = t->is_tuple()->field_at(_con);
+ Node* n = in(0);
+ if ((_con == TypeFunc::Parms) &&
+ n->is_CallStaticJava() && n->as_CallStaticJava()->is_boxing_method()) {
+ // The result of autoboxing is always non-null on normal path.
+ t = t->join(TypePtr::NOTNULL);
+ }
+ return t;
+}
+
const Type *ProjNode::bottom_type() const {
- if (in(0) == NULL) return Type::TOP;
- const Type *tb = in(0)->bottom_type();
- if( tb == Type::TOP ) return Type::TOP;
- if( tb == Type::BOTTOM ) return Type::BOTTOM;
- const TypeTuple *t = tb->is_tuple();
- return t->field_at(_con);
+ if (in(0) == NULL) return Type::TOP;
+ return proj_type(in(0)->bottom_type());
}
const TypePtr *ProjNode::adr_type() const {
@@ -115,11 +129,8 @@
//------------------------------Value------------------------------------------
const Type *ProjNode::Value( PhaseTransform *phase ) const {
- if( !in(0) ) return Type::TOP;
- const Type *t = phase->type(in(0));
- if( t == Type::TOP ) return t;
- if( t == Type::BOTTOM ) return t;
- return t->is_tuple()->field_at(_con);
+ if (in(0) == NULL) return Type::TOP;
+ return proj_type(phase->type(in(0)));
}
//------------------------------out_RegMask------------------------------------
--- a/hotspot/src/share/vm/opto/multnode.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/multnode.hpp Wed May 08 15:08:01 2013 -0700
@@ -60,6 +60,7 @@
virtual uint cmp( const Node &n ) const;
virtual uint size_of() const;
void check_con() const; // Called from constructor.
+ const Type* proj_type(const Type* t) const;
public:
ProjNode( Node *src, uint con, bool io_use = false )
@@ -83,6 +84,7 @@
virtual const Type *Value( PhaseTransform *phase ) const;
virtual uint ideal_reg() const;
virtual const RegMask &out_RegMask() const;
+
#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
#endif
--- a/hotspot/src/share/vm/opto/node.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/node.cpp Wed May 08 15:08:01 2013 -0700
@@ -67,7 +67,8 @@
}
Compile::set_debug_idx(new_debug_idx);
set_debug_idx( new_debug_idx );
- assert(Compile::current()->unique() < (UINT_MAX - 1), "Node limit exceeded UINT_MAX");
+ assert(Compile::current()->unique() < (INT_MAX - 1), "Node limit exceeded INT_MAX");
+ assert(Compile::current()->live_nodes() < (uint)MaxNodeLimit, "Live Node limit exceeded limit");
if (BreakAtNode != 0 && (_debug_idx == BreakAtNode || (int)_idx == BreakAtNode)) {
tty->print_cr("BreakAtNode: _idx=%d _debug_idx=%d", _idx, _debug_idx);
BREAKPOINT;
@@ -471,9 +472,9 @@
//------------------------------clone------------------------------------------
// Clone a Node.
Node *Node::clone() const {
- Compile *compile = Compile::current();
+ Compile* C = Compile::current();
uint s = size_of(); // Size of inherited Node
- Node *n = (Node*)compile->node_arena()->Amalloc_D(size_of() + _max*sizeof(Node*));
+ Node *n = (Node*)C->node_arena()->Amalloc_D(size_of() + _max*sizeof(Node*));
Copy::conjoint_words_to_lower((HeapWord*)this, (HeapWord*)n, s);
// Set the new input pointer array
n->_in = (Node**)(((char*)n)+s);
@@ -492,18 +493,18 @@
if (x != NULL) x->add_out(n);
}
if (is_macro())
- compile->add_macro_node(n);
+ C->add_macro_node(n);
if (is_expensive())
- compile->add_expensive_node(n);
+ C->add_expensive_node(n);
- n->set_idx(compile->next_unique()); // Get new unique index as well
+ n->set_idx(C->next_unique()); // Get new unique index as well
debug_only( n->verify_construction() );
NOT_PRODUCT(nodes_created++);
// Do not patch over the debug_idx of a clone, because it makes it
// impossible to break on the clone's moment of creation.
//debug_only( n->set_debug_idx( debug_idx() ) );
- compile->copy_node_notes_to(n, (Node*) this);
+ C->copy_node_notes_to(n, (Node*) this);
// MachNode clone
uint nopnds;
@@ -518,13 +519,12 @@
(const void*)(&mthis->_opnds), 1));
mach->_opnds = to;
for ( uint i = 0; i < nopnds; ++i ) {
- to[i] = from[i]->clone(compile);
+ to[i] = from[i]->clone(C);
}
}
// cloning CallNode may need to clone JVMState
if (n->is_Call()) {
- CallNode *call = n->as_Call();
- call->clone_jvms();
+ n->as_Call()->clone_jvms(C);
}
return n; // Return the clone
}
@@ -811,6 +811,21 @@
return nrep;
}
+/**
+ * Replace input edges in the range pointing to 'old' node.
+ */
+int Node::replace_edges_in_range(Node* old, Node* neww, int start, int end) {
+ if (old == neww) return 0; // nothing to do
+ uint nrep = 0;
+ for (int i = start; i < end; i++) {
+ if (in(i) == old) {
+ set_req(i, neww);
+ nrep++;
+ }
+ }
+ return nrep;
+}
+
//-------------------------disconnect_inputs-----------------------------------
// NULL out all inputs to eliminate incoming Def-Use edges.
// Return the number of edges between 'n' and 'this'
--- a/hotspot/src/share/vm/opto/node.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/node.hpp Wed May 08 15:08:01 2013 -0700
@@ -410,6 +410,7 @@
// Find first occurrence of n among my edges:
int find_edge(Node* n);
int replace_edge(Node* old, Node* neww);
+ int replace_edges_in_range(Node* old, Node* neww, int start, int end);
// NULL out all inputs to eliminate incoming Def-Use edges.
// Return the number of edges between 'n' and 'this'
int disconnect_inputs(Node *n, Compile *c);
--- a/hotspot/src/share/vm/opto/parse.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/parse.hpp Wed May 08 15:08:01 2013 -0700
@@ -330,6 +330,7 @@
bool _wrote_final; // Did we write a final field?
bool _count_invocations; // update and test invocation counter
bool _method_data_update; // update method data oop
+ Node* _alloc_with_final; // An allocation node with final field
// Variables which track Java semantics during bytecode parsing:
@@ -370,6 +371,11 @@
void set_wrote_final(bool z) { _wrote_final = z; }
bool count_invocations() const { return _count_invocations; }
bool method_data_update() const { return _method_data_update; }
+ Node* alloc_with_final() const { return _alloc_with_final; }
+ void set_alloc_with_final(Node* n) {
+ assert((_alloc_with_final == NULL) || (_alloc_with_final == n), "different init objects?");
+ _alloc_with_final = n;
+ }
Block* block() const { return _block; }
ciBytecodeStream& iter() { return _iter; }
@@ -512,7 +518,7 @@
// loading from a constant field or the constant pool
// returns false if push failed (non-perm field constants only, not ldcs)
- bool push_constant(ciConstant con, bool require_constant = false);
+ bool push_constant(ciConstant con, bool require_constant = false, bool is_autobox_cache = false);
// implementation of object creation bytecodes
void emit_guard_for_new(ciInstanceKlass* klass);
--- a/hotspot/src/share/vm/opto/parse1.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/parse1.cpp Wed May 08 15:08:01 2013 -0700
@@ -390,6 +390,7 @@
_expected_uses = expected_uses;
_depth = 1 + (caller->has_method() ? caller->depth() : 0);
_wrote_final = false;
+ _alloc_with_final = NULL;
_entry_bci = InvocationEntryBci;
_tf = NULL;
_block = NULL;
@@ -723,6 +724,8 @@
// Note: iophi and memphi are not transformed until do_exits.
Node* iophi = new (C) PhiNode(region, Type::ABIO);
Node* memphi = new (C) PhiNode(region, Type::MEMORY, TypePtr::BOTTOM);
+ gvn().set_type_bottom(iophi);
+ gvn().set_type_bottom(memphi);
_exits.set_i_o(iophi);
_exits.set_all_memory(memphi);
@@ -738,6 +741,7 @@
}
int ret_size = type2size[ret_type->basic_type()];
Node* ret_phi = new (C) PhiNode(region, ret_type);
+ gvn().set_type_bottom(ret_phi);
_exits.ensure_stack(ret_size);
assert((int)(tf()->range()->cnt() - TypeFunc::Parms) == ret_size, "good tf range");
assert(method()->return_type()->size() == ret_size, "tf agrees w/ method");
@@ -917,7 +921,7 @@
// such unusual early publications. But no barrier is needed on
// exceptional returns, since they cannot publish normally.
//
- _exits.insert_mem_bar(Op_MemBarRelease);
+ _exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final());
#ifndef PRODUCT
if (PrintOpto && (Verbose || WizardMode)) {
method()->print_name();
--- a/hotspot/src/share/vm/opto/parse2.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/parse2.cpp Wed May 08 15:08:01 2013 -0700
@@ -987,7 +987,7 @@
uncommon_trap(Deoptimization::Reason_unreached,
Deoptimization::Action_reinterpret,
NULL, "cold");
- if (EliminateAutoBox) {
+ if (C->eliminate_boxing()) {
// Mark the successor blocks as parsed
branch_block->next_path_num();
next_block->next_path_num();
@@ -1012,7 +1012,7 @@
if (stopped()) { // Path is dead?
explicit_null_checks_elided++;
- if (EliminateAutoBox) {
+ if (C->eliminate_boxing()) {
// Mark the successor block as parsed
branch_block->next_path_num();
}
@@ -1032,7 +1032,7 @@
if (stopped()) { // Path is dead?
explicit_null_checks_elided++;
- if (EliminateAutoBox) {
+ if (C->eliminate_boxing()) {
// Mark the successor block as parsed
next_block->next_path_num();
}
@@ -1069,7 +1069,7 @@
uncommon_trap(Deoptimization::Reason_unreached,
Deoptimization::Action_reinterpret,
NULL, "cold");
- if (EliminateAutoBox) {
+ if (C->eliminate_boxing()) {
// Mark the successor blocks as parsed
branch_block->next_path_num();
next_block->next_path_num();
@@ -1135,7 +1135,7 @@
set_control(taken_branch);
if (stopped()) {
- if (EliminateAutoBox) {
+ if (C->eliminate_boxing()) {
// Mark the successor block as parsed
branch_block->next_path_num();
}
@@ -1154,7 +1154,7 @@
// Branch not taken.
if (stopped()) {
- if (EliminateAutoBox) {
+ if (C->eliminate_boxing()) {
// Mark the successor block as parsed
next_block->next_path_num();
}
--- a/hotspot/src/share/vm/opto/parse3.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/parse3.cpp Wed May 08 15:08:01 2013 -0700
@@ -150,6 +150,23 @@
// final field
if (field->is_static()) {
// final static field
+ if (C->eliminate_boxing()) {
+ // The pointers in the autobox arrays are always non-null.
+ ciSymbol* klass_name = field->holder()->name();
+ if (field->name() == ciSymbol::cache_field_name() &&
+ field->holder()->uses_default_loader() &&
+ (klass_name == ciSymbol::java_lang_Character_CharacterCache() ||
+ klass_name == ciSymbol::java_lang_Byte_ByteCache() ||
+ klass_name == ciSymbol::java_lang_Short_ShortCache() ||
+ klass_name == ciSymbol::java_lang_Integer_IntegerCache() ||
+ klass_name == ciSymbol::java_lang_Long_LongCache())) {
+ bool require_const = true;
+ bool autobox_cache = true;
+ if (push_constant(field->constant_value(), require_const, autobox_cache)) {
+ return;
+ }
+ }
+ }
if (push_constant(field->constant_value()))
return;
}
@@ -304,11 +321,18 @@
// out of the constructor.
if (is_field && field->is_final()) {
set_wrote_final(true);
+ // Preserve allocation ptr to create precedent edge to it in membar
+ // generated on exit from constructor.
+ if (C->eliminate_boxing() &&
+ adr_type->isa_oopptr() && adr_type->is_oopptr()->is_ptr_to_boxed_value() &&
+ AllocateNode::Ideal_allocation(obj, &_gvn) != NULL) {
+ set_alloc_with_final(obj);
+ }
}
}
-bool Parse::push_constant(ciConstant constant, bool require_constant) {
+bool Parse::push_constant(ciConstant constant, bool require_constant, bool is_autobox_cache) {
switch (constant.basic_type()) {
case T_BOOLEAN: push( intcon(constant.as_boolean()) ); break;
case T_INT: push( intcon(constant.as_int()) ); break;
@@ -329,7 +353,7 @@
push( zerocon(T_OBJECT) );
break;
} else if (require_constant || oop_constant->should_be_constant()) {
- push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant)) );
+ push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant, is_autobox_cache)) );
break;
} else {
// we cannot inline the oop, but we can use it later to narrow a type
--- a/hotspot/src/share/vm/opto/parseHelper.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/parseHelper.cpp Wed May 08 15:08:01 2013 -0700
@@ -284,6 +284,11 @@
klass == C->env()->StringBuffer_klass())) {
C->set_has_stringbuilder(true);
}
+
+ // Keep track of boxed values for EliminateAutoBox optimizations.
+ if (C->eliminate_boxing() && klass->is_box_klass()) {
+ C->set_has_boxed_value(true);
+ }
}
#ifndef PRODUCT
--- a/hotspot/src/share/vm/opto/phase.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/phase.cpp Wed May 08 15:08:01 2013 -0700
@@ -64,6 +64,7 @@
// Subtimers for _t_optimizer
elapsedTimer Phase::_t_iterGVN;
elapsedTimer Phase::_t_iterGVN2;
+elapsedTimer Phase::_t_incrInline;
// Subtimers for _t_registerAllocation
elapsedTimer Phase::_t_ctorChaitin;
@@ -110,6 +111,7 @@
tty->print_cr (" macroEliminate : %3.3f sec", Phase::_t_macroEliminate.seconds());
}
tty->print_cr (" iterGVN : %3.3f sec", Phase::_t_iterGVN.seconds());
+ tty->print_cr (" incrInline : %3.3f sec", Phase::_t_incrInline.seconds());
tty->print_cr (" idealLoop : %3.3f sec", Phase::_t_idealLoop.seconds());
tty->print_cr (" idealLoopVerify: %3.3f sec", Phase::_t_idealLoopVerify.seconds());
tty->print_cr (" ccp : %3.3f sec", Phase::_t_ccp.seconds());
--- a/hotspot/src/share/vm/opto/phase.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/phase.hpp Wed May 08 15:08:01 2013 -0700
@@ -100,6 +100,7 @@
// Subtimers for _t_optimizer
static elapsedTimer _t_iterGVN;
static elapsedTimer _t_iterGVN2;
+ static elapsedTimer _t_incrInline;
// Subtimers for _t_registerAllocation
static elapsedTimer _t_ctorChaitin;
--- a/hotspot/src/share/vm/opto/phaseX.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/phaseX.cpp Wed May 08 15:08:01 2013 -0700
@@ -882,7 +882,7 @@
return;
}
Node *n = _worklist.pop();
- if (++loop_count >= K * C->unique()) {
+ if (++loop_count >= K * C->live_nodes()) {
debug_only(n->dump(4);)
assert(false, "infinite loop in PhaseIterGVN::optimize");
C->record_method_not_compilable("infinite loop in PhaseIterGVN::optimize");
--- a/hotspot/src/share/vm/opto/type.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/type.cpp Wed May 08 15:08:01 2013 -0700
@@ -2372,7 +2372,12 @@
_klass_is_exact(xk),
_is_ptr_to_narrowoop(false),
_is_ptr_to_narrowklass(false),
+ _is_ptr_to_boxed_value(false),
_instance_id(instance_id) {
+ if (Compile::current()->eliminate_boxing() && (t == InstPtr) &&
+ (offset > 0) && xk && (k != 0) && k->is_instance_klass()) {
+ _is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset);
+ }
#ifdef _LP64
if (_offset != 0) {
if (_offset == oopDesc::klass_offset_in_bytes()) {
@@ -2613,44 +2618,50 @@
//------------------------------make_from_constant-----------------------------
// Make a java pointer from an oop constant
-const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_constant) {
- assert(!o->is_null_object(), "null object not yet handled here.");
- ciKlass* klass = o->klass();
- if (klass->is_instance_klass()) {
- // Element is an instance
- if (require_constant) {
- if (!o->can_be_constant()) return NULL;
- } else if (!o->should_be_constant()) {
- return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, 0);
- }
- return TypeInstPtr::make(o);
- } else if (klass->is_obj_array_klass()) {
- // Element is an object array. Recursively call ourself.
- const Type *etype =
+const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o,
+ bool require_constant,
+ bool is_autobox_cache) {
+ assert(!o->is_null_object(), "null object not yet handled here.");
+ ciKlass* klass = o->klass();
+ if (klass->is_instance_klass()) {
+ // Element is an instance
+ if (require_constant) {
+ if (!o->can_be_constant()) return NULL;
+ } else if (!o->should_be_constant()) {
+ return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, 0);
+ }
+ return TypeInstPtr::make(o);
+ } else if (klass->is_obj_array_klass()) {
+ // Element is an object array. Recursively call ourself.
+ const TypeOopPtr *etype =
TypeOopPtr::make_from_klass_raw(klass->as_obj_array_klass()->element_klass());
- const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
- // We used to pass NotNull in here, asserting that the sub-arrays
- // are all not-null. This is not true in generally, as code can
- // slam NULLs down in the subarrays.
- if (require_constant) {
- if (!o->can_be_constant()) return NULL;
- } else if (!o->should_be_constant()) {
- return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
- }
- const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
+ if (is_autobox_cache) {
+ // The pointers in the autobox arrays are always non-null.
+ etype = etype->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr();
+ }
+ const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
+ // We used to pass NotNull in here, asserting that the sub-arrays
+ // are all not-null. This is not true in generally, as code can
+ // slam NULLs down in the subarrays.
+ if (require_constant) {
+ if (!o->can_be_constant()) return NULL;
+ } else if (!o->should_be_constant()) {
+ return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
+ }
+ const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0, InstanceBot, is_autobox_cache);
return arr;
- } else if (klass->is_type_array_klass()) {
- // Element is an typeArray
+ } else if (klass->is_type_array_klass()) {
+ // Element is an typeArray
const Type* etype =
(Type*)get_const_basic_type(klass->as_type_array_klass()->element_type());
- const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
- // We used to pass NotNull in here, asserting that the array pointer
- // is not-null. That was not true in general.
- if (require_constant) {
- if (!o->can_be_constant()) return NULL;
- } else if (!o->should_be_constant()) {
- return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
- }
+ const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
+ // We used to pass NotNull in here, asserting that the array pointer
+ // is not-null. That was not true in general.
+ if (require_constant) {
+ if (!o->can_be_constant()) return NULL;
+ } else if (!o->should_be_constant()) {
+ return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
+ }
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
return arr;
}
@@ -2856,6 +2867,28 @@
return result;
}
+/**
+ * Create constant type for a constant boxed value
+ */
+const Type* TypeInstPtr::get_const_boxed_value() const {
+ assert(is_ptr_to_boxed_value(), "should be called only for boxed value");
+ assert((const_oop() != NULL), "should be called only for constant object");
+ ciConstant constant = const_oop()->as_instance()->field_value_by_offset(offset());
+ BasicType bt = constant.basic_type();
+ switch (bt) {
+ case T_BOOLEAN: return TypeInt::make(constant.as_boolean());
+ case T_INT: return TypeInt::make(constant.as_int());
+ case T_CHAR: return TypeInt::make(constant.as_char());
+ case T_BYTE: return TypeInt::make(constant.as_byte());
+ case T_SHORT: return TypeInt::make(constant.as_short());
+ case T_FLOAT: return TypeF::make(constant.as_float());
+ case T_DOUBLE: return TypeD::make(constant.as_double());
+ case T_LONG: return TypeLong::make(constant.as_long());
+ default: break;
+ }
+ fatal(err_msg_res("Invalid boxed value type '%s'", type2name(bt)));
+ return NULL;
+}
//------------------------------cast_to_ptr_type-------------------------------
const Type *TypeInstPtr::cast_to_ptr_type(PTR ptr) const {
@@ -3330,18 +3363,18 @@
if (!xk) xk = ary->ary_must_be_exact();
assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
if (!UseExactTypes) xk = (ptr == Constant);
- return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id))->hashcons();
+ return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id, false))->hashcons();
}
//------------------------------make-------------------------------------------
-const TypeAryPtr *TypeAryPtr::make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id ) {
+const TypeAryPtr *TypeAryPtr::make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, bool is_autobox_cache) {
assert(!(k == NULL && ary->_elem->isa_int()),
"integral arrays must be pre-equipped with a class");
assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );
if (!xk) xk = (o != NULL) || ary->ary_must_be_exact();
assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
if (!UseExactTypes) xk = (ptr == Constant);
- return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id))->hashcons();
+ return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id, is_autobox_cache))->hashcons();
}
//------------------------------cast_to_ptr_type-------------------------------
@@ -3397,8 +3430,20 @@
jint max_hi = max_array_length(elem()->basic_type());
//if (index_not_size) --max_hi; // type of a valid array index, FTR
bool chg = false;
- if (lo < min_lo) { lo = min_lo; chg = true; }
- if (hi > max_hi) { hi = max_hi; chg = true; }
+ if (lo < min_lo) {
+ lo = min_lo;
+ if (size->is_con()) {
+ hi = lo;
+ }
+ chg = true;
+ }
+ if (hi > max_hi) {
+ hi = max_hi;
+ if (size->is_con()) {
+ lo = hi;
+ }
+ chg = true;
+ }
// Negative length arrays will produce weird intermediate dead fast-path code
if (lo > hi)
return TypeInt::ZERO;
@@ -3630,7 +3675,7 @@
//------------------------------xdual------------------------------------------
// Dual: compute field-by-field dual
const Type *TypeAryPtr::xdual() const {
- return new TypeAryPtr( dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id() );
+ return new TypeAryPtr( dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id(), is_autobox_cache() );
}
//----------------------interface_vs_oop---------------------------------------
--- a/hotspot/src/share/vm/opto/type.hpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/opto/type.hpp Wed May 08 15:08:01 2013 -0700
@@ -234,6 +234,9 @@
bool is_ptr_to_narrowoop() const;
bool is_ptr_to_narrowklass() const;
+ bool is_ptr_to_boxing_obj() const;
+
+
// Convenience access
float getf() const;
double getd() const;
@@ -794,6 +797,7 @@
bool _klass_is_exact;
bool _is_ptr_to_narrowoop;
bool _is_ptr_to_narrowklass;
+ bool _is_ptr_to_boxed_value;
// If not InstanceTop or InstanceBot, indicates that this is
// a particular instance of this type which is distinct.
@@ -826,7 +830,9 @@
// If the object cannot be rendered as a constant,
// may return a non-singleton type.
// If require_constant, produce a NULL if a singleton is not possible.
- static const TypeOopPtr* make_from_constant(ciObject* o, bool require_constant = false);
+ static const TypeOopPtr* make_from_constant(ciObject* o,
+ bool require_constant = false,
+ bool not_null_elements = false);
// Make a generic (unclassed) pointer to an oop.
static const TypeOopPtr* make(PTR ptr, int offset, int instance_id);
@@ -839,7 +845,7 @@
// compressed oop references.
bool is_ptr_to_narrowoop_nv() const { return _is_ptr_to_narrowoop; }
bool is_ptr_to_narrowklass_nv() const { return _is_ptr_to_narrowklass; }
-
+ bool is_ptr_to_boxed_value() const { return _is_ptr_to_boxed_value; }
bool is_known_instance() const { return _instance_id > 0; }
int instance_id() const { return _instance_id; }
bool is_known_instance_field() const { return is_known_instance() && _offset >= 0; }
@@ -912,6 +918,9 @@
// Make a pointer to an oop.
static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot );
+ /** Create constant type for a constant boxed value */
+ const Type* get_const_boxed_value() const;
+
// If this is a java.lang.Class constant, return the type for it or NULL.
// Pass to Type::get_const_type to turn it to a type, which will usually
// be a TypeInstPtr, but may also be a TypeInt::INT for int.class, etc.
@@ -943,7 +952,12 @@
//------------------------------TypeAryPtr-------------------------------------
// Class of Java array pointers
class TypeAryPtr : public TypeOopPtr {
- TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id ) : TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id), _ary(ary) {
+ TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk,
+ int offset, int instance_id, bool is_autobox_cache )
+ : TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id),
+ _ary(ary),
+ _is_autobox_cache(is_autobox_cache)
+ {
#ifdef ASSERT
if (k != NULL) {
// Verify that specified klass and TypeAryPtr::klass() follow the same rules.
@@ -964,6 +978,7 @@
virtual bool eq( const Type *t ) const;
virtual int hash() const; // Type specific hashing
const TypeAry *_ary; // Array we point into
+ const bool _is_autobox_cache;
ciKlass* compute_klass(DEBUG_ONLY(bool verify = false)) const;
@@ -974,9 +989,11 @@
const Type* elem() const { return _ary->_elem; }
const TypeInt* size() const { return _ary->_size; }
+ bool is_autobox_cache() const { return _is_autobox_cache; }
+
static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot);
// 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, bool is_autobox_cache = false);
// Return a 'ptr' version of this type
virtual const Type *cast_to_ptr_type(PTR ptr) const;
@@ -1504,6 +1521,13 @@
return false;
}
+inline bool Type::is_ptr_to_boxing_obj() const {
+ const TypeInstPtr* tp = isa_instptr();
+ return (tp != NULL) && (tp->offset() == 0) &&
+ tp->klass()->is_instance_klass() &&
+ tp->klass()->as_instance_klass()->is_box_klass();
+}
+
// ===============================================================
// Things that need to be 64-bits in the 64-bit build but
--- a/hotspot/src/share/vm/runtime/arguments.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed May 08 15:08:01 2013 -0700
@@ -1089,6 +1089,10 @@
if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) {
FLAG_SET_DEFAULT(ReservedCodeCacheSize, ReservedCodeCacheSize * 5);
}
+ if (!UseInterpreter) { // -Xcomp
+ Tier3InvokeNotifyFreqLog = 0;
+ Tier4InvocationThreshold = 0;
+ }
}
#if INCLUDE_ALL_GCS
@@ -1661,6 +1665,20 @@
// Aggressive optimization flags -XX:+AggressiveOpts
void Arguments::set_aggressive_opts_flags() {
#ifdef COMPILER2
+ if (AggressiveUnboxing) {
+ if (FLAG_IS_DEFAULT(EliminateAutoBox)) {
+ FLAG_SET_DEFAULT(EliminateAutoBox, true);
+ } else if (!EliminateAutoBox) {
+ // warning("AggressiveUnboxing is disabled because EliminateAutoBox is disabled");
+ AggressiveUnboxing = false;
+ }
+ if (FLAG_IS_DEFAULT(DoEscapeAnalysis)) {
+ FLAG_SET_DEFAULT(DoEscapeAnalysis, true);
+ } else if (!DoEscapeAnalysis) {
+ // warning("AggressiveUnboxing is disabled because DoEscapeAnalysis is disabled");
+ AggressiveUnboxing = false;
+ }
+ }
if (AggressiveOpts || !FLAG_IS_DEFAULT(AutoBoxCacheMax)) {
if (FLAG_IS_DEFAULT(EliminateAutoBox)) {
FLAG_SET_DEFAULT(EliminateAutoBox, true);
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Mon May 06 19:49:23 2013 -0700
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed May 08 15:08:01 2013 -0700
@@ -1057,6 +1057,7 @@
c2_nonstatic_field(Compile, _save_argument_registers, const bool) \
c2_nonstatic_field(Compile, _subsume_loads, const bool) \
c2_nonstatic_field(Compile, _do_escape_analysis, const bool) \
+ c2_nonstatic_field(Compile, _eliminate_boxing, const bool) \
c2_nonstatic_field(Compile, _ilt, InlineTree*) \
\
c2_nonstatic_field(InlineTree, _caller_jvms, JVMState*) \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6934604/TestByteBoxing.java Wed May 08 15:08:01 2013 -0700
@@ -0,0 +1,777 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6934604
+ * @summary enable parts of EliminateAutoBox by default
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox TestByteBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestByteBoxing.dummy -XX:CompileCommand=exclude,TestByteBoxing.foo -XX:CompileCommand=exclude,TestByteBoxing.foob TestByteBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestByteBoxing.dummy -XX:CompileCommand=exclude,TestByteBoxing.foo -XX:CompileCommand=exclude,TestByteBoxing.foob TestByteBoxing
+ *
+ */
+
+public class TestByteBoxing {
+
+ static final Byte ibc = new Byte((byte)1);
+
+ //===============================================
+ // Non-inlined methods to test deoptimization info
+ static void dummy() { }
+ static byte foo(byte i) { return i; }
+ static Byte foob(byte i) { return Byte.valueOf(i); }
+
+
+ static byte simple(byte i) {
+ Byte ib = new Byte(i);
+ return ib;
+ }
+
+ static byte simpleb(byte i) {
+ Byte ib = Byte.valueOf(i);
+ return ib;
+ }
+
+ static byte simplec() {
+ Byte ib = ibc;
+ return ib;
+ }
+
+ static byte simplef(byte i) {
+ Byte ib = foob(i);
+ return ib;
+ }
+
+ static byte simplep(Byte ib) {
+ return ib;
+ }
+
+ static byte simple2(byte i) {
+ Byte ib1 = new Byte(i);
+ Byte ib2 = new Byte((byte)(i+1));
+ return (byte)(ib1 + ib2);
+ }
+
+ static byte simpleb2(byte i) {
+ Byte ib1 = Byte.valueOf(i);
+ Byte ib2 = Byte.valueOf((byte)(i+1));
+ return (byte)(ib1 + ib2);
+ }
+
+ static byte simplem2(byte i) {
+ Byte ib1 = new Byte(i);
+ Byte ib2 = Byte.valueOf((byte)(i+1));
+ return (byte)(ib1 + ib2);
+ }
+
+ static byte simplep2(byte i, Byte ib1) {
+ Byte ib2 = Byte.valueOf((byte)(i+1));
+ return (byte)(ib1 + ib2);
+ }
+
+ static byte simplec2(byte i) {
+ Byte ib1 = ibc;
+ Byte ib2 = Byte.valueOf((byte)(i+1));
+ return (byte)(ib1 + ib2);
+ }
+
+ //===============================================
+ static byte test(byte i) {
+ Byte ib = new Byte(i);
+ if ((i&1) == 0)
+ ib = (byte)(i+1);
+ return ib;
+ }
+
+ static byte testb(byte i) {
+ Byte ib = i;
+ if ((i&1) == 0)
+ ib = (byte)(i+1);
+ return ib;
+ }
+
+ static byte testm(byte i) {
+ Byte ib = i;
+ if ((i&1) == 0)
+ ib = new Byte((byte)(i+1));
+ return ib;
+ }
+
+ static byte testp(byte i, Byte ib) {
+ if ((i&1) == 0)
+ ib = new Byte((byte)(i+1));
+ return ib;
+ }
+
+ static byte testc(byte i) {
+ Byte ib = ibc;
+ if ((i&1) == 0)
+ ib = new Byte((byte)(i+1));
+ return ib;
+ }
+
+ static byte test2(byte i) {
+ Byte ib1 = new Byte(i);
+ Byte ib2 = new Byte((byte)(i+1));
+ if ((i&1) == 0) {
+ ib1 = new Byte((byte)(i+1));
+ ib2 = new Byte((byte)(i+2));
+ }
+ return (byte)(ib1+ib2);
+ }
+
+ static byte testb2(byte i) {
+ Byte ib1 = i;
+ Byte ib2 = (byte)(i+1);
+ if ((i&1) == 0) {
+ ib1 = (byte)(i+1);
+ ib2 = (byte)(i+2);
+ }
+ return (byte)(ib1 + ib2);
+ }
+
+ static byte testm2(byte i) {
+ Byte ib1 = new Byte(i);
+ Byte ib2 = (byte)(i+1);
+ if ((i&1) == 0) {
+ ib1 = new Byte((byte)(i+1));
+ ib2 = (byte)(i+2);
+ }
+ return (byte)(ib1 + ib2);
+ }
+
+ static byte testp2(byte i, Byte ib1) {
+ Byte ib2 = (byte)(i+1);
+ if ((i&1) == 0) {
+ ib1 = new Byte((byte)(i+1));
+ ib2 = (byte)(i+2);
+ }
+ return (byte)(ib1 + ib2);
+ }
+
+ static byte testc2(byte i) {
+ Byte ib1 = ibc;
+ Byte ib2 = (byte)(i+1);
+ if ((i&1) == 0) {
+ ib1 = (byte)(ibc+1);
+ ib2 = (byte)(i+2);
+ }
+ return (byte)(ib1 + ib2);
+ }
+
+ //===============================================
+ static byte sum(byte[] a) {
+ byte result = 1;
+ for (Byte i : a)
+ result += i;
+ return result;
+ }
+
+ static byte sumb(byte[] a) {
+ Byte result = 1;
+ for (Byte i : a)
+ result = (byte)(result + i);
+ return result;
+ }
+
+ static byte sumc(byte[] a) {
+ Byte result = ibc;
+ for (Byte i : a)
+ result = (byte)(result + i);
+ return result;
+ }
+
+ static byte sumf(byte[] a) {
+ Byte result = foob((byte)1);
+ for (Byte i : a)
+ result = (byte)(result + i);
+ return result;
+ }
+
+ static byte sump(byte[] a, Byte result) {
+ for (Byte i : a)
+ result = (byte)(result + i);
+ return result;
+ }
+
+ static byte sum2(byte[] a) {
+ byte result1 = 1;
+ byte result2 = 1;
+ for (Byte i : a) {
+ result1 += i;
+ result2 += i + 1;
+ }
+ return (byte)(result1 + result2);
+ }
+
+ static byte sumb2(byte[] a) {
+ Byte result1 = 1;
+ Byte result2 = 1;
+ for (Byte i : a) {
+ result1 = (byte)(result1 + i);
+ result2 = (byte)(result2 + i + 1);
+ }
+ return (byte)(result1 + result2);
+ }
+
+ static byte summ2(byte[] a) {
+ Byte result1 = 1;
+ Byte result2 = new Byte((byte)1);
+ for (Byte i : a) {
+ result1 = (byte)(result1 + i);
+ result2 = (byte)(result2 + new Byte((byte)(i + 1)));
+ }
+ return (byte)(result1 + result2);
+ }
+
+ static byte sump2(byte[] a, Byte result2) {
+ Byte result1 = 1;
+ for (Byte i : a) {
+ result1 = (byte)(result1 + i);
+ result2 = (byte)(result2 + i + 1);
+ }
+ return (byte)(result1 + result2);
+ }
+
+ static byte sumc2(byte[] a) {
+ Byte result1 = 1;
+ Byte result2 = ibc;
+ for (Byte i : a) {
+ result1 = (byte)(result1 + i);
+ result2 = (byte)(result2 + i + ibc);
+ }
+ return (byte)(result1 + result2);
+ }
+
+ //===============================================
+ static byte remi_sum() {
+ Byte j = new Byte((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ j = new Byte((byte)(j + 1));
+ }
+ return j;
+ }
+
+ static byte remi_sumb() {
+ Byte j = Byte.valueOf((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ j = (byte)(j + 1);
+ }
+ return j;
+ }
+
+ static byte remi_sumf() {
+ Byte j = foob((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ j = (byte)(j + 1);
+ }
+ return j;
+ }
+
+ static byte remi_sump(Byte j) {
+ for (int i = 0; i< 1000; i++) {
+ j = new Byte((byte)(j + 1));
+ }
+ return j;
+ }
+
+ static byte remi_sumc() {
+ Byte j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = (byte)(j + ibc);
+ }
+ return j;
+ }
+
+ static byte remi_sum2() {
+ Byte j1 = new Byte((byte)1);
+ Byte j2 = new Byte((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Byte((byte)(j1 + 1));
+ j2 = new Byte((byte)(j2 + 2));
+ }
+ return (byte)(j1 + j2);
+ }
+
+ static byte remi_sumb2() {
+ Byte j1 = Byte.valueOf((byte)1);
+ Byte j2 = Byte.valueOf((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = (byte)(j1 + 1);
+ j2 = (byte)(j2 + 2);
+ }
+ return (byte)(j1 + j2);
+ }
+
+ static byte remi_summ2() {
+ Byte j1 = new Byte((byte)1);
+ Byte j2 = Byte.valueOf((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Byte((byte)(j1 + 1));
+ j2 = (byte)(j2 + 2);
+ }
+ return (byte)(j1 + j2);
+ }
+
+ static byte remi_sump2(Byte j1) {
+ Byte j2 = Byte.valueOf((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Byte((byte)(j1 + 1));
+ j2 = (byte)(j2 + 2);
+ }
+ return (byte)(j1 + j2);
+ }
+
+ static byte remi_sumc2() {
+ Byte j1 = ibc;
+ Byte j2 = Byte.valueOf((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = (byte)(j1 + ibc);
+ j2 = (byte)(j2 + 2);
+ }
+ return (byte)(j1 + j2);
+ }
+
+
+ //===============================================
+ // Safepointa and debug info for deoptimization
+ static byte simple_deop(byte i) {
+ Byte ib = new Byte(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static byte simpleb_deop(byte i) {
+ Byte ib = Byte.valueOf(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static byte simplef_deop(byte i) {
+ Byte ib = foob(i);
+ dummy();
+ return ib;
+ }
+
+ static byte simplep_deop(Byte ib) {
+ dummy();
+ return ib;
+ }
+
+ static byte simplec_deop(byte i) {
+ Byte ib = ibc;
+ dummy();
+ return ib;
+ }
+
+ static byte test_deop(byte i) {
+ Byte ib = new Byte(foo(i));
+ if ((i&1) == 0)
+ ib = foo((byte)(i+1));
+ dummy();
+ return ib;
+ }
+
+ static byte testb_deop(byte i) {
+ Byte ib = foo(i);
+ if ((i&1) == 0)
+ ib = foo((byte)(i+1));
+ dummy();
+ return ib;
+ }
+
+ static byte testf_deop(byte i) {
+ Byte ib = foob(i);
+ if ((i&1) == 0)
+ ib = foo((byte)(i+1));
+ dummy();
+ return ib;
+ }
+
+ static byte testp_deop(byte i, Byte ib) {
+ if ((i&1) == 0)
+ ib = foo((byte)(i+1));
+ dummy();
+ return ib;
+ }
+
+ static byte testc_deop(byte i) {
+ Byte ib = ibc;
+ if ((i&1) == 0)
+ ib = foo((byte)(i+1));
+ dummy();
+ return ib;
+ }
+
+ static byte sum_deop(byte[] a) {
+ byte result = 1;
+ for (Byte i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static byte sumb_deop(byte[] a) {
+ Byte result = 1;
+ for (Byte i : a)
+ result = (byte)(result + foo(i));
+ dummy();
+ return result;
+ }
+
+ static byte sumf_deop(byte[] a) {
+ Byte result = 1;
+ for (Byte i : a)
+ result = (byte)(result + foob(i));
+ dummy();
+ return result;
+ }
+
+ static byte sump_deop(byte[] a, Byte result) {
+ for (Byte i : a)
+ result = (byte)(result + foob(i));
+ dummy();
+ return result;
+ }
+
+ static byte sumc_deop(byte[] a) {
+ Byte result = ibc;
+ for (Byte i : a)
+ result = (byte)(result + foo(i));
+ dummy();
+ return result;
+ }
+
+ static byte remi_sum_deop() {
+ Byte j = new Byte(foo((byte)1));
+ for (int i = 0; i< 1000; i++) {
+ j = new Byte(foo((byte)(j + 1)));
+ }
+ dummy();
+ return j;
+ }
+
+ static byte remi_sumb_deop() {
+ Byte j = Byte.valueOf(foo((byte)1));
+ for (int i = 0; i< 1000; i++) {
+ j = foo((byte)(j + 1));
+ }
+ dummy();
+ return j;
+ }
+
+ static byte remi_sumf_deop() {
+ Byte j = foob((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ j = foo((byte)(j + 1));
+ }
+ dummy();
+ return j;
+ }
+
+ static byte remi_sump_deop(Byte j) {
+ for (int i = 0; i< 1000; i++) {
+ j = foo((byte)(j + 1));
+ }
+ dummy();
+ return j;
+ }
+
+ static byte remi_sumc_deop() {
+ Byte j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = foo((byte)(j + 1));
+ }
+ dummy();
+ return j;
+ }
+
+ //===============================================
+ // Conditional increment
+ static byte remi_sum_cond() {
+ Byte j = new Byte((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = new Byte((byte)(j + 1));
+ }
+ }
+ return j;
+ }
+
+ static byte remi_sumb_cond() {
+ Byte j = Byte.valueOf((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = (byte)(j + 1);
+ }
+ }
+ return j;
+ }
+
+ static byte remi_sumf_cond() {
+ Byte j = foob((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = (byte)(j + 1);
+ }
+ }
+ return j;
+ }
+
+ static byte remi_sump_cond(Byte j) {
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = (byte)(j + 1);
+ }
+ }
+ return j;
+ }
+
+ static byte remi_sumc_cond() {
+ Byte j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = (byte)(j + ibc);
+ }
+ }
+ return j;
+ }
+
+ static byte remi_sum2_cond() {
+ Byte j1 = new Byte((byte)1);
+ Byte j2 = new Byte((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Byte((byte)(j1 + 1));
+ } else {
+ j2 = new Byte((byte)(j2 + 2));
+ }
+ }
+ return (byte)(j1 + j2);
+ }
+
+ static byte remi_sumb2_cond() {
+ Byte j1 = Byte.valueOf((byte)1);
+ Byte j2 = Byte.valueOf((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = (byte)(j1 + 1);
+ } else {
+ j2 = (byte)(j2 + 2);
+ }
+ }
+ return (byte)(j1 + j2);
+ }
+
+ static byte remi_summ2_cond() {
+ Byte j1 = new Byte((byte)1);
+ Byte j2 = Byte.valueOf((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Byte((byte)(j1 + 1));
+ } else {
+ j2 = (byte)(j2 + 2);
+ }
+ }
+ return (byte)(j1 + j2);
+ }
+
+ static byte remi_sump2_cond(Byte j1) {
+ Byte j2 = Byte.valueOf((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Byte((byte)(j1 + 1));
+ } else {
+ j2 = (byte)(j2 + 2);
+ }
+ }
+ return (byte)(j1 + j2);
+ }
+
+ static byte remi_sumc2_cond() {
+ Byte j1 = ibc;
+ Byte j2 = Byte.valueOf((byte)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = (byte)(j1 + ibc);
+ } else {
+ j2 = (byte)(j2 + 2);
+ }
+ }
+ return (byte)(j1 + j2);
+ }
+
+
+ public static void main(String[] args) {
+ final int ntests = 70;
+
+ String[] test_name = new String[] {
+ "simple", "simpleb", "simplec", "simplef", "simplep",
+ "simple2", "simpleb2", "simplec2", "simplem2", "simplep2",
+ "simple_deop", "simpleb_deop", "simplec_deop", "simplef_deop", "simplep_deop",
+ "test", "testb", "testc", "testm", "testp",
+ "test2", "testb2", "testc2", "testm2", "testp2",
+ "test_deop", "testb_deop", "testc_deop", "testf_deop", "testp_deop",
+ "sum", "sumb", "sumc", "sumf", "sump",
+ "sum2", "sumb2", "sumc2", "summ2", "sump2",
+ "sum_deop", "sumb_deop", "sumc_deop", "sumf_deop", "sump_deop",
+ "remi_sum", "remi_sumb", "remi_sumc", "remi_sumf", "remi_sump",
+ "remi_sum2", "remi_sumb2", "remi_sumc2", "remi_summ2", "remi_sump2",
+ "remi_sum_deop", "remi_sumb_deop", "remi_sumc_deop", "remi_sumf_deop", "remi_sump_deop",
+ "remi_sum_cond", "remi_sumb_cond", "remi_sumc_cond", "remi_sumf_cond", "remi_sump_cond",
+ "remi_sum2_cond", "remi_sumb2_cond", "remi_sumc2_cond", "remi_summ2_cond", "remi_sump2_cond"
+ };
+
+ final int[] val = new int[] {
+ -5488, -5488, 12000, -5488, -5488,
+ 1024, 1024, -5552, 1024, 1024,
+ -5488, -5488, 12000, -5488, -5488,
+ 512, 512, 6256, 512, 512,
+ 13024, 13024, -5584, 13024, 13024,
+ 512, 512, 6256, 512, 512,
+ 45, 45, 45, 45, 45,
+ 66, 66, 66, 66, 66,
+ 45, 45, 45, 45, 45,
+ -23, -23, -23, -23, -23,
+ -70, -70, -70, -70, -70,
+ -23, -23, -23, -23, -23,
+ -11, -11, -11, -11, -11,
+ -34, -34, -34, -34, -34
+ };
+
+ int[] res = new int[ntests];
+ for (int i = 0; i < ntests; i++) {
+ res[i] = 0;
+ }
+
+
+ for (int i = 0; i < 12000; i++) {
+ res[0] += simple((byte)i);
+ res[1] += simpleb((byte)i);
+ res[2] += simplec();
+ res[3] += simplef((byte)i);
+ res[4] += simplep((byte)i);
+
+ res[5] += simple2((byte)i);
+ res[6] += simpleb2((byte)i);
+ res[7] += simplec2((byte)i);
+ res[8] += simplem2((byte)i);
+ res[9] += simplep2((byte)i, (byte)i);
+
+ res[10] += simple_deop((byte)i);
+ res[11] += simpleb_deop((byte)i);
+ res[12] += simplec_deop((byte)i);
+ res[13] += simplef_deop((byte)i);
+ res[14] += simplep_deop((byte)i);
+
+ res[15] += test((byte)i);
+ res[16] += testb((byte)i);
+ res[17] += testc((byte)i);
+ res[18] += testm((byte)i);
+ res[19] += testp((byte)i, (byte)i);
+
+ res[20] += test2((byte)i);
+ res[21] += testb2((byte)i);
+ res[22] += testc2((byte)i);
+ res[23] += testm2((byte)i);
+ res[24] += testp2((byte)i, (byte)i);
+
+ res[25] += test_deop((byte)i);
+ res[26] += testb_deop((byte)i);
+ res[27] += testc_deop((byte)i);
+ res[28] += testf_deop((byte)i);
+ res[29] += testp_deop((byte)i, (byte)i);
+ }
+
+ byte[] ia = new byte[1000];
+ for (int i = 0; i < 1000; i++) {
+ ia[i] = (byte)i;
+ }
+
+ for (int i = 0; i < 100; i++) {
+ res[30] = sum(ia);
+ res[31] = sumb(ia);
+ res[32] = sumc(ia);
+ res[33] = sumf(ia);
+ res[34] = sump(ia, (byte)1);
+
+ res[35] = sum2(ia);
+ res[36] = sumb2(ia);
+ res[37] = sumc2(ia);
+ res[38] = summ2(ia);
+ res[39] = sump2(ia, (byte)1);
+
+ res[40] = sum_deop(ia);
+ res[41] = sumb_deop(ia);
+ res[42] = sumc_deop(ia);
+ res[43] = sumf_deop(ia);
+ res[44] = sump_deop(ia, (byte)1);
+
+ res[45] = remi_sum();
+ res[46] = remi_sumb();
+ res[47] = remi_sumc();
+ res[48] = remi_sumf();
+ res[49] = remi_sump((byte)1);
+
+ res[50] = remi_sum2();
+ res[51] = remi_sumb2();
+ res[52] = remi_sumc2();
+ res[53] = remi_summ2();
+ res[54] = remi_sump2((byte)1);
+
+ res[55] = remi_sum_deop();
+ res[56] = remi_sumb_deop();
+ res[57] = remi_sumc_deop();
+ res[58] = remi_sumf_deop();
+ res[59] = remi_sump_deop((byte)1);
+
+ res[60] = remi_sum_cond();
+ res[61] = remi_sumb_cond();
+ res[62] = remi_sumc_cond();
+ res[63] = remi_sumf_cond();
+ res[64] = remi_sump_cond((byte)1);
+
+ res[65] = remi_sum2_cond();
+ res[66] = remi_sumb2_cond();
+ res[67] = remi_sumc2_cond();
+ res[68] = remi_summ2_cond();
+ res[69] = remi_sump2_cond((byte)1);
+ }
+
+ int failed = 0;
+ for (int i = 0; i < ntests; i++) {
+ if (res[i] != val[i]) {
+ System.err.println(test_name[i] + ": " + res[i] + " != " + val[i]);
+ failed++;
+ }
+ }
+ if (failed > 0) {
+ System.err.println("Failed " + failed + " tests.");
+ throw new InternalError();
+ } else {
+ System.out.println("Passed.");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6934604/TestDoubleBoxing.java Wed May 08 15:08:01 2013 -0700
@@ -0,0 +1,777 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6934604
+ * @summary enable parts of EliminateAutoBox by default
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox TestDoubleBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestDoubleBoxing.dummy -XX:CompileCommand=exclude,TestDoubleBoxing.foo -XX:CompileCommand=exclude,TestDoubleBoxing.foob TestDoubleBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestDoubleBoxing.dummy -XX:CompileCommand=exclude,TestDoubleBoxing.foo -XX:CompileCommand=exclude,TestDoubleBoxing.foob TestDoubleBoxing
+ *
+ */
+
+public class TestDoubleBoxing {
+
+ static final Double ibc = new Double(1.);
+
+ //===============================================
+ // Non-inlined methods to test deoptimization info
+ static void dummy() { }
+ static double foo(double i) { return i; }
+ static Double foob(double i) { return Double.valueOf(i); }
+
+
+ static double simple(double i) {
+ Double ib = new Double(i);
+ return ib;
+ }
+
+ static double simpleb(double i) {
+ Double ib = Double.valueOf(i);
+ return ib;
+ }
+
+ static double simplec() {
+ Double ib = ibc;
+ return ib;
+ }
+
+ static double simplef(double i) {
+ Double ib = foob(i);
+ return ib;
+ }
+
+ static double simplep(Double ib) {
+ return ib;
+ }
+
+ static double simple2(double i) {
+ Double ib1 = new Double(i);
+ Double ib2 = new Double(i+1.);
+ return ib1 + ib2;
+ }
+
+ static double simpleb2(double i) {
+ Double ib1 = Double.valueOf(i);
+ Double ib2 = Double.valueOf(i+1.);
+ return ib1 + ib2;
+ }
+
+ static double simplem2(double i) {
+ Double ib1 = new Double(i);
+ Double ib2 = Double.valueOf(i+1.);
+ return ib1 + ib2;
+ }
+
+ static double simplep2(double i, Double ib1) {
+ Double ib2 = Double.valueOf(i+1.);
+ return ib1 + ib2;
+ }
+
+ static double simplec2(double i) {
+ Double ib1 = ibc;
+ Double ib2 = Double.valueOf(i+1.);
+ return ib1 + ib2;
+ }
+
+ //===============================================
+ static double test(double f, int i) {
+ Double ib = new Double(f);
+ if ((i&1) == 0)
+ ib = f+1.;
+ return ib;
+ }
+
+ static double testb(double f, int i) {
+ Double ib = f;
+ if ((i&1) == 0)
+ ib = (f+1.);
+ return ib;
+ }
+
+ static double testm(double f, int i) {
+ Double ib = f;
+ if ((i&1) == 0)
+ ib = new Double(f+1.);
+ return ib;
+ }
+
+ static double testp(double f, int i, Double ib) {
+ if ((i&1) == 0)
+ ib = new Double(f+1.);
+ return ib;
+ }
+
+ static double testc(double f, int i) {
+ Double ib = ibc;
+ if ((i&1) == 0)
+ ib = new Double(f+1.);
+ return ib;
+ }
+
+ static double test2(double f, int i) {
+ Double ib1 = new Double(f);
+ Double ib2 = new Double(f+1.);
+ if ((i&1) == 0) {
+ ib1 = new Double(f+1.);
+ ib2 = new Double(f+2.);
+ }
+ return ib1+ib2;
+ }
+
+ static double testb2(double f, int i) {
+ Double ib1 = f;
+ Double ib2 = f+1.;
+ if ((i&1) == 0) {
+ ib1 = (f+1.);
+ ib2 = (f+2.);
+ }
+ return ib1+ib2;
+ }
+
+ static double testm2(double f, int i) {
+ Double ib1 = new Double(f);
+ Double ib2 = f+1.;
+ if ((i&1) == 0) {
+ ib1 = new Double(f+1.);
+ ib2 = (f+2.);
+ }
+ return ib1+ib2;
+ }
+
+ static double testp2(double f, int i, Double ib1) {
+ Double ib2 = f+1.;
+ if ((i&1) == 0) {
+ ib1 = new Double(f+1.);
+ ib2 = (f+2.);
+ }
+ return ib1+ib2;
+ }
+
+ static double testc2(double f, int i) {
+ Double ib1 = ibc;
+ Double ib2 = f+1.;
+ if ((i&1) == 0) {
+ ib1 = (ibc+1.);
+ ib2 = (f+2.);
+ }
+ return ib1+ib2;
+ }
+
+ //===============================================
+ static double sum(double[] a) {
+ double result = 1.;
+ for (Double i : a)
+ result += i;
+ return result;
+ }
+
+ static double sumb(double[] a) {
+ Double result = 1.;
+ for (Double i : a)
+ result += i;
+ return result;
+ }
+
+ static double sumc(double[] a) {
+ Double result = ibc;
+ for (Double i : a)
+ result += i;
+ return result;
+ }
+
+ static double sumf(double[] a) {
+ Double result = foob(1.);
+ for (Double i : a)
+ result += i;
+ return result;
+ }
+
+ static double sump(double[] a, Double result) {
+ for (Double i : a)
+ result += i;
+ return result;
+ }
+
+ static double sum2(double[] a) {
+ double result1 = 1.;
+ double result2 = 1.;
+ for (Double i : a) {
+ result1 += i;
+ result2 += i + 1.;
+ }
+ return result1 + result2;
+ }
+
+ static double sumb2(double[] a) {
+ Double result1 = 1.;
+ Double result2 = 1.;
+ for (Double i : a) {
+ result1 += i;
+ result2 += i + 1.;
+ }
+ return result1 + result2;
+ }
+
+ static double summ2(double[] a) {
+ Double result1 = 1.;
+ Double result2 = new Double(1.);
+ for (Double i : a) {
+ result1 += i;
+ result2 += new Double(i + 1.);
+ }
+ return result1 + result2;
+ }
+
+ static double sump2(double[] a, Double result2) {
+ Double result1 = 1.;
+ for (Double i : a) {
+ result1 += i;
+ result2 += i + 1.;
+ }
+ return result1 + result2;
+ }
+
+ static double sumc2(double[] a) {
+ Double result1 = 1.;
+ Double result2 = ibc;
+ for (Double i : a) {
+ result1 += i;
+ result2 += i + ibc;
+ }
+ return result1 + result2;
+ }
+
+ //===============================================
+ static double remi_sum() {
+ Double j = new Double(1.);
+ for (int i = 0; i< 1000; i++) {
+ j = new Double(j + 1.);
+ }
+ return j;
+ }
+
+ static double remi_sumb() {
+ Double j = Double.valueOf(1.);
+ for (int i = 0; i< 1000; i++) {
+ j = j + 1.;
+ }
+ return j;
+ }
+
+ static double remi_sumf() {
+ Double j = foob(1.);
+ for (int i = 0; i< 1000; i++) {
+ j = j + 1.;
+ }
+ return j;
+ }
+
+ static double remi_sump(Double j) {
+ for (int i = 0; i< 1000; i++) {
+ j = new Double(j + 1.);
+ }
+ return j;
+ }
+
+ static double remi_sumc() {
+ Double j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = j + ibc;
+ }
+ return j;
+ }
+
+ static double remi_sum2() {
+ Double j1 = new Double(1.);
+ Double j2 = new Double(1.);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Double(j1 + 1.);
+ j2 = new Double(j2 + 2.);
+ }
+ return j1 + j2;
+ }
+
+ static double remi_sumb2() {
+ Double j1 = Double.valueOf(1.);
+ Double j2 = Double.valueOf(1.);
+ for (int i = 0; i< 1000; i++) {
+ j1 = j1 + 1.;
+ j2 = j2 + 2.;
+ }
+ return j1 + j2;
+ }
+
+ static double remi_summ2() {
+ Double j1 = new Double(1.);
+ Double j2 = Double.valueOf(1.);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Double(j1 + 1.);
+ j2 = j2 + 2.;
+ }
+ return j1 + j2;
+ }
+
+ static double remi_sump2(Double j1) {
+ Double j2 = Double.valueOf(1.);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Double(j1 + 1.);
+ j2 = j2 + 2.;
+ }
+ return j1 + j2;
+ }
+
+ static double remi_sumc2() {
+ Double j1 = ibc;
+ Double j2 = Double.valueOf(1.);
+ for (int i = 0; i< 1000; i++) {
+ j1 = j1 + ibc;
+ j2 = j2 + 2.;
+ }
+ return j1 + j2;
+ }
+
+
+ //===============================================
+ // Safepointa and debug info for deoptimization
+ static double simple_deop(double i) {
+ Double ib = new Double(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static double simpleb_deop(double i) {
+ Double ib = Double.valueOf(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static double simplef_deop(double i) {
+ Double ib = foob(i);
+ dummy();
+ return ib;
+ }
+
+ static double simplep_deop(Double ib) {
+ dummy();
+ return ib;
+ }
+
+ static double simplec_deop(double i) {
+ Double ib = ibc;
+ dummy();
+ return ib;
+ }
+
+ static double test_deop(double f, int i) {
+ Double ib = new Double(foo(f));
+ if ((i&1) == 0)
+ ib = foo(f+1.);
+ dummy();
+ return ib;
+ }
+
+ static double testb_deop(double f, int i) {
+ Double ib = foo(f);
+ if ((i&1) == 0)
+ ib = foo(f+1.);
+ dummy();
+ return ib;
+ }
+
+ static double testf_deop(double f, int i) {
+ Double ib = foob(f);
+ if ((i&1) == 0)
+ ib = foo(f+1.);
+ dummy();
+ return ib;
+ }
+
+ static double testp_deop(double f, int i, Double ib) {
+ if ((i&1) == 0)
+ ib = foo(f+1.);
+ dummy();
+ return ib;
+ }
+
+ static double testc_deop(double f, int i) {
+ Double ib = ibc;
+ if ((i&1) == 0)
+ ib = foo(f+1.);
+ dummy();
+ return ib;
+ }
+
+ static double sum_deop(double[] a) {
+ double result = 1.;
+ for (Double i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static double sumb_deop(double[] a) {
+ Double result = 1.;
+ for (Double i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static double sumf_deop(double[] a) {
+ Double result = 1.;
+ for (Double i : a)
+ result += foob(i);
+ dummy();
+ return result;
+ }
+
+ static double sump_deop(double[] a, Double result) {
+ for (Double i : a)
+ result += foob(i);
+ dummy();
+ return result;
+ }
+
+ static double sumc_deop(double[] a) {
+ Double result = ibc;
+ for (Double i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static double remi_sum_deop() {
+ Double j = new Double(foo(1.));
+ for (int i = 0; i< 1000; i++) {
+ j = new Double(foo(j + 1.));
+ }
+ dummy();
+ return j;
+ }
+
+ static double remi_sumb_deop() {
+ Double j = Double.valueOf(foo(1.));
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1.);
+ }
+ dummy();
+ return j;
+ }
+
+ static double remi_sumf_deop() {
+ Double j = foob(1.);
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1.);
+ }
+ dummy();
+ return j;
+ }
+
+ static double remi_sump_deop(Double j) {
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1.);
+ }
+ dummy();
+ return j;
+ }
+
+ static double remi_sumc_deop() {
+ Double j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1.);
+ }
+ dummy();
+ return j;
+ }
+
+ //===============================================
+ // Conditional increment
+ static double remi_sum_cond() {
+ Double j = new Double(1.);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = new Double(j + 1.);
+ }
+ }
+ return j;
+ }
+
+ static double remi_sumb_cond() {
+ Double j = Double.valueOf(1.);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1.;
+ }
+ }
+ return j;
+ }
+
+ static double remi_sumf_cond() {
+ Double j = foob(1.);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1.;
+ }
+ }
+ return j;
+ }
+
+ static double remi_sump_cond(Double j) {
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1.;
+ }
+ }
+ return j;
+ }
+
+ static double remi_sumc_cond() {
+ Double j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + ibc;
+ }
+ }
+ return j;
+ }
+
+ static double remi_sum2_cond() {
+ Double j1 = new Double(1.);
+ Double j2 = new Double(1.);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Double(j1 + 1.);
+ } else {
+ j2 = new Double(j2 + 2.);
+ }
+ }
+ return j1 + j2;
+ }
+
+ static double remi_sumb2_cond() {
+ Double j1 = Double.valueOf(1.);
+ Double j2 = Double.valueOf(1.);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = j1 + 1.;
+ } else {
+ j2 = j2 + 2.;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static double remi_summ2_cond() {
+ Double j1 = new Double(1.);
+ Double j2 = Double.valueOf(1.);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Double(j1 + 1.);
+ } else {
+ j2 = j2 + 2.;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static double remi_sump2_cond(Double j1) {
+ Double j2 = Double.valueOf(1.);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Double(j1 + 1.);
+ } else {
+ j2 = j2 + 2.;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static double remi_sumc2_cond() {
+ Double j1 = ibc;
+ Double j2 = Double.valueOf(1.);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = j1 + ibc;
+ } else {
+ j2 = j2 + 2;
+ }
+ }
+ return j1 + j2;
+ }
+
+
+ public static void main(String[] args) {
+ final int ntests = 70;
+
+ String[] test_name = new String[] {
+ "simple", "simpleb", "simplec", "simplef", "simplep",
+ "simple2", "simpleb2", "simplec2", "simplem2", "simplep2",
+ "simple_deop", "simpleb_deop", "simplec_deop", "simplef_deop", "simplep_deop",
+ "test", "testb", "testc", "testm", "testp",
+ "test2", "testb2", "testc2", "testm2", "testp2",
+ "test_deop", "testb_deop", "testc_deop", "testf_deop", "testp_deop",
+ "sum", "sumb", "sumc", "sumf", "sump",
+ "sum2", "sumb2", "sumc2", "summ2", "sump2",
+ "sum_deop", "sumb_deop", "sumc_deop", "sumf_deop", "sump_deop",
+ "remi_sum", "remi_sumb", "remi_sumc", "remi_sumf", "remi_sump",
+ "remi_sum2", "remi_sumb2", "remi_sumc2", "remi_summ2", "remi_sump2",
+ "remi_sum_deop", "remi_sumb_deop", "remi_sumc_deop", "remi_sumf_deop", "remi_sump_deop",
+ "remi_sum_cond", "remi_sumb_cond", "remi_sumc_cond", "remi_sumf_cond", "remi_sump_cond",
+ "remi_sum2_cond", "remi_sumb2_cond", "remi_sumc2_cond", "remi_summ2_cond", "remi_sump2_cond"
+ };
+
+ final double[] val = new double[] {
+ 71994000., 71994000., 12000., 71994000., 71994000.,
+ 144000000., 144000000., 72018000., 144000000., 144000000.,
+ 71994000., 71994000., 12000., 71994000., 71994000.,
+ 72000000., 72000000., 36006000., 72000000., 72000000.,
+ 144012000., 144012000., 72030000., 144012000., 144012000.,
+ 72000000., 72000000., 36006000., 72000000., 72000000.,
+ 499501., 499501., 499501., 499501., 499501.,
+ 1000002., 1000002., 1000002., 1000002., 1000002.,
+ 499501., 499501., 499501., 499501., 499501.,
+ 1001., 1001., 1001., 1001., 1001.,
+ 3002., 3002., 3002., 3002., 3002.,
+ 1001., 1001., 1001., 1001., 1001.,
+ 501., 501., 501., 501., 501.,
+ 1502., 1502., 1502., 1502., 1502.
+ };
+
+ double[] res = new double[ntests];
+ for (int i = 0; i < ntests; i++) {
+ res[i] = 0.;
+ }
+
+
+ for (int i = 0; i < 12000; i++) {
+ res[0] += simple(i);
+ res[1] += simpleb(i);
+ res[2] += simplec();
+ res[3] += simplef(i);
+ res[4] += simplep((double)i);
+
+ res[5] += simple2((double)i);
+ res[6] += simpleb2((double)i);
+ res[7] += simplec2((double)i);
+ res[8] += simplem2((double)i);
+ res[9] += simplep2((double)i, (double)i);
+
+ res[10] += simple_deop((double)i);
+ res[11] += simpleb_deop((double)i);
+ res[12] += simplec_deop((double)i);
+ res[13] += simplef_deop((double)i);
+ res[14] += simplep_deop((double)i);
+
+ res[15] += test((double)i, i);
+ res[16] += testb((double)i, i);
+ res[17] += testc((double)i, i);
+ res[18] += testm((double)i, i);
+ res[19] += testp((double)i, i, (double)i);
+
+ res[20] += test2((double)i, i);
+ res[21] += testb2((double)i, i);
+ res[22] += testc2((double)i, i);
+ res[23] += testm2((double)i, i);
+ res[24] += testp2((double)i, i, (double)i);
+
+ res[25] += test_deop((double)i, i);
+ res[26] += testb_deop((double)i, i);
+ res[27] += testc_deop((double)i, i);
+ res[28] += testf_deop((double)i, i);
+ res[29] += testp_deop((double)i, i, (double)i);
+ }
+
+ double[] ia = new double[1000];
+ for (int i = 0; i < 1000; i++) {
+ ia[i] = i;
+ }
+
+ for (int i = 0; i < 100; i++) {
+ res[30] = sum(ia);
+ res[31] = sumb(ia);
+ res[32] = sumc(ia);
+ res[33] = sumf(ia);
+ res[34] = sump(ia, 1.);
+
+ res[35] = sum2(ia);
+ res[36] = sumb2(ia);
+ res[37] = sumc2(ia);
+ res[38] = summ2(ia);
+ res[39] = sump2(ia, 1.);
+
+ res[40] = sum_deop(ia);
+ res[41] = sumb_deop(ia);
+ res[42] = sumc_deop(ia);
+ res[43] = sumf_deop(ia);
+ res[44] = sump_deop(ia, 1.);
+
+ res[45] = remi_sum();
+ res[46] = remi_sumb();
+ res[47] = remi_sumc();
+ res[48] = remi_sumf();
+ res[49] = remi_sump(1.);
+
+ res[50] = remi_sum2();
+ res[51] = remi_sumb2();
+ res[52] = remi_sumc2();
+ res[53] = remi_summ2();
+ res[54] = remi_sump2(1.);
+
+ res[55] = remi_sum_deop();
+ res[56] = remi_sumb_deop();
+ res[57] = remi_sumc_deop();
+ res[58] = remi_sumf_deop();
+ res[59] = remi_sump_deop(1.);
+
+ res[60] = remi_sum_cond();
+ res[61] = remi_sumb_cond();
+ res[62] = remi_sumc_cond();
+ res[63] = remi_sumf_cond();
+ res[64] = remi_sump_cond(1.);
+
+ res[65] = remi_sum2_cond();
+ res[66] = remi_sumb2_cond();
+ res[67] = remi_sumc2_cond();
+ res[68] = remi_summ2_cond();
+ res[69] = remi_sump2_cond(1.);
+ }
+
+ int failed = 0;
+ for (int i = 0; i < ntests; i++) {
+ if (res[i] != val[i]) {
+ System.err.println(test_name[i] + ": " + res[i] + " != " + val[i]);
+ failed++;
+ }
+ }
+ if (failed > 0) {
+ System.err.println("Failed " + failed + " tests.");
+ throw new InternalError();
+ } else {
+ System.out.println("Passed.");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6934604/TestFloatBoxing.java Wed May 08 15:08:01 2013 -0700
@@ -0,0 +1,777 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6934604
+ * @summary enable parts of EliminateAutoBox by default
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox TestFloatBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestFloatBoxing.dummy -XX:CompileCommand=exclude,TestFloatBoxing.foo -XX:CompileCommand=exclude,TestFloatBoxing.foob TestFloatBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestFloatBoxing.dummy -XX:CompileCommand=exclude,TestFloatBoxing.foo -XX:CompileCommand=exclude,TestFloatBoxing.foob TestFloatBoxing
+ *
+ */
+
+public class TestFloatBoxing {
+
+ static final Float ibc = new Float(1.f);
+
+ //===============================================
+ // Non-inlined methods to test deoptimization info
+ static void dummy() { }
+ static float foo(float i) { return i; }
+ static Float foob(float i) { return Float.valueOf(i); }
+
+
+ static float simple(float i) {
+ Float ib = new Float(i);
+ return ib;
+ }
+
+ static float simpleb(float i) {
+ Float ib = Float.valueOf(i);
+ return ib;
+ }
+
+ static float simplec() {
+ Float ib = ibc;
+ return ib;
+ }
+
+ static float simplef(float i) {
+ Float ib = foob(i);
+ return ib;
+ }
+
+ static float simplep(Float ib) {
+ return ib;
+ }
+
+ static float simple2(float i) {
+ Float ib1 = new Float(i);
+ Float ib2 = new Float(i+1.f);
+ return ib1 + ib2;
+ }
+
+ static float simpleb2(float i) {
+ Float ib1 = Float.valueOf(i);
+ Float ib2 = Float.valueOf(i+1.f);
+ return ib1 + ib2;
+ }
+
+ static float simplem2(float i) {
+ Float ib1 = new Float(i);
+ Float ib2 = Float.valueOf(i+1.f);
+ return ib1 + ib2;
+ }
+
+ static float simplep2(float i, Float ib1) {
+ Float ib2 = Float.valueOf(i+1.f);
+ return ib1 + ib2;
+ }
+
+ static float simplec2(float i) {
+ Float ib1 = ibc;
+ Float ib2 = Float.valueOf(i+1.f);
+ return ib1 + ib2;
+ }
+
+ //===============================================
+ static float test(float f, int i) {
+ Float ib = new Float(f);
+ if ((i&1) == 0)
+ ib = f+1.f;
+ return ib;
+ }
+
+ static float testb(float f, int i) {
+ Float ib = f;
+ if ((i&1) == 0)
+ ib = (f+1.f);
+ return ib;
+ }
+
+ static float testm(float f, int i) {
+ Float ib = f;
+ if ((i&1) == 0)
+ ib = new Float(f+1.f);
+ return ib;
+ }
+
+ static float testp(float f, int i, Float ib) {
+ if ((i&1) == 0)
+ ib = new Float(f+1.f);
+ return ib;
+ }
+
+ static float testc(float f, int i) {
+ Float ib = ibc;
+ if ((i&1) == 0)
+ ib = new Float(f+1.f);
+ return ib;
+ }
+
+ static float test2(float f, int i) {
+ Float ib1 = new Float(f);
+ Float ib2 = new Float(f+1.f);
+ if ((i&1) == 0) {
+ ib1 = new Float(f+1.f);
+ ib2 = new Float(f+2.f);
+ }
+ return ib1+ib2;
+ }
+
+ static float testb2(float f, int i) {
+ Float ib1 = f;
+ Float ib2 = f+1.f;
+ if ((i&1) == 0) {
+ ib1 = (f+1.f);
+ ib2 = (f+2.f);
+ }
+ return ib1+ib2;
+ }
+
+ static float testm2(float f, int i) {
+ Float ib1 = new Float(f);
+ Float ib2 = f+1.f;
+ if ((i&1) == 0) {
+ ib1 = new Float(f+1.f);
+ ib2 = (f+2.f);
+ }
+ return ib1+ib2;
+ }
+
+ static float testp2(float f, int i, Float ib1) {
+ Float ib2 = f+1.f;
+ if ((i&1) == 0) {
+ ib1 = new Float(f+1.f);
+ ib2 = (f+2.f);
+ }
+ return ib1+ib2;
+ }
+
+ static float testc2(float f, int i) {
+ Float ib1 = ibc;
+ Float ib2 = f+1.f;
+ if ((i&1) == 0) {
+ ib1 = (ibc+1.f);
+ ib2 = (f+2.f);
+ }
+ return ib1+ib2;
+ }
+
+ //===============================================
+ static float sum(float[] a) {
+ float result = 1.f;
+ for (Float i : a)
+ result += i;
+ return result;
+ }
+
+ static float sumb(float[] a) {
+ Float result = 1.f;
+ for (Float i : a)
+ result += i;
+ return result;
+ }
+
+ static float sumc(float[] a) {
+ Float result = ibc;
+ for (Float i : a)
+ result += i;
+ return result;
+ }
+
+ static float sumf(float[] a) {
+ Float result = foob(1.f);
+ for (Float i : a)
+ result += i;
+ return result;
+ }
+
+ static float sump(float[] a, Float result) {
+ for (Float i : a)
+ result += i;
+ return result;
+ }
+
+ static float sum2(float[] a) {
+ float result1 = 1.f;
+ float result2 = 1.f;
+ for (Float i : a) {
+ result1 += i;
+ result2 += i + 1.f;
+ }
+ return result1 + result2;
+ }
+
+ static float sumb2(float[] a) {
+ Float result1 = 1.f;
+ Float result2 = 1.f;
+ for (Float i : a) {
+ result1 += i;
+ result2 += i + 1.f;
+ }
+ return result1 + result2;
+ }
+
+ static float summ2(float[] a) {
+ Float result1 = 1.f;
+ Float result2 = new Float(1.f);
+ for (Float i : a) {
+ result1 += i;
+ result2 += new Float(i + 1.f);
+ }
+ return result1 + result2;
+ }
+
+ static float sump2(float[] a, Float result2) {
+ Float result1 = 1.f;
+ for (Float i : a) {
+ result1 += i;
+ result2 += i + 1.f;
+ }
+ return result1 + result2;
+ }
+
+ static float sumc2(float[] a) {
+ Float result1 = 1.f;
+ Float result2 = ibc;
+ for (Float i : a) {
+ result1 += i;
+ result2 += i + ibc;
+ }
+ return result1 + result2;
+ }
+
+ //===============================================
+ static float remi_sum() {
+ Float j = new Float(1.f);
+ for (int i = 0; i< 1000; i++) {
+ j = new Float(j + 1.f);
+ }
+ return j;
+ }
+
+ static float remi_sumb() {
+ Float j = Float.valueOf(1.f);
+ for (int i = 0; i< 1000; i++) {
+ j = j + 1.f;
+ }
+ return j;
+ }
+
+ static float remi_sumf() {
+ Float j = foob(1.f);
+ for (int i = 0; i< 1000; i++) {
+ j = j + 1.f;
+ }
+ return j;
+ }
+
+ static float remi_sump(Float j) {
+ for (int i = 0; i< 1000; i++) {
+ j = new Float(j + 1.f);
+ }
+ return j;
+ }
+
+ static float remi_sumc() {
+ Float j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = j + ibc;
+ }
+ return j;
+ }
+
+ static float remi_sum2() {
+ Float j1 = new Float(1.f);
+ Float j2 = new Float(1.f);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Float(j1 + 1.f);
+ j2 = new Float(j2 + 2.f);
+ }
+ return j1 + j2;
+ }
+
+ static float remi_sumb2() {
+ Float j1 = Float.valueOf(1.f);
+ Float j2 = Float.valueOf(1.f);
+ for (int i = 0; i< 1000; i++) {
+ j1 = j1 + 1.f;
+ j2 = j2 + 2.f;
+ }
+ return j1 + j2;
+ }
+
+ static float remi_summ2() {
+ Float j1 = new Float(1.f);
+ Float j2 = Float.valueOf(1.f);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Float(j1 + 1.f);
+ j2 = j2 + 2.f;
+ }
+ return j1 + j2;
+ }
+
+ static float remi_sump2(Float j1) {
+ Float j2 = Float.valueOf(1.f);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Float(j1 + 1.f);
+ j2 = j2 + 2.f;
+ }
+ return j1 + j2;
+ }
+
+ static float remi_sumc2() {
+ Float j1 = ibc;
+ Float j2 = Float.valueOf(1.f);
+ for (int i = 0; i< 1000; i++) {
+ j1 = j1 + ibc;
+ j2 = j2 + 2.f;
+ }
+ return j1 + j2;
+ }
+
+
+ //===============================================
+ // Safepointa and debug info for deoptimization
+ static float simple_deop(float i) {
+ Float ib = new Float(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static float simpleb_deop(float i) {
+ Float ib = Float.valueOf(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static float simplef_deop(float i) {
+ Float ib = foob(i);
+ dummy();
+ return ib;
+ }
+
+ static float simplep_deop(Float ib) {
+ dummy();
+ return ib;
+ }
+
+ static float simplec_deop(float i) {
+ Float ib = ibc;
+ dummy();
+ return ib;
+ }
+
+ static float test_deop(float f, int i) {
+ Float ib = new Float(foo(f));
+ if ((i&1) == 0)
+ ib = foo(f+1.f);
+ dummy();
+ return ib;
+ }
+
+ static float testb_deop(float f, int i) {
+ Float ib = foo(f);
+ if ((i&1) == 0)
+ ib = foo(f+1.f);
+ dummy();
+ return ib;
+ }
+
+ static float testf_deop(float f, int i) {
+ Float ib = foob(f);
+ if ((i&1) == 0)
+ ib = foo(f+1.f);
+ dummy();
+ return ib;
+ }
+
+ static float testp_deop(float f, int i, Float ib) {
+ if ((i&1) == 0)
+ ib = foo(f+1.f);
+ dummy();
+ return ib;
+ }
+
+ static float testc_deop(float f, int i) {
+ Float ib = ibc;
+ if ((i&1) == 0)
+ ib = foo(f+1.f);
+ dummy();
+ return ib;
+ }
+
+ static float sum_deop(float[] a) {
+ float result = 1.f;
+ for (Float i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static float sumb_deop(float[] a) {
+ Float result = 1.f;
+ for (Float i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static float sumf_deop(float[] a) {
+ Float result = 1.f;
+ for (Float i : a)
+ result += foob(i);
+ dummy();
+ return result;
+ }
+
+ static float sump_deop(float[] a, Float result) {
+ for (Float i : a)
+ result += foob(i);
+ dummy();
+ return result;
+ }
+
+ static float sumc_deop(float[] a) {
+ Float result = ibc;
+ for (Float i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static float remi_sum_deop() {
+ Float j = new Float(foo(1.f));
+ for (int i = 0; i< 1000; i++) {
+ j = new Float(foo(j + 1.f));
+ }
+ dummy();
+ return j;
+ }
+
+ static float remi_sumb_deop() {
+ Float j = Float.valueOf(foo(1.f));
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1.f);
+ }
+ dummy();
+ return j;
+ }
+
+ static float remi_sumf_deop() {
+ Float j = foob(1.f);
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1.f);
+ }
+ dummy();
+ return j;
+ }
+
+ static float remi_sump_deop(Float j) {
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1.f);
+ }
+ dummy();
+ return j;
+ }
+
+ static float remi_sumc_deop() {
+ Float j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1.f);
+ }
+ dummy();
+ return j;
+ }
+
+ //===============================================
+ // Conditional increment
+ static float remi_sum_cond() {
+ Float j = new Float(1.f);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = new Float(j + 1.f);
+ }
+ }
+ return j;
+ }
+
+ static float remi_sumb_cond() {
+ Float j = Float.valueOf(1.f);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1.f;
+ }
+ }
+ return j;
+ }
+
+ static float remi_sumf_cond() {
+ Float j = foob(1.f);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1.f;
+ }
+ }
+ return j;
+ }
+
+ static float remi_sump_cond(Float j) {
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1.f;
+ }
+ }
+ return j;
+ }
+
+ static float remi_sumc_cond() {
+ Float j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + ibc;
+ }
+ }
+ return j;
+ }
+
+ static float remi_sum2_cond() {
+ Float j1 = new Float(1.f);
+ Float j2 = new Float(1.f);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Float(j1 + 1.f);
+ } else {
+ j2 = new Float(j2 + 2.f);
+ }
+ }
+ return j1 + j2;
+ }
+
+ static float remi_sumb2_cond() {
+ Float j1 = Float.valueOf(1.f);
+ Float j2 = Float.valueOf(1.f);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = j1 + 1.f;
+ } else {
+ j2 = j2 + 2.f;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static float remi_summ2_cond() {
+ Float j1 = new Float(1.f);
+ Float j2 = Float.valueOf(1.f);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Float(j1 + 1.f);
+ } else {
+ j2 = j2 + 2.f;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static float remi_sump2_cond(Float j1) {
+ Float j2 = Float.valueOf(1.f);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Float(j1 + 1.f);
+ } else {
+ j2 = j2 + 2.f;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static float remi_sumc2_cond() {
+ Float j1 = ibc;
+ Float j2 = Float.valueOf(1.f);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = j1 + ibc;
+ } else {
+ j2 = j2 + 2;
+ }
+ }
+ return j1 + j2;
+ }
+
+
+ public static void main(String[] args) {
+ final int ntests = 70;
+
+ String[] test_name = new String[] {
+ "simple", "simpleb", "simplec", "simplef", "simplep",
+ "simple2", "simpleb2", "simplec2", "simplem2", "simplep2",
+ "simple_deop", "simpleb_deop", "simplec_deop", "simplef_deop", "simplep_deop",
+ "test", "testb", "testc", "testm", "testp",
+ "test2", "testb2", "testc2", "testm2", "testp2",
+ "test_deop", "testb_deop", "testc_deop", "testf_deop", "testp_deop",
+ "sum", "sumb", "sumc", "sumf", "sump",
+ "sum2", "sumb2", "sumc2", "summ2", "sump2",
+ "sum_deop", "sumb_deop", "sumc_deop", "sumf_deop", "sump_deop",
+ "remi_sum", "remi_sumb", "remi_sumc", "remi_sumf", "remi_sump",
+ "remi_sum2", "remi_sumb2", "remi_sumc2", "remi_summ2", "remi_sump2",
+ "remi_sum_deop", "remi_sumb_deop", "remi_sumc_deop", "remi_sumf_deop", "remi_sump_deop",
+ "remi_sum_cond", "remi_sumb_cond", "remi_sumc_cond", "remi_sumf_cond", "remi_sump_cond",
+ "remi_sum2_cond", "remi_sumb2_cond", "remi_sumc2_cond", "remi_summ2_cond", "remi_sump2_cond"
+ };
+
+ final float[] val = new float[] {
+ 71990896.f, 71990896.f, 12000.f, 71990896.f, 71990896.f,
+ 144000000.f, 144000000.f, 72014896.f, 144000000.f, 144000000.f,
+ 71990896.f, 71990896.f, 12000.f, 71990896.f, 71990896.f,
+ 72000000.f, 72000000.f, 36004096.f, 72000000.f, 72000000.f,
+ 144012288.f, 144012288.f, 72033096.f, 144012288.f, 144012288.f,
+ 72000000.f, 72000000.f, 36004096.f, 72000000.f, 72000000.f,
+ 499501.f, 499501.f, 499501.f, 499501.f, 499501.f,
+ 1000002.f, 1000002.f, 1000002.f, 1000002.f, 1000002.f,
+ 499501.f, 499501.f, 499501.f, 499501.f, 499501.f,
+ 1001.f, 1001.f, 1001.f, 1001.f, 1001.f,
+ 3002.f, 3002.f, 3002.f, 3002.f, 3002.f,
+ 1001.f, 1001.f, 1001.f, 1001.f, 1001.f,
+ 501.f, 501.f, 501.f, 501.f, 501.f,
+ 1502.f, 1502.f, 1502.f, 1502.f, 1502.f
+ };
+
+ float[] res = new float[ntests];
+ for (int i = 0; i < ntests; i++) {
+ res[i] = 0.f;
+ }
+
+
+ for (int i = 0; i < 12000; i++) {
+ res[0] += simple(i);
+ res[1] += simpleb(i);
+ res[2] += simplec();
+ res[3] += simplef(i);
+ res[4] += simplep((float)i);
+
+ res[5] += simple2((float)i);
+ res[6] += simpleb2((float)i);
+ res[7] += simplec2((float)i);
+ res[8] += simplem2((float)i);
+ res[9] += simplep2((float)i, (float)i);
+
+ res[10] += simple_deop((float)i);
+ res[11] += simpleb_deop((float)i);
+ res[12] += simplec_deop((float)i);
+ res[13] += simplef_deop((float)i);
+ res[14] += simplep_deop((float)i);
+
+ res[15] += test((float)i, i);
+ res[16] += testb((float)i, i);
+ res[17] += testc((float)i, i);
+ res[18] += testm((float)i, i);
+ res[19] += testp((float)i, i, (float)i);
+
+ res[20] += test2((float)i, i);
+ res[21] += testb2((float)i, i);
+ res[22] += testc2((float)i, i);
+ res[23] += testm2((float)i, i);
+ res[24] += testp2((float)i, i, (float)i);
+
+ res[25] += test_deop((float)i, i);
+ res[26] += testb_deop((float)i, i);
+ res[27] += testc_deop((float)i, i);
+ res[28] += testf_deop((float)i, i);
+ res[29] += testp_deop((float)i, i, (float)i);
+ }
+
+ float[] ia = new float[1000];
+ for (int i = 0; i < 1000; i++) {
+ ia[i] = i;
+ }
+
+ for (int i = 0; i < 100; i++) {
+ res[30] = sum(ia);
+ res[31] = sumb(ia);
+ res[32] = sumc(ia);
+ res[33] = sumf(ia);
+ res[34] = sump(ia, 1.f);
+
+ res[35] = sum2(ia);
+ res[36] = sumb2(ia);
+ res[37] = sumc2(ia);
+ res[38] = summ2(ia);
+ res[39] = sump2(ia, 1.f);
+
+ res[40] = sum_deop(ia);
+ res[41] = sumb_deop(ia);
+ res[42] = sumc_deop(ia);
+ res[43] = sumf_deop(ia);
+ res[44] = sump_deop(ia, 1.f);
+
+ res[45] = remi_sum();
+ res[46] = remi_sumb();
+ res[47] = remi_sumc();
+ res[48] = remi_sumf();
+ res[49] = remi_sump(1.f);
+
+ res[50] = remi_sum2();
+ res[51] = remi_sumb2();
+ res[52] = remi_sumc2();
+ res[53] = remi_summ2();
+ res[54] = remi_sump2(1.f);
+
+ res[55] = remi_sum_deop();
+ res[56] = remi_sumb_deop();
+ res[57] = remi_sumc_deop();
+ res[58] = remi_sumf_deop();
+ res[59] = remi_sump_deop(1.f);
+
+ res[60] = remi_sum_cond();
+ res[61] = remi_sumb_cond();
+ res[62] = remi_sumc_cond();
+ res[63] = remi_sumf_cond();
+ res[64] = remi_sump_cond(1.f);
+
+ res[65] = remi_sum2_cond();
+ res[66] = remi_sumb2_cond();
+ res[67] = remi_sumc2_cond();
+ res[68] = remi_summ2_cond();
+ res[69] = remi_sump2_cond(1.f);
+ }
+
+ int failed = 0;
+ for (int i = 0; i < ntests; i++) {
+ if (res[i] != val[i]) {
+ System.err.println(test_name[i] + ": " + res[i] + " != " + val[i]);
+ failed++;
+ }
+ }
+ if (failed > 0) {
+ System.err.println("Failed " + failed + " tests.");
+ throw new InternalError();
+ } else {
+ System.out.println("Passed.");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6934604/TestIntBoxing.java Wed May 08 15:08:01 2013 -0700
@@ -0,0 +1,777 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6934604
+ * @summary enable parts of EliminateAutoBox by default
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox TestIntBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestIntBoxing.dummy -XX:CompileCommand=exclude,TestIntBoxing.foo -XX:CompileCommand=exclude,TestIntBoxing.foob TestIntBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestIntBoxing.dummy -XX:CompileCommand=exclude,TestIntBoxing.foo -XX:CompileCommand=exclude,TestIntBoxing.foob TestIntBoxing
+ *
+ */
+
+public class TestIntBoxing {
+
+ static final Integer ibc = new Integer(1);
+
+ //===============================================
+ // Non-inlined methods to test deoptimization info
+ static void dummy() { }
+ static int foo(int i) { return i; }
+ static Integer foob(int i) { return Integer.valueOf(i); }
+
+
+ static int simple(int i) {
+ Integer ib = new Integer(i);
+ return ib;
+ }
+
+ static int simpleb(int i) {
+ Integer ib = Integer.valueOf(i);
+ return ib;
+ }
+
+ static int simplec() {
+ Integer ib = ibc;
+ return ib;
+ }
+
+ static int simplef(int i) {
+ Integer ib = foob(i);
+ return ib;
+ }
+
+ static int simplep(Integer ib) {
+ return ib;
+ }
+
+ static int simple2(int i) {
+ Integer ib1 = new Integer(i);
+ Integer ib2 = new Integer(i+1);
+ return ib1 + ib2;
+ }
+
+ static int simpleb2(int i) {
+ Integer ib1 = Integer.valueOf(i);
+ Integer ib2 = Integer.valueOf(i+1);
+ return ib1 + ib2;
+ }
+
+ static int simplem2(int i) {
+ Integer ib1 = new Integer(i);
+ Integer ib2 = Integer.valueOf(i+1);
+ return ib1 + ib2;
+ }
+
+ static int simplep2(int i, Integer ib1) {
+ Integer ib2 = Integer.valueOf(i+1);
+ return ib1 + ib2;
+ }
+
+ static int simplec2(int i) {
+ Integer ib1 = ibc;
+ Integer ib2 = Integer.valueOf(i+1);
+ return ib1 + ib2;
+ }
+
+ //===============================================
+ static int test(int i) {
+ Integer ib = new Integer(i);
+ if ((i&1) == 0)
+ ib = i+1;
+ return ib;
+ }
+
+ static int testb(int i) {
+ Integer ib = i;
+ if ((i&1) == 0)
+ ib = (i+1);
+ return ib;
+ }
+
+ static int testm(int i) {
+ Integer ib = i;
+ if ((i&1) == 0)
+ ib = new Integer(i+1);
+ return ib;
+ }
+
+ static int testp(int i, Integer ib) {
+ if ((i&1) == 0)
+ ib = new Integer(i+1);
+ return ib;
+ }
+
+ static int testc(int i) {
+ Integer ib = ibc;
+ if ((i&1) == 0)
+ ib = new Integer(i+1);
+ return ib;
+ }
+
+ static int test2(int i) {
+ Integer ib1 = new Integer(i);
+ Integer ib2 = new Integer(i+1);
+ if ((i&1) == 0) {
+ ib1 = new Integer(i+1);
+ ib2 = new Integer(i+2);
+ }
+ return ib1+ib2;
+ }
+
+ static int testb2(int i) {
+ Integer ib1 = i;
+ Integer ib2 = i+1;
+ if ((i&1) == 0) {
+ ib1 = (i+1);
+ ib2 = (i+2);
+ }
+ return ib1+ib2;
+ }
+
+ static int testm2(int i) {
+ Integer ib1 = new Integer(i);
+ Integer ib2 = i+1;
+ if ((i&1) == 0) {
+ ib1 = new Integer(i+1);
+ ib2 = (i+2);
+ }
+ return ib1+ib2;
+ }
+
+ static int testp2(int i, Integer ib1) {
+ Integer ib2 = i+1;
+ if ((i&1) == 0) {
+ ib1 = new Integer(i+1);
+ ib2 = (i+2);
+ }
+ return ib1+ib2;
+ }
+
+ static int testc2(int i) {
+ Integer ib1 = ibc;
+ Integer ib2 = i+1;
+ if ((i&1) == 0) {
+ ib1 = (ibc+1);
+ ib2 = (i+2);
+ }
+ return ib1+ib2;
+ }
+
+ //===============================================
+ static int sum(int[] a) {
+ int result = 1;
+ for (Integer i : a)
+ result += i;
+ return result;
+ }
+
+ static int sumb(int[] a) {
+ Integer result = 1;
+ for (Integer i : a)
+ result += i;
+ return result;
+ }
+
+ static int sumc(int[] a) {
+ Integer result = ibc;
+ for (Integer i : a)
+ result += i;
+ return result;
+ }
+
+ static int sumf(int[] a) {
+ Integer result = foob(1);
+ for (Integer i : a)
+ result += i;
+ return result;
+ }
+
+ static int sump(int[] a, Integer result) {
+ for (Integer i : a)
+ result += i;
+ return result;
+ }
+
+ static int sum2(int[] a) {
+ int result1 = 1;
+ int result2 = 1;
+ for (Integer i : a) {
+ result1 += i;
+ result2 += i + 1;
+ }
+ return result1 + result2;
+ }
+
+ static int sumb2(int[] a) {
+ Integer result1 = 1;
+ Integer result2 = 1;
+ for (Integer i : a) {
+ result1 += i;
+ result2 += i + 1;
+ }
+ return result1 + result2;
+ }
+
+ static int summ2(int[] a) {
+ Integer result1 = 1;
+ Integer result2 = new Integer(1);
+ for (Integer i : a) {
+ result1 += i;
+ result2 += new Integer(i + 1);
+ }
+ return result1 + result2;
+ }
+
+ static int sump2(int[] a, Integer result2) {
+ Integer result1 = 1;
+ for (Integer i : a) {
+ result1 += i;
+ result2 += i + 1;
+ }
+ return result1 + result2;
+ }
+
+ static int sumc2(int[] a) {
+ Integer result1 = 1;
+ Integer result2 = ibc;
+ for (Integer i : a) {
+ result1 += i;
+ result2 += i + ibc;
+ }
+ return result1 + result2;
+ }
+
+ //===============================================
+ static int remi_sum() {
+ Integer j = new Integer(1);
+ for (int i = 0; i< 1000; i++) {
+ j = new Integer(j + 1);
+ }
+ return j;
+ }
+
+ static int remi_sumb() {
+ Integer j = Integer.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ j = j + 1;
+ }
+ return j;
+ }
+
+ static int remi_sumf() {
+ Integer j = foob(1);
+ for (int i = 0; i< 1000; i++) {
+ j = j + 1;
+ }
+ return j;
+ }
+
+ static int remi_sump(Integer j) {
+ for (int i = 0; i< 1000; i++) {
+ j = new Integer(j + 1);
+ }
+ return j;
+ }
+
+ static int remi_sumc() {
+ Integer j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = j + ibc;
+ }
+ return j;
+ }
+
+ static int remi_sum2() {
+ Integer j1 = new Integer(1);
+ Integer j2 = new Integer(1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Integer(j1 + 1);
+ j2 = new Integer(j2 + 2);
+ }
+ return j1 + j2;
+ }
+
+ static int remi_sumb2() {
+ Integer j1 = Integer.valueOf(1);
+ Integer j2 = Integer.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = j1 + 1;
+ j2 = j2 + 2;
+ }
+ return j1 + j2;
+ }
+
+ static int remi_summ2() {
+ Integer j1 = new Integer(1);
+ Integer j2 = Integer.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Integer(j1 + 1);
+ j2 = j2 + 2;
+ }
+ return j1 + j2;
+ }
+
+ static int remi_sump2(Integer j1) {
+ Integer j2 = Integer.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Integer(j1 + 1);
+ j2 = j2 + 2;
+ }
+ return j1 + j2;
+ }
+
+ static int remi_sumc2() {
+ Integer j1 = ibc;
+ Integer j2 = Integer.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = j1 + ibc;
+ j2 = j2 + 2;
+ }
+ return j1 + j2;
+ }
+
+
+ //===============================================
+ // Safepointa and debug info for deoptimization
+ static int simple_deop(int i) {
+ Integer ib = new Integer(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static int simpleb_deop(int i) {
+ Integer ib = Integer.valueOf(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static int simplef_deop(int i) {
+ Integer ib = foob(i);
+ dummy();
+ return ib;
+ }
+
+ static int simplep_deop(Integer ib) {
+ dummy();
+ return ib;
+ }
+
+ static int simplec_deop(int i) {
+ Integer ib = ibc;
+ dummy();
+ return ib;
+ }
+
+ static int test_deop(int i) {
+ Integer ib = new Integer(foo(i));
+ if ((i&1) == 0)
+ ib = foo(i+1);
+ dummy();
+ return ib;
+ }
+
+ static int testb_deop(int i) {
+ Integer ib = foo(i);
+ if ((i&1) == 0)
+ ib = foo(i+1);
+ dummy();
+ return ib;
+ }
+
+ static int testf_deop(int i) {
+ Integer ib = foob(i);
+ if ((i&1) == 0)
+ ib = foo(i+1);
+ dummy();
+ return ib;
+ }
+
+ static int testp_deop(int i, Integer ib) {
+ if ((i&1) == 0)
+ ib = foo(i+1);
+ dummy();
+ return ib;
+ }
+
+ static int testc_deop(int i) {
+ Integer ib = ibc;
+ if ((i&1) == 0)
+ ib = foo(i+1);
+ dummy();
+ return ib;
+ }
+
+ static int sum_deop(int[] a) {
+ int result = 1;
+ for (Integer i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static int sumb_deop(int[] a) {
+ Integer result = 1;
+ for (Integer i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static int sumf_deop(int[] a) {
+ Integer result = 1;
+ for (Integer i : a)
+ result += foob(i);
+ dummy();
+ return result;
+ }
+
+ static int sump_deop(int[] a, Integer result) {
+ for (Integer i : a)
+ result += foob(i);
+ dummy();
+ return result;
+ }
+
+ static int sumc_deop(int[] a) {
+ Integer result = ibc;
+ for (Integer i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static int remi_sum_deop() {
+ Integer j = new Integer(foo(1));
+ for (int i = 0; i< 1000; i++) {
+ j = new Integer(foo(j + 1));
+ }
+ dummy();
+ return j;
+ }
+
+ static int remi_sumb_deop() {
+ Integer j = Integer.valueOf(foo(1));
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1);
+ }
+ dummy();
+ return j;
+ }
+
+ static int remi_sumf_deop() {
+ Integer j = foob(1);
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1);
+ }
+ dummy();
+ return j;
+ }
+
+ static int remi_sump_deop(Integer j) {
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1);
+ }
+ dummy();
+ return j;
+ }
+
+ static int remi_sumc_deop() {
+ Integer j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1);
+ }
+ dummy();
+ return j;
+ }
+
+ //===============================================
+ // Conditional increment
+ static int remi_sum_cond() {
+ Integer j = new Integer(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = new Integer(j + 1);
+ }
+ }
+ return j;
+ }
+
+ static int remi_sumb_cond() {
+ Integer j = Integer.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1;
+ }
+ }
+ return j;
+ }
+
+ static int remi_sumf_cond() {
+ Integer j = foob(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1;
+ }
+ }
+ return j;
+ }
+
+ static int remi_sump_cond(Integer j) {
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1;
+ }
+ }
+ return j;
+ }
+
+ static int remi_sumc_cond() {
+ Integer j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + ibc;
+ }
+ }
+ return j;
+ }
+
+ static int remi_sum2_cond() {
+ Integer j1 = new Integer(1);
+ Integer j2 = new Integer(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Integer(j1 + 1);
+ } else {
+ j2 = new Integer(j2 + 2);
+ }
+ }
+ return j1 + j2;
+ }
+
+ static int remi_sumb2_cond() {
+ Integer j1 = Integer.valueOf(1);
+ Integer j2 = Integer.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = j1 + 1;
+ } else {
+ j2 = j2 + 2;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static int remi_summ2_cond() {
+ Integer j1 = new Integer(1);
+ Integer j2 = Integer.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Integer(j1 + 1);
+ } else {
+ j2 = j2 + 2;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static int remi_sump2_cond(Integer j1) {
+ Integer j2 = Integer.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Integer(j1 + 1);
+ } else {
+ j2 = j2 + 2;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static int remi_sumc2_cond() {
+ Integer j1 = ibc;
+ Integer j2 = Integer.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = j1 + ibc;
+ } else {
+ j2 = j2 + 2;
+ }
+ }
+ return j1 + j2;
+ }
+
+
+ public static void main(String[] args) {
+ final int ntests = 70;
+
+ String[] test_name = new String[] {
+ "simple", "simpleb", "simplec", "simplef", "simplep",
+ "simple2", "simpleb2", "simplec2", "simplem2", "simplep2",
+ "simple_deop", "simpleb_deop", "simplec_deop", "simplef_deop", "simplep_deop",
+ "test", "testb", "testc", "testm", "testp",
+ "test2", "testb2", "testc2", "testm2", "testp2",
+ "test_deop", "testb_deop", "testc_deop", "testf_deop", "testp_deop",
+ "sum", "sumb", "sumc", "sumf", "sump",
+ "sum2", "sumb2", "sumc2", "summ2", "sump2",
+ "sum_deop", "sumb_deop", "sumc_deop", "sumf_deop", "sump_deop",
+ "remi_sum", "remi_sumb", "remi_sumc", "remi_sumf", "remi_sump",
+ "remi_sum2", "remi_sumb2", "remi_sumc2", "remi_summ2", "remi_sump2",
+ "remi_sum_deop", "remi_sumb_deop", "remi_sumc_deop", "remi_sumf_deop", "remi_sump_deop",
+ "remi_sum_cond", "remi_sumb_cond", "remi_sumc_cond", "remi_sumf_cond", "remi_sump_cond",
+ "remi_sum2_cond", "remi_sumb2_cond", "remi_sumc2_cond", "remi_summ2_cond", "remi_sump2_cond"
+ };
+
+ final int[] val = new int[] {
+ 71994000, 71994000, 12000, 71994000, 71994000,
+ 144000000, 144000000, 72018000, 144000000, 144000000,
+ 71994000, 71994000, 12000, 71994000, 71994000,
+ 72000000, 72000000, 36006000, 72000000, 72000000,
+ 144012000, 144012000, 72030000, 144012000, 144012000,
+ 72000000, 72000000, 36006000, 72000000, 72000000,
+ 499501, 499501, 499501, 499501, 499501,
+ 1000002, 1000002, 1000002, 1000002, 1000002,
+ 499501, 499501, 499501, 499501, 499501,
+ 1001, 1001, 1001, 1001, 1001,
+ 3002, 3002, 3002, 3002, 3002,
+ 1001, 1001, 1001, 1001, 1001,
+ 501, 501, 501, 501, 501,
+ 1502, 1502, 1502, 1502, 1502
+ };
+
+ int[] res = new int[ntests];
+ for (int i = 0; i < ntests; i++) {
+ res[i] = 0;
+ }
+
+
+ for (int i = 0; i < 12000; i++) {
+ res[0] += simple(i);
+ res[1] += simpleb(i);
+ res[2] += simplec();
+ res[3] += simplef(i);
+ res[4] += simplep(i);
+
+ res[5] += simple2(i);
+ res[6] += simpleb2(i);
+ res[7] += simplec2(i);
+ res[8] += simplem2(i);
+ res[9] += simplep2(i, i);
+
+ res[10] += simple_deop(i);
+ res[11] += simpleb_deop(i);
+ res[12] += simplec_deop(i);
+ res[13] += simplef_deop(i);
+ res[14] += simplep_deop(i);
+
+ res[15] += test(i);
+ res[16] += testb(i);
+ res[17] += testc(i);
+ res[18] += testm(i);
+ res[19] += testp(i, i);
+
+ res[20] += test2(i);
+ res[21] += testb2(i);
+ res[22] += testc2(i);
+ res[23] += testm2(i);
+ res[24] += testp2(i, i);
+
+ res[25] += test_deop(i);
+ res[26] += testb_deop(i);
+ res[27] += testc_deop(i);
+ res[28] += testf_deop(i);
+ res[29] += testp_deop(i, i);
+ }
+
+ int[] ia = new int[1000];
+ for (int i = 0; i < 1000; i++) {
+ ia[i] = i;
+ }
+
+ for (int i = 0; i < 100; i++) {
+ res[30] = sum(ia);
+ res[31] = sumb(ia);
+ res[32] = sumc(ia);
+ res[33] = sumf(ia);
+ res[34] = sump(ia, 1);
+
+ res[35] = sum2(ia);
+ res[36] = sumb2(ia);
+ res[37] = sumc2(ia);
+ res[38] = summ2(ia);
+ res[39] = sump2(ia, 1);
+
+ res[40] = sum_deop(ia);
+ res[41] = sumb_deop(ia);
+ res[42] = sumc_deop(ia);
+ res[43] = sumf_deop(ia);
+ res[44] = sump_deop(ia, 1);
+
+ res[45] = remi_sum();
+ res[46] = remi_sumb();
+ res[47] = remi_sumc();
+ res[48] = remi_sumf();
+ res[49] = remi_sump(1);
+
+ res[50] = remi_sum2();
+ res[51] = remi_sumb2();
+ res[52] = remi_sumc2();
+ res[53] = remi_summ2();
+ res[54] = remi_sump2(1);
+
+ res[55] = remi_sum_deop();
+ res[56] = remi_sumb_deop();
+ res[57] = remi_sumc_deop();
+ res[58] = remi_sumf_deop();
+ res[59] = remi_sump_deop(1);
+
+ res[60] = remi_sum_cond();
+ res[61] = remi_sumb_cond();
+ res[62] = remi_sumc_cond();
+ res[63] = remi_sumf_cond();
+ res[64] = remi_sump_cond(1);
+
+ res[65] = remi_sum2_cond();
+ res[66] = remi_sumb2_cond();
+ res[67] = remi_sumc2_cond();
+ res[68] = remi_summ2_cond();
+ res[69] = remi_sump2_cond(1);
+ }
+
+ int failed = 0;
+ for (int i = 0; i < ntests; i++) {
+ if (res[i] != val[i]) {
+ System.err.println(test_name[i] + ": " + res[i] + " != " + val[i]);
+ failed++;
+ }
+ }
+ if (failed > 0) {
+ System.err.println("Failed " + failed + " tests.");
+ throw new InternalError();
+ } else {
+ System.out.println("Passed.");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6934604/TestLongBoxing.java Wed May 08 15:08:01 2013 -0700
@@ -0,0 +1,777 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6934604
+ * @summary enable parts of EliminateAutoBox by default
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox TestLongBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestLongBoxing.dummy -XX:CompileCommand=exclude,TestLongBoxing.foo -XX:CompileCommand=exclude,TestLongBoxing.foob TestLongBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestLongBoxing.dummy -XX:CompileCommand=exclude,TestLongBoxing.foo -XX:CompileCommand=exclude,TestLongBoxing.foob TestLongBoxing
+ *
+ */
+
+public class TestLongBoxing {
+
+ static final Long ibc = new Long(1);
+
+ //===============================================
+ // Non-inlined methods to test deoptimization info
+ static void dummy() { }
+ static long foo(long i) { return i; }
+ static Long foob(long i) { return Long.valueOf(i); }
+
+
+ static long simple(long i) {
+ Long ib = new Long(i);
+ return ib;
+ }
+
+ static long simpleb(long i) {
+ Long ib = Long.valueOf(i);
+ return ib;
+ }
+
+ static long simplec() {
+ Long ib = ibc;
+ return ib;
+ }
+
+ static long simplef(long i) {
+ Long ib = foob(i);
+ return ib;
+ }
+
+ static long simplep(Long ib) {
+ return ib;
+ }
+
+ static long simple2(long i) {
+ Long ib1 = new Long(i);
+ Long ib2 = new Long(i+1);
+ return ib1 + ib2;
+ }
+
+ static long simpleb2(long i) {
+ Long ib1 = Long.valueOf(i);
+ Long ib2 = Long.valueOf(i+1);
+ return ib1 + ib2;
+ }
+
+ static long simplem2(long i) {
+ Long ib1 = new Long(i);
+ Long ib2 = Long.valueOf(i+1);
+ return ib1 + ib2;
+ }
+
+ static long simplep2(long i, Long ib1) {
+ Long ib2 = Long.valueOf(i+1);
+ return ib1 + ib2;
+ }
+
+ static long simplec2(long i) {
+ Long ib1 = ibc;
+ Long ib2 = Long.valueOf(i+1);
+ return ib1 + ib2;
+ }
+
+ //===============================================
+ static long test(long i) {
+ Long ib = new Long(i);
+ if ((i&1) == 0)
+ ib = i+1;
+ return ib;
+ }
+
+ static long testb(long i) {
+ Long ib = i;
+ if ((i&1) == 0)
+ ib = (i+1);
+ return ib;
+ }
+
+ static long testm(long i) {
+ Long ib = i;
+ if ((i&1) == 0)
+ ib = new Long(i+1);
+ return ib;
+ }
+
+ static long testp(long i, Long ib) {
+ if ((i&1) == 0)
+ ib = new Long(i+1);
+ return ib;
+ }
+
+ static long testc(long i) {
+ Long ib = ibc;
+ if ((i&1) == 0)
+ ib = new Long(i+1);
+ return ib;
+ }
+
+ static long test2(long i) {
+ Long ib1 = new Long(i);
+ Long ib2 = new Long(i+1);
+ if ((i&1) == 0) {
+ ib1 = new Long(i+1);
+ ib2 = new Long(i+2);
+ }
+ return ib1+ib2;
+ }
+
+ static long testb2(long i) {
+ Long ib1 = i;
+ Long ib2 = i+1;
+ if ((i&1) == 0) {
+ ib1 = (i+1);
+ ib2 = (i+2);
+ }
+ return ib1+ib2;
+ }
+
+ static long testm2(long i) {
+ Long ib1 = new Long(i);
+ Long ib2 = i+1;
+ if ((i&1) == 0) {
+ ib1 = new Long(i+1);
+ ib2 = (i+2);
+ }
+ return ib1+ib2;
+ }
+
+ static long testp2(long i, Long ib1) {
+ Long ib2 = i+1;
+ if ((i&1) == 0) {
+ ib1 = new Long(i+1);
+ ib2 = (i+2);
+ }
+ return ib1+ib2;
+ }
+
+ static long testc2(long i) {
+ Long ib1 = ibc;
+ Long ib2 = i+1;
+ if ((i&1) == 0) {
+ ib1 = (ibc+1);
+ ib2 = (i+2);
+ }
+ return ib1+ib2;
+ }
+
+ //===============================================
+ static long sum(long[] a) {
+ long result = 1;
+ for (Long i : a)
+ result += i;
+ return result;
+ }
+
+ static long sumb(long[] a) {
+ Long result = 1l;
+ for (Long i : a)
+ result += i;
+ return result;
+ }
+
+ static long sumc(long[] a) {
+ Long result = ibc;
+ for (Long i : a)
+ result += i;
+ return result;
+ }
+
+ static long sumf(long[] a) {
+ Long result = foob(1);
+ for (Long i : a)
+ result += i;
+ return result;
+ }
+
+ static long sump(long[] a, Long result) {
+ for (Long i : a)
+ result += i;
+ return result;
+ }
+
+ static long sum2(long[] a) {
+ long result1 = 1;
+ long result2 = 1;
+ for (Long i : a) {
+ result1 += i;
+ result2 += i + 1;
+ }
+ return result1 + result2;
+ }
+
+ static long sumb2(long[] a) {
+ Long result1 = 1l;
+ Long result2 = 1l;
+ for (Long i : a) {
+ result1 += i;
+ result2 += i + 1;
+ }
+ return result1 + result2;
+ }
+
+ static long summ2(long[] a) {
+ Long result1 = 1l;
+ Long result2 = new Long(1);
+ for (Long i : a) {
+ result1 += i;
+ result2 += new Long(i + 1);
+ }
+ return result1 + result2;
+ }
+
+ static long sump2(long[] a, Long result2) {
+ Long result1 = 1l;
+ for (Long i : a) {
+ result1 += i;
+ result2 += i + 1;
+ }
+ return result1 + result2;
+ }
+
+ static long sumc2(long[] a) {
+ Long result1 = 1l;
+ Long result2 = ibc;
+ for (Long i : a) {
+ result1 += i;
+ result2 += i + ibc;
+ }
+ return result1 + result2;
+ }
+
+ //===============================================
+ static long remi_sum() {
+ Long j = new Long(1);
+ for (int i = 0; i< 1000; i++) {
+ j = new Long(j + 1);
+ }
+ return j;
+ }
+
+ static long remi_sumb() {
+ Long j = Long.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ j = j + 1;
+ }
+ return j;
+ }
+
+ static long remi_sumf() {
+ Long j = foob(1);
+ for (int i = 0; i< 1000; i++) {
+ j = j + 1;
+ }
+ return j;
+ }
+
+ static long remi_sump(Long j) {
+ for (int i = 0; i< 1000; i++) {
+ j = new Long(j + 1);
+ }
+ return j;
+ }
+
+ static long remi_sumc() {
+ Long j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = j + ibc;
+ }
+ return j;
+ }
+
+ static long remi_sum2() {
+ Long j1 = new Long(1);
+ Long j2 = new Long(1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Long(j1 + 1);
+ j2 = new Long(j2 + 2);
+ }
+ return j1 + j2;
+ }
+
+ static long remi_sumb2() {
+ Long j1 = Long.valueOf(1);
+ Long j2 = Long.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = j1 + 1;
+ j2 = j2 + 2;
+ }
+ return j1 + j2;
+ }
+
+ static long remi_summ2() {
+ Long j1 = new Long(1);
+ Long j2 = Long.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Long(j1 + 1);
+ j2 = j2 + 2;
+ }
+ return j1 + j2;
+ }
+
+ static long remi_sump2(Long j1) {
+ Long j2 = Long.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Long(j1 + 1);
+ j2 = j2 + 2;
+ }
+ return j1 + j2;
+ }
+
+ static long remi_sumc2() {
+ Long j1 = ibc;
+ Long j2 = Long.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = j1 + ibc;
+ j2 = j2 + 2;
+ }
+ return j1 + j2;
+ }
+
+
+ //===============================================
+ // Safepointa and debug info for deoptimization
+ static long simple_deop(long i) {
+ Long ib = new Long(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static long simpleb_deop(long i) {
+ Long ib = Long.valueOf(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static long simplef_deop(long i) {
+ Long ib = foob(i);
+ dummy();
+ return ib;
+ }
+
+ static long simplep_deop(Long ib) {
+ dummy();
+ return ib;
+ }
+
+ static long simplec_deop(long i) {
+ Long ib = ibc;
+ dummy();
+ return ib;
+ }
+
+ static long test_deop(long i) {
+ Long ib = new Long(foo(i));
+ if ((i&1) == 0)
+ ib = foo(i+1);
+ dummy();
+ return ib;
+ }
+
+ static long testb_deop(long i) {
+ Long ib = foo(i);
+ if ((i&1) == 0)
+ ib = foo(i+1);
+ dummy();
+ return ib;
+ }
+
+ static long testf_deop(long i) {
+ Long ib = foob(i);
+ if ((i&1) == 0)
+ ib = foo(i+1);
+ dummy();
+ return ib;
+ }
+
+ static long testp_deop(long i, Long ib) {
+ if ((i&1) == 0)
+ ib = foo(i+1);
+ dummy();
+ return ib;
+ }
+
+ static long testc_deop(long i) {
+ Long ib = ibc;
+ if ((i&1) == 0)
+ ib = foo(i+1);
+ dummy();
+ return ib;
+ }
+
+ static long sum_deop(long[] a) {
+ long result = 1;
+ for (Long i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static long sumb_deop(long[] a) {
+ Long result = 1l;
+ for (Long i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static long sumf_deop(long[] a) {
+ Long result = 1l;
+ for (Long i : a)
+ result += foob(i);
+ dummy();
+ return result;
+ }
+
+ static long sump_deop(long[] a, Long result) {
+ for (Long i : a)
+ result += foob(i);
+ dummy();
+ return result;
+ }
+
+ static long sumc_deop(long[] a) {
+ Long result = ibc;
+ for (Long i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static long remi_sum_deop() {
+ Long j = new Long(foo(1));
+ for (int i = 0; i< 1000; i++) {
+ j = new Long(foo(j + 1));
+ }
+ dummy();
+ return j;
+ }
+
+ static long remi_sumb_deop() {
+ Long j = Long.valueOf(foo(1));
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1);
+ }
+ dummy();
+ return j;
+ }
+
+ static long remi_sumf_deop() {
+ Long j = foob(1);
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1);
+ }
+ dummy();
+ return j;
+ }
+
+ static long remi_sump_deop(Long j) {
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1);
+ }
+ dummy();
+ return j;
+ }
+
+ static long remi_sumc_deop() {
+ Long j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = foo(j + 1);
+ }
+ dummy();
+ return j;
+ }
+
+ //===============================================
+ // Conditional increment
+ static long remi_sum_cond() {
+ Long j = new Long(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = new Long(j + 1);
+ }
+ }
+ return j;
+ }
+
+ static long remi_sumb_cond() {
+ Long j = Long.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1;
+ }
+ }
+ return j;
+ }
+
+ static long remi_sumf_cond() {
+ Long j = foob(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1;
+ }
+ }
+ return j;
+ }
+
+ static long remi_sump_cond(Long j) {
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + 1;
+ }
+ }
+ return j;
+ }
+
+ static long remi_sumc_cond() {
+ Long j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = j + ibc;
+ }
+ }
+ return j;
+ }
+
+ static long remi_sum2_cond() {
+ Long j1 = new Long(1);
+ Long j2 = new Long(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Long(j1 + 1);
+ } else {
+ j2 = new Long(j2 + 2);
+ }
+ }
+ return j1 + j2;
+ }
+
+ static long remi_sumb2_cond() {
+ Long j1 = Long.valueOf(1);
+ Long j2 = Long.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = j1 + 1;
+ } else {
+ j2 = j2 + 2;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static long remi_summ2_cond() {
+ Long j1 = new Long(1);
+ Long j2 = Long.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Long(j1 + 1);
+ } else {
+ j2 = j2 + 2;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static long remi_sump2_cond(Long j1) {
+ Long j2 = Long.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Long(j1 + 1);
+ } else {
+ j2 = j2 + 2;
+ }
+ }
+ return j1 + j2;
+ }
+
+ static long remi_sumc2_cond() {
+ Long j1 = ibc;
+ Long j2 = Long.valueOf(1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = j1 + ibc;
+ } else {
+ j2 = j2 + 2;
+ }
+ }
+ return j1 + j2;
+ }
+
+
+ public static void main(String[] args) {
+ final int ntests = 70;
+
+ String[] test_name = new String[] {
+ "simple", "simpleb", "simplec", "simplef", "simplep",
+ "simple2", "simpleb2", "simplec2", "simplem2", "simplep2",
+ "simple_deop", "simpleb_deop", "simplec_deop", "simplef_deop", "simplep_deop",
+ "test", "testb", "testc", "testm", "testp",
+ "test2", "testb2", "testc2", "testm2", "testp2",
+ "test_deop", "testb_deop", "testc_deop", "testf_deop", "testp_deop",
+ "sum", "sumb", "sumc", "sumf", "sump",
+ "sum2", "sumb2", "sumc2", "summ2", "sump2",
+ "sum_deop", "sumb_deop", "sumc_deop", "sumf_deop", "sump_deop",
+ "remi_sum", "remi_sumb", "remi_sumc", "remi_sumf", "remi_sump",
+ "remi_sum2", "remi_sumb2", "remi_sumc2", "remi_summ2", "remi_sump2",
+ "remi_sum_deop", "remi_sumb_deop", "remi_sumc_deop", "remi_sumf_deop", "remi_sump_deop",
+ "remi_sum_cond", "remi_sumb_cond", "remi_sumc_cond", "remi_sumf_cond", "remi_sump_cond",
+ "remi_sum2_cond", "remi_sumb2_cond", "remi_sumc2_cond", "remi_summ2_cond", "remi_sump2_cond"
+ };
+
+ final long[] val = new long[] {
+ 71994000, 71994000, 12000, 71994000, 71994000,
+ 144000000, 144000000, 72018000, 144000000, 144000000,
+ 71994000, 71994000, 12000, 71994000, 71994000,
+ 72000000, 72000000, 36006000, 72000000, 72000000,
+ 144012000, 144012000, 72030000, 144012000, 144012000,
+ 72000000, 72000000, 36006000, 72000000, 72000000,
+ 499501, 499501, 499501, 499501, 499501,
+ 1000002, 1000002, 1000002, 1000002, 1000002,
+ 499501, 499501, 499501, 499501, 499501,
+ 1001, 1001, 1001, 1001, 1001,
+ 3002, 3002, 3002, 3002, 3002,
+ 1001, 1001, 1001, 1001, 1001,
+ 501, 501, 501, 501, 501,
+ 1502, 1502, 1502, 1502, 1502
+ };
+
+ long[] res = new long[ntests];
+ for (int i = 0; i < ntests; i++) {
+ res[i] = 0;
+ }
+
+
+ for (long i = 0; i < 12000; i++) {
+ res[0] += simple(i);
+ res[1] += simpleb(i);
+ res[2] += simplec();
+ res[3] += simplef(i);
+ res[4] += simplep(i);
+
+ res[5] += simple2(i);
+ res[6] += simpleb2(i);
+ res[7] += simplec2(i);
+ res[8] += simplem2(i);
+ res[9] += simplep2(i, i);
+
+ res[10] += simple_deop(i);
+ res[11] += simpleb_deop(i);
+ res[12] += simplec_deop(i);
+ res[13] += simplef_deop(i);
+ res[14] += simplep_deop(i);
+
+ res[15] += test(i);
+ res[16] += testb(i);
+ res[17] += testc(i);
+ res[18] += testm(i);
+ res[19] += testp(i, i);
+
+ res[20] += test2(i);
+ res[21] += testb2(i);
+ res[22] += testc2(i);
+ res[23] += testm2(i);
+ res[24] += testp2(i, i);
+
+ res[25] += test_deop(i);
+ res[26] += testb_deop(i);
+ res[27] += testc_deop(i);
+ res[28] += testf_deop(i);
+ res[29] += testp_deop(i, i);
+ }
+
+ long[] ia = new long[1000];
+ for (int i = 0; i < 1000; i++) {
+ ia[i] = i;
+ }
+
+ for (int i = 0; i < 100; i++) {
+ res[30] = sum(ia);
+ res[31] = sumb(ia);
+ res[32] = sumc(ia);
+ res[33] = sumf(ia);
+ res[34] = sump(ia, (long)1);
+
+ res[35] = sum2(ia);
+ res[36] = sumb2(ia);
+ res[37] = sumc2(ia);
+ res[38] = summ2(ia);
+ res[39] = sump2(ia, (long)1);
+
+ res[40] = sum_deop(ia);
+ res[41] = sumb_deop(ia);
+ res[42] = sumc_deop(ia);
+ res[43] = sumf_deop(ia);
+ res[44] = sump_deop(ia, (long)1);
+
+ res[45] = remi_sum();
+ res[46] = remi_sumb();
+ res[47] = remi_sumc();
+ res[48] = remi_sumf();
+ res[49] = remi_sump((long)1);
+
+ res[50] = remi_sum2();
+ res[51] = remi_sumb2();
+ res[52] = remi_sumc2();
+ res[53] = remi_summ2();
+ res[54] = remi_sump2((long)1);
+
+ res[55] = remi_sum_deop();
+ res[56] = remi_sumb_deop();
+ res[57] = remi_sumc_deop();
+ res[58] = remi_sumf_deop();
+ res[59] = remi_sump_deop((long)1);
+
+ res[60] = remi_sum_cond();
+ res[61] = remi_sumb_cond();
+ res[62] = remi_sumc_cond();
+ res[63] = remi_sumf_cond();
+ res[64] = remi_sump_cond((long)1);
+
+ res[65] = remi_sum2_cond();
+ res[66] = remi_sumb2_cond();
+ res[67] = remi_sumc2_cond();
+ res[68] = remi_summ2_cond();
+ res[69] = remi_sump2_cond((long)1);
+ }
+
+ int failed = 0;
+ for (int i = 0; i < ntests; i++) {
+ if (res[i] != val[i]) {
+ System.err.println(test_name[i] + ": " + res[i] + " != " + val[i]);
+ failed++;
+ }
+ }
+ if (failed > 0) {
+ System.err.println("Failed " + failed + " tests.");
+ throw new InternalError();
+ } else {
+ System.out.println("Passed.");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6934604/TestShortBoxing.java Wed May 08 15:08:01 2013 -0700
@@ -0,0 +1,777 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6934604
+ * @summary enable parts of EliminateAutoBox by default
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox TestShortBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestShortBoxing.dummy -XX:CompileCommand=exclude,TestShortBoxing.foo -XX:CompileCommand=exclude,TestShortBoxing.foob TestShortBoxing
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-EliminateAutoBox
+ * -XX:CompileCommand=exclude,TestShortBoxing.dummy -XX:CompileCommand=exclude,TestShortBoxing.foo -XX:CompileCommand=exclude,TestShortBoxing.foob TestShortBoxing
+ *
+ */
+
+public class TestShortBoxing {
+
+ static final Short ibc = new Short((short)1);
+
+ //===============================================
+ // Non-inlined methods to test deoptimization info
+ static void dummy() { }
+ static short foo(short i) { return i; }
+ static Short foob(short i) { return Short.valueOf(i); }
+
+
+ static short simple(short i) {
+ Short ib = new Short(i);
+ return ib;
+ }
+
+ static short simpleb(short i) {
+ Short ib = Short.valueOf(i);
+ return ib;
+ }
+
+ static short simplec() {
+ Short ib = ibc;
+ return ib;
+ }
+
+ static short simplef(short i) {
+ Short ib = foob(i);
+ return ib;
+ }
+
+ static short simplep(Short ib) {
+ return ib;
+ }
+
+ static short simple2(short i) {
+ Short ib1 = new Short(i);
+ Short ib2 = new Short((short)(i+1));
+ return (short)(ib1 + ib2);
+ }
+
+ static short simpleb2(short i) {
+ Short ib1 = Short.valueOf(i);
+ Short ib2 = Short.valueOf((short)(i+1));
+ return (short)(ib1 + ib2);
+ }
+
+ static short simplem2(short i) {
+ Short ib1 = new Short(i);
+ Short ib2 = Short.valueOf((short)(i+1));
+ return (short)(ib1 + ib2);
+ }
+
+ static short simplep2(short i, Short ib1) {
+ Short ib2 = Short.valueOf((short)(i+1));
+ return (short)(ib1 + ib2);
+ }
+
+ static short simplec2(short i) {
+ Short ib1 = ibc;
+ Short ib2 = Short.valueOf((short)(i+1));
+ return (short)(ib1 + ib2);
+ }
+
+ //===============================================
+ static short test(short i) {
+ Short ib = new Short(i);
+ if ((i&1) == 0)
+ ib = (short)(i+1);
+ return ib;
+ }
+
+ static short testb(short i) {
+ Short ib = i;
+ if ((i&1) == 0)
+ ib = (short)(i+1);
+ return ib;
+ }
+
+ static short testm(short i) {
+ Short ib = i;
+ if ((i&1) == 0)
+ ib = new Short((short)(i+1));
+ return ib;
+ }
+
+ static short testp(short i, Short ib) {
+ if ((i&1) == 0)
+ ib = new Short((short)(i+1));
+ return ib;
+ }
+
+ static short testc(short i) {
+ Short ib = ibc;
+ if ((i&1) == 0)
+ ib = new Short((short)(i+1));
+ return ib;
+ }
+
+ static short test2(short i) {
+ Short ib1 = new Short(i);
+ Short ib2 = new Short((short)(i+1));
+ if ((i&1) == 0) {
+ ib1 = new Short((short)(i+1));
+ ib2 = new Short((short)(i+2));
+ }
+ return (short)(ib1+ib2);
+ }
+
+ static short testb2(short i) {
+ Short ib1 = i;
+ Short ib2 = (short)(i+1);
+ if ((i&1) == 0) {
+ ib1 = (short)(i+1);
+ ib2 = (short)(i+2);
+ }
+ return (short)(ib1 + ib2);
+ }
+
+ static short testm2(short i) {
+ Short ib1 = new Short(i);
+ Short ib2 = (short)(i+1);
+ if ((i&1) == 0) {
+ ib1 = new Short((short)(i+1));
+ ib2 = (short)(i+2);
+ }
+ return (short)(ib1 + ib2);
+ }
+
+ static short testp2(short i, Short ib1) {
+ Short ib2 = (short)(i+1);
+ if ((i&1) == 0) {
+ ib1 = new Short((short)(i+1));
+ ib2 = (short)(i+2);
+ }
+ return (short)(ib1 + ib2);
+ }
+
+ static short testc2(short i) {
+ Short ib1 = ibc;
+ Short ib2 = (short)(i+1);
+ if ((i&1) == 0) {
+ ib1 = (short)(ibc+1);
+ ib2 = (short)(i+2);
+ }
+ return (short)(ib1 + ib2);
+ }
+
+ //===============================================
+ static short sum(short[] a) {
+ short result = 1;
+ for (Short i : a)
+ result += i;
+ return result;
+ }
+
+ static short sumb(short[] a) {
+ Short result = 1;
+ for (Short i : a)
+ result = (short)(result + i);
+ return result;
+ }
+
+ static short sumc(short[] a) {
+ Short result = ibc;
+ for (Short i : a)
+ result = (short)(result + i);
+ return result;
+ }
+
+ static short sumf(short[] a) {
+ Short result = foob((short)1);
+ for (Short i : a)
+ result = (short)(result + i);
+ return result;
+ }
+
+ static short sump(short[] a, Short result) {
+ for (Short i : a)
+ result = (short)(result + i);
+ return result;
+ }
+
+ static short sum2(short[] a) {
+ short result1 = 1;
+ short result2 = 1;
+ for (Short i : a) {
+ result1 += i;
+ result2 += i + 1;
+ }
+ return (short)(result1 + result2);
+ }
+
+ static short sumb2(short[] a) {
+ Short result1 = 1;
+ Short result2 = 1;
+ for (Short i : a) {
+ result1 = (short)(result1 + i);
+ result2 = (short)(result2 + i + 1);
+ }
+ return (short)(result1 + result2);
+ }
+
+ static short summ2(short[] a) {
+ Short result1 = 1;
+ Short result2 = new Short((short)1);
+ for (Short i : a) {
+ result1 = (short)(result1 + i);
+ result2 = (short)(result2 + new Short((short)(i + 1)));
+ }
+ return (short)(result1 + result2);
+ }
+
+ static short sump2(short[] a, Short result2) {
+ Short result1 = 1;
+ for (Short i : a) {
+ result1 = (short)(result1 + i);
+ result2 = (short)(result2 + i + 1);
+ }
+ return (short)(result1 + result2);
+ }
+
+ static short sumc2(short[] a) {
+ Short result1 = 1;
+ Short result2 = ibc;
+ for (Short i : a) {
+ result1 = (short)(result1 + i);
+ result2 = (short)(result2 + i + ibc);
+ }
+ return (short)(result1 + result2);
+ }
+
+ //===============================================
+ static short remi_sum() {
+ Short j = new Short((short)1);
+ for (int i = 0; i< 1000; i++) {
+ j = new Short((short)(j + 1));
+ }
+ return j;
+ }
+
+ static short remi_sumb() {
+ Short j = Short.valueOf((short)1);
+ for (int i = 0; i< 1000; i++) {
+ j = (short)(j + 1);
+ }
+ return j;
+ }
+
+ static short remi_sumf() {
+ Short j = foob((short)1);
+ for (int i = 0; i< 1000; i++) {
+ j = (short)(j + 1);
+ }
+ return j;
+ }
+
+ static short remi_sump(Short j) {
+ for (int i = 0; i< 1000; i++) {
+ j = new Short((short)(j + 1));
+ }
+ return j;
+ }
+
+ static short remi_sumc() {
+ Short j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = (short)(j + ibc);
+ }
+ return j;
+ }
+
+ static short remi_sum2() {
+ Short j1 = new Short((short)1);
+ Short j2 = new Short((short)1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Short((short)(j1 + 1));
+ j2 = new Short((short)(j2 + 2));
+ }
+ return (short)(j1 + j2);
+ }
+
+ static short remi_sumb2() {
+ Short j1 = Short.valueOf((short)1);
+ Short j2 = Short.valueOf((short)1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = (short)(j1 + 1);
+ j2 = (short)(j2 + 2);
+ }
+ return (short)(j1 + j2);
+ }
+
+ static short remi_summ2() {
+ Short j1 = new Short((short)1);
+ Short j2 = Short.valueOf((short)1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Short((short)(j1 + 1));
+ j2 = (short)(j2 + 2);
+ }
+ return (short)(j1 + j2);
+ }
+
+ static short remi_sump2(Short j1) {
+ Short j2 = Short.valueOf((short)1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = new Short((short)(j1 + 1));
+ j2 = (short)(j2 + 2);
+ }
+ return (short)(j1 + j2);
+ }
+
+ static short remi_sumc2() {
+ Short j1 = ibc;
+ Short j2 = Short.valueOf((short)1);
+ for (int i = 0; i< 1000; i++) {
+ j1 = (short)(j1 + ibc);
+ j2 = (short)(j2 + 2);
+ }
+ return (short)(j1 + j2);
+ }
+
+
+ //===============================================
+ // Safepointa and debug info for deoptimization
+ static short simple_deop(short i) {
+ Short ib = new Short(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static short simpleb_deop(short i) {
+ Short ib = Short.valueOf(foo(i));
+ dummy();
+ return ib;
+ }
+
+ static short simplef_deop(short i) {
+ Short ib = foob(i);
+ dummy();
+ return ib;
+ }
+
+ static short simplep_deop(Short ib) {
+ dummy();
+ return ib;
+ }
+
+ static short simplec_deop(short i) {
+ Short ib = ibc;
+ dummy();
+ return ib;
+ }
+
+ static short test_deop(short i) {
+ Short ib = new Short(foo(i));
+ if ((i&1) == 0)
+ ib = foo((short)(i+1));
+ dummy();
+ return ib;
+ }
+
+ static short testb_deop(short i) {
+ Short ib = foo(i);
+ if ((i&1) == 0)
+ ib = foo((short)(i+1));
+ dummy();
+ return ib;
+ }
+
+ static short testf_deop(short i) {
+ Short ib = foob(i);
+ if ((i&1) == 0)
+ ib = foo((short)(i+1));
+ dummy();
+ return ib;
+ }
+
+ static short testp_deop(short i, Short ib) {
+ if ((i&1) == 0)
+ ib = foo((short)(i+1));
+ dummy();
+ return ib;
+ }
+
+ static short testc_deop(short i) {
+ Short ib = ibc;
+ if ((i&1) == 0)
+ ib = foo((short)(i+1));
+ dummy();
+ return ib;
+ }
+
+ static short sum_deop(short[] a) {
+ short result = 1;
+ for (Short i : a)
+ result += foo(i);
+ dummy();
+ return result;
+ }
+
+ static short sumb_deop(short[] a) {
+ Short result = 1;
+ for (Short i : a)
+ result = (short)(result + foo(i));
+ dummy();
+ return result;
+ }
+
+ static short sumf_deop(short[] a) {
+ Short result = 1;
+ for (Short i : a)
+ result = (short)(result + foob(i));
+ dummy();
+ return result;
+ }
+
+ static short sump_deop(short[] a, Short result) {
+ for (Short i : a)
+ result = (short)(result + foob(i));
+ dummy();
+ return result;
+ }
+
+ static short sumc_deop(short[] a) {
+ Short result = ibc;
+ for (Short i : a)
+ result = (short)(result + foo(i));
+ dummy();
+ return result;
+ }
+
+ static short remi_sum_deop() {
+ Short j = new Short(foo((short)1));
+ for (int i = 0; i< 1000; i++) {
+ j = new Short(foo((short)(j + 1)));
+ }
+ dummy();
+ return j;
+ }
+
+ static short remi_sumb_deop() {
+ Short j = Short.valueOf(foo((short)1));
+ for (int i = 0; i< 1000; i++) {
+ j = foo((short)(j + 1));
+ }
+ dummy();
+ return j;
+ }
+
+ static short remi_sumf_deop() {
+ Short j = foob((short)1);
+ for (int i = 0; i< 1000; i++) {
+ j = foo((short)(j + 1));
+ }
+ dummy();
+ return j;
+ }
+
+ static short remi_sump_deop(Short j) {
+ for (int i = 0; i< 1000; i++) {
+ j = foo((short)(j + 1));
+ }
+ dummy();
+ return j;
+ }
+
+ static short remi_sumc_deop() {
+ Short j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ j = foo((short)(j + 1));
+ }
+ dummy();
+ return j;
+ }
+
+ //===============================================
+ // Conditional increment
+ static short remi_sum_cond() {
+ Short j = new Short((short)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = new Short((short)(j + 1));
+ }
+ }
+ return j;
+ }
+
+ static short remi_sumb_cond() {
+ Short j = Short.valueOf((short)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = (short)(j + 1);
+ }
+ }
+ return j;
+ }
+
+ static short remi_sumf_cond() {
+ Short j = foob((short)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = (short)(j + 1);
+ }
+ }
+ return j;
+ }
+
+ static short remi_sump_cond(Short j) {
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = (short)(j + 1);
+ }
+ }
+ return j;
+ }
+
+ static short remi_sumc_cond() {
+ Short j = ibc;
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j = (short)(j + ibc);
+ }
+ }
+ return j;
+ }
+
+ static short remi_sum2_cond() {
+ Short j1 = new Short((short)1);
+ Short j2 = new Short((short)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Short((short)(j1 + 1));
+ } else {
+ j2 = new Short((short)(j2 + 2));
+ }
+ }
+ return (short)(j1 + j2);
+ }
+
+ static short remi_sumb2_cond() {
+ Short j1 = Short.valueOf((short)1);
+ Short j2 = Short.valueOf((short)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = (short)(j1 + 1);
+ } else {
+ j2 = (short)(j2 + 2);
+ }
+ }
+ return (short)(j1 + j2);
+ }
+
+ static short remi_summ2_cond() {
+ Short j1 = new Short((short)1);
+ Short j2 = Short.valueOf((short)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Short((short)(j1 + 1));
+ } else {
+ j2 = (short)(j2 + 2);
+ }
+ }
+ return (short)(j1 + j2);
+ }
+
+ static short remi_sump2_cond(Short j1) {
+ Short j2 = Short.valueOf((short)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = new Short((short)(j1 + 1));
+ } else {
+ j2 = (short)(j2 + 2);
+ }
+ }
+ return (short)(j1 + j2);
+ }
+
+ static short remi_sumc2_cond() {
+ Short j1 = ibc;
+ Short j2 = Short.valueOf((short)1);
+ for (int i = 0; i< 1000; i++) {
+ if ((i&1) == 0) {
+ j1 = (short)(j1 + ibc);
+ } else {
+ j2 = (short)(j2 + 2);
+ }
+ }
+ return (short)(j1 + j2);
+ }
+
+
+ public static void main(String[] args) {
+ final int ntests = 70;
+
+ String[] test_name = new String[] {
+ "simple", "simpleb", "simplec", "simplef", "simplep",
+ "simple2", "simpleb2", "simplec2", "simplem2", "simplep2",
+ "simple_deop", "simpleb_deop", "simplec_deop", "simplef_deop", "simplep_deop",
+ "test", "testb", "testc", "testm", "testp",
+ "test2", "testb2", "testc2", "testm2", "testp2",
+ "test_deop", "testb_deop", "testc_deop", "testf_deop", "testp_deop",
+ "sum", "sumb", "sumc", "sumf", "sump",
+ "sum2", "sumb2", "sumc2", "summ2", "sump2",
+ "sum_deop", "sumb_deop", "sumc_deop", "sumf_deop", "sump_deop",
+ "remi_sum", "remi_sumb", "remi_sumc", "remi_sumf", "remi_sump",
+ "remi_sum2", "remi_sumb2", "remi_sumc2", "remi_summ2", "remi_sump2",
+ "remi_sum_deop", "remi_sumb_deop", "remi_sumc_deop", "remi_sumf_deop", "remi_sump_deop",
+ "remi_sum_cond", "remi_sumb_cond", "remi_sumc_cond", "remi_sumf_cond", "remi_sump_cond",
+ "remi_sum2_cond", "remi_sumb2_cond", "remi_sumc2_cond", "remi_summ2_cond", "remi_sump2_cond"
+ };
+
+ final int[] val = new int[] {
+ 71994000, 71994000, 12000, 71994000, 71994000,
+ 144000000, 144000000, 72018000, 144000000, 144000000,
+ 71994000, 71994000, 12000, 71994000, 71994000,
+ 72000000, 72000000, 36006000, 72000000, 72000000,
+ 144012000, 144012000, 72030000, 144012000, 144012000,
+ 72000000, 72000000, 36006000, 72000000, 72000000,
+ -24787, -24787, -24787, -24787, -24787,
+ 16962, 16962, 16962, 16962, 16962,
+ -24787, -24787, -24787, -24787, -24787,
+ 1001, 1001, 1001, 1001, 1001,
+ 3002, 3002, 3002, 3002, 3002,
+ 1001, 1001, 1001, 1001, 1001,
+ 501, 501, 501, 501, 501,
+ 1502, 1502, 1502, 1502, 1502
+ };
+
+ int[] res = new int[ntests];
+ for (int i = 0; i < ntests; i++) {
+ res[i] = 0;
+ }
+
+
+ for (int i = 0; i < 12000; i++) {
+ res[0] += simple((short)i);
+ res[1] += simpleb((short)i);
+ res[2] += simplec();
+ res[3] += simplef((short)i);
+ res[4] += simplep((short)i);
+
+ res[5] += simple2((short)i);
+ res[6] += simpleb2((short)i);
+ res[7] += simplec2((short)i);
+ res[8] += simplem2((short)i);
+ res[9] += simplep2((short)i, (short)i);
+
+ res[10] += simple_deop((short)i);
+ res[11] += simpleb_deop((short)i);
+ res[12] += simplec_deop((short)i);
+ res[13] += simplef_deop((short)i);
+ res[14] += simplep_deop((short)i);
+
+ res[15] += test((short)i);
+ res[16] += testb((short)i);
+ res[17] += testc((short)i);
+ res[18] += testm((short)i);
+ res[19] += testp((short)i, (short)i);
+
+ res[20] += test2((short)i);
+ res[21] += testb2((short)i);
+ res[22] += testc2((short)i);
+ res[23] += testm2((short)i);
+ res[24] += testp2((short)i, (short)i);
+
+ res[25] += test_deop((short)i);
+ res[26] += testb_deop((short)i);
+ res[27] += testc_deop((short)i);
+ res[28] += testf_deop((short)i);
+ res[29] += testp_deop((short)i, (short)i);
+ }
+
+ short[] ia = new short[1000];
+ for (int i = 0; i < 1000; i++) {
+ ia[i] = (short)i;
+ }
+
+ for (int i = 0; i < 100; i++) {
+ res[30] = sum(ia);
+ res[31] = sumb(ia);
+ res[32] = sumc(ia);
+ res[33] = sumf(ia);
+ res[34] = sump(ia, (short)1);
+
+ res[35] = sum2(ia);
+ res[36] = sumb2(ia);
+ res[37] = sumc2(ia);
+ res[38] = summ2(ia);
+ res[39] = sump2(ia, (short)1);
+
+ res[40] = sum_deop(ia);
+ res[41] = sumb_deop(ia);
+ res[42] = sumc_deop(ia);
+ res[43] = sumf_deop(ia);
+ res[44] = sump_deop(ia, (short)1);
+
+ res[45] = remi_sum();
+ res[46] = remi_sumb();
+ res[47] = remi_sumc();
+ res[48] = remi_sumf();
+ res[49] = remi_sump((short)1);
+
+ res[50] = remi_sum2();
+ res[51] = remi_sumb2();
+ res[52] = remi_sumc2();
+ res[53] = remi_summ2();
+ res[54] = remi_sump2((short)1);
+
+ res[55] = remi_sum_deop();
+ res[56] = remi_sumb_deop();
+ res[57] = remi_sumc_deop();
+ res[58] = remi_sumf_deop();
+ res[59] = remi_sump_deop((short)1);
+
+ res[60] = remi_sum_cond();
+ res[61] = remi_sumb_cond();
+ res[62] = remi_sumc_cond();
+ res[63] = remi_sumf_cond();
+ res[64] = remi_sump_cond((short)1);
+
+ res[65] = remi_sum2_cond();
+ res[66] = remi_sumb2_cond();
+ res[67] = remi_sumc2_cond();
+ res[68] = remi_summ2_cond();
+ res[69] = remi_sump2_cond((short)1);
+ }
+
+ int failed = 0;
+ for (int i = 0; i < ntests; i++) {
+ if (res[i] != val[i]) {
+ System.err.println(test_name[i] + ": " + res[i] + " != " + val[i]);
+ failed++;
+ }
+ }
+ if (failed > 0) {
+ System.err.println("Failed " + failed + " tests.");
+ throw new InternalError();
+ } else {
+ System.out.println("Passed.");
+ }
+ }
+}