6395208: Elide autoboxing for calls to HashMap.get(int) and HashMap.get(long)
Reviewed-by: kvn, rasbold
This commit is contained in:
parent
5fa349cc42
commit
10c473e425
43
hotspot/src/share/vm/ci/ciObjArray.cpp
Normal file
43
hotspot/src/share/vm/ci/ciObjArray.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "incls/_precompiled.incl"
|
||||||
|
#include "incls/_ciObjArray.cpp.incl"
|
||||||
|
|
||||||
|
// ciObjArray
|
||||||
|
//
|
||||||
|
// This class represents an objArrayOop in the HotSpot virtual
|
||||||
|
// machine.
|
||||||
|
|
||||||
|
ciObject* ciObjArray::obj_at(int index) {
|
||||||
|
VM_ENTRY_MARK;
|
||||||
|
objArrayOop array = get_objArrayOop();
|
||||||
|
if (index < 0 || index >= array->length()) return NULL;
|
||||||
|
oop o = array->obj_at(index);
|
||||||
|
if (o == NULL) {
|
||||||
|
return ciNullObject::make();
|
||||||
|
} else {
|
||||||
|
return CURRENT_ENV->get_object(o);
|
||||||
|
}
|
||||||
|
}
|
@ -43,4 +43,6 @@ protected:
|
|||||||
public:
|
public:
|
||||||
// What kind of ciObject is this?
|
// What kind of ciObject is this?
|
||||||
bool is_obj_array() { return true; }
|
bool is_obj_array() { return true; }
|
||||||
|
|
||||||
|
ciObject* obj_at(int index);
|
||||||
};
|
};
|
||||||
|
@ -58,12 +58,17 @@
|
|||||||
template(java_lang_ThreadDeath, "java/lang/ThreadDeath") \
|
template(java_lang_ThreadDeath, "java/lang/ThreadDeath") \
|
||||||
template(java_lang_Boolean, "java/lang/Boolean") \
|
template(java_lang_Boolean, "java/lang/Boolean") \
|
||||||
template(java_lang_Character, "java/lang/Character") \
|
template(java_lang_Character, "java/lang/Character") \
|
||||||
|
template(java_lang_Character_CharacterCache, "java/lang/Character$CharacterCache") \
|
||||||
template(java_lang_Float, "java/lang/Float") \
|
template(java_lang_Float, "java/lang/Float") \
|
||||||
template(java_lang_Double, "java/lang/Double") \
|
template(java_lang_Double, "java/lang/Double") \
|
||||||
template(java_lang_Byte, "java/lang/Byte") \
|
template(java_lang_Byte, "java/lang/Byte") \
|
||||||
|
template(java_lang_Byte_Cache, "java/lang/Byte$ByteCache") \
|
||||||
template(java_lang_Short, "java/lang/Short") \
|
template(java_lang_Short, "java/lang/Short") \
|
||||||
|
template(java_lang_Short_ShortCache, "java/lang/Short$ShortCache") \
|
||||||
template(java_lang_Integer, "java/lang/Integer") \
|
template(java_lang_Integer, "java/lang/Integer") \
|
||||||
|
template(java_lang_Integer_IntegerCache, "java/lang/Integer$IntegerCache") \
|
||||||
template(java_lang_Long, "java/lang/Long") \
|
template(java_lang_Long, "java/lang/Long") \
|
||||||
|
template(java_lang_Long_LongCache, "java/lang/Long$LongCache") \
|
||||||
template(java_lang_Shutdown, "java/lang/Shutdown") \
|
template(java_lang_Shutdown, "java/lang/Shutdown") \
|
||||||
template(java_lang_ref_Reference, "java/lang/ref/Reference") \
|
template(java_lang_ref_Reference, "java/lang/ref/Reference") \
|
||||||
template(java_lang_ref_SoftReference, "java/lang/ref/SoftReference") \
|
template(java_lang_ref_SoftReference, "java/lang/ref/SoftReference") \
|
||||||
@ -274,6 +279,7 @@
|
|||||||
template(exclusive_owner_thread_name, "exclusiveOwnerThread") \
|
template(exclusive_owner_thread_name, "exclusiveOwnerThread") \
|
||||||
template(park_blocker_name, "parkBlocker") \
|
template(park_blocker_name, "parkBlocker") \
|
||||||
template(park_event_name, "nativeParkEventPointer") \
|
template(park_event_name, "nativeParkEventPointer") \
|
||||||
|
template(cache_field_name, "cache") \
|
||||||
template(value_name, "value") \
|
template(value_name, "value") \
|
||||||
\
|
\
|
||||||
/* non-intrinsic name/signature pairs: */ \
|
/* non-intrinsic name/signature pairs: */ \
|
||||||
|
@ -720,6 +720,11 @@ ciObjArray.hpp ciArray.hpp
|
|||||||
ciObjArray.hpp ciClassList.hpp
|
ciObjArray.hpp ciClassList.hpp
|
||||||
ciObjArray.hpp objArrayOop.hpp
|
ciObjArray.hpp objArrayOop.hpp
|
||||||
|
|
||||||
|
ciObjArray.cpp ciObjArray.hpp
|
||||||
|
ciObjArray.cpp ciNullObject.hpp
|
||||||
|
ciObjArray.cpp ciUtilities.hpp
|
||||||
|
ciObjArray.cpp objArrayOop.hpp
|
||||||
|
|
||||||
ciObjArrayKlass.cpp ciInstanceKlass.hpp
|
ciObjArrayKlass.cpp ciInstanceKlass.hpp
|
||||||
ciObjArrayKlass.cpp ciObjArrayKlass.hpp
|
ciObjArrayKlass.cpp ciObjArrayKlass.hpp
|
||||||
ciObjArrayKlass.cpp ciObjArrayKlassKlass.hpp
|
ciObjArrayKlass.cpp ciObjArrayKlassKlass.hpp
|
||||||
|
@ -608,6 +608,28 @@ Node* AddPNode::Ideal_base_and_offset(Node* ptr, PhaseTransform* phase,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------unpack_offsets----------------------------------
|
||||||
|
// Collect the AddP offset values into the elements array, giving up
|
||||||
|
// if there are more than length.
|
||||||
|
int AddPNode::unpack_offsets(Node* elements[], int length) {
|
||||||
|
int count = 0;
|
||||||
|
Node* addr = this;
|
||||||
|
Node* base = addr->in(AddPNode::Base);
|
||||||
|
while (addr->is_AddP()) {
|
||||||
|
if (addr->in(AddPNode::Base) != base) {
|
||||||
|
// give up
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
elements[count++] = addr->in(AddPNode::Offset);
|
||||||
|
if (count == length) {
|
||||||
|
// give up
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
addr = addr->in(AddPNode::Address);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------match_edge-------------------------------------
|
//------------------------------match_edge-------------------------------------
|
||||||
// Do we Match on this edge index or not? Do not match base pointer edge
|
// Do we Match on this edge index or not? Do not match base pointer edge
|
||||||
uint AddPNode::match_edge(uint idx) const {
|
uint AddPNode::match_edge(uint idx) const {
|
||||||
|
@ -144,6 +144,11 @@ public:
|
|||||||
static Node* Ideal_base_and_offset(Node* ptr, PhaseTransform* phase,
|
static Node* Ideal_base_and_offset(Node* ptr, PhaseTransform* phase,
|
||||||
// second return value:
|
// second return value:
|
||||||
intptr_t& offset);
|
intptr_t& offset);
|
||||||
|
|
||||||
|
// Collect the AddP offset values into the elements array, giving up
|
||||||
|
// if there are more than length.
|
||||||
|
int unpack_offsets(Node* elements[], int length);
|
||||||
|
|
||||||
// Do not match base-ptr edge
|
// Do not match base-ptr edge
|
||||||
virtual uint match_edge(uint idx) const;
|
virtual uint match_edge(uint idx) const;
|
||||||
static const Type *mach_bottom_type(const MachNode* n); // used by ad_<arch>.hpp
|
static const Type *mach_bottom_type(const MachNode* n); // used by ad_<arch>.hpp
|
||||||
|
@ -367,6 +367,12 @@
|
|||||||
notproduct(bool, PrintEliminateLocks, false, \
|
notproduct(bool, PrintEliminateLocks, false, \
|
||||||
"Print out when locks are eliminated") \
|
"Print out when locks are eliminated") \
|
||||||
\
|
\
|
||||||
|
diagnostic(bool, EliminateAutoBox, false, \
|
||||||
|
"Private flag to control optimizations for autobox elimination") \
|
||||||
|
\
|
||||||
|
product(intx, AutoBoxCacheMax, 128, \
|
||||||
|
"Sets max value cached by the java.lang.Integer autobox cache") \
|
||||||
|
\
|
||||||
product(bool, DoEscapeAnalysis, false, \
|
product(bool, DoEscapeAnalysis, false, \
|
||||||
"Perform escape analysis") \
|
"Perform escape analysis") \
|
||||||
\
|
\
|
||||||
|
@ -310,8 +310,14 @@ public:
|
|||||||
virtual const RegMask &out_RegMask() const;
|
virtual const RegMask &out_RegMask() const;
|
||||||
void dominated_by(Node* prev_dom, PhaseIterGVN* igvn);
|
void dominated_by(Node* prev_dom, PhaseIterGVN* igvn);
|
||||||
int is_range_check(Node* &range, Node* &index, jint &offset);
|
int is_range_check(Node* &range, Node* &index, jint &offset);
|
||||||
|
Node* fold_compares(PhaseGVN* phase);
|
||||||
static Node* up_one_dom(Node* curr, bool linear_only = false);
|
static Node* up_one_dom(Node* curr, bool linear_only = false);
|
||||||
|
|
||||||
|
// Takes the type of val and filters it through the test represented
|
||||||
|
// by if_proj and returns a more refined type if one is produced.
|
||||||
|
// Returns NULL is it couldn't improve the type.
|
||||||
|
static const TypeInt* filtered_int_type(PhaseGVN* phase, Node* val, Node* if_proj);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
virtual void dump_spec(outputStream *st) const;
|
virtual void dump_spec(outputStream *st) const;
|
||||||
#endif
|
#endif
|
||||||
|
@ -543,6 +543,159 @@ Node* IfNode::up_one_dom(Node *curr, bool linear_only) {
|
|||||||
return NULL; // Dead loop? Or hit root?
|
return NULL; // Dead loop? Or hit root?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------filtered_int_type--------------------------------
|
||||||
|
// Return a possibly more restrictive type for val based on condition control flow for an if
|
||||||
|
const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node *val, Node* if_proj) {
|
||||||
|
assert(if_proj &&
|
||||||
|
(if_proj->Opcode() == Op_IfTrue || if_proj->Opcode() == Op_IfFalse), "expecting an if projection");
|
||||||
|
if (if_proj->in(0) && if_proj->in(0)->is_If()) {
|
||||||
|
IfNode* iff = if_proj->in(0)->as_If();
|
||||||
|
if (iff->in(1) && iff->in(1)->is_Bool()) {
|
||||||
|
BoolNode* bol = iff->in(1)->as_Bool();
|
||||||
|
if (bol->in(1) && bol->in(1)->is_Cmp()) {
|
||||||
|
const CmpNode* cmp = bol->in(1)->as_Cmp();
|
||||||
|
if (cmp->in(1) == val) {
|
||||||
|
const TypeInt* cmp2_t = gvn->type(cmp->in(2))->isa_int();
|
||||||
|
if (cmp2_t != NULL) {
|
||||||
|
jint lo = cmp2_t->_lo;
|
||||||
|
jint hi = cmp2_t->_hi;
|
||||||
|
BoolTest::mask msk = if_proj->Opcode() == Op_IfTrue ? bol->_test._test : bol->_test.negate();
|
||||||
|
switch (msk) {
|
||||||
|
case BoolTest::ne:
|
||||||
|
// Can't refine type
|
||||||
|
return NULL;
|
||||||
|
case BoolTest::eq:
|
||||||
|
return cmp2_t;
|
||||||
|
case BoolTest::lt:
|
||||||
|
lo = TypeInt::INT->_lo;
|
||||||
|
if (hi - 1 < hi) {
|
||||||
|
hi = hi - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BoolTest::le:
|
||||||
|
lo = TypeInt::INT->_lo;
|
||||||
|
break;
|
||||||
|
case BoolTest::gt:
|
||||||
|
if (lo + 1 > lo) {
|
||||||
|
lo = lo + 1;
|
||||||
|
}
|
||||||
|
hi = TypeInt::INT->_hi;
|
||||||
|
break;
|
||||||
|
case BoolTest::ge:
|
||||||
|
// lo unchanged
|
||||||
|
hi = TypeInt::INT->_hi;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const TypeInt* rtn_t = TypeInt::make(lo, hi, cmp2_t->_widen);
|
||||||
|
return rtn_t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------fold_compares----------------------------
|
||||||
|
// See if a pair of CmpIs can be converted into a CmpU. In some cases
|
||||||
|
// the direction of this if is determined by the preciding if so it
|
||||||
|
// can be eliminate entirely. Given an if testing (CmpI n c) check
|
||||||
|
// for an immediately control dependent if that is testing (CmpI n c2)
|
||||||
|
// and has one projection leading to this if and the other projection
|
||||||
|
// leading to a region that merges one of this ifs control
|
||||||
|
// projections.
|
||||||
|
//
|
||||||
|
// If
|
||||||
|
// / |
|
||||||
|
// / |
|
||||||
|
// / |
|
||||||
|
// If |
|
||||||
|
// /\ |
|
||||||
|
// / \ |
|
||||||
|
// / \ |
|
||||||
|
// / Region
|
||||||
|
//
|
||||||
|
Node* IfNode::fold_compares(PhaseGVN* phase) {
|
||||||
|
if (!EliminateAutoBox || Opcode() != Op_If) return NULL;
|
||||||
|
|
||||||
|
Node* this_cmp = in(1)->in(1);
|
||||||
|
if (this_cmp != NULL && this_cmp->Opcode() == Op_CmpI &&
|
||||||
|
this_cmp->in(2)->is_Con() && this_cmp->in(2) != phase->C->top()) {
|
||||||
|
Node* ctrl = in(0);
|
||||||
|
BoolNode* this_bool = in(1)->as_Bool();
|
||||||
|
Node* n = this_cmp->in(1);
|
||||||
|
int hi = this_cmp->in(2)->get_int();
|
||||||
|
if (ctrl != NULL && ctrl->is_Proj() && ctrl->outcnt() == 1 &&
|
||||||
|
ctrl->in(0)->is_If() &&
|
||||||
|
ctrl->in(0)->outcnt() == 2 &&
|
||||||
|
ctrl->in(0)->in(1)->is_Bool() &&
|
||||||
|
ctrl->in(0)->in(1)->in(1)->Opcode() == Op_CmpI &&
|
||||||
|
ctrl->in(0)->in(1)->in(1)->in(2)->is_Con() &&
|
||||||
|
ctrl->in(0)->in(1)->in(1)->in(1) == n) {
|
||||||
|
IfNode* dom_iff = ctrl->in(0)->as_If();
|
||||||
|
Node* otherproj = dom_iff->proj_out(!ctrl->as_Proj()->_con);
|
||||||
|
if (otherproj->outcnt() == 1 && otherproj->unique_out()->is_Region() &&
|
||||||
|
this_bool->_test._test != BoolTest::ne && this_bool->_test._test != BoolTest::eq) {
|
||||||
|
// Identify which proj goes to the region and which continues on
|
||||||
|
RegionNode* region = otherproj->unique_out()->as_Region();
|
||||||
|
Node* success = NULL;
|
||||||
|
Node* fail = NULL;
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
Node* proj = proj_out(i);
|
||||||
|
if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) {
|
||||||
|
success = proj;
|
||||||
|
} else if (fail == NULL) {
|
||||||
|
fail = proj;
|
||||||
|
} else {
|
||||||
|
success = fail = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (success != NULL && fail != NULL && !region->has_phi()) {
|
||||||
|
int lo = dom_iff->in(1)->in(1)->in(2)->get_int();
|
||||||
|
BoolNode* dom_bool = dom_iff->in(1)->as_Bool();
|
||||||
|
Node* dom_cmp = dom_bool->in(1);
|
||||||
|
const TypeInt* failtype = filtered_int_type(phase, n, ctrl);
|
||||||
|
if (failtype != NULL) {
|
||||||
|
const TypeInt* type2 = filtered_int_type(phase, n, fail);
|
||||||
|
if (type2 != NULL) {
|
||||||
|
failtype = failtype->join(type2)->is_int();
|
||||||
|
} else {
|
||||||
|
failtype = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failtype != NULL &&
|
||||||
|
dom_bool->_test._test != BoolTest::ne && dom_bool->_test._test != BoolTest::eq) {
|
||||||
|
int bound = failtype->_hi - failtype->_lo + 1;
|
||||||
|
if (failtype->_hi != max_jint && failtype->_lo != min_jint && bound > 1) {
|
||||||
|
// Merge the two compares into a single unsigned compare by building (CmpU (n - lo) hi)
|
||||||
|
BoolTest::mask cond = fail->as_Proj()->_con ? BoolTest::lt : BoolTest::ge;
|
||||||
|
Node* adjusted = phase->transform(new (phase->C, 3) SubINode(n, phase->intcon(failtype->_lo)));
|
||||||
|
Node* newcmp = phase->transform(new (phase->C, 3) CmpUNode(adjusted, phase->intcon(bound)));
|
||||||
|
Node* newbool = phase->transform(new (phase->C, 2) BoolNode(newcmp, cond));
|
||||||
|
phase->hash_delete(dom_iff);
|
||||||
|
dom_iff->set_req(1, phase->intcon(ctrl->as_Proj()->_con));
|
||||||
|
phase->is_IterGVN()->_worklist.push(dom_iff);
|
||||||
|
phase->hash_delete(this);
|
||||||
|
set_req(1, newbool);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if (failtype->_lo > failtype->_hi) {
|
||||||
|
// previous if determines the result of this if so
|
||||||
|
// replace Bool with constant
|
||||||
|
phase->hash_delete(this);
|
||||||
|
set_req(1, phase->intcon(success->as_Proj()->_con));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------remove_useless_bool----------------------------
|
//------------------------------remove_useless_bool----------------------------
|
||||||
// Check for people making a useless boolean: things like
|
// Check for people making a useless boolean: things like
|
||||||
// if( (x < y ? true : false) ) { ... }
|
// if( (x < y ? true : false) ) { ... }
|
||||||
@ -744,6 +897,11 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
// Normal equivalent-test check.
|
// Normal equivalent-test check.
|
||||||
if( !dom ) return NULL; // Dead loop?
|
if( !dom ) return NULL; // Dead loop?
|
||||||
|
|
||||||
|
Node* result = fold_compares(phase);
|
||||||
|
if (result != NULL) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Search up the dominator tree for an If with an identical test
|
// Search up the dominator tree for an If with an identical test
|
||||||
while( dom->Opcode() != op || // Not same opcode?
|
while( dom->Opcode() != op || // Not same opcode?
|
||||||
dom->in(1) != in(1) || // Not same input 1?
|
dom->in(1) != in(1) || // Not same input 1?
|
||||||
|
@ -651,7 +651,7 @@ const TypeInt* PhaseIdealLoop::filtered_type_from_dominators( Node* val, Node *u
|
|||||||
while (if_cnt < if_limit) {
|
while (if_cnt < if_limit) {
|
||||||
if ((pred->Opcode() == Op_IfTrue || pred->Opcode() == Op_IfFalse)) {
|
if ((pred->Opcode() == Op_IfTrue || pred->Opcode() == Op_IfFalse)) {
|
||||||
if_cnt++;
|
if_cnt++;
|
||||||
const TypeInt* if_t = filtered_type_at_if(val, pred);
|
const TypeInt* if_t = IfNode::filtered_int_type(&_igvn, val, pred);
|
||||||
if (if_t != NULL) {
|
if (if_t != NULL) {
|
||||||
if (rtn_t == NULL) {
|
if (rtn_t == NULL) {
|
||||||
rtn_t = if_t;
|
rtn_t = if_t;
|
||||||
@ -674,59 +674,6 @@ const TypeInt* PhaseIdealLoop::filtered_type_from_dominators( Node* val, Node *u
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------------------------filtered_type_at_if--------------------------------
|
|
||||||
// Return a possibly more restrictive type for val based on condition control flow for an if
|
|
||||||
const TypeInt* PhaseIdealLoop::filtered_type_at_if( Node* val, Node *if_proj) {
|
|
||||||
assert(if_proj &&
|
|
||||||
(if_proj->Opcode() == Op_IfTrue || if_proj->Opcode() == Op_IfFalse), "expecting an if projection");
|
|
||||||
if (if_proj->in(0) && if_proj->in(0)->is_If()) {
|
|
||||||
IfNode* iff = if_proj->in(0)->as_If();
|
|
||||||
if (iff->in(1) && iff->in(1)->is_Bool()) {
|
|
||||||
BoolNode* bol = iff->in(1)->as_Bool();
|
|
||||||
if (bol->in(1) && bol->in(1)->is_Cmp()) {
|
|
||||||
const CmpNode* cmp = bol->in(1)->as_Cmp();
|
|
||||||
if (cmp->in(1) == val) {
|
|
||||||
const TypeInt* cmp2_t = _igvn.type(cmp->in(2))->isa_int();
|
|
||||||
if (cmp2_t != NULL) {
|
|
||||||
jint lo = cmp2_t->_lo;
|
|
||||||
jint hi = cmp2_t->_hi;
|
|
||||||
BoolTest::mask msk = if_proj->Opcode() == Op_IfTrue ? bol->_test._test : bol->_test.negate();
|
|
||||||
switch (msk) {
|
|
||||||
case BoolTest::ne:
|
|
||||||
// Can't refine type
|
|
||||||
return NULL;
|
|
||||||
case BoolTest::eq:
|
|
||||||
return cmp2_t;
|
|
||||||
case BoolTest::lt:
|
|
||||||
lo = TypeInt::INT->_lo;
|
|
||||||
if (hi - 1 < hi) {
|
|
||||||
hi = hi - 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BoolTest::le:
|
|
||||||
lo = TypeInt::INT->_lo;
|
|
||||||
break;
|
|
||||||
case BoolTest::gt:
|
|
||||||
if (lo + 1 > lo) {
|
|
||||||
lo = lo + 1;
|
|
||||||
}
|
|
||||||
hi = TypeInt::INT->_hi;
|
|
||||||
break;
|
|
||||||
case BoolTest::ge:
|
|
||||||
// lo unchanged
|
|
||||||
hi = TypeInt::INT->_hi;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const TypeInt* rtn_t = TypeInt::make(lo, hi, cmp2_t->_widen);
|
|
||||||
return rtn_t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------dump_spec--------------------------------------
|
//------------------------------dump_spec--------------------------------------
|
||||||
// Dump special per-node info
|
// Dump special per-node info
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
@ -850,7 +850,6 @@ private:
|
|||||||
const TypeInt* filtered_type( Node *n ) { return filtered_type(n, NULL); }
|
const TypeInt* filtered_type( Node *n ) { return filtered_type(n, NULL); }
|
||||||
// Helpers for filtered type
|
// Helpers for filtered type
|
||||||
const TypeInt* filtered_type_from_dominators( Node* val, Node *val_ctrl);
|
const TypeInt* filtered_type_from_dominators( Node* val, Node *val_ctrl);
|
||||||
const TypeInt* filtered_type_at_if( Node* val, Node *if_proj);
|
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
void register_new_node( Node *n, Node *blk );
|
void register_new_node( Node *n, Node *blk );
|
||||||
|
@ -634,6 +634,46 @@ uint LoadNode::hash() const {
|
|||||||
Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const {
|
Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const {
|
||||||
Node* ld_adr = in(MemNode::Address);
|
Node* ld_adr = in(MemNode::Address);
|
||||||
|
|
||||||
|
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()) {
|
||||||
|
uint alias_idx = atp->index();
|
||||||
|
bool final = atp->field()->is_final();
|
||||||
|
Node* result = NULL;
|
||||||
|
Node* current = st;
|
||||||
|
// Skip through chains of MemBarNodes checking the MergeMems for
|
||||||
|
// new states for the slice of this load. Stop once any other
|
||||||
|
// kind of node is encountered. Loads from final memory can skip
|
||||||
|
// through any kind of MemBar but normal loads shouldn't skip
|
||||||
|
// through MemBarAcquire since the could allow them to move out of
|
||||||
|
// a synchronized region.
|
||||||
|
while (current->is_Proj()) {
|
||||||
|
int opc = current->in(0)->Opcode();
|
||||||
|
if ((final && opc == Op_MemBarAcquire) ||
|
||||||
|
opc == Op_MemBarRelease || opc == Op_MemBarCPUOrder) {
|
||||||
|
Node* mem = current->in(0)->in(TypeFunc::Memory);
|
||||||
|
if (mem->is_MergeMem()) {
|
||||||
|
MergeMemNode* merge = mem->as_MergeMem();
|
||||||
|
Node* new_st = merge->memory_at(alias_idx);
|
||||||
|
if (new_st == merge->base_memory()) {
|
||||||
|
// Keep searching
|
||||||
|
current = merge->base_memory();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Save the new memory state for the slice and fall through
|
||||||
|
// to exit.
|
||||||
|
result = new_st;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (result != NULL) {
|
||||||
|
st = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Loop around twice in the case Load -> Initialize -> Store.
|
// Loop around twice in the case Load -> Initialize -> Store.
|
||||||
// (See PhaseIterGVN::add_users_to_worklist, which knows about this case.)
|
// (See PhaseIterGVN::add_users_to_worklist, which knows about this case.)
|
||||||
for (int trip = 0; trip <= 1; trip++) {
|
for (int trip = 0; trip <= 1; trip++) {
|
||||||
@ -723,6 +763,168 @@ Node *LoadNode::Identity( PhaseTransform *phase ) {
|
|||||||
return this;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LoadNode* load = NULL;
|
||||||
|
if (allocation != NULL && base->in(load_index)->is_Load()) {
|
||||||
|
load = base->in(load_index)->as_Load();
|
||||||
|
}
|
||||||
|
if (load != NULL && 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* 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, base->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, base->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(base->in(0), this);
|
||||||
|
result->set_req(allocation_index, in1);
|
||||||
|
result->set_req(load_index, in2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} else if (base->is_Load()) {
|
||||||
|
// Eliminate the load of Integer.value for integers 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 != 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()) {
|
||||||
|
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, 3) AddXNode(result, elements[i]));
|
||||||
|
}
|
||||||
|
// 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, 3) 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, 3) RShiftXNode(result->in(1), phase->intcon(0));
|
||||||
|
} else {
|
||||||
|
result = new (phase->C, 3) RShiftXNode(result, phase->intcon(shift));
|
||||||
|
}
|
||||||
|
#ifdef _LP64
|
||||||
|
result = new (phase->C, 2) ConvL2INode(phase->transform(result));
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------------------------Ideal------------------------------------------
|
//------------------------------Ideal------------------------------------------
|
||||||
// If the load is from Field memory and the pointer is non-null, we can
|
// If the load is from Field memory and the pointer is non-null, we can
|
||||||
// zero out the control input.
|
// zero out the control input.
|
||||||
@ -755,6 +957,17 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (EliminateAutoBox && can_reshape && in(Address)->is_AddP()) {
|
||||||
|
Node* base = in(Address)->in(AddPNode::Base);
|
||||||
|
if (base != 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for prior store with a different base or offset; make Load
|
// Check for prior store with a different base or offset; make Load
|
||||||
// independent. Skip through any number of them. Bail out if the stores
|
// independent. Skip through any number of them. Bail out if the stores
|
||||||
// are in an endless dead cycle and report no progress. This is a key
|
// are in an endless dead cycle and report no progress. This is a key
|
||||||
@ -858,6 +1071,17 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
|
|||||||
// This can happen if a interface-typed array narrows to a class type.
|
// This can happen if a interface-typed array narrows to a class type.
|
||||||
jt = _type;
|
jt = _type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (EliminateAutoBox) {
|
||||||
|
// The pointers in the autobox arrays are always non-null
|
||||||
|
Node* base = in(Address)->in(AddPNode::Base);
|
||||||
|
if (base != NULL) {
|
||||||
|
Compile::AliasType* atp = phase->C->alias_type(base->adr_type());
|
||||||
|
if (is_autobox_cache(atp)) {
|
||||||
|
return jt->join(TypePtr::NOTNULL)->is_ptr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return jt;
|
return jt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,6 +141,9 @@ public:
|
|||||||
// zero out the control input.
|
// zero out the control input.
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
|
||||||
|
// Recover original value from boxed values
|
||||||
|
Node *eliminate_autobox(PhaseGVN *phase);
|
||||||
|
|
||||||
// Compute a new Type for this node. Basically we just do the pre-check,
|
// Compute a new Type for this node. Basically we just do the pre-check,
|
||||||
// then call the virtual add() to set the type.
|
// then call the virtual add() to set the type.
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
@ -885,6 +885,9 @@ inline void Parse::repush_if_args() {
|
|||||||
void Parse::do_ifnull(BoolTest::mask btest) {
|
void Parse::do_ifnull(BoolTest::mask btest) {
|
||||||
int target_bci = iter().get_dest();
|
int target_bci = iter().get_dest();
|
||||||
|
|
||||||
|
Block* branch_block = successor_for_bci(target_bci);
|
||||||
|
Block* next_block = successor_for_bci(iter().next_bci());
|
||||||
|
|
||||||
float cnt;
|
float cnt;
|
||||||
float prob = branch_prediction(cnt, btest, target_bci);
|
float prob = branch_prediction(cnt, btest, target_bci);
|
||||||
if (prob == PROB_UNKNOWN) {
|
if (prob == PROB_UNKNOWN) {
|
||||||
@ -902,13 +905,16 @@ void Parse::do_ifnull(BoolTest::mask btest) {
|
|||||||
uncommon_trap(Deoptimization::Reason_unreached,
|
uncommon_trap(Deoptimization::Reason_unreached,
|
||||||
Deoptimization::Action_reinterpret,
|
Deoptimization::Action_reinterpret,
|
||||||
NULL, "cold");
|
NULL, "cold");
|
||||||
|
if (EliminateAutoBox) {
|
||||||
|
// Mark the successor blocks as parsed
|
||||||
|
branch_block->next_path_num();
|
||||||
|
next_block->next_path_num();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a backwards branch in the bytecodes, add Safepoint
|
// If this is a backwards branch in the bytecodes, add Safepoint
|
||||||
maybe_add_safepoint(target_bci);
|
maybe_add_safepoint(target_bci);
|
||||||
Block* branch_block = successor_for_bci(target_bci);
|
|
||||||
Block* next_block = successor_for_bci(iter().next_bci());
|
|
||||||
|
|
||||||
explicit_null_checks_inserted++;
|
explicit_null_checks_inserted++;
|
||||||
Node* a = null();
|
Node* a = null();
|
||||||
@ -935,6 +941,10 @@ void Parse::do_ifnull(BoolTest::mask btest) {
|
|||||||
|
|
||||||
if (stopped()) { // Path is dead?
|
if (stopped()) { // Path is dead?
|
||||||
explicit_null_checks_elided++;
|
explicit_null_checks_elided++;
|
||||||
|
if (EliminateAutoBox) {
|
||||||
|
// Mark the successor block as parsed
|
||||||
|
branch_block->next_path_num();
|
||||||
|
}
|
||||||
} else { // Path is live.
|
} else { // Path is live.
|
||||||
// Update method data
|
// Update method data
|
||||||
profile_taken_branch(target_bci);
|
profile_taken_branch(target_bci);
|
||||||
@ -950,6 +960,10 @@ void Parse::do_ifnull(BoolTest::mask btest) {
|
|||||||
|
|
||||||
if (stopped()) { // Path is dead?
|
if (stopped()) { // Path is dead?
|
||||||
explicit_null_checks_elided++;
|
explicit_null_checks_elided++;
|
||||||
|
if (EliminateAutoBox) {
|
||||||
|
// Mark the successor block as parsed
|
||||||
|
next_block->next_path_num();
|
||||||
|
}
|
||||||
} else { // Path is live.
|
} else { // Path is live.
|
||||||
// Update method data
|
// Update method data
|
||||||
profile_not_taken_branch();
|
profile_not_taken_branch();
|
||||||
@ -962,6 +976,9 @@ void Parse::do_ifnull(BoolTest::mask btest) {
|
|||||||
void Parse::do_if(BoolTest::mask btest, Node* c) {
|
void Parse::do_if(BoolTest::mask btest, Node* c) {
|
||||||
int target_bci = iter().get_dest();
|
int target_bci = iter().get_dest();
|
||||||
|
|
||||||
|
Block* branch_block = successor_for_bci(target_bci);
|
||||||
|
Block* next_block = successor_for_bci(iter().next_bci());
|
||||||
|
|
||||||
float cnt;
|
float cnt;
|
||||||
float prob = branch_prediction(cnt, btest, target_bci);
|
float prob = branch_prediction(cnt, btest, target_bci);
|
||||||
float untaken_prob = 1.0 - prob;
|
float untaken_prob = 1.0 - prob;
|
||||||
@ -980,6 +997,11 @@ void Parse::do_if(BoolTest::mask btest, Node* c) {
|
|||||||
uncommon_trap(Deoptimization::Reason_unreached,
|
uncommon_trap(Deoptimization::Reason_unreached,
|
||||||
Deoptimization::Action_reinterpret,
|
Deoptimization::Action_reinterpret,
|
||||||
NULL, "cold");
|
NULL, "cold");
|
||||||
|
if (EliminateAutoBox) {
|
||||||
|
// Mark the successor blocks as parsed
|
||||||
|
branch_block->next_path_num();
|
||||||
|
next_block->next_path_num();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1018,15 +1040,17 @@ void Parse::do_if(BoolTest::mask btest, Node* c) {
|
|||||||
untaken_branch = tmp;
|
untaken_branch = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block* branch_block = successor_for_bci(target_bci);
|
|
||||||
Block* next_block = successor_for_bci(iter().next_bci());
|
|
||||||
|
|
||||||
// Branch is taken:
|
// Branch is taken:
|
||||||
{ PreserveJVMState pjvms(this);
|
{ PreserveJVMState pjvms(this);
|
||||||
taken_branch = _gvn.transform(taken_branch);
|
taken_branch = _gvn.transform(taken_branch);
|
||||||
set_control(taken_branch);
|
set_control(taken_branch);
|
||||||
|
|
||||||
if (!stopped()) {
|
if (stopped()) {
|
||||||
|
if (EliminateAutoBox) {
|
||||||
|
// Mark the successor block as parsed
|
||||||
|
branch_block->next_path_num();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// Update method data
|
// Update method data
|
||||||
profile_taken_branch(target_bci);
|
profile_taken_branch(target_bci);
|
||||||
adjust_map_after_if(taken_btest, c, prob, branch_block, next_block);
|
adjust_map_after_if(taken_btest, c, prob, branch_block, next_block);
|
||||||
@ -1039,7 +1063,12 @@ void Parse::do_if(BoolTest::mask btest, Node* c) {
|
|||||||
set_control(untaken_branch);
|
set_control(untaken_branch);
|
||||||
|
|
||||||
// Branch not taken.
|
// Branch not taken.
|
||||||
if (!stopped()) {
|
if (stopped()) {
|
||||||
|
if (EliminateAutoBox) {
|
||||||
|
// Mark the successor block as parsed
|
||||||
|
next_block->next_path_num();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// Update method data
|
// Update method data
|
||||||
profile_not_taken_branch();
|
profile_not_taken_branch();
|
||||||
adjust_map_after_if(untaken_btest, c, untaken_prob,
|
adjust_map_after_if(untaken_btest, c, untaken_prob,
|
||||||
|
@ -1070,6 +1070,7 @@ inline bool Type::is_floatingpoint() const {
|
|||||||
#define LShiftXNode LShiftLNode
|
#define LShiftXNode LShiftLNode
|
||||||
// For object size computation:
|
// For object size computation:
|
||||||
#define AddXNode AddLNode
|
#define AddXNode AddLNode
|
||||||
|
#define RShiftXNode RShiftLNode
|
||||||
// For card marks and hashcodes
|
// For card marks and hashcodes
|
||||||
#define URShiftXNode URShiftLNode
|
#define URShiftXNode URShiftLNode
|
||||||
// Opcodes
|
// Opcodes
|
||||||
@ -1108,6 +1109,7 @@ inline bool Type::is_floatingpoint() const {
|
|||||||
#define LShiftXNode LShiftINode
|
#define LShiftXNode LShiftINode
|
||||||
// For object size computation:
|
// For object size computation:
|
||||||
#define AddXNode AddINode
|
#define AddXNode AddINode
|
||||||
|
#define RShiftXNode RShiftINode
|
||||||
// For card marks and hashcodes
|
// For card marks and hashcodes
|
||||||
#define URShiftXNode URShiftINode
|
#define URShiftXNode URShiftINode
|
||||||
// Opcodes
|
// Opcodes
|
||||||
|
@ -1254,6 +1254,22 @@ void Arguments::set_bytecode_flags() {
|
|||||||
|
|
||||||
// Aggressive optimization flags -XX:+AggressiveOpts
|
// Aggressive optimization flags -XX:+AggressiveOpts
|
||||||
void Arguments::set_aggressive_opts_flags() {
|
void Arguments::set_aggressive_opts_flags() {
|
||||||
|
#ifdef COMPILER2
|
||||||
|
if (AggressiveOpts || !FLAG_IS_DEFAULT(AutoBoxCacheMax)) {
|
||||||
|
if (FLAG_IS_DEFAULT(EliminateAutoBox)) {
|
||||||
|
FLAG_SET_DEFAULT(EliminateAutoBox, true);
|
||||||
|
}
|
||||||
|
if (FLAG_IS_DEFAULT(AutoBoxCacheMax)) {
|
||||||
|
FLAG_SET_DEFAULT(AutoBoxCacheMax, 20000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed the cache size setting into the JDK
|
||||||
|
char buffer[1024];
|
||||||
|
sprintf(buffer, "java.lang.Integer.IntegerCache.high=%d", AutoBoxCacheMax);
|
||||||
|
add_property(buffer);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (AggressiveOpts) {
|
if (AggressiveOpts) {
|
||||||
NOT_WINDOWS(
|
NOT_WINDOWS(
|
||||||
// No measured benefit on Windows
|
// No measured benefit on Windows
|
||||||
|
Loading…
Reference in New Issue
Block a user