Path: blob/master/runtime/compiler/aarch64/codegen/ARM64JNILinkage.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2019, 2022 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "codegen/ARM64JNILinkage.hpp"2324#include <algorithm>25#include "codegen/ARM64HelperCallSnippet.hpp"26#include "codegen/CodeGeneratorUtils.hpp"27#include "codegen/GenerateInstructions.hpp"28#include "codegen/Linkage_inlines.hpp"29#include "codegen/MemoryReference.hpp"30#include "codegen/RegisterDependency.hpp"31#include "codegen/Relocation.hpp"32#include "env/StackMemoryRegion.hpp"33#include "env/VMJ9.h"34#include "il/Node.hpp"35#include "il/Node_inlines.hpp"36#include "il/StaticSymbol.hpp"37#include "il/SymbolReference.hpp"38#include "infra/Assert.hpp"3940#if defined(OSX)41#include "env/j9method.h"42#endif4344J9::ARM64::JNILinkage::JNILinkage(TR::CodeGenerator *cg)45: J9::ARM64::PrivateLinkage(cg)46{47_systemLinkage = cg->getLinkage(TR_System);48}4950int32_t J9::ARM64::JNILinkage::buildArgs(TR::Node *callNode,51TR::RegisterDependencyConditions *dependencies)52{53TR_ASSERT(0, "Should call J9::ARM64::JNILinkage::buildJNIArgs instead.");54return 0;55}5657TR::Register *J9::ARM64::JNILinkage::buildIndirectDispatch(TR::Node *callNode)58{59TR_ASSERT(0, "Calling J9::ARM64::JNILinkage::buildIndirectDispatch does not make sense.");60return NULL;61}6263void J9::ARM64::JNILinkage::buildVirtualDispatch(64TR::Node *callNode,65TR::RegisterDependencyConditions *dependencies,66uint32_t argSize)67{68TR_ASSERT(0, "Calling J9::ARM64::JNILinkage::buildVirtualDispatch does not make sense.");69}7071void J9::ARM64::JNILinkage::releaseVMAccess(TR::Node *callNode, TR::Register *vmThreadReg, TR::Register *scratchReg0, TR::Register *scratchReg1, TR::Register *scratchReg2, TR::Register *scratchReg3)72{73TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(fe());7475// Release VM access (spin lock)76//77// addimmx scratch0, vmThreadReg, #publicFlagsOffset78// movzx scratch1, constReleaseVMAccessOutOfLineMask79//80// dmb ishst81// loopHead:82// ldxrx scratch2, [scratch0]83// tst scratch2, scratch184// b.ne releaseVMAccessSnippet85// andimmx scratch2, scratch2, constReleaseVMAccessMask86// stxrx scratch2, scratch2, [scratch0]87// cbnz scratch2, loopHead88// releaseVMRestart:89//9091const int releaseVMAccessMask = fej9->constReleaseVMAccessMask();9293generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addimmx, callNode, scratchReg0, vmThreadReg, fej9->thisThreadGetPublicFlagsOffset());94loadConstant64(cg(), callNode, fej9->constReleaseVMAccessOutOfLineMask(), scratchReg1);95// dmb ishst (Inner Shareable store barrier)96// Arm Architecture Reference Manual states:97// "This architecture assumes that all PEs that use the same operating system or hypervisor are in the same Inner Shareable shareability domain"98// thus, inner shareable dmb suffices99generateSynchronizationInstruction(cg(), TR::InstOpCode::dmb, callNode, 0xb);100101TR::LabelSymbol *loopHead = generateLabelSymbol(cg());102generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, loopHead);103generateTrg1MemInstruction(cg(), TR::InstOpCode::ldxrx, callNode, scratchReg2, TR::MemoryReference::createWithDisplacement(cg(), scratchReg0, 0));104generateTestInstruction(cg(), callNode, scratchReg2, scratchReg1, true);105106TR::LabelSymbol *releaseVMAccessSnippetLabel = generateLabelSymbol(cg());107TR::LabelSymbol *releaseVMAccessRestartLabel = generateLabelSymbol(cg());108TR::SymbolReference *relVMSymRef = comp()->getSymRefTab()->findOrCreateReleaseVMAccessSymbolRef(comp()->getJittedMethodSymbol());109110TR::Snippet *releaseVMAccessSnippet = new (trHeapMemory()) TR::ARM64HelperCallSnippet(cg(), callNode, releaseVMAccessSnippetLabel, relVMSymRef, releaseVMAccessRestartLabel);111cg()->addSnippet(releaseVMAccessSnippet);112generateConditionalBranchInstruction(cg(), TR::InstOpCode::b_cond, callNode, releaseVMAccessSnippetLabel, TR::CC_NE);113releaseVMAccessSnippet->gcMap().setGCRegisterMask(0);114115uint64_t mask = fej9->constReleaseVMAccessMask();116bool n;117uint32_t imm;118if (logicImmediateHelper(mask, true, n, imm))119{120generateLogicalImmInstruction(cg(), TR::InstOpCode::andimmx, callNode, scratchReg2, scratchReg2, n, imm);121}122else123{124loadConstant64(cg(), callNode, mask, scratchReg3);125generateTrg1Src2Instruction(cg(), TR::InstOpCode::andx, callNode, scratchReg2, scratchReg2, scratchReg3);126}127generateTrg1MemSrc1Instruction(cg(), TR::InstOpCode::stxrx, callNode, scratchReg2, TR::MemoryReference::createWithDisplacement(cg(), scratchReg0, 0), scratchReg2);128generateCompareBranchInstruction(cg(), TR::InstOpCode::cbnzx, callNode, scratchReg2, loopHead);129generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, releaseVMAccessRestartLabel);130}131132void J9::ARM64::JNILinkage::acquireVMAccess(TR::Node *callNode, TR::Register *vmThreadReg, TR::Register *scratchReg0, TR::Register *scratchReg1, TR::Register *scratchReg2)133{134TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(fe());135136// Re-acquire VM access.137// addimmx scratch0, vmThreadReg, #publicFlagsOffset138// movzx scratch1, constAcquireMAccessOutOfLineMask139//140// loopHead:141// ldxrx scratch2, [scratch0]142// cbnzx scratch2, reacquireVMAccessSnippet143// stxrx scratch2, scratch1, [scratch0]144// cbnz scratch2, loopHead145// dmb ishld146// reacquireVMAccessRestartLabel:147//148generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addimmx, callNode, scratchReg0, vmThreadReg, fej9->thisThreadGetPublicFlagsOffset());149loadConstant64(cg(), callNode, fej9->constAcquireVMAccessOutOfLineMask(), scratchReg1);150151TR::LabelSymbol *loopHead = generateLabelSymbol(cg());152generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, loopHead);153generateTrg1MemInstruction(cg(), TR::InstOpCode::ldxrx, callNode, scratchReg2, TR::MemoryReference::createWithDisplacement(cg(), scratchReg0, 0));154155TR::LabelSymbol *reacquireVMAccessSnippetLabel = generateLabelSymbol(cg());156TR::LabelSymbol *reacquireVMAccessRestartLabel = generateLabelSymbol(cg());157TR::SymbolReference *acqVMSymRef = comp()->getSymRefTab()->findOrCreateAcquireVMAccessSymbolRef(comp()->getJittedMethodSymbol());158159TR::Snippet *reacquireVMAccessSnippet = new (trHeapMemory()) TR::ARM64HelperCallSnippet(cg(), callNode, reacquireVMAccessSnippetLabel, acqVMSymRef, reacquireVMAccessRestartLabel);160cg()->addSnippet(reacquireVMAccessSnippet);161generateCompareBranchInstruction(cg(), TR::InstOpCode::cbnzx, callNode, scratchReg2, reacquireVMAccessSnippetLabel);162reacquireVMAccessSnippet->gcMap().setGCRegisterMask(0);163164generateTrg1MemSrc1Instruction(cg(), TR::InstOpCode::stxrx, callNode, scratchReg2, TR::MemoryReference::createWithDisplacement(cg(), scratchReg0, 0), scratchReg1);165generateCompareBranchInstruction(cg(), TR::InstOpCode::cbnzx, callNode, scratchReg2, loopHead);166// dmb ishld (Inner Shareable load barrier)167generateSynchronizationInstruction(cg(), TR::InstOpCode::dmb, callNode, 0x9);168169generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, reacquireVMAccessRestartLabel);170}171172#ifdef J9VM_INTERP_ATOMIC_FREE_JNI173void J9::ARM64::JNILinkage::releaseVMAccessAtomicFree(TR::Node *callNode, TR::Register *vmThreadReg, TR::Register *scratchReg0, TR::Register *scratchReg1)174{175TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(fe());176TR_Debug *debugObj = cg()->getDebug();177178// Release VM access atomic free179//180// movzx scratch0, #1181// strimmx scratch0, [vmThreadReg, #inNativeOffset]182// ldrimmx scratch1, [vmThreadReg, #publicFlagsOffset]183// cmpimmx scratch1, #J9_PUBLIC_FLAGS_VM_ACCESS184// b.ne releaseVMAccessSnippet185// releaseVMAccessRestart:186//187static_assert(static_cast<uint64_t>(J9_PUBLIC_FLAGS_VM_ACCESS) < (1 << 12), "J9_PUBLIC_FLAGS_VM_ACCESS must fit in immediate");188generateTrg1ImmInstruction(cg(), TR::InstOpCode::movzx, callNode, scratchReg0, 1);189#ifdef J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH190auto strInNativeInstr = generateMemSrc1Instruction(cg(), TR::InstOpCode::strimmx, callNode, TR::MemoryReference::createWithDisplacement(cg(), vmThreadReg, offsetof(J9VMThread, inNative)), scratchReg0);191auto ldrPubliFlagsInstr = generateTrg1MemInstruction(cg(), TR::InstOpCode::ldrimmx, callNode, scratchReg1, TR::MemoryReference::createWithDisplacement(cg(), vmThreadReg, fej9->thisThreadGetPublicFlagsOffset()));192#else /* J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH */193generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addimmx, callNode, scratchReg1, vmThreadReg, offsetof(J9VMThread, inNative));194auto strInNativeInstr = generateMemSrc1Instruction(cg(), TR::InstOpCode::stlrx, callNode, TR::MemoryReference::createWithDisplacement(cg(), scratchReg1, 0), scratchReg0);195generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addimmx, callNode, scratchReg0, vmThreadReg, fej9->thisThreadGetPublicFlagsOffset());196auto ldrPubliFlagsInstr = generateTrg1MemInstruction(cg(), TR::InstOpCode::ldarx, callNode, scratchReg1, TR::MemoryReference::createWithDisplacement(cg(), scratchReg0, 0));197#endif198if (debugObj)199{200debugObj->addInstructionComment(strInNativeInstr, "store 1 to vmThread->inNative");201debugObj->addInstructionComment(ldrPubliFlagsInstr, "load vmThread->publicFlags");202}203generateCompareImmInstruction(cg(), callNode, scratchReg1, J9_PUBLIC_FLAGS_VM_ACCESS, true);204205TR::LabelSymbol *releaseVMAccessSnippetLabel = generateLabelSymbol(cg());206TR::LabelSymbol *releaseVMAccessRestartLabel = generateLabelSymbol(cg());207TR::SymbolReference *relVMSymRef = comp()->getSymRefTab()->findOrCreateReleaseVMAccessSymbolRef(comp()->getJittedMethodSymbol());208209TR::Snippet *releaseVMAccessSnippet = new (trHeapMemory()) TR::ARM64HelperCallSnippet(cg(), callNode, releaseVMAccessSnippetLabel, relVMSymRef, releaseVMAccessRestartLabel);210cg()->addSnippet(releaseVMAccessSnippet);211generateConditionalBranchInstruction(cg(), TR::InstOpCode::b_cond, callNode, releaseVMAccessSnippetLabel, TR::CC_NE);212releaseVMAccessSnippet->gcMap().setGCRegisterMask(0);213214generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, releaseVMAccessRestartLabel);215}216217void J9::ARM64::JNILinkage::acquireVMAccessAtomicFree(TR::Node *callNode, TR::Register *vmThreadReg, TR::Register *scratchReg0, TR::Register *zeroReg)218{219TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(fe());220TR_Debug *debugObj = cg()->getDebug();221222// Re-acquire VM access atomic free223// strimmx xzr, [vmThreadReg, #inNativeOffset]224// ldrimmx scratch0, [vmThreadReg, #publicFlagsOffset]225// cmpimmx scratch0, #J9_PUBLIC_FLAGS_VM_ACCESS226// b.ne acquireVMAccessSnippet227// reacquireVMAccessRestart:228//229static_assert(static_cast<uint64_t>(J9_PUBLIC_FLAGS_VM_ACCESS) < (1 << 12), "J9_PUBLIC_FLAGS_VM_ACCESS must fit in immediate");230auto strInNativeInstr = generateMemSrc1Instruction(cg(), TR::InstOpCode::strimmx, callNode, TR::MemoryReference::createWithDisplacement(cg(), vmThreadReg, offsetof(J9VMThread, inNative)), zeroReg);231#ifndef J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH232generateSynchronizationInstruction(cg(), TR::InstOpCode::dmb, callNode, 0xb);233#endif234auto ldrPubliFlagsInstr = generateTrg1MemInstruction(cg(), TR::InstOpCode::ldrimmx, callNode, scratchReg0, TR::MemoryReference::createWithDisplacement(cg(), vmThreadReg, fej9->thisThreadGetPublicFlagsOffset()));235if (debugObj)236{237debugObj->addInstructionComment(strInNativeInstr, "store 0 to vmThread->inNative");238debugObj->addInstructionComment(ldrPubliFlagsInstr, "load vmThread->publicFlags");239}240generateCompareImmInstruction(cg(), callNode, scratchReg0, J9_PUBLIC_FLAGS_VM_ACCESS, true);241242TR::LabelSymbol *reacquireVMAccessSnippetLabel = generateLabelSymbol(cg());243TR::LabelSymbol *reacquireVMAccessRestartLabel = generateLabelSymbol(cg());244TR::SymbolReference *acqVMSymRef = comp()->getSymRefTab()->findOrCreateAcquireVMAccessSymbolRef(comp()->getJittedMethodSymbol());245246TR::Snippet *reacquireVMAccessSnippet = new (trHeapMemory()) TR::ARM64HelperCallSnippet(cg(), callNode, reacquireVMAccessSnippetLabel, acqVMSymRef, reacquireVMAccessRestartLabel);247cg()->addSnippet(reacquireVMAccessSnippet);248generateConditionalBranchInstruction(cg(), TR::InstOpCode::b_cond, callNode, reacquireVMAccessSnippetLabel, TR::CC_NE);249reacquireVMAccessSnippet->gcMap().setGCRegisterMask(0);250251generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, reacquireVMAccessRestartLabel);252}253#endif /* J9VM_INTERP_ATOMIC_FREE_JNI */254255void J9::ARM64::JNILinkage::buildJNICallOutFrame(TR::Node *callNode, bool isWrapperForJNI, TR::LabelSymbol *returnAddrLabel,256TR::Register *vmThreadReg, TR::Register *javaStackReg, TR::Register *scratchReg0, TR::Register *scratchReg1)257{258TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(fe());259260// begin: mask out the magic bit that indicates JIT frames below261loadConstant64(cg(), callNode, 0, scratchReg1);262generateMemSrc1Instruction(cg(), TR::InstOpCode::strimmx, callNode, TR::MemoryReference::createWithDisplacement(cg(), vmThreadReg, fej9->thisThreadGetJavaFrameFlagsOffset()), scratchReg1);263264// Grab 5 slots in the frame.265//266// 4: tag bits (savedA0)267// 3: empty (savedPC)268// 2: return address in this frame (savedCP)269// 1: frame flags270// 0: RAM method271//272// push tag bits (savedA0)273int32_t tagBits = fej9->constJNICallOutFrameSpecialTag();274// if the current method is simply a wrapper for the JNI call, hide the call-out stack frame275if (isWrapperForJNI)276tagBits |= fej9->constJNICallOutFrameInvisibleTag();277loadConstant64(cg(), callNode, tagBits, scratchReg0);278279generateMemSrc1Instruction(cg(), TR::InstOpCode::strprex, callNode, TR::MemoryReference::createWithDisplacement(cg(), javaStackReg, -TR::Compiler->om.sizeofReferenceAddress()), scratchReg0);280281// empty saved pc slot282generateMemSrc1Instruction(cg(), TR::InstOpCode::strprex, callNode, TR::MemoryReference::createWithDisplacement(cg(), javaStackReg, -TR::Compiler->om.sizeofReferenceAddress()), scratchReg1);283284// push return address (savedCP)285generateTrg1ImmSymInstruction(cg(), TR::InstOpCode::adr, callNode, scratchReg0, 0, returnAddrLabel);286generateMemSrc1Instruction(cg(), TR::InstOpCode::strprex, callNode, TR::MemoryReference::createWithDisplacement(cg(), javaStackReg, -TR::Compiler->om.sizeofReferenceAddress()), scratchReg0);287288// push flags289loadConstant64(cg(), callNode, fej9->constJNICallOutFrameFlags(), scratchReg0);290generateMemSrc1Instruction(cg(), TR::InstOpCode::strprex, callNode, TR::MemoryReference::createWithDisplacement(cg(), javaStackReg, -TR::Compiler->om.sizeofReferenceAddress()), scratchReg0);291292TR::ResolvedMethodSymbol *resolvedMethodSymbol = callNode->getSymbol()->castToResolvedMethodSymbol();293TR_ResolvedMethod *resolvedMethod = resolvedMethodSymbol->getResolvedMethod();294uintptr_t methodAddr = reinterpret_cast<uintptr_t>(resolvedMethod->resolvedMethodAddress());295296// push the RAM method for the native297if (fej9->needClassAndMethodPointerRelocations())298{299// load a 64-bit constant into a register with a fixed 4 instruction sequence300TR::Instruction *firstInstruction = generateTrg1ImmInstruction(cg(), TR::InstOpCode::movzx, callNode, scratchReg0, methodAddr & 0x0000ffff);301generateTrg1ImmInstruction(cg(), TR::InstOpCode::movkx, callNode, scratchReg0, ((methodAddr >> 16) & 0x0000ffff) | TR::MOV_LSL16);302generateTrg1ImmInstruction(cg(), TR::InstOpCode::movkx, callNode, scratchReg0, ((methodAddr >> 32) & 0x0000ffff) | TR::MOV_LSL32);303generateTrg1ImmInstruction(cg(), TR::InstOpCode::movkx, callNode, scratchReg0, (methodAddr >> 48) | TR::MOV_LSL48);304305TR_ExternalRelocationTargetKind reloType;306if (resolvedMethodSymbol->isSpecial())307reloType = TR_SpecialRamMethodConst;308else if (resolvedMethodSymbol->isStatic())309reloType = TR_StaticRamMethodConst;310else if (resolvedMethodSymbol->isVirtual())311reloType = TR_VirtualRamMethodConst;312else313{314reloType = TR_NoRelocation;315TR_ASSERT(0, "JNI relocation not supported.");316}317cg()->addExternalRelocation(new (trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(318firstInstruction,319reinterpret_cast<uint8_t *>(callNode->getSymbolReference()),320reinterpret_cast<uint8_t *>(callNode->getInlinedSiteIndex()),321reloType, cg()),322__FILE__,__LINE__, callNode);323324}325else326{327loadConstant64(cg(), callNode, methodAddr, scratchReg0);328}329generateMemSrc1Instruction(cg(), TR::InstOpCode::strprex, callNode, TR::MemoryReference::createWithDisplacement(cg(), javaStackReg, -TR::Compiler->om.sizeofReferenceAddress()), scratchReg0);330331// store out java sp332generateMemSrc1Instruction(cg(), TR::InstOpCode::strimmx, callNode, TR::MemoryReference::createWithDisplacement(cg(), vmThreadReg, fej9->thisThreadGetJavaSPOffset()), javaStackReg);333334// store out pc and literals values indicating the callout frame335loadConstant64(cg(), callNode, fej9->constJNICallOutFrameType(), scratchReg0);336generateMemSrc1Instruction(cg(), TR::InstOpCode::strimmx, callNode, TR::MemoryReference::createWithDisplacement(cg(), vmThreadReg, fej9->thisThreadGetJavaPCOffset()), scratchReg0);337338generateMemSrc1Instruction(cg(), TR::InstOpCode::strimmx, callNode, TR::MemoryReference::createWithDisplacement(cg(), vmThreadReg, fej9->thisThreadGetJavaLiteralsOffset()), scratchReg1);339340}341342void J9::ARM64::JNILinkage::restoreJNICallOutFrame(TR::Node *callNode, bool tearDownJNIFrame, TR::Register *vmThreadReg, TR::Register *javaStackReg, TR::Register *scratchReg)343{344TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(fe());345346// restore stack pointer: need to deal with growable stack -- stack may already be moved.347generateTrg1MemInstruction(cg(), TR::InstOpCode::ldrimmx, callNode, scratchReg, TR::MemoryReference::createWithDisplacement(cg(), vmThreadReg, fej9->thisThreadGetJavaLiteralsOffset()));348generateTrg1MemInstruction(cg(),TR::InstOpCode::ldrimmx, callNode, javaStackReg, TR::MemoryReference::createWithDisplacement(cg(), vmThreadReg, fej9->thisThreadGetJavaSPOffset()));349generateTrg1Src2Instruction(cg(), TR::InstOpCode::addx, callNode, javaStackReg, scratchReg, javaStackReg);350351if (tearDownJNIFrame)352{353// must check to see if the ref pool was used and clean them up if so--or we354// leave a bunch of pinned garbage behind that screws up the gc quality forever355TR::LabelSymbol *refPoolRestartLabel = generateLabelSymbol(cg());356TR::LabelSymbol *refPoolSnippetLabel = generateLabelSymbol(cg());357TR::SymbolReference *collapseSymRef = cg()->getSymRefTab()->findOrCreateRuntimeHelper(TR_ARM64jitCollapseJNIReferenceFrame);358TR::Snippet *snippet = new (trHeapMemory()) TR::ARM64HelperCallSnippet(cg(), callNode, refPoolSnippetLabel, collapseSymRef, refPoolRestartLabel);359cg()->addSnippet(snippet);360generateTrg1MemInstruction(cg(), TR::InstOpCode::ldrimmx, callNode, scratchReg, TR::MemoryReference::createWithDisplacement(cg(), javaStackReg, fej9->constJNICallOutFrameFlagsOffset()));361362TR_ASSERT_FATAL(fej9->constJNIReferenceFrameAllocatedFlags() == 0x30000, "constJNIReferenceFrameAllocatedFlags must be 0x30000");363generateTestImmInstruction(cg(), callNode, scratchReg, 0x401, false); // 0x401 is immr:imms for 0x30000364generateConditionalBranchInstruction(cg(), TR::InstOpCode::b_cond, callNode, refPoolSnippetLabel, TR::CC_NE);365generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, refPoolRestartLabel);366}367368// Restore the JIT frame369generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addimmx, callNode, javaStackReg, javaStackReg, 5*TR::Compiler->om.sizeofReferenceAddress());370}371372373size_t J9::ARM64::JNILinkage::buildJNIArgs(TR::Node *callNode, TR::RegisterDependencyConditions *dependencies, bool passThread, bool passReceiver, bool killNonVolatileGPRs)374{375const TR::ARM64LinkageProperties &properties = _systemLinkage->getProperties();376TR::ARM64MemoryArgument *pushToMemory = NULL;377TR::Register *argMemReg;378TR::Register *tempReg;379int32_t argIndex = 0;380int32_t numMemArgs = 0;381int32_t argOffset = 0;382int32_t numIntegerArgs = 0;383int32_t numFloatArgs = 0;384int32_t totalSize = 0;385int32_t i;386387TR::Node *child;388TR::DataType childType;389TR::DataType resType = callNode->getType();390391#if defined(OSX)392TR::SymbolReference *methodSymRef = callNode->getSymbolReference();393TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();394TR::Method *method = methodSymbol->getMethod();395const char *sig = method->signatureChars();396int32_t sigLen = method->signatureLength();397char *sigCursor = (char *)sig;398#endif399400uint32_t firstArgumentChild = callNode->getFirstArgumentIndex();401if (passThread)402{403numIntegerArgs += 1;404}405// if fastJNI do not pass the receiver just evaluate the first child406if (!passReceiver)407{408TR::Node *firstArgChild = callNode->getChild(firstArgumentChild);409cg()->evaluate(firstArgChild);410cg()->decReferenceCount(firstArgChild);411firstArgumentChild += 1;412}413/* Step 1 - figure out how many arguments are going to be spilled to memory i.e. not in registers */414for (i = firstArgumentChild; i < callNode->getNumChildren(); i++)415{416child = callNode->getChild(i);417childType = child->getDataType();418419switch (childType)420{421case TR::Int8:422case TR::Int16:423case TR::Int32:424case TR::Int64:425case TR::Address:426if (numIntegerArgs >= properties.getNumIntArgRegs())427{428numMemArgs++;429#if defined(LINUX)430totalSize += 8;431#elif defined(OSX)432TR::DataType nativeType = OMR::Symbol::convertSigCharToType(*sigCursor);433int32_t nativeTypeSize = TR::DataType::getSize(nativeType);434if (nativeTypeSize > 1)435{436totalSize = (totalSize + nativeTypeSize - 1) & ~(nativeTypeSize - 1);437}438totalSize += nativeTypeSize;439#else440#error Unsupported platform441#endif442}443numIntegerArgs++;444break;445446case TR::Float:447case TR::Double:448if (numFloatArgs >= properties.getNumFloatArgRegs())449{450numMemArgs++;451#if defined(LINUX)452totalSize += 8;453#elif defined(OSX)454if (childType == TR::Double)455{456totalSize = (totalSize + 7) & ~7; // adjust to 8-byte boundary457totalSize += 8;458}459else460{461totalSize += 4;462}463#else464#error Unsupported platform465#endif466}467numFloatArgs++;468break;469470default:471TR_ASSERT(false, "Argument type %s is not supported\n", childType.toString());472}473474#if defined(OSX)475sigCursor = nextSignatureArgument(sigCursor);476#endif477}478479// From here, down, any new stack allocations will expire / die when the function returns480TR::StackMemoryRegion stackMemoryRegion(*trMemory());481/* End result of Step 1 - determined number of memory arguments! */482if (numMemArgs > 0)483{484pushToMemory = new (trStackMemory()) TR::ARM64MemoryArgument[numMemArgs];485486argMemReg = cg()->allocateRegister();487}488489// align to 16-byte boundary490totalSize = (totalSize + 15) & (~15);491492numIntegerArgs = 0;493numFloatArgs = 0;494495if (passThread)496{497// first argument is JNIenv498numIntegerArgs += 1;499}500501#if defined(OSX)502sigCursor = (char *)sig;503#endif504505for (i = firstArgumentChild; i < callNode->getNumChildren(); i++)506{507TR::Register *argRegister;508TR::InstOpCode::Mnemonic op;509bool checkSplit = true;510511child = callNode->getChild(i);512childType = child->getDataType();513514switch (childType)515{516case TR::Int8:517case TR::Int16:518case TR::Int32:519case TR::Int64:520case TR::Address:521if (childType == TR::Address)522{523argRegister = pushJNIReferenceArg(child);524checkSplit = false;525}526else if (childType == TR::Int64)527argRegister = pushLongArg(child);528else529argRegister = pushIntegerWordArg(child);530531if (numIntegerArgs < properties.getNumIntArgRegs())532{533if (checkSplit && !cg()->canClobberNodesRegister(child, 0))534{535if (argRegister->containsCollectedReference())536tempReg = cg()->allocateCollectedReferenceRegister();537else538tempReg = cg()->allocateRegister();539generateMovInstruction(cg(), callNode, tempReg, argRegister);540argRegister = tempReg;541}542if (numIntegerArgs == 0 &&543(resType.isAddress() || resType.isInt32() || resType.isInt64()))544{545TR::Register *resultReg;546if (resType.isAddress())547resultReg = cg()->allocateCollectedReferenceRegister();548else549resultReg = cg()->allocateRegister();550551dependencies->addPreCondition(argRegister, TR::RealRegister::x0);552dependencies->addPostCondition(resultReg, TR::RealRegister::x0);553}554else555{556TR::addDependency(dependencies, argRegister, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());557}558}559else560{561// numIntegerArgs >= properties.getNumIntArgRegs()562int offsetInc;563#if defined(LINUX)564offsetInc = 8; // always 8-byte aligned565op = (childType == TR::Address || childType == TR::Int64) ?566TR::InstOpCode::strimmx : TR::InstOpCode::strimmw;567#elif defined(OSX)568TR::DataType nativeType = OMR::Symbol::convertSigCharToType(*sigCursor);569int32_t nativeTypeSize = TR::DataType::getSize(nativeType);570offsetInc = nativeTypeSize;571if (nativeTypeSize > 1)572{573argOffset = (argOffset + nativeTypeSize - 1) & ~(nativeTypeSize - 1);574}575switch (nativeTypeSize)576{577case 8:578op = TR::InstOpCode::strimmx;579break;580case 4:581op = TR::InstOpCode::strimmw;582break;583case 2:584op = TR::InstOpCode::strhimm;585break;586case 1:587op = TR::InstOpCode::strbimm;588break;589}590#else591#error Unsupported platform592#endif593getOutgoingArgumentMemRef(argMemReg, argOffset, argRegister, op, pushToMemory[argIndex++]);594argOffset += offsetInc;595}596numIntegerArgs++;597break;598599case TR::Float:600case TR::Double:601if (childType == TR::Float)602argRegister = pushFloatArg(child);603else604argRegister = pushDoubleArg(child);605606if (numFloatArgs < properties.getNumFloatArgRegs())607{608if (!cg()->canClobberNodesRegister(child, 0))609{610tempReg = cg()->allocateRegister(TR_FPR);611op = (childType == TR::Float) ? TR::InstOpCode::fmovs : TR::InstOpCode::fmovd;612generateTrg1Src1Instruction(cg(), op, callNode, tempReg, argRegister);613argRegister = tempReg;614}615if ((numFloatArgs == 0 && resType.isFloatingPoint()))616{617TR::Register *resultReg;618if (resType.getDataType() == TR::Float)619resultReg = cg()->allocateSinglePrecisionRegister();620else621resultReg = cg()->allocateRegister(TR_FPR);622623dependencies->addPreCondition(argRegister, TR::RealRegister::v0);624dependencies->addPostCondition(resultReg, TR::RealRegister::v0);625}626else627{628TR::addDependency(dependencies, argRegister, properties.getFloatArgumentRegister(numFloatArgs), TR_FPR, cg());629}630}631else632{633// numFloatArgs >= properties.getNumFloatArgRegs()634int offsetInc;635if (childType == TR::Double)636{637op = TR::InstOpCode::vstrimmd;638offsetInc = 8;639#if defined(OSX)640argOffset = (argOffset + 7) & ~7; // adjust to 8-byte boundary641#endif642}643else644{645op = TR::InstOpCode::vstrimms;646#if defined(LINUX)647offsetInc = 8;648#elif defined(OSX)649offsetInc = 4;650#else651#error Unsupported platform652#endif653}654getOutgoingArgumentMemRef(argMemReg, argOffset, argRegister, op, pushToMemory[argIndex++]);655argOffset += offsetInc;656}657numFloatArgs++;658break;659} // end of switch660661#if defined(OSX)662sigCursor = nextSignatureArgument(sigCursor);663#endif664} // end of for665666for (int32_t i = TR::RealRegister::FirstGPR; i <= TR::RealRegister::LastGPR; ++i)667{668TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)i;669if (getProperties().getRegisterFlags(realReg) & ARM64_Reserved)670{671continue;672}673if (properties.getPreserved(realReg))674{675if (killNonVolatileGPRs)676{677// We release VM access around the native call,678// so even though the callee's linkage won't alter a679// given register, we still have a problem if a stack walk needs to680// inspect/modify that register because once we're in C-land, we have681// no idea where that regsiter's value is located. Therefore, we need682// to spill even the callee-saved registers around the call.683//684// In principle, we only need to do this for registers that contain685// references. However, at this location in the code, we don't yet686// know which real registers those would be. Tragically, this causes687// us to save/restore ALL preserved registers in any method containing688// a JNI call.689TR::addDependency(dependencies, NULL, realReg, TR_GPR, cg());690}691continue;692}693694if (!dependencies->searchPreConditionRegister(realReg))695{696if (realReg == properties.getIntegerArgumentRegister(0) && callNode->getDataType() == TR::Address)697{698dependencies->addPreCondition(cg()->allocateRegister(), TR::RealRegister::x0);699dependencies->addPostCondition(cg()->allocateCollectedReferenceRegister(), TR::RealRegister::x0);700}701else702{703TR::addDependency(dependencies, NULL, realReg, TR_GPR, cg());704}705}706}707708int32_t floatRegsUsed = std::min<int32_t>(numFloatArgs, properties.getNumFloatArgRegs());709for (i = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::v0 + floatRegsUsed); i <= TR::RealRegister::LastFPR; i++)710{711if (!properties.getPreserved((TR::RealRegister::RegNum)i))712{713// NULL dependency for non-preserved regs714TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)i, TR_FPR, cg());715}716}717718/* Spills all vector registers */719if (killsVectorRegisters())720{721TR::Register *tmpReg = cg()->allocateRegister();722dependencies->addPostCondition(tmpReg, TR::RealRegister::KillVectorRegs);723cg()->stopUsingRegister(tmpReg);724}725726if (numMemArgs > 0)727{728TR::RealRegister *sp = cg()->machine()->getRealRegister(properties.getStackPointerRegister());729generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::subimmx, callNode, argMemReg, sp, totalSize);730731for (argIndex = 0; argIndex < numMemArgs; argIndex++)732{733TR::Register *aReg = pushToMemory[argIndex].argRegister;734generateMemSrc1Instruction(cg(), pushToMemory[argIndex].opCode, callNode, pushToMemory[argIndex].argMemory, aReg);735cg()->stopUsingRegister(aReg);736}737738cg()->stopUsingRegister(argMemReg);739}740741return totalSize;742}743744TR::Register *J9::ARM64::JNILinkage::getReturnRegisterFromDeps(TR::Node *callNode, TR::RegisterDependencyConditions *deps)745{746const TR::ARM64LinkageProperties &pp = _systemLinkage->getProperties();747TR::Register *retReg;748749switch(callNode->getOpCodeValue())750{751case TR::icall:752retReg = deps->searchPostConditionRegister(753pp.getIntegerReturnRegister());754break;755case TR::lcall:756case TR::acall:757retReg = deps->searchPostConditionRegister(758pp.getLongReturnRegister());759break;760case TR::fcall:761case TR::dcall:762retReg = deps->searchPostConditionRegister(763pp.getFloatReturnRegister());764break;765case TR::call:766retReg = NULL;767break;768default:769retReg = NULL;770TR_ASSERT_FATAL(false, "Unsupported direct call Opcode.");771}772return retReg;773}774775TR::Register *J9::ARM64::JNILinkage::pushJNIReferenceArg(TR::Node *child)776{777TR::Register *pushRegister;778bool checkSplit = true;779780if (child->getOpCodeValue() == TR::loadaddr)781{782TR::SymbolReference * symRef = child->getSymbolReference();783TR::StaticSymbol *sym = symRef->getSymbol()->getStaticSymbol();784if (sym)785{786if (sym->isAddressOfClassObject())787{788pushRegister = pushAddressArg(child);789}790else791{792TR::Register *addrReg = cg()->evaluate(child);793TR::MemoryReference *tmpMemRef = TR::MemoryReference::createWithDisplacement(cg(), addrReg, (int32_t)0);794TR::Register *whatReg = cg()->allocateCollectedReferenceRegister();795796checkSplit = false;797generateTrg1MemInstruction(cg(), TR::InstOpCode::ldrimmx, child, whatReg, tmpMemRef);798if (!cg()->canClobberNodesRegister(child))799{800// Since this is a static variable, it is non-collectable.801TR::Register *tempRegister = cg()->allocateRegister();802generateMovInstruction(cg(), child, tempRegister, addrReg);803pushRegister = tempRegister;804}805else806pushRegister = addrReg;807generateCompareImmInstruction(cg(), child, whatReg, 0, true);808generateCondTrg1Src2Instruction(cg(), TR::InstOpCode::cselx, child, pushRegister, pushRegister, whatReg, TR::CC_NE);809810cg()->stopUsingRegister(whatReg);811cg()->decReferenceCount(child);812}813}814else // must be loadaddr of parm or local815{816if (child->pointsToNonNull())817{818pushRegister = pushAddressArg(child);819}820else if (child->pointsToNull())821{822checkSplit = false;823pushRegister = cg()->allocateRegister();824loadConstant64(cg(), child, 0, pushRegister);825cg()->decReferenceCount(child);826}827else828{829TR::Register *addrReg = cg()->evaluate(child);830TR::MemoryReference *tmpMemRef = TR::MemoryReference::createWithDisplacement(cg(), addrReg, (int32_t)0);831TR::Register *whatReg = cg()->allocateCollectedReferenceRegister();832833checkSplit = false;834generateTrg1MemInstruction(cg(), TR::InstOpCode::ldrimmx, child, whatReg, tmpMemRef);835if (!cg()->canClobberNodesRegister(child))836{837// Since this points at a parm or local location, it is non-collectable.838TR::Register *tempRegister = cg()->allocateRegister();839generateMovInstruction(cg(), child, tempRegister, addrReg);840pushRegister = tempRegister;841}842else843pushRegister = addrReg;844generateCompareImmInstruction(cg(), child, whatReg, 0, true);845generateCondTrg1Src2Instruction(cg(), TR::InstOpCode::cselx, child, pushRegister, pushRegister, whatReg, TR::CC_NE);846847cg()->stopUsingRegister(whatReg);848cg()->decReferenceCount(child);849}850}851}852else853{854pushRegister = pushAddressArg(child);855}856857if (checkSplit && !cg()->canClobberNodesRegister(child, 0))858{859TR::Register *tempReg = pushRegister->containsCollectedReference()?860cg()->allocateCollectedReferenceRegister():cg()->allocateRegister();861generateMovInstruction(cg(), child, tempReg, pushRegister);862pushRegister = tempReg;863}864return pushRegister;865}866867void J9::ARM64::JNILinkage::adjustReturnValue(TR::Node *callNode, bool wrapRefs, TR::Register *returnRegister)868{869TR::SymbolReference *callSymRef = callNode->getSymbolReference();870TR::ResolvedMethodSymbol *callSymbol = callNode->getSymbol()->castToResolvedMethodSymbol();871TR_ResolvedMethod *resolvedMethod = callSymbol->getResolvedMethod();872873// jni methods may not return a full register in some cases so need to get the declared874// type so that we sign and zero extend the narrower integer return types properly875TR::LabelSymbol *tempLabel = generateLabelSymbol(cg());876877switch (resolvedMethod->returnType())878{879case TR::Address:880if (wrapRefs)881{882// unwrap when the returned object is non-null883generateCompareBranchInstruction(cg(),TR::InstOpCode::cbzx, callNode, returnRegister, tempLabel);884generateTrg1MemInstruction(cg(), TR::InstOpCode::ldrimmx, callNode, returnRegister, TR::MemoryReference::createWithDisplacement(cg(), returnRegister, 0));885generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, tempLabel);886}887break;888case TR::Int8:889if (comp()->getSymRefTab()->isReturnTypeBool(callSymRef))890{891// For bool return type, must check whether value return by892// JNI is zero (false) or non-zero (true) to yield Java result893generateCompareImmInstruction(cg(), callNode, returnRegister, 0);894generateCSetInstruction(cg(), callNode, returnRegister, TR::CC_NE);895}896else if (resolvedMethod->returnTypeIsUnsigned())897{898// 7 in immr:imms means 0xff899generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::andimmw, callNode, returnRegister, returnRegister, 7);900}901else902{903// sxtb (sign extend byte)904generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::sbfmw, callNode, returnRegister, returnRegister, 7);905}906break;907case TR::Int16:908if (resolvedMethod->returnTypeIsUnsigned())909{910// 0xf in immr:imms means 0xffff911generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::andimmw, callNode, returnRegister, returnRegister, 0xf);912}913else914{915// sxth (sign extend halfword)916generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::sbfmw, callNode, returnRegister, returnRegister, 0xf);917}918break;919}920}921922void J9::ARM64::JNILinkage::checkForJNIExceptions(TR::Node *callNode, TR::Register *vmThreadReg, TR::Register *scratchReg)923{924TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(fe());925926generateTrg1MemInstruction(cg(),TR::InstOpCode::ldrimmx, callNode, scratchReg, TR::MemoryReference::createWithDisplacement(cg(), vmThreadReg, fej9->thisThreadGetCurrentExceptionOffset()));927928TR::SymbolReference *throwSymRef = cg()->getSymRefTab()->findOrCreateThrowCurrentExceptionSymbolRef(comp()->getJittedMethodSymbol());929TR::LabelSymbol *exceptionSnippetLabel = generateLabelSymbol(cg());930TR::Snippet *snippet = new (trHeapMemory()) TR::ARM64HelperCallSnippet(cg(), callNode, exceptionSnippetLabel, throwSymRef);931cg()->addSnippet(snippet);932TR::Instruction *gcPoint = generateCompareBranchInstruction(cg(),TR::InstOpCode::cbnzx, callNode, scratchReg, exceptionSnippetLabel);933// x0 may contain a reference returned by JNI method934snippet->gcMap().setGCRegisterMask(1);935}936937TR::Instruction *J9::ARM64::JNILinkage::generateMethodDispatch(TR::Node *callNode, bool isJNIGCPoint,938TR::RegisterDependencyConditions *deps, uintptr_t targetAddress, TR::Register *scratchReg)939{940TR::ResolvedMethodSymbol *resolvedMethodSymbol = callNode->getSymbol()->castToResolvedMethodSymbol();941TR_ResolvedMethod *resolvedMethod = resolvedMethodSymbol->getResolvedMethod();942TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(fe());943944// load a 64-bit constant into a register with a fixed 4 instruction sequence945TR::Instruction *firstInstruction = generateTrg1ImmInstruction(cg(), TR::InstOpCode::movzx, callNode, scratchReg, targetAddress & 0x0000ffff);946generateTrg1ImmInstruction(cg(), TR::InstOpCode::movkx, callNode, scratchReg, ((targetAddress >> 16) & 0x0000ffff) | TR::MOV_LSL16);947generateTrg1ImmInstruction(cg(), TR::InstOpCode::movkx, callNode, scratchReg, ((targetAddress >> 32) & 0x0000ffff) | TR::MOV_LSL32);948generateTrg1ImmInstruction(cg(), TR::InstOpCode::movkx, callNode, scratchReg, (targetAddress >> 48) | TR::MOV_LSL48);949950if (fej9->needClassAndMethodPointerRelocations())951{952TR_ExternalRelocationTargetKind reloType;953if (resolvedMethodSymbol->isSpecial())954reloType = TR_JNISpecialTargetAddress;955else if (resolvedMethodSymbol->isStatic())956reloType = TR_JNIStaticTargetAddress;957else if (resolvedMethodSymbol->isVirtual())958reloType = TR_JNIVirtualTargetAddress;959else960{961reloType = TR_NoRelocation;962TR_ASSERT(0, "JNI relocation not supported.");963}964965TR_RelocationRecordInformation *info = new (comp()->trHeapMemory()) TR_RelocationRecordInformation();966info->data1 = 0;967info->data2 = reinterpret_cast<uintptr_t>(callNode->getSymbolReference());968info->data3 = static_cast<uintptr_t>(callNode->getInlinedSiteIndex());969970cg()->addExternalRelocation(971new (trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(972firstInstruction,973reinterpret_cast<uint8_t *>(info),974reloType,975cg()),976__FILE__,__LINE__, callNode);977}978979// Add the first instruction of address materialization sequence to JNI call sites980cg()->getJNICallSites().push_front(new (trHeapMemory()) TR_Pair<TR_ResolvedMethod, TR::Instruction>(resolvedMethod, firstInstruction));981982TR::Instruction *gcPoint = generateRegBranchInstruction(cg(), TR::InstOpCode::blr, callNode, scratchReg, deps);983if (isJNIGCPoint)984{985// preserved registers are killed986gcPoint->ARM64NeedsGCMap(cg(), 0);987}988return gcPoint;989}990991TR::Register *J9::ARM64::JNILinkage::buildDirectDispatch(TR::Node *callNode)992{993TR::LabelSymbol *returnLabel = generateLabelSymbol(cg());994TR::SymbolReference *callSymRef = callNode->getSymbolReference();995TR::MethodSymbol *callSymbol = callSymRef->getSymbol()->castToMethodSymbol();996TR::ResolvedMethodSymbol *resolvedMethodSymbol = callNode->getSymbol()->castToResolvedMethodSymbol();997TR_ResolvedMethod *resolvedMethod = resolvedMethodSymbol->getResolvedMethod();998uintptr_t targetAddress = reinterpret_cast<uintptr_t>(resolvedMethod->startAddressForJNIMethod(comp()));999TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(fe());10001001bool dropVMAccess = !fej9->jniRetainVMAccess(resolvedMethod);1002bool isJNIGCPoint = !fej9->jniNoGCPoint(resolvedMethod);1003bool killNonVolatileGPRs = isJNIGCPoint;1004bool checkExceptions = !fej9->jniNoExceptionsThrown(resolvedMethod);1005bool createJNIFrame = !fej9->jniNoNativeMethodFrame(resolvedMethod);1006bool tearDownJNIFrame = !fej9->jniNoSpecialTeardown(resolvedMethod);1007bool wrapRefs = !fej9->jniDoNotWrapObjects(resolvedMethod);1008bool passReceiver = !fej9->jniDoNotPassReceiver(resolvedMethod);1009bool passThread = !fej9->jniDoNotPassThread(resolvedMethod);10101011if (resolvedMethodSymbol->canDirectNativeCall())1012{1013dropVMAccess = false;1014killNonVolatileGPRs = false;1015isJNIGCPoint = false;1016checkExceptions = false;1017createJNIFrame = false;1018tearDownJNIFrame = false;1019}1020else if (resolvedMethodSymbol->isPureFunction())1021{1022dropVMAccess = false;1023isJNIGCPoint = false;1024checkExceptions = false;1025}10261027cg()->machine()->setLinkRegisterKilled(true);10281029const int maxRegisters = getProperties()._numAllocatableIntegerRegisters + getProperties()._numAllocatableFloatRegisters;1030// Extra post dependency for killing vector registers (see KillVectorRegs)1031const int extraPostReg = killsVectorRegisters() ? 1 : 0;1032#ifdef J9VM_INTERP_ATOMIC_FREE_JNI1033// Extra post dependency for xzr1034const int maxPostRegisters = maxRegisters + extraPostReg + 1;1035#else1036const int maxPostRegisters = maxRegisters + extraPostReg;1037#endif1038TR::RegisterDependencyConditions *deps = new (trHeapMemory()) TR::RegisterDependencyConditions(maxRegisters, maxPostRegisters, trMemory());10391040size_t spSize = buildJNIArgs(callNode, deps, passThread, passReceiver, killNonVolatileGPRs);1041TR::RealRegister *sp = machine()->getRealRegister(_systemLinkage->getProperties().getStackPointerRegister());10421043if (spSize > 0)1044{1045if (constantIsUnsignedImm12(spSize))1046{1047generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::subimmx, callNode, sp, sp, spSize);1048}1049else1050{1051TR_ASSERT_FATAL(false, "Too many arguments.");1052}1053}10541055TR::Register *returnRegister = getReturnRegisterFromDeps(callNode, deps);10561057#ifdef J9VM_INTERP_ATOMIC_FREE_JNI1058TR::Register *zeroReg = cg()->allocateRegister();1059deps->addPostCondition(zeroReg, TR::RealRegister::xzr);1060#endif1061auto postLabelDeps = deps->clonePost(cg());1062TR::RealRegister *vmThreadReg = machine()->getRealRegister(getProperties().getMethodMetaDataRegister()); // x191063TR::RealRegister *javaStackReg = machine()->getRealRegister(getProperties().getStackPointerRegister()); // x201064TR::Register *x9Reg = deps->searchPreConditionRegister(TR::RealRegister::x9);1065TR::Register *x10Reg = deps->searchPreConditionRegister(TR::RealRegister::x10);1066TR::Register *x11Reg = deps->searchPreConditionRegister(TR::RealRegister::x11);1067TR::Register *x12Reg = deps->searchPreConditionRegister(TR::RealRegister::x12);10681069if (createJNIFrame)1070{1071buildJNICallOutFrame(callNode, (resolvedMethod == comp()->getCurrentMethod()), returnLabel, vmThreadReg, javaStackReg, x9Reg, x10Reg);1072}10731074if (passThread)1075{1076TR::RealRegister *vmThread = machine()->getRealRegister(getProperties().getMethodMetaDataRegister());1077TR::Register *x0Reg = deps->searchPreConditionRegister(TR::RealRegister::x0);1078generateMovInstruction(cg(), callNode, x0Reg, vmThread);1079}10801081if (dropVMAccess)1082{1083#ifdef J9VM_INTERP_ATOMIC_FREE_JNI1084releaseVMAccessAtomicFree(callNode, vmThreadReg, x9Reg, x10Reg);1085#else1086releaseVMAccess(callNode, vmThreadReg, x9Reg, x10Reg, x11Reg, x12Reg);1087#endif1088}10891090TR::Instruction *callInstr = generateMethodDispatch(callNode, isJNIGCPoint, deps, targetAddress, x9Reg);1091generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, returnLabel, callInstr);10921093if (spSize > 0)1094{1095if (constantIsUnsignedImm12(spSize))1096{1097generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addimmx, callNode, sp, sp, spSize);1098}1099else1100{1101TR_ASSERT_FATAL(false, "Too many arguments.");1102}1103}11041105if (dropVMAccess)1106{1107#ifdef J9VM_INTERP_ATOMIC_FREE_JNI1108acquireVMAccessAtomicFree(callNode, vmThreadReg, x9Reg, zeroReg);1109#else1110acquireVMAccess(callNode, vmThreadReg, x9Reg, x10Reg, x11Reg);1111#endif1112}11131114if (returnRegister != NULL)1115{1116adjustReturnValue(callNode, wrapRefs, returnRegister);1117}11181119if (createJNIFrame)1120{1121restoreJNICallOutFrame(callNode, tearDownJNIFrame, vmThreadReg, javaStackReg, x9Reg);1122}11231124if (checkExceptions)1125{1126checkForJNIExceptions(callNode, vmThreadReg, x9Reg);1127}11281129TR::LabelSymbol *depLabel = generateLabelSymbol(cg());1130generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, depLabel, postLabelDeps);11311132callNode->setRegister(returnRegister);11331134#ifdef J9VM_INTERP_ATOMIC_FREE_JNI1135cg()->stopUsingRegister(zeroReg);1136#endif1137deps->stopUsingDepRegs(cg(), returnRegister);1138return returnRegister;1139}114011411142