| /* |
| * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #include "precompiled.hpp" |
| #include "asm/macroAssembler.inline.hpp" |
| #include "interpreter/interp_masm.hpp" |
| #include "interpreter/interpreter.hpp" |
| #include "interpreter/interpreterRuntime.hpp" |
| #include "memory/allocation.inline.hpp" |
| #include "memory/universe.hpp" |
| #include "oops/method.hpp" |
| #include "oops/oop.inline.hpp" |
| #include "runtime/handles.inline.hpp" |
| #include "runtime/icache.hpp" |
| #include "runtime/interfaceSupport.inline.hpp" |
| #include "runtime/signature.hpp" |
| |
| #define __ _masm-> |
| |
| InterpreterRuntime::SignatureHandlerGenerator::SignatureHandlerGenerator( |
| const methodHandle& method, CodeBuffer* buffer) : NativeSignatureIterator(method) { |
| _masm = new MacroAssembler(buffer); |
| _abi_offset = 0; |
| _ireg = is_static() ? 2 : 1; |
| #ifdef __ABI_HARD__ |
| #ifdef AARCH64 |
| _freg = 0; |
| #else |
| _fp_slot = 0; |
| _single_fpr_slot = 0; |
| #endif |
| #endif |
| } |
| |
| #ifdef SHARING_FAST_NATIVE_FINGERPRINTS |
| // mapping from SignatureIterator param to (common) type of parsing |
| static const u1 shared_type[] = { |
| (u1) SignatureIterator::int_parm, // bool |
| (u1) SignatureIterator::int_parm, // byte |
| (u1) SignatureIterator::int_parm, // char |
| (u1) SignatureIterator::int_parm, // short |
| (u1) SignatureIterator::int_parm, // int |
| (u1) SignatureIterator::long_parm, // long |
| #ifndef __ABI_HARD__ |
| (u1) SignatureIterator::int_parm, // float, passed as int |
| (u1) SignatureIterator::long_parm, // double, passed as long |
| #else |
| (u1) SignatureIterator::float_parm, // float |
| (u1) SignatureIterator::double_parm, // double |
| #endif |
| (u1) SignatureIterator::obj_parm, // obj |
| (u1) SignatureIterator::done_parm // done |
| }; |
| |
| uint64_t InterpreterRuntime::normalize_fast_native_fingerprint(uint64_t fingerprint) { |
| if (fingerprint == UCONST64(-1)) { |
| // special signature used when the argument list cannot be encoded in a 64 bits value |
| return fingerprint; |
| } |
| int shift = SignatureIterator::static_feature_size; |
| uint64_t result = fingerprint & ((1 << shift) - 1); |
| fingerprint >>= shift; |
| |
| BasicType ret_type = (BasicType) (fingerprint & SignatureIterator::result_feature_mask); |
| // For ARM, the fast signature handler only needs to know whether |
| // the return value must be unboxed. T_OBJECT and T_ARRAY need not |
| // be distinguished from each other and all other return values |
| // behave like integers with respect to the handler except T_BOOLEAN |
| // which must be mapped to the range 0..1. |
| bool unbox = (ret_type == T_OBJECT) || (ret_type == T_ARRAY); |
| if (unbox) { |
| ret_type = T_OBJECT; |
| } else if (ret_type != T_BOOLEAN) { |
| ret_type = T_INT; |
| } |
| result |= ((uint64_t) ret_type) << shift; |
| shift += SignatureIterator::result_feature_size; |
| fingerprint >>= SignatureIterator::result_feature_size; |
| |
| while (true) { |
| uint32_t type = (uint32_t) (fingerprint & SignatureIterator::parameter_feature_mask); |
| if (type == SignatureIterator::done_parm) { |
| result |= ((uint64_t) SignatureIterator::done_parm) << shift; |
| return result; |
| } |
| assert((type >= SignatureIterator::bool_parm) && (type <= SignatureIterator::obj_parm), "check fingerprint encoding"); |
| int shared = shared_type[type - SignatureIterator::bool_parm]; |
| result |= ((uint64_t) shared) << shift; |
| shift += SignatureIterator::parameter_feature_size; |
| fingerprint >>= SignatureIterator::parameter_feature_size; |
| } |
| } |
| #endif // SHARING_FAST_NATIVE_FINGERPRINTS |
| |
| // Implementation of SignatureHandlerGenerator |
| void InterpreterRuntime::SignatureHandlerGenerator::pass_int() { |
| if (_ireg < GPR_PARAMS) { |
| Register dst = as_Register(_ireg); |
| __ ldr_s32(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| _ireg++; |
| } else { |
| __ ldr_s32(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| __ str_32(Rtemp, Address(SP, _abi_offset * wordSize)); |
| _abi_offset++; |
| } |
| } |
| |
| void InterpreterRuntime::SignatureHandlerGenerator::pass_long() { |
| #ifdef AARCH64 |
| if (_ireg < GPR_PARAMS) { |
| Register dst = as_Register(_ireg); |
| __ ldr(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset() + 1))); |
| _ireg++; |
| } else { |
| __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset() + 1))); |
| __ str(Rtemp, Address(SP, _abi_offset * wordSize)); |
| _abi_offset++; |
| } |
| #else |
| if (_ireg <= 2) { |
| #if (ALIGN_WIDE_ARGUMENTS == 1) |
| if ((_ireg & 1) != 0) { |
| // 64-bit values should be 8-byte aligned |
| _ireg++; |
| } |
| #endif |
| Register dst1 = as_Register(_ireg); |
| Register dst2 = as_Register(_ireg+1); |
| __ ldr(dst1, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()+1))); |
| __ ldr(dst2, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| _ireg += 2; |
| #if (ALIGN_WIDE_ARGUMENTS == 0) |
| } else if (_ireg == 3) { |
| // uses R3 + one stack slot |
| Register dst1 = as_Register(_ireg); |
| __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| __ ldr(dst1, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()+1))); |
| __ str(Rtemp, Address(SP, _abi_offset * wordSize)); |
| _ireg += 1; |
| _abi_offset += 1; |
| #endif |
| } else { |
| #if (ALIGN_WIDE_ARGUMENTS == 1) |
| if(_abi_offset & 1) _abi_offset++; |
| #endif |
| __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()+1))); |
| __ str(Rtemp, Address(SP, (_abi_offset) * wordSize)); |
| __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| __ str(Rtemp, Address(SP, (_abi_offset+1) * wordSize)); |
| _abi_offset += 2; |
| _ireg = 4; |
| } |
| #endif // AARCH64 |
| } |
| |
| void InterpreterRuntime::SignatureHandlerGenerator::pass_object() { |
| #ifdef AARCH64 |
| __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| __ cmp(Rtemp, 0); |
| __ sub(Rtemp, Rlocals, -Interpreter::local_offset_in_bytes(offset())); |
| if (_ireg < GPR_PARAMS) { |
| Register dst = as_Register(_ireg); |
| __ csel(dst, ZR, Rtemp, eq); |
| _ireg++; |
| } else { |
| __ csel(Rtemp, ZR, Rtemp, eq); |
| __ str(Rtemp, Address(SP, _abi_offset * wordSize)); |
| _abi_offset++; |
| } |
| #else |
| if (_ireg < 4) { |
| Register dst = as_Register(_ireg); |
| __ ldr(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| __ cmp(dst, 0); |
| __ sub(dst, Rlocals, -Interpreter::local_offset_in_bytes(offset()), ne); |
| _ireg++; |
| } else { |
| __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| __ cmp(Rtemp, 0); |
| __ sub(Rtemp, Rlocals, -Interpreter::local_offset_in_bytes(offset()), ne); |
| __ str(Rtemp, Address(SP, _abi_offset * wordSize)); |
| _abi_offset++; |
| } |
| #endif // AARCH64 |
| } |
| |
| #ifndef __ABI_HARD__ |
| void InterpreterRuntime::SignatureHandlerGenerator::pass_float() { |
| if (_ireg < 4) { |
| Register dst = as_Register(_ireg); |
| __ ldr(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| _ireg++; |
| } else { |
| __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| __ str(Rtemp, Address(SP, _abi_offset * wordSize)); |
| _abi_offset++; |
| } |
| } |
| |
| #else |
| #ifndef __SOFTFP__ |
| void InterpreterRuntime::SignatureHandlerGenerator::pass_float() { |
| #ifdef AARCH64 |
| if (_freg < FPR_PARAMS) { |
| FloatRegister dst = as_FloatRegister(_freg); |
| __ ldr_s(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| _freg++; |
| } else { |
| __ ldr_u32(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| __ str_32(Rtemp, Address(SP, _abi_offset * wordSize)); |
| _abi_offset++; |
| } |
| #else |
| if((_fp_slot < 16) || (_single_fpr_slot & 1)) { |
| if ((_single_fpr_slot & 1) == 0) { |
| _single_fpr_slot = _fp_slot; |
| _fp_slot += 2; |
| } |
| __ flds(as_FloatRegister(_single_fpr_slot), Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| _single_fpr_slot++; |
| } else { |
| __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| __ str(Rtemp, Address(SP, _abi_offset * wordSize)); |
| _abi_offset++; |
| } |
| #endif // AARCH64 |
| } |
| |
| void InterpreterRuntime::SignatureHandlerGenerator::pass_double() { |
| #ifdef AARCH64 |
| if (_freg < FPR_PARAMS) { |
| FloatRegister dst = as_FloatRegister(_freg); |
| __ ldr_d(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset() + 1))); |
| _freg++; |
| } else { |
| __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset() + 1))); |
| __ str(Rtemp, Address(SP, _abi_offset * wordSize)); |
| _abi_offset++; |
| } |
| #else |
| if(_fp_slot <= 14) { |
| __ fldd(as_FloatRegister(_fp_slot), Address(Rlocals, Interpreter::local_offset_in_bytes(offset()+1))); |
| _fp_slot += 2; |
| } else { |
| __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()+1))); |
| __ str(Rtemp, Address(SP, (_abi_offset) * wordSize)); |
| __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()))); |
| __ str(Rtemp, Address(SP, (_abi_offset+1) * wordSize)); |
| _abi_offset += 2; |
| _single_fpr_slot = 16; |
| } |
| #endif // AARCH64 |
| } |
| #endif // __SOFTFP__ |
| #endif // __ABI_HARD__ |
| |
| void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) { |
| iterate(fingerprint); |
| |
| BasicType result_type = SignatureIterator::return_type(fingerprint); |
| |
| address result_handler = Interpreter::result_handler(result_type); |
| |
| __ mov_slow(R0, (intptr_t)result_handler); |
| |
| __ ret(); |
| } |
| |
| |
| // Implementation of SignatureHandlerLibrary |
| |
| void SignatureHandlerLibrary::pd_set_handler(address handler) {} |
| |
| class SlowSignatureHandler: public NativeSignatureIterator { |
| private: |
| address _from; |
| intptr_t* _to; |
| |
| #ifndef __ABI_HARD__ |
| virtual void pass_int() { |
| *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); |
| _from -= Interpreter::stackElementSize; |
| } |
| |
| virtual void pass_float() { |
| *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); |
| _from -= Interpreter::stackElementSize; |
| } |
| |
| virtual void pass_long() { |
| #if (ALIGN_WIDE_ARGUMENTS == 1) |
| if (((intptr_t)_to & 7) != 0) { |
| // 64-bit values should be 8-byte aligned |
| _to++; |
| } |
| #endif |
| _to[0] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1)); |
| _to[1] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(0)); |
| _to += 2; |
| _from -= 2*Interpreter::stackElementSize; |
| } |
| |
| virtual void pass_object() { |
| intptr_t from_addr = (intptr_t)(_from + Interpreter::local_offset_in_bytes(0)); |
| *_to++ = (*(intptr_t*)from_addr == 0) ? (intptr_t)NULL : from_addr; |
| _from -= Interpreter::stackElementSize; |
| } |
| |
| #else |
| |
| intptr_t* _toFP; |
| intptr_t* _toGP; |
| int _last_gp; |
| int _last_fp; |
| #ifndef AARCH64 |
| int _last_single_fp; |
| #endif // !AARCH64 |
| |
| virtual void pass_int() { |
| if(_last_gp < GPR_PARAMS) { |
| _toGP[_last_gp++] = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); |
| } else { |
| *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); |
| } |
| _from -= Interpreter::stackElementSize; |
| } |
| |
| virtual void pass_long() { |
| #ifdef AARCH64 |
| if(_last_gp < GPR_PARAMS) { |
| _toGP[_last_gp++] = *(jlong *)(_from+Interpreter::local_offset_in_bytes(1)); |
| } else { |
| *_to++ = *(jlong *)(_from+Interpreter::local_offset_in_bytes(1)); |
| } |
| #else |
| assert(ALIGN_WIDE_ARGUMENTS == 1, "ABI_HARD not supported with unaligned wide arguments"); |
| if (_last_gp <= 2) { |
| if(_last_gp & 1) _last_gp++; |
| _toGP[_last_gp++] = *(jint *)(_from+Interpreter::local_offset_in_bytes(1)); |
| _toGP[_last_gp++] = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); |
| } else { |
| if (((intptr_t)_to & 7) != 0) { |
| // 64-bit values should be 8-byte aligned |
| _to++; |
| } |
| _to[0] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1)); |
| _to[1] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(0)); |
| _to += 2; |
| _last_gp = 4; |
| } |
| #endif // AARCH64 |
| _from -= 2*Interpreter::stackElementSize; |
| } |
| |
| virtual void pass_object() { |
| intptr_t from_addr = (intptr_t)(_from + Interpreter::local_offset_in_bytes(0)); |
| if(_last_gp < GPR_PARAMS) { |
| _toGP[_last_gp++] = (*(intptr_t*)from_addr == 0) ? NULL : from_addr; |
| } else { |
| *_to++ = (*(intptr_t*)from_addr == 0) ? NULL : from_addr; |
| } |
| _from -= Interpreter::stackElementSize; |
| } |
| |
| virtual void pass_float() { |
| #ifdef AARCH64 |
| if(_last_fp < FPR_PARAMS) { |
| _toFP[_last_fp++] = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); |
| } else { |
| *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); |
| } |
| #else |
| if((_last_fp < 16) || (_last_single_fp & 1)) { |
| if ((_last_single_fp & 1) == 0) { |
| _last_single_fp = _last_fp; |
| _last_fp += 2; |
| } |
| |
| _toFP[_last_single_fp++] = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); |
| } else { |
| *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); |
| } |
| #endif // AARCH64 |
| _from -= Interpreter::stackElementSize; |
| } |
| |
| virtual void pass_double() { |
| #ifdef AARCH64 |
| if(_last_fp < FPR_PARAMS) { |
| _toFP[_last_fp++] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1)); |
| } else { |
| *_to++ = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1)); |
| } |
| #else |
| assert(ALIGN_WIDE_ARGUMENTS == 1, "ABI_HARD not supported with unaligned wide arguments"); |
| if(_last_fp <= 14) { |
| _toFP[_last_fp++] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1)); |
| _toFP[_last_fp++] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(0)); |
| } else { |
| if (((intptr_t)_to & 7) != 0) { // 64-bit values should be 8-byte aligned |
| _to++; |
| } |
| _to[0] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1)); |
| _to[1] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(0)); |
| _to += 2; |
| _last_single_fp = 16; |
| } |
| #endif // AARCH64 |
| _from -= 2*Interpreter::stackElementSize; |
| } |
| |
| #endif // !__ABI_HARD__ |
| |
| public: |
| SlowSignatureHandler(const methodHandle& method, address from, intptr_t* to) : |
| NativeSignatureIterator(method) { |
| _from = from; |
| |
| #ifdef __ABI_HARD__ |
| _toGP = to; |
| _toFP = _toGP + GPR_PARAMS; |
| _to = _toFP + AARCH64_ONLY(FPR_PARAMS) NOT_AARCH64(8*2); |
| _last_gp = (is_static() ? 2 : 1); |
| _last_fp = 0; |
| #ifndef AARCH64 |
| _last_single_fp = 0; |
| #endif // !AARCH64 |
| #else |
| _to = to + (is_static() ? 2 : 1); |
| #endif // __ABI_HARD__ |
| } |
| }; |
| |
| IRT_ENTRY(address, InterpreterRuntime::slow_signature_handler(JavaThread* thread, Method* method, intptr_t* from, intptr_t* to)) |
| methodHandle m(thread, (Method*)method); |
| assert(m->is_native(), "sanity check"); |
| SlowSignatureHandler(m, (address)from, to).iterate(UCONST64(-1)); |
| return Interpreter::result_handler(m->result_type()); |
| IRT_END |