Path: blob/master/runtime/compiler/p/codegen/PPCJNILinkage.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2000, 2020 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/PPCJNILinkage.hpp"2324#include "codegen/CodeGenerator.hpp"25#include "codegen/CodeGeneratorUtils.hpp"26#include "codegen/Machine.hpp"27#include "codegen/Linkage_inlines.hpp"28#include "codegen/LiveRegister.hpp"29#include "codegen/RealRegister.hpp"30#include "codegen/Register.hpp"31#include "codegen/RegisterDependency.hpp"32#include "codegen/TreeEvaluator.hpp"33#include "compile/ResolvedMethod.hpp"34#include "env/CHTable.hpp"35#include "env/CompilerEnv.hpp"36#include "env/VMJ9.h"37#include "env/jittypes.h"38#include "il/LabelSymbol.hpp"39#include "il/Node.hpp"40#include "il/Node_inlines.hpp"41#include "infra/SimpleRegex.hpp"42#include "p/codegen/CallSnippet.hpp"43#include "p/codegen/GenerateInstructions.hpp"44#include "p/codegen/PPCEvaluator.hpp"45#include "p/codegen/PPCHelperCallSnippet.hpp"46#include "p/codegen/PPCInstruction.hpp"47#include "p/codegen/PPCTableOfConstants.hpp"48#include "p/codegen/StackCheckFailureSnippet.hpp"4950J9::Power::JNILinkage::JNILinkage(TR::CodeGenerator *cg)51: J9::Power::PrivateLinkage(cg)52{53//Copy out SystemLinkage properties. Assumes no objects in TR::PPCLinkageProperties.54TR::Linkage *sysLinkage = cg->getLinkage(TR_System);55const TR::PPCLinkageProperties& sysLinkageProperties = sysLinkage->getProperties();5657_properties = sysLinkageProperties;5859//Set preservedRegisterMapForGC to PrivateLinkage properties.60TR::Linkage *privateLinkage = cg->getLinkage(TR_Private);61const TR::PPCLinkageProperties& privateLinkageProperties = privateLinkage->getProperties();6263_properties._preservedRegisterMapForGC = privateLinkageProperties.getPreservedRegisterMapForGC();6465// TODO: JNI linkage should inherit from system linkage to avoid having to do this copying66setOffsetToFirstParm(sysLinkage->getOffsetToFirstParm());67}6869int32_t J9::Power::JNILinkage::buildArgs(TR::Node *callNode,70TR::RegisterDependencyConditions *dependencies,71const TR::PPCLinkageProperties &properties)72{73TR_ASSERT(0, "Should call J9::Power::JNILinkage::buildJNIArgs instead.");74return 0;75}7677TR::Register *J9::Power::JNILinkage::buildIndirectDispatch(TR::Node *callNode)78{79TR_ASSERT(0, "Calling J9::Power::JNILinkage::buildIndirectDispatch does not make sense.");80return NULL;81}8283void J9::Power::JNILinkage::buildVirtualDispatch(TR::Node *callNode,84TR::RegisterDependencyConditions *dependencies,85uint32_t sizeOfArguments)86{87TR_ASSERT(0, "Calling J9::Power::JNILinkage::buildVirtualDispatch does not make sense.");88}8990const TR::PPCLinkageProperties& J9::Power::JNILinkage::getProperties()91{92return _properties;93}9495TR::Register *J9::Power::JNILinkage::buildDirectDispatch(TR::Node *callNode)96{97bool aix_style_linkage = (comp()->target().isAIX() || (comp()->target().is64Bit() && comp()->target().isLinux()));98TR::LabelSymbol *returnLabel = generateLabelSymbol(cg());99TR::SymbolReference *callSymRef = callNode->getSymbolReference();100TR::MethodSymbol *callSymbol = callSymRef->getSymbol()->castToMethodSymbol();101TR::SymbolReference *gpuHelperSymRef;102103TR::ResolvedMethodSymbol *resolvedMethodSymbol;104TR_ResolvedMethod *resolvedMethod;105bool dropVMAccess;106bool isJNIGCPoint;107bool killNonVolatileGPRs;108bool checkExceptions;109bool createJNIFrame;110bool tearDownJNIFrame;111bool wrapRefs;112bool passReceiver;113bool passThread;114uintptr_t targetAddress;115116bool crc32m1 = (callSymbol->getRecognizedMethod() == TR::java_util_zip_CRC32_update);117bool crc32m2 = (callSymbol->getRecognizedMethod() == TR::java_util_zip_CRC32_updateBytes);118bool crc32m3 = (callSymbol->getRecognizedMethod() == TR::java_util_zip_CRC32_updateByteBuffer);119120// TODO: How to handle discontiguous array?121// The specialCaseJNI shortcut will mangle register dependencies and use system/C dispatch.122// The addresses of the optimized helpers in the server process will not necessarily123// match the client-side addresses, so we can't take this shortcut in JITServer mode.124bool specialCaseJNI = (crc32m1 || crc32m2 || crc32m3) && !comp()->requiresSpineChecks();125126#ifdef J9VM_OPT_JITSERVER127specialCaseJNI = specialCaseJNI && !comp()->isOutOfProcessCompilation();128#endif129130bool isGPUHelper = callSymbol->isHelper() && (callSymRef->getReferenceNumber() == TR_estimateGPU ||131callSymRef->getReferenceNumber() == TR_getStateGPU ||132callSymRef->getReferenceNumber() == TR_regionEntryGPU ||133callSymRef->getReferenceNumber() == TR_allocateGPUKernelParms ||134callSymRef->getReferenceNumber() == TR_copyToGPU ||135callSymRef->getReferenceNumber() == TR_launchGPUKernel ||136callSymRef->getReferenceNumber() == TR_copyFromGPU ||137callSymRef->getReferenceNumber() == TR_invalidateGPU ||138callSymRef->getReferenceNumber() == TR_regionExitGPU ||139callSymRef->getReferenceNumber() == TR_flushGPU);140141142static bool keepVMDuringGPUHelper = feGetEnv("TR_KeepVMDuringGPUHelper") ? true : false;143144TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());145if (!isGPUHelper)146{147resolvedMethodSymbol = callNode->getSymbol()->castToResolvedMethodSymbol();148resolvedMethod = resolvedMethodSymbol->getResolvedMethod();149dropVMAccess = !fej9->jniRetainVMAccess(resolvedMethod);150isJNIGCPoint = !fej9->jniNoGCPoint(resolvedMethod);151killNonVolatileGPRs = isJNIGCPoint;152checkExceptions = !fej9->jniNoExceptionsThrown(resolvedMethod);153createJNIFrame = !fej9->jniNoNativeMethodFrame(resolvedMethod);154tearDownJNIFrame = !fej9->jniNoSpecialTeardown(resolvedMethod);155wrapRefs = !fej9->jniDoNotWrapObjects(resolvedMethod);156passReceiver = !fej9->jniDoNotPassReceiver(resolvedMethod);157passThread = !fej9->jniDoNotPassThread(resolvedMethod);158targetAddress = (uintptr_t)resolvedMethod->startAddressForJNIMethod(comp());159}160else161{162gpuHelperSymRef = comp()->getSymRefTab()->methodSymRefFromName(comp()->getMethodSymbol(), "com/ibm/jit/JITHelpers", "GPUHelper", "()V", TR::MethodSymbol::Static);163resolvedMethodSymbol = gpuHelperSymRef->getSymbol()->castToResolvedMethodSymbol();164resolvedMethod = resolvedMethodSymbol->getResolvedMethod();165166if (keepVMDuringGPUHelper || (callSymRef->getReferenceNumber() == TR_copyToGPU || callSymRef->getReferenceNumber() == TR_copyFromGPU) || callSymRef->getReferenceNumber() == TR_regionExitGPU || callSymRef->getReferenceNumber() == TR_flushGPU)167dropVMAccess = false; //TR_copyToGPU, TR_copyFromGPU, TR_regionExitGPU, TR_flushGPU (and all others if keepVMDuringGPUHelper is true)168else169dropVMAccess = true; //TR_regionEntryGPU, TR_launchGPUKernel, TR_estimateGPU, TR_allocateGPUKernelParms, (only if keepVMDuringGPUHelper is false)170171isJNIGCPoint = true;172killNonVolatileGPRs = isJNIGCPoint;173checkExceptions = false;174createJNIFrame = true;175tearDownJNIFrame = true;176wrapRefs = false; //unused for this code path177passReceiver = true;178passThread = false;179targetAddress = (uintptr_t)callSymbol->getMethodAddress();180}181182if (!isGPUHelper && (callSymbol->isPureFunction() || resolvedMethodSymbol->canDirectNativeCall() || specialCaseJNI))183{184dropVMAccess = false;185killNonVolatileGPRs = false;186isJNIGCPoint = false;187checkExceptions = false;188createJNIFrame = false;189tearDownJNIFrame = false;190if (specialCaseJNI)191{192wrapRefs = false;193passReceiver = false;194passThread = false;195}196}197198TR::Instruction *gcPoint;199TR::Register *returnRegister = NULL;200TR::RealRegister *stackPtr = cg()->getStackPointerRegister();201TR::RealRegister *metaReg = cg()->getMethodMetaDataRegister();202TR::Register *gr2Reg, *gr30Reg, *gr31Reg;203int32_t argSize;204intptr_t aValue;205206TR::RegisterDependencyConditions *deps = new (trHeapMemory()) TR::RegisterDependencyConditions(104,104, trMemory());207const TR::PPCLinkageProperties& jniLinkageProperties = getProperties();208209if (killNonVolatileGPRs || dropVMAccess || checkExceptions || tearDownJNIFrame)210{211gr30Reg = cg()->allocateRegister();212gr31Reg = cg()->allocateRegister();213TR::addDependency(deps, gr30Reg, TR::RealRegister::gr30, TR_GPR, cg());214TR::addDependency(deps, gr31Reg, TR::RealRegister::gr31, TR_GPR, cg());215}216217if (killNonVolatileGPRs)218{219// We need to kill all the non-volatiles so that they'll be in a stack frame in case220// gc needs to find them.221if (comp()->target().is64Bit())222{223if (comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))224TR::addDependency(deps, NULL, TR::RealRegister::gr16, TR_GPR, cg());225}226else227{228// gr15 and gr16 are reserved in 64-bit, normal non-volatile in 32-bit229TR::addDependency(deps, NULL, TR::RealRegister::gr15, TR_GPR, cg());230TR::addDependency(deps, NULL, TR::RealRegister::gr16, TR_GPR, cg());231}232TR::addDependency(deps, NULL, TR::RealRegister::gr17, TR_GPR, cg());233TR::addDependency(deps, NULL, TR::RealRegister::gr18, TR_GPR, cg());234TR::addDependency(deps, NULL, TR::RealRegister::gr19, TR_GPR, cg());235TR::addDependency(deps, NULL, TR::RealRegister::gr20, TR_GPR, cg());236TR::addDependency(deps, NULL, TR::RealRegister::gr21, TR_GPR, cg());237TR::addDependency(deps, NULL, TR::RealRegister::gr22, TR_GPR, cg());238TR::addDependency(deps, NULL, TR::RealRegister::gr23, TR_GPR, cg());239TR::addDependency(deps, NULL, TR::RealRegister::gr24, TR_GPR, cg());240TR::addDependency(deps, NULL, TR::RealRegister::gr25, TR_GPR, cg());241TR::addDependency(deps, NULL, TR::RealRegister::gr26, TR_GPR, cg());242TR::addDependency(deps, NULL, TR::RealRegister::gr27, TR_GPR, cg());243#ifndef J9VM_INTERP_ATOMIC_FREE_JNI244if (!dropVMAccess)245#endif /* J9VM_INTERP_ATOMIC_FREE_JNI */246{247TR::addDependency(deps, NULL, TR::RealRegister::gr28, TR_GPR, cg());248TR::addDependency(deps, NULL, TR::RealRegister::gr29, TR_GPR, cg());249}250}251252cg()->machine()->setLinkRegisterKilled(true);253cg()->setHasCall();254255argSize = buildJNIArgs(callNode, deps, jniLinkageProperties, specialCaseJNI?false:true, passReceiver, passThread);256257if (aix_style_linkage)258{259if (specialCaseJNI)260gr2Reg = deps->searchPreConditionRegister(TR::RealRegister::gr2);261else262{263gr2Reg = cg()->allocateRegister();264TR::addDependency(deps, gr2Reg, TR::RealRegister::gr2, TR_GPR, cg());265}266}267268if (specialCaseJNI)269{270// No argument change is needed271if (crc32m1)272{273targetAddress = (uintptr_t)crc32_oneByte;274}275276// Argument changes are needed277if (crc32m2 || crc32m3)278{279targetAddress = (uintptr_t)((comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) && comp()->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX))?crc32_vpmsum:crc32_no_vpmsum);280281// Assuming pre/postCondition have the same index, we use preCondition to map282OMR::RegisterDependencyMap map(deps->getPreConditions()->getRegisterDependency(0), deps->getAddCursorForPre());283for (int32_t cnt=0; cnt < deps->getAddCursorForPre(); cnt++)284map.addDependency(deps->getPreConditions()->getRegisterDependency(cnt), cnt);285286TR::Register *addrArg, *posArg, *lenArg, *wasteArg;287if (crc32m2)288{289addrArg = map.getSourceWithTarget(TR::RealRegister::gr4);290posArg = map.getSourceWithTarget(TR::RealRegister::gr5);291lenArg = map.getSourceWithTarget(TR::RealRegister::gr6);292293generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2, callNode, addrArg, addrArg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes());294}295296if (crc32m3)297{298addrArg = map.getSourceWithTarget(comp()->target().is64Bit()?(TR::RealRegister::gr4):(TR::RealRegister::gr5));299posArg = map.getSourceWithTarget(comp()->target().is64Bit()?(TR::RealRegister::gr5):(TR::RealRegister::gr6));300lenArg = map.getSourceWithTarget(comp()->target().is64Bit()?(TR::RealRegister::gr6):(TR::RealRegister::gr7));301if (!comp()->target().is64Bit())302wasteArg = map.getSourceWithTarget(TR::RealRegister::gr4);303}304generateTrg1Src2Instruction(cg(), TR::InstOpCode::add, callNode, addrArg, addrArg, posArg);305306deps->getPreConditions()->setDependencyInfo(map.getTargetIndex(TR::RealRegister::gr4), addrArg, TR::RealRegister::gr4, UsesDependentRegister);307deps->getPostConditions()->setDependencyInfo(map.getTargetIndex(TR::RealRegister::gr4), addrArg, TR::RealRegister::gr4, UsesDependentRegister);308309deps->getPreConditions()->setDependencyInfo(map.getTargetIndex(TR::RealRegister::gr5), lenArg, TR::RealRegister::gr5, UsesDependentRegister);310deps->getPostConditions()->setDependencyInfo(map.getTargetIndex(TR::RealRegister::gr5), lenArg, TR::RealRegister::gr5, UsesDependentRegister);311312deps->getPreConditions()->setDependencyInfo(map.getTargetIndex(TR::RealRegister::gr6), posArg, TR::RealRegister::gr6, UsesDependentRegister);313deps->getPostConditions()->setDependencyInfo(map.getTargetIndex(TR::RealRegister::gr6), posArg, TR::RealRegister::gr6, UsesDependentRegister);314315if (crc32m3 && !comp()->target().is64Bit())316{317deps->getPreConditions()->setDependencyInfo(map.getTargetIndex(TR::RealRegister::gr7), wasteArg, TR::RealRegister::gr7, UsesDependentRegister);318deps->getPostConditions()->setDependencyInfo(map.getTargetIndex(TR::RealRegister::gr7), wasteArg, TR::RealRegister::gr7, UsesDependentRegister);319}320}321}322323TR::Register *gr0Reg = deps->searchPreConditionRegister(TR::RealRegister::gr0);324TR::Register *gr3Reg = deps->searchPreConditionRegister(TR::RealRegister::gr3);325TR::Register *gr11Reg = deps->searchPreConditionRegister(TR::RealRegister::gr11);326TR::Register *gr12Reg = deps->searchPreConditionRegister(TR::RealRegister::gr12);327TR::Register *cr0Reg = deps->searchPreConditionRegister(TR::RealRegister::cr0);328TR::Register *lowReg = NULL, *highReg;329330switch (callNode->getOpCodeValue())331{332case TR::icall:333case TR::acall:334if (callNode->getDataType() == TR::Address)335{336if (!gr3Reg)337{338gr3Reg = cg()->allocateRegister();339returnRegister = cg()->allocateCollectedReferenceRegister();340deps->addPreCondition(gr3Reg, TR::RealRegister::gr3);341deps->addPostCondition(returnRegister, TR::RealRegister::gr3);342}343else344{345returnRegister = deps->searchPostConditionRegister(TR::RealRegister::gr3);346}347}348else349{350if (!gr3Reg)351{352gr3Reg = cg()->allocateRegister();353returnRegister = gr3Reg;354TR::addDependency(deps, gr3Reg, TR::RealRegister::gr3, TR_GPR, cg());355}356else357{358returnRegister = deps->searchPostConditionRegister(TR::RealRegister::gr3);359}360}361break;362case TR::lcall:363if (comp()->target().is64Bit())364{365if (!gr3Reg)366{367gr3Reg = cg()->allocateRegister();368returnRegister = gr3Reg;369TR::addDependency(deps, gr3Reg, TR::RealRegister::gr3, TR_GPR, cg());370}371else372{373returnRegister = deps->searchPostConditionRegister(TR::RealRegister::gr3);374}375}376else377{378if (!gr3Reg)379{380gr3Reg = cg()->allocateRegister();381TR::addDependency(deps, gr3Reg, TR::RealRegister::gr3, TR_GPR, cg());382highReg = gr3Reg;383}384else385{386highReg = deps->searchPostConditionRegister(TR::RealRegister::gr3);387}388lowReg = deps->searchPostConditionRegister(TR::RealRegister::gr4);389returnRegister = cg()->allocateRegisterPair(lowReg, highReg);390}391break;392case TR::fcall:393case TR::dcall:394returnRegister = deps->searchPostConditionRegister(jniLinkageProperties.getFloatReturnRegister());395if (!gr3Reg)396{397gr3Reg = cg()->allocateRegister();398TR::addDependency(deps, gr3Reg, TR::RealRegister::gr3, TR_GPR, cg());399}400break;401case TR::call:402if (!gr3Reg)403{404gr3Reg = cg()->allocateRegister();405TR::addDependency(deps, gr3Reg, TR::RealRegister::gr3, TR_GPR, cg());406}407returnRegister = NULL;408break;409default:410if (!gr3Reg)411{412gr3Reg = cg()->allocateRegister();413TR::addDependency(deps, gr3Reg, TR::RealRegister::gr3, TR_GPR, cg());414}415returnRegister = NULL;416TR_ASSERT( false, "Unknown direct call Opcode.");417}418419if (createJNIFrame)420{421// push tag bits (savedA0)422int32_t tagBits = fej9->constJNICallOutFrameSpecialTag();423// if the current method is simply a wrapper for the JNI call, hide the call-out stack frame424if (resolvedMethod == comp()->getCurrentMethod())425tagBits |= fej9->constJNICallOutFrameInvisibleTag();426loadConstant(cg(), callNode, tagBits, gr11Reg);427loadConstant(cg(), callNode, 0, gr12Reg);428429generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stu, callNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, -TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()), gr11Reg);430431// skip savedPC slot (unused) and push return address (savedCP)432cg()->fixedLoadLabelAddressIntoReg(callNode, gr11Reg, returnLabel);433generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stu, callNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, -2*TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()), gr11Reg);434435// begin: mask out the magic bit that indicates JIT frames below436generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, callNode, TR::MemoryReference::createWithDisplacement(cg(), metaReg, fej9->thisThreadGetJavaFrameFlagsOffset(), TR::Compiler->om.sizeofReferenceAddress()), gr12Reg);437438// push flags: use lis instead of lis/ori pair since this is a constant. Save one instr439aValue = fej9->constJNICallOutFrameFlags();440TR_ASSERT_FATAL((aValue & ~0x7FFF0000) == 0, "Length assumption broken.");441generateTrg1ImmInstruction(cg(), TR::InstOpCode::lis, callNode, gr11Reg, aValue>>16);442generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stu, callNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, -TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()),gr11Reg);443444// push the RAM method for the native445aValue = (uintptr_t)resolvedMethod->resolvedMethodAddress();446// use loadAddressConstantFixed - fixed instruction count 2 32-bit, or 5 64-bit447// loadAddressRAM needs a resolved method symbol so the gpuHelper SumRef is passed in instead of448// the callSymRef which does not have a resolved method symbol449if (isGPUHelper)450callNode->setSymbolReference(gpuHelperSymRef);451loadAddressRAM(cg(), callNode, aValue, gr11Reg);452if (isGPUHelper)453callNode->setSymbolReference(callSymRef); //change back to callSymRef afterwards454generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stu, callNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, -TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()),gr11Reg);455456// store out jsp457generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, callNode, TR::MemoryReference::createWithDisplacement(cg(), metaReg,fej9->thisThreadGetJavaSPOffset(), TR::Compiler->om.sizeofReferenceAddress()), stackPtr);458459// store out pc and literals values indicating the callout frame460aValue = fej9->constJNICallOutFrameType();461TR_ASSERT(aValue>=LOWER_IMMED && aValue<=UPPER_IMMED, "Length assumption broken.");462loadConstant(cg(), callNode, (int32_t)aValue, gr11Reg);463generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, callNode, TR::MemoryReference::createWithDisplacement(cg(), metaReg,fej9->thisThreadGetJavaPCOffset(), TR::Compiler->om.sizeofReferenceAddress()), gr11Reg);464465generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, callNode, TR::MemoryReference::createWithDisplacement(cg(), metaReg,fej9->thisThreadGetJavaLiteralsOffset(), TR::Compiler->om.sizeofReferenceAddress()), gr12Reg);466}467468if (passThread)469generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, gr3Reg, metaReg);470471// Change if VMAccessLength if this code changes472if (dropVMAccess)473{474// At this point: arguments for the native routine are all in place already, i.e., if there are475// more than 32Byte worth of arguments, some of them are on the stack. However,476// we potentially go out to call a helper before jumping to the native. There is477// no definite guarantee that the helper call will not trash the stack area concerned.478// But GAC did make sure it is safe with the current helper implementation. If this479// condition changes in the future, we will need some heroic measure to fix it.480// Furthermore, this potential call should not touch FP argument registers. ***481#ifdef J9VM_INTERP_ATOMIC_FREE_JNI482releaseVMAccessAtomicFree(callNode, deps, metaReg, cr0Reg, gr30Reg, gr31Reg);483#else484releaseVMAccess(callNode, deps, metaReg, gr12Reg, gr30Reg, gr31Reg);485#endif /* J9VM_INTERP_ATOMIC_FREE_JNI */486}487488// get the address of the function descriptor489// use loadAddressConstantFixed - fixed instruction count 2 32-bit, or 5 64-bit490TR::Instruction *current = cg()->getAppendInstruction();491if (isGPUHelper)492loadConstant(cg(), callNode, (int64_t)targetAddress, gr12Reg);493else494loadAddressJNI(cg(), callNode, targetAddress, gr12Reg);495cg()->getJNICallSites().push_front(new (trHeapMemory()) TR_Pair<TR_ResolvedMethod, TR::Instruction>(resolvedMethod, current->getNext())); // the first instruction generated by loadAddressC...496497if (aix_style_linkage &&498!(comp()->target().is64Bit() && comp()->target().isLinux() && comp()->target().cpu.isLittleEndian()))499{500// get the target address501generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, callNode, gr0Reg, TR::MemoryReference::createWithDisplacement(cg(), gr12Reg, 0, TR::Compiler->om.sizeofReferenceAddress()));502// put the target address into the count register503generateSrc1Instruction(cg(), TR::InstOpCode::mtctr, callNode, gr0Reg);504// load the toc register505generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, callNode, gr2Reg, TR::MemoryReference::createWithDisplacement(cg(), gr12Reg, TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()));506// load the environment register507generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, callNode, gr11Reg, TR::MemoryReference::createWithDisplacement(cg(), gr12Reg, 2*TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()));508}509else510{511// put the target address into the count register512generateSrc1Instruction(cg(), TR::InstOpCode::mtctr, callNode, gr12Reg);513}514515// call the JNI function516if (isJNIGCPoint)517{518gcPoint = generateInstruction(cg(), TR::InstOpCode::bctrl, callNode);519gcPoint->PPCNeedsGCMap(jniLinkageProperties.getPreservedRegisterMapForGC());520}521else522{523generateInstruction(cg(), TR::InstOpCode::bctrl, callNode);524}525generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, returnLabel, deps);526527if (dropVMAccess)528{529// Again, we have dependency on the fact that:530// 1) this potential call will not trash the in-register return values531// 2) we know GPRs are ok, since OTI saves GPRs before use532// 3) FPRs are not so sure, pending GAC's verification ***533#ifdef J9VM_INTERP_ATOMIC_FREE_JNI534acquireVMAccessAtomicFree(callNode, deps, metaReg, cr0Reg, gr30Reg, gr31Reg);535#else536acquireVMAccess(callNode, deps, metaReg, gr12Reg, gr30Reg, gr31Reg);537#endif /* J9VM_INTERP_ATOMIC_FREE_JNI */538}539540// jni methods may not return a full register in some cases so need to get the declared541// type so that we sign and zero extend the narrower integer return types properly542TR::LabelSymbol *tempLabel = generateLabelSymbol(cg());543if (!isGPUHelper)544{545switch (resolvedMethod->returnType())546{547case TR::Address:548if (wrapRefs)549{550// Unwrap the returned object if non-null551generateTrg1Src1ImmInstruction(cg(),TR::InstOpCode::Op_cmpi, callNode, cr0Reg, returnRegister, 0);552generateConditionalBranchInstruction(cg(), TR::InstOpCode::beq, callNode, tempLabel, cr0Reg);553generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, callNode, returnRegister, TR::MemoryReference::createWithDisplacement(cg(), returnRegister, 0, TR::Compiler->om.sizeofReferenceAddress()));554generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, tempLabel);555}556break;557case TR::Int8:558if (comp()->getSymRefTab()->isReturnTypeBool(callSymRef))559{560// For bool return type, must check whether value return by561// JNI is zero (false) or non-zero (true) to yield Java result562generateTrg1Src1ImmInstruction(cg(),TR::InstOpCode::Op_cmpi, callNode, cr0Reg, returnRegister, 0);563generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, callNode, returnRegister, 1);564generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, callNode, tempLabel, cr0Reg);565generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, callNode, returnRegister, 0);566generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, tempLabel);567}568else if (resolvedMethod->returnTypeIsUnsigned())569generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::andi_r, callNode, returnRegister, returnRegister, 0xff);570else571generateTrg1Src1Instruction(cg(), TR::InstOpCode::extsb, callNode, returnRegister, returnRegister);572break;573case TR::Int16:574if (resolvedMethod->returnTypeIsUnsigned())575generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::andi_r, callNode, returnRegister, returnRegister, 0xffff);576else577generateTrg1Src1Instruction(cg(), TR::InstOpCode::extsh, callNode, returnRegister, returnRegister);578break;579}580}581582if (createJNIFrame)583{584// restore stack pointer: need to deal with growable stack -- stack may already be moved.585generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, callNode, gr12Reg, TR::MemoryReference::createWithDisplacement(cg(), metaReg, fej9->thisThreadGetJavaLiteralsOffset(), TR::Compiler->om.sizeofReferenceAddress()));586generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, callNode, stackPtr, TR::MemoryReference::createWithDisplacement(cg(), metaReg,fej9->thisThreadGetJavaSPOffset(), TR::Compiler->om.sizeofReferenceAddress()));587generateTrg1Src2Instruction(cg(), TR::InstOpCode::add, callNode, stackPtr, gr12Reg, stackPtr);588589if (tearDownJNIFrame)590{591// must check to see if the ref pool was used and clean them up if so--or we592// leave a bunch of pinned garbage behind that screws up the gc quality forever593// Again, depend on that this call will not trash return register values, especially FPRs.594// Pending GAC's verification. ***595uint32_t flagValue = fej9->constJNIReferenceFrameAllocatedFlags();596TR::LabelSymbol *refPoolRestartLabel = generateLabelSymbol(cg());597TR::SymbolReference *collapseSymRef = cg()->getSymRefTab()->findOrCreateRuntimeHelper(TR_PPCcollapseJNIReferenceFrame);598599generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, callNode, gr30Reg, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, fej9->constJNICallOutFrameFlagsOffset(), TR::Compiler->om.sizeofReferenceAddress()));600simplifyANDRegImm(callNode, gr31Reg, gr30Reg, flagValue, cg());601generateTrg1Src1ImmInstruction(cg(),TR::InstOpCode::Op_cmpi, callNode, cr0Reg, gr31Reg, 0);602generateConditionalBranchInstruction(cg(), TR::InstOpCode::beq, callNode, refPoolRestartLabel, cr0Reg);603generateDepImmSymInstruction(cg(), TR::InstOpCode::bl, callNode, (uintptr_t)collapseSymRef->getMethodAddress(), new (trHeapMemory()) TR::RegisterDependencyConditions(0,0, trMemory()), collapseSymRef, NULL);604generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, refPoolRestartLabel);605}606607// Restore the JIT frame608generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2, callNode, stackPtr, stackPtr, 5*TR::Compiler->om.sizeofReferenceAddress());609}610611if (checkExceptions)612{613generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, callNode, gr31Reg, TR::MemoryReference::createWithDisplacement(cg(), metaReg, fej9->thisThreadGetCurrentExceptionOffset(), TR::Compiler->om.sizeofReferenceAddress()));614generateTrg1Src1ImmInstruction(cg(),TR::InstOpCode::Op_cmpi, callNode, cr0Reg, gr31Reg, 0);615616TR::SymbolReference *throwSymRef = comp()->getSymRefTab()->findOrCreateThrowCurrentExceptionSymbolRef(comp()->getJittedMethodSymbol());617TR::LabelSymbol *exceptionSnippetLabel = cg()->lookUpSnippet(TR::Snippet::IsHelperCall, throwSymRef);618if (exceptionSnippetLabel == NULL)619{620exceptionSnippetLabel = generateLabelSymbol(cg());621cg()->addSnippet(new (trHeapMemory()) TR::PPCHelperCallSnippet(cg(), callNode, exceptionSnippetLabel, throwSymRef));622}623gcPoint = generateConditionalBranchInstruction(cg(), TR::InstOpCode::bnel, callNode, exceptionSnippetLabel, cr0Reg);624gcPoint->PPCNeedsGCMap(0x10000000);625}626627TR::LabelSymbol *depLabel = generateLabelSymbol(cg());628generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, depLabel, deps->cloneAndFix(cg()));629630callNode->setRegister(returnRegister);631632cg()->freeAndResetTransientLongs();633deps->stopUsingDepRegs(cg(), lowReg == NULL ? returnRegister : highReg, lowReg);634635return returnRegister;636}637638// tempReg0 to tempReg2 are temporary registers639void J9::Power::JNILinkage::releaseVMAccess(TR::Node* callNode, TR::RegisterDependencyConditions* deps, TR::RealRegister* metaReg, TR::Register* tempReg0, TR::Register* tempReg1, TR::Register* tempReg2)640{641// Release vm access - use hardware registers because of the control flow642TR::Instruction *gcPoint;643const TR::PPCLinkageProperties &properties = getProperties();644645TR::Register *gr28Reg = cg()->allocateRegister();646TR::Register *gr29Reg = cg()->allocateRegister();647TR::Register *cr0Reg = deps->searchPreConditionRegister(TR::RealRegister::cr0);648649TR::addDependency(deps, gr28Reg, TR::RealRegister::gr28, TR_GPR, cg());650TR::addDependency(deps, gr29Reg, TR::RealRegister::gr29, TR_GPR, cg());651652intptr_t aValue;653654TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());655aValue = fej9->constReleaseVMAccessOutOfLineMask();656TR_ASSERT(aValue<=0x7fffffff, "Value assumption broken.");657// use loadIntConstantFixed - fixed instruction count 2 with int32_t argument658cg()->loadIntConstantFixed(callNode, (int32_t) aValue, tempReg1);659660aValue = fej9->constReleaseVMAccessMask();661// use loadAddressConstantFixed - fixed instruction count 2 32-bit, or 5 64-bit662cg()->loadAddressConstantFixed(callNode, aValue, tempReg0, NULL, NULL, -1, false);663generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2, callNode, gr28Reg, metaReg,664fej9->thisThreadGetPublicFlagsOffset());665generateInstruction(cg(), TR::InstOpCode::lwsync, callNode); // This is necessary for the fast path but redundant for the slow path666TR::LabelSymbol *loopHead = generateLabelSymbol(cg());667generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, loopHead);668generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_larx, callNode, tempReg2, TR::MemoryReference::createWithIndexReg(cg(), NULL, gr28Reg, TR::Compiler->om.sizeofReferenceAddress()));669generateTrg1Src2Instruction(cg(), TR::InstOpCode::and_r, callNode, gr29Reg, tempReg2, tempReg1);670generateTrg1Src2Instruction(cg(), TR::InstOpCode::AND, callNode, tempReg2, tempReg2, tempReg0);671672TR::LabelSymbol *longReleaseLabel = generateLabelSymbol(cg());673TR::LabelSymbol *longReleaseSnippetLabel;674TR::LabelSymbol *doneLabel = generateLabelSymbol(cg());675TR::SymbolReference *relVMSymRef = comp()->getSymRefTab()->findOrCreateReleaseVMAccessSymbolRef(comp()->getJittedMethodSymbol());676longReleaseSnippetLabel = cg()->lookUpSnippet(TR::Snippet::IsHelperCall, relVMSymRef);677if (longReleaseSnippetLabel == NULL)678{679longReleaseSnippetLabel = generateLabelSymbol(cg());680cg()->addSnippet(new (trHeapMemory()) TR::PPCHelperCallSnippet(cg(), callNode, longReleaseSnippetLabel, relVMSymRef));681}682683generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, callNode, longReleaseLabel, cr0Reg);684generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stcx_r, callNode, TR::MemoryReference::createWithIndexReg(cg(), NULL, gr28Reg, TR::Compiler->om.sizeofReferenceAddress()), tempReg2);685686if (comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))687// use PPC AS branch hint688generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, callNode, loopHead, cr0Reg);689else690generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, callNode, loopHead, cr0Reg);691692generateLabelInstruction(cg(), TR::InstOpCode::b, callNode, doneLabel);693generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, longReleaseLabel);694gcPoint = generateLabelInstruction(cg(), TR::InstOpCode::bl, callNode, longReleaseSnippetLabel);695gcPoint->PPCNeedsGCMap(~(properties.getPreservedRegisterMapForGC()));696generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel);697// end of release vm access (spin lock)698}699700// tempReg0 to tempReg2 are temporary registers701void J9::Power::JNILinkage::acquireVMAccess(TR::Node* callNode, TR::RegisterDependencyConditions* deps, TR::RealRegister* metaReg, TR::Register* tempReg0, TR::Register* tempReg1, TR::Register* tempReg2)702{703// Acquire VM Access704TR::Instruction *gcPoint;705706TR::Register *cr0Reg = deps->searchPreConditionRegister(TR::RealRegister::cr0);707708TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());709loadConstant(cg(), callNode, (int32_t)fej9->constAcquireVMAccessOutOfLineMask(), tempReg1);710generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2, callNode, tempReg0, metaReg,711fej9->thisThreadGetPublicFlagsOffset());712TR::LabelSymbol *loopHead2 = generateLabelSymbol(cg());713generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, loopHead2);714generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_larx, PPCOpProp_LoadReserveExclusiveAccess, callNode, tempReg2, TR::MemoryReference::createWithIndexReg(cg(), NULL, tempReg0, TR::Compiler->om.sizeofReferenceAddress()));715generateTrg1Src1ImmInstruction(cg(),TR::InstOpCode::Op_cmpi, callNode, cr0Reg, tempReg2, 0);716TR::LabelSymbol *longReacquireLabel = generateLabelSymbol(cg());717TR::LabelSymbol *longReacquireSnippetLabel;718TR::LabelSymbol *doneLabel2 = generateLabelSymbol(cg());719TR::SymbolReference *acqVMSymRef = comp()->getSymRefTab()->findOrCreateAcquireVMAccessSymbolRef(comp()->getJittedMethodSymbol());720longReacquireSnippetLabel = cg()->lookUpSnippet(TR::Snippet::IsHelperCall, acqVMSymRef);721if (longReacquireSnippetLabel == NULL)722{723longReacquireSnippetLabel = generateLabelSymbol(cg());724cg()->addSnippet(new (trHeapMemory()) TR::PPCHelperCallSnippet(cg(), callNode, longReacquireSnippetLabel, acqVMSymRef));725}726727generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, callNode, longReacquireLabel, cr0Reg);728generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stcx_r, callNode, TR::MemoryReference::createWithIndexReg(cg(), NULL, tempReg0, TR::Compiler->om.sizeofReferenceAddress()), tempReg1);729730if (comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))731// use PPC AS branch hint732generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, callNode, loopHead2, cr0Reg);733else734generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, callNode, loopHead2, cr0Reg);735736generateInstruction(cg(), TR::InstOpCode::isync, callNode);737generateLabelInstruction(cg(), TR::InstOpCode::b, callNode, doneLabel2);738generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, longReacquireLabel);739gcPoint = generateLabelInstruction(cg(), TR::InstOpCode::bl, callNode, longReacquireSnippetLabel);740gcPoint->PPCNeedsGCMap(0x00000000);741generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel2);742// end of reacquire VM Access743}744745#ifdef J9VM_INTERP_ATOMIC_FREE_JNI746void J9::Power::JNILinkage::releaseVMAccessAtomicFree(TR::Node* callNode, TR::RegisterDependencyConditions* deps, TR::RealRegister* metaReg, TR::Register* cr0Reg, TR::Register* tempReg1, TR::Register* tempReg2)747{748TR_J9VMBase *fej9 = (TR_J9VMBase *)fe();749750#if !defined(J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH)751generateInstruction(cg(), TR::InstOpCode::lwsync, callNode);752#endif /* !J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH */753generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, callNode, tempReg1, 1);754generateMemSrc1Instruction(cg(), TR::InstOpCode::Op_st, callNode, TR::MemoryReference::createWithDisplacement(cg(), metaReg, (int32_t)offsetof(struct J9VMThread, inNative), TR::Compiler->om.sizeofReferenceAddress()), tempReg1);755#if !defined(J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH)756generateInstruction(cg(), TR::InstOpCode::sync, callNode);757#endif /* !J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH */758generateTrg1MemInstruction(cg(), TR::InstOpCode::Op_load, callNode, tempReg1, TR::MemoryReference::createWithDisplacement(cg(), metaReg, fej9->thisThreadGetPublicFlagsOffset(), TR::Compiler->om.sizeofReferenceAddress()));759TR_ASSERT_FATAL(J9_PUBLIC_FLAGS_VM_ACCESS >= LOWER_IMMED && J9_PUBLIC_FLAGS_VM_ACCESS <= UPPER_IMMED, "VM access bit must be immediate");760generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::Op_cmpli, callNode, cr0Reg, tempReg1, J9_PUBLIC_FLAGS_VM_ACCESS);761762TR::SymbolReference *jitReleaseVMAccessSymRef = comp()->getSymRefTab()->findOrCreateReleaseVMAccessSymbolRef(comp()->getJittedMethodSymbol());763TR::LabelSymbol *releaseVMAccessSnippetLabel = cg()->lookUpSnippet(TR::Snippet::IsHelperCall, jitReleaseVMAccessSymRef);764if (!releaseVMAccessSnippetLabel)765{766releaseVMAccessSnippetLabel = generateLabelSymbol(cg());767cg()->addSnippet(new (trHeapMemory()) TR::PPCHelperCallSnippet(cg(), callNode, releaseVMAccessSnippetLabel, jitReleaseVMAccessSymRef));768}769770if (comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))771generateConditionalBranchInstruction(cg(), TR::InstOpCode::bnel, PPCOpProp_BranchUnlikely, callNode, releaseVMAccessSnippetLabel, cr0Reg);772else773generateConditionalBranchInstruction(cg(), TR::InstOpCode::bnel, callNode, releaseVMAccessSnippetLabel, cr0Reg);774}775776void J9::Power::JNILinkage::acquireVMAccessAtomicFree(TR::Node* callNode, TR::RegisterDependencyConditions* deps, TR::RealRegister* metaReg, TR::Register* cr0Reg, TR::Register* tempReg1, TR::Register* tempReg2)777{778TR_J9VMBase *fej9 = (TR_J9VMBase *)fe();779780generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, callNode, tempReg1, 0);781generateMemSrc1Instruction(cg(), TR::InstOpCode::Op_st, callNode, TR::MemoryReference::createWithDisplacement(cg(), metaReg, (int32_t)offsetof(struct J9VMThread, inNative), TR::Compiler->om.sizeofReferenceAddress()), tempReg1);782#if !defined(J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH)783generateInstruction(cg(), TR::InstOpCode::sync, callNode);784#endif /* !J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH */785generateTrg1MemInstruction(cg(), TR::InstOpCode::Op_load, callNode, tempReg1, TR::MemoryReference::createWithDisplacement(cg(), metaReg, fej9->thisThreadGetPublicFlagsOffset(), TR::Compiler->om.sizeofReferenceAddress()));786TR_ASSERT_FATAL(J9_PUBLIC_FLAGS_VM_ACCESS >= LOWER_IMMED && J9_PUBLIC_FLAGS_VM_ACCESS <= UPPER_IMMED, "VM access bit must be immediate");787generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::Op_cmpli, callNode, cr0Reg, tempReg1, J9_PUBLIC_FLAGS_VM_ACCESS);788789TR::SymbolReference *jitAcquireVMAccessSymRef = comp()->getSymRefTab()->findOrCreateAcquireVMAccessSymbolRef(comp()->getJittedMethodSymbol());790TR::LabelSymbol *acquireVMAccessSnippetLabel = cg()->lookUpSnippet(TR::Snippet::IsHelperCall, jitAcquireVMAccessSymRef);791if (!acquireVMAccessSnippetLabel)792{793acquireVMAccessSnippetLabel = generateLabelSymbol(cg());794cg()->addSnippet(new (trHeapMemory()) TR::PPCHelperCallSnippet(cg(), callNode, acquireVMAccessSnippetLabel, jitAcquireVMAccessSymRef));795}796797if (comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))798generateConditionalBranchInstruction(cg(), TR::InstOpCode::bnel, PPCOpProp_BranchUnlikely, callNode, acquireVMAccessSnippetLabel, cr0Reg);799else800generateConditionalBranchInstruction(cg(), TR::InstOpCode::bnel, callNode, acquireVMAccessSnippetLabel, cr0Reg);801}802#endif /* J9VM_INTERP_ATOMIC_FREE_JNI */803804int32_t J9::Power::JNILinkage::buildJNIArgs(TR::Node *callNode,805TR::RegisterDependencyConditions *dependencies,806const TR::PPCLinkageProperties &properties,807bool isFastJNI,808bool passReceiver,809bool implicitEnvArg)810811{812//TODO: Temporary clone of PPCSystemLinkage::buildArgs. Both PPCSystemLinkage::buildArgs and813//this buildJNIArgs will be refactored for commonality.814815TR::PPCMemoryArgument *pushToMemory = NULL;816TR::Register *tempRegister;817int32_t argIndex = 0, memArgs = 0, i;818int32_t argSize = 0;819uint32_t numIntegerArgs = 0;820uint32_t numFloatArgs = 0;821822TR::Node *child;823void *smark;824TR::DataType resType = callNode->getType();825TR_Array<TR::Register *> &tempLongRegisters = cg()->getTransientLongRegisters();826TR::Symbol * callSymbol = callNode->getSymbolReference()->getSymbol();827828uint32_t firstArgumentChild = callNode->getFirstArgumentIndex();829830bool aix_style_linkage = (comp()->target().isAIX() || (comp()->target().is64Bit() && comp()->target().isLinux()));831832if (isFastJNI) // Account for extra parameters (env and obj)833{834if (implicitEnvArg)835numIntegerArgs += 1;836if (!passReceiver)837{838// Evaluate as usual if necessary, but don't actually pass it to the callee839TR::Node *firstArgChild = callNode->getChild(firstArgumentChild);840if (firstArgChild->getReferenceCount() > 1)841{842switch (firstArgChild->getDataType())843{844case TR::Int32:845pushIntegerWordArg(firstArgChild);846break;847case TR::Int64:848pushLongArg(firstArgChild);849break;850case TR::Address:851pushAddressArg(firstArgChild);852break;853default:854TR_ASSERT( false, "Unexpected first child type");855}856}857else858cg()->recursivelyDecReferenceCount(firstArgChild);859firstArgumentChild += 1;860}861}862863/* Step 1 - figure out how many arguments are going to be spilled to memory i.e. not in registers */864for (i = firstArgumentChild; i < callNode->getNumChildren(); i++)865{866child = callNode->getChild(i);867switch (child->getDataType())868{869case TR::Int8:870case TR::Int16:871case TR::Int32:872case TR::Address:873if (numIntegerArgs >= properties.getNumIntArgRegs())874memArgs++;875numIntegerArgs++;876break;877case TR::Int64:878if (comp()->target().is64Bit())879{880if (numIntegerArgs >= properties.getNumIntArgRegs())881memArgs++;882numIntegerArgs++;883}884else885{886if (aix_style_linkage)887{888if (numIntegerArgs == properties.getNumIntArgRegs()-1)889memArgs++;890else if (numIntegerArgs > properties.getNumIntArgRegs()-1)891memArgs += 2;892}893else894{895if (numIntegerArgs & 1)896numIntegerArgs++;897if (numIntegerArgs >= properties.getNumIntArgRegs())898memArgs += 2;899}900numIntegerArgs += 2;901}902break;903case TR::Float:904if (aix_style_linkage)905{906if (numIntegerArgs >= properties.getNumIntArgRegs())907memArgs++;908numIntegerArgs++;909}910else911{912if (numFloatArgs >= properties.getNumFloatArgRegs())913memArgs++;914}915numFloatArgs++;916break;917case TR::Double:918if (aix_style_linkage)919{920if (comp()->target().is64Bit())921{922if (numIntegerArgs >= properties.getNumIntArgRegs())923memArgs++;924numIntegerArgs++;925}926else927{928if (numIntegerArgs >= properties.getNumIntArgRegs()-1)929memArgs++;930numIntegerArgs += 2;931}932}933else934{935if (numFloatArgs >= properties.getNumFloatArgRegs())936memArgs++;937}938numFloatArgs++;939break;940case TR::VectorDouble:941TR_ASSERT(false, "JNI dispatch: VectorDouble argument not expected");942break;943case TR::Aggregate:944{945size_t size = child->getSymbolReference()->getSymbol()->getSize();946size = (size + sizeof(uintptr_t) - 1) & (~(sizeof(uintptr_t) - 1)); // round up the size947size_t slots = size / sizeof(uintptr_t);948949if (numIntegerArgs >= properties.getNumIntArgRegs())950memArgs += slots;951else952memArgs += (properties.getNumIntArgRegs() - numIntegerArgs) > slots ? 0: slots - (properties.getNumIntArgRegs() - numIntegerArgs);953numIntegerArgs += slots;954}955break;956default:957TR_ASSERT(false, "Argument type %s is not supported\n", child->getDataType().toString());958}959}960961// From here, down, any new stack allocations will expire / die when the function returns962TR::StackMemoryRegion stackMemoryRegion(*trMemory());963964/* End result of Step 1 - determined number of memory arguments! */965if (memArgs > 0)966{967pushToMemory = new (trStackMemory()) TR::PPCMemoryArgument[memArgs];968}969970numIntegerArgs = 0;971numFloatArgs = 0;972973if (isFastJNI && implicitEnvArg) // Account for extra parameter (env)974{975// first argument is JNIenv976numIntegerArgs += 1;977if (aix_style_linkage)978argSize += TR::Compiler->om.sizeofReferenceAddress();979}980981for (i = firstArgumentChild; i < callNode->getNumChildren(); i++)982{983TR::MemoryReference *mref=NULL;984TR::Register *argRegister;985bool checkSplit = true;986987child = callNode->getChild(i);988TR::DataType childType = child->getDataType();989990switch (childType)991{992case TR::Int8:993case TR::Int16:994case TR::Int32:995case TR::Address: // have to do something for GC maps here996if (isFastJNI && childType==TR::Address)997{998argRegister = pushJNIReferenceArg(child);999checkSplit = false;1000}1001else1002if (childType == TR::Address && !isFastJNI)1003argRegister = pushAddressArg(child);1004else1005argRegister = pushIntegerWordArg(child);10061007if (numIntegerArgs < properties.getNumIntArgRegs())1008{1009// Sign extend non-64bit Integers on LinuxPPC64 as required by the ABI1010// The AIX64 ABI also specifies this behaviour but we observed otherwise1011// We can do this blindly in Java since there is no unsigned types1012// WCode will have to do something better!1013if (isFastJNI &&1014(comp()->target().isLinux() && comp()->target().is64Bit()) &&1015childType != TR::Address)1016generateTrg1Src1Instruction(cg(), TR::InstOpCode::extsw, callNode, argRegister, argRegister);10171018if (checkSplit && !cg()->canClobberNodesRegister(child, 0))1019{1020if (argRegister->containsCollectedReference())1021tempRegister = cg()->allocateCollectedReferenceRegister();1022else1023tempRegister = cg()->allocateRegister();1024generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, argRegister);1025argRegister = tempRegister;1026}1027if (numIntegerArgs == 0 &&1028(resType.isAddress() || resType.isInt32() || resType.isInt64()))1029{1030TR::Register *resultReg;1031if (resType.isAddress())1032resultReg = cg()->allocateCollectedReferenceRegister();1033else1034resultReg = cg()->allocateRegister();1035dependencies->addPreCondition(argRegister, TR::RealRegister::gr3);1036dependencies->addPostCondition(resultReg, TR::RealRegister::gr3);1037}1038else if (comp()->target().is32Bit() && numIntegerArgs == 1 && resType.isInt64())1039{1040TR::Register *resultReg = cg()->allocateRegister();1041dependencies->addPreCondition(argRegister, TR::RealRegister::gr4);1042dependencies->addPostCondition(resultReg, TR::RealRegister::gr4);1043}1044else1045{1046TR::addDependency(dependencies, argRegister, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());1047}1048}1049else // numIntegerArgs >= properties.getNumIntArgRegs()1050{1051mref = getOutgoingArgumentMemRef(argSize, argRegister,TR::InstOpCode::Op_st, pushToMemory[argIndex++], TR::Compiler->om.sizeofReferenceAddress(), properties);1052//printf("integral or address memory arg, offset = %d\n", argSize);1053if (!aix_style_linkage)1054argSize += TR::Compiler->om.sizeofReferenceAddress();1055}1056numIntegerArgs++;1057if (aix_style_linkage)1058argSize += TR::Compiler->om.sizeofReferenceAddress();1059break;1060case TR::Int64:1061argRegister = pushLongArg(child);1062if (!aix_style_linkage)1063{1064if (numIntegerArgs & 1)1065{1066if (numIntegerArgs < properties.getNumIntArgRegs())1067TR::addDependency(dependencies, NULL, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());1068numIntegerArgs++;1069}1070}1071if (numIntegerArgs < properties.getNumIntArgRegs())1072{1073if (!cg()->canClobberNodesRegister(child, 0))1074{1075if (comp()->target().is64Bit())1076{1077tempRegister = cg()->allocateRegister();1078generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, argRegister);1079argRegister = tempRegister;1080}1081else1082{1083tempRegister = cg()->allocateRegister();1084generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, argRegister->getRegisterPair()->getHighOrder());1085argRegister = cg()->allocateRegisterPair(argRegister->getRegisterPair()->getLowOrder(), tempRegister);1086tempLongRegisters.add(argRegister);1087}1088}1089if (numIntegerArgs == 0 &&1090(resType.isAddress() || resType.isInt32() || resType.isInt64()))1091{1092TR::Register *resultReg;1093if (resType.isAddress())1094resultReg = cg()->allocateCollectedReferenceRegister();1095else1096resultReg = cg()->allocateRegister();1097if (comp()->target().is64Bit())1098dependencies->addPreCondition(argRegister, TR::RealRegister::gr3);1099else1100dependencies->addPreCondition(argRegister->getRegisterPair()->getHighOrder(), TR::RealRegister::gr3);1101dependencies->addPostCondition(resultReg, TR::RealRegister::gr3);1102}1103else if (comp()->target().is32Bit() && numIntegerArgs == 1 && resType.isInt64())1104{1105TR::Register *resultReg = cg()->allocateRegister();1106dependencies->addPreCondition(argRegister, TR::RealRegister::gr4);1107dependencies->addPostCondition(resultReg, TR::RealRegister::gr4);1108}1109else1110{1111if (comp()->target().is64Bit())1112TR::addDependency(dependencies, argRegister, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());1113else1114TR::addDependency(dependencies, argRegister->getRegisterPair()->getHighOrder(), properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());1115}1116if (comp()->target().is32Bit())1117{1118if (numIntegerArgs < properties.getNumIntArgRegs()-1)1119{1120if (!cg()->canClobberNodesRegister(child, 0))1121{1122TR::Register *over_lowReg = argRegister->getRegisterPair()->getLowOrder();1123tempRegister = cg()->allocateRegister();1124generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, over_lowReg);1125argRegister->getRegisterPair()->setLowOrder(tempRegister, cg());1126}1127if (numIntegerArgs == 0 && resType.isInt64())1128{1129TR::Register *resultReg = cg()->allocateRegister();1130dependencies->addPreCondition(argRegister->getRegisterPair()->getLowOrder(), TR::RealRegister::gr4);1131dependencies->addPostCondition(resultReg, TR::RealRegister::gr4);1132}1133else1134TR::addDependency(dependencies, argRegister->getRegisterPair()->getLowOrder(), properties.getIntegerArgumentRegister(numIntegerArgs+1), TR_GPR, cg());1135}1136else // numIntegerArgs == properties.getNumIntArgRegs()-11137{1138mref = getOutgoingArgumentMemRef(argSize+4, argRegister->getRegisterPair()->getLowOrder(), TR::InstOpCode::stw, pushToMemory[argIndex++], 4, properties);1139}1140numIntegerArgs ++;1141}1142}1143else // numIntegerArgs >= properties.getNumIntArgRegs()1144{1145if (comp()->target().is64Bit())1146{1147mref = getOutgoingArgumentMemRef(argSize, argRegister, TR::InstOpCode::std, pushToMemory[argIndex++], TR::Compiler->om.sizeofReferenceAddress(), properties);1148}1149else1150{1151if (!aix_style_linkage)1152argSize = (argSize + 4) & (~7);1153mref = getOutgoingArgumentMemRef(argSize, argRegister->getRegisterPair()->getHighOrder(), TR::InstOpCode::stw, pushToMemory[argIndex++], 4, properties);1154mref = getOutgoingArgumentMemRef(argSize+4, argRegister->getRegisterPair()->getLowOrder(), TR::InstOpCode::stw, pushToMemory[argIndex++], 4, properties);1155numIntegerArgs ++;1156if (!aix_style_linkage)1157argSize += 8;1158}1159}1160numIntegerArgs ++;1161if (aix_style_linkage)1162argSize += 8;1163break;11641165case TR::Float:1166argRegister = pushFloatArg(child);1167for (int r = 0; r < ((childType == TR::Float) ? 1: 2); r++)1168{1169TR::Register * argReg;1170if (childType == TR::Float)1171argReg = argRegister;1172else1173argReg = (r == 0) ? argRegister->getHighOrder() : argRegister->getLowOrder();11741175if (numFloatArgs < properties.getNumFloatArgRegs())1176{1177if (!cg()->canClobberNodesRegister(child, 0))1178{1179tempRegister = cg()->allocateRegister(TR_FPR);1180generateTrg1Src1Instruction(cg(), TR::InstOpCode::fmr, callNode, tempRegister, argReg);1181argReg = tempRegister;1182}1183if (numFloatArgs == 0 && resType.isFloatingPoint())1184{1185TR::Register *resultReg;1186if (resType.getDataType() == TR::Float)1187resultReg = cg()->allocateSinglePrecisionRegister();1188else1189resultReg = cg()->allocateRegister(TR_FPR);11901191dependencies->addPreCondition(argReg, (r == 0) ? TR::RealRegister::fp1 : TR::RealRegister::fp2);1192dependencies->addPostCondition(resultReg, (r == 0) ? TR::RealRegister::fp1 : TR::RealRegister::fp2);1193}1194else1195TR::addDependency(dependencies, argReg, properties.getFloatArgumentRegister(numFloatArgs), TR_FPR, cg());1196}1197else if (!aix_style_linkage)1198// numFloatArgs >= properties.getNumFloatArgRegs()1199{1200mref = getOutgoingArgumentMemRef(argSize, argReg, TR::InstOpCode::stfs, pushToMemory[argIndex++], 4, properties);1201argSize += 4;1202}12031204if (aix_style_linkage)1205{1206if (numIntegerArgs < properties.getNumIntArgRegs())1207{1208if (numIntegerArgs==0 && resType.isAddress())1209{1210TR::Register *aReg = cg()->allocateRegister();1211TR::Register *bReg = cg()->allocateCollectedReferenceRegister();1212dependencies->addPreCondition(aReg, TR::RealRegister::gr3);1213dependencies->addPostCondition(bReg, TR::RealRegister::gr3);1214}1215else1216TR::addDependency(dependencies, NULL, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());1217}1218else // numIntegerArgs >= properties.getNumIntArgRegs()1219{1220if (comp()->target().is64Bit() && comp()->target().isLinux())1221{1222mref = getOutgoingArgumentMemRef(argSize+4, argReg, TR::InstOpCode::stfs, pushToMemory[argIndex++], 4, properties);1223}1224else1225{1226mref = getOutgoingArgumentMemRef(argSize, argReg, TR::InstOpCode::stfs, pushToMemory[argIndex++], 4, properties);1227}1228}12291230numIntegerArgs++;1231}1232numFloatArgs++;1233if (aix_style_linkage)1234argSize += TR::Compiler->om.sizeofReferenceAddress();12351236} // for loop1237break;12381239case TR::Double:1240argRegister = pushDoubleArg(child);1241for (int r = 0; r < ((childType == TR::Double) ? 1: 2); r++)1242{1243TR::Register * argReg;1244if (childType == TR::Double)1245argReg = argRegister;1246else1247argReg = (r == 0) ? argRegister->getHighOrder() : argRegister->getLowOrder();12481249if (numFloatArgs < properties.getNumFloatArgRegs())1250{1251if (!cg()->canClobberNodesRegister(child, 0))1252{1253tempRegister = cg()->allocateRegister(TR_FPR);1254generateTrg1Src1Instruction(cg(), TR::InstOpCode::fmr, callNode, tempRegister, argReg);1255argReg = tempRegister;1256}1257if (numFloatArgs == 0 && resType.isFloatingPoint())1258{1259TR::Register *resultReg;1260if (resType.getDataType() == TR::Float)1261resultReg = cg()->allocateSinglePrecisionRegister();1262else1263resultReg = cg()->allocateRegister(TR_FPR);1264dependencies->addPreCondition(argReg, (r==0) ? TR::RealRegister::fp1 : TR::RealRegister::fp2);1265dependencies->addPostCondition(resultReg, (r==0) ? TR::RealRegister::fp1 : TR::RealRegister::fp2);1266}1267else1268TR::addDependency(dependencies, argReg, properties.getFloatArgumentRegister(numFloatArgs), TR_FPR, cg());1269}1270else if (!aix_style_linkage)1271// numFloatArgs >= properties.getNumFloatArgRegs()1272{1273argSize = (argSize + 4) & (~7);1274mref = getOutgoingArgumentMemRef(argSize, argReg, TR::InstOpCode::stfd, pushToMemory[argIndex++], 8, properties);1275argSize += 8;1276}12771278if (aix_style_linkage)1279{1280if (numIntegerArgs < properties.getNumIntArgRegs())1281{1282TR::MemoryReference *tempMR;12831284if (numIntegerArgs==0 && resType.isAddress())1285{1286TR::Register *aReg = cg()->allocateRegister();1287TR::Register *bReg = cg()->allocateCollectedReferenceRegister();1288dependencies->addPreCondition(aReg, TR::RealRegister::gr3);1289dependencies->addPostCondition(bReg, TR::RealRegister::gr3);1290}1291else1292TR::addDependency(dependencies, NULL, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());12931294if (comp()->target().is32Bit())1295{1296if ((numIntegerArgs+1) < properties.getNumIntArgRegs())1297TR::addDependency(dependencies, NULL, properties.getIntegerArgumentRegister(numIntegerArgs+1), TR_GPR, cg());1298else1299{1300mref = getOutgoingArgumentMemRef(argSize, argReg, TR::InstOpCode::stfd, pushToMemory[argIndex++], 8, properties);1301}1302}1303}1304else // numIntegerArgs >= properties.getNumIntArgRegs()1305{1306mref = getOutgoingArgumentMemRef(argSize, argReg, TR::InstOpCode::stfd, pushToMemory[argIndex++], 8, properties);1307}13081309numIntegerArgs += comp()->target().is64Bit()?1:2;1310}1311numFloatArgs++;1312if (aix_style_linkage)1313argSize += 8;13141315} // end of for loop1316break;1317case TR::VectorDouble:1318TR_ASSERT(false, "JNI dispatch: VectorDouble argument not expected");1319break;1320}1321}13221323while (numIntegerArgs < properties.getNumIntArgRegs())1324{1325if (numIntegerArgs == 0 && resType.isAddress())1326{1327dependencies->addPreCondition(cg()->allocateRegister(), properties.getIntegerArgumentRegister(0));1328dependencies->addPostCondition(cg()->allocateCollectedReferenceRegister(), properties.getIntegerArgumentRegister(0));1329}1330else1331{1332TR::addDependency(dependencies, NULL, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());1333}1334numIntegerArgs++;1335}13361337TR_LiveRegisters *liveRegs;1338bool liveVSXScalar, liveVSXVector, liveVMX;13391340liveRegs = cg()->getLiveRegisters(TR_VSX_SCALAR);1341liveVSXScalar = (!liveRegs || liveRegs->getNumberOfLiveRegisters() > 0);1342liveRegs = cg()->getLiveRegisters(TR_VSX_VECTOR);1343liveVSXVector = (!liveRegs || liveRegs->getNumberOfLiveRegisters() > 0);1344liveRegs = cg()->getLiveRegisters(TR_VRF);1345liveVMX = (!liveRegs || liveRegs->getNumberOfLiveRegisters() > 0);13461347TR::addDependency(dependencies, NULL, TR::RealRegister::fp0, TR_FPR, cg());1348TR::addDependency(dependencies, NULL, TR::RealRegister::gr0, TR_GPR, cg());1349TR::addDependency(dependencies, NULL, TR::RealRegister::gr11, TR_GPR, cg());1350TR::addDependency(dependencies, NULL, TR::RealRegister::gr12, TR_GPR, cg());1351TR::addDependency(dependencies, NULL, TR::RealRegister::cr0, TR_CCR, cg());1352TR::addDependency(dependencies, NULL, TR::RealRegister::cr1, TR_CCR, cg());1353TR::addDependency(dependencies, NULL, TR::RealRegister::cr5, TR_CCR, cg());1354TR::addDependency(dependencies, NULL, TR::RealRegister::cr6, TR_CCR, cg());1355TR::addDependency(dependencies, NULL, TR::RealRegister::cr7, TR_CCR, cg());1356if (!isFastJNI && aix_style_linkage)1357TR::addDependency(dependencies, NULL, TR::RealRegister::gr2, TR_GPR, cg());13581359int32_t floatRegsUsed = (numFloatArgs>properties.getNumFloatArgRegs())?properties.getNumFloatArgRegs():numFloatArgs;13601361if (liveVMX || liveVSXScalar || liveVSXVector)1362{1363for (i=(TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::LastFPR+1); i<=TR::RealRegister::LastVSR; i++)1364{1365// isFastJNI implying: no call back into Java, such that preserved is preserved1366if (!properties.getPreserved((TR::RealRegister::RegNum)i) || !isFastJNI)1367{1368TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)i, TR_VSX_SCALAR, cg());1369}13701371}1372}13731374for (i=(TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0+floatRegsUsed+1); i<=TR::RealRegister::LastFPR; i++)1375{1376// isFastJNI implying: no call back into Java, such that preserved is preserved1377// TODO: liveVSXVector is an overkill for assembler mode, really only vectors required1378if (!properties.getPreserved((TR::RealRegister::RegNum)i) || liveVSXVector ||1379(!isFastJNI))1380{1381TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)i, TR_FPR, cg());1382}1383}13841385if (memArgs > 0)1386{1387for (argIndex=0; argIndex<memArgs; argIndex++)1388{1389TR::Register *aReg = pushToMemory[argIndex].argRegister;1390generateMemSrc1Instruction(cg(), pushToMemory[argIndex].opCode, callNode, pushToMemory[argIndex].argMemory, aReg);1391cg()->stopUsingRegister(aReg);1392}1393}13941395return argSize;1396}13971398TR::Register *J9::Power::JNILinkage::pushJNIReferenceArg(TR::Node *child)1399{1400TR::Register *pushRegister;1401bool checkSplit = true;14021403if (child->getOpCodeValue() == TR::loadaddr)1404{1405TR::SymbolReference * symRef = child->getSymbolReference();1406TR::StaticSymbol *sym = symRef->getSymbol()->getStaticSymbol();1407if (sym)1408{1409if (sym->isAddressOfClassObject())1410{1411pushRegister = pushAddressArg(child);1412}1413else1414{1415TR::Register *condReg = cg()->allocateRegister(TR_CCR);1416TR::Register *addrReg = cg()->evaluate(child);1417TR::MemoryReference *tmpMemRef = TR::MemoryReference::createWithDisplacement(cg(), addrReg, (int32_t)0, TR::Compiler->om.sizeofReferenceAddress());1418TR::Register *whatReg = cg()->allocateCollectedReferenceRegister();1419TR::LabelSymbol *nonNullLabel = generateLabelSymbol(cg());14201421checkSplit = false;1422generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, child, whatReg, tmpMemRef);1423if (!cg()->canClobberNodesRegister(child))1424{1425// Since this is a static variable, it is non-collectable.1426TR::Register *tempRegister = cg()->allocateRegister();1427generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, child, tempRegister, addrReg);1428pushRegister = tempRegister;1429}1430else1431pushRegister = addrReg;1432generateTrg1Src1ImmInstruction(cg(),TR::InstOpCode::Op_cmpi, child, condReg, whatReg, 0);1433generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, child, nonNullLabel, condReg);1434generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, child, pushRegister, 0);14351436TR::RegisterDependencyConditions *conditions = new (trHeapMemory()) TR::RegisterDependencyConditions(3, 3, trMemory());1437TR::addDependency(conditions, pushRegister, TR::RealRegister::NoReg, TR_GPR, cg());1438TR::addDependency(conditions, whatReg, TR::RealRegister::NoReg, TR_GPR, cg());1439TR::addDependency(conditions, condReg, TR::RealRegister::NoReg, TR_CCR, cg());14401441generateDepLabelInstruction(cg(), TR::InstOpCode::label, child, nonNullLabel, conditions);1442conditions->stopUsingDepRegs(cg(), pushRegister);1443cg()->decReferenceCount(child);1444}1445}1446else // must be loadaddr of parm or local1447{1448if (child->pointsToNonNull())1449{1450pushRegister = pushAddressArg(child);1451}1452else if (child->pointsToNull())1453{1454checkSplit = false;1455pushRegister = cg()->allocateRegister();1456loadConstant(cg(), child, 0, pushRegister);1457cg()->decReferenceCount(child);1458}1459else1460{1461TR::Register *addrReg = cg()->evaluate(child);1462TR::Register *condReg = cg()->allocateRegister(TR_CCR);1463TR::Register *whatReg = cg()->allocateCollectedReferenceRegister();1464TR::LabelSymbol *nonNullLabel = generateLabelSymbol(cg());14651466checkSplit = false;1467generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, child, whatReg, TR::MemoryReference::createWithDisplacement(cg(), addrReg, (int32_t)0, TR::Compiler->om.sizeofReferenceAddress()));1468if (!cg()->canClobberNodesRegister(child))1469{1470// Since this points at a parm or local location, it is non-collectable.1471TR::Register *tempReg = cg()->allocateRegister();1472generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, child, tempReg, addrReg);1473pushRegister = tempReg;1474}1475else1476pushRegister = addrReg;1477generateTrg1Src1ImmInstruction(cg(),TR::InstOpCode::Op_cmpi, child, condReg, whatReg, 0);1478generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, child, nonNullLabel, condReg);1479generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, child, pushRegister, 0);14801481TR::RegisterDependencyConditions *conditions = new (trHeapMemory()) TR::RegisterDependencyConditions(3, 3, trMemory());1482TR::addDependency(conditions, pushRegister, TR::RealRegister::NoReg, TR_GPR, cg());1483TR::addDependency(conditions, whatReg, TR::RealRegister::NoReg, TR_GPR, cg());1484TR::addDependency(conditions, condReg, TR::RealRegister::NoReg, TR_CCR, cg());14851486generateDepLabelInstruction(cg(), TR::InstOpCode::label, child, nonNullLabel, conditions);1487conditions->stopUsingDepRegs(cg(), pushRegister);1488cg()->decReferenceCount(child);1489}1490}1491}1492else1493{1494pushRegister = pushAddressArg(child);1495}14961497if (checkSplit && !cg()->canClobberNodesRegister(child, 0))1498{1499TR::Register *tempReg = pushRegister->containsCollectedReference()?1500cg()->allocateCollectedReferenceRegister():cg()->allocateRegister();1501generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, child, tempReg, pushRegister);1502pushRegister = tempReg;1503}1504return pushRegister;1505}150615071508