6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)

Fri, 06 Mar 2009 21:36:50 -0800

author
jrose
date
Fri, 06 Mar 2009 21:36:50 -0800
changeset 1058
9adddb8c0fc8
parent 1057
56aae7be60d4
child 1059
337400e7a5dd

6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
Summary: Code in vtableStubs and templateTable moved into MacroAssembler.
Reviewed-by: kvn

src/cpu/sparc/vm/assembler_sparc.cpp file | annotate | diff | comparison | revisions
src/cpu/sparc/vm/assembler_sparc.hpp file | annotate | diff | comparison | revisions
src/cpu/sparc/vm/assembler_sparc.inline.hpp file | annotate | diff | comparison | revisions
src/cpu/sparc/vm/vtableStubs_sparc.cpp file | annotate | diff | comparison | revisions
src/cpu/x86/vm/assembler_x86.cpp file | annotate | diff | comparison | revisions
src/cpu/x86/vm/assembler_x86.hpp file | annotate | diff | comparison | revisions
src/cpu/x86/vm/templateTable_x86_32.cpp file | annotate | diff | comparison | revisions
src/cpu/x86/vm/templateTable_x86_64.cpp file | annotate | diff | comparison | revisions
src/cpu/x86/vm/vtableStubs_x86_32.cpp file | annotate | diff | comparison | revisions
src/cpu/x86/vm/vtableStubs_x86_64.cpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/cpu/sparc/vm/assembler_sparc.cpp	Wed Mar 04 09:58:39 2009 -0800
     1.2 +++ b/src/cpu/sparc/vm/assembler_sparc.cpp	Fri Mar 06 21:36:50 2009 -0800
     1.3 @@ -2638,6 +2638,135 @@
     1.4  }
     1.5  
     1.6  
     1.7 +void MacroAssembler::regcon_inc_ptr( RegisterConstant& dest, RegisterConstant src, Register temp ) {
     1.8 +  assert(dest.register_or_noreg() != G0, "lost side effect");
     1.9 +  if ((src.is_constant() && src.as_constant() == 0) ||
    1.10 +      (src.is_register() && src.as_register() == G0)) {
    1.11 +    // do nothing
    1.12 +  } else if (dest.is_register()) {
    1.13 +    add(dest.as_register(), ensure_rs2(src, temp), dest.as_register());
    1.14 +  } else if (src.is_constant()) {
    1.15 +    intptr_t res = dest.as_constant() + src.as_constant();
    1.16 +    dest = RegisterConstant(res); // side effect seen by caller
    1.17 +  } else {
    1.18 +    assert(temp != noreg, "cannot handle constant += register");
    1.19 +    add(src.as_register(), ensure_rs2(dest, temp), temp);
    1.20 +    dest = RegisterConstant(temp); // side effect seen by caller
    1.21 +  }
    1.22 +}
    1.23 +
    1.24 +void MacroAssembler::regcon_sll_ptr( RegisterConstant& dest, RegisterConstant src, Register temp ) {
    1.25 +  assert(dest.register_or_noreg() != G0, "lost side effect");
    1.26 +  if (!is_simm13(src.constant_or_zero()))
    1.27 +    src = (src.as_constant() & 0xFF);
    1.28 +  if ((src.is_constant() && src.as_constant() == 0) ||
    1.29 +      (src.is_register() && src.as_register() == G0)) {
    1.30 +    // do nothing
    1.31 +  } else if (dest.is_register()) {
    1.32 +    sll_ptr(dest.as_register(), src, dest.as_register());
    1.33 +  } else if (src.is_constant()) {
    1.34 +    intptr_t res = dest.as_constant() << src.as_constant();
    1.35 +    dest = RegisterConstant(res); // side effect seen by caller
    1.36 +  } else {
    1.37 +    assert(temp != noreg, "cannot handle constant <<= register");
    1.38 +    set(dest.as_constant(), temp);
    1.39 +    sll_ptr(temp, src, temp);
    1.40 +    dest = RegisterConstant(temp); // side effect seen by caller
    1.41 +  }
    1.42 +}
    1.43 +
    1.44 +
    1.45 +// Look up the method for a megamorphic invokeinterface call.
    1.46 +// The target method is determined by <intf_klass, itable_index>.
    1.47 +// The receiver klass is in recv_klass.
    1.48 +// On success, the result will be in method_result, and execution falls through.
    1.49 +// On failure, execution transfers to the given label.
    1.50 +void MacroAssembler::lookup_interface_method(Register recv_klass,
    1.51 +                                             Register intf_klass,
    1.52 +                                             RegisterConstant itable_index,
    1.53 +                                             Register method_result,
    1.54 +                                             Register scan_temp,
    1.55 +                                             Register sethi_temp,
    1.56 +                                             Label& L_no_such_interface) {
    1.57 +  assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
    1.58 +  assert(itable_index.is_constant() || itable_index.as_register() == method_result,
    1.59 +         "caller must use same register for non-constant itable index as for method");
    1.60 +
    1.61 +  // Compute start of first itableOffsetEntry (which is at the end of the vtable)
    1.62 +  int vtable_base = instanceKlass::vtable_start_offset() * wordSize;
    1.63 +  int scan_step   = itableOffsetEntry::size() * wordSize;
    1.64 +  int vte_size    = vtableEntry::size() * wordSize;
    1.65 +
    1.66 +  lduw(recv_klass, instanceKlass::vtable_length_offset() * wordSize, scan_temp);
    1.67 +  // %%% We should store the aligned, prescaled offset in the klassoop.
    1.68 +  // Then the next several instructions would fold away.
    1.69 +
    1.70 +  int round_to_unit = ((HeapWordsPerLong > 1) ? BytesPerLong : 0);
    1.71 +  int itb_offset = vtable_base;
    1.72 +  if (round_to_unit != 0) {
    1.73 +    // hoist first instruction of round_to(scan_temp, BytesPerLong):
    1.74 +    itb_offset += round_to_unit - wordSize;
    1.75 +  }
    1.76 +  int itb_scale = exact_log2(vtableEntry::size() * wordSize);
    1.77 +  sll(scan_temp, itb_scale,  scan_temp);
    1.78 +  add(scan_temp, itb_offset, scan_temp);
    1.79 +  if (round_to_unit != 0) {
    1.80 +    // Round up to align_object_offset boundary
    1.81 +    // see code for instanceKlass::start_of_itable!
    1.82 +    // Was: round_to(scan_temp, BytesPerLong);
    1.83 +    // Hoisted: add(scan_temp, BytesPerLong-1, scan_temp);
    1.84 +    and3(scan_temp, -round_to_unit, scan_temp);
    1.85 +  }
    1.86 +  add(recv_klass, scan_temp, scan_temp);
    1.87 +
    1.88 +  // Adjust recv_klass by scaled itable_index, so we can free itable_index.
    1.89 +  RegisterConstant itable_offset = itable_index;
    1.90 +  regcon_sll_ptr(itable_offset, exact_log2(itableMethodEntry::size() * wordSize));
    1.91 +  regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes());
    1.92 +  add(recv_klass, ensure_rs2(itable_offset, sethi_temp), recv_klass);
    1.93 +
    1.94 +  // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
    1.95 +  //   if (scan->interface() == intf) {
    1.96 +  //     result = (klass + scan->offset() + itable_index);
    1.97 +  //   }
    1.98 +  // }
    1.99 +  Label search, found_method;
   1.100 +
   1.101 +  for (int peel = 1; peel >= 0; peel--) {
   1.102 +    // %%%% Could load both offset and interface in one ldx, if they were
   1.103 +    // in the opposite order.  This would save a load.
   1.104 +    ld_ptr(scan_temp, itableOffsetEntry::interface_offset_in_bytes(), method_result);
   1.105 +
   1.106 +    // Check that this entry is non-null.  A null entry means that
   1.107 +    // the receiver class doesn't implement the interface, and wasn't the
   1.108 +    // same as when the caller was compiled.
   1.109 +    bpr(Assembler::rc_z, false, Assembler::pn, method_result, L_no_such_interface);
   1.110 +    delayed()->cmp(method_result, intf_klass);
   1.111 +
   1.112 +    if (peel) {
   1.113 +      brx(Assembler::equal,    false, Assembler::pt, found_method);
   1.114 +    } else {
   1.115 +      brx(Assembler::notEqual, false, Assembler::pn, search);
   1.116 +      // (invert the test to fall through to found_method...)
   1.117 +    }
   1.118 +    delayed()->add(scan_temp, scan_step, scan_temp);
   1.119 +
   1.120 +    if (!peel)  break;
   1.121 +
   1.122 +    bind(search);
   1.123 +  }
   1.124 +
   1.125 +  bind(found_method);
   1.126 +
   1.127 +  // Got a hit.
   1.128 +  int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
   1.129 +  // scan_temp[-scan_step] points to the vtable offset we need
   1.130 +  ito_offset -= scan_step;
   1.131 +  lduw(scan_temp, ito_offset, scan_temp);
   1.132 +  ld_ptr(recv_klass, scan_temp, method_result);
   1.133 +}
   1.134 +
   1.135 +
   1.136  void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg,
   1.137                                            Register temp_reg,
   1.138                                            Label& done, Label* slow_case,
     2.1 --- a/src/cpu/sparc/vm/assembler_sparc.hpp	Wed Mar 04 09:58:39 2009 -0800
     2.2 +++ b/src/cpu/sparc/vm/assembler_sparc.hpp	Fri Mar 06 21:36:50 2009 -0800
     2.3 @@ -1859,6 +1859,7 @@
     2.4    // Functions for isolating 64 bit shifts for LP64
     2.5    inline void sll_ptr( Register s1, Register s2, Register d );
     2.6    inline void sll_ptr( Register s1, int imm6a,   Register d );
     2.7 +  inline void sll_ptr( Register s1, RegisterConstant s2, Register d );
     2.8    inline void srl_ptr( Register s1, Register s2, Register d );
     2.9    inline void srl_ptr( Register s1, int imm6a,   Register d );
    2.10  
    2.11 @@ -1986,6 +1987,25 @@
    2.12    void load_sized_value(Register s1, RegisterConstant s2, Register d,
    2.13                          int size_in_bytes, bool is_signed);
    2.14  
    2.15 +  // Helpers for address formation.
    2.16 +  // They update the dest in place, whether it is a register or constant.
    2.17 +  // They emit no code at all if src is a constant zero.
    2.18 +  // If dest is a constant and src is a register, the temp argument
    2.19 +  // is required, and becomes the result.
    2.20 +  // If dest is a register and src is a non-simm13 constant,
    2.21 +  // the temp argument is required, and is used to materialize the constant.
    2.22 +  void regcon_inc_ptr( RegisterConstant& dest, RegisterConstant src,
    2.23 +                       Register temp = noreg );
    2.24 +  void regcon_sll_ptr( RegisterConstant& dest, RegisterConstant src,
    2.25 +                       Register temp = noreg );
    2.26 +  RegisterConstant ensure_rs2(RegisterConstant rs2, Register sethi_temp) {
    2.27 +    guarantee(sethi_temp != noreg, "constant offset overflow");
    2.28 +    if (is_simm13(rs2.constant_or_zero()))
    2.29 +      return rs2;               // register or short constant
    2.30 +    set(rs2.as_constant(), sethi_temp);
    2.31 +    return sethi_temp;
    2.32 +  }
    2.33 +
    2.34    // --------------------------------------------------
    2.35  
    2.36   public:
    2.37 @@ -2299,6 +2319,14 @@
    2.38    );
    2.39    void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
    2.40  
    2.41 +  // interface method calling
    2.42 +  void lookup_interface_method(Register recv_klass,
    2.43 +                               Register intf_klass,
    2.44 +                               RegisterConstant itable_index,
    2.45 +                               Register method_result,
    2.46 +                               Register temp_reg, Register temp2_reg,
    2.47 +                               Label& no_such_interface);
    2.48 +
    2.49    // Stack overflow checking
    2.50  
    2.51    // Note: this clobbers G3_scratch
     3.1 --- a/src/cpu/sparc/vm/assembler_sparc.inline.hpp	Wed Mar 04 09:58:39 2009 -0800
     3.2 +++ b/src/cpu/sparc/vm/assembler_sparc.inline.hpp	Fri Mar 06 21:36:50 2009 -0800
     3.3 @@ -455,6 +455,11 @@
     3.4  #endif
     3.5  }
     3.6  
     3.7 +inline void MacroAssembler::sll_ptr( Register s1, RegisterConstant s2, Register d ) {
     3.8 +  if (s2.is_register())  sll_ptr(s1, s2.as_register(), d);
     3.9 +  else                   sll_ptr(s1, s2.as_constant(), d);
    3.10 +}
    3.11 +
    3.12  // Use the right branch for the platform
    3.13  
    3.14  inline void MacroAssembler::br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) {
     4.1 --- a/src/cpu/sparc/vm/vtableStubs_sparc.cpp	Wed Mar 04 09:58:39 2009 -0800
     4.2 +++ b/src/cpu/sparc/vm/vtableStubs_sparc.cpp	Fri Mar 06 21:36:50 2009 -0800
     4.3 @@ -106,6 +106,15 @@
     4.4    __ delayed()->nop();
     4.5  
     4.6    masm->flush();
     4.7 +
     4.8 +  if (PrintMiscellaneous && (WizardMode || Verbose)) {
     4.9 +    tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
    4.10 +                  vtable_index, s->entry_point(),
    4.11 +                  (int)(s->code_end() - s->entry_point()),
    4.12 +                  (int)(s->code_end() - __ pc()));
    4.13 +  }
    4.14 +  guarantee(__ pc() <= s->code_end(), "overflowed buffer");
    4.15 +
    4.16    s->set_exception_points(npe_addr, ame_addr);
    4.17    return s;
    4.18  }
    4.19 @@ -113,9 +122,9 @@
    4.20  
    4.21  // NOTE:  %%%% if any change is made to this stub make sure that the function
    4.22  //             pd_code_size_limit is changed to ensure the correct size for VtableStub
    4.23 -VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
    4.24 +VtableStub* VtableStubs::create_itable_stub(int itable_index) {
    4.25    const int sparc_code_length = VtableStub::pd_code_size_limit(false);
    4.26 -  VtableStub* s = new(sparc_code_length) VtableStub(false, vtable_index);
    4.27 +  VtableStub* s = new(sparc_code_length) VtableStub(false, itable_index);
    4.28    ResourceMark rm;
    4.29    CodeBuffer cb(s->entry_point(), sparc_code_length);
    4.30    MacroAssembler* masm = new MacroAssembler(&cb);
    4.31 @@ -139,7 +148,6 @@
    4.32    // are passed in the %o registers.  Instead, longs are passed in G1 and G4
    4.33    // and so those registers are not available here.
    4.34    __ save(SP,-frame::register_save_words*wordSize,SP);
    4.35 -  Register I0_receiver = I0;    // Location of receiver after save
    4.36  
    4.37  #ifndef PRODUCT
    4.38    if (CountCompiledCalls) {
    4.39 @@ -151,63 +159,31 @@
    4.40    }
    4.41  #endif /* PRODUCT */
    4.42  
    4.43 -  // load start of itable entries into L0 register
    4.44 -  const int base = instanceKlass::vtable_start_offset() * wordSize;
    4.45 -  __ ld(Address(G3_klassOop, 0, instanceKlass::vtable_length_offset() * wordSize), L0);
    4.46 +  Label throw_icce;
    4.47  
    4.48 -  // %%% Could store the aligned, prescaled offset in the klassoop.
    4.49 -  __ sll(L0, exact_log2(vtableEntry::size() * wordSize), L0);
    4.50 -  // see code for instanceKlass::start_of_itable!
    4.51 -  const int vtable_alignment = align_object_offset(1);
    4.52 -  assert(vtable_alignment == 1 || vtable_alignment == 2, "");
    4.53 -  const int odd_bit = vtableEntry::size() * wordSize;
    4.54 -  if (vtable_alignment == 2) {
    4.55 -    __ and3(L0, odd_bit, L1);   // isolate the odd bit
    4.56 -  }
    4.57 -  __ add(G3_klassOop, L0, L0);
    4.58 -  if (vtable_alignment == 2) {
    4.59 -    __ add(L0, L1, L0);         // double the odd bit, to align up
    4.60 -  }
    4.61 -
    4.62 -  // Loop over all itable entries until desired interfaceOop (G5_interface) found
    4.63 -  __ bind(search);
    4.64 -
    4.65 -  // %%%% Could load both offset and interface in one ldx, if they were
    4.66 -  // in the opposite order.  This would save a load.
    4.67 -  __ ld_ptr(L0, base + itableOffsetEntry::interface_offset_in_bytes(), L1);
    4.68 -
    4.69 -  // If the entry is NULL then we've reached the end of the table
    4.70 -  // without finding the expected interface, so throw an exception
    4.71 -  Label throw_icce;
    4.72 -  __ bpr(Assembler::rc_z, false, Assembler::pn, L1, throw_icce);
    4.73 -  __ delayed()->cmp(G5_interface, L1);
    4.74 -  __ brx(Assembler::notEqual, true, Assembler::pn, search);
    4.75 -  __ delayed()->add(L0, itableOffsetEntry::size() * wordSize, L0);
    4.76 -
    4.77 -  // entry found and L0 points to it, move offset of vtable for interface into L0
    4.78 -  __ ld(L0, base + itableOffsetEntry::offset_offset_in_bytes(), L0);
    4.79 -
    4.80 -  // Compute itableMethodEntry and get methodOop(G5_method) and entrypoint(L0) for compiler
    4.81 -  const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes();
    4.82 -  __ add(G3_klassOop, L0, L1);
    4.83 -  __ ld_ptr(L1, method_offset, G5_method);
    4.84 +  Register L5_method = L5;
    4.85 +  __ lookup_interface_method(// inputs: rec. class, interface, itable index
    4.86 +                             G3_klassOop, G5_interface, itable_index,
    4.87 +                             // outputs: method, scan temp. reg
    4.88 +                             L5_method, L2, L3,
    4.89 +                             throw_icce);
    4.90  
    4.91  #ifndef PRODUCT
    4.92    if (DebugVtables) {
    4.93      Label L01;
    4.94 -    __ ld_ptr(L1, method_offset, G5_method);
    4.95 -    __ bpr(Assembler::rc_nz, false, Assembler::pt, G5_method, L01);
    4.96 +    __ bpr(Assembler::rc_nz, false, Assembler::pt, L5_method, L01);
    4.97      __ delayed()->nop();
    4.98      __ stop("methodOop is null");
    4.99      __ bind(L01);
   4.100 -    __ verify_oop(G5_method);
   4.101 +    __ verify_oop(L5_method);
   4.102    }
   4.103  #endif
   4.104  
   4.105    // If the following load is through a NULL pointer, we'll take an OS
   4.106    // exception that should translate into an AbstractMethodError.  We need the
   4.107    // window count to be correct at that time.
   4.108 -  __ restore();                 // Restore registers BEFORE the AME point
   4.109 +  __ restore(L5_method, 0, G5_method);
   4.110 +  // Restore registers *before* the AME point.
   4.111  
   4.112    address ame_addr = __ pc();   // if the vtable entry is null, the method is abstract
   4.113    __ ld_ptr(G5_method, in_bytes(methodOopDesc::from_compiled_offset()), G3_scratch);
   4.114 @@ -225,6 +201,12 @@
   4.115  
   4.116    masm->flush();
   4.117  
   4.118 +  if (PrintMiscellaneous && (WizardMode || Verbose)) {
   4.119 +    tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
   4.120 +                  itable_index, s->entry_point(),
   4.121 +                  (int)(s->code_end() - s->entry_point()),
   4.122 +                  (int)(s->code_end() - __ pc()));
   4.123 +  }
   4.124    guarantee(__ pc() <= s->code_end(), "overflowed buffer");
   4.125  
   4.126    s->set_exception_points(npe_addr, ame_addr);
   4.127 @@ -243,8 +225,7 @@
   4.128                          (UseCompressedOops ? 2*BytesPerInstWord : 0);
   4.129        return basic + slop;
   4.130      } else {
   4.131 -      // save, ld, ld, sll, and, add, add, ld, cmp, br, add, ld, add, ld, ld, jmp, restore, sethi, jmpl, restore
   4.132 -      const int basic = (20 LP64_ONLY(+ 6)) * BytesPerInstWord +
   4.133 +      const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord +
   4.134                          // shift;add for load_klass
   4.135                          (UseCompressedOops ? 2*BytesPerInstWord : 0);
   4.136        return (basic + slop);
     5.1 --- a/src/cpu/x86/vm/assembler_x86.cpp	Wed Mar 04 09:58:39 2009 -0800
     5.2 +++ b/src/cpu/x86/vm/assembler_x86.cpp	Fri Mar 06 21:36:50 2009 -0800
     5.3 @@ -7076,6 +7076,81 @@
     5.4  }
     5.5  
     5.6  
     5.7 +// Look up the method for a megamorphic invokeinterface call.
     5.8 +// The target method is determined by <intf_klass, itable_index>.
     5.9 +// The receiver klass is in recv_klass.
    5.10 +// On success, the result will be in method_result, and execution falls through.
    5.11 +// On failure, execution transfers to the given label.
    5.12 +void MacroAssembler::lookup_interface_method(Register recv_klass,
    5.13 +                                             Register intf_klass,
    5.14 +                                             RegisterConstant itable_index,
    5.15 +                                             Register method_result,
    5.16 +                                             Register scan_temp,
    5.17 +                                             Label& L_no_such_interface) {
    5.18 +  assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
    5.19 +  assert(itable_index.is_constant() || itable_index.as_register() == method_result,
    5.20 +         "caller must use same register for non-constant itable index as for method");
    5.21 +
    5.22 +  // Compute start of first itableOffsetEntry (which is at the end of the vtable)
    5.23 +  int vtable_base = instanceKlass::vtable_start_offset() * wordSize;
    5.24 +  int itentry_off = itableMethodEntry::method_offset_in_bytes();
    5.25 +  int scan_step   = itableOffsetEntry::size() * wordSize;
    5.26 +  int vte_size    = vtableEntry::size() * wordSize;
    5.27 +  Address::ScaleFactor times_vte_scale = Address::times_ptr;
    5.28 +  assert(vte_size == wordSize, "else adjust times_vte_scale");
    5.29 +
    5.30 +  movl(scan_temp, Address(recv_klass, instanceKlass::vtable_length_offset() * wordSize));
    5.31 +
    5.32 +  // %%% Could store the aligned, prescaled offset in the klassoop.
    5.33 +  lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base));
    5.34 +  if (HeapWordsPerLong > 1) {
    5.35 +    // Round up to align_object_offset boundary
    5.36 +    // see code for instanceKlass::start_of_itable!
    5.37 +    round_to(scan_temp, BytesPerLong);
    5.38 +  }
    5.39 +
    5.40 +  // Adjust recv_klass by scaled itable_index, so we can free itable_index.
    5.41 +  assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
    5.42 +  lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
    5.43 +
    5.44 +  // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
    5.45 +  //   if (scan->interface() == intf) {
    5.46 +  //     result = (klass + scan->offset() + itable_index);
    5.47 +  //   }
    5.48 +  // }
    5.49 +  Label search, found_method;
    5.50 +
    5.51 +  for (int peel = 1; peel >= 0; peel--) {
    5.52 +    movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
    5.53 +    cmpptr(intf_klass, method_result);
    5.54 +
    5.55 +    if (peel) {
    5.56 +      jccb(Assembler::equal, found_method);
    5.57 +    } else {
    5.58 +      jccb(Assembler::notEqual, search);
    5.59 +      // (invert the test to fall through to found_method...)
    5.60 +    }
    5.61 +
    5.62 +    if (!peel)  break;
    5.63 +
    5.64 +    bind(search);
    5.65 +
    5.66 +    // Check that the previous entry is non-null.  A null entry means that
    5.67 +    // the receiver class doesn't implement the interface, and wasn't the
    5.68 +    // same as when the caller was compiled.
    5.69 +    testptr(method_result, method_result);
    5.70 +    jcc(Assembler::zero, L_no_such_interface);
    5.71 +    addptr(scan_temp, scan_step);
    5.72 +  }
    5.73 +
    5.74 +  bind(found_method);
    5.75 +
    5.76 +  // Got a hit.
    5.77 +  movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
    5.78 +  movptr(method_result, Address(recv_klass, scan_temp, Address::times_1));
    5.79 +}
    5.80 +
    5.81 +
    5.82  void MacroAssembler::ucomisd(XMMRegister dst, AddressLiteral src) {
    5.83    ucomisd(dst, as_Address(src));
    5.84  }
     6.1 --- a/src/cpu/x86/vm/assembler_x86.hpp	Wed Mar 04 09:58:39 2009 -0800
     6.2 +++ b/src/cpu/x86/vm/assembler_x86.hpp	Fri Mar 06 21:36:50 2009 -0800
     6.3 @@ -1765,6 +1765,14 @@
     6.4    );
     6.5    void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
     6.6  
     6.7 +  // interface method calling
     6.8 +  void lookup_interface_method(Register recv_klass,
     6.9 +                               Register intf_klass,
    6.10 +                               RegisterConstant itable_index,
    6.11 +                               Register method_result,
    6.12 +                               Register scan_temp,
    6.13 +                               Label& no_such_interface);
    6.14 +
    6.15    //----
    6.16    void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
    6.17  
     7.1 --- a/src/cpu/x86/vm/templateTable_x86_32.cpp	Wed Mar 04 09:58:39 2009 -0800
     7.2 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp	Fri Mar 06 21:36:50 2009 -0800
     7.3 @@ -3055,35 +3055,44 @@
     7.4    // profile this call
     7.5    __ profile_virtual_call(rdx, rsi, rdi);
     7.6  
     7.7 -  __ mov(rdi, rdx); // Save klassOop in rdi
     7.8 -
     7.9 -  // Compute start of first itableOffsetEntry (which is at the end of the vtable)
    7.10 -  const int base = instanceKlass::vtable_start_offset() * wordSize;
    7.11 -  assert(vtableEntry::size() * wordSize == (1 << (int)Address::times_ptr), "adjust the scaling in the code below");
    7.12 -  __ movl(rsi, Address(rdx, instanceKlass::vtable_length_offset() * wordSize)); // Get length of vtable
    7.13 -  __ lea(rdx, Address(rdx, rsi, Address::times_4, base));
    7.14 -  if (HeapWordsPerLong > 1) {
    7.15 -    // Round up to align_object_offset boundary
    7.16 -    __ round_to(rdx, BytesPerLong);
    7.17 -  }
    7.18 -
    7.19 -  Label entry, search, interface_ok;
    7.20 -
    7.21 -  __ jmpb(entry);
    7.22 -  __ bind(search);
    7.23 -  __ addptr(rdx, itableOffsetEntry::size() * wordSize);
    7.24 -
    7.25 -  __ bind(entry);
    7.26 -
    7.27 -  // Check that the entry is non-null.  A null entry means that the receiver
    7.28 -  // class doesn't implement the interface, and wasn't the same as the
    7.29 -  // receiver class checked when the interface was resolved.
    7.30 -  __ push(rdx);
    7.31 -  __ movptr(rdx, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
    7.32 -  __ testptr(rdx, rdx);
    7.33 -  __ jcc(Assembler::notZero, interface_ok);
    7.34 +  Label no_such_interface, no_such_method;
    7.35 +
    7.36 +  __ lookup_interface_method(// inputs: rec. class, interface, itable index
    7.37 +                             rdx, rax, rbx,
    7.38 +                             // outputs: method, scan temp. reg
    7.39 +                             rbx, rsi,
    7.40 +                             no_such_interface);
    7.41 +
    7.42 +  // rbx,: methodOop to call
    7.43 +  // rcx: receiver
    7.44 +  // Check for abstract method error
    7.45 +  // Note: This should be done more efficiently via a throw_abstract_method_error
    7.46 +  //       interpreter entry point and a conditional jump to it in case of a null
    7.47 +  //       method.
    7.48 +  __ testptr(rbx, rbx);
    7.49 +  __ jcc(Assembler::zero, no_such_method);
    7.50 +
    7.51 +  // do the call
    7.52 +  // rcx: receiver
    7.53 +  // rbx,: methodOop
    7.54 +  __ jump_from_interpreted(rbx, rdx);
    7.55 +  __ should_not_reach_here();
    7.56 +
    7.57 +  // exception handling code follows...
    7.58 +  // note: must restore interpreter registers to canonical
    7.59 +  //       state for exception handling to work correctly!
    7.60 +
    7.61 +  __ bind(no_such_method);
    7.62    // throw exception
    7.63 -  __ pop(rdx);           // pop saved register first.
    7.64 +  __ pop(rbx);           // pop return address (pushed by prepare_invoke)
    7.65 +  __ restore_bcp();      // rsi must be correct for exception handler   (was destroyed)
    7.66 +  __ restore_locals();   // make sure locals pointer is correct as well (was destroyed)
    7.67 +  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
    7.68 +  // the call_VM checks for exception, so we should never return here.
    7.69 +  __ should_not_reach_here();
    7.70 +
    7.71 +  __ bind(no_such_interface);
    7.72 +  // throw exception
    7.73    __ pop(rbx);           // pop return address (pushed by prepare_invoke)
    7.74    __ restore_bcp();      // rsi must be correct for exception handler   (was destroyed)
    7.75    __ restore_locals();   // make sure locals pointer is correct as well (was destroyed)
    7.76 @@ -3091,42 +3100,6 @@
    7.77                     InterpreterRuntime::throw_IncompatibleClassChangeError));
    7.78    // the call_VM checks for exception, so we should never return here.
    7.79    __ should_not_reach_here();
    7.80 -  __ bind(interface_ok);
    7.81 -
    7.82 -    __ pop(rdx);
    7.83 -
    7.84 -    __ cmpptr(rax, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
    7.85 -    __ jcc(Assembler::notEqual, search);
    7.86 -
    7.87 -    __ movl(rdx, Address(rdx, itableOffsetEntry::offset_offset_in_bytes()));
    7.88 -    __ addptr(rdx, rdi); // Add offset to klassOop
    7.89 -    assert(itableMethodEntry::size() * wordSize == (1 << (int)Address::times_ptr), "adjust the scaling in the code below");
    7.90 -    __ movptr(rbx, Address(rdx, rbx, Address::times_ptr));
    7.91 -    // rbx,: methodOop to call
    7.92 -    // rcx: receiver
    7.93 -    // Check for abstract method error
    7.94 -    // Note: This should be done more efficiently via a throw_abstract_method_error
    7.95 -    //       interpreter entry point and a conditional jump to it in case of a null
    7.96 -    //       method.
    7.97 -    { Label L;
    7.98 -      __ testptr(rbx, rbx);
    7.99 -      __ jcc(Assembler::notZero, L);
   7.100 -      // throw exception
   7.101 -          // note: must restore interpreter registers to canonical
   7.102 -          //       state for exception handling to work correctly!
   7.103 -          __ pop(rbx);           // pop return address (pushed by prepare_invoke)
   7.104 -          __ restore_bcp();      // rsi must be correct for exception handler   (was destroyed)
   7.105 -          __ restore_locals();   // make sure locals pointer is correct as well (was destroyed)
   7.106 -      __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
   7.107 -      // the call_VM checks for exception, so we should never return here.
   7.108 -      __ should_not_reach_here();
   7.109 -      __ bind(L);
   7.110 -    }
   7.111 -
   7.112 -  // do the call
   7.113 -  // rcx: receiver
   7.114 -  // rbx,: methodOop
   7.115 -  __ jump_from_interpreted(rbx, rdx);
   7.116  }
   7.117  
   7.118  //----------------------------------------------------------------------------------------------------
     8.1 --- a/src/cpu/x86/vm/templateTable_x86_64.cpp	Wed Mar 04 09:58:39 2009 -0800
     8.2 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp	Fri Mar 06 21:36:50 2009 -0800
     8.3 @@ -3010,97 +3010,55 @@
     8.4    // profile this call
     8.5    __ profile_virtual_call(rdx, r13, r14);
     8.6  
     8.7 -  __ mov(r14, rdx); // Save klassOop in r14
     8.8 -
     8.9 -  // Compute start of first itableOffsetEntry (which is at the end of
    8.10 -  // the vtable)
    8.11 -  const int base = instanceKlass::vtable_start_offset() * wordSize;
    8.12 -  // Get length of vtable
    8.13 -  assert(vtableEntry::size() * wordSize == 8,
    8.14 -         "adjust the scaling in the code below");
    8.15 -  __ movl(r13, Address(rdx,
    8.16 -                       instanceKlass::vtable_length_offset() * wordSize));
    8.17 -  __ lea(rdx, Address(rdx, r13, Address::times_8, base));
    8.18 -
    8.19 -  if (HeapWordsPerLong > 1) {
    8.20 -    // Round up to align_object_offset boundary
    8.21 -    __ round_to(rdx, BytesPerLong);
    8.22 -  }
    8.23 -
    8.24 -  Label entry, search, interface_ok;
    8.25 -
    8.26 -  __ jmpb(entry);
    8.27 -  __ bind(search);
    8.28 -  __ addptr(rdx, itableOffsetEntry::size() * wordSize);
    8.29 -
    8.30 -  __ bind(entry);
    8.31 -
    8.32 -  // Check that the entry is non-null.  A null entry means that the
    8.33 -  // receiver class doesn't implement the interface, and wasn't the
    8.34 -  // same as the receiver class checked when the interface was
    8.35 -  // resolved.
    8.36 -  __ push(rdx);
    8.37 -  __ movptr(rdx, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
    8.38 -  __ testptr(rdx, rdx);
    8.39 -  __ jcc(Assembler::notZero, interface_ok);
    8.40 +  Label no_such_interface, no_such_method;
    8.41 +
    8.42 +  __ lookup_interface_method(// inputs: rec. class, interface, itable index
    8.43 +                             rdx, rax, rbx,
    8.44 +                             // outputs: method, scan temp. reg
    8.45 +                             rbx, r13,
    8.46 +                             no_such_interface);
    8.47 +
    8.48 +  // rbx,: methodOop to call
    8.49 +  // rcx: receiver
    8.50 +  // Check for abstract method error
    8.51 +  // Note: This should be done more efficiently via a throw_abstract_method_error
    8.52 +  //       interpreter entry point and a conditional jump to it in case of a null
    8.53 +  //       method.
    8.54 +  __ testptr(rbx, rbx);
    8.55 +  __ jcc(Assembler::zero, no_such_method);
    8.56 +
    8.57 +  // do the call
    8.58 +  // rcx: receiver
    8.59 +  // rbx,: methodOop
    8.60 +  __ jump_from_interpreted(rbx, rdx);
    8.61 +  __ should_not_reach_here();
    8.62 +
    8.63 +  // exception handling code follows...
    8.64 +  // note: must restore interpreter registers to canonical
    8.65 +  //       state for exception handling to work correctly!
    8.66 +
    8.67 +  __ bind(no_such_method);
    8.68    // throw exception
    8.69 -  __ pop(rdx); // pop saved register first.
    8.70 -  __ pop(rbx); // pop return address (pushed by prepare_invoke)
    8.71 -  __ restore_bcp(); // r13 must be correct for exception handler (was
    8.72 -                    // destroyed)
    8.73 -  __ restore_locals(); // make sure locals pointer is correct as well
    8.74 -                       // (was destroyed)
    8.75 +  __ pop(rbx);           // pop return address (pushed by prepare_invoke)
    8.76 +  __ restore_bcp();      // r13 must be correct for exception handler   (was destroyed)
    8.77 +  __ restore_locals();   // make sure locals pointer is correct as well (was destroyed)
    8.78 +  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
    8.79 +  // the call_VM checks for exception, so we should never return here.
    8.80 +  __ should_not_reach_here();
    8.81 +
    8.82 +  __ bind(no_such_interface);
    8.83 +  // throw exception
    8.84 +  __ pop(rbx);           // pop return address (pushed by prepare_invoke)
    8.85 +  __ restore_bcp();      // r13 must be correct for exception handler   (was destroyed)
    8.86 +  __ restore_locals();   // make sure locals pointer is correct as well (was destroyed)
    8.87    __ call_VM(noreg, CAST_FROM_FN_PTR(address,
    8.88                     InterpreterRuntime::throw_IncompatibleClassChangeError));
    8.89    // the call_VM checks for exception, so we should never return here.
    8.90    __ should_not_reach_here();
    8.91 -  __ bind(interface_ok);
    8.92 -
    8.93 -  __ pop(rdx);
    8.94 -
    8.95 -  __ cmpptr(rax, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
    8.96 -  __ jcc(Assembler::notEqual, search);
    8.97 -
    8.98 -  __ movl(rdx, Address(rdx, itableOffsetEntry::offset_offset_in_bytes()));
    8.99 -
   8.100 -  __ addptr(rdx, r14); // Add offset to klassOop
   8.101 -  assert(itableMethodEntry::size() * wordSize == 8,
   8.102 -         "adjust the scaling in the code below");
   8.103 -  __ movptr(rbx, Address(rdx, rbx, Address::times_8));
   8.104 -  // rbx: methodOop to call
   8.105 -  // rcx: receiver
   8.106 -  // Check for abstract method error
   8.107 -  // Note: This should be done more efficiently via a
   8.108 -  // throw_abstract_method_error interpreter entry point and a
   8.109 -  // conditional jump to it in case of a null method.
   8.110 -  {
   8.111 -    Label L;
   8.112 -    __ testptr(rbx, rbx);
   8.113 -    __ jcc(Assembler::notZero, L);
   8.114 -    // throw exception
   8.115 -    // note: must restore interpreter registers to canonical
   8.116 -    //       state for exception handling to work correctly!
   8.117 -    __ pop(rbx);  // pop return address (pushed by prepare_invoke)
   8.118 -    __ restore_bcp(); // r13 must be correct for exception handler
   8.119 -                      // (was destroyed)
   8.120 -    __ restore_locals(); // make sure locals pointer is correct as
   8.121 -                         // well (was destroyed)
   8.122 -    __ call_VM(noreg,
   8.123 -               CAST_FROM_FN_PTR(address,
   8.124 -                             InterpreterRuntime::throw_AbstractMethodError));
   8.125 -    // the call_VM checks for exception, so we should never return here.
   8.126 -    __ should_not_reach_here();
   8.127 -    __ bind(L);
   8.128 -  }
   8.129 -
   8.130 -  __ movptr(rcx, Address(rbx, methodOopDesc::interpreter_entry_offset()));
   8.131 -
   8.132 -  // do the call
   8.133 -  // rcx: receiver
   8.134 -  // rbx: methodOop
   8.135 -  __ jump_from_interpreted(rbx, rdx);
   8.136 +  return;
   8.137  }
   8.138  
   8.139 +
   8.140  //-----------------------------------------------------------------------------
   8.141  // Allocation
   8.142  
     9.1 --- a/src/cpu/x86/vm/vtableStubs_x86_32.cpp	Wed Mar 04 09:58:39 2009 -0800
     9.2 +++ b/src/cpu/x86/vm/vtableStubs_x86_32.cpp	Fri Mar 06 21:36:50 2009 -0800
     9.3 @@ -34,10 +34,16 @@
     9.4  extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int index);
     9.5  #endif
     9.6  
     9.7 -// used by compiler only; may use only caller saved registers rax, rbx, rcx.
     9.8 -// rdx holds first int arg, rsi, rdi, rbp are callee-save & must be preserved.
     9.9 -// Leave receiver in rcx; required behavior when +OptoArgsInRegisters
    9.10 -// is modifed to put first oop in rcx.
    9.11 +// These stubs are used by the compiler only.
    9.12 +// Argument registers, which must be preserved:
    9.13 +//   rcx - receiver (always first argument)
    9.14 +//   rdx - second argument (if any)
    9.15 +// Other registers that might be usable:
    9.16 +//   rax - inline cache register (is interface for itable stub)
    9.17 +//   rbx - method (used when calling out to interpreter)
    9.18 +// Available now, but may become callee-save at some point:
    9.19 +//   rsi, rdi
    9.20 +// Note that rax and rdx are also used for return values.
    9.21  //
    9.22  VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
    9.23    const int i486_code_length = VtableStub::pd_code_size_limit(true);
    9.24 @@ -94,16 +100,25 @@
    9.25    __ jmp( Address(method, methodOopDesc::from_compiled_offset()));
    9.26  
    9.27    masm->flush();
    9.28 +
    9.29 +  if (PrintMiscellaneous && (WizardMode || Verbose)) {
    9.30 +    tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
    9.31 +                  vtable_index, s->entry_point(),
    9.32 +                  (int)(s->code_end() - s->entry_point()),
    9.33 +                  (int)(s->code_end() - __ pc()));
    9.34 +  }
    9.35 +  guarantee(__ pc() <= s->code_end(), "overflowed buffer");
    9.36 +
    9.37    s->set_exception_points(npe_addr, ame_addr);
    9.38    return s;
    9.39  }
    9.40  
    9.41  
    9.42 -VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
    9.43 +VtableStub* VtableStubs::create_itable_stub(int itable_index) {
    9.44    // Note well: pd_code_size_limit is the absolute minimum we can get away with.  If you
    9.45    //            add code here, bump the code stub size returned by pd_code_size_limit!
    9.46    const int i486_code_length = VtableStub::pd_code_size_limit(false);
    9.47 -  VtableStub* s = new(i486_code_length) VtableStub(false, vtable_index);
    9.48 +  VtableStub* s = new(i486_code_length) VtableStub(false, itable_index);
    9.49    ResourceMark rm;
    9.50    CodeBuffer cb(s->entry_point(), i486_code_length);
    9.51    MacroAssembler* masm = new MacroAssembler(&cb);
    9.52 @@ -123,50 +138,19 @@
    9.53  
    9.54    // get receiver klass (also an implicit null-check)
    9.55    address npe_addr = __ pc();
    9.56 -  __ movptr(rbx, Address(rcx, oopDesc::klass_offset_in_bytes()));
    9.57 +  __ movptr(rsi, Address(rcx, oopDesc::klass_offset_in_bytes()));
    9.58  
    9.59 -  __ mov(rsi, rbx);   // Save klass in free register
    9.60 -  // Most registers are in use, so save a few
    9.61 -  __ push(rdx);
    9.62 -  // compute itable entry offset (in words)
    9.63 -  const int base = instanceKlass::vtable_start_offset() * wordSize;
    9.64 -  assert(vtableEntry::size() * wordSize == 4, "adjust the scaling in the code below");
    9.65 -  __ movl(rdx, Address(rbx, instanceKlass::vtable_length_offset() * wordSize)); // Get length of vtable
    9.66 -  __ lea(rbx, Address(rbx, rdx, Address::times_ptr, base));
    9.67 -  if (HeapWordsPerLong > 1) {
    9.68 -    // Round up to align_object_offset boundary
    9.69 -    __ round_to(rbx, BytesPerLong);
    9.70 -  }
    9.71 -
    9.72 -  Label hit, next, entry, throw_icce;
    9.73 -
    9.74 -  __ jmpb(entry);
    9.75 -
    9.76 -  __ bind(next);
    9.77 -  __ addptr(rbx, itableOffsetEntry::size() * wordSize);
    9.78 -
    9.79 -  __ bind(entry);
    9.80 -
    9.81 -  // If the entry is NULL then we've reached the end of the table
    9.82 -  // without finding the expected interface, so throw an exception
    9.83 -  __ movptr(rdx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes()));
    9.84 -  __ testptr(rdx, rdx);
    9.85 -  __ jcc(Assembler::zero, throw_icce);
    9.86 -  __ cmpptr(rax, rdx);
    9.87 -  __ jcc(Assembler::notEqual, next);
    9.88 -
    9.89 -  // We found a hit, move offset into rbx,
    9.90 -  __ movl(rdx, Address(rbx, itableOffsetEntry::offset_offset_in_bytes()));
    9.91 -
    9.92 -  // Compute itableMethodEntry.
    9.93 -  const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes();
    9.94 +  // Most registers are in use; we'll use rax, rbx, rsi, rdi
    9.95 +  // (If we need to make rsi, rdi callee-save, do a push/pop here.)
    9.96 +  const Register method = rbx;
    9.97 +  Label throw_icce;
    9.98  
    9.99    // Get methodOop and entrypoint for compiler
   9.100 -  const Register method = rbx;
   9.101 -  __ movptr(method, Address(rsi, rdx, Address::times_1, method_offset));
   9.102 -
   9.103 -  // Restore saved register, before possible trap.
   9.104 -  __ pop(rdx);
   9.105 +  __ lookup_interface_method(// inputs: rec. class, interface, itable index
   9.106 +                             rsi, rax, itable_index,
   9.107 +                             // outputs: method, scan temp. reg
   9.108 +                             method, rdi,
   9.109 +                             throw_icce);
   9.110  
   9.111    // method (rbx): methodOop
   9.112    // rcx: receiver
   9.113 @@ -187,12 +171,15 @@
   9.114    __ jmp(Address(method, methodOopDesc::from_compiled_offset()));
   9.115  
   9.116    __ bind(throw_icce);
   9.117 -  // Restore saved register
   9.118 -  __ pop(rdx);
   9.119    __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
   9.120 -
   9.121    masm->flush();
   9.122  
   9.123 +  if (PrintMiscellaneous && (WizardMode || Verbose)) {
   9.124 +    tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
   9.125 +                  itable_index, s->entry_point(),
   9.126 +                  (int)(s->code_end() - s->entry_point()),
   9.127 +                  (int)(s->code_end() - __ pc()));
   9.128 +  }
   9.129    guarantee(__ pc() <= s->code_end(), "overflowed buffer");
   9.130  
   9.131    s->set_exception_points(npe_addr, ame_addr);
   9.132 @@ -207,7 +194,7 @@
   9.133      return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
   9.134    } else {
   9.135      // Itable stub size
   9.136 -    return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0);
   9.137 +    return (DebugVtables ? 256 : 66) + (CountCompiledCalls ? 6 : 0);
   9.138    }
   9.139  }
   9.140  
    10.1 --- a/src/cpu/x86/vm/vtableStubs_x86_64.cpp	Wed Mar 04 09:58:39 2009 -0800
    10.2 +++ b/src/cpu/x86/vm/vtableStubs_x86_64.cpp	Fri Mar 06 21:36:50 2009 -0800
    10.3 @@ -98,17 +98,26 @@
    10.4    __ jmp( Address(rbx, methodOopDesc::from_compiled_offset()));
    10.5  
    10.6    __ flush();
    10.7 +
    10.8 +  if (PrintMiscellaneous && (WizardMode || Verbose)) {
    10.9 +    tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
   10.10 +                  vtable_index, s->entry_point(),
   10.11 +                  (int)(s->code_end() - s->entry_point()),
   10.12 +                  (int)(s->code_end() - __ pc()));
   10.13 +  }
   10.14 +  guarantee(__ pc() <= s->code_end(), "overflowed buffer");
   10.15 +
   10.16    s->set_exception_points(npe_addr, ame_addr);
   10.17    return s;
   10.18  }
   10.19  
   10.20  
   10.21 -VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
   10.22 +VtableStub* VtableStubs::create_itable_stub(int itable_index) {
   10.23    // Note well: pd_code_size_limit is the absolute minimum we can get
   10.24    // away with.  If you add code here, bump the code stub size
   10.25    // returned by pd_code_size_limit!
   10.26    const int amd64_code_length = VtableStub::pd_code_size_limit(false);
   10.27 -  VtableStub* s = new(amd64_code_length) VtableStub(false, vtable_index);
   10.28 +  VtableStub* s = new(amd64_code_length) VtableStub(false, itable_index);
   10.29    ResourceMark rm;
   10.30    CodeBuffer cb(s->entry_point(), amd64_code_length);
   10.31    MacroAssembler* masm = new MacroAssembler(&cb);
   10.32 @@ -131,68 +140,28 @@
   10.33    // get receiver klass (also an implicit null-check)
   10.34    address npe_addr = __ pc();
   10.35  
   10.36 -  __ load_klass(rbx, j_rarg0);
   10.37 +  // Most registers are in use; we'll use rax, rbx, r10, r11
   10.38 +  // (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them)
   10.39 +  __ load_klass(r10, j_rarg0);
   10.40  
   10.41    // If we take a trap while this arg is on the stack we will not
   10.42    // be able to walk the stack properly. This is not an issue except
   10.43    // when there are mistakes in this assembly code that could generate
   10.44    // a spurious fault. Ask me how I know...
   10.45  
   10.46 -  __ push(j_rarg1);     // Most registers are in use, so save one
   10.47 -
   10.48 -  // compute itable entry offset (in words)
   10.49 -  const int base = instanceKlass::vtable_start_offset() * wordSize;
   10.50 -  assert(vtableEntry::size() * wordSize == 8,
   10.51 -         "adjust the scaling in the code below");
   10.52 -  // Get length of vtable
   10.53 -  __ movl(j_rarg1,
   10.54 -          Address(rbx, instanceKlass::vtable_length_offset() * wordSize));
   10.55 -  __ lea(rbx, Address(rbx, j_rarg1, Address::times_8, base));
   10.56 -
   10.57 -  if (HeapWordsPerLong > 1) {
   10.58 -    // Round up to align_object_offset boundary
   10.59 -    __ round_to(rbx, BytesPerLong);
   10.60 -  }
   10.61 -  Label hit, next, entry, throw_icce;
   10.62 -
   10.63 -  __ jmpb(entry);
   10.64 -
   10.65 -  __ bind(next);
   10.66 -  __ addptr(rbx, itableOffsetEntry::size() * wordSize);
   10.67 -
   10.68 -  __ bind(entry);
   10.69 -
   10.70 -  // If the entry is NULL then we've reached the end of the table
   10.71 -  // without finding the expected interface, so throw an exception
   10.72 -  __ movptr(j_rarg1, Address(rbx, itableOffsetEntry::interface_offset_in_bytes()));
   10.73 -  __ testptr(j_rarg1, j_rarg1);
   10.74 -  __ jcc(Assembler::zero, throw_icce);
   10.75 -  __ cmpptr(rax, j_rarg1);
   10.76 -  __ jccb(Assembler::notEqual, next);
   10.77 -
   10.78 -  // We found a hit, move offset into j_rarg1
   10.79 -  __ movl(j_rarg1, Address(rbx, itableOffsetEntry::offset_offset_in_bytes()));
   10.80 -
   10.81 -  // Compute itableMethodEntry
   10.82 -  const int method_offset =
   10.83 -    (itableMethodEntry::size() * wordSize * vtable_index) +
   10.84 -    itableMethodEntry::method_offset_in_bytes();
   10.85 +  const Register method = rbx;
   10.86 +  Label throw_icce;
   10.87  
   10.88    // Get methodOop and entrypoint for compiler
   10.89 -
   10.90 -  // Get klass pointer again
   10.91 -  __ load_klass(rax, j_rarg0);
   10.92 -
   10.93 -  const Register method = rbx;
   10.94 -  __ movptr(method, Address(rax, j_rarg1, Address::times_1, method_offset));
   10.95 -
   10.96 -  // Restore saved register, before possible trap.
   10.97 -  __ pop(j_rarg1);
   10.98 +  __ lookup_interface_method(// inputs: rec. class, interface, itable index
   10.99 +                             r10, rax, itable_index,
  10.100 +                             // outputs: method, scan temp. reg
  10.101 +                             method, r11,
  10.102 +                             throw_icce);
  10.103  
  10.104    // method (rbx): methodOop
  10.105    // j_rarg0: receiver
  10.106  
  10.107 -
  10.108  #ifdef ASSERT
  10.109    if (DebugVtables) {
  10.110      Label L2;
  10.111 @@ -211,12 +180,16 @@
  10.112    __ jmp(Address(method, methodOopDesc::from_compiled_offset()));
  10.113  
  10.114    __ bind(throw_icce);
  10.115 -  // Restore saved register
  10.116 -  __ pop(j_rarg1);
  10.117    __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
  10.118  
  10.119    __ flush();
  10.120  
  10.121 +  if (PrintMiscellaneous && (WizardMode || Verbose)) {
  10.122 +    tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
  10.123 +                  itable_index, s->entry_point(),
  10.124 +                  (int)(s->code_end() - s->entry_point()),
  10.125 +                  (int)(s->code_end() - __ pc()));
  10.126 +  }
  10.127    guarantee(__ pc() <= s->code_end(), "overflowed buffer");
  10.128  
  10.129    s->set_exception_points(npe_addr, ame_addr);
  10.130 @@ -230,7 +203,7 @@
  10.131             (UseCompressedOops ? 16 : 0);  // 1 leaq can be 3 bytes + 1 long
  10.132    } else {
  10.133      // Itable stub size
  10.134 -    return (DebugVtables ? 636 : 72) + (CountCompiledCalls ? 13 : 0) +
  10.135 +    return (DebugVtables ? 512 : 72) + (CountCompiledCalls ? 13 : 0) +
  10.136             (UseCompressedOops ? 32 : 0);  // 2 leaqs
  10.137    }
  10.138  }

mercurial