# HG changeset patch # User kvn # Date 1368050881 25200 # Node ID 6f3fd5150b67cddeef94377fa4f4a1f6f35846ce # Parent aabf54ccedb18ab4cf15614eb4b64703b5479eb4 6934604: enable parts of EliminateAutoBox by default Summary: Resurrected autobox elimination code and enabled part of it by default. Reviewed-by: roland, twisti diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/ci/ciInstanceKlass.cpp --- a/src/share/vm/ci/ciInstanceKlass.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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? diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/ci/ciInstanceKlass.hpp --- a/src/share/vm/ci/ciInstanceKlass.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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)); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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) { diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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") \ diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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) diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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"); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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") \ \ diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/c2compiler.cpp --- a/src/share/vm/opto/c2compiler.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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(). diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/callGenerator.cpp --- a/src/share/vm/opto/callGenerator.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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. diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/callGenerator.hpp --- a/src/share/vm/opto/callGenerator.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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, diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/callnode.cpp --- a/src/share/vm/opto/callnode.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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<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"); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/callnode.hpp --- a/src/share/vm/opto/callnode.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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? diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/cfgnode.cpp --- a/src/share/vm/opto/cfgnode.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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; iprint_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) { diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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 _string_late_inlines; // same but for string operations + GrowableArray _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* 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 diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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) { diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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 "); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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---------------------------- diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/ifnode.cpp --- a/src/share/vm/opto/ifnode.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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 && diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/loopPredicate.cpp --- a/src/share/vm/opto/loopPredicate.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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(); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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; diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/macro.hpp --- a/src/share/vm/opto/macro.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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 & safepoints); bool scalar_replacement(AllocateNode *alloc, GrowableArray & 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); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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 ==> X + (Y>>Z) + // but for boxing cache access we know that X<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 diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/memnode.hpp --- a/src/share/vm/opto/memnode.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/multnode.cpp --- a/src/share/vm/opto/multnode.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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------------------------------------ diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/multnode.hpp --- a/src/share/vm/opto/multnode.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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 diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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' diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/parse1.cpp --- a/src/share/vm/opto/parse1.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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(); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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(); } diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/parse3.cpp --- a/src/share/vm/opto/parse3.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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 diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/parseHelper.cpp --- a/src/share/vm/opto/parseHelper.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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 diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/phase.cpp --- a/src/share/vm/opto/phase.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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()); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/phase.hpp --- a/src/share/vm/opto/phase.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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; diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/phaseX.cpp --- a/src/share/vm/opto/phaseX.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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"); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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--------------------------------------- diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp Mon May 06 19:49:23 2013 -0700 +++ b/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 diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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); diff -r aabf54ccedb1 -r 6f3fd5150b67 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Mon May 06 19:49:23 2013 -0700 +++ b/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*) \ diff -r aabf54ccedb1 -r 6f3fd5150b67 test/compiler/6934604/TestByteBoxing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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."); + } + } +} diff -r aabf54ccedb1 -r 6f3fd5150b67 test/compiler/6934604/TestDoubleBoxing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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."); + } + } +} diff -r aabf54ccedb1 -r 6f3fd5150b67 test/compiler/6934604/TestFloatBoxing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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."); + } + } +} diff -r aabf54ccedb1 -r 6f3fd5150b67 test/compiler/6934604/TestIntBoxing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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."); + } + } +} diff -r aabf54ccedb1 -r 6f3fd5150b67 test/compiler/6934604/TestLongBoxing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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."); + } + } +} diff -r aabf54ccedb1 -r 6f3fd5150b67 test/compiler/6934604/TestShortBoxing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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."); + } + } +}