[aarch64-port-dev ] RFR: Add fast accessors and java.lang.ref.Reference.get

dean long dean.long at oracle.com
Fri Oct 10 04:08:38 UTC 2014


FYI, I believe fast accessors were removed in jdk9.

https://bugs.openjdk.java.net/browse/JDK-8003426

dl

On 10/9/2014 1:32 AM, Edward Nevill wrote:
> Hi,
>
> The following patch adds support for fast accessors and java.lang.ref.Reference.get to the template interpreter.
>
> This probably doesn't add a great deal to overall performance but I think it is worthwhile including for completeness.
>
> Tested with hotspot jtreg.
>
> Best regards,
> Ed.
>
> --- CUT HERE ---
> # HG changeset patch
> # User Edward Nevill edward.nevill at linaro.org
> # Date 1412843164 -3600
> #      Thu Oct 09 09:26:04 2014 +0100
> # Node ID 547811e68a5e8e7fa0e09da2cc64a8e167148178
> # Parent  68cf8e406ce5fefb353901c8bb52882703ab649f
> Add support for fast accessors and java.lang.ref.Reference.get in template interpreter
>
> diff -r 68cf8e406ce5 -r 547811e68a5e src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
> --- a/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp	Wed Sep 24 12:56:10 2014 +0100
> +++ b/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp	Thu Oct 09 09:26:04 2014 +0100
> @@ -664,12 +664,178 @@
>   // Call an accessor method (assuming it is resolved, otherwise drop
>   // into vanilla (slow path) entry
>   address InterpreterGenerator::generate_accessor_entry(void) {
> -  return NULL;
> +  // rmethod: Method*
> +  // r13: senderSP must preserved for slow path
> +  address entry_point = __ pc();
> +
> +  // do fastpath for resolved accessor methods
> +  if (UseFastAccessorMethods) {
> +    // Code: _aload_0, _(i|a)getfield, _(i|a)return or any rewrites
> +    //       thereof; parameter size = 1
> +    // Note: We can only use this code if the getfield has been resolved
> +    //       and if we don't have a null-pointer exception => check for
> +    //       these conditions first and use slow path if necessary.
> +    Label slow_path;
> +    unsigned long offset;
> +    __ adrp(rscratch1, ExternalAddress(SafepointSynchronize::address_of_state()), offset);
> +    __ ldrw(rscratch1, Address(rscratch1, offset));
> +    assert(SafepointSynchronize::_not_synchronized == 0, "rewrite this code");
> +    __ cbnzw(rscratch1, slow_path);
> +
> +    const Register local_0 = c_rarg0;
> +    __ ldr(local_0, Address(esp, 0));
> +    __ cbz(local_0, slow_path);
> +    __ ldr(rscratch1, Address(rmethod, Method::const_offset()));
> +    __ ldr(rscratch2, Address(rscratch1, ConstMethod::constants_offset()));
> +    // Bytecode sequence is <0x2a><0xb4><index>
> +    __ ldrh(rscratch1, Address(rscratch1, in_bytes(ConstMethod::codes_offset()) + 2));
> +    __ lsl(rscratch1, rscratch1, exact_log2(in_words(ConstantPoolCacheEntry::size())));
> +    __ ldr(rscratch2, Address(rscratch2, ConstantPool::cache_offset_in_bytes()));
> +
> +    // check if getfield has been resolved and read constant pool cache entry
> +    // check the validity of the cache entry by testing whether _indices field
> +    // contains Bytecode::_getfield in b1 byte.
> +    assert(in_words(ConstantPoolCacheEntry::size()) == 4, "adjust shift below");
> +    __ add(rscratch2, rscratch2, rscratch1, Assembler::LSL, 3);  // add in cache index
> +
> +    __ ldrb(rscratch1, Address(rscratch2, in_bytes(ConstantPoolCache::base_offset() +
> +                                      ConstantPoolCacheEntry::indices_offset()) + 2));
> +    __ cmpw(rscratch1, Bytecodes::_getfield);
> +    __ br(Assembler::NE, slow_path);
> +
> +    // rscratch1: field_offset
> +    // Note: constant pool entry is not valid before bytecode is resolved
> +    __ ldr(rscratch1, Address(rscratch2, ConstantPoolCache::base_offset() +
> +                                      ConstantPoolCacheEntry::f2_offset()));
> +    // rscratch2: flags
> +    __ ldrw(rscratch2, Address(rscratch2, ConstantPoolCache::base_offset() +
> +                                      ConstantPoolCacheEntry::flags_offset()));
> +
> +    Label notObj, notInt, notByte, notShort;
> +    const Address field_address(local_0, rscratch1);
> +
> +    // Need to differentiate between igetfield, agetfield, bgetfield etc.
> +    // because they are different sizes.
> +    // Use the type from the constant pool cache
> +    __ lsr(rscratch2, rscratch2, ConstantPoolCacheEntry::tos_state_shift);
> +    // Make sure we don't need to mask edx after the above shift
> +    ConstantPoolCacheEntry::verify_tos_state_shift();
> +
> +    // result in c_rarg0
> +    __ andr(sp, r13, -16);  // done with stack
> +
> +    __ cmp(rscratch2, atos);
> +    __ br(Assembler::NE, notObj);
> +    __ load_heap_oop(c_rarg0, field_address);
> +    __ ret(lr);
> +
> +    __ bind(notObj);
> +    __ cmp(rscratch2, itos);
> +    __ br(Assembler::NE, notInt);
> +    __ ldrw(c_rarg0, field_address);
> +    __ ret(lr);
> +
> +    __ bind(notInt);
> +    __ cmp(rscratch2, btos);
> +    __ br(Assembler::NE, notByte);
> +    __ ldrsb(c_rarg0, field_address);
> +    __ ret(lr);
> +
> +    __ bind(notByte);
> +    __ cmp(rscratch2, stos);
> +    __ br(Assembler::NE, notShort);
> +    __ ldrsh(c_rarg0, field_address);
> +    __ ret(lr);
> +
> +    __ bind(notShort);
> +#ifdef ASSERT
> +    Label okay;
> +    __ cmp(rscratch2, ctos);
> +    __ br(Assembler::EQ, okay);
> +    __ stop("what type is this?");
> +    __ bind(okay);
> +#endif
> +    __ ldrh(c_rarg0, field_address);
> +    __ ret(lr);
> +
> +    __ bind(slow_path);
> +  }
> +  (void)generate_normal_entry(false);
> +  return entry_point;
>   }
>   
>   // Method entry for java.lang.ref.Reference.get.
>   address InterpreterGenerator::generate_Reference_get_entry(void) {
> -  return NULL;
> +#if INCLUDE_ALL_GCS
> +  // Code: _aload_0, _getfield, _areturn
> +  // parameter size = 1
> +  //
> +  // The code that gets generated by this routine is split into 2 parts:
> +  //    1. The "intrinsified" code for G1 (or any SATB based GC),
> +  //    2. The slow path - which is an expansion of the regular method entry.
> +  //
> +  // Notes:-
> +  // * In the G1 code we do not check whether we need to block for
> +  //   a safepoint. If G1 is enabled then we must execute the specialized
> +  //   code for Reference.get (except when the Reference object is null)
> +  //   so that we can log the value in the referent field with an SATB
> +  //   update buffer.
> +  //   If the code for the getfield template is modified so that the
> +  //   G1 pre-barrier code is executed when the current method is
> +  //   Reference.get() then going through the normal method entry
> +  //   will be fine.
> +  // * The G1 code can, however, check the receiver object (the instance
> +  //   of java.lang.Reference) and jump to the slow path if null. If the
> +  //   Reference object is null then we obviously cannot fetch the referent
> +  //   and so we don't need to call the G1 pre-barrier. Thus we can use the
> +  //   regular method entry code to generate the NPE.
> +  //
> +  // This code is based on generate_accessor_enty.
> +  //
> +  // rmethod: Method*
> +  // r13: senderSP must preserve for slow path, set SP to it on fast path
> +
> +  address entry = __ pc();
> +
> +  const int referent_offset = java_lang_ref_Reference::referent_offset;
> +  guarantee(referent_offset > 0, "referent offset not initialized");
> +
> +  if (UseG1GC) {
> +    Label slow_path;
> +    const Register local_0 = c_rarg0;
> +    // Check if local 0 != NULL
> +    // If the receiver is null then it is OK to jump to the slow path.
> +    __ ldr(local_0, Address(esp, 0));
> +    __ cbz(local_0, slow_path);
> +
> +
> +    // Load the value of the referent field.
> +    const Address field_address(local_0, referent_offset);
> +    __ load_heap_oop(local_0, field_address);
> +
> +    // Generate the G1 pre-barrier code to log the value of
> +    // the referent field in an SATB buffer.
> +    __ g1_write_barrier_pre(noreg /* obj */,
> +                            local_0 /* pre_val */,
> +                            rthread /* thread */,
> +                            rscratch1 /* tmp */,
> +                            true /* tosca_live */,
> +                            true /* expand_call */);
> +    // areturn
> +    __ andr(sp, r13, -16);  // done with stack
> +    __ ret(lr);
> +
> +    // generate a vanilla interpreter entry as the slow path
> +    __ bind(slow_path);
> +    (void) generate_normal_entry(false);
> +
> +    return entry;
> +  }
> +#endif // INCLUDE_ALL_GCS
> +
> +  // If G1 is not enabled then attempt to go through the accessor entry point
> +  // Reference.get is an accessor
> +  return generate_accessor_entry();
>   }
>   
>   /**
> --- CUT HERE ---
>
>



More information about the aarch64-port-dev mailing list