[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