Path: blob/master/runtime/compiler/arm/codegen/ARMJNILinkage.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2016, 2021 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/ARMJNILinkage.hpp"2324#include "arm/codegen/ARMInstruction.hpp"25#include "codegen/CallSnippet.hpp"26#include "codegen/CodeGenerator.hpp"27#include "codegen/CodeGeneratorUtils.hpp"28#include "codegen/GCStackAtlas.hpp"29#include "codegen/GCStackMap.hpp"30#include "codegen/GenerateInstructions.hpp"31#include "codegen/Linkage_inlines.hpp"32#include "codegen/Machine.hpp"33#include "codegen/RealRegister.hpp"34#include "codegen/Register.hpp"35#include "codegen/RegisterPair.hpp"36#include "codegen/StackCheckFailureSnippet.hpp"37#include "env/CompilerEnv.hpp"38#include "env/J2IThunk.hpp"39#include "env/VMJ9.h"40#include "env/jittypes.h"41#include "il/LabelSymbol.hpp"42#include "il/MethodSymbol.hpp"43#include "il/Node.hpp"44#include "il/Node_inlines.hpp"45#include "il/RegisterMappedSymbol.hpp"46#include "il/ResolvedMethodSymbol.hpp"47#include "il/StaticSymbol.hpp"48#include "il/Symbol.hpp"49#include "il/TreeTop.hpp"50#include "il/TreeTop_inlines.hpp"5152#define LOCK_R145354// TODO: Merge with TR::ARMLinkageProperties55static TR::RealRegister::RegNum _singleArgumentRegisters[] =56{57TR::RealRegister::fs0,58TR::RealRegister::fs1,59TR::RealRegister::fs2,60TR::RealRegister::fs3,61TR::RealRegister::fs4,62TR::RealRegister::fs5,63TR::RealRegister::fs6,64TR::RealRegister::fs7,65TR::RealRegister::fs8,66TR::RealRegister::fs9,67TR::RealRegister::fs10,68TR::RealRegister::fs11,69TR::RealRegister::fs12,70TR::RealRegister::fs13,71TR::RealRegister::fs14,72TR::RealRegister::fs1573};7475J9::ARM::JNILinkage::JNILinkage(TR::CodeGenerator *cg)76: J9::ARM::PrivateLinkage(cg)77{78//Copy out SystemLinkage properties. Assumes no objects in TR::ARMLinkageProperties.79TR::Linkage *sysLinkage = cg->getLinkage(TR_System);80const TR::ARMLinkageProperties& sysLinkageProperties = sysLinkage->getProperties();8182_properties = sysLinkageProperties;8384//Set preservedRegisterMapForGC to PrivateLinkage properties.85TR::Linkage *privateLinkage = cg->getLinkage(TR_Private);86const TR::ARMLinkageProperties& privateLinkageProperties = privateLinkage->getProperties();8788_properties._preservedRegisterMapForGC = privateLinkageProperties.getPreservedRegisterMapForGC();8990}9192int32_t J9::ARM::JNILinkage::buildArgs(TR::Node *callNode,93TR::RegisterDependencyConditions *dependencies,94TR::Register* &vftReg,95bool isVirtual)96{97TR_ASSERT(0, "Should call J9::ARM::JNILinkage::buildJNIArgs instead.");98return 0;99}100101TR::Register *J9::ARM::JNILinkage::buildIndirectDispatch(TR::Node *callNode)102{103TR_ASSERT(0, "Calling J9::ARM::JNILinkage::buildIndirectDispatch does not make sense.");104return NULL;105}106107void J9::ARM::JNILinkage::buildVirtualDispatch(TR::Node *callNode,108TR::RegisterDependencyConditions *dependencies,109TR::RegisterDependencyConditions *postDeps,110TR::Register *vftReg,111uint32_t sizeOfArguments)112{113TR_ASSERT(0, "Calling J9::ARM::JNILinkage::buildVirtualDispatch does not make sense.");114}115116TR::ARMLinkageProperties& J9::ARM::JNILinkage::getProperties()117{118return _properties;119}120121#if defined(__VFP_FP__) && !defined(__SOFTFP__)122TR::Register *J9::ARM::JNILinkage::pushFloatArgForJNI(TR::Node *child)123{124// if (isSmall()) return 0;125126TR::Register *pushRegister = cg()->evaluate(child);127child->setRegister(pushRegister);128child->decReferenceCount();129if (pushRegister->getKind() == TR_GPR)130{131TR::Register *trgReg = cg()->allocateSinglePrecisionRegister();132generateTrg1Src1Instruction(cg(), TR::InstOpCode::fmsr, child, trgReg, pushRegister);133return trgReg;134}135136return pushRegister;137}138139TR::Register *J9::ARM::JNILinkage::pushDoubleArgForJNI(TR::Node *child)140{141// if (isSmall()) return 0;142143TR::Register *pushRegister = cg()->evaluate(child);144child->setRegister(pushRegister);145child->decReferenceCount();146if (pushRegister->getKind() == TR_GPR)147{148TR::Register *trgReg = cg()->allocateRegister(TR_FPR);149TR::RegisterPair *pair = pushRegister->getRegisterPair();150generateTrg1Src2Instruction(cg(), TR::InstOpCode::fmdrr, child, trgReg, pair->getLowOrder(), pair->getHighOrder());151return trgReg;152}153return pushRegister;154}155#endif156157TR::MemoryReference *J9::ARM::JNILinkage::getOutgoingArgumentMemRef(int32_t totalSize,158int32_t offset,159TR::Register *argReg,160TR::InstOpCode::Mnemonic opCode,161TR::ARMMemoryArgument &memArg)162{163/* totalSize does not matter */164#ifdef DEBUG_ARM_LINKAGE165printf("JNI: offset %d\n", offset); fflush(stdout);166#endif167const TR::ARMLinkageProperties &jniLinkageProperties = getProperties();168int32_t spOffset = offset + getOffsetToFirstParm();169TR::RealRegister *sp = cg()->machine()->getRealRegister(jniLinkageProperties.getStackPointerRegister());170TR::MemoryReference *result = new (trHeapMemory()) TR::MemoryReference(sp, spOffset, cg());171memArg.argRegister = argReg;172memArg.argMemory = result;173memArg.opCode = opCode;174return result;175}176177int32_t J9::ARM::JNILinkage::buildJNIArgs(TR::Node *callNode,178TR::RegisterDependencyConditions *dependencies,179TR::Register* &vftReg,180bool passReceiver,181bool passEnvArg)182{183TR::CodeGenerator *codeGen = cg();184TR::Compilation *comp = codeGen->comp();185TR::ARMMemoryArgument *pushToMemory = NULL;186const TR::ARMLinkageProperties &jniLinkageProperties = getProperties();187188bool bigEndian = comp->target().cpu.isBigEndian();189int32_t i;190uint32_t numIntegerArgRegIndex = 0;191uint32_t numFloatArgRegIndex = 0;192uint32_t numDoubleArgRegIndex = 0;193uint32_t numSingleArgRegIndex = 0; // if nonzero, use the second half of VFP register194uint32_t numMemArgs = 0;195uint32_t stackOffset = 0;196uint32_t numIntArgRegs = jniLinkageProperties.getNumIntArgRegs();197uint32_t numFloatArgRegs = jniLinkageProperties.getNumFloatArgRegs();198bool isEABI = comp->target().isEABI();199uint32_t firstArgumentChild = callNode->getFirstArgumentIndex();200TR::DataType callNodeDataType = callNode->getDataType();201TR::DataType resType = callNode->getType();202TR::MethodSymbol *callSymbol = callNode->getSymbol()->castToMethodSymbol();203204if (passEnvArg)205numIntegerArgRegIndex = 1;206207if (!passReceiver)208{209// Evaluate as usual if necessary, but don't actually pass it to the callee210TR::Node *firstArgChild = callNode->getChild(firstArgumentChild);211if (firstArgChild->getReferenceCount() > 1)212{213switch (firstArgChild->getDataType())214{215case TR::Int32:216pushIntegerWordArg(firstArgChild);217break;218case TR::Int64:219pushLongArg(firstArgChild);220break;221case TR::Address:222pushAddressArg(firstArgChild);223break;224default:225TR_ASSERT( false, "Unexpected first child type");226}227}228else229codeGen->recursivelyDecReferenceCount(firstArgChild);230firstArgumentChild += 1;231}232233/* Step 1 - figure out how many arguments are going to be spilled to memory i.e. not in registers */234for (i = firstArgumentChild; i < callNode->getNumChildren(); i++)235{236switch (callNode->getChild(i)->getDataType())237{238case TR::Int8:239case TR::Int16:240case TR::Int32:241case TR::Address:242#if !defined(__ARM_PCS_VFP)243case TR::Float:244#endif245if (numIntegerArgRegIndex >= numIntArgRegs)246{247numMemArgs++;248stackOffset += 4;249}250numIntegerArgRegIndex++;251break;252case TR::Int64:253#if !defined(__ARM_PCS_VFP)254case TR::Double:255#endif256if (isEABI)257{258// The MVL CEE 3.0 system linkage requires that an unaligned259// long argument consume an extra slot of padding260if (numIntegerArgRegIndex + 1 >= numIntArgRegs)261{262/* if numIntegerArgRegIndex >= numIntArgReg - 1, we do not need to care about the register slot padding. */263numIntegerArgRegIndex += 2;264numMemArgs += 2;265/* but we need to care about the stack alignment instead. */266stackOffset = (stackOffset + 12) & (~7);267}268else269{270if (numIntegerArgRegIndex & 1)271numIntegerArgRegIndex += 3; // an unaligned long argument consume an extra slot of padding272else273numIntegerArgRegIndex += 2;274}275}276else277{278if (numIntegerArgRegIndex + 1 == numIntArgRegs)279{280numMemArgs++;281stackOffset += 4;282}283else if (numIntegerArgRegIndex + 1 > numIntArgRegs)284{285numMemArgs += 2;286stackOffset += 8;287}288289numIntegerArgRegIndex += 2;290}291break;292#if defined(__ARM_PCS_VFP) // -mfloat-abi=hard293case TR::Float:294if ((numFloatArgRegIndex < numFloatArgRegs) || (numFloatArgRegIndex == numFloatArgRegs && numSingleArgRegIndex != 0))295{296if (numSingleArgRegIndex != 0)297{298numSingleArgRegIndex = 0;299}300else301{302numSingleArgRegIndex = numFloatArgRegIndex * 2 + 1;303numFloatArgRegIndex++;304}305}306else307{308numMemArgs++;309stackOffset += 4;310311numFloatArgRegIndex++;312if (numSingleArgRegIndex != 0)313{314numSingleArgRegIndex = 0;315}316}317break;318case TR::Double:319if (isEABI)320{321// The MVL CEE 3.0 system linkage requires that an unaligned322// long argument consume an extra slot of padding323// A VFP register can hold 64bit double value.324if (numFloatArgRegIndex >= numFloatArgRegs)325{326numMemArgs++;327/* 8byte stack alignment. */328stackOffset = (stackOffset + 12) & (~7);329}330}331else332{333if (numFloatArgRegIndex >= numFloatArgRegs)334{335numMemArgs++;336stackOffset += 8;337}338}339numFloatArgRegIndex++;340break;341#endif // ifndef __VFP_FP__342}343}344345#ifdef DEBUG_ARM_LINKAGE346// const char *sig = callNode->getSymbol()->getResolvedMethodSymbol()->signature();347const char *sig = "CALL";348printf("%s: numIntegerArgRegIndex %d numMemArgs %d\n", sig, numIntegerArgRegIndex, numMemArgs); fflush(stdout);349#endif350351352int32_t numStackParmSlots = 0;353// From here, down, all stack memory allocations will expire / die when the function returns.354TR::StackMemoryRegion stackMemoryRegion(*trMemory());355if (numMemArgs > 0)356{357358pushToMemory = new(trStackMemory()) TR::ARMMemoryArgument[numMemArgs];359360// For direct-to-JNI calls, instead of pushing361// arguments, buy the necessary stack slots up front.362// On EABI, keep the C stack 8-byte aligned on entry to native callee.363numStackParmSlots = (isEABI ? ((stackOffset + 4) & (~7)) : stackOffset);364#ifdef DEBUG_ARM_LINKAGE365printf("subtracting %d slots from SP\n", numStackParmSlots); fflush(stdout);366#endif367TR::RealRegister *sp = codeGen->machine()->getRealRegister(jniLinkageProperties.getStackPointerRegister());368uint32_t base, rotate;369if (constantIsImmed8r(numStackParmSlots, &base, &rotate))370{371generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::sub, callNode, sp, sp, base, rotate);372}373else374{375TR::Register *tmpReg = codeGen->allocateRegister();376armLoadConstant(callNode, numStackParmSlots, tmpReg, codeGen);377generateTrg1Src2Instruction(codeGen, TR::InstOpCode::sub, callNode, sp, sp, tmpReg);378codeGen->stopUsingRegister(tmpReg);379}380}381382if (passEnvArg)383numIntegerArgRegIndex = 1;384385numFloatArgRegIndex = 0;386numSingleArgRegIndex = 0;387stackOffset = 0;388389int32_t memArg = 0;390for (i = firstArgumentChild; i < callNode->getNumChildren(); i++)391{392TR::Node *child = callNode->getChild(i);393TR::DataType childType = child->getDataType();394TR::Register *reg;395TR::Register *tempReg;396TR::MemoryReference *tempMR;397398switch (childType)399{400case TR::Int8:401case TR::Int16:402case TR::Int32:403case TR::Address: // have to do something for GC maps here404#if !defined(__ARM_PCS_VFP)405case TR::Float:406#endif407if (childType == TR::Address)408reg = pushJNIReferenceArg(child);409else410reg = pushIntegerWordArg(child);411412if (numIntegerArgRegIndex < numIntArgRegs)413{414if ((childType != TR::Address) && !cg()->canClobberNodesRegister(child, 0))415{416/* If the reg is shared by another node, we copy it to tempReg, so that the reg is not reused after returning the call. */417if (reg->containsCollectedReference())418tempReg = codeGen->allocateCollectedReferenceRegister();419else420tempReg = codeGen->allocateRegister();421generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, child, tempReg, reg);422reg = tempReg;423}424if (numIntegerArgRegIndex == 0 &&425(resType.isAddress() || resType.isInt32() || resType.isInt64()))426{427TR::Register *resultReg;428if (resType.isAddress())429resultReg = codeGen->allocateCollectedReferenceRegister();430else431resultReg = codeGen->allocateRegister();432dependencies->addPreCondition(reg, TR::RealRegister::gr0);433dependencies->addPostCondition(resultReg, TR::RealRegister::gr0);434}435else if (numIntegerArgRegIndex == 1 && resType.isInt64())436{437TR::Register *resultReg = codeGen->allocateRegister();438dependencies->addPreCondition(reg, TR::RealRegister::gr1);439dependencies->addPostCondition(resultReg, TR::RealRegister::gr1);440}441else442{443TR::addDependency(dependencies, reg, jniLinkageProperties.getIntegerArgumentRegister(numIntegerArgRegIndex), TR_GPR, codeGen);444}445}446else447{448#ifdef DEBUG_ARM_LINKAGE449printf("pushing 32-bit arg %d %d\n", numIntegerArgRegIndex, memArg); fflush(stdout);450#endif451tempMR = getOutgoingArgumentMemRef(0, stackOffset, reg, TR::InstOpCode::str, pushToMemory[memArg++]);452stackOffset += 4;453}454numIntegerArgRegIndex++;455break;456case TR::Int64:457#if !defined(__ARM_PCS_VFP)458case TR::Double:459#endif460if (isEABI)461{462if (numIntegerArgRegIndex & 1)463{464#ifdef DEBUG_ARM_LINKAGE465printf("skipping one argument slot\n"); fflush(stdout);466#endif467numIntegerArgRegIndex++;468}469}470reg = pushLongArg(child);471472if (numIntegerArgRegIndex < numIntArgRegs)473{474if (!cg()->canClobberNodesRegister(child, 0))475{476tempReg = codeGen->allocateRegister();477478if (bigEndian)479{480generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, child, tempReg, reg->getRegisterPair()->getHighOrder());481reg = codeGen->allocateRegisterPair(reg->getRegisterPair()->getLowOrder(), tempReg);482}483else484{485generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, child, tempReg, reg->getRegisterPair()->getLowOrder());486reg = codeGen->allocateRegisterPair(tempReg, reg->getRegisterPair()->getHighOrder());487}488}489490dependencies->addPreCondition(bigEndian ? reg->getRegisterPair()->getHighOrder() : reg->getRegisterPair()->getLowOrder(), jniLinkageProperties.getIntegerArgumentRegister(numIntegerArgRegIndex));491if ((numIntegerArgRegIndex == 0) && resType.isAddress())492dependencies->addPostCondition(codeGen->allocateCollectedReferenceRegister(), TR::RealRegister::gr0);493else494dependencies->addPostCondition(codeGen->allocateRegister(), jniLinkageProperties.getIntegerArgumentRegister(numIntegerArgRegIndex));495496if (numIntegerArgRegIndex + 1 < numIntArgRegs)497{498if (!cg()->canClobberNodesRegister(child, 0))499{500tempReg = codeGen->allocateRegister();501if (bigEndian)502{503generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, child, tempReg, reg->getRegisterPair()->getLowOrder());504reg->getRegisterPair()->setLowOrder(tempReg, codeGen);505}506else507{508generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, child, tempReg, reg->getRegisterPair()->getHighOrder());509reg->getRegisterPair()->setHighOrder(tempReg, codeGen);510}511}512dependencies->addPreCondition(bigEndian ? reg->getRegisterPair()->getLowOrder() : reg->getRegisterPair()->getHighOrder(), jniLinkageProperties.getIntegerArgumentRegister(numIntegerArgRegIndex + 1));513dependencies->addPostCondition(codeGen->allocateRegister(), jniLinkageProperties.getIntegerArgumentRegister(numIntegerArgRegIndex + 1));514}515else516{517#ifdef DEBUG_ARM_LINKAGE518printf("pushing %s word of 64-bit arg %d %d\n", bigEndian ? "low" : "high", numIntegerArgRegIndex, memArg); fflush(stdout);519#endif520tempMR = getOutgoingArgumentMemRef(0, stackOffset, bigEndian ? reg->getRegisterPair()->getLowOrder() : reg->getRegisterPair()->getHighOrder(), TR::InstOpCode::str, pushToMemory[memArg++]);521stackOffset += 4;522}523}524else525{526#ifdef DEBUG_ARM_LINKAGE527printf("pushing 64-bit JNI arg %d %d %d\n", numIntegerArgs, memArg, totalSize); fflush(stdout);528#endif529if (isEABI)530stackOffset = (stackOffset + 4) & (~7);531tempMR = getOutgoingArgumentMemRef(0, stackOffset, bigEndian ? reg->getRegisterPair()->getHighOrder() : reg->getRegisterPair()->getLowOrder(), TR::InstOpCode::str, pushToMemory[memArg++]);532tempMR = getOutgoingArgumentMemRef(0, stackOffset + 4, bigEndian ? reg->getRegisterPair()->getLowOrder() : reg->getRegisterPair()->getHighOrder(), TR::InstOpCode::str, pushToMemory[memArg++]);533stackOffset += 8;534}535numIntegerArgRegIndex += 2;536break;537#if defined(__ARM_PCS_VFP) // -mfloat-abi=hard538case TR::Float:539reg = pushFloatArgForJNI(child);540if ((numFloatArgRegIndex < numFloatArgRegs) || (numFloatArgRegIndex == numFloatArgRegs && numSingleArgRegIndex != 0))541{542if (!cg()->canClobberNodesRegister(child, 0))543{544tempReg = codeGen->allocateSinglePrecisionRegister();545generateTrg1Src1Instruction(codeGen, TR::InstOpCode::fcpys, child, tempReg, reg);546reg = tempReg;547}548if ((numFloatArgRegIndex == 0) && resType.isFloatingPoint())549{550TR::Register *resultReg;551if (resType.getDataType() == TR::Float)552resultReg = codeGen->allocateSinglePrecisionRegister();553else554resultReg = codeGen->allocateRegister(TR_FPR);555556dependencies->addPreCondition(reg, TR::RealRegister::fs0);557dependencies->addPostCondition(resultReg, TR::RealRegister::fp0);558}559else560{561uint32_t regIdx = (numSingleArgRegIndex != 0) ? numSingleArgRegIndex : numFloatArgRegIndex * 2;562dependencies->addPreCondition(reg, _singleArgumentRegisters[regIdx]);563if (numSingleArgRegIndex == 0)564{565dependencies->addPostCondition(reg, jniLinkageProperties.getFloatArgumentRegister(numFloatArgRegIndex));566}567}568569if (numSingleArgRegIndex != 0)570{571numSingleArgRegIndex = 0;572}573else574{575numSingleArgRegIndex = numFloatArgRegIndex * 2 + 1;576numFloatArgRegIndex++;577}578}579else580{581tempMR = getOutgoingArgumentMemRef(0, stackOffset, reg, TR::InstOpCode::fsts, pushToMemory[memArg++]);582stackOffset += 4;583584numFloatArgRegIndex++;585if (numSingleArgRegIndex != 0)586{587numSingleArgRegIndex = 0;588}589}590break;591case TR::Double:592reg = pushDoubleArgForJNI(child);593if (numFloatArgRegIndex < numFloatArgRegs)594{595if (!cg()->canClobberNodesRegister(child, 0))596{597tempReg = cg()->allocateRegister(TR_FPR);598generateTrg1Src1Instruction(codeGen, TR::InstOpCode::fcpyd, child, tempReg, reg);599reg = tempReg;600}601if ((numFloatArgRegIndex == 0) && resType.isFloatingPoint())602{603TR::Register *resultReg;604if (resType.getDataType() == TR::Float)605resultReg = codeGen->allocateSinglePrecisionRegister();606else607resultReg = codeGen->allocateRegister(TR_FPR);608609dependencies->addPreCondition(reg, TR::RealRegister::fp0);610dependencies->addPostCondition(resultReg, TR::RealRegister::fp0);611}612else613TR::addDependency(dependencies, reg, jniLinkageProperties.getFloatArgumentRegister(numFloatArgRegIndex), TR_FPR, codeGen);614}615else616{617if (isEABI)618stackOffset = (stackOffset + 4) & (~7);619tempMR = getOutgoingArgumentMemRef(0, stackOffset, reg, TR::InstOpCode::fstd, pushToMemory[memArg++]);620stackOffset += 8;621}622numFloatArgRegIndex++;623break;624#endif625}626}627628for (i = 0; i < jniLinkageProperties.getNumIntArgRegs(); i++)629{630TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::gr0 + i);631if (passEnvArg && (realReg == TR::RealRegister::gr0))632continue;633if (!dependencies->searchPreConditionRegister(realReg))634{635if (realReg == jniLinkageProperties.getIntegerArgumentRegister(0) && resType.isAddress())636{637dependencies->addPreCondition(codeGen->allocateRegister(), TR::RealRegister::gr0);638dependencies->addPostCondition(codeGen->allocateCollectedReferenceRegister(), TR::RealRegister::gr0);639}640else if ((realReg == TR::RealRegister::gr1) && resType.isInt64())641{642dependencies->addPreCondition(codeGen->allocateRegister(), TR::RealRegister::gr1);643dependencies->addPostCondition(codeGen->allocateRegister(), TR::RealRegister::gr1);644}645else646{647TR::addDependency(dependencies, NULL, realReg, TR_GPR, codeGen);648}649}650}651652/* d0-d8 are argument registers and not preserved across the call. */653for (i = 0; i < jniLinkageProperties.getNumFloatArgRegs(); i++)654{655TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i);656if (!dependencies->searchPreConditionRegister(realReg))657{658TR::RealRegister::RegNum singleReg1, singleReg2;659singleReg1 = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fs0 + i*2);660singleReg2 = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fs0 + i*2 + 1);661if (!dependencies->searchPreConditionRegister(singleReg1))662{663TR_ASSERT(!dependencies->searchPreConditionRegister(singleReg2), "Wrong dependency for single precision register.\n");664if (realReg == jniLinkageProperties.getFloatArgumentRegister(0) && (resType.getDataType() == TR::Float))665{666dependencies->addPreCondition(codeGen->allocateRegister(TR_FPR), TR::RealRegister::fp0);667dependencies->addPostCondition(codeGen->allocateSinglePrecisionRegister(), TR::RealRegister::fp0);668}669else670{671TR::addDependency(dependencies, NULL, realReg, TR_FPR, codeGen);672}673}674}675}676677// add dependencies for other volatile registers; for virtual calls,678// dependencies on gr11 and gr14 have already been added above679#ifndef LOCK_R14680TR::addDependency(dependencies, NULL, TR::RealRegister::gr14, TR_GPR, codeGen);681#endif682683for (i = 0; i < numMemArgs; i++)684{685#ifdef DEBUG_ARM_LINKAGE686printf("pushing mem arg %d of %d (in reg %x) to [sp + %d]... ", i, numMemArgs, pushToMemory[i].argRegister, pushToMemory[i].argMemory->getOffset()); fflush(stdout);687#endif688TR::Register *aReg = pushToMemory[i].argRegister;689generateMemSrc1Instruction(codeGen,690pushToMemory[i].opCode,691callNode,692pushToMemory[i].argMemory,693pushToMemory[i].argRegister);694codeGen->stopUsingRegister(aReg);695#ifdef DEBUG_ARM_LINKAGE696printf("done\n"); fflush(stdout);697#endif698}699//Returns the size of parameter buffers allocated on stack700return numStackParmSlots;701702}703704705TR::Register *J9::ARM::JNILinkage::buildDirectDispatch(TR::Node *callNode)706{707TR::CodeGenerator *codeGen = cg();708const TR::ARMLinkageProperties &jniLinkageProperties = getProperties();709TR::Linkage *privateLinkage = codeGen->getLinkage(TR_Private);710const TR::ARMLinkageProperties &privateLinkageProperties = privateLinkage->getProperties();711712TR::RegisterDependencyConditions *deps =713new (trHeapMemory()) TR::RegisterDependencyConditions(jniLinkageProperties.getNumberOfDependencyGPRegisters() + jniLinkageProperties.getNumFloatArgRegs()*2,714jniLinkageProperties.getNumberOfDependencyGPRegisters() + jniLinkageProperties.getNumFloatArgRegs()*2, trMemory());715716TR::SymbolReference *callSymRef = callNode->getSymbolReference();717TR::ResolvedMethodSymbol *calleeSym = callSymRef->getSymbol()->castToResolvedMethodSymbol();718TR_ResolvedMethod *resolvedMethod = calleeSym->getResolvedMethod();719720codeGen->machine()->setLinkRegisterKilled(true);721codeGen->setHasCall();722723// buildArgs() will set up dependencies for the volatile registers, except gr0.724TR::Register* vftReg = NULL;725int32_t spSize = buildJNIArgs(callNode, deps, vftReg, true, true);726727// kill all values in non-volatile registers so that the728// values will be in a stack frame in case GC looks for them729TR::addDependency(deps, NULL, TR::RealRegister::gr4, TR_GPR, codeGen);730TR::addDependency(deps, NULL, TR::RealRegister::gr5, TR_GPR, codeGen);731TR::addDependency(deps, NULL, TR::RealRegister::gr6, TR_GPR, codeGen);732TR::addDependency(deps, NULL, TR::RealRegister::gr9, TR_GPR, codeGen);733TR::addDependency(deps, NULL, TR::RealRegister::gr10, TR_GPR, codeGen);734TR::addDependency(deps, NULL, TR::RealRegister::gr11, TR_GPR, codeGen);735736// set up dependency for the return register737TR::Register *gr0Reg = deps->searchPreConditionRegister(TR::RealRegister::gr0);738TR::Register *returnRegister = NULL;739TR::Register *lowReg = NULL, *highReg;740741switch (callNode->getOpCodeValue())742{743case TR::icall:744case TR::acall:745#if !defined(__VFP_FP__) || defined(__SOFTFP__)746case TR::fcall:747#endif748if (callNode->getDataType() == TR::Address)749{750if (!gr0Reg)751{752gr0Reg = codeGen->allocateRegister();753returnRegister = codeGen->allocateCollectedReferenceRegister();754deps->addPreCondition(gr0Reg, TR::RealRegister::gr0);755deps->addPostCondition(returnRegister, TR::RealRegister::gr0);756}757else758{759returnRegister = deps->searchPostConditionRegister(TR::RealRegister::gr0);760}761}762else763{764if (!gr0Reg)765{766gr0Reg = codeGen->allocateRegister();767returnRegister = gr0Reg;768TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);769}770else771{772returnRegister = deps->searchPostConditionRegister(TR::RealRegister::gr0);773}774}775break;776case TR::lcall:777#if !defined(__VFP_FP__) || defined(__SOFTFP__)778case TR::dcall:779#endif780{781if(codeGen->comp()->target().cpu.isBigEndian())782{783if (!gr0Reg)784{785gr0Reg = codeGen->allocateRegister();786TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);787highReg = gr0Reg;788}789else790{791highReg = deps->searchPostConditionRegister(TR::RealRegister::gr0);792}793lowReg = deps->searchPostConditionRegister(TR::RealRegister::gr1);794}795else796{797if (!gr0Reg)798{799gr0Reg = codeGen->allocateRegister();800TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);801lowReg = gr0Reg;802}803else804{805lowReg = deps->searchPostConditionRegister(TR::RealRegister::gr0);806}807highReg = deps->searchPostConditionRegister(TR::RealRegister::gr1);808}809returnRegister = codeGen->allocateRegisterPair(lowReg, highReg);810break;811}812#if (defined(__VFP_FP__) && !defined(__SOFTFP__))813case TR::fcall:814case TR::dcall:815returnRegister = deps->searchPostConditionRegister(jniLinkageProperties.getFloatReturnRegister(0));816if (!gr0Reg)817{818gr0Reg = codeGen->allocateRegister();819TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);820}821break;822#endif823case TR::call:824if (!gr0Reg)825{826gr0Reg = codeGen->allocateRegister();827TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);828}829returnRegister = NULL;830break;831default:832if (!gr0Reg)833{834gr0Reg = codeGen->allocateRegister();835TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);836}837returnRegister = NULL;838TR_ASSERT(0, "Unknown direct call opode.\n");839}840841deps->stopAddingConditions();842843// build stack frame on the Java stack844TR::MemoryReference *tempMR;845846TR::Machine *machine = codeGen->machine();847TR::RealRegister *metaReg = codeGen->getMethodMetaDataRegister();848TR::RealRegister *stackPtr = machine->getRealRegister(privateLinkageProperties.getStackPointerRegister());//JavaSP849TR::RealRegister *instrPtr = machine->getRealRegister(TR::RealRegister::gr15);850TR::RealRegister *gr13Reg = machine->getRealRegister(TR::RealRegister::gr13);851TR::Register *gr4Reg = deps->searchPreConditionRegister(TR::RealRegister::gr4);852TR::Register *gr5Reg = deps->searchPreConditionRegister(TR::RealRegister::gr5);853854// Force spilling the volatile FPRs855int32_t i;856TR::LabelSymbol *spillLabel = generateLabelSymbol(codeGen);857TR::RegisterDependencyConditions *spillDeps = new (trHeapMemory()) TR::RegisterDependencyConditions(0, jniLinkageProperties.getNumFloatArgRegs()*2, codeGen->trMemory());858for (i = 0; i < jniLinkageProperties.getNumFloatArgRegs()*2; i++)859{860spillDeps->addPostCondition(codeGen->allocateRegister(TR_FPR), (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fs0 + i));861}862generateLabelInstruction(codeGen, TR::InstOpCode::label, callNode, spillLabel, spillDeps);863864TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());865// mask out the magic bit that indicates JIT frames below866generateTrg1ImmInstruction(codeGen, TR::InstOpCode::mov, callNode, gr5Reg, 0, 0);867tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaFrameFlagsOffset(), codeGen);868generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr5Reg);869870// push tag bits (savedA0 slot)871// if the current method is simply a wrapper for the JNI call, hide the call-out stack frame872uintptr_t tagBits = fej9->constJNICallOutFrameSpecialTag();873if (resolvedMethod == comp()->getCurrentMethod())874{875tagBits |= fej9->constJNICallOutFrameInvisibleTag();876}877armLoadConstant(callNode, tagBits, gr4Reg, codeGen);878tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, -((int)sizeof(uintptr_t)), codeGen);879tempMR->setImmediatePreIndexed();880generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr4Reg);881882// skip unused savedPC slot and push return address (savedCP slot)883//884TR::LabelSymbol *returnAddrLabel = generateLabelSymbol(codeGen);885generateLabelInstruction(codeGen, TR::InstOpCode::add, callNode, returnAddrLabel, NULL, gr4Reg, instrPtr);886tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, -2 * ((int)sizeof(uintptr_t)), codeGen);887tempMR->setImmediatePreIndexed();888generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr4Reg);889890// push frame flags891intParts flags((int32_t)fej9->constJNICallOutFrameFlags());892TR_ASSERT((flags.getValue() & ~0x7FFF0000) == 0, "JNI call-out frame flags have more than 15 bits");893generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(flags.getByte3(), 24));894generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, gr4Reg, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(flags.getByte2(), 16));895tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, -((int)TR::Compiler->om.sizeofReferenceAddress()), codeGen);896tempMR->setImmediatePreIndexed();897generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr4Reg);898899// push the RAM method for the native900intParts ramMethod((int32_t)resolvedMethod->resolvedMethodAddress());901generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(ramMethod.getByte3(), 24));902generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, gr4Reg, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(ramMethod.getByte2(), 16));903generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, gr4Reg, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(ramMethod.getByte1(), 8));904generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, gr4Reg, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(ramMethod.getByte0(), 0));905tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, -((int)TR::Compiler->om.sizeofReferenceAddress()), codeGen);906tempMR->setImmediatePreIndexed();907generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr4Reg);908909// store the Java SP910tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaSPOffset(), codeGen);911generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, stackPtr);912913// store the PC and literals values indicating the call-out frame914intParts frameType((int32_t)fej9->constJNICallOutFrameType());915TR_ASSERT((frameType.getValue() & ~0xFFFF) == 0, "JNI call-out frame type has more than 16 bits");916generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(frameType.getByte1(), 8));917generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, gr4Reg, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(frameType.getByte0(), 0));918tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaPCOffset(), codeGen);919generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr4Reg);920tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaLiteralsOffset(), codeGen);921generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr5Reg);922923// the Java arguments for the native method are all in place already; now924// pass the vmThread pointer as the hidden first argument to a JNI call925generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr0Reg, metaReg);926927// release VM access (go to internalReleaseVMAccess directly)928TR::ResolvedMethodSymbol *callerSym = comp()->getJittedMethodSymbol();929TR::SymbolReferenceTable *symRefTab = comp()->getSymRefTab();930TR::SymbolReference *helperSymRef = symRefTab->findOrCreateReleaseVMAccessSymbolRef(callerSym);931932TR::ARMMultipleMoveInstruction *instr;933instr = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(TR::InstOpCode::stmdb, callNode, gr13Reg, 0x0f, codeGen);934instr->setWriteBack();935936//AOT relocation is handled in TR::ARMImmSymInstruction::generateBinaryEncoding()937TR::Instruction *gcPoint = generateImmSymInstruction(codeGen, TR::InstOpCode::bl, callNode, (uint32_t)helperSymRef->getMethodAddress(), NULL, helperSymRef);938gcPoint->ARMNeedsGCMap(~(jniLinkageProperties.getPreservedRegisterMapForGC()));939instr = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(TR::InstOpCode::ldmia, callNode, gr13Reg, 0x0f, codeGen);940instr->setWriteBack();941942// split dependencies to prevent register assigner from inserting code. Any generated943// spills/loads would be incorrect as the stack pointer has not been fixed up yet.944TR::RegisterDependencyConditions *postDeps = deps->clone(cg());945deps->setNumPostConditions(0, trMemory());946postDeps->setNumPreConditions(0, trMemory());947// get the target method address and dispatch JNI method directly948uintptr_t methodAddress = (uintptr_t)resolvedMethod->startAddressForJNIMethod(comp());949//AOT relocation is handled in TR::ARMImmSymInstruction::generateBinaryEncoding()950gcPoint = generateImmSymInstruction(codeGen, TR::InstOpCode::bl, callNode, methodAddress, deps, callSymRef);951codeGen->getJNICallSites().push_front(new (trHeapMemory()) TR_Pair<TR_ResolvedMethod, TR::Instruction>(calleeSym->getResolvedMethod(), gcPoint));952gcPoint->ARMNeedsGCMap(jniLinkageProperties.getPreservedRegisterMapForGC());953954generateLabelInstruction(codeGen, TR::InstOpCode::label, callNode, returnAddrLabel);955956// JNI methods may not return a full register in some cases so we need to957// sign- or zero-extend the narrower integer return types properly.958switch (resolvedMethod->returnType())959{960case TR::Int8:961if (resolvedMethod->returnTypeIsUnsigned())962generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::and_, callNode, returnRegister, returnRegister, 0xFF, 0);963else964{965generateShiftLeftImmediate(codeGen, callNode, returnRegister, returnRegister, 24);966generateShiftRightArithmeticImmediate(codeGen, callNode, returnRegister, returnRegister, 24);967}968break;969case TR::Int16:970if (resolvedMethod->returnTypeIsUnsigned())971{972generateTrg1ImmInstruction(codeGen, TR::InstOpCode::mvn, callNode, gr4Reg, 0xFF, 0);973generateTrg1Src2Instruction(codeGen, TR::InstOpCode::and_, callNode, returnRegister, returnRegister,974new (trHeapMemory()) TR_ARMOperand2(ARMOp2RegLSRImmed, gr4Reg, 16));975}976else977{978generateShiftLeftImmediate(codeGen, callNode, returnRegister, returnRegister, 16);979generateShiftRightArithmeticImmediate(codeGen, callNode, returnRegister, returnRegister, 16);980}981break;982}983984// if a particular flavour of arm-linux does not support soft-float then any floating point return value will985// be in f0 and must be moved to the expected gpr(s).986if (codeGen->hasHardFloatReturn())987{988switch (resolvedMethod->returnType())989{990case TR::Float:991{992TR::RealRegister *fpReg = machine->getRealRegister(jniLinkageProperties.getFloatReturnRegister());993fpReg->setAssignedRegister(fpReg);994tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetFloatTemp1Offset(), codeGen);995generateMemSrc1Instruction(codeGen, TR::InstOpCode::fsts, callNode, tempMR, fpReg);996generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, returnRegister, tempMR);997break;998}999case TR::Double:1000{1001TR::RealRegister *fdReg = machine->getRealRegister(jniLinkageProperties.getDoubleReturnRegister());1002fdReg->setAssignedRegister(fdReg);1003TR_ASSERT(fej9->thisThreadGetFloatTemp2Offset() - fej9->thisThreadGetFloatTemp1Offset() == 4,"floatTemp1 and floatTemp2 not contiguous");1004tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetFloatTemp1Offset(), codeGen);1005generateMemSrc1Instruction(codeGen, TR::InstOpCode::fstd, callNode, tempMR, fdReg);1006bool bigEndian = codeGen->comp()->target().cpu.isBigEndian();1007generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, bigEndian ? returnRegister->getHighOrder() : returnRegister->getLowOrder(), tempMR);1008tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetFloatTemp2Offset(), codeGen);1009generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, bigEndian ? returnRegister->getLowOrder() : returnRegister->getHighOrder(), tempMR);1010break;1011}1012}1013}10141015// restore the system stack pointer (r13)1016if (spSize > 0)1017{1018TR::RealRegister *sp = machine->getRealRegister(jniLinkageProperties.getStackPointerRegister());1019uint32_t base, rotate;1020if (constantIsImmed8r(spSize, &base, &rotate))1021{1022generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, callNode, sp, sp, base, rotate);1023}1024else1025{1026TR::Register *tmpReg = codeGen->allocateRegister();1027armLoadConstant(callNode, spSize, gr4Reg, codeGen);1028generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, sp, sp, gr4Reg);1029}1030}10311032// re-acquire VM access1033helperSymRef = symRefTab->findOrCreateAcquireVMAccessSymbolRef(callerSym);1034//AOT relocation is handled in TR::ARMImmSymInstruction::generateBinaryEncoding()1035gcPoint = generateImmSymInstruction(codeGen, TR::InstOpCode::bl, callNode, (uint32_t)helperSymRef->getMethodAddress(), NULL, helperSymRef);1036gcPoint->ARMNeedsGCMap(1 << (jniLinkageProperties.getIntegerReturnRegister() - TR::RealRegister::FirstGPR));10371038// JNI methods return objects with an extra level of indirection (unless1039// the result is NULL) so we need to dereference the return register;1040// This dereference must be done after vm access is re-acquired so the underlying1041// object is not moved by gc.1042if (resolvedMethod->returnType() == TR::Address)1043{1044tempMR = new (trHeapMemory()) TR::MemoryReference(returnRegister, 0, codeGen);1045generateSrc1ImmInstruction(codeGen, TR::InstOpCode::cmp, callNode, returnRegister, 0, 0);1046gcPoint = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, returnRegister, tempMR);1047gcPoint->setConditionCode(ARMConditionCodeNE);1048}10491050// restore stack pointer and deal with possibly grown stack1051tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaLiteralsOffset(), codeGen);1052generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr4Reg, tempMR);1053tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaSPOffset(), codeGen);1054generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, stackPtr, tempMR);1055generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, stackPtr, stackPtr, gr4Reg);10561057// see if the reference pool was used and, if used, clean it up; otherwise we can1058// leave a bunch of pinned garbage behind that screws up the GC quality forever1059tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, fej9->constJNICallOutFrameFlagsOffset(), codeGen);1060generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr4Reg, tempMR);10611062uint32_t flagValue = fej9->constJNIReferenceFrameAllocatedFlags();1063uint32_t base, rotate;1064if (constantIsImmed8r(flagValue, &base, &rotate))1065{1066generateSrc1ImmInstruction(codeGen, TR::InstOpCode::tst, callNode, gr4Reg, base, rotate);1067}1068else1069{1070armLoadConstant(callNode, flagValue, gr5Reg, codeGen);1071generateSrc2Instruction(codeGen, TR::InstOpCode::tst, callNode, gr4Reg, gr5Reg);1072}10731074helperSymRef = codeGen->symRefTab()->findOrCreateRuntimeHelper(TR_ARMjitCollapseJNIReferenceFrame);1075//AOT relocation is handled in TR::ARMImmSymInstruction::generateBinaryEncoding()1076generateImmSymInstruction(codeGen, TR::InstOpCode::bl, callNode, (uint32_t)helperSymRef->getMethodAddress(), NULL, helperSymRef, NULL, NULL, ARMConditionCodeEQ);10771078// restore the JIT frame1079generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, callNode, stackPtr, stackPtr, 20, 0);10801081// check exceptions1082tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetCurrentExceptionOffset(), codeGen);1083generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr4Reg, tempMR);1084generateSrc1ImmInstruction(codeGen, TR::InstOpCode::cmp, callNode, gr4Reg, 0, 0);1085helperSymRef = symRefTab->findOrCreateThrowCurrentExceptionSymbolRef(callerSym);1086//AOT relocation is handled in TR::ARMImmSymInstruction::generateBinaryEncoding()1087gcPoint = generateImmSymInstruction(codeGen, TR::InstOpCode::bl, callNode, (uint32_t)helperSymRef->getMethodAddress(), NULL, helperSymRef, NULL, NULL, ARMConditionCodeNE);1088gcPoint->ARMNeedsGCMap(1 << (jniLinkageProperties.getIntegerReturnRegister() - TR::RealRegister::FirstGPR));10891090TR::LabelSymbol *doneLabel = generateLabelSymbol(codeGen);1091generateLabelInstruction(codeGen, TR::InstOpCode::label, callNode, doneLabel, postDeps);10921093return callNode->setRegister(returnRegister);1094}109510961097