aboutsummaryrefslogtreecommitdiff
path: root/src/cpu/sparc
diff options
context:
space:
mode:
authorkvn <none@none>2009-03-19 09:13:24 -0700
committerkvn <none@none>2009-03-19 09:13:24 -0700
commitf839691b0d3d6ac53e4be22f2c7a04f5af6479e3 (patch)
treec25fdc8c0124c49c5705c60b5a538472340920f0 /src/cpu/sparc
parenteab35a70c0518262702a7971676dbc7057bc62c8 (diff)
parentab5da72d4742289e98dcd8b5ecb1c68b1f43bd3e (diff)
downloadjdk8u_hotspot-f839691b0d3d6ac53e4be22f2c7a04f5af6479e3.tar.gz
Merge
Diffstat (limited to 'src/cpu/sparc')
-rw-r--r--src/cpu/sparc/vm/assembler_sparc.cpp307
-rw-r--r--src/cpu/sparc/vm/assembler_sparc.hpp40
-rw-r--r--src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp144
-rw-r--r--src/cpu/sparc/vm/c1_Runtime1_sparc.cpp27
-rw-r--r--src/cpu/sparc/vm/interp_masm_sparc.cpp61
-rw-r--r--src/cpu/sparc/vm/sparc.ad43
-rw-r--r--src/cpu/sparc/vm/stubGenerator_sparc.cpp142
-rw-r--r--src/cpu/sparc/vm/vm_version_sparc.cpp19
-rw-r--r--src/cpu/sparc/vm/vm_version_sparc.hpp58
-rw-r--r--src/cpu/sparc/vm/vtableStubs_sparc.cpp10
10 files changed, 513 insertions, 338 deletions
diff --git a/src/cpu/sparc/vm/assembler_sparc.cpp b/src/cpu/sparc/vm/assembler_sparc.cpp
index d9a7cf076..4a61d2f2c 100644
--- a/src/cpu/sparc/vm/assembler_sparc.cpp
+++ b/src/cpu/sparc/vm/assembler_sparc.cpp
@@ -2767,6 +2767,268 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
}
+void MacroAssembler::check_klass_subtype(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Register temp2_reg,
+ Label& L_success) {
+ Label L_failure, L_pop_to_failure;
+ check_klass_subtype_fast_path(sub_klass, super_klass,
+ temp_reg, temp2_reg,
+ &L_success, &L_failure, NULL);
+ Register sub_2 = sub_klass;
+ Register sup_2 = super_klass;
+ if (!sub_2->is_global()) sub_2 = L0;
+ if (!sup_2->is_global()) sup_2 = L1;
+
+ save_frame_and_mov(0, sub_klass, sub_2, super_klass, sup_2);
+ check_klass_subtype_slow_path(sub_2, sup_2,
+ L2, L3, L4, L5,
+ NULL, &L_pop_to_failure);
+
+ // on success:
+ restore();
+ ba(false, L_success);
+ delayed()->nop();
+
+ // on failure:
+ bind(L_pop_to_failure);
+ restore();
+ bind(L_failure);
+}
+
+
+void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Register temp2_reg,
+ Label* L_success,
+ Label* L_failure,
+ Label* L_slow_path,
+ RegisterConstant super_check_offset,
+ Register instanceof_hack) {
+ int sc_offset = (klassOopDesc::header_size() * HeapWordSize +
+ Klass::secondary_super_cache_offset_in_bytes());
+ int sco_offset = (klassOopDesc::header_size() * HeapWordSize +
+ Klass::super_check_offset_offset_in_bytes());
+
+ bool must_load_sco = (super_check_offset.constant_or_zero() == -1);
+ bool need_slow_path = (must_load_sco ||
+ super_check_offset.constant_or_zero() == sco_offset);
+
+ assert_different_registers(sub_klass, super_klass, temp_reg);
+ if (super_check_offset.is_register()) {
+ assert_different_registers(sub_klass, super_klass,
+ super_check_offset.as_register());
+ } else if (must_load_sco) {
+ assert(temp2_reg != noreg, "supply either a temp or a register offset");
+ }
+
+ Label L_fallthrough;
+ int label_nulls = 0;
+ if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
+ if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
+ if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; }
+ assert(label_nulls <= 1 || instanceof_hack != noreg ||
+ (L_slow_path == &L_fallthrough && label_nulls <= 2 && !need_slow_path),
+ "at most one NULL in the batch, usually");
+
+ // Support for the instanceof hack, which uses delay slots to
+ // set a destination register to zero or one.
+ bool do_bool_sets = (instanceof_hack != noreg);
+#define BOOL_SET(bool_value) \
+ if (do_bool_sets && bool_value >= 0) \
+ set(bool_value, instanceof_hack)
+#define DELAYED_BOOL_SET(bool_value) \
+ if (do_bool_sets && bool_value >= 0) \
+ delayed()->set(bool_value, instanceof_hack); \
+ else delayed()->nop()
+ // Hacked ba(), which may only be used just before L_fallthrough.
+#define FINAL_JUMP(label, bool_value) \
+ if (&(label) == &L_fallthrough) { \
+ BOOL_SET(bool_value); \
+ } else { \
+ ba((do_bool_sets && bool_value >= 0), label); \
+ DELAYED_BOOL_SET(bool_value); \
+ }
+
+ // If the pointers are equal, we are done (e.g., String[] elements).
+ // This self-check enables sharing of secondary supertype arrays among
+ // non-primary types such as array-of-interface. Otherwise, each such
+ // type would need its own customized SSA.
+ // We move this check to the front of the fast path because many
+ // type checks are in fact trivially successful in this manner,
+ // so we get a nicely predicted branch right at the start of the check.
+ cmp(super_klass, sub_klass);
+ brx(Assembler::equal, do_bool_sets, Assembler::pn, *L_success);
+ DELAYED_BOOL_SET(1);
+
+ // Check the supertype display:
+ if (must_load_sco) {
+ // The super check offset is always positive...
+ lduw(super_klass, sco_offset, temp2_reg);
+ super_check_offset = RegisterConstant(temp2_reg);
+ }
+ ld_ptr(sub_klass, super_check_offset, temp_reg);
+ cmp(super_klass, temp_reg);
+
+ // This check has worked decisively for primary supers.
+ // Secondary supers are sought in the super_cache ('super_cache_addr').
+ // (Secondary supers are interfaces and very deeply nested subtypes.)
+ // This works in the same check above because of a tricky aliasing
+ // between the super_cache and the primary super display elements.
+ // (The 'super_check_addr' can address either, as the case requires.)
+ // Note that the cache is updated below if it does not help us find
+ // what we need immediately.
+ // So if it was a primary super, we can just fail immediately.
+ // Otherwise, it's the slow path for us (no success at this point).
+
+ if (super_check_offset.is_register()) {
+ brx(Assembler::equal, do_bool_sets, Assembler::pn, *L_success);
+ delayed(); if (do_bool_sets) BOOL_SET(1);
+ // if !do_bool_sets, sneak the next cmp into the delay slot:
+ cmp(super_check_offset.as_register(), sc_offset);
+
+ if (L_failure == &L_fallthrough) {
+ brx(Assembler::equal, do_bool_sets, Assembler::pt, *L_slow_path);
+ delayed()->nop();
+ BOOL_SET(0); // fallthrough on failure
+ } else {
+ brx(Assembler::notEqual, do_bool_sets, Assembler::pn, *L_failure);
+ DELAYED_BOOL_SET(0);
+ FINAL_JUMP(*L_slow_path, -1); // -1 => vanilla delay slot
+ }
+ } else if (super_check_offset.as_constant() == sc_offset) {
+ // Need a slow path; fast failure is impossible.
+ if (L_slow_path == &L_fallthrough) {
+ brx(Assembler::equal, do_bool_sets, Assembler::pt, *L_success);
+ DELAYED_BOOL_SET(1);
+ } else {
+ brx(Assembler::notEqual, false, Assembler::pn, *L_slow_path);
+ delayed()->nop();
+ FINAL_JUMP(*L_success, 1);
+ }
+ } else {
+ // No slow path; it's a fast decision.
+ if (L_failure == &L_fallthrough) {
+ brx(Assembler::equal, do_bool_sets, Assembler::pt, *L_success);
+ DELAYED_BOOL_SET(1);
+ BOOL_SET(0);
+ } else {
+ brx(Assembler::notEqual, do_bool_sets, Assembler::pn, *L_failure);
+ DELAYED_BOOL_SET(0);
+ FINAL_JUMP(*L_success, 1);
+ }
+ }
+
+ bind(L_fallthrough);
+
+#undef final_jump
+#undef bool_set
+#undef DELAYED_BOOL_SET
+#undef final_jump
+}
+
+
+void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
+ Register super_klass,
+ Register count_temp,
+ Register scan_temp,
+ Register scratch_reg,
+ Register coop_reg,
+ Label* L_success,
+ Label* L_failure) {
+ assert_different_registers(sub_klass, super_klass,
+ count_temp, scan_temp, scratch_reg, coop_reg);
+
+ Label L_fallthrough, L_loop;
+ int label_nulls = 0;
+ if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
+ if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
+ assert(label_nulls <= 1, "at most one NULL in the batch");
+
+ // a couple of useful fields in sub_klass:
+ int ss_offset = (klassOopDesc::header_size() * HeapWordSize +
+ Klass::secondary_supers_offset_in_bytes());
+ int sc_offset = (klassOopDesc::header_size() * HeapWordSize +
+ Klass::secondary_super_cache_offset_in_bytes());
+
+ // Do a linear scan of the secondary super-klass chain.
+ // This code is rarely used, so simplicity is a virtue here.
+
+#ifndef PRODUCT
+ int* pst_counter = &SharedRuntime::_partial_subtype_ctr;
+ inc_counter((address) pst_counter, count_temp, scan_temp);
+#endif
+
+ // We will consult the secondary-super array.
+ ld_ptr(sub_klass, ss_offset, scan_temp);
+
+ // Compress superclass if necessary.
+ Register search_key = super_klass;
+ bool decode_super_klass = false;
+ if (UseCompressedOops) {
+ if (coop_reg != noreg) {
+ encode_heap_oop_not_null(super_klass, coop_reg);
+ search_key = coop_reg;
+ } else {
+ encode_heap_oop_not_null(super_klass);
+ decode_super_klass = true; // scarce temps!
+ }
+ // The superclass is never null; it would be a basic system error if a null
+ // pointer were to sneak in here. Note that we have already loaded the
+ // Klass::super_check_offset from the super_klass in the fast path,
+ // so if there is a null in that register, we are already in the afterlife.
+ }
+
+ // Load the array length. (Positive movl does right thing on LP64.)
+ lduw(scan_temp, arrayOopDesc::length_offset_in_bytes(), count_temp);
+
+ // Check for empty secondary super list
+ tst(count_temp);
+
+ // Top of search loop
+ bind(L_loop);
+ br(Assembler::equal, false, Assembler::pn, *L_failure);
+ delayed()->add(scan_temp, heapOopSize, scan_temp);
+ assert(heapOopSize != 0, "heapOopSize should be initialized");
+
+ // Skip the array header in all array accesses.
+ int elem_offset = arrayOopDesc::base_offset_in_bytes(T_OBJECT);
+ elem_offset -= heapOopSize; // the scan pointer was pre-incremented also
+
+ // Load next super to check
+ if (UseCompressedOops) {
+ // Don't use load_heap_oop; we don't want to decode the element.
+ lduw( scan_temp, elem_offset, scratch_reg );
+ } else {
+ ld_ptr( scan_temp, elem_offset, scratch_reg );
+ }
+
+ // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list
+ cmp(scratch_reg, search_key);
+
+ // A miss means we are NOT a subtype and need to keep looping
+ brx(Assembler::notEqual, false, Assembler::pn, L_loop);
+ delayed()->deccc(count_temp); // decrement trip counter in delay slot
+
+ // Falling out the bottom means we found a hit; we ARE a subtype
+ if (decode_super_klass) decode_heap_oop(super_klass);
+
+ // Success. Cache the super we found and proceed in triumph.
+ st_ptr(super_klass, sub_klass, sc_offset);
+
+ if (L_success != &L_fallthrough) {
+ ba(false, *L_success);
+ delayed()->nop();
+ }
+
+ bind(L_fallthrough);
+}
+
+
+
+
void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg,
Register temp_reg,
Label& done, Label* slow_case,
@@ -4316,7 +4578,13 @@ void MacroAssembler::store_heap_oop(Register d, const Address& a, int offset) {
void MacroAssembler::encode_heap_oop(Register src, Register dst) {
assert (UseCompressedOops, "must be compressed");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
verify_oop(src);
+ if (Universe::narrow_oop_base() == NULL) {
+ srlx(src, LogMinObjAlignmentInBytes, dst);
+ return;
+ }
Label done;
if (src == dst) {
// optimize for frequent case src == dst
@@ -4338,26 +4606,39 @@ void MacroAssembler::encode_heap_oop(Register src, Register dst) {
void MacroAssembler::encode_heap_oop_not_null(Register r) {
assert (UseCompressedOops, "must be compressed");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
verify_oop(r);
- sub(r, G6_heapbase, r);
+ if (Universe::narrow_oop_base() != NULL)
+ sub(r, G6_heapbase, r);
srlx(r, LogMinObjAlignmentInBytes, r);
}
void MacroAssembler::encode_heap_oop_not_null(Register src, Register dst) {
assert (UseCompressedOops, "must be compressed");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
verify_oop(src);
- sub(src, G6_heapbase, dst);
- srlx(dst, LogMinObjAlignmentInBytes, dst);
+ if (Universe::narrow_oop_base() == NULL) {
+ srlx(src, LogMinObjAlignmentInBytes, dst);
+ } else {
+ sub(src, G6_heapbase, dst);
+ srlx(dst, LogMinObjAlignmentInBytes, dst);
+ }
}
// Same algorithm as oops.inline.hpp decode_heap_oop.
void MacroAssembler::decode_heap_oop(Register src, Register dst) {
assert (UseCompressedOops, "must be compressed");
- Label done;
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
sllx(src, LogMinObjAlignmentInBytes, dst);
- bpr(rc_nz, true, Assembler::pt, dst, done);
- delayed() -> add(dst, G6_heapbase, dst); // annuled if not taken
- bind(done);
+ if (Universe::narrow_oop_base() != NULL) {
+ Label done;
+ bpr(rc_nz, true, Assembler::pt, dst, done);
+ delayed() -> add(dst, G6_heapbase, dst); // annuled if not taken
+ bind(done);
+ }
verify_oop(dst);
}
@@ -4366,8 +4647,11 @@ void MacroAssembler::decode_heap_oop_not_null(Register r) {
// pd_code_size_limit.
// Also do not verify_oop as this is called by verify_oop.
assert (UseCompressedOops, "must be compressed");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
sllx(r, LogMinObjAlignmentInBytes, r);
- add(r, G6_heapbase, r);
+ if (Universe::narrow_oop_base() != NULL)
+ add(r, G6_heapbase, r);
}
void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) {
@@ -4375,14 +4659,17 @@ void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) {
// pd_code_size_limit.
// Also do not verify_oop as this is called by verify_oop.
assert (UseCompressedOops, "must be compressed");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
sllx(src, LogMinObjAlignmentInBytes, dst);
- add(dst, G6_heapbase, dst);
+ if (Universe::narrow_oop_base() != NULL)
+ add(dst, G6_heapbase, dst);
}
void MacroAssembler::reinit_heapbase() {
if (UseCompressedOops) {
// call indirectly to solve generation ordering problem
- Address base(G6_heapbase, (address)Universe::heap_base_addr());
+ Address base(G6_heapbase, (address)Universe::narrow_oop_base_addr());
load_ptr_contents(base, G6_heapbase);
}
}
diff --git a/src/cpu/sparc/vm/assembler_sparc.hpp b/src/cpu/sparc/vm/assembler_sparc.hpp
index 8f1de780c..fc05cef68 100644
--- a/src/cpu/sparc/vm/assembler_sparc.hpp
+++ b/src/cpu/sparc/vm/assembler_sparc.hpp
@@ -2327,6 +2327,46 @@ class MacroAssembler: public Assembler {
Register temp_reg, Register temp2_reg,
Label& no_such_interface);
+ // Test sub_klass against super_klass, with fast and slow paths.
+
+ // The fast path produces a tri-state answer: yes / no / maybe-slow.
+ // One of the three labels can be NULL, meaning take the fall-through.
+ // If super_check_offset is -1, the value is loaded up from super_klass.
+ // No registers are killed, except temp_reg and temp2_reg.
+ // If super_check_offset is not -1, temp2_reg is not used and can be noreg.
+ void check_klass_subtype_fast_path(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Register temp2_reg,
+ Label* L_success,
+ Label* L_failure,
+ Label* L_slow_path,
+ RegisterConstant super_check_offset = RegisterConstant(-1),
+ Register instanceof_hack = noreg);
+
+ // The rest of the type check; must be wired to a corresponding fast path.
+ // It does not repeat the fast path logic, so don't use it standalone.
+ // The temp_reg can be noreg, if no temps are available.
+ // It can also be sub_klass or super_klass, meaning it's OK to kill that one.
+ // Updates the sub's secondary super cache as necessary.
+ void check_klass_subtype_slow_path(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Register temp2_reg,
+ Register temp3_reg,
+ Register temp4_reg,
+ Label* L_success,
+ Label* L_failure);
+
+ // Simplified, combined version, good for typical uses.
+ // Falls through on failure.
+ void check_klass_subtype(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Register temp2_reg,
+ Label& L_success);
+
+
// Stack overflow checking
// Note: this clobbers G3_scratch
diff --git a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
index dabea15a0..389acd2ee 100644
--- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
+++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
@@ -2393,23 +2393,11 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
// get instance klass
load(k_RInfo, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc), k_RInfo, T_OBJECT, NULL);
- // get super_check_offset
- load(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), Rtmp1, T_INT, NULL);
- // See if we get an immediate positive hit
- __ ld_ptr(klass_RInfo, Rtmp1, FrameMap::O7_oop_opr->as_register());
- __ cmp(k_RInfo, O7);
- __ br(Assembler::equal, false, Assembler::pn, done);
- __ delayed()->nop();
- // check for immediate negative hit
- __ cmp(Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes());
- __ br(Assembler::notEqual, false, Assembler::pn, *stub->entry());
- __ delayed()->nop();
- // check for self
- __ cmp(klass_RInfo, k_RInfo);
- __ br(Assembler::equal, false, Assembler::pn, done);
- __ delayed()->nop();
+ // perform the fast part of the checking logic
+ __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, &done, stub->entry(), NULL);
- // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup");
+ // call out-of-line instance of __ check_klass_subtype_slow_path(...):
+ assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup");
__ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
__ delayed()->nop();
__ cmp(G3, 0);
@@ -2493,58 +2481,30 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
__ delayed()->nop();
__ bind(done);
} else {
+ bool need_slow_path = true;
if (k->is_loaded()) {
- load(klass_RInfo, k->super_check_offset(), Rtmp1, T_OBJECT, NULL);
-
- if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) {
- // See if we get an immediate positive hit
- __ cmp(Rtmp1, k_RInfo );
- __ br(Assembler::notEqual, false, Assembler::pn, *stub->entry());
- __ delayed()->nop();
- } else {
- // See if we get an immediate positive hit
- assert_different_registers(Rtmp1, k_RInfo, klass_RInfo);
- __ cmp(Rtmp1, k_RInfo );
- __ br(Assembler::equal, false, Assembler::pn, done);
- // check for self
- __ delayed()->cmp(klass_RInfo, k_RInfo);
- __ br(Assembler::equal, false, Assembler::pn, done);
- __ delayed()->nop();
-
- // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup");
- __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
- __ delayed()->nop();
- __ cmp(G3, 0);
- __ br(Assembler::equal, false, Assembler::pn, *stub->entry());
- __ delayed()->nop();
- }
- __ bind(done);
+ if (k->super_check_offset() != sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes())
+ need_slow_path = false;
+ // perform the fast part of the checking logic
+ __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, noreg,
+ (need_slow_path ? &done : NULL),
+ stub->entry(), NULL,
+ RegisterConstant(k->super_check_offset()));
} else {
- assert_different_registers(Rtmp1, klass_RInfo, k_RInfo);
-
- load(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), Rtmp1, T_INT, NULL);
- // See if we get an immediate positive hit
- load(klass_RInfo, Rtmp1, FrameMap::O7_oop_opr, T_OBJECT);
- __ cmp(k_RInfo, O7);
- __ br(Assembler::equal, false, Assembler::pn, done);
- __ delayed()->nop();
- // check for immediate negative hit
- __ cmp(Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes());
- __ br(Assembler::notEqual, false, Assembler::pn, *stub->entry());
- // check for self
- __ delayed()->cmp(klass_RInfo, k_RInfo);
- __ br(Assembler::equal, false, Assembler::pn, done);
- __ delayed()->nop();
-
- // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup");
+ // perform the fast part of the checking logic
+ __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7,
+ &done, stub->entry(), NULL);
+ }
+ if (need_slow_path) {
+ // call out-of-line instance of __ check_klass_subtype_slow_path(...):
+ assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup");
__ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
__ delayed()->nop();
__ cmp(G3, 0);
__ br(Assembler::equal, false, Assembler::pn, *stub->entry());
__ delayed()->nop();
- __ bind(done);
}
-
+ __ bind(done);
}
__ mov(obj, dst);
} else if (code == lir_instanceof) {
@@ -2582,58 +2542,32 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
__ set(0, dst);
__ bind(done);
} else {
+ bool need_slow_path = true;
if (k->is_loaded()) {
- assert_different_registers(Rtmp1, klass_RInfo, k_RInfo);
- load(klass_RInfo, k->super_check_offset(), Rtmp1, T_OBJECT, NULL);
-
- if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) {
- // See if we get an immediate positive hit
- __ cmp(Rtmp1, k_RInfo );
- __ br(Assembler::equal, true, Assembler::pt, done);
- __ delayed()->set(1, dst);
- __ set(0, dst);
- __ bind(done);
- } else {
- // See if we get an immediate positive hit
- assert_different_registers(Rtmp1, k_RInfo, klass_RInfo);
- __ cmp(Rtmp1, k_RInfo );
- __ br(Assembler::equal, true, Assembler::pt, done);
- __ delayed()->set(1, dst);
- // check for self
- __ cmp(klass_RInfo, k_RInfo);
- __ br(Assembler::equal, true, Assembler::pt, done);
- __ delayed()->set(1, dst);
-
- // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup");
- __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
- __ delayed()->nop();
- __ mov(G3, dst);
- __ bind(done);
- }
+ if (k->super_check_offset() != sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes())
+ need_slow_path = false;
+ // perform the fast part of the checking logic
+ __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, noreg,
+ (need_slow_path ? &done : NULL),
+ (need_slow_path ? &done : NULL), NULL,
+ RegisterConstant(k->super_check_offset()),
+ dst);
} else {
assert(dst != klass_RInfo && dst != k_RInfo, "need 3 registers");
-
- load(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), dst, T_INT, NULL);
- // See if we get an immediate positive hit
- load(klass_RInfo, dst, FrameMap::O7_oop_opr, T_OBJECT);
- __ cmp(k_RInfo, O7);
- __ br(Assembler::equal, true, Assembler::pt, done);
- __ delayed()->set(1, dst);
- // check for immediate negative hit
- __ cmp(dst, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes());
- __ br(Assembler::notEqual, true, Assembler::pt, done);
- __ delayed()->set(0, dst);
- // check for self
- __ cmp(klass_RInfo, k_RInfo);
- __ br(Assembler::equal, true, Assembler::pt, done);
- __ delayed()->set(1, dst);
-
- // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup");
+ // perform the fast part of the checking logic
+ __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, dst,
+ &done, &done, NULL,
+ RegisterConstant(-1),
+ dst);
+ }
+ if (need_slow_path) {
+ // call out-of-line instance of __ check_klass_subtype_slow_path(...):
+ assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup");
__ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
__ delayed()->nop();
__ mov(G3, dst);
- __ bind(done);
}
+ __ bind(done);
}
} else {
ShouldNotReachHere();
diff --git a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp
index 489e84dd5..6dfb8efbc 100644
--- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp
+++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp
@@ -714,38 +714,19 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
// sub : G3, argument, destroyed
// super: G1, argument, not changed
// raddr: O7, blown by call
- Label loop, miss;
+ Label miss;
__ save_frame(0); // Blow no registers!
- __ ld_ptr( G3, sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes(), L3 );
- __ lduw(L3,arrayOopDesc::length_offset_in_bytes(),L0); // length in l0
- __ add(L3,arrayOopDesc::base_offset_in_bytes(T_OBJECT),L1); // ptr into array
- __ clr(L4); // Index
- // Load a little early; will load 1 off the end of the array.
- // Ok for now; revisit if we have other uses of this routine.
- __ ld_ptr(L1,0,L2); // Will load a little early
-
- // The scan loop
- __ bind(loop);
- __ add(L1,wordSize,L1); // Bump by OOP size
- __ cmp(L4,L0);
- __ br(Assembler::equal,false,Assembler::pn,miss);
- __ delayed()->inc(L4); // Bump index
- __ subcc(L2,G1,L3); // Check for match; zero in L3 for a hit
- __ brx( Assembler::notEqual, false, Assembler::pt, loop );
- __ delayed()->ld_ptr(L1,0,L2); // Will load a little early
-
- // Got a hit; report success; set cache
- __ st_ptr( G1, G3, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() );
+ __ check_klass_subtype_slow_path(G3, G1, L0, L1, L2, L4, NULL, &miss);
__ mov(1, G3);
- __ ret(); // Result in G5 is ok; flags set
+ __ ret(); // Result in G5 is 'true'
__ delayed()->restore(); // free copy or add can go here
__ bind(miss);
__ mov(0, G3);
- __ ret(); // Result in G5 is ok; flags set
+ __ ret(); // Result in G5 is 'false'
__ delayed()->restore(); // free copy or add can go here
}
diff --git a/src/cpu/sparc/vm/interp_masm_sparc.cpp b/src/cpu/sparc/vm/interp_masm_sparc.cpp
index dee9fcc3c..e843d3fad 100644
--- a/src/cpu/sparc/vm/interp_masm_sparc.cpp
+++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp
@@ -866,65 +866,18 @@ void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,
Register Rtmp2,
Register Rtmp3,
Label &ok_is_subtype ) {
- Label not_subtype, loop;
+ Label not_subtype;
// Profile the not-null value's klass.
profile_typecheck(Rsub_klass, Rtmp1);
- // Load the super-klass's check offset into Rtmp1
- ld( Rsuper_klass, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), Rtmp1 );
- // Load from the sub-klass's super-class display list, or a 1-word cache of
- // the secondary superclass list, or a failing value with a sentinel offset
- // if the super-klass is an interface or exceptionally deep in the Java
- // hierarchy and we have to scan the secondary superclass list the hard way.
- ld_ptr( Rsub_klass, Rtmp1, Rtmp2 );
- // See if we get an immediate positive hit
- cmp( Rtmp2, Rsuper_klass );
- brx( Assembler::equal, false, Assembler::pt, ok_is_subtype );
- // In the delay slot, check for immediate negative hit
- delayed()->cmp( Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() );
- br( Assembler::notEqual, false, Assembler::pt, not_subtype );
- // In the delay slot, check for self
- delayed()->cmp( Rsub_klass, Rsuper_klass );
- brx( Assembler::equal, false, Assembler::pt, ok_is_subtype );
-
- // Now do a linear scan of the secondary super-klass chain.
- delayed()->ld_ptr( Rsub_klass, sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes(), Rtmp2 );
-
- // compress superclass
- if (UseCompressedOops) encode_heap_oop(Rsuper_klass);
-
- // Rtmp2 holds the objArrayOop of secondary supers.
- ld( Rtmp2, arrayOopDesc::length_offset_in_bytes(), Rtmp1 );// Load the array length
- // Check for empty secondary super list
- tst(Rtmp1);
-
- // Top of search loop
- bind( loop );
- br( Assembler::equal, false, Assembler::pn, not_subtype );
- delayed()->nop();
+ check_klass_subtype_fast_path(Rsub_klass, Rsuper_klass,
+ Rtmp1, Rtmp2,
+ &ok_is_subtype, &not_subtype, NULL);
- // load next super to check
- if (UseCompressedOops) {
- lduw( Rtmp2, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rtmp3);
- // Bump array pointer forward one oop
- add( Rtmp2, 4, Rtmp2 );
- } else {
- ld_ptr( Rtmp2, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rtmp3);
- // Bump array pointer forward one oop
- add( Rtmp2, wordSize, Rtmp2);
- }
- // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list
- cmp( Rtmp3, Rsuper_klass );
- // A miss means we are NOT a subtype and need to keep looping
- brx( Assembler::notEqual, false, Assembler::pt, loop );
- delayed()->deccc( Rtmp1 ); // dec trip counter in delay slot
- // Falling out the bottom means we found a hit; we ARE a subtype
- if (UseCompressedOops) decode_heap_oop(Rsuper_klass);
- br( Assembler::always, false, Assembler::pt, ok_is_subtype );
- // Update the cache
- delayed()->st_ptr( Rsuper_klass, Rsub_klass,
- sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() );
+ check_klass_subtype_slow_path(Rsub_klass, Rsuper_klass,
+ Rtmp1, Rtmp2, Rtmp3, /*hack:*/ noreg,
+ &ok_is_subtype, NULL);
bind(not_subtype);
profile_typecheck_failed(Rtmp1);
diff --git a/src/cpu/sparc/vm/sparc.ad b/src/cpu/sparc/vm/sparc.ad
index f9631ddf6..df6e9049e 100644
--- a/src/cpu/sparc/vm/sparc.ad
+++ b/src/cpu/sparc/vm/sparc.ad
@@ -547,7 +547,11 @@ int MachCallDynamicJavaNode::ret_addr_offset() {
int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes();
int klass_load_size;
if (UseCompressedOops) {
- klass_load_size = 3*BytesPerInstWord; // see MacroAssembler::load_klass()
+ assert(Universe::heap() != NULL, "java heap should be initialized");
+ if (Universe::narrow_oop_base() == NULL)
+ klass_load_size = 2*BytesPerInstWord; // see MacroAssembler::load_klass()
+ else
+ klass_load_size = 3*BytesPerInstWord;
} else {
klass_load_size = 1*BytesPerInstWord;
}
@@ -1601,9 +1605,11 @@ void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
st->print_cr("\nUEP:");
#ifdef _LP64
if (UseCompressedOops) {
+ assert(Universe::heap() != NULL, "java heap should be initialized");
st->print_cr("\tLDUW [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check - compressed klass");
st->print_cr("\tSLL R_G5,3,R_G5");
- st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5");
+ if (Universe::narrow_oop_base() != NULL)
+ st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5");
} else {
st->print_cr("\tLDX [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check");
}
@@ -2502,7 +2508,11 @@ encode %{
__ load_klass(O0, G3_scratch);
int klass_load_size;
if (UseCompressedOops) {
- klass_load_size = 3*BytesPerInstWord;
+ assert(Universe::heap() != NULL, "java heap should be initialized");
+ if (Universe::narrow_oop_base() == NULL)
+ klass_load_size = 2*BytesPerInstWord;
+ else
+ klass_load_size = 3*BytesPerInstWord;
} else {
klass_load_size = 1*BytesPerInstWord;
}
@@ -9005,6 +9015,33 @@ instruct string_compare(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, note
ins_pipe(long_memory_op);
%}
+
+//---------- Population Count Instructions -------------------------------------
+
+instruct popCountI(iRegI dst, iRegI src) %{
+ predicate(UsePopCountInstruction);
+ match(Set dst (PopCountI src));
+
+ format %{ "POPC $src, $dst" %}
+ ins_encode %{
+ __ popc($src$$Register, $dst$$Register);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+// Note: Long.bitCount(long) returns an int.
+instruct popCountL(iRegI dst, iRegL src) %{
+ predicate(UsePopCountInstruction);
+ match(Set dst (PopCountL src));
+
+ format %{ "POPC $src, $dst" %}
+ ins_encode %{
+ __ popc($src$$Register, $dst$$Register);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+
// ============================================================================
//------------Bytes reverse--------------------------------------------------
diff --git a/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/src/cpu/sparc/vm/stubGenerator_sparc.cpp
index 9b4981dff..e4a3806da 100644
--- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp
+++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp
@@ -900,19 +900,7 @@ class StubGenerator: public StubCodeGenerator {
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", "partial_subtype_check");
address start = __ pc();
- Label loop, miss;
-
- // Compare super with sub directly, since super is not in its own SSA.
- // The compiler used to emit this test, but we fold it in here,
- // to increase overall code density, with no real loss of speed.
- { Label L;
- __ cmp(O1, O2);
- __ brx(Assembler::notEqual, false, Assembler::pt, L);
- __ delayed()->nop();
- __ retl();
- __ delayed()->addcc(G0,0,O0); // set Z flags, zero result
- __ bind(L);
- }
+ Label miss;
#if defined(COMPILER2) && !defined(_LP64)
// Do not use a 'save' because it blows the 64-bit O registers.
@@ -936,56 +924,12 @@ class StubGenerator: public StubCodeGenerator {
Register L2_super = L2;
Register L3_index = L3;
-#ifdef _LP64
- Register L4_ooptmp = L4;
-
- if (UseCompressedOops) {
- // this must be under UseCompressedOops check, as we rely upon fact
- // that L4 not clobbered in C2 on 32-bit platforms, where we do explicit save
- // on stack, see several lines above
- __ encode_heap_oop(Rsuper, L4_ooptmp);
- }
-#endif
-
- inc_counter_np(SharedRuntime::_partial_subtype_ctr, L0, L1);
-
- __ ld_ptr( Rsub, sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes(), L3 );
- __ lduw(L3,arrayOopDesc::length_offset_in_bytes(),L0_ary_len);
- __ add(L3,arrayOopDesc::base_offset_in_bytes(T_OBJECT),L1_ary_ptr);
- __ clr(L3_index); // zero index
- // Load a little early; will load 1 off the end of the array.
- // Ok for now; revisit if we have other uses of this routine.
- if (UseCompressedOops) {
- __ lduw(L1_ary_ptr,0,L2_super);// Will load a little early
- } else {
- __ ld_ptr(L1_ary_ptr,0,L2_super);// Will load a little early
- }
-
- assert(heapOopSize != 0, "heapOopSize should be initialized");
- // The scan loop
- __ BIND(loop);
- __ add(L1_ary_ptr, heapOopSize, L1_ary_ptr); // Bump by OOP size
- __ cmp(L3_index,L0_ary_len);
- __ br(Assembler::equal,false,Assembler::pn,miss);
- __ delayed()->inc(L3_index); // Bump index
-
- if (UseCompressedOops) {
-#ifdef _LP64
- __ subcc(L2_super,L4_ooptmp,Rret); // Check for match; zero in Rret for a hit
- __ br( Assembler::notEqual, false, Assembler::pt, loop );
- __ delayed()->lduw(L1_ary_ptr,0,L2_super);// Will load a little early
-#else
- ShouldNotReachHere();
-#endif
- } else {
- __ subcc(L2_super,Rsuper,Rret); // Check for match; zero in Rret for a hit
- __ brx( Assembler::notEqual, false, Assembler::pt, loop );
- __ delayed()->ld_ptr(L1_ary_ptr,0,L2_super);// Will load a little early
- }
+ __ check_klass_subtype_slow_path(Rsub, Rsuper,
+ L0, L1, L2, L3,
+ NULL, &miss);
- // Got a hit; report success; set cache. Cache load doesn't
- // happen here; for speed it is directly emitted by the compiler.
- __ st_ptr( Rsuper, Rsub, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() );
+ // Match falls through here.
+ __ addcc(G0,0,Rret); // set Z flags, Z result
#if defined(COMPILER2) && !defined(_LP64)
__ ld_ptr(SP,(frame::register_save_words+0)*wordSize,L0);
@@ -999,7 +943,6 @@ class StubGenerator: public StubCodeGenerator {
__ delayed()->restore();
#endif
- // Hit or miss falls through here
__ BIND(miss);
__ addcc(G0,1,Rret); // set NZ flags, NZ result
@@ -2330,50 +2273,30 @@ class StubGenerator: public StubCodeGenerator {
Register super_check_offset,
Register super_klass,
Register temp,
- Label& L_success,
- Register deccc_hack = noreg) {
+ Label& L_success) {
assert_different_registers(sub_klass, super_check_offset, super_klass, temp);
BLOCK_COMMENT("type_check:");
- Label L_miss;
+ Label L_miss, L_pop_to_miss;
assert_clean_int(super_check_offset, temp);
- // maybe decrement caller's trip count:
-#define DELAY_SLOT delayed(); \
- { if (deccc_hack == noreg) __ nop(); else __ deccc(deccc_hack); }
-
- // if the pointers are equal, we are done (e.g., String[] elements)
- __ cmp(sub_klass, super_klass);
- __ brx(Assembler::equal, true, Assembler::pt, L_success);
- __ DELAY_SLOT;
-
- // check the supertype display:
- __ ld_ptr(sub_klass, super_check_offset, temp); // query the super type
- __ cmp(super_klass, temp); // test the super type
- __ brx(Assembler::equal, true, Assembler::pt, L_success);
- __ DELAY_SLOT;
-
- int sc_offset = (klassOopDesc::header_size() * HeapWordSize +
- Klass::secondary_super_cache_offset_in_bytes());
- __ cmp(super_klass, sc_offset);
- __ brx(Assembler::notEqual, true, Assembler::pt, L_miss);
- __ delayed()->nop();
+ __ check_klass_subtype_fast_path(sub_klass, super_klass, temp, noreg,
+ &L_success, &L_miss, NULL,
+ super_check_offset);
+ BLOCK_COMMENT("type_check_slow_path:");
__ save_frame(0);
- __ mov(sub_klass->after_save(), O1);
- // mov(super_klass->after_save(), O2); //fill delay slot
- assert(StubRoutines::Sparc::_partial_subtype_check != NULL, "order of generation");
- __ call(StubRoutines::Sparc::_partial_subtype_check);
- __ delayed()->mov(super_klass->after_save(), O2);
- __ restore();
-
- // Upon return, the condition codes are already set.
- __ brx(Assembler::equal, true, Assembler::pt, L_success);
- __ DELAY_SLOT;
+ __ check_klass_subtype_slow_path(sub_klass->after_save(),
+ super_klass->after_save(),
+ L0, L1, L2, L4,
+ NULL, &L_pop_to_miss);
+ __ ba(false, L_success);
+ __ delayed()->restore();
-#undef DELAY_SLOT
+ __ bind(L_pop_to_miss);
+ __ restore();
// Fall through on failure!
__ BIND(L_miss);
@@ -2411,7 +2334,7 @@ class StubGenerator: public StubCodeGenerator {
gen_write_ref_array_pre_barrier(O1, O2);
#ifdef ASSERT
- // We sometimes save a frame (see partial_subtype_check below).
+ // We sometimes save a frame (see generate_type_check below).
// If this will cause trouble, let's fail now instead of later.
__ save_frame(0);
__ restore();
@@ -2455,41 +2378,39 @@ class StubGenerator: public StubCodeGenerator {
// G3, G4, G5 --- current oop, oop.klass, oop.klass.super
__ align(16);
- __ bind(store_element);
- // deccc(G1_remain); // decrement the count (hoisted)
+ __ BIND(store_element);
+ __ deccc(G1_remain); // decrement the count
__ store_heap_oop(G3_oop, O1_to, O5_offset); // store the oop
__ inc(O5_offset, heapOopSize); // step to next offset
__ brx(Assembler::zero, true, Assembler::pt, do_card_marks);
__ delayed()->set(0, O0); // return -1 on success
// ======== loop entry is here ========
- __ bind(load_element);
+ __ BIND(load_element);
__ load_heap_oop(O0_from, O5_offset, G3_oop); // load the oop
__ br_null(G3_oop, true, Assembler::pt, store_element);
- __ delayed()->deccc(G1_remain); // decrement the count
+ __ delayed()->nop();
__ load_klass(G3_oop, G4_klass); // query the object klass
generate_type_check(G4_klass, O3_ckoff, O4_ckval, G5_super,
// branch to this on success:
- store_element,
- // decrement this on success:
- G1_remain);
+ store_element);
// ======== end loop ========
// It was a real error; we must depend on the caller to finish the job.
// Register G1 has number of *remaining* oops, O2 number of *total* oops.
// Emit GC store barriers for the oops we have copied (O2 minus G1),
// and report their number to the caller.
- __ bind(fail);
+ __ BIND(fail);
__ subcc(O2_count, G1_remain, O2_count);
__ brx(Assembler::zero, false, Assembler::pt, done);
__ delayed()->not1(O2_count, O0); // report (-1^K) to caller
- __ bind(do_card_marks);
+ __ BIND(do_card_marks);
gen_write_ref_array_post_barrier(O1_to, O2_count, O3); // store check on O1[0..O2]
- __ bind(done);
+ __ BIND(done);
inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, O3, O4);
__ retl();
__ delayed()->nop(); // return value in 00
@@ -2942,14 +2863,15 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_atomic_add_ptr_entry = StubRoutines::_atomic_add_entry;
StubRoutines::_fence_entry = generate_fence();
#endif // COMPILER2 !=> _LP64
-
- StubRoutines::Sparc::_partial_subtype_check = generate_partial_subtype_check();
}
void generate_all() {
// Generates all stubs and initializes the entry points
+ // Generate partial_subtype_check first here since its code depends on
+ // UseZeroBaseCompressedOops which is defined after heap initialization.
+ StubRoutines::Sparc::_partial_subtype_check = generate_partial_subtype_check();
// These entry points require SharedInfo::stack0 to be set up in non-core builds
StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false);
StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false);
diff --git a/src/cpu/sparc/vm/vm_version_sparc.cpp b/src/cpu/sparc/vm/vm_version_sparc.cpp
index a870c7dc1..dc7f6b5bd 100644
--- a/src/cpu/sparc/vm/vm_version_sparc.cpp
+++ b/src/cpu/sparc/vm/vm_version_sparc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 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
@@ -72,6 +72,9 @@ void VM_Version::initialize() {
FLAG_SET_ERGO(bool, UseCompressedOops, false);
}
}
+ // 32-bit oops don't make sense for the 64-bit VM on sparc
+ // since the 32-bit VM has the same registers and smaller objects.
+ Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
#endif // _LP64
#ifdef COMPILER2
// Indirect branch is the same cost as direct
@@ -89,16 +92,26 @@ void VM_Version::initialize() {
#endif
}
+ // Use hardware population count instruction if available.
+ if (has_hardware_popc()) {
+ if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
+ UsePopCountInstruction = true;
+ }
+ }
+
char buf[512];
- jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
+ jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s",
(has_v8() ? ", has_v8" : ""),
(has_v9() ? ", has_v9" : ""),
+ (has_hardware_popc() ? ", popc" : ""),
(has_vis1() ? ", has_vis1" : ""),
(has_vis2() ? ", has_vis2" : ""),
(is_ultra3() ? ", is_ultra3" : ""),
(is_sun4v() ? ", is_sun4v" : ""),
(is_niagara1() ? ", is_niagara1" : ""),
- (!has_hardware_int_muldiv() ? ", no-muldiv" : ""),
+ (is_niagara1_plus() ? ", is_niagara1_plus" : ""),
+ (!has_hardware_mul32() ? ", no-mul32" : ""),
+ (!has_hardware_div32() ? ", no-div32" : ""),
(!has_hardware_fsmuld() ? ", no-fsmuld" : ""));
// buf is started with ", " or is empty
diff --git a/src/cpu/sparc/vm/vm_version_sparc.hpp b/src/cpu/sparc/vm/vm_version_sparc.hpp
index 050e7e68f..e057c608c 100644
--- a/src/cpu/sparc/vm/vm_version_sparc.hpp
+++ b/src/cpu/sparc/vm/vm_version_sparc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 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
@@ -25,34 +25,38 @@
class VM_Version: public Abstract_VM_Version {
protected:
enum Feature_Flag {
- v8_instructions = 0,
- hardware_int_muldiv = 1,
- hardware_fsmuld = 2,
- v9_instructions = 3,
- vis1_instructions = 4,
- vis2_instructions = 5,
- sun4v_instructions = 6
+ v8_instructions = 0,
+ hardware_mul32 = 1,
+ hardware_div32 = 2,
+ hardware_fsmuld = 3,
+ hardware_popc = 4,
+ v9_instructions = 5,
+ vis1_instructions = 6,
+ vis2_instructions = 7,
+ sun4v_instructions = 8
};
enum Feature_Flag_Set {
- unknown_m = 0,
- all_features_m = -1,
-
- v8_instructions_m = 1 << v8_instructions,
- hardware_int_muldiv_m = 1 << hardware_int_muldiv,
- hardware_fsmuld_m = 1 << hardware_fsmuld,
- v9_instructions_m = 1 << v9_instructions,
- vis1_instructions_m = 1 << vis1_instructions,
- vis2_instructions_m = 1 << vis2_instructions,
- sun4v_m = 1 << sun4v_instructions,
-
- generic_v8_m = v8_instructions_m | hardware_int_muldiv_m | hardware_fsmuld_m,
- generic_v9_m = generic_v8_m | v9_instructions_m | vis1_instructions_m,
- ultra3_m = generic_v9_m | vis2_instructions_m,
+ unknown_m = 0,
+ all_features_m = -1,
+
+ v8_instructions_m = 1 << v8_instructions,
+ hardware_mul32_m = 1 << hardware_mul32,
+ hardware_div32_m = 1 << hardware_div32,
+ hardware_fsmuld_m = 1 << hardware_fsmuld,
+ hardware_popc_m = 1 << hardware_popc,
+ v9_instructions_m = 1 << v9_instructions,
+ vis1_instructions_m = 1 << vis1_instructions,
+ vis2_instructions_m = 1 << vis2_instructions,
+ sun4v_m = 1 << sun4v_instructions,
+
+ generic_v8_m = v8_instructions_m | hardware_mul32_m | hardware_div32_m | hardware_fsmuld_m,
+ generic_v9_m = generic_v8_m | v9_instructions_m,
+ ultra3_m = generic_v9_m | vis1_instructions_m | vis2_instructions_m,
// Temporary until we have something more accurate
- niagara1_unique_m = sun4v_m,
- niagara1_m = generic_v9_m | niagara1_unique_m
+ niagara1_unique_m = sun4v_m,
+ niagara1_m = generic_v9_m | niagara1_unique_m
};
static int _features;
@@ -62,7 +66,7 @@ protected:
static int determine_features();
static int platform_features(int features);
- static bool is_niagara1(int features) { return (features & niagara1_m) == niagara1_m; }
+ static bool is_niagara1(int features) { return (features & sun4v_m) != 0; }
static int maximum_niagara1_processor_count() { return 32; }
// Returns true if the platform is in the niagara line and
@@ -76,8 +80,10 @@ public:
// Instruction support
static bool has_v8() { return (_features & v8_instructions_m) != 0; }
static bool has_v9() { return (_features & v9_instructions_m) != 0; }
- static bool has_hardware_int_muldiv() { return (_features & hardware_int_muldiv_m) != 0; }
+ static bool has_hardware_mul32() { return (_features & hardware_mul32_m) != 0; }
+ static bool has_hardware_div32() { return (_features & hardware_div32_m) != 0; }
static bool has_hardware_fsmuld() { return (_features & hardware_fsmuld_m) != 0; }
+ static bool has_hardware_popc() { return (_features & hardware_popc_m) != 0; }
static bool has_vis1() { return (_features & vis1_instructions_m) != 0; }
static bool has_vis2() { return (_features & vis2_instructions_m) != 0; }
diff --git a/src/cpu/sparc/vm/vtableStubs_sparc.cpp b/src/cpu/sparc/vm/vtableStubs_sparc.cpp
index df9262ccb..ce2c8532d 100644
--- a/src/cpu/sparc/vm/vtableStubs_sparc.cpp
+++ b/src/cpu/sparc/vm/vtableStubs_sparc.cpp
@@ -221,13 +221,15 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
if (is_vtable_stub) {
// ld;ld;ld,jmp,nop
const int basic = 5*BytesPerInstWord +
- // shift;add for load_klass
- (UseCompressedOops ? 2*BytesPerInstWord : 0);
+ // shift;add for load_klass (only shift with zero heap based)
+ (UseCompressedOops ?
+ ((Universe::narrow_oop_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0);
return basic + slop;
} else {
const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord +
- // shift;add for load_klass
- (UseCompressedOops ? 2*BytesPerInstWord : 0);
+ // shift;add for load_klass (only shift with zero heap based)
+ (UseCompressedOops ?
+ ((Universe::narrow_oop_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0);
return (basic + slop);
}
}