Mercurial > hg > openjdk > aarch64-port > hotspot
changeset 7555:b1e1dda2c069
Add support for fast accessors and java.lang.ref.Reference.get in template interpreter
author | Edward Nevill edward.nevill@linaro.org |
---|---|
date | Thu, 09 Oct 2014 16:39:10 +0100 |
parents | 68cf8e406ce5 |
children | b2bf0d45c617 |
files | src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp |
diffstat | 1 files changed, 170 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- 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 16:39:10 2014 +0100 @@ -664,12 +664,180 @@ // 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. + __ enter(); // g1_write may call runtime + __ g1_write_barrier_pre(noreg /* obj */, + local_0 /* pre_val */, + rthread /* thread */, + rscratch2 /* tmp */, + true /* tosca_live */, + true /* expand_call */); + __ leave(); + // 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(); } /**