--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp Fri May 30 07:22:22 2008 -0700
@@ -1523,6 +1523,21 @@
return Address(d, address(obj), oop_Relocation::spec(oop_index));
}
+void MacroAssembler::set_narrow_oop(jobject obj, Register d) {
+ assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int oop_index = oop_recorder()->find_index(obj);
+ RelocationHolder rspec = oop_Relocation::spec(oop_index);
+
+ assert_not_delayed();
+ // Relocation with special format (see relocInfo_sparc.hpp).
+ relocate(rspec, 1);
+ // Assembler::sethi(0x3fffff, d);
+ emit_long( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(0x3fffff) );
+ // Don't add relocation for 'add'. Do patching during 'sethi' processing.
+ add(d, 0x3ff, d);
+
+}
+
void MacroAssembler::align(int modulus) {
while (offset() % modulus != 0) nop();
@@ -3406,13 +3421,15 @@
set((intptr_t)markOopDesc::prototype()->copy_set_hash(0x2), t2);
st_ptr(t2, top, oopDesc::mark_offset_in_bytes()); // set up the mark word
// set klass to intArrayKlass
- set((intptr_t)Universe::intArrayKlassObj_addr(), t2);
- ld_ptr(t2, 0, t2);
- store_klass(t2, top);
sub(t1, typeArrayOopDesc::header_size(T_INT), t1);
add(t1, ThreadLocalAllocBuffer::alignment_reserve(), t1);
sll_ptr(t1, log2_intptr(HeapWordSize/sizeof(jint)), t1);
st(t1, top, arrayOopDesc::length_offset_in_bytes());
+ set((intptr_t)Universe::intArrayKlassObj_addr(), t2);
+ ld_ptr(t2, 0, t2);
+ // store klass last. concurrent gcs assumes klass length is valid if
+ // klass field is not null.
+ store_klass(t2, top);
verify_oop(top);
// refill the tlab with an eden allocation
@@ -3537,28 +3554,32 @@
}
}
-void MacroAssembler::load_klass(Register s, Register d) {
+void MacroAssembler::load_klass(Register src_oop, Register klass) {
// The number of bytes in this code is used by
// MachCallDynamicJavaNode::ret_addr_offset()
// if this changes, change that.
if (UseCompressedOops) {
- lduw(s, oopDesc::klass_offset_in_bytes(), d);
- decode_heap_oop_not_null(d);
+ lduw(src_oop, oopDesc::klass_offset_in_bytes(), klass);
+ decode_heap_oop_not_null(klass);
} else {
- ld_ptr(s, oopDesc::klass_offset_in_bytes(), d);
+ ld_ptr(src_oop, oopDesc::klass_offset_in_bytes(), klass);
}
}
-// ??? figure out src vs. dst!
-void MacroAssembler::store_klass(Register d, Register s1) {
+void MacroAssembler::store_klass(Register klass, Register dst_oop) {
if (UseCompressedOops) {
- assert(s1 != d, "not enough registers");
- encode_heap_oop_not_null(d);
- // Zero out entire klass field first.
- st_ptr(G0, s1, oopDesc::klass_offset_in_bytes());
- st(d, s1, oopDesc::klass_offset_in_bytes());
+ assert(dst_oop != klass, "not enough registers");
+ encode_heap_oop_not_null(klass);
+ st(klass, dst_oop, oopDesc::klass_offset_in_bytes());
} else {
- st_ptr(d, s1, oopDesc::klass_offset_in_bytes());
+ st_ptr(klass, dst_oop, oopDesc::klass_offset_in_bytes());
+ }
+}
+
+void MacroAssembler::store_klass_gap(Register s, Register d) {
+ if (UseCompressedOops) {
+ assert(s != d, "not enough registers");
+ st(s, d, oopDesc::klass_gap_offset_in_bytes());
}
}
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Fri May 30 07:22:22 2008 -0700
@@ -1977,8 +1977,9 @@
inline void movbool( bool boolconst, Register d) { mov( (int) boolconst, d); }
// klass oop manipulations if compressed
- void load_klass(Register src_oop, Register dst);
- void store_klass(Register dst_oop, Register s1);
+ void load_klass(Register src_oop, Register klass);
+ void store_klass(Register klass, Register dst_oop);
+ void store_klass_gap(Register s, Register dst_oop);
// oop manipulations
void load_heap_oop(const Address& s, Register d, int offset = 0);
@@ -2103,6 +2104,8 @@
inline void set_oop_constant( jobject obj, Register d ); // uses constant_oop_address
inline void set_oop ( Address obj_addr ); // same as load_address
+ void set_narrow_oop( jobject obj, Register d );
+
// nop padding
void align(int modulus);
--- a/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp Fri May 30 07:22:22 2008 -0700
@@ -87,6 +87,17 @@
#ifdef _LP64
jint inst2;
guarantee(Assembler::inv_op2(inst)==Assembler::sethi_op2, "must be sethi");
+ if (format() != 0) {
+ assert(type() == relocInfo::oop_type, "only narrow oops case");
+ jint np = oopDesc::encode_heap_oop((oop)x);
+ inst &= ~Assembler::hi22(-1);
+ inst |= Assembler::hi22((intptr_t)np);
+ ip->set_long_at(0, inst);
+ inst2 = ip->long_at( NativeInstruction::nop_instruction_size );
+ guarantee(Assembler::inv_op(inst2)==Assembler::arith_op, "arith op");
+ ip->set_long_at(NativeInstruction::nop_instruction_size, ip->set_data32_simm13( inst2, (intptr_t)np));
+ break;
+ }
ip->set_data64_sethi( ip->addr_at(0), (intptr_t)x );
#ifdef COMPILER2
// [RGV] Someone must have missed putting in a reloc entry for the
--- a/hotspot/src/cpu/sparc/vm/relocInfo_sparc.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/sparc/vm/relocInfo_sparc.hpp Fri May 30 07:22:22 2008 -0700
@@ -31,7 +31,12 @@
// There is no need for format bits; the instructions are
// sufficiently self-identifying.
+#ifndef _LP64
format_width = 0
+#else
+ // Except narrow oops in 64-bits VM.
+ format_width = 1
+#endif
};
--- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Fri May 30 07:22:22 2008 -0700
@@ -2556,7 +2556,6 @@
int total_strings = 0;
int first_arg_to_pass = 0;
int total_c_args = 0;
- int box_offset = java_lang_boxing_object::value_offset_in_bytes();
// Skip the receiver as dtrace doesn't want to see it
if( !method->is_static() ) {
@@ -2778,7 +2777,9 @@
__ br_null(in_reg, true, Assembler::pn, skipUnbox);
__ delayed()->mov(G0, tmp);
- switch (out_sig_bt[c_arg]) {
+ BasicType bt = out_sig_bt[c_arg];
+ int box_offset = java_lang_boxing_object::value_offset_in_bytes(bt);
+ switch (bt) {
case T_BYTE:
__ ldub(in_reg, box_offset, tmp); break;
case T_SHORT:
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Fri May 30 07:22:22 2008 -0700
@@ -5471,7 +5471,6 @@
// Load Klass Pointer
instruct loadKlass(iRegP dst, memory mem) %{
match(Set dst (LoadKlass mem));
- predicate(!n->in(MemNode::Address)->bottom_type()->is_narrow());
ins_cost(MEMORY_REF_COST);
size(4);
@@ -5486,11 +5485,11 @@
ins_pipe(iload_mem);
%}
-// Load Klass Pointer
-instruct loadKlassComp(iRegP dst, memory mem) %{
- match(Set dst (LoadKlass mem));
- predicate(n->in(MemNode::Address)->bottom_type()->is_narrow());
+// Load narrow Klass Pointer
+instruct loadNKlass(iRegN dst, memory mem) %{
+ match(Set dst (LoadNKlass mem));
ins_cost(MEMORY_REF_COST);
+ size(4);
format %{ "LDUW $mem,$dst\t! compressed klass ptr" %}
@@ -5503,9 +5502,6 @@
} else {
__ lduw(base, $mem$$disp, dst);
}
- // klass oop never null but this is generated for nonheader klass loads
- // too which can be null.
- __ decode_heap_oop(dst);
%}
ins_pipe(iload_mem);
%}
@@ -5609,22 +5605,24 @@
ins_pipe(loadConP_poll);
%}
+instruct loadConN0(iRegN dst, immN0 src) %{
+ match(Set dst src);
+
+ size(4);
+ format %{ "CLR $dst\t! compressed NULL ptr" %}
+ ins_encode( SetNull( dst ) );
+ ins_pipe(ialu_imm);
+%}
+
instruct loadConN(iRegN dst, immN src) %{
match(Set dst src);
- ins_cost(DEFAULT_COST * 2);
- format %{ "SET $src,$dst\t!ptr" %}
+ ins_cost(DEFAULT_COST * 3/2);
+ format %{ "SET $src,$dst\t! compressed ptr" %}
ins_encode %{
- address con = (address)$src$$constant;
Register dst = $dst$$Register;
- if (con == NULL) {
- __ mov(G0, dst);
- } else {
- __ set_oop((jobject)$src$$constant, dst);
- __ encode_heap_oop(dst);
- }
- %}
- ins_pipe(loadConP);
-
+ __ set_narrow_oop((jobject)$src$$constant, dst);
+ %}
+ ins_pipe(ialu_hi_lo_reg);
%}
instruct loadConL(iRegL dst, immL src, o7RegL tmp) %{
@@ -6258,6 +6256,34 @@
ins_pipe(ialu_imm);
%}
+// Conditional move for RegN. Only cmov(reg,reg).
+instruct cmovNP_reg(cmpOpP cmp, flagsRegP pcc, iRegN dst, iRegN src) %{
+ match(Set dst (CMoveN (Binary cmp pcc) (Binary dst src)));
+ ins_cost(150);
+ format %{ "MOV$cmp $pcc,$src,$dst" %}
+ ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::ptr_cc)) );
+ ins_pipe(ialu_reg);
+%}
+
+// This instruction also works with CmpN so we don't need cmovNN_reg.
+instruct cmovNI_reg(cmpOp cmp, flagsReg icc, iRegN dst, iRegN src) %{
+ match(Set dst (CMoveN (Binary cmp icc) (Binary dst src)));
+ ins_cost(150);
+ size(4);
+ format %{ "MOV$cmp $icc,$src,$dst" %}
+ ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) );
+ ins_pipe(ialu_reg);
+%}
+
+instruct cmovNF_reg(cmpOpF cmp, flagsRegF fcc, iRegN dst, iRegN src) %{
+ match(Set dst (CMoveN (Binary cmp fcc) (Binary dst src)));
+ ins_cost(150);
+ size(4);
+ format %{ "MOV$cmp $fcc,$src,$dst" %}
+ ins_encode( enc_cmov_reg_f(cmp,dst,src, fcc) );
+ ins_pipe(ialu_reg);
+%}
+
// Conditional move
instruct cmovPP_reg(cmpOpP cmp, flagsRegP pcc, iRegP dst, iRegP src) %{
match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src)));
@@ -6275,6 +6301,7 @@
ins_pipe(ialu_imm);
%}
+// This instruction also works with CmpN so we don't need cmovPN_reg.
instruct cmovPI_reg(cmpOp cmp, flagsReg icc, iRegP dst, iRegP src) %{
match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
ins_cost(150);
@@ -8265,6 +8292,27 @@
ins_pipe(ialu_cconly_reg_imm);
%}
+// Compare Narrow oops
+instruct compN_iRegN(flagsReg icc, iRegN op1, iRegN op2 ) %{
+ match(Set icc (CmpN op1 op2));
+
+ size(4);
+ format %{ "CMP $op1,$op2\t! compressed ptr" %}
+ opcode(Assembler::subcc_op3, Assembler::arith_op);
+ ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) );
+ ins_pipe(ialu_cconly_reg_reg);
+%}
+
+instruct compN_iRegN_immN0(flagsReg icc, iRegN op1, immN0 op2 ) %{
+ match(Set icc (CmpN op1 op2));
+
+ size(4);
+ format %{ "CMP $op1,$op2\t! compressed ptr" %}
+ opcode(Assembler::subcc_op3, Assembler::arith_op);
+ ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) );
+ ins_pipe(ialu_cconly_reg_imm);
+%}
+
//----------Max and Min--------------------------------------------------------
// Min Instructions
// Conditional move for min
@@ -8595,6 +8643,14 @@
ins_pipe(ialu_imm);
%}
+instruct cmovNL_reg(cmpOp cmp, flagsRegL xcc, iRegN dst, iRegN src) %{
+ match(Set dst (CMoveN (Binary cmp xcc) (Binary dst src)));
+ ins_cost(150);
+ format %{ "MOV$cmp $xcc,$src,$dst" %}
+ ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::xcc)) );
+ ins_pipe(ialu_reg);
+%}
+
instruct cmovPL_reg(cmpOp cmp, flagsRegL xcc, iRegP dst, iRegP src) %{
match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
ins_cost(150);
@@ -8826,16 +8882,6 @@
%}
-instruct compP_iRegN_immN0(flagsRegP pcc, iRegN op1, immN0 op2 ) %{
- match(Set pcc (CmpN op1 op2));
-
- size(4);
- format %{ "CMP $op1,$op2\t! ptr" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_imm);
-%}
-
// ============================================================================
// inlined locking and unlocking
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Fri May 30 07:22:22 2008 -0700
@@ -3222,7 +3222,8 @@
__ set((intptr_t)markOopDesc::prototype(), G4_scratch);
}
__ st_ptr(G4_scratch, RallocatedObject, oopDesc::mark_offset_in_bytes()); // mark
- __ store_klass(RinstanceKlass, RallocatedObject); // klass
+ __ store_klass_gap(G0, RallocatedObject); // klass gap if compressed
+ __ store_klass(RinstanceKlass, RallocatedObject); // klass (last for cms)
{
SkipIfEqual skip_if(
--- a/hotspot/src/cpu/x86/vm/assembler_x86_32.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/assembler_x86_32.hpp Fri May 30 07:22:22 2008 -0700
@@ -1054,7 +1054,7 @@
// range (0 <= offset <= page_size).
void null_check(Register reg, int offset = -1);
- static bool needs_explicit_null_check(int offset);
+ static bool needs_explicit_null_check(intptr_t offset);
// Required platform-specific helpers for Label::patch_instructions.
// They _shadow_ the declarations in AbstractAssembler, which are undefined.
--- a/hotspot/src/cpu/x86/vm/assembler_x86_64.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/assembler_x86_64.cpp Fri May 30 07:22:22 2008 -0700
@@ -683,7 +683,8 @@
case REP8(0xB8): // movl/q r, #32/#64(oop?)
if (which == end_pc_operand) return ip + (is_64bit ? 8 : 4);
- assert((which == call32_operand || which == imm64_operand) && is_64bit, "");
+ assert((which == call32_operand || which == imm64_operand) && is_64bit ||
+ which == narrow_oop_operand && !is_64bit, "");
return ip;
case 0x69: // imul r, a, #32
@@ -909,7 +910,8 @@
} else if (r->is_call() || format == call32_operand) {
opnd = locate_operand(inst, call32_operand);
} else if (r->is_data()) {
- assert(format == imm64_operand || format == disp32_operand, "format ok");
+ assert(format == imm64_operand || format == disp32_operand ||
+ format == narrow_oop_operand, "format ok");
opnd = locate_operand(inst, (WhichOperand) format);
} else {
assert(format == 0, "cannot specify a format");
@@ -4933,6 +4935,8 @@
movq(Address(top, arrayOopDesc::length_offset_in_bytes()), t1);
// set klass to intArrayKlass
movptr(t1, ExternalAddress((address) Universe::intArrayKlassObj_addr()));
+ // store klass last. concurrent gcs assumes klass length is valid if
+ // klass field is not null.
store_klass(top, t1);
// refill the tlab with an eden allocation
@@ -5157,14 +5161,19 @@
void MacroAssembler::store_klass(Register dst, Register src) {
if (UseCompressedOops) {
encode_heap_oop_not_null(src);
- // zero the entire klass field first as the gap needs to be zeroed too.
- movptr(Address(dst, oopDesc::klass_offset_in_bytes()), NULL_WORD);
movl(Address(dst, oopDesc::klass_offset_in_bytes()), src);
} else {
movq(Address(dst, oopDesc::klass_offset_in_bytes()), src);
}
}
+void MacroAssembler::store_klass_gap(Register dst, Register src) {
+ if (UseCompressedOops) {
+ // Store to klass gap in destination
+ movl(Address(dst, oopDesc::klass_gap_offset_in_bytes()), src);
+ }
+}
+
void MacroAssembler::load_heap_oop(Register dst, Address src) {
if (UseCompressedOops) {
movl(dst, src);
@@ -5188,13 +5197,15 @@
void MacroAssembler::encode_heap_oop(Register r) {
assert (UseCompressedOops, "should be compressed");
#ifdef ASSERT
- Label ok;
- pushq(rscratch1); // cmpptr trashes rscratch1
- cmpptr(r12_heapbase, ExternalAddress((address)Universe::heap_base_addr()));
- jcc(Assembler::equal, ok);
- stop("MacroAssembler::encode_heap_oop: heap base corrupted?");
- bind(ok);
- popq(rscratch1);
+ if (CheckCompressedOops) {
+ Label ok;
+ pushq(rscratch1); // cmpptr trashes rscratch1
+ cmpptr(r12_heapbase, ExternalAddress((address)Universe::heap_base_addr()));
+ jcc(Assembler::equal, ok);
+ stop("MacroAssembler::encode_heap_oop: heap base corrupted?");
+ bind(ok);
+ popq(rscratch1);
+ }
#endif
verify_oop(r, "broken oop in encode_heap_oop");
testq(r, r);
@@ -5206,11 +5217,13 @@
void MacroAssembler::encode_heap_oop_not_null(Register r) {
assert (UseCompressedOops, "should be compressed");
#ifdef ASSERT
- Label ok;
- testq(r, r);
- jcc(Assembler::notEqual, ok);
- stop("null oop passed to encode_heap_oop_not_null");
- bind(ok);
+ if (CheckCompressedOops) {
+ Label ok;
+ testq(r, r);
+ jcc(Assembler::notEqual, ok);
+ stop("null oop passed to encode_heap_oop_not_null");
+ bind(ok);
+ }
#endif
verify_oop(r, "broken oop in encode_heap_oop_not_null");
subq(r, r12_heapbase);
@@ -5220,11 +5233,13 @@
void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) {
assert (UseCompressedOops, "should be compressed");
#ifdef ASSERT
- Label ok;
- testq(src, src);
- jcc(Assembler::notEqual, ok);
- stop("null oop passed to encode_heap_oop_not_null2");
- bind(ok);
+ if (CheckCompressedOops) {
+ Label ok;
+ testq(src, src);
+ jcc(Assembler::notEqual, ok);
+ stop("null oop passed to encode_heap_oop_not_null2");
+ bind(ok);
+ }
#endif
verify_oop(src, "broken oop in encode_heap_oop_not_null2");
if (dst != src) {
@@ -5237,14 +5252,16 @@
void MacroAssembler::decode_heap_oop(Register r) {
assert (UseCompressedOops, "should be compressed");
#ifdef ASSERT
- Label ok;
- pushq(rscratch1);
- cmpptr(r12_heapbase,
- ExternalAddress((address)Universe::heap_base_addr()));
- jcc(Assembler::equal, ok);
- stop("MacroAssembler::decode_heap_oop: heap base corrupted?");
- bind(ok);
- popq(rscratch1);
+ if (CheckCompressedOops) {
+ Label ok;
+ pushq(rscratch1);
+ cmpptr(r12_heapbase,
+ ExternalAddress((address)Universe::heap_base_addr()));
+ jcc(Assembler::equal, ok);
+ stop("MacroAssembler::decode_heap_oop: heap base corrupted?");
+ bind(ok);
+ popq(rscratch1);
+ }
#endif
Label done;
@@ -5277,6 +5294,19 @@
leaq(dst, Address(r12_heapbase, src, Address::times_8, 0));
}
+void MacroAssembler::set_narrow_oop(Register dst, jobject obj) {
+ assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int oop_index = oop_recorder()->find_index(obj);
+ RelocationHolder rspec = oop_Relocation::spec(oop_index);
+
+ // movl dst,obj
+ InstructionMark im(this);
+ int encode = prefix_and_encode(dst->encoding());
+ emit_byte(0xB8 | encode);
+ emit_data(oop_index, rspec, narrow_oop_operand);
+}
+
+
Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) {
switch (cond) {
// Note some conditions are synonyms for others
--- a/hotspot/src/cpu/x86/vm/assembler_x86_64.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/assembler_x86_64.hpp Fri May 30 07:22:22 2008 -0700
@@ -490,7 +490,12 @@
imm64_operand = 0, // embedded 64-bit immediate operand
disp32_operand = 1, // embedded 32-bit displacement
call32_operand = 2, // embedded 32-bit self-relative displacement
+#ifndef AMD64
_WhichOperand_limit = 3
+#else
+ narrow_oop_operand = 3, // embedded 32-bit immediate narrow oop
+ _WhichOperand_limit = 4
+#endif
};
public:
@@ -1023,7 +1028,7 @@
// is needed if the offset is within a certain range (0 <= offset <=
// page_size).
void null_check(Register reg, int offset = -1);
- static bool needs_explicit_null_check(int offset);
+ static bool needs_explicit_null_check(intptr_t offset);
// Required platform-specific helpers for Label::patch_instructions.
// They _shadow_ the declarations in AbstractAssembler, which are undefined.
@@ -1104,6 +1109,7 @@
// oop manipulations
void load_klass(Register dst, Register src);
void store_klass(Register dst, Register src);
+ void store_klass_gap(Register dst, Register src);
void load_heap_oop(Register dst, Address src);
void store_heap_oop(Address dst, Register src);
@@ -1114,6 +1120,8 @@
void encode_heap_oop_not_null(Register dst, Register src);
void decode_heap_oop_not_null(Register dst, Register src);
+ void set_narrow_oop(Register dst, jobject obj);
+
// Stack frame creation/removal
void enter();
void leave();
--- a/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp Fri May 30 07:22:22 2008 -0700
@@ -30,11 +30,15 @@
#ifdef AMD64
x += o;
typedef Assembler::WhichOperand WhichOperand;
- WhichOperand which = (WhichOperand) format(); // that is, disp32 or imm64, call32
+ WhichOperand which = (WhichOperand) format(); // that is, disp32 or imm64, call32, narrow oop
assert(which == Assembler::disp32_operand ||
+ which == Assembler::narrow_oop_operand ||
which == Assembler::imm64_operand, "format unpacks ok");
if (which == Assembler::imm64_operand) {
*pd_address_in_code() = x;
+ } else if (which == Assembler::narrow_oop_operand) {
+ address disp = Assembler::locate_operand(addr(), which);
+ *(int32_t*) disp = oopDesc::encode_heap_oop((oop)x);
} else {
// Note: Use runtime_call_type relocations for call32_operand.
address ip = addr();
--- a/hotspot/src/cpu/x86/vm/relocInfo_x86.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/relocInfo_x86.hpp Fri May 30 07:22:22 2008 -0700
@@ -29,5 +29,10 @@
offset_unit = 1,
// Encodes Assembler::disp32_operand vs. Assembler::imm32_operand.
+#ifndef AMD64
format_width = 1
+#else
+ // vs Assembler::narrow_oop_operand.
+ format_width = 2
+#endif
};
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Fri May 30 07:22:22 2008 -0700
@@ -1920,7 +1920,6 @@
int total_strings = 0;
int first_arg_to_pass = 0;
int total_c_args = 0;
- int box_offset = java_lang_boxing_object::value_offset_in_bytes();
if( !method->is_static() ) { // Pass in receiver first
in_sig_bt[i++] = T_OBJECT;
@@ -2131,7 +2130,10 @@
assert(dst.first()->is_stack() &&
(!dst.second()->is_valid() || dst.second()->is_stack()),
"value(s) must go into stack slots");
- if ( out_sig_bt[c_arg] == T_LONG ) {
+
+ BasicType bt = out_sig_bt[c_arg];
+ int box_offset = java_lang_boxing_object::value_offset_in_bytes(bt);
+ if ( bt == T_LONG ) {
__ movl(rbx, Address(in_reg,
box_offset + VMRegImpl::stack_slot_size));
__ movl(Address(rsp, reg2offset_out(dst.second())), rbx);
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Fri May 30 07:22:22 2008 -0700
@@ -1950,7 +1950,6 @@
int total_strings = 0;
int first_arg_to_pass = 0;
int total_c_args = 0;
- int box_offset = java_lang_boxing_object::value_offset_in_bytes();
// Skip the receiver as dtrace doesn't want to see it
if( !method->is_static() ) {
@@ -2197,8 +2196,10 @@
__ testq(in_reg, in_reg);
__ jcc(Assembler::zero, skipUnbox);
+ BasicType bt = out_sig_bt[c_arg];
+ int box_offset = java_lang_boxing_object::value_offset_in_bytes(bt);
Address src1(in_reg, box_offset);
- if ( out_sig_bt[c_arg] == T_LONG ) {
+ if ( bt == T_LONG ) {
__ movq(in_reg, src1);
__ movq(stack_dst, in_reg);
assert(out_sig_bt[c_arg+1] == T_VOID, "must be");
@@ -2460,8 +2461,10 @@
Label skip;
__ testq(r, r);
__ jcc(Assembler::equal, skip);
+ BasicType bt = out_sig_bt[c_arg];
+ int box_offset = java_lang_boxing_object::value_offset_in_bytes(bt);
Address src1(r, box_offset);
- if ( out_sig_bt[c_arg] == T_LONG ) {
+ if ( bt == T_LONG ) {
__ movq(r, src1);
} else {
__ movl(r, src1);
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Fri May 30 07:22:22 2008 -0700
@@ -3163,7 +3163,9 @@
__ movptr(Address(rax, oopDesc::mark_offset_in_bytes()),
(intptr_t) markOopDesc::prototype()); // header (address 0x1)
}
- __ store_klass(rax, rsi); // klass
+ __ xorl(rcx, rcx); // use zero reg to clear memory (shorter code)
+ __ store_klass_gap(rax, rcx); // zero klass gap for compressed oops
+ __ store_klass(rax, rsi); // store klass last
__ jmp(done);
}
--- a/hotspot/src/cpu/x86/vm/x86_32.ad Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad Fri May 30 07:22:22 2008 -0700
@@ -3806,6 +3806,78 @@
masm.bind(DONE_LABEL);
%}
+ enc_class enc_Array_Equals(eDIRegP ary1, eSIRegP ary2, eAXRegI tmp1, eBXRegI tmp2, eCXRegI result) %{
+ Label TRUE_LABEL, FALSE_LABEL, DONE_LABEL, COMPARE_LOOP_HDR, COMPARE_LOOP;
+ MacroAssembler masm(&cbuf);
+
+ Register ary1Reg = as_Register($ary1$$reg);
+ Register ary2Reg = as_Register($ary2$$reg);
+ Register tmp1Reg = as_Register($tmp1$$reg);
+ Register tmp2Reg = as_Register($tmp2$$reg);
+ Register resultReg = as_Register($result$$reg);
+
+ int length_offset = arrayOopDesc::length_offset_in_bytes();
+ int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
+
+ // Check the input args
+ masm.cmpl(ary1Reg, ary2Reg);
+ masm.jcc(Assembler::equal, TRUE_LABEL);
+ masm.testl(ary1Reg, ary1Reg);
+ masm.jcc(Assembler::zero, FALSE_LABEL);
+ masm.testl(ary2Reg, ary2Reg);
+ masm.jcc(Assembler::zero, FALSE_LABEL);
+
+ // Check the lengths
+ masm.movl(tmp2Reg, Address(ary1Reg, length_offset));
+ masm.movl(resultReg, Address(ary2Reg, length_offset));
+ masm.cmpl(tmp2Reg, resultReg);
+ masm.jcc(Assembler::notEqual, FALSE_LABEL);
+ masm.testl(resultReg, resultReg);
+ masm.jcc(Assembler::zero, TRUE_LABEL);
+
+ // Get the number of 4 byte vectors to compare
+ masm.shrl(resultReg, 1);
+
+ // Check for odd-length arrays
+ masm.andl(tmp2Reg, 1);
+ masm.testl(tmp2Reg, tmp2Reg);
+ masm.jcc(Assembler::zero, COMPARE_LOOP_HDR);
+
+ // Compare 2-byte "tail" at end of arrays
+ masm.load_unsigned_word(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
+ masm.load_unsigned_word(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
+ masm.cmpl(tmp1Reg, tmp2Reg);
+ masm.jcc(Assembler::notEqual, FALSE_LABEL);
+ masm.testl(resultReg, resultReg);
+ masm.jcc(Assembler::zero, TRUE_LABEL);
+
+ // Setup compare loop
+ masm.bind(COMPARE_LOOP_HDR);
+ // Shift tmp1Reg and tmp2Reg to the last 4-byte boundary of the arrays
+ masm.leal(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
+ masm.leal(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
+ masm.negl(resultReg);
+
+ // 4-byte-wide compare loop
+ masm.bind(COMPARE_LOOP);
+ masm.movl(ary1Reg, Address(tmp1Reg, resultReg, Address::times_4, 0));
+ masm.movl(ary2Reg, Address(tmp2Reg, resultReg, Address::times_4, 0));
+ masm.cmpl(ary1Reg, ary2Reg);
+ masm.jcc(Assembler::notEqual, FALSE_LABEL);
+ masm.increment(resultReg);
+ masm.jcc(Assembler::notZero, COMPARE_LOOP);
+
+ masm.bind(TRUE_LABEL);
+ masm.movl(resultReg, 1); // return true
+ masm.jmp(DONE_LABEL);
+
+ masm.bind(FALSE_LABEL);
+ masm.xorl(resultReg, resultReg); // return false
+
+ // That's it
+ masm.bind(DONE_LABEL);
+ %}
+
enc_class enc_pop_rdx() %{
emit_opcode(cbuf,0x5A);
%}
@@ -11565,6 +11637,17 @@
ins_pipe( pipe_slow );
%}
+// fast array equals
+instruct array_equals(eDIRegP ary1, eSIRegP ary2, eAXRegI tmp1, eBXRegI tmp2, eCXRegI result, eFlagsReg cr) %{
+ match(Set result (AryEq ary1 ary2));
+ effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL cr);
+ //ins_cost(300);
+
+ format %{ "Array Equals $ary1,$ary2 -> $result // KILL EAX, EBX" %}
+ ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result) );
+ ins_pipe( pipe_slow );
+%}
+
//----------Control Flow Instructions------------------------------------------
// Signed compare Instructions
instruct compI_eReg(eFlagsReg cr, eRegI op1, eRegI op2) %{
--- a/hotspot/src/cpu/x86/vm/x86_64.ad Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad Fri May 30 07:22:22 2008 -0700
@@ -3808,6 +3808,78 @@
masm.bind(DONE_LABEL);
%}
+ enc_class enc_Array_Equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI tmp1, rbx_RegI tmp2, rcx_RegI result) %{
+ Label TRUE_LABEL, FALSE_LABEL, DONE_LABEL, COMPARE_LOOP_HDR, COMPARE_LOOP;
+ MacroAssembler masm(&cbuf);
+
+ Register ary1Reg = as_Register($ary1$$reg);
+ Register ary2Reg = as_Register($ary2$$reg);
+ Register tmp1Reg = as_Register($tmp1$$reg);
+ Register tmp2Reg = as_Register($tmp2$$reg);
+ Register resultReg = as_Register($result$$reg);
+
+ int length_offset = arrayOopDesc::length_offset_in_bytes();
+ int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
+
+ // Check the input args
+ masm.cmpq(ary1Reg, ary2Reg);
+ masm.jcc(Assembler::equal, TRUE_LABEL);
+ masm.testq(ary1Reg, ary1Reg);
+ masm.jcc(Assembler::zero, FALSE_LABEL);
+ masm.testq(ary2Reg, ary2Reg);
+ masm.jcc(Assembler::zero, FALSE_LABEL);
+
+ // Check the lengths
+ masm.movl(tmp2Reg, Address(ary1Reg, length_offset));
+ masm.movl(resultReg, Address(ary2Reg, length_offset));
+ masm.cmpl(tmp2Reg, resultReg);
+ masm.jcc(Assembler::notEqual, FALSE_LABEL);
+ masm.testl(resultReg, resultReg);
+ masm.jcc(Assembler::zero, TRUE_LABEL);
+
+ // Get the number of 4 byte vectors to compare
+ masm.shrl(resultReg, 1);
+
+ // Check for odd-length arrays
+ masm.andl(tmp2Reg, 1);
+ masm.testl(tmp2Reg, tmp2Reg);
+ masm.jcc(Assembler::zero, COMPARE_LOOP_HDR);
+
+ // Compare 2-byte "tail" at end of arrays
+ masm.load_unsigned_word(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
+ masm.load_unsigned_word(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
+ masm.cmpl(tmp1Reg, tmp2Reg);
+ masm.jcc(Assembler::notEqual, FALSE_LABEL);
+ masm.testl(resultReg, resultReg);
+ masm.jcc(Assembler::zero, TRUE_LABEL);
+
+ // Setup compare loop
+ masm.bind(COMPARE_LOOP_HDR);
+ // Shift tmp1Reg and tmp2Reg to the last 4-byte boundary of the arrays
+ masm.leaq(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
+ masm.leaq(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
+ masm.negq(resultReg);
+
+ // 4-byte-wide compare loop
+ masm.bind(COMPARE_LOOP);
+ masm.movl(ary1Reg, Address(tmp1Reg, resultReg, Address::times_4, 0));
+ masm.movl(ary2Reg, Address(tmp2Reg, resultReg, Address::times_4, 0));
+ masm.cmpl(ary1Reg, ary2Reg);
+ masm.jcc(Assembler::notEqual, FALSE_LABEL);
+ masm.incrementq(resultReg);
+ masm.jcc(Assembler::notZero, COMPARE_LOOP);
+
+ masm.bind(TRUE_LABEL);
+ masm.movl(resultReg, 1); // return true
+ masm.jmp(DONE_LABEL);
+
+ masm.bind(FALSE_LABEL);
+ masm.xorl(resultReg, resultReg); // return false
+
+ // That's it
+ masm.bind(DONE_LABEL);
+ %}
+
enc_class enc_rethrow()
%{
cbuf.set_inst_mark();
@@ -5202,15 +5274,15 @@
%}
%}
-// Indirect Memory Times Scale Plus Index Register Plus Offset Operand
-operand indIndexScaleOffsetComp(rRegN src, immL32 off, r12RegL base) %{
+// Indirect Narrow Oop Plus Offset Operand
+operand indNarrowOopOffset(rRegN src, immL32 off) %{
constraint(ALLOC_IN_RC(ptr_reg));
- match(AddP (DecodeN src base) off);
+ match(AddP (DecodeN src) off);
op_cost(10);
- format %{"[$base + $src << 3 + $off] (compressed)" %}
+ format %{"[R12 + $src << 3 + $off] (compressed oop addressing)" %}
interface(MEMORY_INTER) %{
- base($base);
+ base(0xc); // R12
index($src);
scale(0x3);
disp($off);
@@ -5365,7 +5437,7 @@
opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex,
indIndexScale, indIndexScaleOffset, indPosIndexScaleOffset,
- indIndexScaleOffsetComp);
+ indNarrowOopOffset);
//----------PIPELINE-----------------------------------------------------------
// Rules which define the behavior of the target architectures pipeline.
@@ -6044,10 +6116,9 @@
%}
// Load Compressed Pointer
-instruct loadN(rRegN dst, memory mem, rFlagsReg cr)
+instruct loadN(rRegN dst, memory mem)
%{
match(Set dst (LoadN mem));
- effect(KILL cr);
ins_cost(125); // XXX
format %{ "movl $dst, $mem\t# compressed ptr" %}
@@ -6064,7 +6135,6 @@
instruct loadKlass(rRegP dst, memory mem)
%{
match(Set dst (LoadKlass mem));
- predicate(!n->in(MemNode::Address)->bottom_type()->is_narrow());
ins_cost(125); // XXX
format %{ "movq $dst, $mem\t# class" %}
@@ -6073,22 +6143,17 @@
ins_pipe(ialu_reg_mem); // XXX
%}
-// Load Klass Pointer
-instruct loadKlassComp(rRegP dst, memory mem)
-%{
- match(Set dst (LoadKlass mem));
- predicate(n->in(MemNode::Address)->bottom_type()->is_narrow());
+// Load narrow Klass Pointer
+instruct loadNKlass(rRegN dst, memory mem)
+%{
+ match(Set dst (LoadNKlass mem));
ins_cost(125); // XXX
- format %{ "movl $dst, $mem\t# compressed class\n\t"
- "decode_heap_oop $dst,$dst" %}
+ format %{ "movl $dst, $mem\t# compressed klass ptr\n\t" %}
ins_encode %{
Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp);
Register dst = as_Register($dst$$reg);
__ movl(dst, addr);
- // klass is never null in the header but this is generated for all
- // klass loads not just the _klass field in the header.
- __ decode_heap_oop(dst);
%}
ins_pipe(ialu_reg_mem); // XXX
%}
@@ -6362,16 +6427,14 @@
match(Set dst src);
ins_cost(125);
- format %{ "movq $dst, $src\t# compressed ptr\n\t"
- "encode_heap_oop_not_null $dst,$dst" %}
+ format %{ "movl $dst, $src\t# compressed ptr" %}
ins_encode %{
address con = (address)$src$$constant;
Register dst = $dst$$Register;
if (con == NULL) {
ShouldNotReachHere();
} else {
- __ movoop(dst, (jobject)$src$$constant);
- __ encode_heap_oop_not_null(dst);
+ __ set_narrow_oop(dst, (jobject)$src$$constant);
}
%}
ins_pipe(ialu_reg_fat); // XXX
@@ -6633,13 +6696,12 @@
%}
// Store Compressed Pointer
-instruct storeN(memory mem, rRegN src, rFlagsReg cr)
+instruct storeN(memory mem, rRegN src)
%{
match(Set mem (StoreN mem src));
- effect(KILL cr);
ins_cost(125); // XXX
- format %{ "movl $mem, $src\t# ptr" %}
+ format %{ "movl $mem, $src\t# compressed ptr" %}
ins_encode %{
Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp);
Register src = as_Register($src$$reg);
@@ -7143,6 +7205,30 @@
%}
// Conditional move
+instruct cmovN_reg(rRegN dst, rRegN src, rFlagsReg cr, cmpOp cop)
+%{
+ match(Set dst (CMoveN (Binary cop cr) (Binary dst src)));
+
+ ins_cost(200); // XXX
+ format %{ "cmovl$cop $dst, $src\t# signed, compressed ptr" %}
+ opcode(0x0F, 0x40);
+ ins_encode(REX_reg_reg(dst, src), enc_cmov(cop), reg_reg(dst, src));
+ ins_pipe(pipe_cmov_reg);
+%}
+
+// Conditional move
+instruct cmovN_regU(rRegN dst, rRegN src, rFlagsRegU cr, cmpOpU cop)
+%{
+ match(Set dst (CMoveN (Binary cop cr) (Binary dst src)));
+
+ ins_cost(200); // XXX
+ format %{ "cmovl$cop $dst, $src\t# unsigned, compressed ptr" %}
+ opcode(0x0F, 0x40);
+ ins_encode(REX_reg_reg(dst, src), enc_cmov(cop), reg_reg(dst, src));
+ ins_pipe(pipe_cmov_reg);
+%}
+
+// Conditional move
instruct cmovP_reg(rRegP dst, rRegP src, rFlagsReg cr, cmpOp cop)
%{
match(Set dst (CMoveP (Binary cop cr) (Binary dst src)));
@@ -10862,6 +10948,18 @@
ins_pipe( pipe_slow );
%}
+// fast array equals
+instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI tmp1,
+ rbx_RegI tmp2, rcx_RegI result, rFlagsReg cr) %{
+ match(Set result (AryEq ary1 ary2));
+ effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL cr);
+ //ins_cost(300);
+
+ format %{ "Array Equals $ary1,$ary2 -> $result // KILL RAX, RBX" %}
+ ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result) );
+ ins_pipe( pipe_slow );
+%}
+
//----------Control Flow Instructions------------------------------------------
// Signed compare Instructions
@@ -11055,14 +11153,50 @@
ins_pipe(ialu_cr_reg_imm);
%}
+
+instruct compN_rReg(rFlagsRegU cr, rRegN op1, rRegN op2)
+%{
+ match(Set cr (CmpN op1 op2));
+
+ format %{ "cmpl $op1, $op2\t# compressed ptr" %}
+ ins_encode %{ __ cmpl(as_Register($op1$$reg), as_Register($op2$$reg)); %}
+ ins_pipe(ialu_cr_reg_reg);
+%}
+
+instruct compN_rReg_mem(rFlagsRegU cr, rRegN src, memory mem)
+%{
+ match(Set cr (CmpN src (LoadN mem)));
+
+ ins_cost(500); // XXX
+ format %{ "cmpl $src, mem\t# compressed ptr" %}
+ ins_encode %{
+ Address adr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp);
+ __ cmpl(as_Register($src$$reg), adr);
+ %}
+ ins_pipe(ialu_cr_reg_mem);
+%}
+
instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{
match(Set cr (CmpN src zero));
- format %{ "testl $src, $src" %}
+ format %{ "testl $src, $src\t# compressed ptr" %}
ins_encode %{ __ testl($src$$Register, $src$$Register); %}
ins_pipe(ialu_cr_reg_imm);
%}
+instruct testN_reg_mem(rFlagsReg cr, memory mem, immN0 zero)
+%{
+ match(Set cr (CmpN (LoadN mem) zero));
+
+ ins_cost(500); // XXX
+ format %{ "testl $mem, 0xffffffff\t# compressed ptr" %}
+ ins_encode %{
+ Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp);
+ __ cmpl(addr, (int)0xFFFFFFFF);
+ %}
+ ins_pipe(ialu_cr_reg_mem);
+%}
+
// Yanked all unsigned pointer compare operations.
// Pointer compares are done with CmpP which is already unsigned.
--- a/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_32.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_32.cpp Fri May 30 07:22:22 2008 -0700
@@ -40,7 +40,7 @@
movptr(thread, tls);
}
-bool MacroAssembler::needs_explicit_null_check(int offset) {
+bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// Linux kernel guarantees that the first page is always unmapped. Don't
// assume anything more than that.
bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size();
--- a/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_64.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_64.cpp Fri May 30 07:22:22 2008 -0700
@@ -66,8 +66,21 @@
}
}
-// NOTE: since the linux kernel resides at the low end of
-// user address space, no null pointer check is needed.
-bool MacroAssembler::needs_explicit_null_check(int offset) {
- return offset < 0 || offset >= 0x100000;
+bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
+ // Exception handler checks the nmethod's implicit null checks table
+ // only when this method returns false.
+ if (UseCompressedOops) {
+ // The first page after heap_base is unmapped and
+ // the 'offset' is equal to [heap_base + offset] for
+ // narrow oop implicit null checks.
+ uintptr_t heap_base = (uintptr_t)Universe::heap_base();
+ if ((uintptr_t)offset >= heap_base) {
+ // Normalize offset for the next check.
+ offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1));
+ }
+ }
+ // Linux kernel guarantees that the first page is always unmapped. Don't
+ // assume anything more than that.
+ bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size();
+ return !offset_in_first_page;
}
--- a/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_32.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_32.cpp Fri May 30 07:22:22 2008 -0700
@@ -80,7 +80,7 @@
popl(thread);
}
-bool MacroAssembler::needs_explicit_null_check(int offset) {
+bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// Identical to Sparc/Solaris code
bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size();
return !offset_in_first_page;
--- a/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_64.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_64.cpp Fri May 30 07:22:22 2008 -0700
@@ -86,8 +86,21 @@
}
}
-bool MacroAssembler::needs_explicit_null_check(int offset) {
+bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// Identical to Sparc/Solaris code
+
+ // Exception handler checks the nmethod's implicit null checks table
+ // only when this method returns false.
+ if (UseCompressedOops) {
+ // The first page after heap_base is unmapped and
+ // the 'offset' is equal to [heap_base + offset] for
+ // narrow oop implicit null checks.
+ uintptr_t heap_base = (uintptr_t)Universe::heap_base();
+ if ((uintptr_t)offset >= heap_base) {
+ // Normalize offset for the next check.
+ offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1));
+ }
+ }
bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size();
return !offset_in_first_page;
}
--- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_32.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_32.cpp Fri May 30 07:22:22 2008 -0700
@@ -59,6 +59,6 @@
movl(thread, Address(thread, ThreadLocalStorage::get_thread_ptr_offset()));
}
-bool MacroAssembler::needs_explicit_null_check(int offset) {
+bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
return offset < 0 || (int)os::vm_page_size() <= offset;
}
--- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_64.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_64.cpp Fri May 30 07:22:22 2008 -0700
@@ -66,6 +66,18 @@
}
}
-bool MacroAssembler::needs_explicit_null_check(int offset) {
- return offset < 0 || (int)os::vm_page_size() <= offset;
+bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
+ // Exception handler checks the nmethod's implicit null checks table
+ // only when this method returns false.
+ if (UseCompressedOops) {
+ // The first page after heap_base is unmapped and
+ // the 'offset' is equal to [heap_base + offset] for
+ // narrow oop implicit null checks.
+ uintptr_t heap_base = (uintptr_t)Universe::heap_base();
+ if ((uintptr_t)offset >= heap_base) {
+ // Normalize offset for the next check.
+ offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1));
+ }
+ }
+ return offset < 0 || os::vm_page_size() <= offset;
}
--- a/hotspot/src/share/vm/adlc/forms.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/adlc/forms.cpp Fri May 30 07:22:22 2008 -0700
@@ -252,6 +252,7 @@
if( strcmp(opType,"LoadF")==0 ) return Form::idealF;
if( strcmp(opType,"LoadI")==0 ) return Form::idealI;
if( strcmp(opType,"LoadKlass")==0 ) return Form::idealP;
+ if( strcmp(opType,"LoadNKlass")==0 ) return Form::idealN;
if( strcmp(opType,"LoadL")==0 ) return Form::idealL;
if( strcmp(opType,"LoadL_unaligned")==0 ) return Form::idealL;
if( strcmp(opType,"LoadPLocked")==0 ) return Form::idealP;
--- a/hotspot/src/share/vm/adlc/formssel.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/adlc/formssel.cpp Fri May 30 07:22:22 2008 -0700
@@ -3313,7 +3313,7 @@
"Store8B","Store4B","Store8C","Store4C","Store2C",
"Load4I" ,"Load2I" ,"Load2L" ,"Load2D" ,"Load4F" ,"Load2F" ,"Load16B" ,
"Load8B" ,"Load4B" ,"Load8C" ,"Load4C" ,"Load2C" ,"Load8S", "Load4S","Load2S",
- "LoadRange", "LoadKlass", "LoadL_unaligned", "LoadD_unaligned",
+ "LoadRange", "LoadKlass", "LoadNKlass", "LoadL_unaligned", "LoadD_unaligned",
"LoadPLocked", "LoadLLocked",
"StorePConditional", "StoreLConditional",
"CompareAndSwapI", "CompareAndSwapL", "CompareAndSwapP", "CompareAndSwapN",
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Fri May 30 07:22:22 2008 -0700
@@ -392,12 +392,12 @@
assert(!is_java_lang_Object(), "bootstrap OK");
// Size in bytes of my fields, including inherited fields.
- int fsize = nonstatic_field_size() * wordSize;
+ int fsize = nonstatic_field_size() * heapOopSize;
ciInstanceKlass* super = this->super();
GrowableArray<ciField*>* super_fields = NULL;
if (super != NULL && super->has_nonstatic_fields()) {
- int super_fsize = super->nonstatic_field_size() * wordSize;
+ int super_fsize = super->nonstatic_field_size() * heapOopSize;
int super_flen = super->nof_nonstatic_fields();
super_fields = super->_nonstatic_fields;
assert(super_flen == 0 || super_fields != NULL, "first get nof_fields");
@@ -438,7 +438,7 @@
// This is a minor inefficiency classFileParser.cpp.
last_offset = offset + size;
}
- assert(last_offset <= (int)sizeof(oopDesc) + fsize, "no overflow");
+ assert(last_offset <= (int)instanceOopDesc::base_offset_in_bytes() + fsize, "no overflow");
#endif
_nonstatic_fields = fields;
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Fri May 30 07:22:22 2008 -0700
@@ -2664,8 +2664,8 @@
fac.static_byte_count ), wordSize );
static_field_size = (next_static_type_offset -
next_static_oop_offset) / wordSize;
- first_nonstatic_field_offset = (instanceOopDesc::header_size() +
- nonstatic_field_size) * wordSize;
+ first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() +
+ nonstatic_field_size * heapOopSize;
next_nonstatic_field_offset = first_nonstatic_field_offset;
// Add fake fields for java.lang.Class instances (also see below)
@@ -2734,9 +2734,9 @@
next_nonstatic_byte_offset = next_nonstatic_short_offset +
(nonstatic_short_count * BytesPerShort);
next_nonstatic_type_offset = align_size_up((next_nonstatic_byte_offset +
- nonstatic_byte_count ), wordSize );
+ nonstatic_byte_count ), heapOopSize );
orig_nonstatic_field_size = nonstatic_field_size +
- ((next_nonstatic_type_offset - first_nonstatic_field_offset)/wordSize);
+ ((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize);
}
#endif
bool compact_fields = CompactFields;
@@ -2791,18 +2791,8 @@
int nonstatic_short_space_offset;
int nonstatic_byte_space_offset;
- bool compact_into_header = (UseCompressedOops &&
- allocation_style == 1 && compact_fields &&
- !super_has_nonstatic_fields);
-
- if( compact_into_header || nonstatic_double_count > 0 ) {
- int offset;
- // Pack something in with the header if no super klass has done so.
- if (compact_into_header) {
- offset = oopDesc::klass_gap_offset_in_bytes();
- } else {
- offset = next_nonstatic_double_offset;
- }
+ if( nonstatic_double_count > 0 ) {
+ int offset = next_nonstatic_double_offset;
next_nonstatic_double_offset = align_size_up(offset, BytesPerLong);
if( compact_fields && offset != next_nonstatic_double_offset ) {
// Allocate available fields into the gap before double field.
@@ -2830,8 +2820,7 @@
}
// Allocate oop field in the gap if there are no other fields for that.
nonstatic_oop_space_offset = offset;
- if(!compact_into_header && length >= heapOopSize &&
- nonstatic_oop_count > 0 &&
+ if( length >= heapOopSize && nonstatic_oop_count > 0 &&
allocation_style != 0 ) { // when oop fields not first
nonstatic_oop_count -= 1;
nonstatic_oop_space_count = 1; // Only one will fit
@@ -2854,14 +2843,13 @@
} else { // allocation_style == 1
next_nonstatic_oop_offset = next_nonstatic_byte_offset + nonstatic_byte_count;
if( nonstatic_oop_count > 0 ) {
- notaligned_offset = next_nonstatic_oop_offset;
next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize);
}
notaligned_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize);
}
- next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize );
+ next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize );
nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset
- - first_nonstatic_field_offset)/wordSize);
+ - first_nonstatic_field_offset)/heapOopSize);
// Iterate over fields again and compute correct offsets.
// The field allocation type was temporarily stored in the offset slot.
@@ -2962,9 +2950,10 @@
// Size of instances
int instance_size;
+ next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize );
instance_size = align_object_size(next_nonstatic_type_offset / wordSize);
- assert(instance_size == align_object_size(instanceOopDesc::header_size() + nonstatic_field_size), "consistent layout helper value");
+ assert(instance_size == align_object_size(align_size_up((instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize), wordSize) / wordSize), "consistent layout helper value");
// Size of non-static oop map blocks (in words) allocated at end of klass
int nonstatic_oop_map_size = compute_oop_map_size(super_klass, nonstatic_oop_map_count, first_nonstatic_oop_offset);
@@ -3122,13 +3111,15 @@
#ifndef PRODUCT
if( PrintCompactFieldsSavings ) {
if( nonstatic_field_size < orig_nonstatic_field_size ) {
- tty->print("[Saved %d of %3d words in %s]\n",
- orig_nonstatic_field_size - nonstatic_field_size,
- orig_nonstatic_field_size, this_klass->external_name());
+ tty->print("[Saved %d of %d bytes in %s]\n",
+ (orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize,
+ orig_nonstatic_field_size*heapOopSize,
+ this_klass->external_name());
} else if( nonstatic_field_size > orig_nonstatic_field_size ) {
- tty->print("[Wasted %d over %3d words in %s]\n",
- nonstatic_field_size - orig_nonstatic_field_size,
- orig_nonstatic_field_size, this_klass->external_name());
+ tty->print("[Wasted %d over %d bytes in %s]\n",
+ (nonstatic_field_size - orig_nonstatic_field_size)*heapOopSize,
+ orig_nonstatic_field_size*heapOopSize,
+ this_klass->external_name());
}
}
#endif
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Fri May 30 07:22:22 2008 -0700
@@ -1872,7 +1872,7 @@
box->float_field_put(value_offset, value->f);
break;
case T_DOUBLE:
- box->double_field_put(value_offset, value->d);
+ box->double_field_put(long_value_offset, value->d);
break;
case T_BYTE:
box->byte_field_put(value_offset, value->b);
@@ -1884,7 +1884,7 @@
box->int_field_put(value_offset, value->i);
break;
case T_LONG:
- box->long_field_put(value_offset, value->j);
+ box->long_field_put(long_value_offset, value->j);
break;
default:
return NULL;
@@ -1915,7 +1915,7 @@
value->f = box->float_field(value_offset);
break;
case T_DOUBLE:
- value->d = box->double_field(value_offset);
+ value->d = box->double_field(long_value_offset);
break;
case T_BYTE:
value->b = box->byte_field(value_offset);
@@ -1927,7 +1927,7 @@
value->i = box->int_field(value_offset);
break;
case T_LONG:
- value->j = box->long_field(value_offset);
+ value->j = box->long_field(long_value_offset);
break;
default:
return T_ILLEGAL;
@@ -1949,7 +1949,7 @@
box->float_field_put(value_offset, value->f);
break;
case T_DOUBLE:
- box->double_field_put(value_offset, value->d);
+ box->double_field_put(long_value_offset, value->d);
break;
case T_BYTE:
box->byte_field_put(value_offset, value->b);
@@ -1961,7 +1961,7 @@
box->int_field_put(value_offset, value->i);
break;
case T_LONG:
- box->long_field_put(value_offset, value->j);
+ box->long_field_put(long_value_offset, value->j);
break;
default:
return T_ILLEGAL;
@@ -2163,6 +2163,7 @@
int java_lang_reflect_Field::signature_offset;
int java_lang_reflect_Field::annotations_offset;
int java_lang_boxing_object::value_offset;
+int java_lang_boxing_object::long_value_offset;
int java_lang_ref_Reference::referent_offset;
int java_lang_ref_Reference::queue_offset;
int java_lang_ref_Reference::next_offset;
@@ -2282,10 +2283,7 @@
// are not available to determine the offset_of_static_fields.
void JavaClasses::compute_hard_coded_offsets() {
const int x = heapOopSize;
- // Objects don't get allocated in the gap in the header with compressed oops
- // for these special classes because hard coded offsets can't be conditional
- // so base_offset_in_bytes() is wrong here, allocate after the header.
- const int header = sizeof(instanceOopDesc);
+ const int header = instanceOopDesc::base_offset_in_bytes();
// Do the String Class
java_lang_String::value_offset = java_lang_String::hc_value_offset * x + header;
@@ -2308,7 +2306,8 @@
java_lang_Throwable::stackTrace_offset = java_lang_Throwable::hc_stackTrace_offset * x + header;
// java_lang_boxing_object
- java_lang_boxing_object::value_offset = java_lang_boxing_object::hc_value_offset * x + header;
+ java_lang_boxing_object::value_offset = java_lang_boxing_object::hc_value_offset + header;
+ java_lang_boxing_object::long_value_offset = align_size_up((java_lang_boxing_object::hc_value_offset + header), BytesPerLong);
// java_lang_ref_Reference:
java_lang_ref_Reference::referent_offset = java_lang_ref_Reference::hc_referent_offset * x + header;
@@ -2322,7 +2321,7 @@
java_lang_ref_Reference::number_of_fake_oop_fields = 1;
// java_lang_ref_SoftReference Class
- java_lang_ref_SoftReference::timestamp_offset = java_lang_ref_SoftReference::hc_timestamp_offset * x + header;
+ java_lang_ref_SoftReference::timestamp_offset = align_size_up((java_lang_ref_SoftReference::hc_timestamp_offset * x + header), BytesPerLong);
// Don't multiply static fields because they are always in wordSize units
java_lang_ref_SoftReference::static_clock_offset = java_lang_ref_SoftReference::hc_static_clock_offset * x;
@@ -2469,6 +2468,9 @@
#define CHECK_OFFSET(klass_name, cpp_klass_name, field_name, field_sig) \
valid &= check_offset(klass_name, cpp_klass_name :: field_name ## _offset, #field_name, field_sig)
+#define CHECK_LONG_OFFSET(klass_name, cpp_klass_name, field_name, field_sig) \
+ valid &= check_offset(klass_name, cpp_klass_name :: long_ ## field_name ## _offset, #field_name, field_sig)
+
#define CHECK_STATIC_OFFSET(klass_name, cpp_klass_name, field_name, field_sig) \
valid &= check_static_offset(klass_name, cpp_klass_name :: static_ ## field_name ## _offset, #field_name, field_sig)
@@ -2501,11 +2503,11 @@
CHECK_OFFSET("java/lang/Boolean", java_lang_boxing_object, value, "Z");
CHECK_OFFSET("java/lang/Character", java_lang_boxing_object, value, "C");
CHECK_OFFSET("java/lang/Float", java_lang_boxing_object, value, "F");
- CHECK_OFFSET("java/lang/Double", java_lang_boxing_object, value, "D");
+ CHECK_LONG_OFFSET("java/lang/Double", java_lang_boxing_object, value, "D");
CHECK_OFFSET("java/lang/Byte", java_lang_boxing_object, value, "B");
CHECK_OFFSET("java/lang/Short", java_lang_boxing_object, value, "S");
CHECK_OFFSET("java/lang/Integer", java_lang_boxing_object, value, "I");
- CHECK_OFFSET("java/lang/Long", java_lang_boxing_object, value, "J");
+ CHECK_LONG_OFFSET("java/lang/Long", java_lang_boxing_object, value, "J");
// java.lang.ClassLoader
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Fri May 30 07:22:22 2008 -0700
@@ -653,6 +653,7 @@
hc_value_offset = 0
};
static int value_offset;
+ static int long_value_offset;
static oop initialize_and_allocate(BasicType type, TRAPS);
public:
@@ -665,7 +666,10 @@
static bool is_instance(oop box) { return basic_type(box) != T_ILLEGAL; }
static bool is_instance(oop box, BasicType type) { return basic_type(box) == type; }
- static int value_offset_in_bytes() { return value_offset; }
+ static int value_offset_in_bytes(BasicType type) {
+ return ( type == T_LONG || type == T_DOUBLE ) ? long_value_offset :
+ value_offset;
+ }
// Debugging
friend class JavaClasses;
@@ -747,7 +751,7 @@
public:
enum {
// The timestamp is a long field and may need to be adjusted for alignment.
- hc_timestamp_offset = align_object_offset_(hc_discovered_offset + 1)
+ hc_timestamp_offset = hc_discovered_offset + 1
};
enum {
hc_static_clock_offset = 0
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Fri May 30 07:22:22 2008 -0700
@@ -564,6 +564,10 @@
do_name( copyOfRange_name, "copyOfRange") \
do_signature(copyOfRange_signature, "([Ljava/lang/Object;IILjava/lang/Class;)[Ljava/lang/Object;") \
\
+ do_intrinsic(_equalsC, java_util_Arrays, equals_name, equalsC_signature, F_S) \
+ do_name( equals_name, "equals") \
+ do_signature(equalsC_signature, "([C[C)Z") \
+ \
do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_array_object_object_signature, F_R) \
/* (symbols invoke_name and invoke_signature defined above) */ \
\
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared Fri May 30 07:22:22 2008 -0700
@@ -54,6 +54,7 @@
markSweep.inline.hpp psParallelCompact.hpp
mutableNUMASpace.cpp mutableNUMASpace.hpp
+mutableNUMASpace.cpp oop.inline.hpp
mutableNUMASpace.cpp sharedHeap.hpp
mutableNUMASpace.cpp thread_<os_family>.inline.hpp
--- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Fri May 30 07:22:22 2008 -0700
@@ -1169,18 +1169,18 @@
// Trim off a prefix of at most objsFromOverflow items
int i = 1;
oop cur = prefix;
- while (i < objsFromOverflow && cur->klass() != NULL) {
+ while (i < objsFromOverflow && cur->klass_or_null() != NULL) {
i++; cur = oop(cur->klass());
}
// Reattach remaining (suffix) to overflow list
- if (cur->klass() != NULL) {
+ if (cur->klass_or_null() != NULL) {
oop suffix = oop(cur->klass());
cur->set_klass_to_list_ptr(NULL);
// Find last item of suffix list
oop last = suffix;
- while (last->klass() != NULL) {
+ while (last->klass_or_null() != NULL) {
last = oop(last->klass());
}
// Atomically prepend suffix to current overflow list
--- a/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp Fri May 30 07:22:22 2008 -0700
@@ -90,11 +90,12 @@
HeapWord* obj,
size_t size,
int length) {
+ // Set array length before setting the _klass field
+ // in post_allocation_setup_common() because the klass field
+ // indicates that the object is parsable by concurrent GC.
assert(length >= 0, "length should be non-negative");
+ ((arrayOop)obj)->set_length(length);
post_allocation_setup_common(klass, obj, size);
- // Must set length after installing klass as set_klass zeros the length
- // field in UseCompressedOops
- ((arrayOop)obj)->set_length(length);
assert(((oop)obj)->blueprint()->oop_is_array(), "must be an array");
// notify jvmti and dtrace (must be after length is set for dtrace)
post_allocation_notify(klass, (oop)obj);
@@ -224,6 +225,7 @@
assert(obj != NULL, "cannot initialize NULL object");
const size_t hs = oopDesc::header_size();
assert(size >= hs, "unexpected object size");
+ ((oop)obj)->set_klass_gap(0);
Copy::fill_to_aligned_words(obj + hs, size - hs);
}
--- a/hotspot/src/share/vm/includeDB_core Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/includeDB_core Fri May 30 07:22:22 2008 -0700
@@ -3492,6 +3492,7 @@
relocInfo_<arch>.cpp assembler.inline.hpp
relocInfo_<arch>.cpp assembler_<arch_model>.inline.hpp
relocInfo_<arch>.cpp nativeInst_<arch>.hpp
+relocInfo_<arch>.cpp oop.inline.hpp
relocInfo_<arch>.cpp relocInfo.hpp
relocInfo_<arch>.cpp safepoint.hpp
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Fri May 30 07:22:22 2008 -0700
@@ -1931,6 +1931,7 @@
} else {
result->set_mark(markOopDesc::prototype());
}
+ result->set_klass_gap(0);
result->set_klass(k_entry);
SET_STACK_OBJECT(result, 0);
UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1);
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xml Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xml Fri May 30 07:22:22 2008 -0700
@@ -1,7 +1,25 @@
<?xml version="1.0"?>
<!--
- Copyright 2006 Sun Microsystems, Inc. All rights reserved.
- SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ 6opyright 2006-2008 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.
-->
<!DOCTYPE processcode [
<!ELEMENT processcode ANY>
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xsl Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreterWithChecks.xsl Fri May 30 07:22:22 2008 -0700
@@ -1,10 +1,29 @@
<?xml version="1.0"?>
<!--
- Copyright 2006 Sun Microsystems, Inc. All rights reserved.
- SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ Copyright 2006-2008 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.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="text" indent="no" omit-xml-declaration="yes"/>
<xsl:template match="processcode">
<xsl:text>
@@ -15,7 +34,6 @@
</xsl:text>
-<xsl:output method="text" indent="no" omit-xml-declaration="yes"/>
</xsl:template>
</xsl:stylesheet>
--- a/hotspot/src/share/vm/memory/space.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/memory/space.cpp Fri May 30 07:22:22 2008 -0700
@@ -815,6 +815,7 @@
"size for smallest fake object doesn't match");
instanceOop obj = (instanceOop) allocate(size);
obj->set_mark(markOopDesc::prototype());
+ obj->set_klass_gap(0);
obj->set_klass(SystemDictionary::object_klass());
}
}
--- a/hotspot/src/share/vm/oops/arrayOop.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/oops/arrayOop.hpp Fri May 30 07:22:22 2008 -0700
@@ -41,11 +41,10 @@
// Header size computation.
// The header is considered the oop part of this type plus the length.
// Returns the aligned header_size_in_bytes. This is not equivalent to
- // sizeof(arrayOopDesc) which should not appear in the code, except here.
+ // sizeof(arrayOopDesc) which should not appear in the code.
static int header_size_in_bytes() {
- size_t hs = UseCompressedOops ?
- sizeof(arrayOopDesc) :
- align_size_up(sizeof(arrayOopDesc) + sizeof(int), HeapWordSize);
+ size_t hs = align_size_up(length_offset_in_bytes() + sizeof(int),
+ HeapWordSize);
#ifdef ASSERT
// make sure it isn't called before UseCompressedOops is initialized.
static size_t arrayoopdesc_hs = 0;
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Fri May 30 07:22:22 2008 -0700
@@ -180,9 +180,8 @@
// End of the oop block.
//
- // number of words used by non-static fields in this klass (including
- // inherited fields but after header_size()). If fields are compressed into
- // header, this can be zero so it's not the same as number of static fields.
+ // Number of heapOopSize words used by non-static fields in this klass
+ // (including inherited fields but after header_size()).
int _nonstatic_field_size;
int _static_field_size; // number words used by static fields (oop and non-oop) in this klass
int _static_oop_field_size;// number of static oop fields in this klass
--- a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp Fri May 30 07:22:22 2008 -0700
@@ -581,7 +581,7 @@
OopMapBlock* map = ik->start_of_nonstatic_oop_maps();
OopMapBlock* end_map = map + ik->nonstatic_oop_map_size();
while (map < end_map) {
- st->print("%d-%d ", map->offset(), map->offset() + oopSize*(map->length() - 1));
+ st->print("%d-%d ", map->offset(), map->offset() + heapOopSize*(map->length() - 1));
map++;
}
st->cr();
--- a/hotspot/src/share/vm/oops/instanceOop.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/oops/instanceOop.hpp Fri May 30 07:22:22 2008 -0700
@@ -39,14 +39,7 @@
static bool contains_field_offset(int offset, int nonstatic_field_size) {
int base_in_bytes = base_offset_in_bytes();
- if (UseCompressedOops) {
- return (offset >= base_in_bytes &&
- // field can be embedded in header, or is after header.
- (offset < (int)sizeof(instanceOopDesc) ||
- (offset-(int)sizeof(instanceOopDesc))/wordSize < nonstatic_field_size));
- } else {
- return (offset >= base_in_bytes &&
- (offset-base_in_bytes)/wordSize < nonstatic_field_size);
- }
+ return (offset >= base_in_bytes &&
+ (offset-base_in_bytes) < nonstatic_field_size * heapOopSize);
}
};
--- a/hotspot/src/share/vm/oops/oop.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/oops/oop.hpp Fri May 30 07:22:22 2008 -0700
@@ -77,10 +77,15 @@
void init_mark();
klassOop klass() const;
+ klassOop klass_or_null() const volatile;
oop* klass_addr();
narrowOop* compressed_klass_addr();
void set_klass(klassOop k);
+
+ // For klass field compression
+ int klass_gap() const;
+ void set_klass_gap(int z);
// For when the klass pointer is being used as a linked list "next" field.
void set_klass_to_list_ptr(oop k);
--- a/hotspot/src/share/vm/oops/oop.inline.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp Fri May 30 07:22:22 2008 -0700
@@ -36,7 +36,15 @@
inline klassOop oopDesc::klass() const {
if (UseCompressedOops) {
return (klassOop)decode_heap_oop_not_null(_metadata._compressed_klass);
- // can be NULL in CMS, but isn't supported on CMS yet.
+ } else {
+ return _metadata._klass;
+ }
+}
+
+inline klassOop oopDesc::klass_or_null() const volatile {
+ // can be NULL in CMS
+ if (UseCompressedOops) {
+ return (klassOop)decode_heap_oop(_metadata._compressed_klass);
} else {
return _metadata._klass;
}
@@ -64,15 +72,22 @@
assert(Universe::is_bootstrapping() || k != NULL, "must be a real klassOop");
assert(Universe::is_bootstrapping() || k->is_klass(), "not a klassOop");
if (UseCompressedOops) {
- // zero the gap when the klass is set, by zeroing the pointer sized
- // part of the union.
- _metadata._klass = NULL;
oop_store_without_check(compressed_klass_addr(), (oop)k);
} else {
oop_store_without_check(klass_addr(), (oop) k);
}
}
+inline int oopDesc::klass_gap() const {
+ return *(int*)(((intptr_t)this) + klass_gap_offset_in_bytes());
+}
+
+inline void oopDesc::set_klass_gap(int v) {
+ if (UseCompressedOops) {
+ *(int*)(((intptr_t)this) + klass_gap_offset_in_bytes()) = v;
+ }
+}
+
inline void oopDesc::set_klass_to_list_ptr(oop k) {
// This is only to be used during GC, for from-space objects, so no
// barrier is needed.
@@ -505,7 +520,7 @@
// try to find metaclass cycle safely without seg faulting on bad input
// we should reach klassKlassObj by following klass link at most 3 times
for (int i = 0; i < 3; i++) {
- obj = obj->klass();
+ obj = obj->klass_or_null();
// klass should be aligned and in permspace
if (!check_obj_alignment(obj)) return false;
if (!Universe::heap()->is_in_permanent(obj)) return false;
--- a/hotspot/src/share/vm/opto/callnode.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/callnode.cpp Fri May 30 07:22:22 2008 -0700
@@ -637,7 +637,7 @@
}
Compile *C = phase->C;
int offset = adrInst_t->offset();
- assert(offset >= 0, "should be valid offset");
+ assert(adrInst_t->klass_is_exact() && offset >= 0, "should be valid offset");
ciKlass* adr_k = adrInst_t->klass();
assert(adr_k->is_loaded() &&
adr_k->is_java_klass() &&
@@ -674,12 +674,11 @@
ciKlass* at_k = at_ptr->klass();
if ((adrInst_t->base() == at_ptr->base()) &&
at_k->is_loaded() &&
- at_k->is_java_klass() &&
- !at_k->is_interface()) {
+ at_k->is_java_klass()) {
// If we have found an argument matching addr_t, check if the field
// at the specified offset is modified.
- int at_idx = C->get_alias_index(at_ptr->add_offset(offset)->isa_oopptr());
- if (base_idx == at_idx &&
+ if ((at_k->is_interface() || adr_k == at_k ||
+ adr_k->is_subclass_of(at_k) && !at_ptr->klass_is_exact()) &&
(bcea == NULL ||
bcea->is_arg_modified(i - TypeFunc::Parms, offset, size))) {
return true;
--- a/hotspot/src/share/vm/opto/callnode.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/callnode.hpp Fri May 30 07:22:22 2008 -0700
@@ -388,9 +388,6 @@
void set_next_exception(SafePointNode* n);
bool has_exceptions() const { return next_exception() != NULL; }
- // Does this node have a use of n other than in debug information?
- virtual bool has_non_debug_use(Node *n) {return false; }
-
// Standard Node stuff
virtual int Opcode() const;
virtual bool pinned() const { return true; }
@@ -497,7 +494,7 @@
// Returns true if the call may modify n
virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase);
// Does this node have a use of n other than in debug information?
- virtual bool has_non_debug_use(Node *n);
+ bool has_non_debug_use(Node *n);
// Returns the unique CheckCastPP of a call
// or result projection is there are several CheckCastPP
// or returns NULL if there is no one.
--- a/hotspot/src/share/vm/opto/cfgnode.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/cfgnode.cpp Fri May 30 07:22:22 2008 -0700
@@ -707,8 +707,14 @@
//------------------------split_out_instance-----------------------------------
// Split out an instance type from a bottom phi.
PhiNode* PhiNode::split_out_instance(const TypePtr* at, PhaseIterGVN *igvn) const {
- assert(type() == Type::MEMORY && (adr_type() == TypePtr::BOTTOM ||
- adr_type() == TypeRawPtr::BOTTOM) , "bottom or raw memory required");
+ const TypeOopPtr *t_oop = at->isa_oopptr();
+ assert(t_oop != NULL && t_oop->is_instance(), "expecting instance oopptr");
+ const TypePtr *t = adr_type();
+ assert(type() == Type::MEMORY &&
+ (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM ||
+ t->isa_oopptr() && !t->is_oopptr()->is_instance() &&
+ t->is_oopptr()->cast_to_instance(t_oop->instance_id()) == t_oop),
+ "bottom or raw memory required");
// Check if an appropriate node already exists.
Node *region = in(0);
@@ -1342,7 +1348,7 @@
Node *n = phi->in(i);
if( !n ) return NULL;
if( phase->type(n) == Type::TOP ) return NULL;
- if( n->Opcode() == Op_ConP )
+ if( n->Opcode() == Op_ConP || n->Opcode() == Op_ConN )
break;
}
if( i >= phi->req() ) // Only split for constants
--- a/hotspot/src/share/vm/opto/chaitin.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/chaitin.cpp Fri May 30 07:22:22 2008 -0700
@@ -1385,7 +1385,7 @@
cisc->ins_req(1,src); // Requires a memory edge
}
b->_nodes.map(j,cisc); // Insert into basic block
- n->replace_by(cisc); // Correct graph
+ n->subsume_by(cisc); // Correct graph
//
++_used_cisc_instructions;
#ifndef PRODUCT
--- a/hotspot/src/share/vm/opto/classes.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/classes.hpp Fri May 30 07:22:22 2008 -0700
@@ -37,6 +37,7 @@
macro(AllocateArray)
macro(AndI)
macro(AndL)
+macro(AryEq)
macro(AtanD)
macro(Binary)
macro(Bool)
@@ -64,6 +65,7 @@
macro(CMoveI)
macro(CMoveL)
macro(CMoveP)
+macro(CMoveN)
macro(CmpN)
macro(CmpD)
macro(CmpD3)
@@ -133,6 +135,7 @@
macro(LoadF)
macro(LoadI)
macro(LoadKlass)
+macro(LoadNKlass)
macro(LoadL)
macro(LoadL_unaligned)
macro(LoadPLocked)
--- a/hotspot/src/share/vm/opto/compile.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/compile.cpp Fri May 30 07:22:22 2008 -0700
@@ -368,7 +368,12 @@
BufferBlob* blob = BufferBlob::create("Compile::scratch_buffer", size);
// Record the buffer blob for next time.
set_scratch_buffer_blob(blob);
- guarantee(scratch_buffer_blob() != NULL, "Need BufferBlob for code generation");
+ // Have we run out of code space?
+ if (scratch_buffer_blob() == NULL) {
+ // Let CompilerBroker disable further compilations.
+ record_failure("Not enough space for scratch buffer in CodeCache");
+ return;
+ }
// Initialize the relocation buffers
relocInfo* locs_buf = (relocInfo*) blob->instructions_end() - MAX_locs_size;
@@ -1065,6 +1070,8 @@
// No constant oop pointers (such as Strings); they alias with
// unknown strings.
tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
+ } else if( to->is_instance_field() ) {
+ tj = to; // Keep NotNull and klass_is_exact for instance type
} else if( ptr == TypePtr::NotNull || to->klass_is_exact() ) {
// During the 2nd round of IterGVN, NotNull castings are removed.
// Make sure the Bottom and NotNull variants alias the same.
@@ -1084,7 +1091,7 @@
} else {
ciInstanceKlass *canonical_holder = k->get_canonical_holder(offset);
if (!k->equals(canonical_holder) || tj->offset() != offset) {
- tj = to = TypeInstPtr::make(TypePtr::BotPTR, canonical_holder, false, NULL, offset, to->instance_id());
+ tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, NULL, offset, to->instance_id());
}
}
}
@@ -1835,6 +1842,7 @@
// Implement items 1-5 from final_graph_reshaping below.
static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) {
+ if ( n->outcnt() == 0 ) return; // dead node
uint nop = n->Opcode();
// Check for 2-input instruction with "last use" on right input.
@@ -1901,7 +1909,7 @@
break;
case Op_Opaque1: // Remove Opaque Nodes before matching
case Op_Opaque2: // Remove Opaque Nodes before matching
- n->replace_by(n->in(1));
+ n->subsume_by(n->in(1));
break;
case Op_CallStaticJava:
case Op_CallJava:
@@ -1961,6 +1969,7 @@
case Op_LoadC:
case Op_LoadI:
case Op_LoadKlass:
+ case Op_LoadNKlass:
case Op_LoadL:
case Op_LoadL_unaligned:
case Op_LoadPLocked:
@@ -1991,6 +2000,48 @@
break;
}
+#ifdef _LP64
+ case Op_CmpP:
+ // Do this transformation here to preserve CmpPNode::sub() and
+ // other TypePtr related Ideal optimizations (for example, ptr nullness).
+ if( n->in(1)->is_DecodeN() ) {
+ Compile* C = Compile::current();
+ Node* in2 = NULL;
+ if( n->in(2)->is_DecodeN() ) {
+ in2 = n->in(2)->in(1);
+ } else if ( n->in(2)->Opcode() == Op_ConP ) {
+ const Type* t = n->in(2)->bottom_type();
+ if (t == TypePtr::NULL_PTR) {
+ Node *in1 = n->in(1);
+ if (Matcher::clone_shift_expressions) {
+ // x86, ARM and friends can handle 2 adds in addressing mode.
+ // Decode a narrow oop and do implicit NULL check in address
+ // [R12 + narrow_oop_reg<<3 + offset]
+ in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR);
+ } else {
+ // Don't replace CmpP(o ,null) if 'o' is used in AddP
+ // to generate implicit NULL check on Sparc where
+ // narrow oops can't be used in address.
+ uint i = 0;
+ for (; i < in1->outcnt(); i++) {
+ if (in1->raw_out(i)->is_AddP())
+ break;
+ }
+ if (i >= in1->outcnt()) {
+ in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR);
+ }
+ }
+ } else if (t->isa_oopptr()) {
+ in2 = ConNode::make(C, t->is_oopptr()->make_narrowoop());
+ }
+ }
+ if( in2 != NULL ) {
+ Node* cmpN = new (C, 3) CmpNNode(n->in(1)->in(1), in2);
+ n->subsume_by( cmpN );
+ }
+ }
+#endif
+
case Op_ModI:
if (UseDivMod) {
// Check if a%b and a/b both exist
@@ -2000,13 +2051,13 @@
Compile* C = Compile::current();
if (Matcher::has_match_rule(Op_DivModI)) {
DivModINode* divmod = DivModINode::make(C, n);
- d->replace_by(divmod->div_proj());
- n->replace_by(divmod->mod_proj());
+ d->subsume_by(divmod->div_proj());
+ n->subsume_by(divmod->mod_proj());
} else {
// replace a%b with a-((a/b)*b)
Node* mult = new (C, 3) MulINode(d, d->in(2));
Node* sub = new (C, 3) SubINode(d->in(1), mult);
- n->replace_by( sub );
+ n->subsume_by( sub );
}
}
}
@@ -2021,13 +2072,13 @@
Compile* C = Compile::current();
if (Matcher::has_match_rule(Op_DivModL)) {
DivModLNode* divmod = DivModLNode::make(C, n);
- d->replace_by(divmod->div_proj());
- n->replace_by(divmod->mod_proj());
+ d->subsume_by(divmod->div_proj());
+ n->subsume_by(divmod->mod_proj());
} else {
// replace a%b with a-((a/b)*b)
Node* mult = new (C, 3) MulLNode(d, d->in(2));
Node* sub = new (C, 3) SubLNode(d->in(1), mult);
- n->replace_by( sub );
+ n->subsume_by( sub );
}
}
}
@@ -2073,7 +2124,7 @@
// Replace many operand PackNodes with a binary tree for matching
PackNode* p = (PackNode*) n;
Node* btp = p->binaryTreePack(Compile::current(), 1, n->req());
- n->replace_by(btp);
+ n->subsume_by(btp);
}
break;
default:
--- a/hotspot/src/share/vm/opto/connode.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/connode.cpp Fri May 30 07:22:22 2008 -0700
@@ -35,16 +35,16 @@
//------------------------------make-------------------------------------------
ConNode *ConNode::make( Compile* C, const Type *t ) {
- if (t->isa_narrowoop()) return new (C, 1) ConNNode( t->is_narrowoop() );
switch( t->basic_type() ) {
case T_INT: return new (C, 1) ConINode( t->is_int() );
- case T_ARRAY: return new (C, 1) ConPNode( t->is_aryptr() );
case T_LONG: return new (C, 1) ConLNode( t->is_long() );
case T_FLOAT: return new (C, 1) ConFNode( t->is_float_constant() );
case T_DOUBLE: return new (C, 1) ConDNode( t->is_double_constant() );
case T_VOID: return new (C, 1) ConNode ( Type::TOP );
case T_OBJECT: return new (C, 1) ConPNode( t->is_oopptr() );
+ case T_ARRAY: return new (C, 1) ConPNode( t->is_aryptr() );
case T_ADDRESS: return new (C, 1) ConPNode( t->is_ptr() );
+ case T_NARROWOOP: return new (C, 1) ConNNode( t->is_narrowoop() );
// Expected cases: TypePtr::NULL_PTR, any is_rawptr()
// Also seen: AnyPtr(TopPTR *+top); from command line:
// r -XX:+PrintOpto -XX:CIStart=285 -XX:+CompileTheWorld -XX:CompileTheWorldStartAt=660
@@ -185,6 +185,7 @@
case T_LONG: return new (C, 4) CMoveLNode( bol, left, right, t->is_long() );
case T_OBJECT: return new (C, 4) CMovePNode( c, bol, left, right, t->is_oopptr() );
case T_ADDRESS: return new (C, 4) CMovePNode( c, bol, left, right, t->is_ptr() );
+ case T_NARROWOOP: return new (C, 4) CMoveNNode( c, bol, left, right, t );
default:
ShouldNotReachHere();
return NULL;
@@ -556,7 +557,7 @@
const Type *t = phase->type( in(1) );
if( t == Type::TOP ) return in(1);
- if (in(1)->Opcode() == Op_EncodeP) {
+ if (in(1)->is_EncodeP()) {
// (DecodeN (EncodeP p)) -> p
return in(1)->in(1);
}
@@ -570,16 +571,19 @@
return bottom_type();
}
-Node* DecodeNNode::decode(PhaseGVN* phase, Node* value) {
- if (value->Opcode() == Op_EncodeP) {
+Node* DecodeNNode::decode(PhaseTransform* phase, Node* value) {
+ if (value->is_EncodeP()) {
// (DecodeN (EncodeP p)) -> p
return value->in(1);
}
const Type* newtype = value->bottom_type();
if (newtype == TypeNarrowOop::NULL_PTR) {
return phase->transform(new (phase->C, 1) ConPNode(TypePtr::NULL_PTR));
+ } else if (newtype->isa_narrowoop()) {
+ return phase->transform(new (phase->C, 2) DecodeNNode(value, newtype->is_narrowoop()->make_oopptr()));
} else {
- return phase->transform(new (phase->C, 2) DecodeNNode(value, newtype->is_narrowoop()->make_oopptr()));
+ ShouldNotReachHere();
+ return NULL; // to make C++ compiler happy.
}
}
@@ -587,7 +591,7 @@
const Type *t = phase->type( in(1) );
if( t == Type::TOP ) return in(1);
- if (in(1)->Opcode() == Op_DecodeN) {
+ if (in(1)->is_DecodeN()) {
// (EncodeP (DecodeN p)) -> p
return in(1)->in(1);
}
@@ -601,8 +605,8 @@
return bottom_type();
}
-Node* EncodePNode::encode(PhaseGVN* phase, Node* value) {
- if (value->Opcode() == Op_DecodeN) {
+Node* EncodePNode::encode(PhaseTransform* phase, Node* value) {
+ if (value->is_DecodeN()) {
// (EncodeP (DecodeN p)) -> p
return value->in(1);
}
@@ -617,6 +621,9 @@
}
}
+Node *EncodePNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
+ return MemNode::Ideal_common_DU_postCCP(ccp, this, in(1));
+}
//=============================================================================
//------------------------------Identity---------------------------------------
--- a/hotspot/src/share/vm/opto/connode.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/connode.hpp Fri May 30 07:22:22 2008 -0700
@@ -70,11 +70,6 @@
else
return new (C, 1) ConPNode( TypeRawPtr::make(con) );
}
-
- static ConPNode* make( Compile *C, ciObject* con ) {
- return new (C, 1) ConPNode( TypeOopPtr::make_from_constant(con) );
- }
-
};
@@ -84,11 +79,6 @@
public:
ConNNode( const TypeNarrowOop *t ) : ConNode(t) {}
virtual int Opcode() const;
-
- static ConNNode* make( Compile *C, ciObject* con ) {
- return new (C, 1) ConNNode( TypeNarrowOop::make_from_constant(con) );
- }
-
};
@@ -210,7 +200,14 @@
virtual int Opcode() const;
};
-//------------------------------ConstraintCastNode-------------------------------------
+//------------------------------CMoveNNode-------------------------------------
+class CMoveNNode : public CMoveNode {
+public:
+ CMoveNNode( Node *c, Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); }
+ virtual int Opcode() const;
+};
+
+//------------------------------ConstraintCastNode-----------------------------
// cast to a different range
class ConstraintCastNode: public TypeNode {
public:
@@ -274,6 +271,7 @@
public:
EncodePNode(Node* value, const Type* type):
TypeNode(type, 2) {
+ init_class_id(Class_EncodeP);
init_req(0, NULL);
init_req(1, value);
}
@@ -282,7 +280,8 @@
virtual const Type *Value( PhaseTransform *phase ) const;
virtual uint ideal_reg() const { return Op_RegN; }
- static Node* encode(PhaseGVN* phase, Node* value);
+ static Node* encode(PhaseTransform* phase, Node* value);
+ virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp );
};
//------------------------------DecodeN--------------------------------
@@ -293,6 +292,7 @@
public:
DecodeNNode(Node* value, const Type* type):
TypeNode(type, 2) {
+ init_class_id(Class_DecodeN);
init_req(0, NULL);
init_req(1, value);
}
@@ -301,7 +301,7 @@
virtual const Type *Value( PhaseTransform *phase ) const;
virtual uint ideal_reg() const { return Op_RegP; }
- static Node* decode(PhaseGVN* phase, Node* value);
+ static Node* decode(PhaseTransform* phase, Node* value);
};
//------------------------------Conv2BNode-------------------------------------
--- a/hotspot/src/share/vm/opto/doCall.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/doCall.cpp Fri May 30 07:22:22 2008 -0700
@@ -580,7 +580,7 @@
Node* ex_klass_node = NULL;
if (has_ex_handler() && !ex_type->klass_is_exact()) {
Node* p = basic_plus_adr( ex_node, ex_node, oopDesc::klass_offset_in_bytes());
- ex_klass_node = _gvn.transform(new (C, 3) LoadKlassNode(NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
+ ex_klass_node = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) );
// Compute the exception klass a little more cleverly.
// Obvious solution is to simple do a LoadKlass from the 'ex_node'.
@@ -592,7 +592,7 @@
ex_klass_node = new (C, ex_node->req()) PhiNode( ex_node->in(0), TypeKlassPtr::OBJECT );
for( uint i = 1; i < ex_node->req(); i++ ) {
Node* p = basic_plus_adr( ex_node->in(i), ex_node->in(i), oopDesc::klass_offset_in_bytes() );
- Node* k = _gvn.transform(new (C, 3) LoadKlassNode(0, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
+ Node* k = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) );
ex_klass_node->init_req( i, k );
}
_gvn.set_type(ex_klass_node, TypeKlassPtr::OBJECT);
--- a/hotspot/src/share/vm/opto/escape.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/escape.cpp Fri May 30 07:22:22 2008 -0700
@@ -417,11 +417,18 @@
// | |
// AddP ( base == address )
//
+ // case #8. narrow Klass's field reference.
+ // LoadNKlass
+ // |
+ // DecodeN
+ // | |
+ // AddP ( base == address )
+ //
Node *base = addp->in(AddPNode::Base)->uncast();
if (base->is_top()) { // The AddP case #3 and #6.
base = addp->in(AddPNode::Address)->uncast();
assert(base->Opcode() == Op_ConP || base->Opcode() == Op_ThreadLocal ||
- base->Opcode() == Op_CastX2P ||
+ base->Opcode() == Op_CastX2P || base->is_DecodeN() ||
(base->is_Mem() && base->bottom_type() == TypeRawPtr::NOTNULL) ||
(base->is_Proj() && base->in(0)->is_Allocate()), "sanity");
}
@@ -888,6 +895,23 @@
record_for_optimizer(n);
if (alloc->is_Allocate() && ptn->_scalar_replaceable &&
(t->isa_instptr() || t->isa_aryptr())) {
+
+ // First, put on the worklist all Field edges from Connection Graph
+ // which is more accurate then putting immediate users from Ideal Graph.
+ for (uint e = 0; e < ptn->edge_count(); e++) {
+ Node *use = _nodes->adr_at(ptn->edge_target(e))->_node;
+ assert(ptn->edge_type(e) == PointsToNode::FieldEdge && use->is_AddP(),
+ "only AddP nodes are Field edges in CG");
+ if (use->outcnt() > 0) { // Don't process dead nodes
+ Node* addp2 = find_second_addp(use, use->in(AddPNode::Base));
+ if (addp2 != NULL) {
+ assert(alloc->is_AllocateArray(),"array allocation was expected");
+ alloc_worklist.append_if_missing(addp2);
+ }
+ alloc_worklist.append_if_missing(use);
+ }
+ }
+
// An allocation may have an Initialize which has raw stores. Scan
// the users of the raw allocation result and push AddP users
// on alloc_worklist.
@@ -919,6 +943,8 @@
tinst = igvn->type(base)->isa_oopptr();
} else if (n->is_Phi() ||
n->is_CheckCastPP() ||
+ n->is_EncodeP() ||
+ n->is_DecodeN() ||
(n->is_ConstraintCast() && n->Opcode() == Op_CastPP)) {
if (visited.test_set(n->_idx)) {
assert(n->is_Phi(), "loops only through Phi's");
@@ -935,13 +961,25 @@
tinst = igvn->type(val)->isa_oopptr();
assert(tinst != NULL && tinst->is_instance() &&
tinst->instance_id() == elem , "instance type expected.");
- const TypeOopPtr *tn_t = igvn->type(tn)->isa_oopptr();
+
+ const TypeOopPtr *tn_t = NULL;
+ const Type *tn_type = igvn->type(tn);
+ if (tn_type->isa_narrowoop()) {
+ tn_t = tn_type->is_narrowoop()->make_oopptr()->isa_oopptr();
+ } else {
+ tn_t = tn_type->isa_oopptr();
+ }
if (tn_t != NULL &&
tinst->cast_to_instance(TypeOopPtr::UNKNOWN_INSTANCE)->higher_equal(tn_t)) {
+ if (tn_type->isa_narrowoop()) {
+ tn_type = tinst->make_narrowoop();
+ } else {
+ tn_type = tinst;
+ }
igvn->hash_delete(tn);
- igvn->set_type(tn, tinst);
- tn->set_type(tinst);
+ igvn->set_type(tn, tn_type);
+ tn->set_type(tn_type);
igvn->hash_insert(tn);
record_for_optimizer(n);
}
@@ -978,6 +1016,8 @@
alloc_worklist.append_if_missing(use);
} else if (use->is_Phi() ||
use->is_CheckCastPP() ||
+ use->is_EncodeP() ||
+ use->is_DecodeN() ||
(use->is_ConstraintCast() && use->Opcode() == Op_CastPP)) {
alloc_worklist.append_if_missing(use);
}
@@ -1199,7 +1239,7 @@
void ConnectionGraph::compute_escape() {
- // 1. Populate Connection Graph with Ideal nodes.
+ // 1. Populate Connection Graph (CG) with Ideal nodes.
Unique_Node_List worklist_init;
worklist_init.map(_compile->unique(), NULL); // preallocate space
@@ -1281,11 +1321,13 @@
remove_deferred(ni, &deferred_edges, &visited);
if (n->is_AddP()) {
// If this AddP computes an address which may point to more that one
- // object, nothing the address points to can be scalar replaceable.
+ // object or more then one field (array's element), nothing the address
+ // points to can be scalar replaceable.
Node *base = get_addp_base(n);
ptset.Clear();
PointsTo(ptset, base, igvn);
- if (ptset.Size() > 1) {
+ if (ptset.Size() > 1 ||
+ (ptset.Size() != 0 && ptn->offset() == Type::OffsetBot)) {
for( VectorSetI j(&ptset); j.test(); ++j ) {
uint pt = j.elem;
ptnode_adr(pt)->_scalar_replaceable = false;
@@ -1538,6 +1580,7 @@
if (k->Opcode() == Op_LoadKlass) {
kt = k->as_Load()->type()->isa_klassptr();
} else {
+ // Also works for DecodeN(LoadNKlass).
kt = k->as_Type()->type()->isa_klassptr();
}
assert(kt != NULL, "TypeKlassPtr required.");
@@ -1776,6 +1819,7 @@
break;
}
case Op_LoadKlass:
+ case Op_LoadNKlass:
{
add_node(n, PointsToNode::JavaObject, PointsToNode::GlobalEscape, true);
break;
@@ -1979,12 +2023,18 @@
assert(false, "Op_ConP");
break;
}
+ case Op_ConN:
+ {
+ assert(false, "Op_ConN");
+ break;
+ }
case Op_CreateEx:
{
assert(false, "Op_CreateEx");
break;
}
case Op_LoadKlass:
+ case Op_LoadNKlass:
{
assert(false, "Op_LoadKlass");
break;
--- a/hotspot/src/share/vm/opto/graphKit.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/graphKit.cpp Fri May 30 07:22:22 2008 -0700
@@ -532,7 +532,7 @@
C->log()->elem("hot_throw preallocated='1' reason='%s'",
Deoptimization::trap_reason_name(reason));
const TypeInstPtr* ex_con = TypeInstPtr::make(ex_obj);
- Node* ex_node = _gvn.transform(new (C, 1) ConPNode(ex_con));
+ Node* ex_node = _gvn.transform( ConNode::make(C, ex_con) );
// Clear the detail message of the preallocated exception object.
// Weblogic sometimes mutates the detail message of exceptions
@@ -1043,7 +1043,7 @@
Node* akls = AllocateNode::Ideal_klass(obj, &_gvn);
if (akls != NULL) return akls;
Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
- return _gvn.transform( new (C, 3) LoadKlassNode(0, immutable_memory(), k_adr, TypeInstPtr::KLASS) );
+ return _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), k_adr, TypeInstPtr::KLASS) );
}
//-------------------------load_array_length-----------------------------------
@@ -2210,7 +2210,7 @@
// cache which is mutable so can't use immutable memory. Other
// types load from the super-class display table which is immutable.
Node *kmem = might_be_cache ? memory(p2) : immutable_memory();
- Node *nkls = _gvn.transform( new (C, 3) LoadKlassNode( NULL, kmem, p2, _gvn.type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL ) );
+ Node *nkls = _gvn.transform( LoadKlassNode::make( _gvn, kmem, p2, _gvn.type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL ) );
// Compile speed common case: ARE a subtype and we canNOT fail
if( superklass == nkls )
@@ -2801,7 +2801,6 @@
// initialization, and source them from the new InitializeNode.
// This will allow us to observe initializations when they occur,
// and link them properly (as a group) to the InitializeNode.
- Node* klass_node = alloc->in(AllocateNode::KlassNode);
assert(init->in(InitializeNode::Memory) == malloc, "");
MergeMemNode* minit_in = MergeMemNode::make(C, malloc);
init->set_req(InitializeNode::Memory, minit_in);
--- a/hotspot/src/share/vm/opto/lcm.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/lcm.cpp Fri May 30 07:22:22 2008 -0700
@@ -113,6 +113,7 @@
case Op_LoadN:
case Op_LoadS:
case Op_LoadKlass:
+ case Op_LoadNKlass:
case Op_LoadRange:
case Op_LoadD_unaligned:
case Op_LoadL_unaligned:
@@ -133,6 +134,7 @@
if( mach->in(2) != val ) continue;
break; // Found a memory op?
case Op_StrComp:
+ case Op_AryEq:
// Not a legit memory op for implicit null check regardless of
// embedded loads
continue;
--- a/hotspot/src/share/vm/opto/library_call.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/library_call.cpp Fri May 30 07:22:22 2008 -0700
@@ -163,6 +163,7 @@
bool inline_native_newArray();
bool inline_native_getLength();
bool inline_array_copyOf(bool is_copyOfRange);
+ bool inline_array_equals();
bool inline_native_clone(bool is_virtual);
bool inline_native_Reflection_getCallerClass();
bool inline_native_AtomicLong_get();
@@ -259,6 +260,7 @@
switch (id) {
case vmIntrinsics::_indexOf:
case vmIntrinsics::_compareTo:
+ case vmIntrinsics::_equalsC:
break; // InlineNatives does not control String.compareTo
default:
return NULL;
@@ -272,6 +274,9 @@
case vmIntrinsics::_indexOf:
if (!SpecialStringIndexOf) return NULL;
break;
+ case vmIntrinsics::_equalsC:
+ if (!SpecialArraysEquals) return NULL;
+ break;
case vmIntrinsics::_arraycopy:
if (!InlineArrayCopy) return NULL;
break;
@@ -586,6 +591,8 @@
return inline_array_copyOf(false);
case vmIntrinsics::_copyOfRange:
return inline_array_copyOf(true);
+ case vmIntrinsics::_equalsC:
+ return inline_array_equals();
case vmIntrinsics::_clone:
return inline_native_clone(intrinsic()->is_virtual());
@@ -813,6 +820,22 @@
return true;
}
+//------------------------------inline_array_equals----------------------------
+bool LibraryCallKit::inline_array_equals() {
+
+ _sp += 2;
+ Node *argument2 = pop();
+ Node *argument1 = pop();
+
+ Node* equals =
+ _gvn.transform(new (C, 3) AryEqNode(control(),
+ argument1,
+ argument2)
+ );
+ push(equals);
+ return true;
+}
+
// Java version of String.indexOf(constant string)
// class StringDecl {
// StringDecl(char[] ca) {
@@ -896,7 +919,7 @@
Node* sourcea = basic_plus_adr(string_object, string_object, value_offset);
Node* source = make_load(no_ctrl, sourcea, source_type, T_OBJECT, string_type->add_offset(value_offset));
- Node* target = _gvn.transform(ConPNode::make(C, target_array));
+ Node* target = _gvn.transform( makecon(TypeOopPtr::make_from_constant(target_array)) );
jint target_length = target_array->length();
const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin));
const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot);
@@ -2168,7 +2191,7 @@
// (They don't if CAS fails, but it isn't worth checking.)
pre_barrier(control(), base, adr, alias_idx, newval, value_type, T_OBJECT);
#ifdef _LP64
- if (adr->bottom_type()->is_narrow()) {
+ if (adr->bottom_type()->is_ptr_to_narrowoop()) {
cas = _gvn.transform(new (C, 5) CompareAndSwapNNode(control(), mem, adr,
EncodePNode::encode(&_gvn, newval),
EncodePNode::encode(&_gvn, oldval)));
@@ -2454,7 +2477,7 @@
if (region == NULL) never_see_null = true;
Node* p = basic_plus_adr(mirror, offset);
const TypeKlassPtr* kls_type = TypeKlassPtr::OBJECT_OR_NULL;
- Node* kls = _gvn.transform(new (C, 3) LoadKlassNode(0, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type));
+ Node* kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type) );
_sp += nargs; // any deopt will start just before call to enclosing method
Node* null_ctl = top();
kls = null_check_oop(kls, &null_ctl, never_see_null);
@@ -2634,7 +2657,7 @@
phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror())));
// If we fall through, it's a plain class. Get its _super.
p = basic_plus_adr(kls, Klass::super_offset_in_bytes() + sizeof(oopDesc));
- kls = _gvn.transform(new (C, 3) LoadKlassNode(0, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL));
+ kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL) );
null_ctl = top();
kls = null_check_oop(kls, &null_ctl);
if (null_ctl != top()) {
@@ -2720,7 +2743,7 @@
args[which_arg] = _gvn.transform(arg);
Node* p = basic_plus_adr(arg, class_klass_offset);
- Node* kls = new (C, 3) LoadKlassNode(0, immutable_memory(), p, adr_type, kls_type);
+ Node* kls = LoadKlassNode::make(_gvn, immutable_memory(), p, adr_type, kls_type);
klasses[which_arg] = _gvn.transform(kls);
}
@@ -2838,6 +2861,8 @@
_sp += nargs; // set original stack for use by uncommon_trap
mirror = do_null_check(mirror, T_OBJECT);
_sp -= nargs;
+ // If mirror or obj is dead, only null-path is taken.
+ if (stopped()) return true;
enum { _normal_path = 1, _slow_path = 2, PATH_LIMIT };
RegionNode* result_reg = new(C, PATH_LIMIT) RegionNode(PATH_LIMIT);
@@ -3827,24 +3852,22 @@
if (!stopped()) {
// Copy the fastest available way.
// (No need for PreserveJVMState, since we're using it all up now.)
+ // TODO: generate fields/elements copies for small objects instead.
Node* src = obj;
Node* dest = raw_obj;
- Node* end = dest;
Node* size = _gvn.transform(alloc_siz);
// Exclude the header.
int base_off = instanceOopDesc::base_offset_in_bytes();
if (UseCompressedOops) {
- // copy the header gap though.
- Node* sptr = basic_plus_adr(src, base_off);
- Node* dptr = basic_plus_adr(dest, base_off);
- Node* sval = make_load(control(), sptr, TypeInt::INT, T_INT, raw_adr_type);
- store_to_memory(control(), dptr, sval, T_INT, raw_adr_type);
- base_off += sizeof(int);
+ assert(base_off % BytesPerLong != 0, "base with compressed oops");
+ // With compressed oops base_offset_in_bytes is 12 which creates
+ // the gap since countx is rounded by 8 bytes below.
+ // Copy klass and the gap.
+ base_off = instanceOopDesc::klass_offset_in_bytes();
}
src = basic_plus_adr(src, base_off);
dest = basic_plus_adr(dest, base_off);
- end = basic_plus_adr(end, size);
// Compute the length also, if needed:
Node* countx = size;
@@ -4388,7 +4411,7 @@
// (At this point we can assume disjoint_bases, since types differ.)
int ek_offset = objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc);
Node* p1 = basic_plus_adr(dest_klass, ek_offset);
- Node* n1 = new (C, 3) LoadKlassNode(0, immutable_memory(), p1, TypeRawPtr::BOTTOM);
+ Node* n1 = LoadKlassNode::make(_gvn, immutable_memory(), p1, TypeRawPtr::BOTTOM);
Node* dest_elem_klass = _gvn.transform(n1);
Node* cv = generate_checkcast_arraycopy(adr_type,
dest_elem_klass,
--- a/hotspot/src/share/vm/opto/loopnode.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/loopnode.cpp Fri May 30 07:22:22 2008 -0700
@@ -2632,6 +2632,7 @@
case Op_LoadD_unaligned:
case Op_LoadL_unaligned:
case Op_StrComp: // Does a bunch of load-like effects
+ case Op_AryEq:
pinned = false;
}
if( pinned ) {
--- a/hotspot/src/share/vm/opto/loopopts.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/loopopts.cpp Fri May 30 07:22:22 2008 -0700
@@ -464,6 +464,7 @@
case T_FLOAT:
case T_DOUBLE:
case T_ADDRESS: // (RawPtr)
+ case T_NARROWOOP:
cost++;
break;
case T_OBJECT: { // Base oops are OK, but not derived oops
--- a/hotspot/src/share/vm/opto/macro.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/macro.cpp Fri May 30 07:22:22 2008 -0700
@@ -458,7 +458,7 @@
}
} else if (use->is_SafePoint()) {
SafePointNode* sfpt = use->as_SafePoint();
- if (sfpt->has_non_debug_use(res)) {
+ if (sfpt->is_Call() && sfpt->as_Call()->has_non_debug_use(res)) {
// Object is passed as argument.
DEBUG_ONLY(disq_node = use;)
NOT_PRODUCT(fail_eliminate = "Object is passed as argument";)
@@ -1282,12 +1282,6 @@
}
rawmem = make_store(control, rawmem, object, oopDesc::mark_offset_in_bytes(), mark_node, T_ADDRESS);
- if (UseCompressedOops) {
- Node *zeronode = makecon(TypeInt::ZERO);
- // store uncompressed 0 into klass ptr to zero out gap. The gap is
- // used for primitive fields and has to be zeroed.
- rawmem = make_store(control, rawmem, object, oopDesc::klass_gap_offset_in_bytes(), zeronode, T_INT);
- }
rawmem = make_store(control, rawmem, object, oopDesc::klass_offset_in_bytes(), klass_node, T_OBJECT);
int header_size = alloc->minimum_header_size(); // conservatively small
--- a/hotspot/src/share/vm/opto/matcher.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/matcher.cpp Fri May 30 07:22:22 2008 -0700
@@ -52,7 +52,7 @@
#ifdef ASSERT
_old2new_map(C->comp_arena()),
#endif
- _shared_constants(C->comp_arena()),
+ _shared_nodes(C->comp_arena()),
_reduceOp(reduceOp), _leftOp(leftOp), _rightOp(rightOp),
_swallowed(swallowed),
_begin_inst_chain_rule(_BEGIN_INST_CHAIN_RULE),
@@ -744,6 +744,7 @@
if (nidx == Compile::AliasIdxBot && midx == Compile::AliasIdxTop) {
switch (n->Opcode()) {
case Op_StrComp:
+ case Op_AryEq:
case Op_MemBarVolatile:
case Op_MemBarCPUOrder: // %%% these ideals should have narrower adr_type?
nidx = Compile::AliasIdxTop;
@@ -880,7 +881,7 @@
Node *m = n->in(i); // Get input
int op = m->Opcode();
assert((op == Op_BoxLock) == jvms->is_monitor_use(i), "boxes only at monitor sites");
- if( op == Op_ConI || op == Op_ConP ||
+ if( op == Op_ConI || op == Op_ConP || op == Op_ConN ||
op == Op_ConF || op == Op_ConD || op == Op_ConL
// || op == Op_BoxLock // %%%% enable this and remove (+++) in chaitin.cpp
) {
@@ -1191,7 +1192,7 @@
uint cnt = n->req();
uint start = 1;
if( mem != (Node*)1 ) start = MemNode::Memory+1;
- if( n->Opcode() == Op_AddP ) {
+ if( n->is_AddP() ) {
assert( mem == (Node*)1, "" );
start = AddPNode::Base+1;
}
@@ -1219,7 +1220,7 @@
if( t->singleton() ) {
// Never force constants into registers. Allow them to match as
// constants or registers. Copies of the same value will share
- // the same register. See find_shared_constant.
+ // the same register. See find_shared_node.
return false;
} else { // Not a constant
// Stop recursion if they have different Controls.
@@ -1243,12 +1244,10 @@
if( j == max_scan ) // No post-domination before scan end?
return true; // Then break the match tree up
}
-
- if (m->Opcode() == Op_DecodeN && m->outcnt() == 2) {
+ if (m->is_DecodeN() && Matcher::clone_shift_expressions) {
// These are commonly used in address expressions and can
- // efficiently fold into them in some cases but because they are
- // consumed by AddP they commonly have two users.
- if (m->raw_out(0) == m->raw_out(1) && m->raw_out(0)->Opcode() == Op_AddP) return false;
+ // efficiently fold into them on X64 in some cases.
+ return false;
}
}
@@ -1368,13 +1367,16 @@
// which reduces the number of copies of a constant in the final
// program. The register allocator is free to split uses later to
// split live ranges.
-MachNode* Matcher::find_shared_constant(Node* leaf, uint rule) {
- if (!leaf->is_Con()) return NULL;
+MachNode* Matcher::find_shared_node(Node* leaf, uint rule) {
+ if (!leaf->is_Con() && !leaf->is_DecodeN()) return NULL;
// See if this Con has already been reduced using this rule.
- if (_shared_constants.Size() <= leaf->_idx) return NULL;
- MachNode* last = (MachNode*)_shared_constants.at(leaf->_idx);
+ if (_shared_nodes.Size() <= leaf->_idx) return NULL;
+ MachNode* last = (MachNode*)_shared_nodes.at(leaf->_idx);
if (last != NULL && rule == last->rule()) {
+ // Don't expect control change for DecodeN
+ if (leaf->is_DecodeN())
+ return last;
// Get the new space root.
Node* xroot = new_node(C->root());
if (xroot == NULL) {
@@ -1420,9 +1422,9 @@
MachNode *Matcher::ReduceInst( State *s, int rule, Node *&mem ) {
assert( rule >= NUM_OPERANDS, "called with operand rule" );
- MachNode* shared_con = find_shared_constant(s->_leaf, rule);
- if (shared_con != NULL) {
- return shared_con;
+ MachNode* shared_node = find_shared_node(s->_leaf, rule);
+ if (shared_node != NULL) {
+ return shared_node;
}
// Build the object to represent this state & prepare for recursive calls
@@ -1447,7 +1449,7 @@
mach->ins_req(MemNode::Memory,mem);
// If the _leaf is an AddP, insert the base edge
- if( leaf->Opcode() == Op_AddP )
+ if( leaf->is_AddP() )
mach->ins_req(AddPNode::Base,leaf->in(AddPNode::Base));
uint num_proj = _proj_list.size();
@@ -1475,9 +1477,9 @@
guarantee(_proj_list.size() == num_proj, "no allocation during spill generation");
}
- if (leaf->is_Con()) {
+ if (leaf->is_Con() || leaf->is_DecodeN()) {
// Record the con for sharing
- _shared_constants.map(leaf->_idx, ex);
+ _shared_nodes.map(leaf->_idx, ex);
}
return ex;
@@ -1716,6 +1718,7 @@
mstack.push(n->in(0), Pre_Visit); // Visit Control input
continue; // while (mstack.is_nonempty())
case Op_StrComp:
+ case Op_AryEq:
set_shared(n); // Force result into register (it will be anyways)
break;
case Op_ConP: { // Convert pointers above the centerline to NUL
@@ -1726,6 +1729,14 @@
}
break;
}
+ case Op_ConN: { // Convert narrow pointers above the centerline to NUL
+ TypeNode *tn = n->as_Type(); // Constants derive from type nodes
+ const TypePtr* tp = tn->type()->is_narrowoop()->make_oopptr();
+ if (tp->_ptr == TypePtr::AnyNull) {
+ tn->set_type(TypeNarrowOop::NULL_PTR);
+ }
+ break;
+ }
case Op_Binary: // These are introduced in the Post_Visit state.
ShouldNotReachHere();
break;
@@ -1760,6 +1771,7 @@
case Op_LoadF:
case Op_LoadI:
case Op_LoadKlass:
+ case Op_LoadNKlass:
case Op_LoadL:
case Op_LoadS:
case Op_LoadP:
@@ -1817,7 +1829,7 @@
Node *adr = m->in(AddPNode::Address);
// Intel, ARM and friends can handle 2 adds in addressing mode
- if( clone_shift_expressions && adr->Opcode() == Op_AddP &&
+ if( clone_shift_expressions && adr->is_AddP() &&
// AtomicAdd is not an addressing expression.
// Cheap to find it by looking for screwy base.
!adr->in(AddPNode::Base)->is_top() ) {
@@ -1891,6 +1903,7 @@
case Op_CMoveF:
case Op_CMoveI:
case Op_CMoveL:
+ case Op_CMoveN:
case Op_CMoveP: {
// Restructure into a binary tree for Matching. It's possible that
// we could move this code up next to the graph reshaping for IfNodes
--- a/hotspot/src/share/vm/opto/matcher.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/matcher.hpp Fri May 30 07:22:22 2008 -0700
@@ -48,7 +48,7 @@
void ReduceOper( State *s, int newrule, Node *&mem, MachNode *mach );
// If this node already matched using "rule", return the MachNode for it.
- MachNode* find_shared_constant(Node* con, uint rule);
+ MachNode* find_shared_node(Node* n, uint rule);
// Convert a dense opcode number to an expanded rule number
const int *_reduceOp;
@@ -81,7 +81,7 @@
Node_List &_proj_list; // For Machine nodes killing many values
- Node_Array _shared_constants;
+ Node_Array _shared_nodes;
debug_only(Node_Array _old2new_map;) // Map roots of ideal-trees to machine-roots
--- a/hotspot/src/share/vm/opto/memnode.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/memnode.cpp Fri May 30 07:22:22 2008 -0700
@@ -133,7 +133,9 @@
PhiNode *mphi = result->as_Phi();
assert(mphi->bottom_type() == Type::MEMORY, "memory phi required");
const TypePtr *t = mphi->adr_type();
- if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM) {
+ if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM ||
+ t->isa_oopptr() && !t->is_oopptr()->is_instance() &&
+ t->is_oopptr()->cast_to_instance(t_oop->instance_id()) == t_oop) {
// clone the Phi with our address type
result = mphi->split_out_instance(t_adr, igvn);
} else {
@@ -154,7 +156,7 @@
phase->C->must_alias(adr_check, alias_idx );
// Sometimes dead array references collapse to a[-1], a[-2], or a[-3]
if( !consistent && adr_check != NULL && !adr_check->empty() &&
- tp->isa_aryptr() && tp->offset() == Type::OffsetBot &&
+ tp->isa_aryptr() && tp->offset() == Type::OffsetBot &&
adr_check->isa_aryptr() && adr_check->offset() != Type::OffsetBot &&
( adr_check->offset() == arrayOopDesc::length_offset_in_bytes() ||
adr_check->offset() == oopDesc::klass_offset_in_bytes() ||
@@ -263,7 +265,10 @@
// of all its inputs dominate or equal to sub's control edge.
// Currently 'sub' is either Allocate, Initialize or Start nodes.
- assert(sub->is_Allocate() || sub->is_Initialize() || sub->is_Start(), "expecting only these nodes");
+ // Or Region for the check in LoadNode::Ideal();
+ // 'sub' should have sub->in(0) != NULL.
+ assert(sub->is_Allocate() || sub->is_Initialize() || sub->is_Start() ||
+ sub->is_Region(), "expecting only these nodes");
// Get control edge of 'sub'.
sub = sub->find_exact_control(sub->in(0));
@@ -576,6 +581,9 @@
// Find any cast-away of null-ness and keep its control. Null cast-aways are
// going away in this pass and we need to make this memory op depend on the
// gating null check.
+Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
+ return Ideal_common_DU_postCCP(ccp, this, in(MemNode::Address));
+}
// I tried to leave the CastPP's in. This makes the graph more accurate in
// some sense; we get to keep around the knowledge that an oop is not-null
@@ -585,15 +593,14 @@
// some of the more trivial cases in the optimizer. Removing more useless
// Phi's started allowing Loads to illegally float above null checks. I gave
// up on this approach. CNC 10/20/2000
-Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
- Node *ctr = in(MemNode::Control);
- Node *mem = in(MemNode::Memory);
- Node *adr = in(MemNode::Address);
+// This static method may be called not from MemNode (EncodePNode calls it).
+// Only the control edge of the node 'n' might be updated.
+Node *MemNode::Ideal_common_DU_postCCP( PhaseCCP *ccp, Node* n, Node* adr ) {
Node *skipped_cast = NULL;
// Need a null check? Regular static accesses do not because they are
// from constant addresses. Array ops are gated by the range check (which
// always includes a NULL check). Just check field ops.
- if( !ctr ) {
+ if( n->in(MemNode::Control) == NULL ) {
// Scan upwards for the highest location we can place this memory op.
while( true ) {
switch( adr->Opcode() ) {
@@ -618,10 +625,10 @@
}
// CastPP is going away in this pass! We need this memory op to be
// control-dependent on the test that is guarding the CastPP.
- ccp->hash_delete(this);
- set_req(MemNode::Control, adr->in(0));
- ccp->hash_insert(this);
- return this;
+ ccp->hash_delete(n);
+ n->set_req(MemNode::Control, adr->in(0));
+ ccp->hash_insert(n);
+ return n;
case Op_Phi:
// Attempt to float above a Phi to some dominating point.
@@ -652,10 +659,10 @@
adr = adr->in(1);
continue;
}
- ccp->hash_delete(this);
- set_req(MemNode::Control, adr->in(0));
- ccp->hash_insert(this);
- return this;
+ ccp->hash_delete(n);
+ n->set_req(MemNode::Control, adr->in(0));
+ ccp->hash_insert(n);
+ return n;
// List of "safe" opcodes; those that implicitly block the memory
// op below any null check.
@@ -664,10 +671,13 @@
case Op_LoadP: // Loading from within a klass
case Op_LoadN: // Loading from within a klass
case Op_LoadKlass: // Loading from within a klass
+ case Op_LoadNKlass: // Loading from within a klass
case Op_ConP: // Loading from a klass
+ case Op_ConN: // Loading from a klass
case Op_CreateEx: // Sucking up the guts of an exception oop
case Op_Con: // Reading from TLS
case Op_CMoveP: // CMoveP is pinned
+ case Op_CMoveN: // CMoveN is pinned
break; // No progress
case Op_Proj: // Direct call to an allocation routine
@@ -676,8 +686,8 @@
{
assert(adr->as_Proj()->_con == TypeFunc::Parms, "must be return value");
const Node* call = adr->in(0);
- if (call->is_CallStaticJava()) {
- const CallStaticJavaNode* call_java = call->as_CallStaticJava();
+ if (call->is_CallJava()) {
+ const CallJavaNode* call_java = call->as_CallJava();
const TypeTuple *r = call_java->tf()->range();
assert(r->cnt() > TypeFunc::Parms, "must return value");
const Type* ret_type = r->field_at(TypeFunc::Parms);
@@ -749,7 +759,7 @@
case T_ADDRESS: return new (C, 3) LoadPNode(ctl, mem, adr, adr_type, rt->is_ptr() );
case T_OBJECT:
#ifdef _LP64
- if (adr->bottom_type()->is_narrow()) {
+ if (adr->bottom_type()->is_ptr_to_narrowoop()) {
const TypeNarrowOop* narrowtype;
if (rt->isa_narrowoop()) {
narrowtype = rt->is_narrowoop();
@@ -761,10 +771,10 @@
return DecodeNNode::decode(&gvn, load);
} else
#endif
- {
- assert(!adr->bottom_type()->is_narrow(), "should have got back a narrow oop");
- return new (C, 3) LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr());
- }
+ {
+ assert(!adr->bottom_type()->is_ptr_to_narrowoop(), "should have got back a narrow oop");
+ return new (C, 3) LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr());
+ }
}
ShouldNotReachHere();
return (LoadNode*)NULL;
@@ -1118,6 +1128,127 @@
return NULL;
}
+//------------------------------split_through_phi------------------------------
+// Split instance field load through Phi.
+Node *LoadNode::split_through_phi(PhaseGVN *phase) {
+ Node* mem = in(MemNode::Memory);
+ Node* address = in(MemNode::Address);
+ const TypePtr *addr_t = phase->type(address)->isa_ptr();
+ const TypeOopPtr *t_oop = addr_t->isa_oopptr();
+
+ assert(mem->is_Phi() && (t_oop != NULL) &&
+ t_oop->is_instance_field(), "invalide conditions");
+
+ Node *region = mem->in(0);
+ if (region == NULL) {
+ return NULL; // Wait stable graph
+ }
+ uint cnt = mem->req();
+ for( uint i = 1; i < cnt; i++ ) {
+ Node *in = mem->in(i);
+ if( in == NULL ) {
+ return NULL; // Wait stable graph
+ }
+ }
+ // Check for loop invariant.
+ if (cnt == 3) {
+ for( uint i = 1; i < cnt; i++ ) {
+ Node *in = mem->in(i);
+ Node* m = MemNode::optimize_memory_chain(in, addr_t, phase);
+ if (m == mem) {
+ set_req(MemNode::Memory, mem->in(cnt - i)); // Skip this phi.
+ return this;
+ }
+ }
+ }
+ // Split through Phi (see original code in loopopts.cpp).
+ assert(phase->C->have_alias_type(addr_t), "instance should have alias type");
+
+ // Do nothing here if Identity will find a value
+ // (to avoid infinite chain of value phis generation).
+ if ( !phase->eqv(this, this->Identity(phase)) )
+ return NULL;
+
+ // Skip the split if the region dominates some control edge of the address.
+ if (cnt == 3 && !MemNode::all_controls_dominate(address, region))
+ return NULL;
+
+ const Type* this_type = this->bottom_type();
+ int this_index = phase->C->get_alias_index(addr_t);
+ int this_offset = addr_t->offset();
+ int this_iid = addr_t->is_oopptr()->instance_id();
+ int wins = 0;
+ PhaseIterGVN *igvn = phase->is_IterGVN();
+ Node *phi = new (igvn->C, region->req()) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset);
+ for( uint i = 1; i < region->req(); i++ ) {
+ Node *x;
+ Node* the_clone = NULL;
+ if( region->in(i) == phase->C->top() ) {
+ x = phase->C->top(); // Dead path? Use a dead data op
+ } else {
+ x = this->clone(); // Else clone up the data op
+ the_clone = x; // Remember for possible deletion.
+ // Alter data node to use pre-phi inputs
+ if( this->in(0) == region ) {
+ x->set_req( 0, region->in(i) );
+ } else {
+ x->set_req( 0, NULL );
+ }
+ for( uint j = 1; j < this->req(); j++ ) {
+ Node *in = this->in(j);
+ if( in->is_Phi() && in->in(0) == region )
+ x->set_req( j, in->in(i) ); // Use pre-Phi input for the clone
+ }
+ }
+ // Check for a 'win' on some paths
+ const Type *t = x->Value(igvn);
+
+ bool singleton = t->singleton();
+
+ // See comments in PhaseIdealLoop::split_thru_phi().
+ if( singleton && t == Type::TOP ) {
+ singleton &= region->is_Loop() && (i != LoopNode::EntryControl);
+ }
+
+ if( singleton ) {
+ wins++;
+ x = igvn->makecon(t);
+ } else {
+ // We now call Identity to try to simplify the cloned node.
+ // Note that some Identity methods call phase->type(this).
+ // Make sure that the type array is big enough for
+ // our new node, even though we may throw the node away.
+ // (This tweaking with igvn only works because x is a new node.)
+ igvn->set_type(x, t);
+ Node *y = x->Identity(igvn);
+ if( y != x ) {
+ wins++;
+ x = y;
+ } else {
+ y = igvn->hash_find(x);
+ if( y ) {
+ wins++;
+ x = y;
+ } else {
+ // Else x is a new node we are keeping
+ // We do not need register_new_node_with_optimizer
+ // because set_type has already been called.
+ igvn->_worklist.push(x);
+ }
+ }
+ }
+ if (x != the_clone && the_clone != NULL)
+ igvn->remove_dead_node(the_clone);
+ phi->set_req(i, x);
+ }
+ if( wins > 0 ) {
+ // Record Phi
+ igvn->register_new_node_with_optimizer(phi);
+ return phi;
+ }
+ igvn->remove_dead_node(phi);
+ return NULL;
+}
//------------------------------Ideal------------------------------------------
// If the load is from Field memory and the pointer is non-null, we can
@@ -1175,112 +1306,9 @@
const TypeOopPtr *t_oop = addr_t->isa_oopptr();
if (can_reshape && opt_mem->is_Phi() &&
(t_oop != NULL) && t_oop->is_instance_field()) {
- assert(t_oop->offset() != Type::OffsetBot && t_oop->offset() != Type::OffsetTop, "");
- Node *region = opt_mem->in(0);
- uint cnt = opt_mem->req();
- for( uint i = 1; i < cnt; i++ ) {
- Node *in = opt_mem->in(i);
- if( in == NULL ) {
- region = NULL; // Wait stable graph
- break;
- }
- }
- if (region != NULL) {
- // Check for loop invariant.
- if (cnt == 3) {
- for( uint i = 1; i < cnt; i++ ) {
- Node *in = opt_mem->in(i);
- Node* m = MemNode::optimize_memory_chain(in, addr_t, phase);
- if (m == opt_mem) {
- set_req(MemNode::Memory, opt_mem->in(cnt - i)); // Skip this phi.
- return this;
- }
- }
- }
- // Split through Phi (see original code in loopopts.cpp).
- assert(phase->C->have_alias_type(addr_t), "instance should have alias type");
-
- // Do nothing here if Identity will find a value
- // (to avoid infinite chain of value phis generation).
- if ( !phase->eqv(this, this->Identity(phase)) )
- return NULL;
-
- const Type* this_type = this->bottom_type();
- int this_index = phase->C->get_alias_index(addr_t);
- int this_offset = addr_t->offset();
- int this_iid = addr_t->is_oopptr()->instance_id();
- int wins = 0;
- PhaseIterGVN *igvn = phase->is_IterGVN();
- Node *phi = new (igvn->C, region->req()) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset);
- for( uint i = 1; i < region->req(); i++ ) {
- Node *x;
- Node* the_clone = NULL;
- if( region->in(i) == phase->C->top() ) {
- x = phase->C->top(); // Dead path? Use a dead data op
- } else {
- x = this->clone(); // Else clone up the data op
- the_clone = x; // Remember for possible deletion.
- // Alter data node to use pre-phi inputs
- if( this->in(0) == region ) {
- x->set_req( 0, region->in(i) );
- } else {
- x->set_req( 0, NULL );
- }
- for( uint j = 1; j < this->req(); j++ ) {
- Node *in = this->in(j);
- if( in->is_Phi() && in->in(0) == region )
- x->set_req( j, in->in(i) ); // Use pre-Phi input for the clone
- }
- }
- // Check for a 'win' on some paths
- const Type *t = x->Value(igvn);
-
- bool singleton = t->singleton();
-
- // See comments in PhaseIdealLoop::split_thru_phi().
- if( singleton && t == Type::TOP ) {
- singleton &= region->is_Loop() && (i != LoopNode::EntryControl);
- }
-
- if( singleton ) {
- wins++;
- x = igvn->makecon(t);
- } else {
- // We now call Identity to try to simplify the cloned node.
- // Note that some Identity methods call phase->type(this).
- // Make sure that the type array is big enough for
- // our new node, even though we may throw the node away.
- // (This tweaking with igvn only works because x is a new node.)
- igvn->set_type(x, t);
- Node *y = x->Identity(igvn);
- if( y != x ) {
- wins++;
- x = y;
- } else {
- y = igvn->hash_find(x);
- if( y ) {
- wins++;
- x = y;
- } else {
- // Else x is a new node we are keeping
- // We do not need register_new_node_with_optimizer
- // because set_type has already been called.
- igvn->_worklist.push(x);
- }
- }
- }
- if (x != the_clone && the_clone != NULL)
- igvn->remove_dead_node(the_clone);
- phi->set_req(i, x);
- }
- if( wins > 0 ) {
- // Record Phi
- igvn->register_new_node_with_optimizer(phi);
- return phi;
- } else {
- igvn->remove_dead_node(phi);
- }
- }
+ // Split instance field load through Phi.
+ Node* result = split_through_phi(phase);
+ if (result != NULL) return result;
}
}
@@ -1584,8 +1612,31 @@
}
//=============================================================================
+//----------------------------LoadKlassNode::make------------------------------
+// Polymorphic factory method:
+Node *LoadKlassNode::make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, const TypeKlassPtr *tk ) {
+ Compile* C = gvn.C;
+ Node *ctl = NULL;
+ // sanity check the alias category against the created node type
+ const TypeOopPtr *adr_type = adr->bottom_type()->isa_oopptr();
+ assert(adr_type != NULL, "expecting TypeOopPtr");
+#ifdef _LP64
+ if (adr_type->is_ptr_to_narrowoop()) {
+ const TypeNarrowOop* narrowtype = tk->is_oopptr()->make_narrowoop();
+ Node* load_klass = gvn.transform(new (C, 3) LoadNKlassNode(ctl, mem, adr, at, narrowtype));
+ return DecodeNNode::decode(&gvn, load_klass);
+ }
+#endif
+ assert(!adr_type->is_ptr_to_narrowoop(), "should have got back a narrow oop");
+ return new (C, 3) LoadKlassNode(ctl, mem, adr, at, tk);
+}
+
//------------------------------Value------------------------------------------
const Type *LoadKlassNode::Value( PhaseTransform *phase ) const {
+ return klass_value_common(phase);
+}
+
+const Type *LoadNode::klass_value_common( PhaseTransform *phase ) const {
// Either input is TOP ==> the result is TOP
const Type *t1 = phase->type( in(MemNode::Memory) );
if (t1 == Type::TOP) return Type::TOP;
@@ -1717,6 +1768,10 @@
// To clean up reflective code, simplify k.java_mirror.as_klass to plain k.
// Also feed through the klass in Allocate(...klass...)._klass.
Node* LoadKlassNode::Identity( PhaseTransform *phase ) {
+ return klass_identity_common(phase);
+}
+
+Node* LoadNode::klass_identity_common(PhaseTransform *phase ) {
Node* x = LoadNode::Identity(phase);
if (x != this) return x;
@@ -1775,6 +1830,34 @@
return this;
}
+
+//------------------------------Value------------------------------------------
+const Type *LoadNKlassNode::Value( PhaseTransform *phase ) const {
+ const Type *t = klass_value_common(phase);
+
+ if (t == TypePtr::NULL_PTR) {
+ return TypeNarrowOop::NULL_PTR;
+ }
+ if (t != Type::TOP && !t->isa_narrowoop()) {
+ assert(t->is_oopptr(), "sanity");
+ t = t->is_oopptr()->make_narrowoop();
+ }
+ return t;
+}
+
+//------------------------------Identity---------------------------------------
+// To clean up reflective code, simplify k.java_mirror.as_klass to narrow k.
+// Also feed through the klass in Allocate(...klass...)._klass.
+Node* LoadNKlassNode::Identity( PhaseTransform *phase ) {
+ Node *x = klass_identity_common(phase);
+
+ const Type *t = phase->type( x );
+ if( t == Type::TOP ) return x;
+ if( t->isa_narrowoop()) return x;
+
+ return EncodePNode::encode(phase, x);
+}
+
//------------------------------Value-----------------------------------------
const Type *LoadRangeNode::Value( PhaseTransform *phase ) const {
// Either input is TOP ==> the result is TOP
@@ -1835,7 +1918,7 @@
case T_ADDRESS:
case T_OBJECT:
#ifdef _LP64
- if (adr->bottom_type()->is_narrow() ||
+ if (adr->bottom_type()->is_ptr_to_narrowoop() ||
(UseCompressedOops && val->bottom_type()->isa_klassptr() &&
adr->bottom_type()->isa_rawptr())) {
const TypePtr* type = val->bottom_type()->is_ptr();
@@ -2311,6 +2394,13 @@
return remove_dead_region(phase, can_reshape) ? this : NULL;
}
+//------------------------------Ideal------------------------------------------
+// Return a node which is more "ideal" than the current node. Strip out
+// control copies
+Node *AryEqNode::Ideal(PhaseGVN *phase, bool can_reshape){
+ return remove_dead_region(phase, can_reshape) ? this : NULL;
+}
+
//=============================================================================
MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent)
--- a/hotspot/src/share/vm/opto/memnode.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/memnode.hpp Fri May 30 07:22:22 2008 -0700
@@ -72,7 +72,8 @@
// This one should probably be a phase-specific function:
static bool all_controls_dominate(Node* dom, Node* sub);
- // Is this Node a MemNode or some descendent? Default is YES.
+ // Find any cast-away of null-ness and keep its control.
+ static Node *Ideal_common_DU_postCCP( PhaseCCP *ccp, Node* n, Node* adr );
virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp );
virtual const class TypePtr *adr_type() const; // returns bottom_type of address
@@ -150,6 +151,9 @@
// zero out the control input.
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
+ // Split instance field load through Phi.
+ Node* split_through_phi(PhaseGVN *phase);
+
// Recover original value from boxed values
Node *eliminate_autobox(PhaseGVN *phase);
@@ -157,6 +161,10 @@
// then call the virtual add() to set the type.
virtual const Type *Value( PhaseTransform *phase ) const;
+ // Common methods for LoadKlass and LoadNKlass nodes.
+ const Type *klass_value_common( PhaseTransform *phase ) const;
+ Node *klass_identity_common( PhaseTransform *phase );
+
virtual uint ideal_reg() const;
virtual const Type *bottom_type() const;
// Following method is copied from TypeNode:
@@ -358,14 +366,35 @@
// Load a Klass from an object
class LoadKlassNode : public LoadPNode {
public:
- LoadKlassNode( Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk = TypeKlassPtr::OBJECT )
+ LoadKlassNode( Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk )
: LoadPNode(c,mem,adr,at,tk) {}
virtual int Opcode() const;
virtual const Type *Value( PhaseTransform *phase ) const;
virtual Node *Identity( PhaseTransform *phase );
virtual bool depends_only_on_test() const { return true; }
+
+ // Polymorphic factory method:
+ static Node* make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at,
+ const TypeKlassPtr *tk = TypeKlassPtr::OBJECT );
};
+//------------------------------LoadNKlassNode---------------------------------
+// Load a narrow Klass from an object.
+class LoadNKlassNode : public LoadNNode {
+public:
+ LoadNKlassNode( Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeNarrowOop *tk )
+ : LoadNNode(c,mem,adr,at,tk) {}
+ virtual int Opcode() const;
+ virtual uint ideal_reg() const { return Op_RegN; }
+ virtual int store_Opcode() const { return Op_StoreN; }
+ virtual BasicType memory_type() const { return T_NARROWOOP; }
+
+ virtual const Type *Value( PhaseTransform *phase ) const;
+ virtual Node *Identity( PhaseTransform *phase );
+ virtual bool depends_only_on_test() const { return true; }
+};
+
+
//------------------------------LoadSNode--------------------------------------
// Load a short (16bits signed) from memory
class LoadSNode : public LoadNode {
@@ -696,6 +725,18 @@
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
};
+//------------------------------AryEq---------------------------------------
+class AryEqNode: public Node {
+public:
+ AryEqNode(Node *control, Node* s1, Node* s2): Node(control, s1, s2) {};
+ virtual int Opcode() const;
+ virtual bool depends_only_on_test() const { return false; }
+ virtual const Type* bottom_type() const { return TypeInt::BOOL; }
+ virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; }
+ virtual uint ideal_reg() const { return Op_RegI; }
+ virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
+};
+
//------------------------------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
--- a/hotspot/src/share/vm/opto/node.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/node.cpp Fri May 30 07:22:22 2008 -0700
@@ -1049,51 +1049,80 @@
Node* orig_sub = sub;
nlist.clear();
bool this_dominates = false;
- uint region_input = 0;
+ bool result = false; // Conservative answer
+
while (sub != NULL) { // walk 'sub' up the chain to 'this'
if (sub == this) {
if (nlist.size() == 0) {
// No Region nodes except loops were visited before and the EntryControl
// path was taken for loops: it did not walk in a cycle.
- return true;
- } else if (!this_dominates) {
+ result = true;
+ break;
+ } else if (this_dominates) {
+ result = false; // already met before: walk in a cycle
+ break;
+ } else {
// Region nodes were visited. Continue walk up to Start or Root
// to make sure that it did not walk in a cycle.
this_dominates = true; // first time meet
iterations_without_region_limit = DominatorSearchLimit; // Reset
- } else {
- return false; // already met before: walk in a cycle
- }
+ }
}
- if (sub->is_Start() || sub->is_Root())
- return this_dominates;
-
+ if (sub->is_Start() || sub->is_Root()) {
+ result = this_dominates;
+ break;
+ }
Node* up = sub->find_exact_control(sub->in(0));
- if (up == NULL || up->is_top())
- return false; // Conservative answer for dead code
+ if (up == NULL || up->is_top()) {
+ result = false; // Conservative answer for dead code
+ break;
+ }
+ if (sub == up && (sub->is_Loop() || sub->is_Region() && sub->req() != 3)) {
+ // Take first valid path on the way up to 'this'.
+ up = sub->in(1); // in(LoopNode::EntryControl);
+ } else if (sub == up && sub->is_Region()) {
+ assert(sub->req() == 3, "sanity");
+ iterations_without_region_limit = DominatorSearchLimit; // Reset
- if (sub == up && sub->is_Loop()) {
- up = sub->in(1); // in(LoopNode::EntryControl);
- } else if (sub == up && sub->is_Region() && sub->req() == 3) {
- iterations_without_region_limit = DominatorSearchLimit; // Reset
+ // Try both paths for such Regions.
+ // It is not accurate without regions dominating information.
+ // With such information the other path should be checked for
+ // the most dominating Region which was visited before.
+ bool region_was_visited_before = false;
uint i = 1;
uint size = nlist.size();
if (size == 0) {
- // No Region nodes (except Loops) were visited before.
+ // No such Region nodes were visited before.
// Take first valid path on the way up to 'this'.
- } else if (nlist.at(size - 1) == sub) {
- // This Region node was just visited. Take other path.
- i = region_input + 1;
- nlist.pop();
} else {
// Was this Region node visited before?
- for (uint j = 0; j < size; j++) {
- if (nlist.at(j) == sub) {
- return false; // The Region node was visited before. Give up.
+ intptr_t ni;
+ int j = size - 1;
+ for (; j >= 0; j--) {
+ ni = (intptr_t)nlist.at(j);
+ if ((Node*)(ni & ~1) == sub) {
+ if ((ni & 1) != 0) {
+ break; // Visited 2 paths. Give up.
+ } else {
+ // The Region node was visited before only once.
+ nlist.remove(j);
+ region_was_visited_before = true;
+ for (; i < sub->req(); i++) {
+ Node* in = sub->in(i);
+ if (in != NULL && !in->is_top() && in != sub) {
+ break;
+ }
+ }
+ i++; // Take other path.
+ break;
+ }
}
}
+ if (j >= 0 && (ni & 1) != 0) {
+ result = false; // Visited 2 paths. Give up.
+ break;
+ }
// The Region node was not visited before.
- // Take first valid path on the way up to 'this'.
}
for (; i < sub->req(); i++) {
Node* in = sub->in(i);
@@ -1102,20 +1131,26 @@
}
}
if (i < sub->req()) {
- nlist.push(sub);
up = sub->in(i);
- region_input = i;
+ if (region_was_visited_before && sub != up) {
+ // Set 0 bit to indicate that both paths were taken.
+ nlist.push((Node*)((intptr_t)sub + 1));
+ } else {
+ nlist.push(sub);
+ }
}
}
- if (sub == up)
- return false; // some kind of tight cycle
-
- if (--iterations_without_region_limit < 0)
- return false; // dead cycle
-
+ if (sub == up) {
+ result = false; // some kind of tight cycle
+ break;
+ }
+ if (--iterations_without_region_limit < 0) {
+ result = false; // dead cycle
+ break;
+ }
sub = up;
}
- return false;
+ return result;
}
//------------------------------remove_dead_region-----------------------------
--- a/hotspot/src/share/vm/opto/node.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/node.hpp Fri May 30 07:22:22 2008 -0700
@@ -53,6 +53,8 @@
class ConNode;
class CountedLoopNode;
class CountedLoopEndNode;
+class DecodeNNode;
+class EncodePNode;
class FastLockNode;
class FastUnlockNode;
class IfNode;
@@ -438,6 +440,12 @@
public:
// Globally replace this node by a given new node, updating all uses.
void replace_by(Node* new_node);
+ // Globally replace this node by a given new node, updating all uses
+ // and cutting input edges of old node.
+ void subsume_by(Node* new_node) {
+ replace_by(new_node);
+ disconnect_inputs(NULL);
+ }
void set_req_X( uint i, Node *n, PhaseIterGVN *igvn );
// Find the one non-null required input. RegionNode only
Node *nonnull_req() const;
@@ -577,6 +585,8 @@
DEFINE_CLASS_ID(CheckCastPP, Type, 2)
DEFINE_CLASS_ID(CMove, Type, 3)
DEFINE_CLASS_ID(SafePointScalarObject, Type, 4)
+ DEFINE_CLASS_ID(DecodeN, Type, 5)
+ DEFINE_CLASS_ID(EncodeP, Type, 6)
DEFINE_CLASS_ID(Mem, Node, 6)
DEFINE_CLASS_ID(Load, Mem, 0)
@@ -685,6 +695,8 @@
DEFINE_CLASS_QUERY(Cmp)
DEFINE_CLASS_QUERY(CountedLoop)
DEFINE_CLASS_QUERY(CountedLoopEnd)
+ DEFINE_CLASS_QUERY(DecodeN)
+ DEFINE_CLASS_QUERY(EncodeP)
DEFINE_CLASS_QUERY(FastLock)
DEFINE_CLASS_QUERY(FastUnlock)
DEFINE_CLASS_QUERY(If)
--- a/hotspot/src/share/vm/opto/output.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/output.cpp Fri May 30 07:22:22 2008 -0700
@@ -48,6 +48,7 @@
// Initialize the space for the BufferBlob used to find and verify
// instruction size in MachNode::emit_size()
init_scratch_buffer_blob();
+ if (failing()) return; // Out of memory
// Make sure I can find the Start Node
Block_Array& bbs = _cfg->_bbs;
--- a/hotspot/src/share/vm/opto/parse1.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/parse1.cpp Fri May 30 07:22:22 2008 -0700
@@ -1901,7 +1901,7 @@
// finalization. In general this will fold up since the concrete
// class is often visible so the access flags are constant.
Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() );
- Node* klass = _gvn.transform(new (C, 3) LoadKlassNode(NULL, immutable_memory(), klass_addr, TypeInstPtr::KLASS));
+ Node* klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), klass_addr, TypeInstPtr::KLASS) );
Node* access_flags_addr = basic_plus_adr(klass, klass, Klass::access_flags_offset_in_bytes() + sizeof(oopDesc));
Node* access_flags = make_load(NULL, access_flags_addr, TypeInt::INT, T_INT);
--- a/hotspot/src/share/vm/opto/parseHelper.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/parseHelper.cpp Fri May 30 07:22:22 2008 -0700
@@ -38,7 +38,7 @@
// Get method
const TypeInstPtr* method_type = TypeInstPtr::make(TypePtr::Constant, method->klass(), true, method, 0);
- Node *method_node = _gvn.transform( new (C, 1) ConPNode(method_type) );
+ Node *method_node = _gvn.transform( ConNode::make(C, method_type) );
kill_dead_locals();
@@ -143,7 +143,7 @@
int klass_offset = oopDesc::klass_offset_in_bytes();
Node* p = basic_plus_adr( ary, ary, klass_offset );
// p's type is array-of-OOPS plus klass_offset
- Node* array_klass = _gvn.transform(new (C, 3) LoadKlassNode(0, immutable_memory(), p, TypeInstPtr::KLASS));
+ Node* array_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS) );
// Get the array klass
const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr();
@@ -189,7 +189,7 @@
// Extract the array element class
int element_klass_offset = objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc);
Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset);
- Node *a_e_klass = _gvn.transform(new (C, 3) LoadKlassNode(0, immutable_memory(), p2, tak));
+ Node *a_e_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p2, tak) );
// Check (the hard way) and throw if not a subklass.
// Result is ignored, we just need the CFG effects.
--- a/hotspot/src/share/vm/opto/type.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/type.cpp Fri May 30 07:22:22 2008 -0700
@@ -311,8 +311,18 @@
mreg2type[Op_RegFlags] = TypeInt::CC;
TypeAryPtr::RANGE = TypeAryPtr::make( TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), current->env()->Object_klass(), false, arrayOopDesc::length_offset_in_bytes());
- // There is no shared klass for Object[]. See note in TypeAryPtr::klass().
- TypeAryPtr::OOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot);
+
+ TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot);
+
+#ifdef _LP64
+ if (UseCompressedOops) {
+ TypeAryPtr::OOPS = TypeAryPtr::NARROWOOPS;
+ } else
+#endif
+ {
+ // There is no shared klass for Object[]. See note in TypeAryPtr::klass().
+ TypeAryPtr::OOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot);
+ }
TypeAryPtr::BYTES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE ,TypeInt::POS), ciTypeArrayKlass::make(T_BYTE), true, Type::OffsetBot);
TypeAryPtr::SHORTS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::SHORT ,TypeInt::POS), ciTypeArrayKlass::make(T_SHORT), true, Type::OffsetBot);
TypeAryPtr::CHARS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::CHAR ,TypeInt::POS), ciTypeArrayKlass::make(T_CHAR), true, Type::OffsetBot);
@@ -321,9 +331,10 @@
TypeAryPtr::FLOATS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::FLOAT ,TypeInt::POS), ciTypeArrayKlass::make(T_FLOAT), true, Type::OffsetBot);
TypeAryPtr::DOUBLES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::DOUBLE ,TypeInt::POS), ciTypeArrayKlass::make(T_DOUBLE), true, Type::OffsetBot);
- TypeAryPtr::_array_body_type[T_NARROWOOP] = NULL; // what should this be?
+ // Nobody should ask _array_body_type[T_NARROWOOP]. Use NULL as assert.
+ TypeAryPtr::_array_body_type[T_NARROWOOP] = NULL;
TypeAryPtr::_array_body_type[T_OBJECT] = TypeAryPtr::OOPS;
- TypeAryPtr::_array_body_type[T_ARRAY] = TypeAryPtr::OOPS; // arrays are stored in oop arrays
+ TypeAryPtr::_array_body_type[T_ARRAY] = TypeAryPtr::OOPS; // arrays are stored in oop arrays
TypeAryPtr::_array_body_type[T_BYTE] = TypeAryPtr::BYTES;
TypeAryPtr::_array_body_type[T_BOOLEAN] = TypeAryPtr::BYTES; // boolean[] is a byte array
TypeAryPtr::_array_body_type[T_SHORT] = TypeAryPtr::SHORTS;
@@ -696,7 +707,7 @@
ResourceMark rm;
Dict d(cmpkey,hashkey); // Stop recursive type dumping
dump2(d,1, st);
- if (isa_ptr() && is_ptr()->is_narrow()) {
+ if (is_ptr_to_narrowoop()) {
st->print(" [narrow]");
}
}
@@ -2146,6 +2157,67 @@
// Convenience common pre-built type.
const TypeOopPtr *TypeOopPtr::BOTTOM;
+//------------------------------TypeOopPtr-------------------------------------
+TypeOopPtr::TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id )
+ : TypePtr(t, ptr, offset),
+ _const_oop(o), _klass(k),
+ _klass_is_exact(xk),
+ _is_ptr_to_narrowoop(false),
+ _instance_id(instance_id) {
+#ifdef _LP64
+ if (UseCompressedOops && _offset != 0) {
+ if (klass() == NULL) {
+ assert(this->isa_aryptr(), "only arrays without klass");
+ _is_ptr_to_narrowoop = true;
+ } else if (_offset == oopDesc::klass_offset_in_bytes()) {
+ _is_ptr_to_narrowoop = true;
+ } else if (this->isa_aryptr()) {
+ _is_ptr_to_narrowoop = (klass()->is_obj_array_klass() &&
+ _offset != arrayOopDesc::length_offset_in_bytes());
+ } else if (klass() == ciEnv::current()->Class_klass() &&
+ (_offset == java_lang_Class::klass_offset_in_bytes() ||
+ _offset == java_lang_Class::array_klass_offset_in_bytes())) {
+ // Special hidden fields from the Class.
+ assert(this->isa_instptr(), "must be an instance ptr.");
+ _is_ptr_to_narrowoop = true;
+ } else if (klass()->is_instance_klass()) {
+ ciInstanceKlass* ik = klass()->as_instance_klass();
+ ciField* field = NULL;
+ if (this->isa_klassptr()) {
+ // Perm objects don't use compressed references, except for
+ // static fields which are currently compressed.
+ field = ik->get_field_by_offset(_offset, true);
+ if (field != NULL) {
+ BasicType basic_elem_type = field->layout_type();
+ _is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT ||
+ basic_elem_type == T_ARRAY);
+ }
+ } else if (_offset == OffsetBot || _offset == OffsetTop) {
+ // unsafe access
+ _is_ptr_to_narrowoop = true;
+ } else { // exclude unsafe ops
+ assert(this->isa_instptr(), "must be an instance ptr.");
+ // Field which contains a compressed oop references.
+ field = ik->get_field_by_offset(_offset, false);
+ if (field != NULL) {
+ BasicType basic_elem_type = field->layout_type();
+ _is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT ||
+ basic_elem_type == T_ARRAY);
+ } else if (klass()->equals(ciEnv::current()->Object_klass())) {
+ // Compile::find_alias_type() cast exactness on all types to verify
+ // that it does not affect alias type.
+ _is_ptr_to_narrowoop = true;
+ } else {
+ // Type for the copy start in LibraryCallKit::inline_native_clone().
+ assert(!klass_is_exact(), "only non-exact klass");
+ _is_ptr_to_narrowoop = true;
+ }
+ }
+ }
+ }
+#endif
+}
+
//------------------------------make-------------------------------------------
const TypeOopPtr *TypeOopPtr::make(PTR ptr,
int offset) {
@@ -2593,9 +2665,13 @@
//-----------------------------cast_to_instance-------------------------------
const TypeOopPtr *TypeInstPtr::cast_to_instance(int instance_id) const {
if( instance_id == _instance_id) return this;
- bool exact = (instance_id == UNKNOWN_INSTANCE) ? _klass_is_exact : true;
-
- return make(ptr(), klass(), exact, const_oop(), _offset, instance_id);
+ bool exact = true;
+ PTR ptr_t = NotNull;
+ if (instance_id == UNKNOWN_INSTANCE) {
+ exact = _klass_is_exact;
+ ptr_t = _ptr;
+ }
+ return make(ptr_t, klass(), exact, const_oop(), _offset, instance_id);
}
//------------------------------xmeet_unloaded---------------------------------
@@ -3014,6 +3090,7 @@
// Convenience common pre-built types.
const TypeAryPtr *TypeAryPtr::RANGE;
const TypeAryPtr *TypeAryPtr::OOPS;
+const TypeAryPtr *TypeAryPtr::NARROWOOPS;
const TypeAryPtr *TypeAryPtr::BYTES;
const TypeAryPtr *TypeAryPtr::SHORTS;
const TypeAryPtr *TypeAryPtr::CHARS;
@@ -3063,8 +3140,13 @@
//-----------------------------cast_to_instance-------------------------------
const TypeOopPtr *TypeAryPtr::cast_to_instance(int instance_id) const {
if( instance_id == _instance_id) return this;
- bool exact = (instance_id == UNKNOWN_INSTANCE) ? _klass_is_exact : true;
- return make(ptr(), const_oop(), _ary, klass(), exact, _offset, instance_id);
+ bool exact = true;
+ PTR ptr_t = NotNull;
+ if (instance_id == UNKNOWN_INSTANCE) {
+ exact = _klass_is_exact;
+ ptr_t = _ptr;
+ }
+ return make(ptr_t, const_oop(), _ary, klass(), exact, _offset, instance_id);
}
//-----------------------------narrow_size_type-------------------------------
@@ -3547,7 +3629,7 @@
k_ary = ciTypeArrayKlass::make(el->basic_type());
}
- if( this != TypeAryPtr::OOPS )
+ if( this != TypeAryPtr::OOPS ) {
// The _klass field acts as a cache of the underlying
// ciKlass for this array type. In order to set the field,
// we need to cast away const-ness.
@@ -3562,6 +3644,11 @@
// a bit less efficient than caching, but calls to
// TypeAryPtr::OOPS->klass() are not common enough to matter.
((TypeAryPtr*)this)->_klass = k_ary;
+ if (UseCompressedOops && k_ary != NULL && k_ary->is_obj_array_klass() &&
+ _offset != 0 && _offset != arrayOopDesc::length_offset_in_bytes()) {
+ ((TypeAryPtr*)this)->_is_ptr_to_narrowoop = true;
+ }
+ }
return k_ary;
}
--- a/hotspot/src/share/vm/opto/type.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/opto/type.hpp Fri May 30 07:22:22 2008 -0700
@@ -191,9 +191,8 @@
virtual const Type *filter( const Type *kills ) const;
// Returns true if this pointer points at memory which contains a
- // compressed oop references. In 32-bit builds it's non-virtual
- // since we don't support compressed oops at all in the mode.
- LP64_ONLY(virtual) bool is_narrow() const { return false; }
+ // compressed oop references.
+ bool is_ptr_to_narrowoop() const;
// Convenience access
float getf() const;
@@ -213,8 +212,8 @@
const TypePtr *isa_ptr() const; // Returns NULL if not ptr type
const TypeRawPtr *isa_rawptr() const; // NOT Java oop
const TypeRawPtr *is_rawptr() const; // Asserts is rawptr
- const TypeNarrowOop *is_narrowoop() const; // Java-style GC'd pointer
- const TypeNarrowOop *isa_narrowoop() const; // Returns NULL if not oop ptr type
+ const TypeNarrowOop *is_narrowoop() const; // Java-style GC'd pointer
+ const TypeNarrowOop *isa_narrowoop() const; // Returns NULL if not oop ptr type
const TypeOopPtr *isa_oopptr() const; // Returns NULL if not oop ptr type
const TypeOopPtr *is_oopptr() const; // Java-style GC'd pointer
const TypeKlassPtr *isa_klassptr() const; // Returns NULL if not KlassPtr
@@ -643,7 +642,7 @@
// Some kind of oop (Java pointer), either klass or instance or array.
class TypeOopPtr : public TypePtr {
protected:
- TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id ) : TypePtr(t, ptr, offset), _const_oop(o), _klass(k), _klass_is_exact(xk), _instance_id(instance_id) { }
+ TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id );
public:
virtual bool eq( const Type *t ) const;
virtual int hash() const; // Type specific hashing
@@ -660,8 +659,9 @@
ciKlass* _klass; // Klass object
// Does the type exclude subclasses of the klass? (Inexact == polymorphic.)
bool _klass_is_exact;
+ bool _is_ptr_to_narrowoop;
- int _instance_id; // if not UNKNOWN_INSTANCE, indicates that this is a particular instance
+ int _instance_id; // if not UNKNOWN_INSTANCE, indicates that this is a particular instance
// of this type which is distinct. This is the the node index of the
// node creating this instance
@@ -696,6 +696,11 @@
ciObject* const_oop() const { return _const_oop; }
virtual ciKlass* klass() const { return _klass; }
bool klass_is_exact() const { return _klass_is_exact; }
+
+ // Returns true if this pointer points at memory which contains a
+ // compressed oop references.
+ bool is_ptr_to_narrowoop_nv() const { return _is_ptr_to_narrowoop; }
+
bool is_instance() const { return _instance_id != UNKNOWN_INSTANCE; }
uint instance_id() const { return _instance_id; }
bool is_instance_field() const { return _instance_id != UNKNOWN_INSTANCE && _offset >= 0; }
@@ -716,12 +721,6 @@
// returns the equivalent compressed version of this pointer type
virtual const TypeNarrowOop* make_narrowoop() const;
-#ifdef _LP64
- virtual bool is_narrow() const {
- return (UseCompressedOops && _offset != 0);
- }
-#endif
-
virtual const Type *xmeet( const Type *t ) const;
virtual const Type *xdual() const; // Compute dual right now.
@@ -843,15 +842,10 @@
virtual const Type *xmeet( const Type *t ) const;
virtual const Type *xdual() const; // Compute dual right now.
-#ifdef _LP64
- virtual bool is_narrow() const {
- return (UseCompressedOops && klass() != NULL && _offset != 0);
- }
-#endif
-
// Convenience common pre-built types.
static const TypeAryPtr *RANGE;
static const TypeAryPtr *OOPS;
+ static const TypeAryPtr *NARROWOOPS;
static const TypeAryPtr *BYTES;
static const TypeAryPtr *SHORTS;
static const TypeAryPtr *CHARS;
@@ -901,18 +895,6 @@
virtual const Type *xmeet( const Type *t ) const;
virtual const Type *xdual() const; // Compute dual right now.
-#ifdef _LP64
- // Perm objects don't use compressed references, except for static fields
- // which are currently compressed
- virtual bool is_narrow() const {
- if (UseCompressedOops && _offset != 0 && _klass->is_instance_klass()) {
- ciInstanceKlass* ik = _klass->as_instance_klass();
- return ik != NULL && ik->get_field_by_offset(_offset, true) != NULL;
- }
- return false;
- }
-#endif
-
// Convenience common pre-built types.
static const TypeKlassPtr* OBJECT; // Not-null object klass or below
static const TypeKlassPtr* OBJECT_OR_NULL; // Maybe-null version of same
@@ -921,7 +903,7 @@
#endif
};
-//------------------------------TypeNarrowOop----------------------------------------
+//------------------------------TypeNarrowOop----------------------------------
// A compressed reference to some kind of Oop. This type wraps around
// a preexisting TypeOopPtr and forwards most of it's operations to
// the underlying type. It's only real purpose is to track the
@@ -1013,6 +995,14 @@
};
//------------------------------accessors--------------------------------------
+inline bool Type::is_ptr_to_narrowoop() const {
+#ifdef _LP64
+ return (isa_oopptr() != NULL && is_oopptr()->is_ptr_to_narrowoop_nv());
+#else
+ return false;
+#endif
+}
+
inline float Type::getf() const {
assert( _base == FloatCon, "Not a FloatCon" );
return ((TypeF*)this)->_f;
--- a/hotspot/src/share/vm/runtime/arguments.cpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Fri May 30 07:22:22 2008 -0700
@@ -1312,6 +1312,9 @@
if (AggressiveOpts && FLAG_IS_DEFAULT(DoEscapeAnalysis)) {
FLAG_SET_DEFAULT(DoEscapeAnalysis, true);
}
+ if (AggressiveOpts && FLAG_IS_DEFAULT(SpecialArraysEquals)) {
+ FLAG_SET_DEFAULT(SpecialArraysEquals, true);
+ }
#endif
if (AggressiveOpts) {
--- a/hotspot/src/share/vm/runtime/globals.hpp Fri May 30 03:53:31 2008 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp Fri May 30 07:22:22 2008 -0700
@@ -291,6 +291,9 @@
"Use 32-bit object references in 64-bit VM. " \
"lp64_product means flag is always constant in 32 bit VM") \
\
+ lp64_product(bool, CheckCompressedOops, trueInDebug, \
+ "generate checks in encoding/decoding code") \
+ \
/* UseMembar is theoretically a temp flag used for memory barrier \
* removal testing. It was supposed to be removed before FCS but has \
* been re-added (see 6401008) */ \
@@ -457,6 +460,9 @@
develop(bool, SpecialStringIndexOf, true, \
"special version of string indexOf") \
\
+ product(bool, SpecialArraysEquals, true, \
+ "special version of Arrays.equals(char[],char[])") \
+ \
develop(bool, TraceCallFixup, false, \
"traces all call fixups") \
\
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6689060/Test.java Fri May 30 07:22:22 2008 -0700
@@ -0,0 +1,577 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ * @test
+ * @bug 6689060
+ * @summary Escape Analysis does not work with Compressed Oops
+ * @run main/othervm -Xbatch -XX:CompileCommand=exclude,Test.dummy -XX:+AggressiveOpts Test
+ */
+
+import java.lang.reflect.Array;
+
+class Point {
+ int x;
+ int y;
+ Point next;
+ int ax[];
+ int ay[];
+ Point pax[];
+ Point pay[];
+ public Point getNext() {
+ return next;
+ }
+}
+
+public class Test {
+
+ void dummy() {
+ // Empty method to verify correctness of DebugInfo.
+ // Use -XX:CompileCommand=exclude,Test.dummy
+ }
+
+ int ival(int i) {
+ return i*2;
+ }
+
+ int test80(int y, int l, int i) {
+ Point p = new Point();
+ p.ax = new int[2];
+ p.ay = new int[2];
+ int x = 3;
+ p.ax[0] = x;
+ p.ay[1] = 3 * x + y;
+ dummy();
+ return p.ax[0] * p.ay[1];
+ }
+
+ int test81(int y, int l, int i) {
+ Point p = new Point();
+ p.ax = new int[2];
+ p.ay = new int[2];
+ int x = 3;
+ p.ax[0] = x;
+ p.ay[1] = 3 * x + y;
+ dummy();
+ return p.ax[0] * p.ay[1];
+ }
+
+
+ int test44(int y) {
+ Point p1 = new Point();
+ p1.x = ival(3);
+ dummy();
+ p1.y = 3 * p1.x + y;
+ return p1.y;
+ }
+
+ int test43(int y) {
+ Point p1 = new Point();
+ if ( (y & 1) == 1 ) {
+ p1.x = ival(3);
+ } else {
+ p1.x = ival(5);
+ }
+ dummy();
+ p1.y = 3 * p1.x + y;
+ return p1.y;
+ }
+
+ int test42(int y) {
+ Point p1 = new Point();
+ p1.x = 3;
+ for (int i = 0; i < y; i++) {
+ if ( (i & 1) == 1 ) {
+ p1.x += 4;
+ }
+ }
+ p1.y = 3 * y + p1.x;
+ return p1.y;
+ }
+
+ int test40(int y) {
+ Point p1 = new Point();
+ if ( (y & 1) == 1 ) {
+ p1.x = 3;
+ } else {
+ p1.x = 5;
+ }
+ p1.y = 3 * p1.x + y;
+ return p1.y;
+ }
+
+ int test41(int y) {
+ Point p1 = new Point();
+ if ( (y & 1) == 1 ) {
+ p1.x += 4;
+ } else {
+ p1.x += 5;
+ }
+ p1.y = 3 * p1.x + y;
+ return p1.y;
+ }
+
+ Point test00(int y) {
+ int x = 3;
+ Point p = new Point();
+ p.x = x;
+ p.y = 3 * x + y;
+ return p;
+ }
+
+ Point test01(int y) {
+ int x = 3;
+ Point p = new Point();
+ p.x = x;
+ p.y = 3 * x + y;
+ dummy();
+ return p;
+ }
+
+ Point test02(int y) {
+ int x = 3;
+ Point p1 = null;
+ for (int i = 0; i < y; i++) {
+ Point p2 = new Point();
+ p2.x = x;
+ p2.y = 3 * y + x;
+ p2.next = p1;
+ p1 = p2;
+ }
+ return p1;
+ }
+
+ Point test03(int y) {
+ int x = 3;
+ Point p1 = null;
+ for (int i = 0; i < y; i++) {
+ Point p2 = new Point();
+ p2.x = x;
+ p2.y = 3 * y + x;
+ p2.next = p1;
+ p1 = p2;
+ }
+ dummy();
+ return p1;
+ }
+
+ Point test04(int y) {
+ int x = 3;
+ Point p1 = null;
+ for (int i = 0; i < y; i++) {
+ Point p2 = new Point();
+ p2.x = x;
+ p2.y = 3 * y + x;
+ p2.next = p1;
+ dummy();
+ p1 = p2;
+ }
+ return p1;
+ }
+
+ int test05(int y) {
+ int x = 3;
+ Point p1 = new Point();
+ for (int i = 0; i < y; i++) {
+ Point p2 = new Point();
+ p2.x = x;
+ p2.y = 3 * y + x;
+ p1.next = p2;
+ p1 = p2;
+ }
+ return p1.y;
+ }
+
+ int test0(int y) {
+ int x = 3;
+ Point p = new Point();
+ p.x = x;
+ p.y = 3 * x + y;
+ dummy();
+ return p.x * p.y;
+ }
+
+ int test1(int y) {
+ Point p = new Point();
+ if ( (y & 1) == 1 ) {
+ p = new Point(); // Kill previous
+ }
+ int x = 3;
+ p.x = x;
+ p.y = 3 * x + y;
+ dummy();
+ return p.x * p.y;
+ }
+
+ int test2(int y) {
+ Point p1 = new Point();
+ Point p2 = new Point();
+ p1.x = 3;
+ p2.x = 4;
+ p1.y = 3 * p2.x + y;
+ p2.y = 3 * p1.x + y;
+ dummy();
+ return p1.y * p2.y;
+ }
+
+ int test3(int y, Point p1) {
+ Point p2 = new Point();
+ p1.x = 3;
+ p2.x = 4;
+ p1.y = 3 * p2.x + y;
+ p2.y = 3 * p1.x + y;
+ dummy();
+ return p1.y * p2.y;
+ }
+
+ int test4(int y) {
+ Point p1 = new Point();
+ Point p2 = new Point();
+ if ( (y & 1) == 1 ) {
+ p1.x = 3;
+ p2.x = 4;
+ } else {
+ p1.x = 5;
+ p2.x = 6;
+ }
+ p1.y = 3 * p2.x + y;
+ p2.y = 3 * p1.x + y;
+ dummy();
+ return p1.y * p2.y;
+ }
+
+ int test5(int y, Point p1) {
+ Point p2 = new Point();
+ if ( (y & 1) == 1 ) {
+ p1.x = 3;
+ p2.x = 4;
+ } else {
+ p1.x = 5;
+ p2.x = 6;
+ }
+ p1.y = 3 * p2.x + y;
+ p2.y = 3 * p1.x + y;
+ dummy();
+ return p1.y * p2.y;
+ }
+
+ int test6(int y) {
+ Point p1 = new Point();
+ Point p2 = new Point();
+ p1.next = p2;
+ if ( (y & 1) == 1 ) {
+ p1.x = 3;
+ p1.getNext().x = 4;
+ } else {
+ p1.x = 5;
+ p1.getNext().x = 6;
+ }
+ p1.y = 3 * p2.x + y;
+ p2.y = 3 * p1.x + y;
+ dummy();
+ return p1.y * p2.y;
+ }
+
+ int test7(int y, Point p1) {
+ Point p2 = new Point();
+ p1.next = p2;
+ if ( (y & 1) == 1 ) {
+ p1.x = 3;
+ p1.getNext().x = 4;
+ } else {
+ p1.x = 5;
+ p1.getNext().x = 6;
+ }
+ p1.y = 3 * p2.x + y;
+ p2.y = 3 * p1.x + y;
+ dummy();
+ return p1.y * p2.y;
+ }
+
+ int test8(int y, int l, int i) {
+ Point p = new Point();
+ p.ax = new int[l];
+ p.ay = new int[l];
+ int x = 3;
+ p.ax[i] = x;
+ p.ay[i] = 3 * x + y;
+ dummy();
+ return p.ax[i] * p.ay[i];
+ }
+
+ int test9(int y, int l, int i) {
+ Point p = new Point();
+ p.pax = new Point[l];
+ p.pay = new Point[l];
+ p.pax[i] = new Point();
+ p.pay[i] = new Point();
+ p.pax[i].x = 3;
+ p.pay[i].x = 4;
+ p.pax[i].y = 3 * p.pay[i].x + y;
+ p.pay[i].y = 3 * p.pax[i].x + y;
+ dummy();
+ return p.pax[i].y * p.pay[i].y;
+ }
+
+ int test10(int y, int l, int i, Class cls) {
+ Point p = new Point();
+ try {
+ p.pax = (Point[])Array.newInstance(cls, l);
+ p.pax[i] = (Point)cls.newInstance();
+ }
+ catch(java.lang.InstantiationException ex) {
+ return 0;
+ }
+ catch(java.lang.IllegalAccessException ex) {
+ return 0;
+ }
+ p.pax[i].x = 3;
+ p.pax[i].y = 3 * p.pax[i].x + y;
+ dummy();
+ return p.pax[i].x * p.pax[i].y;
+ }
+
+ int test11(int y) {
+ Point p1 = new Point();
+ Point p2 = new Point();
+ p1.next = p2;
+ if ( (y & 1) == 1 ) {
+ p1.x = 3;
+ p1.next.x = 4;
+ } else {
+ p1.x = 5;
+ p1.next.x = 6;
+ }
+ p1.y = 3 * p1.next.x + y;
+ p1.next.y = 3 * p1.x + y;
+ dummy();
+ return p1.y * p1.next.y;
+ }
+
+ int test12(int y) {
+ Point p1 = new Point();
+ p1.next = p1;
+ if ( (y & 1) == 1 ) {
+ p1.x = 3;
+ p1.next.x = 4;
+ } else {
+ p1.x = 5;
+ p1.next.x = 6;
+ }
+ p1.y = 3 * p1.next.x + y;
+ p1.next.y = 3 * p1.x + y;
+ dummy();
+ return p1.y * p1.next.y;
+ }
+
+
+ public static void main(String args[]) {
+ Test tsr = new Test();
+ Point p = new Point();
+ Point ptmp = p;
+ Class cls = Point.class;
+ int y = 0;
+ for (int i=0; i<10000; i++) {
+ ptmp.next = tsr.test00(1);
+ ptmp.next = tsr.test01(1);
+ ptmp.next = tsr.test02(1);
+ ptmp.next = tsr.test03(1);
+ ptmp.next = tsr.test04(1);
+
+ y = tsr.test05(1);
+
+ y = tsr.test80(y, 1, 0);
+ y = tsr.test81(y, 1, 0);
+
+ y = tsr.test44(y);
+ y = tsr.test43(y);
+ y = tsr.test42(y);
+ y = tsr.test40(y);
+ y = tsr.test41(y);
+
+ y = tsr.test0(y);
+ y = tsr.test1(y);
+ y = tsr.test2(y);
+ y = tsr.test3(y, p);
+ y = tsr.test4(y);
+ y = tsr.test5(y, p);
+ y = tsr.test6(y);
+ y = tsr.test7(y, p);
+ y = tsr.test8(y, 1, 0);
+ y = tsr.test9(y, 1, 0);
+ y = tsr.test10(y, 1, 0, cls);
+ y = tsr.test11(y);
+ y = tsr.test12(y);
+ }
+ for (int i=0; i<10000; i++) {
+ ptmp.next = tsr.test00(1);
+ ptmp.next = tsr.test01(1);
+ ptmp.next = tsr.test02(1);
+ ptmp.next = tsr.test03(1);
+ ptmp.next = tsr.test04(1);
+
+ y = tsr.test05(1);
+
+ y = tsr.test80(y, 1, 0);
+ y = tsr.test81(y, 1, 0);
+
+ y = tsr.test44(y);
+ y = tsr.test43(y);
+ y = tsr.test42(y);
+ y = tsr.test40(y);
+ y = tsr.test41(y);
+
+ y = tsr.test0(y);
+ y = tsr.test1(y);
+ y = tsr.test2(y);
+ y = tsr.test3(y, p);
+ y = tsr.test4(y);
+ y = tsr.test5(y, p);
+ y = tsr.test6(y);
+ y = tsr.test7(y, p);
+ y = tsr.test8(y, 1, 0);
+ y = tsr.test9(y, 1, 0);
+ y = tsr.test10(y, 1, 0, cls);
+ y = tsr.test11(y);
+ y = tsr.test12(y);
+ }
+ for (int i=0; i<10000; i++) {
+ ptmp.next = tsr.test00(1);
+ ptmp.next = tsr.test01(1);
+ ptmp.next = tsr.test02(1);
+ ptmp.next = tsr.test03(1);
+ ptmp.next = tsr.test04(1);
+
+ y = tsr.test05(1);
+
+ y = tsr.test80(y, 1, 0);
+ y = tsr.test81(y, 1, 0);
+
+ y = tsr.test44(y);
+ y = tsr.test43(y);
+ y = tsr.test42(y);
+ y = tsr.test40(y);
+ y = tsr.test41(y);
+
+ y = tsr.test0(y);
+ y = tsr.test1(y);
+ y = tsr.test2(y);
+ y = tsr.test3(y, p);
+ y = tsr.test4(y);
+ y = tsr.test5(y, p);
+ y = tsr.test6(y);
+ y = tsr.test7(y, p);
+ y = tsr.test8(y, 1, 0);
+ y = tsr.test9(y, 1, 0);
+ y = tsr.test10(y, 1, 0, cls);
+ y = tsr.test11(y);
+ y = tsr.test12(y);
+ }
+
+ int z = 0;
+ y = tsr.test80(0, 1, 0);
+ z += y;
+ System.out.println("After 'test80' y=" + y);
+ y = tsr.test81(0, 1, 0);
+ z += y;
+ System.out.println("After 'test81' y=" + y);
+
+ y = tsr.test44(0);
+ z += y;
+ System.out.println("After 'test44' y=" + y);
+ y = tsr.test43(0);
+ z += y;
+ System.out.println("After 'test43' y=" + y);
+ y = tsr.test42(0);
+ z += y;
+ System.out.println("After 'test42' y=" + y);
+ y = tsr.test40(0);
+ z += y;
+ System.out.println("After 'test40' y=" + y);
+ y = tsr.test41(0);
+ z += y;
+ System.out.println("After 'test41' y=" + y);
+
+ ptmp.next = tsr.test00(1);
+ z += y;
+ System.out.println("After 'test00' p.y=" + ptmp.next.y);
+ ptmp.next = tsr.test01(1);
+ z += y;
+ System.out.println("After 'test01' p.y=" + ptmp.next.y);
+ ptmp.next = tsr.test02(1);
+ z += y;
+ System.out.println("After 'test02' p.y=" + ptmp.next.y);
+ ptmp.next = tsr.test03(1);
+ z += y;
+ System.out.println("After 'test03' p.y=" + ptmp.next.y);
+ ptmp.next = tsr.test04(1);
+ z += y;
+ System.out.println("After 'test04' p.y=" + ptmp.next.y);
+
+ y = tsr.test05(1);
+ z += y;
+ System.out.println("After 'test05' y=" + y);
+
+ y = tsr.test0(0);
+ z += y;
+ System.out.println("After 'test0' y=" + y);
+ y = tsr.test1(0);
+ z += y;
+ System.out.println("After 'test1' y=" + y);
+ y = tsr.test2(0);
+ z += y;
+ System.out.println("After 'test2' y=" + y);
+ y = tsr.test3(0, new Point());
+ z += y;
+ System.out.println("After 'test3' y=" + y);
+ y = tsr.test4(0);
+ z += y;
+ System.out.println("After 'test4' y=" + y);
+ y = tsr.test5(0, new Point());
+ z += y;
+ System.out.println("After 'test5' y=" + y);
+ y = tsr.test6(0);
+ z += y;
+ System.out.println("After 'test6' y=" + y);
+ y = tsr.test7(0, new Point());
+ z += y;
+ System.out.println("After 'test7' y=" + y);
+ y = tsr.test8(0, 1, 0);
+ z += y;
+ System.out.println("After 'test8' y=" + y);
+ y = tsr.test9(0, 1, 0);
+ z += y;
+ System.out.println("After 'test9' y=" + y);
+ y = tsr.test10(0, 1, 0, cls);
+ z += y;
+ System.out.println("After 'test10' y=" + y);
+ y = tsr.test11(0);
+ z += y;
+ System.out.println("After 'test11' y=" + y);
+ y = tsr.test12(0);
+ z += y;
+ System.out.println("After 'test12' y=" + y);
+ System.out.println("Sum of y =" + z);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6695810/Test.java Fri May 30 07:22:22 2008 -0700
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ * @test
+ * @bug 6695810
+ * @summary null oop passed to encode_heap_oop_not_null
+ * @run main/othervm -Xbatch Test
+ */
+
+public class Test {
+ Test _t;
+
+ static void test(Test t1, Test t2) {
+ if (t2 != null)
+ t1._t = t2;
+
+ if (t2 != null)
+ t1._t = t2;
+ }
+
+ public static void main(String[] args) {
+ Test t = new Test();
+ for (int i = 0; i < 50; i++) {
+ for (int j = 0; j < 100; j++) {
+ test(t, t);
+ }
+ test(t, null);
+ }
+ for (int i = 0; i < 10000; i++) {
+ test(t, t);
+ }
+ test(t, null);
+ }
+}