--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp Fri Mar 13 11:35:17 2009 -0700
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp Fri Mar 13 18:39:22 2009 -0700
@@ -2767,6 +2767,268 @@
}
+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,