Path: blob/master/runtime/compiler/arm/codegen/ARMPrivateLinkage.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2000, 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/ARMPrivateLinkage.hpp"2324#include "arm/codegen/ARMInstruction.hpp"25#include "codegen/CallSnippet.hpp"26#include "codegen/GCStackAtlas.hpp"27#include "codegen/GCStackMap.hpp"28#include "codegen/GenerateInstructions.hpp"29#include "codegen/Linkage_inlines.hpp"30#include "codegen/Machine.hpp"31#include "codegen/Register.hpp"32#include "codegen/RegisterPair.hpp"33#include "codegen/Snippet.hpp"34#include "codegen/StackCheckFailureSnippet.hpp"35#include "env/CompilerEnv.hpp"36#include "env/J2IThunk.hpp"37#include "il/Node.hpp"38#include "il/Node_inlines.hpp"39#include "il/TreeTop.hpp"40#include "il/TreeTop_inlines.hpp"41#include "il/LabelSymbol.hpp"42#include "il/MethodSymbol.hpp"43#include "il/ParameterSymbol.hpp"44#include "il/RegisterMappedSymbol.hpp"45#include "il/ResolvedMethodSymbol.hpp"46#include "il/StaticSymbol.hpp"47#include "il/Symbol.hpp"48#include "env/VMJ9.h"4950#define LOCK_R1451// #define DEBUG_ARM_LINKAGE5253TR::ARMLinkageProperties J9::ARM::PrivateLinkage::properties =54{ // TR_Private550, // linkage properties56{ // register flags570, // NoReg580, // gr0590, // gr1600, // gr2610, // gr3620, /*Preserved,*/ // gr4630, /*Preserved,*/ // gr564Preserved, // gr6 Java BP65Preserved, // gr7 Java SP66Preserved, // gr8 Java J9VMThread67Preserved, // gr968Preserved, // gr10690, /* Preserved,*/ // gr11 APCS FP (ignore for now - use as temp)70Preserved, // gr12 (OS RESERVED)710, /* Preserved,*/ // gr13 APCS SP (OS RESERVED)720, // gr14 LR730, // gr15 IP74#if (defined(__VFP_FP__) && !defined(__SOFTFP__))750, // f0760, // f1770, // f2780, // f3790, // f4800, // f5810, // f6820, // f7830, // f8840, // f9850, // f10860, // f11870, // f12880, // f13890, // f14900, // f1591#else92FloatReturn, // f0930, // f1940, // f2950, // f396Preserved, // f497Preserved, // f598Preserved, // f699Preserved, // f7100#endif101},102{ // preserved registers103// TR::RealRegister::gr4,104// TR::RealRegister::gr5,105TR::RealRegister::gr6,106TR::RealRegister::gr7,107TR::RealRegister::gr8,108TR::RealRegister::gr9,109TR::RealRegister::gr10,110// TR::RealRegister::gr11,111// TR::RealRegister::gr13,112// TR::RealRegister::gr14,113TR::RealRegister::gr15,114#if !defined(__VFP_FP__) || defined(__SOFTFP__)115TR::RealRegister::fp4,116TR::RealRegister::fp5,117TR::RealRegister::fp6,118TR::RealRegister::fp7119#endif120},121{ // argument registers122TR::RealRegister::gr0,123TR::RealRegister::gr1,124TR::RealRegister::gr2,125TR::RealRegister::gr3,126#if !defined(__VFP_FP__) || defined(__SOFTFP__)127TR::RealRegister::fp0,128TR::RealRegister::fp1,129TR::RealRegister::fp2,130TR::RealRegister::fp3,131#endif132},133{ // return registers134TR::RealRegister::gr0,135TR::RealRegister::gr1,136#if !defined(__VFP_FP__) || defined(__SOFTFP__)137TR::RealRegister::fp0,138#endif139},140MAX_ARM_GLOBAL_GPRS, // numAllocatableIntegerRegisters141MAX_ARM_GLOBAL_FPRS, // numAllocatableFloatRegisters1420x0000FFC0, // preserved register map143TR::RealRegister::gr6, // frame register144TR::RealRegister::gr8, // method meta data register145TR::RealRegister::gr7, // stack pointer register146TR::RealRegister::gr11, // vtable index register147TR::RealRegister::gr0, // j9method argument register14815, // numberOfDependencyRegisters149-4, // offsetToFirstLocal1504, // numIntegerArgumentRegisters1510, // firstIntegerArgumentRegister152#if defined(__VFP_FP__) && !defined(__SOFTFP__)1530, // numFloatArgumentRegisters154#else1554, // numFloatArgumentRegisters156#endif1570, // firstFloatArgumentRegister1580, // firstIntegerReturnRegister1590 // firstFloatReturnRegister160};161162J9::ARM::PrivateLinkage::PrivateLinkage(TR::CodeGenerator *cg)163: J9::PrivateLinkage(cg)164{165setOffsetToFirstParm(0);166}167168TR::ARMLinkageProperties& J9::ARM::PrivateLinkage::getProperties()169{170return properties;171}172173static void lockRegister(TR::RealRegister *regToAssign)174{175regToAssign->setState(TR::RealRegister::Locked);176regToAssign->setAssignedRegister(regToAssign);177}178179void J9::ARM::PrivateLinkage::initARMRealRegisterLinkage()180{181TR::CodeGenerator *codeGen = cg();182TR::Machine *machine = codeGen->machine();183const TR::ARMLinkageProperties &linkage = getProperties();184int icount;185186for (icount = TR::RealRegister::FirstGPR; icount <= TR::RealRegister::gr5; icount++)187{188machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(icount);189}190191// mark all magic registers as locked and having a physical192// register associated so the register assigner stays happy193lockRegister(codeGen->getMethodMetaDataRegister());194lockRegister(codeGen->getFrameRegister());195lockRegister(codeGen->machine()->getRealRegister(properties.getStackPointerRegister()));196lockRegister(machine->getRealRegister(TR::RealRegister::gr12)); // r12 is OS reserved197lockRegister(machine->getRealRegister(TR::RealRegister::gr13)); // r13 is OS SP198#ifdef LOCK_R14199lockRegister(machine->getRealRegister(TR::RealRegister::gr14)); // r14 is LR200#endif201lockRegister(machine->getRealRegister(TR::RealRegister::gr15)); // r15 is IP202203for (icount=TR::RealRegister::LastGPR; icount>=TR::RealRegister::gr6; icount--)204machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);205206#if defined(__VFP_FP__) && !defined(__SOFTFP__)207for (icount=TR::RealRegister::FirstFPR; icount<=TR::RealRegister::LastFPR; icount++)208machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(icount);209#else210for (icount=TR::RealRegister::FirstFPR; icount<=TR::RealRegister::fp3; icount++)211machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(icount);212213for (icount=TR::RealRegister::LastFPR; icount>=TR::RealRegister::fp4; icount--)214machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);215#endif216}217218uint32_t J9::ARM::PrivateLinkage::getRightToLeft()219{220return getProperties().getRightToLeft();221}222223void J9::ARM::PrivateLinkage::mapStack(TR::ResolvedMethodSymbol *method)224{225ListIterator<TR::AutomaticSymbol> automaticIterator(&method->getAutomaticList());226TR::AutomaticSymbol *localCursor = automaticIterator.getFirst();227const TR::ARMLinkageProperties& linkage = getProperties();228TR::CodeGenerator *codeGen = cg();229TR::Machine *machine = codeGen->machine();230int32_t firstLocalOffset = linkage.getOffsetToFirstLocal();231uint32_t stackIndex = firstLocalOffset;232int32_t lowGCOffset;233TR::GCStackAtlas *atlas = codeGen->getStackAtlas();234235// map all garbage collected references together so can concisely represent236// stack maps. They must be mapped so that the GC map index in each local237// symbol is honoured.238239lowGCOffset = stackIndex;240int32_t firstLocalGCIndex = atlas->getNumberOfParmSlotsMapped();241242stackIndex -= (atlas->getNumberOfSlotsMapped() - atlas->getNumberOfParmSlotsMapped()) << 2;243244// Map local references again to set the stack position correct according to245// the GC map index.246//247for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())248if (localCursor->getGCMapIndex() >= 0)249{250localCursor->setOffset(stackIndex + 4 * (localCursor->getGCMapIndex() - firstLocalGCIndex));251if (localCursor->getGCMapIndex() == atlas->getIndexOfFirstInternalPointer())252{253atlas->setOffsetOfFirstInternalPointer(localCursor->getOffset() - firstLocalOffset);254}255}256257method->setObjectTempSlots((lowGCOffset-stackIndex) >> 2);258lowGCOffset = stackIndex;259260// Now map the rest of the locals261//262automaticIterator.reset();263localCursor = automaticIterator.getFirst();264265while (localCursor != NULL)266{267if (localCursor->getGCMapIndex() < 0 &&268localCursor->getDataType() != TR::Double)269{270mapSingleAutomatic(localCursor, stackIndex);271}272localCursor = automaticIterator.getNext();273}274275automaticIterator.reset();276localCursor = automaticIterator.getFirst();277278while (localCursor != NULL)279{280if (localCursor->getDataType() == TR::Double)281{282stackIndex -= (stackIndex & 0x4)?4:0;283mapSingleAutomatic(localCursor, stackIndex);284}285localCursor = automaticIterator.getNext();286}287method->setLocalMappingCursor(stackIndex);288289ListIterator<TR::ParameterSymbol> parameterIterator(&method->getParameterList());290TR::ParameterSymbol *parmCursor = parameterIterator.getFirst();291int32_t offsetToFirstParm = getOffsetToFirstParm();292if (linkage.getRightToLeft())293{294while (parmCursor != NULL)295{296parmCursor->setParameterOffset(parmCursor->getParameterOffset() + offsetToFirstParm);297parmCursor = parameterIterator.getNext();298}299}300else301{302uint32_t sizeOfParameterArea = method->getNumParameterSlots() << 2;303while (parmCursor != NULL)304{305parmCursor->setParameterOffset(sizeOfParameterArea -306parmCursor->getParameterOffset() -307parmCursor->getSize() +308offsetToFirstParm);309parmCursor = parameterIterator.getNext();310}311}312313atlas->setLocalBaseOffset(lowGCOffset - firstLocalOffset);314atlas->setParmBaseOffset(atlas->getParmBaseOffset() + offsetToFirstParm - firstLocalOffset);315}316317void J9::ARM::PrivateLinkage::mapSingleAutomatic(TR::AutomaticSymbol *p, uint32_t &stackIndex)318{319int32_t roundedSize = (p->getSize()+3)&(~3);320if (roundedSize == 0)321roundedSize = 4;322323p->setOffset(stackIndex -= roundedSize);324}325326void J9::ARM::PrivateLinkage::setParameterLinkageRegisterIndex(TR::ResolvedMethodSymbol *method)327{328ListIterator<TR::ParameterSymbol> paramIterator(&(method->getParameterList()));329TR::ParameterSymbol *paramCursor = paramIterator.getFirst();330int32_t numIntArgs = 0;331const TR::ARMLinkageProperties& properties = getProperties();332333while ( (paramCursor!=NULL) &&334(numIntArgs < properties.getNumIntArgRegs()) )335{336int32_t index = -1;337338switch (paramCursor->getDataType())339{340case TR::Int8:341case TR::Int16:342case TR::Int32:343case TR::Address:344case TR::Float://float args are passed in gpr345if (numIntArgs<properties.getNumIntArgRegs())346{347index = numIntArgs;348}349numIntArgs++;350break;351case TR::Int64:352case TR::Double://float args are passed in 2 gprs353if (numIntArgs<properties.getNumIntArgRegs())354{355index = numIntArgs;356}357numIntArgs += 2;358break;359}360paramCursor->setLinkageRegisterIndex(index);361paramCursor = paramIterator.getNext();362}363364}365366// the following three functions are to be modified together367// all lists are dealing with the _preserved_ registers on the machine368uint16_t getAssignedRegisterList(TR::Machine *machine, const TR::ARMLinkageProperties *linkage)369{370uint16_t assignedRegisters = 0;371372for(int i = TR::RealRegister::LastGPR; i; i--)373{374assignedRegisters <<= 1;375if(linkage->getPreserved((TR::RealRegister::RegNum)i))376{377assignedRegisters |= machine->getRealRegister((TR::RealRegister::RegNum)i)->getHasBeenAssignedInMethod();378}379}380381return assignedRegisters;382}383384uint16_t getAssignedRegisterCount(TR::Machine *machine, const TR::ARMLinkageProperties *linkage)385{386uint16_t assignedRegisters = 0;387388for (int i = TR::RealRegister::LastGPR; i; i--)389{390if (linkage->getPreserved((TR::RealRegister::RegNum)i))391{392assignedRegisters += machine->getRealRegister((TR::RealRegister::RegNum)i)->getHasBeenAssignedInMethod() ? 1 : 0;393}394}395396return assignedRegisters;397}398399TR::RealRegister::RegNum getSingleAssignedRegister(TR::Machine *machine, const TR::ARMLinkageProperties *linkage)400{401for (int i = TR::RealRegister::LastGPR; i; i--)402if (linkage->getPreserved((TR::RealRegister::RegNum)i) &&403machine->getRealRegister((TR::RealRegister::RegNum)i)->getHasBeenAssignedInMethod())404return (TR::RealRegister::RegNum) i;405return (TR::RealRegister::RegNum) -1;406}407408// OLD FRAME SHAPE NEW FRAME SHAPE409//410// + + + +411// | caller's frame | | caller's frame |412// +==========================+ <-+ BP +==========================+413// | locals | | | return address* |414// | register saves | | +--------------------------+ <-+ BP415// | outgoing arguments | size | locals | |416// | callee's return address* | | | register saves | size417// | (hole)* | | | outgoing arguments | |418// +==========================+ <-+ SP +==========================+ <-+ SP419// | callee's frame | | caller's frame |420//421// * Linkage slots are not needed in leaf methods. (TODO)422423void J9::ARM::PrivateLinkage::createPrologue(TR::Instruction *cursor)424{425TR::CodeGenerator *codeGen = cg();426TR::Machine *machine = codeGen->machine();427TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();428TR::RealRegister *stackPtr = machine->getRealRegister(properties.getStackPointerRegister());429TR::RealRegister *metaBase = codeGen->getMethodMetaDataRegister();430TR::Node *firstNode = comp()->getStartTree()->getNode();431int i;432433const TR::ARMLinkageProperties& linkage = getProperties();434435int32_t localSize = -((int32_t)bodySymbol->getLocalMappingCursor());436int32_t intRegistersSaved = getAssignedRegisterCount(machine, &linkage);437int32_t registerSaveDescription = getAssignedRegisterList(machine, &linkage);438439TR::RealRegister::RegNum lastSavedFPR = TR::RealRegister::LastFPR;440while (lastSavedFPR >= TR::RealRegister::fp8 &&441!machine->getRealRegister(lastSavedFPR)->getHasBeenAssignedInMethod())442{443lastSavedFPR = (TR::RealRegister::RegNum)((uint32_t)lastSavedFPR - 1);444}445446// TODO Fit GPR and FPR save data into (lower) 16 bits of descriptor.447int32_t fpRegistersSaved = (int32_t)lastSavedFPR + 1 - (int32_t)TR::RealRegister::fp8;448449int32_t registerSaveSize = intRegistersSaved * 4 + fpRegistersSaved * 8;450451int32_t outgoingArgSize = getOffsetToFirstParm() + codeGen->getLargestOutgoingArgSize();452int32_t totalFrameSize = localSize + registerSaveSize + outgoingArgSize;453454// Align frame to 8-byte boundaries.455if (debug("alignStackFrame"))456totalFrameSize += ((totalFrameSize & 4) ? 4 : 0);457458int32_t resudialSize = totalFrameSize + properties.getOffsetToFirstLocal();459460codeGen->setFrameSizeInBytes(resudialSize);461462// Put offset to saved registers in top 16 bit of descriptor.463int32_t offsetToSavedRegisters = localSize + properties.getOffsetToFirstLocal() + registerSaveSize;464TR_ASSERT(offsetToSavedRegisters < 65536,465"offset to saved registers from base of stack frame must be less than 2^16\n");466registerSaveDescription |= (offsetToSavedRegisters << 16);467codeGen->setRegisterSaveDescription(registerSaveDescription);468469if (comp()->getOption(TR_EntryBreakPoints))470{471cursor = new (trHeapMemory()) TR::Instruction(cursor, TR::InstOpCode::bad, firstNode, codeGen);472}473474// TODO Only save arguments if full-speed debugging is enabled; otherwise, they475// TODO should be moved from the registers in which they reside to the ones in476// TODO which the method body expects them. See copyParametersToHomeLocation in477// TODO the AMD64 codegen.478//479cursor = saveArguments(cursor);480481TR::RealRegister *gr4 = machine->getRealRegister(TR::RealRegister::gr4);482TR::RealRegister *gr5 = machine->getRealRegister(TR::RealRegister::gr5);483TR::RealRegister *gr11 = machine->getRealRegister(TR::RealRegister::gr11);484TR::RealRegister *gr14 = machine->getRealRegister(TR::RealRegister::gr14);485TR::MemoryReference *tempMR = NULL;486uint32_t base, rotate;487488// Save return address, decrement the stack pointer, and check for stack489// overflow.490//491if (!codeGen->getSnippetList().empty() ||492bodySymbol->isEHAware() ||493machine->getLinkRegisterKilled())494{495tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, -4, codeGen);496cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, firstNode, tempMR, gr14, cursor);497}498499if (constantIsImmed8r(totalFrameSize, &base, &rotate))500{501cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::sub, firstNode, stackPtr, stackPtr, base, rotate, cursor);502}503else504{505cursor = armLoadConstant(firstNode, totalFrameSize, gr11, codeGen, cursor);506cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::sub, firstNode, stackPtr, stackPtr, gr11, cursor);507}508509if (!comp()->isDLT())510{511tempMR = new (trHeapMemory()) TR::MemoryReference(metaBase, codeGen->getStackLimitOffset(), codeGen);512cursor = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, firstNode, gr4, tempMR, cursor);513cursor = generateSrc2Instruction(codeGen, TR::InstOpCode::cmp, firstNode, stackPtr, gr4, cursor);514515TR::LabelSymbol *snippetLabel = generateLabelSymbol(codeGen);516TR::LabelSymbol *restartLabel = generateLabelSymbol(codeGen);517518cursor = generateConditionalBranchInstruction(codeGen, firstNode, ARMConditionCodeLS, snippetLabel, cursor);519520TR::Snippet *snippet = new (trHeapMemory()) TR::ARMStackCheckFailureSnippet(codeGen, cursor->getNode(), restartLabel, snippetLabel);521snippet->resetNeedsExceptionTableEntry();522codeGen->addSnippet(snippet);523524cursor = generateLabelInstruction(codeGen, TR::InstOpCode::label, firstNode, restartLabel, cursor);525}526527// Save preserved registers.528// outgoingArgSize <= 1020 because the JVM spec limits the max number of method param to 255, so constantIsImmed8r can handle outgoingArgSize.529if (intRegistersSaved)530{531if (1 == intRegistersSaved)532{533TR::Register *reg = machine->getRealRegister(getSingleAssignedRegister(machine, &linkage));534tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, outgoingArgSize, codeGen);535cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, firstNode, tempMR, reg, cursor);536}537else538{539constantIsImmed8r(outgoingArgSize, &base, &rotate);540cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, firstNode, gr4, stackPtr, base, rotate, cursor);541// FIXME Need generateMultiMoveInstruction().542cursor = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(cursor, TR::InstOpCode::stm, firstNode, gr4, getAssignedRegisterList(machine, &linkage), codeGen);543}544}545546// for saving preserved VFP registers, the offset can be larger than 1024, so constantIsImmed10 and constantIsImmed8r might not be able to handle the offset.547outgoingArgSize += intRegistersSaved * 4;548if (fpRegistersSaved > 0)549{550if (1 == fpRegistersSaved)551{552TR::Register *reg = machine->getRealRegister(lastSavedFPR);553if (constantIsImmed10(outgoingArgSize))554{555tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, outgoingArgSize, codeGen);556}557else558{559cursor = armLoadConstant(firstNode, outgoingArgSize, gr4, codeGen, cursor);560cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, firstNode, gr4, stackPtr, gr4, cursor);561tempMR = new (trHeapMemory()) TR::MemoryReference(gr4, 0, codeGen);562}563cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::fstd, firstNode, tempMR, reg, cursor);564}565else566{567if (constantIsImmed8r(outgoingArgSize, &base, &rotate))568{569cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, firstNode, gr4, stackPtr, base, rotate, cursor);570}571else572{573cursor = armLoadConstant(firstNode, outgoingArgSize, gr4, codeGen, cursor);574cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, firstNode, gr4, stackPtr, gr4, cursor);575}576// FIXME Need generateMultiMoveInstruction().577uint16_t offset = ((TR::RealRegister::fp8 - TR::RealRegister::FirstFPR) << 12) | (fpRegistersSaved << 1);578cursor = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(cursor, TR::InstOpCode::fstmd, firstNode, gr4, offset, codeGen);579((TR::ARMMultipleMoveInstruction *)cursor)->setIncrement();580}581}582583// Initialize reference-type locals to NULL.584TR::GCStackAtlas *atlas = codeGen->getStackAtlas();585if (atlas)586{587uint32_t numLocalsToBeInitialized = atlas->getNumberOfSlotsToBeInitialized();588589// TODO Support internal pointers.590if (numLocalsToBeInitialized > 0)591{592uint32_t offset = resudialSize + atlas->getLocalBaseOffset();593cursor = armLoadConstant(firstNode, NULLVALUE, gr11, codeGen, cursor);594595if (numLocalsToBeInitialized > 0)596{597#if 0598traceMsg("%d locals to be initialized in %s\n",599numLocalsToBeInitialized,600signature(TR::comp()->getCurrentMethod()));601#endif602// Inline zero initialization if the number of stores is small;603// otherwise, set up a loop to perform the initialization.604if (numLocalsToBeInitialized > 8)605{606TR::LabelSymbol *loopLabel = generateLabelSymbol(codeGen);607cursor = armLoadConstant(firstNode, offset, gr4, codeGen, cursor);608cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, firstNode, gr4, gr4, stackPtr, cursor);609cursor = armLoadConstant(firstNode, (numLocalsToBeInitialized - 1) << 2, gr5, codeGen, cursor);610cursor = generateLabelInstruction(codeGen, TR::InstOpCode::label, firstNode, loopLabel, cursor);611tempMR = new (trHeapMemory()) TR::MemoryReference(gr4, gr5, codeGen);612cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, firstNode, tempMR, gr11, cursor);613cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::sub_r, firstNode, gr5, gr5, 4, 0, cursor);614cursor = generateConditionalBranchInstruction(codeGen, firstNode, ARMConditionCodeGE, loopLabel, cursor);615}616else617{618for (uint32_t i = 0; i < numLocalsToBeInitialized; i++, offset += 4)619{620tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, offset, codeGen);621cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, firstNode, tempMR, gr11, cursor);622}623}624}625}626627if (atlas->getInternalPointerMap())628{629int32_t offset = resudialSize + atlas->getOffsetOfFirstInternalPointer();630631// First collect all pinning arrays that are the base for at least632// one derived internal pointer stack slot633//634int32_t numDistinctPinningArrays = 0;635List<TR_InternalPointerPair> seenInternalPtrPairs(trMemory());636List<TR::AutomaticSymbol> seenPinningArrays(trMemory());637ListIterator<TR_InternalPointerPair> internalPtrIt(&atlas->getInternalPointerMap()->getInternalPointerPairs());638for (TR_InternalPointerPair *internalPtrPair = internalPtrIt.getFirst(); internalPtrPair; internalPtrPair = internalPtrIt.getNext())639{640bool seenPinningArrayBefore = false;641ListIterator<TR_InternalPointerPair> seenInternalPtrIt(&seenInternalPtrPairs);642for (TR_InternalPointerPair *seenInternalPtrPair = seenInternalPtrIt.getFirst(); seenInternalPtrPair && (seenInternalPtrPair != internalPtrPair); seenInternalPtrPair = seenInternalPtrIt.getNext())643{644if (internalPtrPair->getPinningArrayPointer() == seenInternalPtrPair->getPinningArrayPointer())645{646seenPinningArrayBefore = true;647break;648}649}650651if (!seenPinningArrayBefore)652{653seenPinningArrays.add(internalPtrPair->getPinningArrayPointer());654seenInternalPtrPairs.add(internalPtrPair);655numDistinctPinningArrays++;656}657}658659// Now collect all pinning arrays that are the base for only660// internal pointers in registers661//662ListIterator<TR::AutomaticSymbol> autoIt(&atlas->getPinningArrayPtrsForInternalPtrRegs());663TR::AutomaticSymbol *autoSymbol;664for (autoSymbol = autoIt.getFirst(); autoSymbol != NULL; autoSymbol = autoIt.getNext())665{666if (!seenPinningArrays.find(autoSymbol))667{668seenPinningArrays.add(autoSymbol);669numDistinctPinningArrays++;670}671}672673// Total number of slots to be initialized is number of pinning arrays +674// number of derived internal pointer stack slots675//676int32_t numSlotsToBeInitialized = numDistinctPinningArrays + atlas->getInternalPointerMap()->getNumInternalPointers();677678if ((numSlotsToBeInitialized > 0) && !(numLocalsToBeInitialized > 0))679{680cursor = armLoadConstant(firstNode, NULLVALUE, gr11, codeGen, cursor);681}682683for (i = 0; i < numSlotsToBeInitialized; i++, offset += TR::Compiler->om.sizeofReferenceAddress())684{685tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, offset, codeGen);686cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, firstNode, tempMR, gr11, cursor);687}688}689690// FIXME Remove calls to debug("hasFramePointer"). The VM no longer691// FIXME supports the use of a frame pointer. The TR_ASSERT() message692// FIXME below seems to have been inherited from the PPC codegen, and693// FIXME may be completely irrelevant.694//695if (!debug("hasFramePointer"))696{697// TR_ASSERT(totalFrameSize <= 1028, "Setting up a frame pointer anyway.");698ListIterator<TR::AutomaticSymbol> automaticIterator(&bodySymbol->getAutomaticList());699TR::AutomaticSymbol *localCursor = automaticIterator.getFirst();700while (localCursor)701{702localCursor->setOffset(localCursor->getOffset() + totalFrameSize);703localCursor = automaticIterator.getNext();704}705706ListIterator<TR::ParameterSymbol> parameterIterator(&bodySymbol->getParameterList());707TR::ParameterSymbol *parmCursor = parameterIterator.getFirst();708while (parmCursor)709{710parmCursor->setParameterOffset(parmCursor->getParameterOffset() + totalFrameSize);711parmCursor = parameterIterator.getNext();712}713}714715TR_GCStackMap *map = atlas->getLocalMap();716map->setLowestOffsetInstruction(cursor);717if (!comp()->useRegisterMaps())718atlas->addStackMap(map);719}720}721722void J9::ARM::PrivateLinkage::createEpilogue(TR::Instruction *cursor)723{724TR::CodeGenerator *codeGen = cg();725TR::Machine *machine = codeGen->machine();726TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();727TR::RealRegister *stackPtr = machine->getRealRegister(properties.getStackPointerRegister());728TR::Node *lastNode = cursor->getNode();729730const TR::ARMLinkageProperties &linkage = getProperties();731732int32_t localSize = -((int32_t)bodySymbol->getLocalMappingCursor());733int32_t intRegistersSaved = getAssignedRegisterCount(machine, &linkage);734735TR::RealRegister::RegNum lastSavedFPR = TR::RealRegister::LastFPR;736while (lastSavedFPR >= TR::RealRegister::fp8 &&737!machine->getRealRegister(lastSavedFPR)->getHasBeenAssignedInMethod())738{739lastSavedFPR = (TR::RealRegister::RegNum)((uint32_t)lastSavedFPR - 1);740}741742// TODO Fit GPR and FPR save data into (lower) 16 bits of descriptor.743int32_t fpRegistersSaved = (int32_t)lastSavedFPR + 1 - (int32_t)TR::RealRegister::fp8;744745int32_t registerSaveSize = intRegistersSaved * 4 + fpRegistersSaved * 8;746747int32_t outgoingArgSize = getOffsetToFirstParm() + codeGen->getLargestOutgoingArgSize();748int32_t totalFrameSize = localSize + registerSaveSize + outgoingArgSize;749750if (debug("alignStackFrame"))751totalFrameSize += ((totalFrameSize & 4) ? 4 : 0);752753// Reload preserved registers.754TR::MemoryReference *tempMR;755uint32_t base, rotate;756757if (intRegistersSaved)758{759if (1 == intRegistersSaved)760{761TR::RealRegister *reg = machine->getRealRegister(getSingleAssignedRegister(machine, &linkage));762tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, outgoingArgSize, codeGen);763cursor = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, lastNode, reg, tempMR, cursor);764}765else766{767TR::RealRegister *gr4 = machine->getRealRegister(TR::RealRegister::gr4);768constantIsImmed8r(outgoingArgSize, &base, &rotate);769cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, lastNode, gr4, stackPtr, base, rotate, cursor);770cursor = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(cursor, TR::InstOpCode::ldm, lastNode, gr4, getAssignedRegisterList(machine, &linkage), codeGen);771}772}773774outgoingArgSize += intRegistersSaved * 4;775if (fpRegistersSaved > 0)776{777TR::RealRegister *gr4 = machine->getRealRegister(TR::RealRegister::gr4);778if (1 == fpRegistersSaved)779{780TR::Register *reg = machine->getRealRegister(lastSavedFPR);781if (constantIsImmed10(outgoingArgSize))782{783tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, outgoingArgSize, codeGen);784}785else786{787cursor = armLoadConstant(lastNode, outgoingArgSize, gr4, codeGen, cursor);788cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, lastNode, gr4, stackPtr, gr4, cursor);789tempMR = new (trHeapMemory()) TR::MemoryReference(gr4, 0, codeGen);790}791cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::fldd, lastNode, tempMR, reg, cursor);792}793else794{795if (constantIsImmed8r(outgoingArgSize, &base, &rotate))796{797cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, lastNode, gr4, stackPtr, base, rotate, cursor);798}799else800{801cursor = armLoadConstant(lastNode, outgoingArgSize, gr4, codeGen, cursor);802cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, lastNode, gr4, stackPtr, gr4, cursor);803}804// FIXME Need generateMultiMoveInstruction().805uint16_t offset = ((TR::RealRegister::fp8 - TR::RealRegister::FirstFPR) << 12) | (fpRegistersSaved << 1);806cursor = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(cursor, TR::InstOpCode::fldmd, lastNode, gr4, offset, codeGen);807((TR::ARMMultipleMoveInstruction *)cursor)->setIncrement();808}809}810811// Reload return address.812TR::RealRegister *gr14 = machine->getRealRegister(TR::RealRegister::gr14);813TR::RealRegister *gr15 = machine->getRealRegister(TR::RealRegister::gr15);814815if (codeGen->getSnippetList().size() > 1 ||816(comp()->isDLT() && !codeGen->getSnippetList().empty()) ||817bodySymbol->isEHAware() ||818machine->getLinkRegisterKilled())819{820tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, totalFrameSize + properties.getOffsetToFirstLocal(), codeGen);821cursor = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, lastNode, gr14, tempMR, cursor);822}823824// Collapse stack frame and return.825if (constantIsImmed8r(totalFrameSize, &base, &rotate))826{827cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, lastNode, stackPtr, stackPtr, base, rotate, cursor);828}829else830{831TR::RealRegister *gr4 = machine->getRealRegister(TR::RealRegister::gr4);832cursor = armLoadConstant(lastNode, totalFrameSize, gr4, codeGen, cursor);833cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, lastNode, stackPtr, stackPtr, gr4, cursor);834}835836cursor = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, lastNode, gr15, gr14, cursor);837}838839TR::MemoryReference *J9::ARM::PrivateLinkage::getOutgoingArgumentMemRef(int32_t totalSize,840int32_t offset,841TR::Register *argReg,842TR::InstOpCode::Mnemonic opCode,843TR::ARMMemoryArgument &memArg)844{845#ifdef DEBUG_ARM_LINKAGE846printf("private: totalSize %d offset %d\n", totalSize, offset); fflush(stdout);847#endif848849int32_t spOffset = totalSize - offset - TR::Compiler->om.sizeofReferenceAddress();850TR::RealRegister *sp = cg()->machine()->getRealRegister(properties.getStackPointerRegister());851TR::MemoryReference *result = new (trHeapMemory()) TR::MemoryReference(sp, spOffset, cg());852memArg.argRegister = argReg;853memArg.argMemory = result;854memArg.opCode = opCode;855return result;856}857858int32_t J9::ARM::PrivateLinkage::buildArgs(TR::Node *callNode,859TR::RegisterDependencyConditions *dependencies,860TR::Register* &vftReg,861bool isVirtual)862{863return buildARMLinkageArgs(callNode, dependencies, vftReg, TR_Private, isVirtual);864}865866void J9::ARM::PrivateLinkage::buildVirtualDispatch(TR::Node *callNode,867TR::RegisterDependencyConditions *dependencies,868TR::RegisterDependencyConditions *postDeps,869TR::Register *vftReg,870uint32_t sizeOfArguments)871{872TR::CodeGenerator *codeGen = cg();873TR::Machine *machine = codeGen->machine();874875#ifdef LOCK_R14876/* Dependency #0 is for vftReg. */877TR::Register *gr11 = dependencies->searchPreConditionRegister(TR::RealRegister::gr11);878TR::Register *gr0 = dependencies->searchPreConditionRegister(TR::RealRegister::gr0);879TR::Register *gr4 = dependencies->searchPreConditionRegister(TR::RealRegister::gr4);880TR::RealRegister *gr14 = machine->getRealRegister(TR::RealRegister::gr14);881TR::RealRegister *gr15 = machine->getRealRegister(TR::RealRegister::gr15);882#else883TR::Register *gr11 = dependencies->searchPreConditionRegister(TR::RealRegister::gr11);884TR::Register *gr14 = dependencies->searchPreConditionRegister(TR::RealRegister::gr14);885TR::Register *gr0 = dependencies->searchPreConditionRegister(TR::RealRegister::gr0);886TR::Register *gr4 = dependencies->searchPreConditionRegister(TR::RealRegister::gr4);887TR::RealRegister *gr15 = machine->getRealRegister(TR::RealRegister::gr15);888#endif889890TR::SymbolReference *methodSymRef = callNode->getSymbolReference();891TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();892TR::LabelSymbol *doneLabel = NULL;893TR::Instruction *gcPoint;894895TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());896897// Computed calls898//899if (methodSymbol->isComputed())900{901void *thunk;902903switch (methodSymbol->getMandatoryRecognizedMethod())904{905case TR::java_lang_invoke_ComputedCalls_dispatchVirtual:906{907// Need a j2i thunk for the method that will ultimately be dispatched by this handle call908char *j2iSignature = fej9->getJ2IThunkSignatureForDispatchVirtual(methodSymbol->getMethod()->signatureChars(), methodSymbol->getMethod()->signatureLength(), comp());909int32_t signatureLen = strlen(j2iSignature);910thunk = fej9->getJ2IThunk(j2iSignature, signatureLen, comp());911if (!thunk)912{913thunk = fej9->setJ2IThunk(j2iSignature, signatureLen,914TR::ARMCallSnippet::generateVIThunk(fej9->getEquivalentVirtualCallNodeForDispatchVirtual(callNode, comp()), sizeOfArguments, codeGen), comp());915}916}917default:918if (fej9->needsInvokeExactJ2IThunk(callNode, comp()))919{920comp()->getPersistentInfo()->getInvokeExactJ2IThunkTable()->addThunk(921TR::ARMCallSnippet::generateInvokeExactJ2IThunk(callNode, sizeOfArguments, codeGen, methodSymbol->getMethod()->signatureChars()), fej9);922}923break;924}925926TR::Node *child = callNode->getFirstChild();927TR::Register *targetAddress = codeGen->evaluate(child);928if (targetAddress->getRegisterPair())929{930// On 32-bit, we can just ignore the top 32 bits of the 64-bit target address931targetAddress = targetAddress->getLowOrder();932}933doneLabel = generateLabelSymbol(codeGen);934generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr4, targetAddress);935936TR::Instruction *instr = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr14, gr15);937instr->setDependencyConditions(dependencies);938dependencies->incRegisterTotalUseCounts(codeGen);939940gcPoint = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr15, gr4);941942gcPoint->ARMNeedsGCMap(getProperties().getPreservedRegisterMapForGC());943944generateLabelInstruction(codeGen, TR::InstOpCode::label, callNode, doneLabel, postDeps);945946return;947}948949uint8_t *thunk = (uint8_t*)fej9->getJ2IThunk(methodSymbol->getMethod()->signatureChars(), methodSymbol->getMethod()->signatureLength(), comp());950if (!thunk)951thunk = (uint8_t*)fej9->setJ2IThunk(methodSymbol->getMethod()->signatureChars(), methodSymbol->getMethod()->signatureLength(), TR::ARMCallSnippet::generateVIThunk(callNode, sizeOfArguments, codeGen), comp());952953if (methodSymbol->isVirtual())954{955TR::Register * classReg;956if (methodSymRef == comp()->getSymRefTab()->findObjectNewInstanceImplSymbol())957{//In this case, methodSymRef is resolved and VTable index is small enough to fit in 12bit, so we can safely use gr11 for classReg.958classReg = gr11;959generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr11, new (trHeapMemory()) TR::MemoryReference(gr0, fej9->getOffsetOfClassFromJavaLangClassField(), codeGen));960}961else962{963classReg = vftReg;964}965TR::MemoryReference *tempMR;966if (methodSymRef->isUnresolved() || comp()->compileRelocatableCode())967{968doneLabel = generateLabelSymbol(codeGen);969970TR::LabelSymbol *snippetLabel = generateLabelSymbol(codeGen);971codeGen->addSnippet(new (trHeapMemory()) TR::ARMVirtualUnresolvedSnippet(codeGen,972callNode,973snippetLabel,974sizeOfArguments,975doneLabel,976thunk));977978// These 5 instructions will be ultimately modified to load the979// method pointer and move return address to link register.980// The 4 instruction before branch should be a no-op if the offset turns981// out to be within range (for most cases).982generateTrg1ImmInstruction(codeGen, TR::InstOpCode::mov, callNode, gr11, 0, 0);983generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, callNode, gr11, gr11, 0, 8);984generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, callNode, gr11, gr11, 0, 16);985generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, callNode, gr11, gr11, 0, 24);986987generateLabelInstruction(codeGen, TR::InstOpCode::b, callNode, snippetLabel, dependencies);988989tempMR = new (trHeapMemory()) TR::MemoryReference(classReg, 0, codeGen);990gcPoint = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr15, tempMR);991}992else993{994int32_t offset = methodSymRef->getOffset();995if (constantIsImmed12(offset))996{997TR::Instruction *instr = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr14, gr15);998instr->setDependencyConditions(dependencies);999dependencies->incRegisterTotalUseCounts(codeGen);10001001tempMR = new (trHeapMemory()) TR::MemoryReference(classReg, offset, codeGen);1002gcPoint = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr15, tempMR);1003gcPoint->setDependencyConditions(postDeps);1004postDeps->incRegisterTotalUseCounts(codeGen);1005}1006else1007{1008TR::Instruction *instr = armLoadConstant(callNode, offset, gr11, codeGen);1009instr = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr14, gr15);1010instr->setDependencyConditions(dependencies);1011dependencies->incRegisterTotalUseCounts(codeGen);10121013tempMR = new (trHeapMemory()) TR::MemoryReference(classReg, gr11, 0, codeGen);1014gcPoint = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr15, tempMR);1015gcPoint->setDependencyConditions(postDeps);1016postDeps->incRegisterTotalUseCounts(codeGen);1017}1018}1019}1020else1021{1022// TODO inline interface dispatch and IPIC1023doneLabel = generateLabelSymbol(codeGen);10241025TR::LabelSymbol *snippetLabel = generateLabelSymbol(codeGen);1026codeGen->addSnippet(new (trHeapMemory()) TR::ARMInterfaceCallSnippet(codeGen,1027callNode,1028snippetLabel,1029sizeOfArguments,1030doneLabel,1031thunk));10321033gcPoint = generateLabelInstruction(codeGen, TR::InstOpCode::b, callNode, snippetLabel, dependencies);1034}10351036gcPoint->ARMNeedsGCMap(getProperties().getPreservedRegisterMapForGC());10371038// Insert a return label if a snippet is used. The register dependency1039// pre-conditions must be anchored on the branch out, and the post-1040// conditions must be anchored on the return label.1041if (doneLabel)1042generateLabelInstruction(codeGen, TR::InstOpCode::label, callNode, doneLabel, postDeps);10431044return;1045}10461047TR::Register *J9::ARM::PrivateLinkage::buildDirectDispatch(TR::Node *callNode)1048{1049TR::MethodSymbol *callSym = callNode->getSymbol()->castToMethodSymbol();1050if (callSym->isJNI() &&1051callNode->isPreparedForDirectJNI())1052{1053callSym->setLinkage(TR_J9JNILinkage);1054TR::Linkage *linkage = cg()->getLinkage(callSym->getLinkageConvention());10551056return linkage->buildDirectDispatch(callNode);1057}1058else1059{1060return buildARMLinkageDirectDispatch(callNode);1061}1062}10631064TR::Register *J9::ARM::PrivateLinkage::buildIndirectDispatch(TR::Node *callNode)1065{1066TR::CodeGenerator *codeGen = cg();1067TR::Machine *machine = codeGen->machine();10681069const TR::ARMLinkageProperties &pp = getProperties();1070TR::RegisterDependencyConditions *deps =1071new (trHeapMemory()) TR::RegisterDependencyConditions(pp.getNumberOfDependencyGPRegisters() + 8 /*pp.getNumFloatArgRegs()*/,1072pp.getNumberOfDependencyGPRegisters() + 8 /* pp.getNumFloatArgRegs()*/, trMemory());10731074TR::Register *vftReg = NULL;1075int32_t argSize = buildArgs(callNode, deps, vftReg, true);1076deps->stopAddingConditions();10771078TR::RegisterDependencyConditions *postDeps = deps->clone(cg());10791080deps->setNumPostConditions(0, trMemory());1081postDeps->setNumPreConditions(0, trMemory());10821083#ifdef LOCK_R141084/* Dependency #0 is for vftReg. */1085TR::Register *gr11 = deps->searchPreConditionRegister(TR::RealRegister::gr11);1086TR::Register *gr0 = deps->searchPreConditionRegister(TR::RealRegister::gr0);1087TR::RealRegister *gr14 = machine->getRealRegister(TR::RealRegister::gr14);1088TR::RealRegister *gr15 = machine->getRealRegister(TR::RealRegister::gr15);1089#else1090TR::Register *gr11 = deps->searchPreConditionRegister(TR::RealRegister::gr11);1091TR::Register *gr14 = deps->searchPreConditionRegister(TR::RealRegister::gr14);1092TR::Register *gr0 = deps->searchPreConditionRegister(TR::RealRegister::gr0);1093TR::RealRegister *gr15 = machine->getRealRegister(TR::RealRegister::gr15);1094#endif10951096TR::Register *returnRegister;1097TR::DataType resType = callNode->getType();10981099buildVirtualDispatch(callNode, deps, postDeps, vftReg, argSize);11001101codeGen->machine()->setLinkRegisterKilled(true);1102codeGen->setHasCall();11031104switch(callNode->getOpCodeValue())1105{1106case TR::icalli:1107case TR::acalli:1108#if (defined(__VFP_FP__) && !defined(__SOFTFP__))1109case TR::fcalli:1110#endif1111returnRegister = postDeps->searchPostConditionRegister(pp.getIntegerReturnRegister());1112if (resType.isFloatingPoint())1113{1114TR::Register *tempReg = codeGen->allocateSinglePrecisionRegister();1115TR::Instruction *cursor = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::fmsr, callNode, tempReg, returnRegister);1116returnRegister = tempReg;1117}1118break;1119case TR::lcalli:1120#if (defined(__VFP_FP__) && !defined(__SOFTFP__))1121case TR::dcalli:1122#endif1123{1124TR::Register *lowReg = postDeps->searchPostConditionRegister(pp.getLongLowReturnRegister());1125TR::Register *highReg = postDeps->searchPostConditionRegister(pp.getLongHighReturnRegister());1126returnRegister = codeGen->allocateRegisterPair(lowReg, highReg);1127if (resType.isDouble())1128{1129TR::Register *tempReg = codeGen->allocateRegister(TR_FPR);1130TR::Instruction *cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::fmdrr, callNode, tempReg, lowReg, highReg);1131returnRegister = tempReg;1132}11331134}1135break;1136#if !defined(__VFP_FP__) || defined(__SOFTFP__)1137case TR::fcalli:1138case TR::dcalli:1139returnRegister = postDeps->searchPostConditionRegister(pp.getFloatReturnRegister());1140break;1141#endif1142case TR::calli:1143returnRegister = NULL;1144break;1145default:1146returnRegister = NULL;1147TR_ASSERT(0, "Unknown indirect call Opcode.");1148}11491150callNode->setRegister(returnRegister);1151return returnRegister;1152}11531154int32_t J9::ARM::HelperLinkage::buildArgs(TR::Node *callNode,1155TR::RegisterDependencyConditions *dependencies,1156TR::Register* &vftReg,1157bool isVirtual)1158{1159TR_ASSERT(!isVirtual, "virtual helper calls not supported");1160return buildARMLinkageArgs(callNode, dependencies, vftReg, TR_Helper, isVirtual);1161}116211631164