[aarch64-port-dev ] RFR: Add fast accessors and java.lang.ref.Reference.get
Edward Nevill
edward.nevill at linaro.org
Thu Oct 9 08:32:06 UTC 2014
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