提交 0ba7505d 编写于 作者: K kmo

Merge

......@@ -2263,6 +2263,18 @@ void Assembler::packuswb(XMMRegister dst, XMMRegister src) {
emit_simd_arith(0x67, dst, src, VEX_SIMD_66);
}
void Assembler::vpackuswb(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) {
assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
emit_vex_arith(0x67, dst, nds, src, VEX_SIMD_66, vector256);
}
void Assembler::vpermq(XMMRegister dst, XMMRegister src, int imm8, bool vector256) {
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, true, vector256);
emit_int8(0x00);
emit_int8(0xC0 | encode);
emit_int8(imm8);
}
void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) {
assert(VM_Version::supports_sse4_2(), "");
InstructionMark im(this);
......@@ -2475,7 +2487,7 @@ void Assembler::vptest(XMMRegister dst, Address src) {
assert(dst != xnoreg, "sanity");
int dst_enc = dst->encoding();
// swap src<->dst for encoding
vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, false, vector256);
vex_prefix(src, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, false, vector256);
emit_int8(0x17);
emit_operand(dst, src);
}
......
......@@ -1395,6 +1395,10 @@ private:
// Pack with unsigned saturation
void packuswb(XMMRegister dst, XMMRegister src);
void packuswb(XMMRegister dst, Address src);
void vpackuswb(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256);
// Pemutation of 64bit words
void vpermq(XMMRegister dst, XMMRegister src, int imm8, bool vector256);
// SSE4.2 string instructions
void pcmpestri(XMMRegister xmm1, XMMRegister xmm2, int imm8);
......
......@@ -6209,6 +6209,128 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned,
}
BIND(L_exit);
}
// encode char[] to byte[] in ISO_8859_1
void MacroAssembler::encode_iso_array(Register src, Register dst, Register len,
XMMRegister tmp1Reg, XMMRegister tmp2Reg,
XMMRegister tmp3Reg, XMMRegister tmp4Reg,
Register tmp5, Register result) {
// rsi: src
// rdi: dst
// rdx: len
// rcx: tmp5
// rax: result
ShortBranchVerifier sbv(this);
assert_different_registers(src, dst, len, tmp5, result);
Label L_done, L_copy_1_char, L_copy_1_char_exit;
// set result
xorl(result, result);
// check for zero length
testl(len, len);
jcc(Assembler::zero, L_done);
movl(result, len);
// Setup pointers
lea(src, Address(src, len, Address::times_2)); // char[]
lea(dst, Address(dst, len, Address::times_1)); // byte[]
negptr(len);
if (UseSSE42Intrinsics || UseAVX >= 2) {
Label L_chars_8_check, L_copy_8_chars, L_copy_8_chars_exit;
Label L_chars_16_check, L_copy_16_chars, L_copy_16_chars_exit;
if (UseAVX >= 2) {
Label L_chars_32_check, L_copy_32_chars, L_copy_32_chars_exit;
movl(tmp5, 0xff00ff00); // create mask to test for Unicode chars in vector
movdl(tmp1Reg, tmp5);
vpbroadcastd(tmp1Reg, tmp1Reg);
jmpb(L_chars_32_check);
bind(L_copy_32_chars);
vmovdqu(tmp3Reg, Address(src, len, Address::times_2, -64));
vmovdqu(tmp4Reg, Address(src, len, Address::times_2, -32));
vpor(tmp2Reg, tmp3Reg, tmp4Reg, /* vector256 */ true);
vptest(tmp2Reg, tmp1Reg); // check for Unicode chars in vector
jccb(Assembler::notZero, L_copy_32_chars_exit);
vpackuswb(tmp3Reg, tmp3Reg, tmp4Reg, /* vector256 */ true);
vpermq(tmp4Reg, tmp3Reg, 0xD8, /* vector256 */ true);
vmovdqu(Address(dst, len, Address::times_1, -32), tmp4Reg);
bind(L_chars_32_check);
addptr(len, 32);
jccb(Assembler::lessEqual, L_copy_32_chars);
bind(L_copy_32_chars_exit);
subptr(len, 16);
jccb(Assembler::greater, L_copy_16_chars_exit);
} else if (UseSSE42Intrinsics) {
movl(tmp5, 0xff00ff00); // create mask to test for Unicode chars in vector
movdl(tmp1Reg, tmp5);
pshufd(tmp1Reg, tmp1Reg, 0);
jmpb(L_chars_16_check);
}
bind(L_copy_16_chars);
if (UseAVX >= 2) {
vmovdqu(tmp2Reg, Address(src, len, Address::times_2, -32));
vptest(tmp2Reg, tmp1Reg);
jccb(Assembler::notZero, L_copy_16_chars_exit);
vpackuswb(tmp2Reg, tmp2Reg, tmp1Reg, /* vector256 */ true);
vpermq(tmp3Reg, tmp2Reg, 0xD8, /* vector256 */ true);
} else {
if (UseAVX > 0) {
movdqu(tmp3Reg, Address(src, len, Address::times_2, -32));
movdqu(tmp4Reg, Address(src, len, Address::times_2, -16));
vpor(tmp2Reg, tmp3Reg, tmp4Reg, /* vector256 */ false);
} else {
movdqu(tmp3Reg, Address(src, len, Address::times_2, -32));
por(tmp2Reg, tmp3Reg);
movdqu(tmp4Reg, Address(src, len, Address::times_2, -16));
por(tmp2Reg, tmp4Reg);
}
ptest(tmp2Reg, tmp1Reg); // check for Unicode chars in vector
jccb(Assembler::notZero, L_copy_16_chars_exit);
packuswb(tmp3Reg, tmp4Reg);
}
movdqu(Address(dst, len, Address::times_1, -16), tmp3Reg);
bind(L_chars_16_check);
addptr(len, 16);
jccb(Assembler::lessEqual, L_copy_16_chars);
bind(L_copy_16_chars_exit);
subptr(len, 8);
jccb(Assembler::greater, L_copy_8_chars_exit);
bind(L_copy_8_chars);
movdqu(tmp3Reg, Address(src, len, Address::times_2, -16));
ptest(tmp3Reg, tmp1Reg);
jccb(Assembler::notZero, L_copy_8_chars_exit);
packuswb(tmp3Reg, tmp1Reg);
movq(Address(dst, len, Address::times_1, -8), tmp3Reg);
addptr(len, 8);
jccb(Assembler::lessEqual, L_copy_8_chars);
bind(L_copy_8_chars_exit);
subptr(len, 8);
jccb(Assembler::zero, L_done);
}
bind(L_copy_1_char);
load_unsigned_short(tmp5, Address(src, len, Address::times_2, 0));
testl(tmp5, 0xff00); // check if Unicode char
jccb(Assembler::notZero, L_copy_1_char_exit);
movb(Address(dst, len, Address::times_1, 0), tmp5);
addptr(len, 1);
jccb(Assembler::less, L_copy_1_char);
bind(L_copy_1_char_exit);
addptr(result, len); // len is negative count of not processed elements
bind(L_done);
}
#undef BIND
#undef BLOCK_COMMENT
......
......@@ -1135,6 +1135,10 @@ public:
Register to, Register value, Register count,
Register rtmp, XMMRegister xtmp);
void encode_iso_array(Register src, Register dst, Register len,
XMMRegister tmp1, XMMRegister tmp2, XMMRegister tmp3,
XMMRegister tmp4, Register tmp5, Register result);
#undef VIRTUAL
};
......
......@@ -661,6 +661,14 @@ void VM_Version::get_processor_features() {
}
}
}
#if defined(COMPILER2) && defined(_ALLBSD_SOURCE)
if (MaxVectorSize > 16) {
// Limit vectors size to 16 bytes on BSD until it fixes
// restoring upper 128bit of YMM registers on return
// from signal handler.
FLAG_SET_DEFAULT(MaxVectorSize, 16);
}
#endif // COMPILER2
// Use population count instruction if available.
if (supports_popcnt()) {
......
......@@ -11687,6 +11687,23 @@ instruct array_equals(eDIRegP ary1, eSIRegP ary2, eAXRegI result,
ins_pipe( pipe_slow );
%}
// encode char[] to byte[] in ISO_8859_1
instruct encode_iso_array(eSIRegP src, eDIRegP dst, eDXRegI len,
regD tmp1, regD tmp2, regD tmp3, regD tmp4,
eCXRegI tmp5, eAXRegI result, eFlagsReg cr) %{
match(Set result (EncodeISOArray src (Binary dst len)));
effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr);
format %{ "Encode array $src,$dst,$len -> $result // KILL ECX, EDX, $tmp1, $tmp2, $tmp3, $tmp4, ESI, EDI " %}
ins_encode %{
__ encode_iso_array($src$$Register, $dst$$Register, $len$$Register,
$tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister,
$tmp4$$XMMRegister, $tmp5$$Register, $result$$Register);
%}
ins_pipe( pipe_slow );
%}
//----------Control Flow Instructions------------------------------------------
// Signed compare Instructions
instruct compI_eReg(eFlagsReg cr, rRegI op1, rRegI op2) %{
......
......@@ -10495,6 +10495,23 @@ instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result,
ins_pipe( pipe_slow );
%}
// encode char[] to byte[] in ISO_8859_1
instruct encode_iso_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len,
regD tmp1, regD tmp2, regD tmp3, regD tmp4,
rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{
match(Set result (EncodeISOArray src (Binary dst len)));
effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr);
format %{ "Encode array $src,$dst,$len -> $result // KILL RCX, RDX, $tmp1, $tmp2, $tmp3, $tmp4, RSI, RDI " %}
ins_encode %{
__ encode_iso_array($src$$Register, $dst$$Register, $len$$Register,
$tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister,
$tmp4$$XMMRegister, $tmp5$$Register, $result$$Register);
%}
ins_pipe( pipe_slow );
%}
//----------Control Flow Instructions------------------------------------------
// Signed compare Instructions
......
......@@ -862,8 +862,10 @@ uint InstructForm::oper_input_base(FormDict &globals) {
( strcmp(_matrule->_rChild->_opType,"AryEq" )==0 ||
strcmp(_matrule->_rChild->_opType,"StrComp" )==0 ||
strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 ||
strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 )) {
strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 ||
strcmp(_matrule->_rChild->_opType,"EncodeISOArray")==0)) {
// String.(compareTo/equals/indexOf) and Arrays.equals
// and sun.nio.cs.iso8859_1$Encoder.EncodeISOArray
// take 1 control and 1 memory edges.
return 2;
}
......
......@@ -1802,11 +1802,9 @@ ClassFileParser::AnnotationCollector::ID
ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_data,
Symbol* name) {
vmSymbols::SID sid = vmSymbols::find_sid(name);
bool privileged = false;
if (loader_data->is_the_null_class_loader_data()) {
// Privileged code can use all annotations. Other code silently drops some.
privileged = true;
}
// Privileged code can use all annotations. Other code silently drops some.
bool privileged = loader_data->is_the_null_class_loader_data() ||
loader_data->is_anonymous();
switch (sid) {
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature):
if (_location != _in_method) break; // only allow for methods
......
......@@ -735,6 +735,11 @@
do_intrinsic(_checkIndex, java_nio_Buffer, checkIndex_name, int_int_signature, F_R) \
do_name( checkIndex_name, "checkIndex") \
\
do_class(sun_nio_cs_iso8859_1_Encoder, "sun/nio/cs/ISO_8859_1$Encoder") \
do_intrinsic(_encodeISOArray, sun_nio_cs_iso8859_1_Encoder, encodeISOArray_name, encodeISOArray_signature, F_S) \
do_name( encodeISOArray_name, "encodeISOArray") \
do_signature(encodeISOArray_signature, "([CI[BII)I") \
\
/* java/lang/ref/Reference */ \
do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \
\
......
......@@ -542,17 +542,17 @@ void print_register_type(OopMapValue::oop_types x, VMReg optional,
st->print("Oop");
break;
case OopMapValue::value_value:
st->print("Value" );
st->print("Value");
break;
case OopMapValue::narrowoop_value:
tty->print("NarrowOop" );
st->print("NarrowOop");
break;
case OopMapValue::callee_saved_value:
st->print("Callers_" );
st->print("Callers_");
optional->print_on(st);
break;
case OopMapValue::derived_oop_value:
st->print("Derived_oop_" );
st->print("Derived_oop_");
optional->print_on(st);
break;
default:
......
......@@ -516,6 +516,9 @@
develop(bool, SpecialArraysEquals, true, \
"special version of Arrays.equals(char[],char[])") \
\
product(bool, SpecialEncodeISOArray, true, \
"special version of ISO_8859_1$Encoder.encodeISOArray") \
\
develop(bool, BailoutToInterpreterForThrows, false, \
"Compiled methods which throws/catches exceptions will be " \
"deopt and intp.") \
......
......@@ -165,13 +165,13 @@ uint ReturnNode::match_edge(uint idx) const {
#ifndef PRODUCT
void ReturnNode::dump_req() const {
void ReturnNode::dump_req(outputStream *st) const {
// Dump the required inputs, enclosed in '(' and ')'
uint i; // Exit value of loop
for( i=0; i<req(); i++ ) { // For all required inputs
if( i == TypeFunc::Parms ) tty->print("returns");
if( in(i) ) tty->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx);
else tty->print("_ ");
for (i = 0; i < req(); i++) { // For all required inputs
if (i == TypeFunc::Parms) st->print("returns");
if (in(i)) st->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx);
else st->print("_ ");
}
}
#endif
......@@ -208,13 +208,13 @@ uint RethrowNode::match_edge(uint idx) const {
}
#ifndef PRODUCT
void RethrowNode::dump_req() const {
void RethrowNode::dump_req(outputStream *st) const {
// Dump the required inputs, enclosed in '(' and ')'
uint i; // Exit value of loop
for( i=0; i<req(); i++ ) { // For all required inputs
if( i == TypeFunc::Parms ) tty->print("exception");
if( in(i) ) tty->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx);
else tty->print("_ ");
for (i = 0; i < req(); i++) { // For all required inputs
if (i == TypeFunc::Parms) st->print("exception");
if (in(i)) st->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx);
else st->print("_ ");
}
}
#endif
......@@ -330,7 +330,8 @@ static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, c
st->print(" %s%d]=#ScObj" INT32_FORMAT, msg, i, sco_n);
return;
}
if( OptoReg::is_valid(regalloc->get_reg_first(n))) { // Check for undefined
if (regalloc->node_regs_max_index() > 0 &&
OptoReg::is_valid(regalloc->get_reg_first(n))) { // Check for undefined
char buf[50];
regalloc->dump_register(n,buf);
st->print(" %s%d]=%s",msg,i,buf);
......@@ -381,7 +382,7 @@ static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, c
//------------------------------format-----------------------------------------
void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) const {
st->print(" #");
if( _method ) {
if (_method) {
_method->print_short_name(st);
st->print(" @ bci:%d ",_bci);
} else {
......@@ -393,21 +394,22 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st)
MachSafePointNode *mcall = n->as_MachSafePoint();
uint i;
// Print locals
for( i = 0; i < (uint)loc_size(); i++ )
format_helper( regalloc, st, mcall->local(this, i), "L[", i, &scobjs );
for (i = 0; i < (uint)loc_size(); i++)
format_helper(regalloc, st, mcall->local(this, i), "L[", i, &scobjs);
// Print stack
for (i = 0; i < (uint)stk_size(); i++) {
if ((uint)(_stkoff + i) >= mcall->len())
st->print(" oob ");
else
format_helper( regalloc, st, mcall->stack(this, i), "STK[", i, &scobjs );
format_helper(regalloc, st, mcall->stack(this, i), "STK[", i, &scobjs);
}
for (i = 0; (int)i < nof_monitors(); i++) {
Node *box = mcall->monitor_box(this, i);
Node *obj = mcall->monitor_obj(this, i);
if ( OptoReg::is_valid(regalloc->get_reg_first(box)) ) {
if (regalloc->node_regs_max_index() > 0 &&
OptoReg::is_valid(regalloc->get_reg_first(box))) {
box = BoxLockNode::box_node(box);
format_helper( regalloc, st, box, "MON-BOX[", i, &scobjs );
format_helper(regalloc, st, box, "MON-BOX[", i, &scobjs);
} else {
OptoReg::Name box_reg = BoxLockNode::reg(box);
st->print(" MON-BOX%d=%s+%d",
......@@ -420,7 +422,7 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st)
if (BoxLockNode::box_node(box)->is_eliminated())
obj_msg = "MON-OBJ(LOCK ELIMINATED)[";
}
format_helper( regalloc, st, obj, obj_msg, i, &scobjs );
format_helper(regalloc, st, obj, obj_msg, i, &scobjs);
}
for (i = 0; i < (uint)scobjs.length(); i++) {
......@@ -463,9 +465,9 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st)
st->print(" [");
cifield = iklass->nonstatic_field_at(0);
cifield->print_name_on(st);
format_helper( regalloc, st, fld_node, ":", 0, &scobjs );
format_helper(regalloc, st, fld_node, ":", 0, &scobjs);
} else {
format_helper( regalloc, st, fld_node, "[", 0, &scobjs );
format_helper(regalloc, st, fld_node, "[", 0, &scobjs);
}
for (uint j = 1; j < nf; j++) {
fld_node = mcall->in(first_ind+j);
......@@ -473,9 +475,9 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st)
st->print(", [");
cifield = iklass->nonstatic_field_at(j);
cifield->print_name_on(st);
format_helper( regalloc, st, fld_node, ":", j, &scobjs );
format_helper(regalloc, st, fld_node, ":", j, &scobjs);
} else {
format_helper( regalloc, st, fld_node, ", [", j, &scobjs );
format_helper(regalloc, st, fld_node, ", [", j, &scobjs);
}
}
}
......@@ -483,7 +485,7 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st)
}
}
st->print_cr("");
if (caller() != NULL) caller()->format(regalloc, n, st);
if (caller() != NULL) caller()->format(regalloc, n, st);
}
......@@ -586,15 +588,15 @@ JVMState* JVMState::clone_deep(Compile* C) const {
uint CallNode::cmp( const Node &n ) const
{ return _tf == ((CallNode&)n)._tf && _jvms == ((CallNode&)n)._jvms; }
#ifndef PRODUCT
void CallNode::dump_req() const {
void CallNode::dump_req(outputStream *st) const {
// Dump the required inputs, enclosed in '(' and ')'
uint i; // Exit value of loop
for( i=0; i<req(); i++ ) { // For all required inputs
if( i == TypeFunc::Parms ) tty->print("(");
if( in(i) ) tty->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx);
else tty->print("_ ");
for (i = 0; i < req(); i++) { // For all required inputs
if (i == TypeFunc::Parms) st->print("(");
if (in(i)) st->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx);
else st->print("_ ");
}
tty->print(")");
st->print(")");
}
void CallNode::dump_spec(outputStream *st) const {
......
......@@ -126,7 +126,7 @@ public:
virtual uint ideal_reg() const { return NotAMachineReg; }
virtual uint match_edge(uint idx) const;
#ifndef PRODUCT
virtual void dump_req() const;
virtual void dump_req(outputStream *st = tty) const;
#endif
};
......@@ -147,7 +147,7 @@ class RethrowNode : public Node {
virtual uint match_edge(uint idx) const;
virtual uint ideal_reg() const { return NotAMachineReg; }
#ifndef PRODUCT
virtual void dump_req() const;
virtual void dump_req(outputStream *st = tty) const;
#endif
};
......@@ -579,7 +579,7 @@ public:
virtual uint match_edge(uint idx) const;
#ifndef PRODUCT
virtual void dump_req() const;
virtual void dump_req(outputStream *st = tty) const;
virtual void dump_spec(outputStream *st) const;
#endif
};
......
......@@ -127,6 +127,7 @@ macro(DivL)
macro(DivMod)
macro(DivModI)
macro(DivModL)
macro(EncodeISOArray)
macro(EncodeP)
macro(EncodePKlass)
macro(ExpD)
......
......@@ -523,7 +523,8 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de
case Op_AryEq:
case Op_StrComp:
case Op_StrEquals:
case Op_StrIndexOf: {
case Op_StrIndexOf:
case Op_EncodeISOArray: {
add_local_var(n, PointsToNode::ArgEscape);
delayed_worklist->push(n); // Process it later.
break;
......@@ -701,7 +702,8 @@ void ConnectionGraph::add_final_edges(Node *n) {
case Op_AryEq:
case Op_StrComp:
case Op_StrEquals:
case Op_StrIndexOf: {
case Op_StrIndexOf:
case Op_EncodeISOArray: {
// char[] arrays passed to string intrinsic do not escape but
// they are not scalar replaceable. Adjust escape state for them.
// Start from in(2) edge since in(1) is memory edge.
......@@ -2581,15 +2583,22 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
}
// Otherwise skip it (the call updated 'result' value).
} else if (result->Opcode() == Op_SCMemProj) {
assert(result->in(0)->is_LoadStore(), "sanity");
const Type *at = igvn->type(result->in(0)->in(MemNode::Address));
Node* mem = result->in(0);
Node* adr = NULL;
if (mem->is_LoadStore()) {
adr = mem->in(MemNode::Address);
} else {
assert(mem->Opcode() == Op_EncodeISOArray, "sanity");
adr = mem->in(3); // Memory edge corresponds to destination array
}
const Type *at = igvn->type(adr);
if (at != Type::TOP) {
assert (at->isa_ptr() != NULL, "pointer type required.");
int idx = C->get_alias_index(at->is_ptr());
assert(idx != alias_idx, "Object is not scalar replaceable if a LoadStore node access its field");
break;
}
result = result->in(0)->in(MemNode::Memory);
result = mem->in(MemNode::Memory);
}
}
if (result->is_Phi()) {
......@@ -2927,6 +2936,11 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
if (m->is_MergeMem()) {
assert(_mergemem_worklist.contains(m->as_MergeMem()), "EA: missing MergeMem node in the worklist");
}
} else if (use->Opcode() == Op_EncodeISOArray) {
if (use->in(MemNode::Memory) == n || use->in(3) == n) {
// EncodeISOArray overwrites destination array
memnode_worklist.append_if_missing(use);
}
} else {
uint op = use->Opcode();
if (!(op == Op_CmpP || op == Op_Conv2B ||
......@@ -2962,6 +2976,16 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
n = n->as_MemBar()->proj_out(TypeFunc::Memory);
if (n == NULL)
continue;
} else if (n->Opcode() == Op_EncodeISOArray) {
// get the memory projection
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node *use = n->fast_out(i);
if (use->Opcode() == Op_SCMemProj) {
n = use;
break;
}
}
assert(n->Opcode() == Op_SCMemProj, "memory projection required");
} else {
assert(n->is_Mem(), "memory node required.");
Node *addr = n->in(MemNode::Address);
......@@ -2999,7 +3023,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
Node *use = n->fast_out(i);
if (use->is_Phi() || use->is_ClearArray()) {
memnode_worklist.append_if_missing(use);
} else if(use->is_Mem() && use->in(MemNode::Memory) == n) {
} else if (use->is_Mem() && use->in(MemNode::Memory) == n) {
if (use->Opcode() == Op_StoreCM) // Ignore cardmark stores
continue;
memnode_worklist.append_if_missing(use);
......@@ -3010,6 +3034,11 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
assert(use->in(MemNode::Memory) != n, "EA: missing memory path");
} else if (use->is_MergeMem()) {
assert(_mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist");
} else if (use->Opcode() == Op_EncodeISOArray) {
if (use->in(MemNode::Memory) == n || use->in(3) == n) {
// EncodeISOArray overwrites destination array
memnode_worklist.append_if_missing(use);
}
} else {
uint op = use->Opcode();
if (!(op == Op_StoreCM ||
......
......@@ -175,6 +175,7 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe
case Op_StrEquals:
case Op_StrIndexOf:
case Op_AryEq:
case Op_EncodeISOArray:
// Not a legit memory op for implicit null check regardless of
// embedded loads
continue;
......
......@@ -290,6 +290,7 @@ class LibraryCallKit : public GraphKit {
bool inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id);
Node* inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting);
Node* get_key_start_from_aescrypt_object(Node* aescrypt_object);
bool inline_encodeISOArray();
};
......@@ -381,6 +382,10 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
// These also use the arraycopy intrinsic mechanism:
if (!InlineArrayCopy) return NULL;
break;
case vmIntrinsics::_encodeISOArray:
if (!SpecialEncodeISOArray) return NULL;
if (!Matcher::match_rule_supported(Op_EncodeISOArray)) return NULL;
break;
case vmIntrinsics::_checkIndex:
// We do not intrinsify this. The optimizer does fine with it.
return NULL;
......@@ -799,6 +804,9 @@ bool LibraryCallKit::try_to_inline() {
case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
return inline_cipherBlockChaining_AESCrypt(intrinsic_id());
case vmIntrinsics::_encodeISOArray:
return inline_encodeISOArray();
default:
// If you get here, it may be that someone has added a new intrinsic
// to the list in vmSymbols.hpp without implementing it here.
......@@ -5368,6 +5376,47 @@ LibraryCallKit::generate_unchecked_arraycopy(const TypePtr* adr_type,
src_start, dest_start, copy_length XTOP);
}
//-------------inline_encodeISOArray-----------------------------------
// encode char[] to byte[] in ISO_8859_1
bool LibraryCallKit::inline_encodeISOArray() {
assert(callee()->signature()->size() == 5, "encodeISOArray has 5 parameters");
// no receiver since it is static method
Node *src = argument(0);
Node *src_offset = argument(1);
Node *dst = argument(2);
Node *dst_offset = argument(3);
Node *length = argument(4);
const Type* src_type = src->Value(&_gvn);
const Type* dst_type = dst->Value(&_gvn);
const TypeAryPtr* top_src = src_type->isa_aryptr();
const TypeAryPtr* top_dest = dst_type->isa_aryptr();
if (top_src == NULL || top_src->klass() == NULL ||
top_dest == NULL || top_dest->klass() == NULL) {
// failed array check
return false;
}
// Figure out the size and type of the elements we will be copying.
BasicType src_elem = src_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
BasicType dst_elem = dst_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
if (src_elem != T_CHAR || dst_elem != T_BYTE) {
return false;
}
Node* src_start = array_element_address(src, src_offset, src_elem);
Node* dst_start = array_element_address(dst, dst_offset, dst_elem);
// 'src_start' points to src array + scaled offset
// 'dst_start' points to dst array + scaled offset
const TypeAryPtr* mtype = TypeAryPtr::BYTES;
Node* enc = new (C) EncodeISOArrayNode(control(), memory(mtype), src_start, dst_start, length);
enc = _gvn.transform(enc);
Node* res_mem = _gvn.transform(new (C) SCMemProjNode(enc));
set_memory(res_mem, mtype);
set_result(enc);
return true;
}
//----------------------------inline_reference_get----------------------------
// public T java.lang.ref.Reference.get();
bool LibraryCallKit::inline_reference_get() {
......
......@@ -613,6 +613,7 @@ bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const {
case Op_StrComp:
case Op_StrEquals:
case Op_StrIndexOf:
case Op_EncodeISOArray:
case Op_AryEq: {
return false;
}
......@@ -717,6 +718,7 @@ bool IdealLoopTree::policy_unroll( PhaseIdealLoop *phase ) const {
case Op_StrComp:
case Op_StrEquals:
case Op_StrIndexOf:
case Op_EncodeISOArray:
case Op_AryEq: {
// Do not unroll a loop with String intrinsics code.
// String intrinsics are large and have loops.
......
......@@ -506,7 +506,7 @@ int MachConstantNode::constant_offset() {
#ifndef PRODUCT
void MachNullCheckNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
int reg = ra_->get_reg_first(in(1)->in(_vidx));
tty->print("%s %s", Name(), Matcher::regName[reg]);
st->print("%s %s", Name(), Matcher::regName[reg]);
}
#endif
......
......@@ -361,14 +361,21 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me
}
// Otherwise skip it (the call updated 'mem' value).
} else if (mem->Opcode() == Op_SCMemProj) {
assert(mem->in(0)->is_LoadStore(), "sanity");
const TypePtr* atype = mem->in(0)->in(MemNode::Address)->bottom_type()->is_ptr();
mem = mem->in(0);
Node* adr = NULL;
if (mem->is_LoadStore()) {
adr = mem->in(MemNode::Address);
} else {
assert(mem->Opcode() == Op_EncodeISOArray, "sanity");
adr = mem->in(3); // Destination array
}
const TypePtr* atype = adr->bottom_type()->is_ptr();
int adr_idx = Compile::current()->get_alias_index(atype);
if (adr_idx == alias_idx) {
assert(false, "Object is not scalar replaceable if a LoadStore node access its field");
return NULL;
}
mem = mem->in(0)->in(MemNode::Memory);
mem = mem->in(MemNode::Memory);
} else {
return mem;
}
......@@ -445,7 +452,7 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *
}
values.at_put(j, val);
} else if (val->Opcode() == Op_SCMemProj) {
assert(val->in(0)->is_LoadStore(), "sanity");
assert(val->in(0)->is_LoadStore() || val->in(0)->Opcode() == Op_EncodeISOArray, "sanity");
assert(false, "Object is not scalar replaceable if a LoadStore node access its field");
return NULL;
} else {
......
......@@ -919,6 +919,7 @@ static void match_alias_type(Compile* C, Node* n, Node* m) {
case Op_AryEq:
case Op_MemBarVolatile:
case Op_MemBarCPUOrder: // %%% these ideals should have narrower adr_type?
case Op_EncodeISOArray:
nidx = Compile::AliasIdxTop;
nat = NULL;
break;
......@@ -1982,6 +1983,7 @@ void Matcher::find_shared( Node *n ) {
case Op_StrEquals:
case Op_StrIndexOf:
case Op_AryEq:
case Op_EncodeISOArray:
set_shared(n); // Force result into register (it will be anyways)
break;
case Op_ConP: { // Convert pointers above the centerline to NUL
......@@ -2183,6 +2185,13 @@ void Matcher::find_shared( Node *n ) {
n->del_req(4);
break;
}
case Op_EncodeISOArray: {
// Restructure into a binary tree for Matching.
Node* pair = new (C) BinaryNode(n->in(3), n->in(4));
n->set_req(3, pair);
n->del_req(4);
break;
}
default:
break;
}
......
......@@ -2796,6 +2796,26 @@ const Type *StrIntrinsicNode::Value( PhaseTransform *phase ) const {
return bottom_type();
}
//=============================================================================
//------------------------------match_edge-------------------------------------
// Do not match memory edge
uint EncodeISOArrayNode::match_edge(uint idx) const {
return idx == 2 || idx == 3; // EncodeISOArray src (Binary dst len)
}
//------------------------------Ideal------------------------------------------
// Return a node which is more "ideal" than the current node. Strip out
// control copies
Node *EncodeISOArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
return remove_dead_region(phase, can_reshape) ? this : NULL;
}
//------------------------------Value------------------------------------------
const Type *EncodeISOArrayNode::Value(PhaseTransform *phase) const {
if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP;
return bottom_type();
}
//=============================================================================
MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent)
: MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)),
......
......@@ -888,6 +888,22 @@ public:
virtual const Type* bottom_type() const { return TypeInt::BOOL; }
};
//------------------------------EncodeISOArray--------------------------------
// encode char[] to byte[] in ISO_8859_1
class EncodeISOArrayNode: public Node {
public:
EncodeISOArrayNode(Node *control, Node* arymem, Node* s1, Node* s2, Node* c): Node(control, arymem, s1, s2, c) {};
virtual int Opcode() const;
virtual bool depends_only_on_test() const { return false; }
virtual const Type* bottom_type() const { return TypeInt::INT; }
virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; }
virtual uint match_edge(uint idx) const;
virtual uint ideal_reg() const { return Op_RegI; }
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
virtual const Type *Value(PhaseTransform *phase) const;
};
//------------------------------MemBar-----------------------------------------
// There are different flavors of Memory Barriers to match the Java Memory
// Model. Monitor-enter and volatile-load act as Aquires: no following ref
......
......@@ -1476,35 +1476,35 @@ static bool is_disconnected(const Node* n) {
}
#ifdef ASSERT
static void dump_orig(Node* orig) {
static void dump_orig(Node* orig, outputStream *st) {
Compile* C = Compile::current();
if (NotANode(orig)) orig = NULL;
if (orig != NULL && !C->node_arena()->contains(orig)) orig = NULL;
if (orig == NULL) return;
tty->print(" !orig=");
if (NotANode(orig)) orig = NULL;
if (orig != NULL && !C->node_arena()->contains(orig)) orig = NULL;
if (orig == NULL) return;
st->print(" !orig=");
Node* fast = orig->debug_orig(); // tortoise & hare algorithm to detect loops
if (NotANode(fast)) fast = NULL;
if (NotANode(fast)) fast = NULL;
while (orig != NULL) {
bool discon = is_disconnected(orig); // if discon, print [123] else 123
if (discon) tty->print("[");
if (discon) st->print("[");
if (!Compile::current()->node_arena()->contains(orig))
tty->print("o");
tty->print("%d", orig->_idx);
if (discon) tty->print("]");
st->print("o");
st->print("%d", orig->_idx);
if (discon) st->print("]");
orig = orig->debug_orig();
if (NotANode(orig)) orig = NULL;
if (orig != NULL && !C->node_arena()->contains(orig)) orig = NULL;
if (orig != NULL) tty->print(",");
if (NotANode(orig)) orig = NULL;
if (orig != NULL && !C->node_arena()->contains(orig)) orig = NULL;
if (orig != NULL) st->print(",");
if (fast != NULL) {
// Step fast twice for each single step of orig:
fast = fast->debug_orig();
if (NotANode(fast)) fast = NULL;
if (NotANode(fast)) fast = NULL;
if (fast != NULL && fast != orig) {
fast = fast->debug_orig();
if (NotANode(fast)) fast = NULL;
if (NotANode(fast)) fast = NULL;
}
if (fast == orig) {
tty->print("...");
st->print("...");
break;
}
}
......@@ -1531,35 +1531,34 @@ void Node::set_debug_orig(Node* orig) {
//------------------------------dump------------------------------------------
// Dump a Node
void Node::dump() const {
void Node::dump(const char* suffix, outputStream *st) const {
Compile* C = Compile::current();
bool is_new = C->node_arena()->contains(this);
_in_dump_cnt++;
tty->print("%c%d\t%s\t=== ",
is_new ? ' ' : 'o', _idx, Name());
st->print("%c%d\t%s\t=== ", is_new ? ' ' : 'o', _idx, Name());
// Dump the required and precedence inputs
dump_req();
dump_prec();
dump_req(st);
dump_prec(st);
// Dump the outputs
dump_out();
dump_out(st);
if (is_disconnected(this)) {
#ifdef ASSERT
tty->print(" [%d]",debug_idx());
dump_orig(debug_orig());
st->print(" [%d]",debug_idx());
dump_orig(debug_orig(), st);
#endif
tty->cr();
st->cr();
_in_dump_cnt--;
return; // don't process dead nodes
}
// Dump node-specific info
dump_spec(tty);
dump_spec(st);
#ifdef ASSERT
// Dump the non-reset _debug_idx
if( Verbose && WizardMode ) {
tty->print(" [%d]",debug_idx());
if (Verbose && WizardMode) {
st->print(" [%d]",debug_idx());
}
#endif
......@@ -1569,88 +1568,88 @@ void Node::dump() const {
const TypeInstPtr *toop = t->isa_instptr();
const TypeKlassPtr *tkls = t->isa_klassptr();
ciKlass* klass = toop ? toop->klass() : (tkls ? tkls->klass() : NULL );
if( klass && klass->is_loaded() && klass->is_interface() ) {
tty->print(" Interface:");
} else if( toop ) {
tty->print(" Oop:");
} else if( tkls ) {
tty->print(" Klass:");
if (klass && klass->is_loaded() && klass->is_interface()) {
st->print(" Interface:");
} else if (toop) {
st->print(" Oop:");
} else if (tkls) {
st->print(" Klass:");
}
t->dump();
} else if( t == Type::MEMORY ) {
tty->print(" Memory:");
MemNode::dump_adr_type(this, adr_type(), tty);
} else if( Verbose || WizardMode ) {
tty->print(" Type:");
if( t ) {
t->dump();
t->dump_on(st);
} else if (t == Type::MEMORY) {
st->print(" Memory:");
MemNode::dump_adr_type(this, adr_type(), st);
} else if (Verbose || WizardMode) {
st->print(" Type:");
if (t) {
t->dump_on(st);
} else {
tty->print("no type");
st->print("no type");
}
} else if (t->isa_vect() && this->is_MachSpillCopy()) {
// Dump MachSpillcopy vector type.
t->dump();
t->dump_on(st);
}
if (is_new) {
debug_only(dump_orig(debug_orig()));
debug_only(dump_orig(debug_orig(), st));
Node_Notes* nn = C->node_notes_at(_idx);
if (nn != NULL && !nn->is_clear()) {
if (nn->jvms() != NULL) {
tty->print(" !jvms:");
nn->jvms()->dump_spec(tty);
st->print(" !jvms:");
nn->jvms()->dump_spec(st);
}
}
}
tty->cr();
if (suffix) st->print(suffix);
_in_dump_cnt--;
}
//------------------------------dump_req--------------------------------------
void Node::dump_req() const {
void Node::dump_req(outputStream *st) const {
// Dump the required input edges
for (uint i = 0; i < req(); i++) { // For all required inputs
Node* d = in(i);
if (d == NULL) {
tty->print("_ ");
st->print("_ ");
} else if (NotANode(d)) {
tty->print("NotANode "); // uninitialized, sentinel, garbage, etc.
st->print("NotANode "); // uninitialized, sentinel, garbage, etc.
} else {
tty->print("%c%d ", Compile::current()->node_arena()->contains(d) ? ' ' : 'o', d->_idx);
st->print("%c%d ", Compile::current()->node_arena()->contains(d) ? ' ' : 'o', d->_idx);
}
}
}
//------------------------------dump_prec-------------------------------------
void Node::dump_prec() const {
void Node::dump_prec(outputStream *st) const {
// Dump the precedence edges
int any_prec = 0;
for (uint i = req(); i < len(); i++) { // For all precedence inputs
Node* p = in(i);
if (p != NULL) {
if( !any_prec++ ) tty->print(" |");
if (NotANode(p)) { tty->print("NotANode "); continue; }
tty->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx);
if (!any_prec++) st->print(" |");
if (NotANode(p)) { st->print("NotANode "); continue; }
st->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx);
}
}
}
//------------------------------dump_out--------------------------------------
void Node::dump_out() const {
void Node::dump_out(outputStream *st) const {
// Delimit the output edges
tty->print(" [[");
st->print(" [[");
// Dump the output edges
for (uint i = 0; i < _outcnt; i++) { // For all outputs
Node* u = _out[i];
if (u == NULL) {
tty->print("_ ");
st->print("_ ");
} else if (NotANode(u)) {
tty->print("NotANode ");
st->print("NotANode ");
} else {
tty->print("%c%d ", Compile::current()->node_arena()->contains(u) ? ' ' : 'o', u->_idx);
st->print("%c%d ", Compile::current()->node_arena()->contains(u) ? ' ' : 'o', u->_idx);
}
}
tty->print("]] ");
st->print("]] ");
}
//------------------------------dump_nodes-------------------------------------
......
......@@ -994,12 +994,13 @@ public:
#ifndef PRODUCT
Node* find(int idx) const; // Search the graph for the given idx.
Node* find_ctrl(int idx) const; // Search control ancestors for the given idx.
void dump() const; // Print this node,
void dump() const { dump("\n"); } // Print this node.
void dump(const char* suffix, outputStream *st = tty) const;// Print this node.
void dump(int depth) const; // Print this node, recursively to depth d
void dump_ctrl(int depth) const; // Print control nodes, to depth d
virtual void dump_req() const; // Print required-edge info
virtual void dump_prec() const; // Print precedence-edge info
virtual void dump_out() const; // Print the output edge info
virtual void dump_req(outputStream *st = tty) const; // Print required-edge info
virtual void dump_prec(outputStream *st = tty) const; // Print precedence-edge info
virtual void dump_out(outputStream *st = tty) const; // Print the output edge info
virtual void dump_spec(outputStream *st) const {}; // Print per-node info
void verify_edges(Unique_Node_List &visited); // Verify bi-directional edges
void verify() const; // Check Def-Use info for my subgraph
......
......@@ -77,7 +77,7 @@ class OptoReg VALUE_OBJ_CLASS_SPEC {
// (We would like to have an operator+ for RegName, but it is not
// a class, so this would be illegal in C++.)
static void dump( int );
static void dump(int, outputStream *st = tty);
// Get the stack slot number of an OptoReg::Name
static unsigned int reg2stack( OptoReg::Name r) {
......
......@@ -40,6 +40,7 @@ PhaseRegAlloc::PhaseRegAlloc( uint unique, PhaseCFG &cfg,
Phase(Register_Allocation), _cfg(cfg), _matcher(matcher),
_node_oops(Thread::current()->resource_area()),
_node_regs(0),
_node_regs_max_index(0),
_framesize(0xdeadbeef)
{
int i;
......
......@@ -108,13 +108,13 @@ int find_hihghest_bit( uint32 mask ) {
//------------------------------dump-------------------------------------------
#ifndef PRODUCT
void OptoReg::dump( int r ) {
switch( r ) {
case Special: tty->print("r---"); break;
case Bad: tty->print("rBAD"); break;
void OptoReg::dump(int r, outputStream *st) {
switch (r) {
case Special: st->print("r---"); break;
case Bad: st->print("rBAD"); break;
default:
if( r < _last_Mach_Reg ) tty->print(Matcher::regName[r]);
else tty->print("rS%d",r);
if (r < _last_Mach_Reg) st->print(Matcher::regName[r]);
else st->print("rS%d",r);
break;
}
}
......@@ -404,53 +404,53 @@ uint RegMask::Size() const {
#ifndef PRODUCT
//------------------------------print------------------------------------------
void RegMask::dump( ) const {
tty->print("[");
void RegMask::dump(outputStream *st) const {
st->print("[");
RegMask rm = *this; // Structure copy into local temp
OptoReg::Name start = rm.find_first_elem(); // Get a register
if( OptoReg::is_valid(start) ) { // Check for empty mask
if (OptoReg::is_valid(start)) { // Check for empty mask
rm.Remove(start); // Yank from mask
OptoReg::dump(start); // Print register
OptoReg::dump(start, st); // Print register
OptoReg::Name last = start;
// Now I have printed an initial register.
// Print adjacent registers as "rX-rZ" instead of "rX,rY,rZ".
// Begin looping over the remaining registers.
while( 1 ) { //
while (1) { //
OptoReg::Name reg = rm.find_first_elem(); // Get a register
if( !OptoReg::is_valid(reg) )
if (!OptoReg::is_valid(reg))
break; // Empty mask, end loop
rm.Remove(reg); // Yank from mask
if( last+1 == reg ) { // See if they are adjacent
if (last+1 == reg) { // See if they are adjacent
// Adjacent registers just collect into long runs, no printing.
last = reg;
} else { // Ending some kind of run
if( start == last ) { // 1-register run; no special printing
} else if( start+1 == last ) {
tty->print(","); // 2-register run; print as "rX,rY"
OptoReg::dump(last);
if (start == last) { // 1-register run; no special printing
} else if (start+1 == last) {
st->print(","); // 2-register run; print as "rX,rY"
OptoReg::dump(last, st);
} else { // Multi-register run; print as "rX-rZ"
tty->print("-");
OptoReg::dump(last);
st->print("-");
OptoReg::dump(last, st);
}
tty->print(","); // Seperate start of new run
st->print(","); // Seperate start of new run
start = last = reg; // Start a new register run
OptoReg::dump(start); // Print register
OptoReg::dump(start, st); // Print register
} // End of if ending a register run or not
} // End of while regmask not empty
if( start == last ) { // 1-register run; no special printing
} else if( start+1 == last ) {
tty->print(","); // 2-register run; print as "rX,rY"
OptoReg::dump(last);
if (start == last) { // 1-register run; no special printing
} else if (start+1 == last) {
st->print(","); // 2-register run; print as "rX,rY"
OptoReg::dump(last, st);
} else { // Multi-register run; print as "rX-rZ"
tty->print("-");
OptoReg::dump(last);
st->print("-");
OptoReg::dump(last, st);
}
if( rm.is_AllStack() ) tty->print("...");
if (rm.is_AllStack()) st->print("...");
}
tty->print("]");
st->print("]");
}
#endif
......@@ -310,7 +310,7 @@ public:
#ifndef PRODUCT
void print() const { dump(); }
void dump() const; // Print a mask
void dump(outputStream *st = tty) const; // Print a mask
#endif
static const RegMask Empty; // Common empty mask
......
/*
* 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 6896617
* @summary Optimize sun.nio.cs.ISO_8859_1$Encode.encodeArrayLoop() with SSE instructions on x86
* @run main/othervm/timeout=1200 -Xbatch -Xmx256m Test6896617
*
*/
import java.util.*;
import java.nio.*;
import java.nio.charset.*;
public class Test6896617 {
final static int SIZE = 256;
public static void main(String[] args) {
String csn = "ISO-8859-1";
Charset cs = Charset.forName(csn);
CharsetEncoder enc = cs.newEncoder();
enc.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
CharsetDecoder dec = cs.newDecoder();
dec.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
byte repl = (byte)'?';
enc.replaceWith(new byte[] { repl });
// Use internal API for tests.
sun.nio.cs.ArrayEncoder arrenc = (sun.nio.cs.ArrayEncoder)enc;
sun.nio.cs.ArrayDecoder arrdec = (sun.nio.cs.ArrayDecoder)dec;
// Populate char[] with chars which can be encoded by ISO_8859_1 (<= 0xFF)
Random rnd = new Random(0);
int maxchar = 0xFF;
char[] a = new char[SIZE];
byte[] b = new byte[SIZE];
char[] at = new char[SIZE];
byte[] bt = new byte[SIZE];
for (int i = 0; i < SIZE; i++) {
char c = (char) rnd.nextInt(maxchar);
if (!enc.canEncode(c)) {
System.out.printf("Something wrong: can't encode c=%03x\n", (int)c);
System.exit(97);
}
a[i] = c;
b[i] = (byte)c;
at[i] = (char)-1;
bt[i] = (byte)-1;
}
if (arrenc.encode(a, 0, SIZE, bt) != SIZE || !Arrays.equals(b, bt)) {
System.out.println("Something wrong: ArrayEncoder.encode failed");
System.exit(97);
}
if (arrdec.decode(b, 0, SIZE, at) != SIZE || !Arrays.equals(a, at)) {
System.out.println("Something wrong: ArrayDecoder.decode failed");
System.exit(97);
}
for (int i = 0; i < SIZE; i++) {
at[i] = (char)-1;
bt[i] = (byte)-1;
}
ByteBuffer bb = ByteBuffer.wrap(b);
CharBuffer ba = CharBuffer.wrap(a);
ByteBuffer bbt = ByteBuffer.wrap(bt);
CharBuffer bat = CharBuffer.wrap(at);
if (!enc.encode(ba, bbt, true).isUnderflow() || !Arrays.equals(b, bt)) {
System.out.println("Something wrong: Encoder.encode failed");
System.exit(97);
}
if (!dec.decode(bb, bat, true).isUnderflow() || !Arrays.equals(a, at)) {
System.out.println("Something wrong: Decoder.decode failed");
System.exit(97);
}
for (int i = 0; i < SIZE; i++) {
at[i] = (char)-1;
bt[i] = (byte)-1;
}
// Warm up
boolean failed = false;
int result = 0;
for (int i = 0; i < 10000; i++) {
result += arrenc.encode(a, 0, SIZE, bt);
result -= arrdec.decode(b, 0, SIZE, at);
}
for (int i = 0; i < 10000; i++) {
result += arrenc.encode(a, 0, SIZE, bt);
result -= arrdec.decode(b, 0, SIZE, at);
}
for (int i = 0; i < 10000; i++) {
result += arrenc.encode(a, 0, SIZE, bt);
result -= arrdec.decode(b, 0, SIZE, at);
}
if (result != 0 || !Arrays.equals(b, bt) || !Arrays.equals(a, at)) {
failed = true;
System.out.println("Failed: ArrayEncoder.encode char[" + SIZE + "] and ArrayDecoder.decode byte[" + SIZE + "]");
}
for (int i = 0; i < SIZE; i++) {
at[i] = (char)-1;
bt[i] = (byte)-1;
}
boolean is_underflow = true;
for (int i = 0; i < 10000; i++) {
ba.clear(); bb.clear(); bat.clear(); bbt.clear();
boolean enc_res = enc.encode(ba, bbt, true).isUnderflow();
boolean dec_res = dec.decode(bb, bat, true).isUnderflow();
is_underflow = is_underflow && enc_res && dec_res;
}
for (int i = 0; i < SIZE; i++) {
at[i] = (char)-1;
bt[i] = (byte)-1;
}
for (int i = 0; i < 10000; i++) {
ba.clear(); bb.clear(); bat.clear(); bbt.clear();
boolean enc_res = enc.encode(ba, bbt, true).isUnderflow();
boolean dec_res = dec.decode(bb, bat, true).isUnderflow();
is_underflow = is_underflow && enc_res && dec_res;
}
for (int i = 0; i < SIZE; i++) {
at[i] = (char)-1;
bt[i] = (byte)-1;
}
for (int i = 0; i < 10000; i++) {
ba.clear(); bb.clear(); bat.clear(); bbt.clear();
boolean enc_res = enc.encode(ba, bbt, true).isUnderflow();
boolean dec_res = dec.decode(bb, bat, true).isUnderflow();
is_underflow = is_underflow && enc_res && dec_res;
}
if (!is_underflow || !Arrays.equals(b, bt) || !Arrays.equals(a, at)) {
failed = true;
System.out.println("Failed: Encoder.encode char[" + SIZE + "] and Decoder.decode byte[" + SIZE + "]");
}
// Test encoder with different source and destination sizes
System.out.println("Testing different source and destination sizes");
for (int i = 1; i <= SIZE; i++) {
for (int j = 1; j <= SIZE; j++) {
bt = new byte[j];
// very source's SIZE
result = arrenc.encode(a, 0, i, bt);
int l = Math.min(i, j);
if (result != l) {
failed = true;
System.out.println("Failed: encode char[" + i + "] to byte[" + j + "]: result = " + result + ", expected " + l);
}
for (int k = 0; k < l; k++) {
if (bt[k] != b[k]) {
failed = true;
System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[k]);
}
}
// very source's offset
int sz = SIZE - i + 1;
result = arrenc.encode(a, i-1, sz, bt);
l = Math.min(sz, j);
if (result != l) {
failed = true;
System.out.println("Failed: encode char[" + sz + "] to byte[" + j + "]: result = " + result + ", expected " + l);
}
for (int k = 0; k < l; k++) {
if (bt[k] != b[i+k-1]) {
failed = true;
System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[i+k-1]);
}
}
}
}
// Test encoder with char > 0xFF
System.out.println("Testing big char");
byte orig = (byte)'A';
bt = new byte[SIZE];
for (int i = 1; i <= SIZE; i++) {
for (int j = 0; j < i; j++) {
a[j] += 0x100;
// make sure to replace a different byte
bt[j] = orig;
result = arrenc.encode(a, 0, i, bt);
if (result != i) {
failed = true;
System.out.println("Failed: encode char[" + i + "] to byte[" + i + "]: result = " + result + ", expected " + i);
}
if (bt[j] != repl) {
failed = true;
System.out.println("Failed: encoded replace byte[" + j + "] (" + bt[j] + ") != " + repl);
}
bt[j] = b[j]; // Restore to compare whole array
for (int k = 0; k < i; k++) {
if (bt[k] != b[k]) {
failed = true;
System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[k]);
}
}
a[j] -= 0x100; // Restore
}
}
// Test sun.nio.cs.ISO_8859_1$Encode.encodeArrayLoop() performance.
int itrs = Integer.getInteger("iterations", 1000000);
int size = Integer.getInteger("size", 256);
a = new char[size];
b = new byte[size];
bt = new byte[size];
for (int i = 0; i < size; i++) {
char c = (char) rnd.nextInt(maxchar);
if (!enc.canEncode(c)) {
System.out.printf("Something wrong: can't encode c=%03x\n", (int)c);
System.exit(97);
}
a[i] = c;
b[i] = (byte)-1;
bt[i] = (byte)c;
}
ba = CharBuffer.wrap(a);
bb = ByteBuffer.wrap(b);
boolean enc_res = enc.encode(ba, bb, true).isUnderflow();
if (!enc_res || !Arrays.equals(b, bt)) {
failed = true;
System.out.println("Failed 1: Encoder.encode char[" + size + "]");
}
for (int i = 0; i < size; i++) {
b[i] = (byte)-1;
}
// Make sure to recompile method if needed before performance run.
for (int i = 0; i < 10000; i++) {
ba.clear(); bb.clear();
enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow();
}
for (int i = 0; i < size; i++) {
b[i] = (byte)-1;
}
for (int i = 0; i < 10000; i++) {
ba.clear(); bb.clear();
enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow();
}
if (!enc_res || !Arrays.equals(b, bt)) {
failed = true;
System.out.println("Failed 2: Encoder.encode char[" + size + "]");
}
for (int i = 0; i < size; i++) {
b[i] = (byte)-1;
}
System.out.println("Testing ISO_8859_1$Encode.encodeArrayLoop() performance");
long start = System.currentTimeMillis();
for (int i = 0; i < itrs; i++) {
ba.clear(); bb.clear();
enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow();
}
long end = System.currentTimeMillis();
if (!enc_res || !Arrays.equals(b, bt)) {
failed = true;
System.out.println("Failed 3: Encoder.encode char[" + size + "]");
} else {
System.out.println("size: " + size + " time: " + (end - start));
}
// Test sun.nio.cs.ISO_8859_1$Encode.encode() performance.
// Make sure to recompile method if needed before performance run.
result = 0;
for (int i = 0; i < size; i++) {
b[i] = (byte)-1;
}
for (int i = 0; i < 10000; i++) {
result += arrenc.encode(a, 0, size, b);
}
for (int i = 0; i < size; i++) {
b[i] = (byte)-1;
}
for (int i = 0; i < 10000; i++) {
result += arrenc.encode(a, 0, size, b);
}
if (result != size*20000 || !Arrays.equals(b, bt)) {
failed = true;
System.out.println("Failed 1: ArrayEncoder.encode char[" + SIZE + "]");
}
for (int i = 0; i < size; i++) {
b[i] = (byte)-1;
}
System.out.println("Testing ISO_8859_1$Encode.encode() performance");
result = 0;
start = System.currentTimeMillis();
for (int i = 0; i < itrs; i++) {
result += arrenc.encode(a, 0, size, b);
}
end = System.currentTimeMillis();
if (!Arrays.equals(b, bt)) {
failed = true;
System.out.println("Failed 2: ArrayEncoder.encode char[" + size + "]");
} else {
System.out.println("size: " + size + " time: " + (end - start));
}
if (failed) {
System.out.println("FAILED");
System.exit(97);
}
System.out.println("PASSED");
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册