Path: blob/master/runtime/compiler/p/codegen/PPCPrivateLinkage.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2000, 2022 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "codegen/PPCPrivateLinkage.hpp"2324#include "codegen/CodeGenerator.hpp"25#include "codegen/CodeGeneratorUtils.hpp"26#include "codegen/Linkage_inlines.hpp"27#include "codegen/LiveRegister.hpp"28#include "codegen/Machine.hpp"29#include "codegen/RealRegister.hpp"30#include "codegen/Register.hpp"31#include "codegen/RegisterDependency.hpp"32#include "codegen/Snippet.hpp"33#include "codegen/TreeEvaluator.hpp"34#include "compile/ResolvedMethod.hpp"35#include "compile/VirtualGuard.hpp"36#include "env/CHTable.hpp"37#include "env/CompilerEnv.hpp"38#include "env/J2IThunk.hpp"39#include "env/PersistentCHTable.hpp"40#include "env/VMJ9.h"41#include "env/jittypes.h"42#include "il/LabelSymbol.hpp"43#include "il/Node.hpp"44#include "il/Node_inlines.hpp"45#include "il/ParameterSymbol.hpp"46#include "il/TreeTop.hpp"47#include "il/TreeTop_inlines.hpp"48#include "p/codegen/CallSnippet.hpp"49#include "p/codegen/GenerateInstructions.hpp"50#include "p/codegen/PPCEvaluator.hpp"51#include "p/codegen/PPCHelperCallSnippet.hpp"52#include "p/codegen/PPCInstruction.hpp"53#include "p/codegen/PPCTableOfConstants.hpp"54#include "p/codegen/StackCheckFailureSnippet.hpp"55#include "runtime/J9Profiler.hpp"56#include "runtime/J9ValueProfiler.hpp"5758#define MIN_PROFILED_CALL_FREQUENCY (.075f)59#define MAX_PROFILED_CALL_FREQUENCY (.90f)6061J9::Power::PrivateLinkage::PrivateLinkage(TR::CodeGenerator *cg)62: J9::PrivateLinkage(cg)63{64TR::Compilation *comp = cg->comp();65int i = 0;66bool is32bitLinux = false;6768_properties._properties = 0;69_properties._registerFlags[TR::RealRegister::NoReg] = 0;70_properties._registerFlags[TR::RealRegister::gr0] = 0;71_properties._registerFlags[TR::RealRegister::gr1] = Preserved|PPC_Reserved; // system sp7273// gr2 is Preserved in 32-bit Linux74if (comp->target().is64Bit())75{76_properties._registerFlags[TR::RealRegister::gr2] = 0;77}78else79{80if (comp->target().isAIX())81{82_properties._registerFlags[TR::RealRegister::gr2] = 0;83}84else if (comp->target().isLinux())85{86_properties._registerFlags[TR::RealRegister::gr2] = Preserved|PPC_Reserved;87is32bitLinux = true;88}89else90{91TR_ASSERT(0, "unsupported target");92}93}9495_properties._registerFlags[TR::RealRegister::gr3] = IntegerReturn|IntegerArgument;9697if (comp->target().is64Bit())98_properties._registerFlags[TR::RealRegister::gr4] = IntegerArgument;99else100_properties._registerFlags[TR::RealRegister::gr4] = IntegerReturn|IntegerArgument;101102_properties._registerFlags[TR::RealRegister::gr5] = IntegerArgument;103_properties._registerFlags[TR::RealRegister::gr6] = IntegerArgument;104_properties._registerFlags[TR::RealRegister::gr7] = IntegerArgument;105_properties._registerFlags[TR::RealRegister::gr8] = IntegerArgument;106_properties._registerFlags[TR::RealRegister::gr9] = IntegerArgument;107_properties._registerFlags[TR::RealRegister::gr10] = IntegerArgument;108_properties._registerFlags[TR::RealRegister::gr11] = 0;109_properties._registerFlags[TR::RealRegister::gr12] = 0;110_properties._registerFlags[TR::RealRegister::gr13] = Preserved|PPC_Reserved; // meta data for 32bit, system for 64bit;111_properties._registerFlags[TR::RealRegister::gr14] = Preserved|PPC_Reserved; // J9 sp112if (comp->target().is64Bit())113{114_properties._registerFlags[TR::RealRegister::gr15] = Preserved|PPC_Reserved; // meta data115if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))116_properties._registerFlags[TR::RealRegister::gr16] = Preserved; // typical preserved reg117else118_properties._registerFlags[TR::RealRegister::gr16] = Preserved|PPC_Reserved; // JTOC119}120else121{122_properties._registerFlags[TR::RealRegister::gr15] = Preserved;123_properties._registerFlags[TR::RealRegister::gr16] = Preserved;124}125126for (i = TR::RealRegister::gr17; i <= TR::RealRegister::LastGPR; i++)127_properties._registerFlags[i] = Preserved; // gr17 - gr31 preserved128129_properties._registerFlags[TR::RealRegister::fp0] = FloatReturn|FloatArgument;130_properties._registerFlags[TR::RealRegister::fp1] = FloatArgument;131_properties._registerFlags[TR::RealRegister::fp2] = FloatArgument;132_properties._registerFlags[TR::RealRegister::fp3] = FloatArgument;133_properties._registerFlags[TR::RealRegister::fp4] = FloatArgument;134_properties._registerFlags[TR::RealRegister::fp5] = FloatArgument;135_properties._registerFlags[TR::RealRegister::fp6] = FloatArgument;136_properties._registerFlags[TR::RealRegister::fp7] = FloatArgument;137138for (i = TR::RealRegister::fp8; i <= TR::RealRegister::LastFPR; i++)139_properties._registerFlags[i] = 0; // fp8 - fp31 volatile140141for (i = TR::RealRegister::vsr32; i <= TR::RealRegister::LastVSR; i++)142_properties._registerFlags[i] = 0; // vsr32 - vsr63 volatile143144for (i = TR::RealRegister::FirstCCR; i <= TR::RealRegister::LastCCR; i++)145_properties._registerFlags[i] = 0; // cr0 - cr7 volatile146147_properties._numIntegerArgumentRegisters = 8;148_properties._firstIntegerArgumentRegister = 0;149_properties._numFloatArgumentRegisters = 8;150_properties._firstFloatArgumentRegister = 8;151152_properties._argumentRegisters[0] = TR::RealRegister::gr3;153_properties._argumentRegisters[1] = TR::RealRegister::gr4;154_properties._argumentRegisters[2] = TR::RealRegister::gr5;155_properties._argumentRegisters[3] = TR::RealRegister::gr6;156_properties._argumentRegisters[4] = TR::RealRegister::gr7;157_properties._argumentRegisters[5] = TR::RealRegister::gr8;158_properties._argumentRegisters[6] = TR::RealRegister::gr9;159_properties._argumentRegisters[7] = TR::RealRegister::gr10;160_properties._argumentRegisters[8] = TR::RealRegister::fp0;161_properties._argumentRegisters[9] = TR::RealRegister::fp1;162_properties._argumentRegisters[10] = TR::RealRegister::fp2;163_properties._argumentRegisters[11] = TR::RealRegister::fp3;164_properties._argumentRegisters[12] = TR::RealRegister::fp4;165_properties._argumentRegisters[13] = TR::RealRegister::fp5;166_properties._argumentRegisters[14] = TR::RealRegister::fp6;167_properties._argumentRegisters[15] = TR::RealRegister::fp7;168169_properties._firstIntegerReturnRegister = 0;170_properties._returnRegisters[0] = TR::RealRegister::gr3;171172if (comp->target().is64Bit())173{174_properties._firstFloatReturnRegister = 1;175_properties._returnRegisters[1] = TR::RealRegister::fp0;176177if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))178{179_properties._numAllocatableIntegerRegisters = 28; // 64 post-P10180_properties._firstAllocatableFloatArgumentRegister = 41; // 64 post-P10181_properties._lastAllocatableFloatVolatileRegister = 59; // 64 post-P10182}183else184{185_properties._numAllocatableIntegerRegisters = 27; // 64 pre-P10186_properties._firstAllocatableFloatArgumentRegister = 40; // 64 pre-P10187_properties._lastAllocatableFloatVolatileRegister = 58; // 64 pre-P10188}189}190else191{192_properties._firstFloatReturnRegister = 2;193_properties._returnRegisters[1] = TR::RealRegister::gr4;194_properties._returnRegisters[2] = TR::RealRegister::fp0;195196if (is32bitLinux)197{198_properties._numAllocatableIntegerRegisters = 28; // 32 linux199_properties._firstAllocatableFloatArgumentRegister = 41; // 32 linux200_properties._lastAllocatableFloatVolatileRegister = 59; // 32 linux201}202else203{204_properties._numAllocatableIntegerRegisters = 29; // 32 non-linux205_properties._firstAllocatableFloatArgumentRegister = 42; // 32 non-linux206_properties._lastAllocatableFloatVolatileRegister = 60; // 32 non-linux207}208}209210if (is32bitLinux)211{212_properties._firstAllocatableIntegerArgumentRegister = 8;213_properties._lastAllocatableIntegerVolatileRegister = 10;214}215else216{217_properties._firstAllocatableIntegerArgumentRegister = 9;218_properties._lastAllocatableIntegerVolatileRegister = 11;219}220_properties._numAllocatableFloatRegisters = 32;221_properties._numAllocatableVectorRegisters = 32;222_properties._numAllocatableCCRegisters = 8;223224i = 0;225if (!is32bitLinux)226_properties._allocationOrder[i++] = TR::RealRegister::gr2;227_properties._allocationOrder[i++] = TR::RealRegister::gr12;228_properties._allocationOrder[i++] = TR::RealRegister::gr10;229_properties._allocationOrder[i++] = TR::RealRegister::gr9;230_properties._allocationOrder[i++] = TR::RealRegister::gr8;231_properties._allocationOrder[i++] = TR::RealRegister::gr7;232_properties._allocationOrder[i++] = TR::RealRegister::gr6;233_properties._allocationOrder[i++] = TR::RealRegister::gr5;234_properties._allocationOrder[i++] = TR::RealRegister::gr4;235_properties._allocationOrder[i++] = TR::RealRegister::gr3;236_properties._allocationOrder[i++] = TR::RealRegister::gr11;237_properties._allocationOrder[i++] = TR::RealRegister::gr0;238_properties._allocationOrder[i++] = TR::RealRegister::gr31;239_properties._allocationOrder[i++] = TR::RealRegister::gr30;240_properties._allocationOrder[i++] = TR::RealRegister::gr29;241_properties._allocationOrder[i++] = TR::RealRegister::gr28;242_properties._allocationOrder[i++] = TR::RealRegister::gr27;243_properties._allocationOrder[i++] = TR::RealRegister::gr26;244_properties._allocationOrder[i++] = TR::RealRegister::gr25;245_properties._allocationOrder[i++] = TR::RealRegister::gr24;246_properties._allocationOrder[i++] = TR::RealRegister::gr23;247_properties._allocationOrder[i++] = TR::RealRegister::gr22;248_properties._allocationOrder[i++] = TR::RealRegister::gr21;249_properties._allocationOrder[i++] = TR::RealRegister::gr20;250_properties._allocationOrder[i++] = TR::RealRegister::gr19;251_properties._allocationOrder[i++] = TR::RealRegister::gr18;252_properties._allocationOrder[i++] = TR::RealRegister::gr17;253254if (comp->target().is64Bit())255{256if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))257_properties._allocationOrder[i++] = TR::RealRegister::gr16;258}259else260{261_properties._allocationOrder[i++] = TR::RealRegister::gr16;262_properties._allocationOrder[i++] = TR::RealRegister::gr15;263}264265_properties._allocationOrder[i++] = TR::RealRegister::fp13;266_properties._allocationOrder[i++] = TR::RealRegister::fp12;267_properties._allocationOrder[i++] = TR::RealRegister::fp11;268_properties._allocationOrder[i++] = TR::RealRegister::fp10;269_properties._allocationOrder[i++] = TR::RealRegister::fp9;270_properties._allocationOrder[i++] = TR::RealRegister::fp8;271_properties._allocationOrder[i++] = TR::RealRegister::fp7;272_properties._allocationOrder[i++] = TR::RealRegister::fp6;273_properties._allocationOrder[i++] = TR::RealRegister::fp5;274_properties._allocationOrder[i++] = TR::RealRegister::fp4;275_properties._allocationOrder[i++] = TR::RealRegister::fp3;276_properties._allocationOrder[i++] = TR::RealRegister::fp2;277_properties._allocationOrder[i++] = TR::RealRegister::fp1;278_properties._allocationOrder[i++] = TR::RealRegister::fp0;279_properties._allocationOrder[i++] = TR::RealRegister::fp31;280_properties._allocationOrder[i++] = TR::RealRegister::fp30;281_properties._allocationOrder[i++] = TR::RealRegister::fp29;282_properties._allocationOrder[i++] = TR::RealRegister::fp28;283_properties._allocationOrder[i++] = TR::RealRegister::fp27;284_properties._allocationOrder[i++] = TR::RealRegister::fp26;285_properties._allocationOrder[i++] = TR::RealRegister::fp25;286_properties._allocationOrder[i++] = TR::RealRegister::fp24;287_properties._allocationOrder[i++] = TR::RealRegister::fp23;288_properties._allocationOrder[i++] = TR::RealRegister::fp22;289_properties._allocationOrder[i++] = TR::RealRegister::fp21;290_properties._allocationOrder[i++] = TR::RealRegister::fp20;291_properties._allocationOrder[i++] = TR::RealRegister::fp19;292_properties._allocationOrder[i++] = TR::RealRegister::fp18;293_properties._allocationOrder[i++] = TR::RealRegister::fp17;294_properties._allocationOrder[i++] = TR::RealRegister::fp16;295_properties._allocationOrder[i++] = TR::RealRegister::fp15;296_properties._allocationOrder[i++] = TR::RealRegister::fp14;297298_properties._allocationOrder[i++] = TR::RealRegister::vsr32;299_properties._allocationOrder[i++] = TR::RealRegister::vsr33;300_properties._allocationOrder[i++] = TR::RealRegister::vsr34;301_properties._allocationOrder[i++] = TR::RealRegister::vsr35;302_properties._allocationOrder[i++] = TR::RealRegister::vsr36;303_properties._allocationOrder[i++] = TR::RealRegister::vsr37;304_properties._allocationOrder[i++] = TR::RealRegister::vsr38;305_properties._allocationOrder[i++] = TR::RealRegister::vsr39;306_properties._allocationOrder[i++] = TR::RealRegister::vsr40;307_properties._allocationOrder[i++] = TR::RealRegister::vsr41;308_properties._allocationOrder[i++] = TR::RealRegister::vsr42;309_properties._allocationOrder[i++] = TR::RealRegister::vsr43;310_properties._allocationOrder[i++] = TR::RealRegister::vsr44;311_properties._allocationOrder[i++] = TR::RealRegister::vsr45;312_properties._allocationOrder[i++] = TR::RealRegister::vsr46;313_properties._allocationOrder[i++] = TR::RealRegister::vsr47;314_properties._allocationOrder[i++] = TR::RealRegister::vsr48;315_properties._allocationOrder[i++] = TR::RealRegister::vsr49;316_properties._allocationOrder[i++] = TR::RealRegister::vsr50;317_properties._allocationOrder[i++] = TR::RealRegister::vsr51;318_properties._allocationOrder[i++] = TR::RealRegister::vsr52;319_properties._allocationOrder[i++] = TR::RealRegister::vsr53;320_properties._allocationOrder[i++] = TR::RealRegister::vsr54;321_properties._allocationOrder[i++] = TR::RealRegister::vsr55;322_properties._allocationOrder[i++] = TR::RealRegister::vsr56;323_properties._allocationOrder[i++] = TR::RealRegister::vsr57;324_properties._allocationOrder[i++] = TR::RealRegister::vsr58;325_properties._allocationOrder[i++] = TR::RealRegister::vsr59;326_properties._allocationOrder[i++] = TR::RealRegister::vsr60;327_properties._allocationOrder[i++] = TR::RealRegister::vsr61;328_properties._allocationOrder[i++] = TR::RealRegister::vsr62;329_properties._allocationOrder[i++] = TR::RealRegister::vsr63;330331_properties._allocationOrder[i++] = TR::RealRegister::cr7;332_properties._allocationOrder[i++] = TR::RealRegister::cr6;333_properties._allocationOrder[i++] = TR::RealRegister::cr5;334_properties._allocationOrder[i++] = TR::RealRegister::cr1;335_properties._allocationOrder[i++] = TR::RealRegister::cr0;336_properties._allocationOrder[i++] = TR::RealRegister::cr2;337_properties._allocationOrder[i++] = TR::RealRegister::cr3;338_properties._allocationOrder[i++] = TR::RealRegister::cr4;339340if (comp->target().is64Bit())341{342if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))343_properties._preservedRegisterMapForGC = 0x0000ffff;344else345_properties._preservedRegisterMapForGC = 0x00007fff;346_properties._methodMetaDataRegister = TR::RealRegister::gr15;347_properties._normalStackPointerRegister = TR::RealRegister::gr14;348_properties._alternateStackPointerRegister = TR::RealRegister::NoReg;349_properties._TOCBaseRegister = TR::RealRegister::gr16;350// Volatile GPR (0,2-12) + FPR (0-31) + CCR (0-7) + VR (0-31)351_properties._numberOfDependencyGPRegisters = 12 + 32 + 8 + 32;352setOffsetToFirstParm(0);353_properties._offsetToFirstLocal = -8;354}355else356{357_properties._preservedRegisterMapForGC = 0x0001ffff;358_properties._methodMetaDataRegister = TR::RealRegister::gr13;359_properties._normalStackPointerRegister = TR::RealRegister::gr14;360_properties._alternateStackPointerRegister = TR::RealRegister::NoReg;361_properties._TOCBaseRegister = TR::RealRegister::NoReg;362if (is32bitLinux)363// Volatile GPR (0,3-12) + FPR (0-31) + CCR (0-7) + VR (0-31)364_properties._numberOfDependencyGPRegisters = 11 + 32 + 8 + 32;365else366// Volatile GPR (0,2-12) + FPR (0-31) + CCR (0-7) + VR (0-31)367_properties._numberOfDependencyGPRegisters = 12 + 32 + 8 + 32;368setOffsetToFirstParm(0);369_properties._offsetToFirstLocal = -4;370}371_properties._computedCallTargetRegister = TR::RealRegister::gr0; // gr11 = interface, gr12 = virtual, so we need something else for computed372_properties._vtableIndexArgumentRegister = TR::RealRegister::gr12;373_properties._j9methodArgumentRegister = TR::RealRegister::gr3; // TODO:JSR292: Confirm374}375376const TR::PPCLinkageProperties& J9::Power::PrivateLinkage::getProperties()377{378return _properties;379}380381void J9::Power::PrivateLinkage::initPPCRealRegisterLinkage()382{383TR::Machine *machine = cg()->machine();384const TR::PPCLinkageProperties &linkage = getProperties();385int icount, ret_count=0, lockedGPRs = 0;386387for (icount=TR::RealRegister::FirstGPR; icount<=TR::RealRegister::gr12;388icount++)389{390if (linkage.getReserved((TR::RealRegister::RegNum)icount))391{392machine->getRealRegister((TR::RealRegister::RegNum)icount)->setState(TR::RealRegister::Locked);393++lockedGPRs;394machine->getRealRegister((TR::RealRegister::RegNum)icount)->setAssignedRegister(machine->getRealRegister((TR::RealRegister::RegNum)icount));395}396else397{398int weight;399if (linkage.getIntegerReturn((TR::RealRegister::RegNum)icount))400{401weight = ++ret_count;402}403else404{405if (icount < TR::RealRegister::gr3)406{407weight = 2 + icount;408}409else410{411weight = icount;412}413}414machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(weight);415}416}417418for (icount=TR::RealRegister::LastGPR;419icount>=TR::RealRegister::gr13; icount--)420{421if (linkage.getReserved((TR::RealRegister::RegNum)icount))422{423machine->getRealRegister((TR::RealRegister::RegNum)icount)->setState(TR::RealRegister::Locked);424++lockedGPRs;425machine->getRealRegister((TR::RealRegister::RegNum)icount)->setAssignedRegister(machine->getRealRegister((TR::RealRegister::RegNum)icount));426}427machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);428}429430int lowestFPRWeight = TR::RealRegister::FirstFPR;431432for (icount=TR::RealRegister::FirstFPR;433icount<=TR::RealRegister::LastFPR; icount++)434{435if (linkage.getPreserved((TR::RealRegister::RegNum)icount))436{437machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);438}439else440{441machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(lowestFPRWeight);442}443}444445for (icount=TR::RealRegister::FirstVRF;446icount<=TR::RealRegister::LastVRF; icount++)447{448if (linkage.getPreserved((TR::RealRegister::RegNum)icount))449{450machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);451}452else453{454machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(icount);455}456}457458for (icount=TR::RealRegister::FirstCCR;459icount<=TR::RealRegister::LastCCR; icount++)460{461if (linkage.getPreserved((TR::RealRegister::RegNum)icount))462{463machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);464}465else466{467machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(icount);468}469}470471machine->setNumberOfLockedRegisters(TR_GPR, lockedGPRs);472machine->setNumberOfLockedRegisters(TR_FPR, 0);473machine->setNumberOfLockedRegisters(TR_VRF, 0);474}475476uint32_t J9::Power::PrivateLinkage::getRightToLeft()477{478return getProperties().getRightToLeft();479}480481void J9::Power::PrivateLinkage::mapStack(TR::ResolvedMethodSymbol *method)482{483ListIterator<TR::AutomaticSymbol> automaticIterator(&method->getAutomaticList());484TR::AutomaticSymbol *localCursor = automaticIterator.getFirst();485const TR::PPCLinkageProperties& linkage = getProperties();486TR::RealRegister::RegNum regIndex;487int32_t firstLocalOffset = linkage.getOffsetToFirstLocal();488uint32_t stackIndex = firstLocalOffset;489int32_t lowGCOffset = stackIndex;490TR::GCStackAtlas *atlas = cg()->getStackAtlas();491int32_t firstLocalGCIndex = atlas->getNumberOfParmSlotsMapped();492493// map all garbage collected references together so can concisely represent494// stack maps. They must be mapped so that the GC map index in each local495// symbol is honoured.496497uint32_t numberOfLocalSlotsMapped = atlas->getNumberOfSlotsMapped() - atlas->getNumberOfParmSlotsMapped();498499stackIndex -= numberOfLocalSlotsMapped * TR::Compiler->om.sizeofReferenceAddress();500501if (comp()->useCompressedPointers())502{503// If we have any local objects we have to make sure they're aligned properly when compressed pointers are used,504// otherwise pointer compression may clobber part of the pointer.505// Each auto's GC index will have already been aligned, we just need to make sure506// we align the starting stack offset.507uint32_t unalignedStackIndex = stackIndex;508stackIndex &= ~(TR::Compiler->om.getObjectAlignmentInBytes() - 1);509uint32_t paddingBytes = unalignedStackIndex - stackIndex;510if (paddingBytes > 0)511{512TR_ASSERT((paddingBytes & (TR::Compiler->om.sizeofReferenceAddress() - 1)) == 0, "Padding bytes should be a multiple of the slot/pointer size");513uint32_t paddingSlots = paddingBytes / TR::Compiler->om.sizeofReferenceAddress();514atlas->setNumberOfSlotsMapped(atlas->getNumberOfSlotsMapped() + paddingSlots);515}516}517518// Map local references again to set the stack position correct according to519// the GC map index.520//521for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())522{523if (localCursor->getGCMapIndex() >= 0)524{525localCursor->setOffset(stackIndex + TR::Compiler->om.sizeofReferenceAddress() * (localCursor->getGCMapIndex() - firstLocalGCIndex));526if (localCursor->getGCMapIndex() == atlas->getIndexOfFirstInternalPointer())527{528atlas->setOffsetOfFirstInternalPointer(localCursor->getOffset() - firstLocalOffset);529}530}531}532533method->setObjectTempSlots((lowGCOffset - stackIndex) / TR::Compiler->om.sizeofReferenceAddress());534lowGCOffset = stackIndex;535536// Now map the rest of the locals537//538automaticIterator.reset();539localCursor = automaticIterator.getFirst();540541while (localCursor != NULL)542{543if (comp()->target().is64Bit())544{545if (localCursor->getGCMapIndex() < 0 &&546localCursor->getSize() != 8)547{548mapSingleAutomatic(localCursor, stackIndex);549}550}551else552{553if (localCursor->getGCMapIndex() < 0 &&554localCursor->getDataType() != TR::Double)555{556mapSingleAutomatic(localCursor, stackIndex);557}558}559localCursor = automaticIterator.getNext();560}561562automaticIterator.reset();563localCursor = automaticIterator.getFirst();564565while (localCursor != NULL)566{567if (comp()->target().is64Bit())568{569if (localCursor->getGCMapIndex() < 0 &&570localCursor->getSize() == 8)571{572stackIndex -= (stackIndex & 0x4)?4:0;573mapSingleAutomatic(localCursor, stackIndex);574}575}576else577{578if (localCursor->getGCMapIndex() < 0 &&579localCursor->getDataType() == TR::Double)580{581stackIndex -= (stackIndex & 0x4)?4:0;582mapSingleAutomatic(localCursor, stackIndex);583}584}585localCursor = automaticIterator.getNext();586}587method->setLocalMappingCursor(stackIndex);588589mapIncomingParms(method);590591atlas->setLocalBaseOffset(lowGCOffset - firstLocalOffset);592atlas->setParmBaseOffset(atlas->getParmBaseOffset() + getOffsetToFirstParm() - firstLocalOffset);593}594595void J9::Power::PrivateLinkage::mapSingleAutomatic(TR::AutomaticSymbol *p, uint32_t &stackIndex)596{597int32_t roundup = (comp()->useCompressedPointers() && p->isLocalObject() ? TR::Compiler->om.getObjectAlignmentInBytes() : TR::Compiler->om.sizeofReferenceAddress()) - 1;598int32_t roundedSize = (p->getSize() + roundup) & (~roundup);599if (roundedSize == 0)600roundedSize = 4;601602p->setOffset(stackIndex -= roundedSize);603}604605void J9::Power::PrivateLinkage::setParameterLinkageRegisterIndex(TR::ResolvedMethodSymbol *method)606{607ListIterator<TR::ParameterSymbol> paramIterator(&(method->getParameterList()));608TR::ParameterSymbol *paramCursor = paramIterator.getFirst();609int32_t numIntArgs = 0, numFloatArgs = 0;610const TR::PPCLinkageProperties& properties = getProperties();611612while ( (paramCursor!=NULL) &&613( (numIntArgs < properties.getNumIntArgRegs()) ||614(numFloatArgs < properties.getNumFloatArgRegs()) ) )615{616int32_t index = -1;617618switch (paramCursor->getDataType())619{620case TR::Int8:621case TR::Int16:622case TR::Int32:623case TR::Address:624if (numIntArgs<properties.getNumIntArgRegs())625{626index = numIntArgs;627}628numIntArgs++;629break;630case TR::Int64:631if (numIntArgs<properties.getNumIntArgRegs())632{633index = numIntArgs;634}635if (comp()->target().is64Bit())636numIntArgs ++;637else638numIntArgs += 2;639break;640case TR::Float:641case TR::Double:642if (numFloatArgs<properties.getNumFloatArgRegs())643{644index = numFloatArgs;645}646numFloatArgs++;647break;648}649paramCursor->setLinkageRegisterIndex(index);650paramCursor = paramIterator.getNext();651}652}653654bool J9::Power::PrivateLinkage::hasToBeOnStack(TR::ParameterSymbol *parm)655{656TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();657TR_OpaqueClassBlock *throwableClass;658659/* Defect 138664: All synchronized methods can potentially throw an660IllegalMonitorState exception so we must always save the this pointer on661to the stack so the exception handler can unlock the object. Also,662hasCall() does not consider jitNewObject() calls so an OOM exception could663be thrown even when hasCall() returns false */664665TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());666667bool result = (parm->getAssignedGlobalRegisterIndex()>=0 &&668( ( parm->getLinkageRegisterIndex()==0 &&669parm->isCollectedReference() &&670!bodySymbol->isStatic() &&671( ( bodySymbol->isSynchronised()672) ||673(674!strncmp(bodySymbol->getResolvedMethod()->nameChars(), "<init>", 6) &&675( (throwableClass = fej9->getClassFromSignature("Ljava/lang/Throwable;", 21, bodySymbol->getResolvedMethod())) == 0 ||676fej9->isInstanceOf(bodySymbol->getResolvedMethod()->containingClass(), throwableClass, true) != TR_no677)678)679)680) ||681parm->isParmHasToBeOnStack()682)683);684685// Problem Report 96788:686//687// There is a potential race condition here. Because of the query to the frontend this function could688// possibly return different results at different points in the compilation dependent on whether the689// java/lang/Throwable class is resolved or not. This is a problem because this query is used to690// determine whether we need to generate a GC map for this parameter and whether we need to generate691// a store out to the stack for this parameter. Because these two queries happen at two different points692// in the compilation we could encounter a situation where we generate a GC map for this parameter but693// not generate a store out to the stack. This causes assertions in the VM if we hit a GC point in this694// compilation unit. To avoid this issue we cache the result of this function and directly modify the695// parameter symbol.696697// TODO : Where does the java/lang/Throwable code below originate and why is it here? This seems like698// a very hacky fix to a very specific problem. Also why is this code not commoned up with Z and why699// is it missing for X?700701if (result)702parm->setParmHasToBeOnStack();703704return result;705}706707static TR::Instruction *unrollPrologueInitLoop(TR::CodeGenerator *cg, TR::Node *node, int32_t num, int32_t initSlotOffset, TR::Register *nullReg,708TR::RealRegister *gr11, TR::RealRegister *baseInitReg, TR::RealRegister *gr12, TR::RealRegister *cr0, TR::LabelSymbol *loopLabel,709TR::Instruction *cursor)710{711TR_HeapMemory trHeapMemory = cg->trMemory();712int32_t wordsToUnroll = num;713TR::Compilation *comp = cg->comp();714715static bool disableVSXMemInit = (feGetEnv("TR_disableVSXMemInit") != NULL); //Disable toggle incase we break in production.716bool use8Bytes = ((cg->is64BitProcessor() && TR::Compiler->om.sizeofReferenceAddress() == 4) || TR::Compiler->om.sizeofReferenceAddress() == 8);717bool useVectorStores = (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) && comp->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX) && !disableVSXMemInit);718719if (useVectorStores)720{721int32_t wordsUnrolledPerIteration = (128 * 4) / (TR::Compiler->om.sizeofReferenceAddress() * 8); // (number of bits cleared by one iteration using 4 stxvw4x) / (number of bits per word i.e. bits in a java pointer)722if (wordsToUnroll >= wordsUnrolledPerIteration)723{724TR::RealRegister *vectorNullReg = cg->machine()->getRealRegister(TR::RealRegister::vr0);725cursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::xxlxor, node, vectorNullReg, vectorNullReg, vectorNullReg, cursor);726727int32_t loopIterations = wordsToUnroll / wordsUnrolledPerIteration;728wordsToUnroll = wordsToUnroll % wordsUnrolledPerIteration;729730TR_ASSERT_FATAL( initSlotOffset <= UPPER_IMMED, "initSlotOffset (%d) is too big to fit in a signed immediate field", initSlotOffset);731cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, gr12, baseInitReg, initSlotOffset, cursor);732baseInitReg = gr12;733initSlotOffset = 0;734735if (loopIterations > 1)736{737cursor = loadConstant(cg, node, loopIterations, gr11, cursor);738cursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, gr11, 0, cursor);739cursor = loadConstant(cg, node, 16, gr11, cursor); // r11 is now free so we can use it for const 16 offset740cursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel, cursor);741}742else743{744cursor = loadConstant(cg, node, 16, gr11, cursor);745}746747cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stxvw4x, node, TR::MemoryReference::createWithIndexReg(cg, nullReg, baseInitReg, 16), vectorNullReg, cursor);748cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stxvw4x, node, TR::MemoryReference::createWithIndexReg(cg, gr11 , baseInitReg, 16), vectorNullReg, cursor);749cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, baseInitReg, baseInitReg, 32, cursor);750cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stxvw4x, node, TR::MemoryReference::createWithIndexReg(cg, nullReg, baseInitReg, 16), vectorNullReg, cursor);751cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stxvw4x, node, TR::MemoryReference::createWithIndexReg(cg, gr11 , baseInitReg, 16), vectorNullReg, cursor);752753if (loopIterations > 1)754{755cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, baseInitReg, baseInitReg, 32, cursor);756cursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, loopLabel, cr0, cursor);757}758else759{760initSlotOffset += 32; // if no loops needed, then no need to generate the addi when we can just increase the offset761}762}763764if (use8Bytes && TR::Compiler->om.sizeofReferenceAddress() == 4)765{766// we only need to do half the work since we'll be using std to wipe two 32bit words767// NOTE: we need to do a stw at the end if this is odd since std only stores 8 bytes at a time768// (and we have 4 bytes leftover after the loop)769wordsToUnroll /= 2;770}771772// unroll any remaining words773TR::InstOpCode::Mnemonic instruction = (use8Bytes ? TR::InstOpCode::std : TR::InstOpCode::stw);774int32_t storeSize = (use8Bytes ? 8 : 4);775while (wordsToUnroll > 0)776{777cursor = generateMemSrc1Instruction(cg, instruction, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset, storeSize), nullReg, cursor);778initSlotOffset += storeSize;779wordsToUnroll--;780}781782// if we had an odd number of words to unroll with a 64bit arch, we need to add one more store to clear it783// (since we used store double word)784if ((use8Bytes && TR::Compiler->om.sizeofReferenceAddress() == 4) && (num % 2 == 1))785{786cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset, 4), nullReg, cursor);787}788}789else790{791if (use8Bytes && TR::Compiler->om.sizeofReferenceAddress() == 4)792wordsToUnroll /= 2;793794if (wordsToUnroll >=4)795{796if (wordsToUnroll >=8)797{798if(baseInitReg->getRegisterNumber()== TR::RealRegister::gr14)799{800cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, gr12,baseInitReg, 0 , cursor);801baseInitReg = gr12;802}803cursor = loadConstant(cg, node, (int32_t)(wordsToUnroll/4), gr11, cursor);804cursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, gr11, 0, cursor);805cursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel, cursor);806}807// This clears (wordsToUnroll/4) * (use8Bytes ? 32: 16) bytes.808cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset, TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);809cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset+(use8Bytes?8:4), TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);810cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset+(use8Bytes?16:8), TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);811cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset+(use8Bytes?24:12), TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);812if (wordsToUnroll >=8)813{814cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, gr12, gr12, (use8Bytes?32:16), cursor);815cursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, loopLabel, cr0, cursor);816}817else818{819initSlotOffset += (use8Bytes?32:16);820}821}822// Clears ((use8Bytes ? 8 : 4)* (wordsToUnroll % 4)) bytes823switch (wordsToUnroll % 4)824{825case 3:826cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset+(use8Bytes?16:8), TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);827case 2:828cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset+(use8Bytes?8:4), TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);829case 1:830cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset, TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);831break;832}833// Last one if needed834if (use8Bytes && TR::Compiler->om.sizeofReferenceAddress() == 4 && num % 2 == 1)835{836if (wordsToUnroll %4)837initSlotOffset += (use8Bytes?8:4)*(wordsToUnroll%4);838cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset, TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);839}840}841return cursor;842}843844static int32_t calculateFrameSize(TR::RealRegister::RegNum &intSavedFirst,845int32_t &argSize,846int32_t &size,847int32_t ®SaveOffset,848int32_t &saveSize,849TR::CodeGenerator *cg,850bool &saveLR)851{852TR::Compilation *comp = cg->comp();853TR::Machine *machine = cg->machine();854TR::Linkage* linkage = cg->getLinkage(TR_Private);855const TR::PPCLinkageProperties& properties = cg->getProperties();856int32_t firstLocalOffset = properties.getOffsetToFirstLocal();857int32_t registerSaveDescription = 0;858859// Currently no non-volatile FPR's in private linkage860// If we change the private linkage to add non-volatile FPR's or CCR's861// we should clean up this code to be independent of the linkage862// (ie, to test properties.getPreserved).863//864saveLR = (!cg->getSnippetList().empty() ||865comp->getJittedMethodSymbol()->isEHAware() ||866cg->canExceptByTrap() ||867machine->getLinkRegisterKilled());868869if (0 && comp->target().is64Bit())870{871argSize = (cg->getLargestOutgoingArgSize() * 2) + linkage->getOffsetToFirstParm();872}873else874{875argSize = cg->getLargestOutgoingArgSize() + linkage->getOffsetToFirstParm();876}877878while (intSavedFirst<=TR::RealRegister::LastGPR && !machine->getRealRegister(intSavedFirst)->getHasBeenAssignedInMethod())879intSavedFirst=(TR::RealRegister::RegNum)((uint32_t)intSavedFirst+1);880881// the registerSaveDescription is emitted as follows:882// 0000 0000 0000 000 0 0000 0000 0000 0000883// <---- ---->884// 17 bits for saved GPRs (r15 - r32)885// so the first bit represents whether r15 is saved & so on886// <--- --->887// 15 bits to represent the save offset from bp888// allowing 2^15 bytes / 8 = 4096 locals in 64-bit889//890for (int32_t i = intSavedFirst; i <= TR::RealRegister::LastGPR; i++)891{892registerSaveDescription |= 1 << (i - TR::RealRegister::gr15);893}894895// Currently no non-volatile FPR's in private linkage896897saveSize += (TR::RealRegister::LastGPR - intSavedFirst + 1) * TR::Compiler->om.sizeofReferenceAddress();898899size += saveSize+argSize;900if (!saveLR && size == -firstLocalOffset) // TODO: have a emptyFrame bool to be used throughout901{902TR_ASSERT(argSize==0, "Wrong descriptor setting");903size = 0;904cg->setFrameSizeInBytes(0);905}906else907{908//Align the stack frame909const uint32_t alignBytes = 16;910size = (size + (alignBytes - 1) & (~(alignBytes - 1)));911912regSaveOffset = (size-argSize+firstLocalOffset);913914//In MethodMetaData jitAddSpilledRegisters, we lookup the regSaveOffset915//which must match up to what we have here or else the stackwalker will916//run into errors.917//Fail the compilation if we overflow the 15 bits of regSaveOffset.918if(regSaveOffset > 0x7FFF || regSaveOffset < 0 )919{920//Fail if we underflow or overflow.921comp->failCompilation<TR::CompilationInterrupted>("Overflowed or underflowed bounds of regSaveOffset in calculateFrameSize.");922}923924if (comp->getOption(TR_TraceCG))925traceMsg(comp, "PPCLinkage calculateFrameSize registerSaveDescription: 0x%x regSaveOffset: %x\n", registerSaveDescription, regSaveOffset);926registerSaveDescription |= (regSaveOffset << 17); // see above for details927cg->setFrameSizeInBytes(size+firstLocalOffset);928TR_ASSERT((size-argSize+firstLocalOffset)<2048*1024, "Descriptor overflowed.\n");929}930931return registerSaveDescription;932}933934void J9::Power::PrivateLinkage::createPrologue(TR::Instruction *cursor)935{936TR::Machine *machine = cg()->machine();937const TR::PPCLinkageProperties& properties = getProperties();938TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();939TR::RealRegister *stackPtr = cg()->getStackPointerRegister();940TR::RealRegister *metaBase = cg()->getMethodMetaDataRegister();941TR::RealRegister *gr0 = machine->getRealRegister(TR::RealRegister::gr0);942TR::RealRegister *gr11 = machine->getRealRegister(TR::RealRegister::gr11);943TR::RealRegister *gr12 = machine->getRealRegister(TR::RealRegister::gr12);944TR::RealRegister *cr0 = machine->getRealRegister(TR::RealRegister::cr0);945TR::Node *firstNode = comp()->getStartTree()->getNode();946int32_t size = -(bodySymbol->getLocalMappingCursor());947int32_t residualSize, saveSize=0, argSize;948int32_t registerSaveDescription=0;949int32_t firstLocalOffset = properties.getOffsetToFirstLocal();950int i;951TR::RealRegister::RegNum intSavedFirst=TR::RealRegister::gr15;952TR::RealRegister::RegNum regIndex;953int32_t regSaveOffset = 0;954bool saveLR = false;955registerSaveDescription = calculateFrameSize(intSavedFirst, argSize, size, regSaveOffset, saveSize, cg(), saveLR);956957cg()->setRegisterSaveDescription(registerSaveDescription);958residualSize = size;959960if (comp()->getOption(TR_EntryBreakPoints))961{962cursor = generateInstruction(cg(), TR::InstOpCode::bad, firstNode, cursor);963}964965bool fsd = comp()->getOption(TR_FullSpeedDebug);966967// If in Full Speed Debug, the parameters have to be saved before the call to Stack Check968// and the stack map and register maps have to be updated accordingly969if (fsd)970{971// Only call saveArguments for pushing the parameters on the stack when we are on Full Speed Debug972cursor = saveArguments(cursor, fsd, true);973}974975// Load the stack limit offset for comparison976if (!comp()->isDLT())977cursor = generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, firstNode, gr11,978TR::MemoryReference::createWithDisplacement(cg(), metaBase, cg()->getStackLimitOffset(),979TR::Compiler->om.sizeofReferenceAddress()), cursor);980981if (cg()->getFrameSizeInBytes() || saveLR)982{983if ((cg()->getFrameSizeInBytes() + TR::Compiler->om.sizeofReferenceAddress()) > (-LOWER_IMMED))984{985// Large Frame Support986987// gr12 <- (totalFrameSize + 1 slot)988cursor = loadConstant(cg(), firstNode, (int32_t)(cg()->getFrameSizeInBytes() + TR::Compiler->om.sizeofReferenceAddress()), gr12, cursor);989990// javaSP <- javaSP - (totalFrameSize + 1 slot)991cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::subf, firstNode, stackPtr, gr12, stackPtr, cursor);992993// gr12 == totalFrameSize994if (!comp()->isDLT())995cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2, firstNode, gr12, gr12, -TR::Compiler->om.sizeofReferenceAddress(), cursor);996997if (saveLR)998{999cursor = generateTrg1Instruction(cg(), TR::InstOpCode::mflr, firstNode, gr0, cursor);1000}10011002// Check for stack overflow (set a flag)1003if (!comp()->isDLT())1004cursor = generateTrg1Src2Instruction(cg(),TR::InstOpCode::Op_cmpl, firstNode, cr0, stackPtr, gr11, cursor);10051006if (saveLR)1007{1008// javaSP[totalFrameSize] <- linkRegister1009cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stx, firstNode, TR::MemoryReference::createWithIndexReg(cg(), stackPtr, gr12, TR::Compiler->om.sizeofReferenceAddress()),1010gr0, cursor);1011}1012}1013else1014{1015// Small Frame Support10161017// javaSP <- javaSP - (totalFrameSize + 1 slot)1018cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2,1019firstNode, stackPtr, stackPtr, -(cg()->getFrameSizeInBytes() + TR::Compiler->om.sizeofReferenceAddress()), cursor);1020if (saveLR)1021{1022cursor = generateTrg1Instruction(cg(), TR::InstOpCode::mflr, firstNode, gr0, cursor);1023}10241025// Check for stack overflow (set a flag)1026if (!comp()->isDLT())1027cursor = generateTrg1Src2Instruction(cg(),TR::InstOpCode::Op_cmpl, firstNode, cr0, stackPtr, gr11, cursor);10281029if (saveLR)1030{1031// javaSP[totalFrameSize] <- linkRegister1032cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, cg()->getFrameSizeInBytes(), TR::Compiler->om.sizeofReferenceAddress()),1033gr0, cursor);1034}1035}1036}1037else1038{1039// Empty Frame Support10401041// Check for stack overflow (set a flag)1042if (!comp()->isDLT())1043cursor = generateTrg1Src2Instruction(cg(),TR::InstOpCode::Op_cmpl, firstNode, cr0, stackPtr, gr11, cursor);1044}10451046if (!comp()->isDLT())1047{1048TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg());1049TR::LabelSymbol *reStartLabel = generateLabelSymbol(cg());10501051// Branch to StackOverflow snippet if javaSP > stack limit1052if (comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))1053// use PPC AS branch hint1054cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::ble, PPCOpProp_BranchUnlikely, firstNode, snippetLabel, cr0, cursor);1055else1056cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::ble, firstNode, snippetLabel, cr0, cursor);1057TR::Snippet *snippet = new (trHeapMemory()) TR::PPCStackCheckFailureSnippet(cg(), firstNode, reStartLabel, snippetLabel);1058cg()->addSnippet(snippet);1059cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, firstNode, reStartLabel, cursor);1060}10611062if (intSavedFirst <= TR::RealRegister::LastGPR)1063{1064if (comp()->target().is64Bit() ||1065(TR::RealRegister::LastGPR - intSavedFirst <= 3))1066{1067for (regIndex=intSavedFirst; regIndex<=TR::RealRegister::LastGPR; regIndex=(TR::RealRegister::RegNum)((uint32_t)regIndex+1))1068{1069cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, argSize, TR::Compiler->om.sizeofReferenceAddress()), machine->getRealRegister(regIndex), cursor);10701071argSize = argSize + TR::Compiler->om.sizeofReferenceAddress();1072}1073}1074else1075{1076cursor = generateMemSrc1Instruction(cg(), (intSavedFirst==TR::RealRegister::LastGPR)?TR::InstOpCode::stw:TR::InstOpCode::stmw, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, argSize, 4*(TR::RealRegister::LastGPR-intSavedFirst+1)), machine->getRealRegister(intSavedFirst), cursor);10771078argSize += (TR::RealRegister::LastGPR - intSavedFirst + 1) * 4;1079}1080}108110821083TR::GCStackAtlas *atlas = cg()->getStackAtlas();1084if (atlas != NULL)1085{1086//1087// Note that since internal pointer support has been added, all pinning1088// array autos and derived internal pointer autos must be zero initialized1089// in prologue regardless of the liveness information. This is because1090// the stack walker/GC examine internal pointer related slots whenever GC1091// occurs. Having the slots in uninitialized state is not correct for GC.1092//1093uint32_t numLocalsToBeInitialized = atlas->getNumberOfSlotsToBeInitialized();1094if ((numLocalsToBeInitialized > 0) ||1095atlas->getInternalPointerMap())1096{1097bool adjustedFrameOnce = false;1098TR::RealRegister *nullValueRegister = gr0;1099int32_t offset = atlas->getLocalBaseOffset();11001101cursor = loadConstant(cg(), firstNode, NULLVALUE, nullValueRegister, cursor);11021103static bool disableUnrollPrologueInitLoop = (feGetEnv("TR_DisableUnrollPrologueInitLoop") != NULL);1104if (numLocalsToBeInitialized > 5)1105{1106int32_t loopDistance = -numLocalsToBeInitialized * TR::Compiler->om.sizeofReferenceAddress();1107int32_t initBottomOffset = offset - loopDistance;1108int32_t initSlotOffset =0;11091110TR_ASSERT(initBottomOffset<=0, "Initialized and internal pointer portion size doesn't make senses");1111if (residualSize >= -LOWER_IMMED)1112{1113cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::add, firstNode, gr12, gr12, stackPtr, cursor);1114adjustedFrameOnce = true;1115if (size == residualSize) // only happens when LR is not saved1116{1117residualSize -= TR::Compiler->om.sizeofReferenceAddress();1118initBottomOffset -= TR::Compiler->om.sizeofReferenceAddress();1119}11201121if (initBottomOffset < LOWER_IMMED)1122{1123if (0x00008000 == HI_VALUE(initBottomOffset))1124{1125cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addis, firstNode, gr12, gr12, 0x7FFF, cursor);1126cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addis, firstNode, gr12, gr12, 0x1, cursor);1127}1128else1129{1130cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addis, firstNode, gr12, gr12, HI_VALUE(initBottomOffset), cursor);1131}1132}11331134if (initBottomOffset & 0xFFFF)1135cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2, firstNode, gr12, gr12, LO_VALUE(initBottomOffset), cursor);1136}1137else1138{1139adjustedFrameOnce = true;1140if (size == residualSize) // only happens when LR is not saved1141residualSize -= TR::Compiler->om.sizeofReferenceAddress();1142initSlotOffset = initSlotOffset+ residualSize+initBottomOffset;1143}11441145TR::LabelSymbol *loopLabel = generateLabelSymbol(cg());1146if (!disableUnrollPrologueInitLoop)1147{1148initSlotOffset += loopDistance;1149if (residualSize >= -LOWER_IMMED)1150cursor = unrollPrologueInitLoop(cg(), firstNode, numLocalsToBeInitialized, loopDistance, nullValueRegister, gr11, gr12, gr12, cr0, loopLabel, cursor);1151else1152cursor = unrollPrologueInitLoop(cg(), firstNode, numLocalsToBeInitialized, initSlotOffset, nullValueRegister, gr11, stackPtr, gr12, cr0, loopLabel, cursor);1153}1154else1155{1156cursor = loadConstant(cg(), firstNode, loopDistance, gr11, cursor);1157cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, firstNode, loopLabel, cursor);1158if (residualSize >= -LOWER_IMMED)1159cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stx, firstNode, TR::MemoryReference::createWithIndexReg(cg(), gr12, gr11, TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);1160else1161cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stx, firstNode, TR::MemoryReference::createWithIndexReg(cg(), stackPtr, gr11, initSlotOffset+ TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);1162cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addic_r, firstNode, gr11, gr11, cr0, TR::Compiler->om.sizeofReferenceAddress(), cursor);1163cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, firstNode, loopLabel, cr0, cursor);1164}1165}1166else1167{1168adjustedFrameOnce = true;1169if (size == residualSize) // only happens when LR is not saved1170residualSize -= TR::Compiler->om.sizeofReferenceAddress();1171bool use8BytesOn32Bit = cg()->is64BitProcessor() && (TR::Compiler->om.sizeofReferenceAddress() == 4);1172if (!disableUnrollPrologueInitLoop && use8BytesOn32Bit)1173{1174int32_t count = 0;1175if (numLocalsToBeInitialized >= 2)1176{1177cursor = generateMemSrc1Instruction(cg(), TR::InstOpCode::std, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, offset+residualSize, TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);1178count++;1179if (numLocalsToBeInitialized >= 4)1180{1181cursor = generateMemSrc1Instruction(cg(), TR::InstOpCode::std, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, offset+residualSize+8, TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);1182count++;1183}1184}1185if (numLocalsToBeInitialized % 2 == 1)1186cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, offset+residualSize+(count*8), TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);1187}1188else1189{1190for (i = 0; i < numLocalsToBeInitialized; i++, offset += TR::Compiler->om.sizeofReferenceAddress())1191{1192cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, offset+residualSize, TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);1193}1194}1195}11961197if (atlas->getInternalPointerMap())1198{1199int32_t offset = atlas->getOffsetOfFirstInternalPointer();12001201// First collect all pinning arrays that are the base for at least1202// one derived internal pointer stack slot1203//1204int32_t numDistinctPinningArrays = 0;1205List<TR_InternalPointerPair> seenInternalPtrPairs(trMemory());1206List<TR::AutomaticSymbol> seenPinningArrays(trMemory());1207ListIterator<TR_InternalPointerPair> internalPtrIt(&atlas->getInternalPointerMap()->getInternalPointerPairs());1208for (TR_InternalPointerPair *internalPtrPair = internalPtrIt.getFirst(); internalPtrPair; internalPtrPair = internalPtrIt.getNext())1209{1210bool seenPinningArrayBefore = false;1211ListIterator<TR_InternalPointerPair> seenInternalPtrIt(&seenInternalPtrPairs);1212for (TR_InternalPointerPair *seenInternalPtrPair = seenInternalPtrIt.getFirst(); seenInternalPtrPair && (seenInternalPtrPair != internalPtrPair); seenInternalPtrPair = seenInternalPtrIt.getNext())1213{1214if (internalPtrPair->getPinningArrayPointer() == seenInternalPtrPair->getPinningArrayPointer())1215{1216seenPinningArrayBefore = true;1217break;1218}1219}12201221if (!seenPinningArrayBefore)1222{1223seenPinningArrays.add(internalPtrPair->getPinningArrayPointer());1224seenInternalPtrPairs.add(internalPtrPair);1225numDistinctPinningArrays++;1226}1227}12281229// Now collect all pinning arrays that are the base for only1230// internal pointers in registers1231//1232ListIterator<TR::AutomaticSymbol> autoIt(&atlas->getPinningArrayPtrsForInternalPtrRegs());1233TR::AutomaticSymbol *autoSymbol;1234for (autoSymbol = autoIt.getFirst(); autoSymbol != NULL; autoSymbol = autoIt.getNext())1235{1236if (!seenPinningArrays.find(autoSymbol))1237{1238seenPinningArrays.add(autoSymbol);1239numDistinctPinningArrays++;1240}1241}12421243// Total number of slots to be initialized is number of pinning arrays +1244// number of derived internal pointer stack slots1245//1246int32_t numSlotsToBeInitialized = numDistinctPinningArrays + atlas->getInternalPointerMap()->getNumInternalPointers();12471248if (!adjustedFrameOnce)1249{1250if (size == residualSize) // only happens when LR is not saved1251residualSize -= TR::Compiler->om.sizeofReferenceAddress();1252}1253if (!disableUnrollPrologueInitLoop)1254{1255TR::LabelSymbol *loopLabel = generateLabelSymbol(cg());1256cursor = unrollPrologueInitLoop(cg(), firstNode, numSlotsToBeInitialized, offset+residualSize, nullValueRegister, gr11, stackPtr, gr12, cr0, loopLabel, cursor);1257}1258else1259{1260for (i = 0; i < numSlotsToBeInitialized; i++, offset += TR::Compiler->om.sizeofReferenceAddress())1261{1262cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, offset+residualSize, TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);1263}1264}1265}1266}1267}12681269TR_ASSERT(size<=UPPER_IMMED-1032, "Setting up a frame pointer anyway.");1270ListIterator<TR::AutomaticSymbol> automaticIterator(&bodySymbol->getAutomaticList());1271TR::AutomaticSymbol *localCursor = automaticIterator.getFirst();12721273while (localCursor!=NULL)1274{1275TR_ASSERT(!comp()->useCompressedPointers() ||1276!localCursor->isLocalObject() ||1277!localCursor->isCollectedReference() ||1278(localCursor->getOffset() & (TR::Compiler->om.getObjectAlignmentInBytes() - 1)) == 0,1279"Stack allocated object not aligned to minimum required alignment");1280localCursor->setOffset(localCursor->getOffset() + size);1281localCursor = automaticIterator.getNext();1282}12831284ListIterator<TR::ParameterSymbol> parameterIterator(&bodySymbol->getParameterList());1285TR::ParameterSymbol *parmCursor = parameterIterator.getFirst();1286while (parmCursor != NULL)1287{1288parmCursor->setParameterOffset(parmCursor->getParameterOffset() + size);1289parmCursor = parameterIterator.getNext();1290}12911292// Save or move arguments according to the result of register assignment.1293// If in Full Speed Debug mode, it will not push the arguments to the stack (which was done1294// above) but it will complete the other operations1295// If not in Full Speed Debug mode, it will execute all operations in saveArguments1296cursor = saveArguments(cursor, fsd, false);12971298if (atlas != NULL)1299{1300TR_GCStackMap *map = atlas->getLocalMap();1301map->setLowestOffsetInstruction(cursor);1302if (!comp()->useRegisterMaps())1303atlas->addStackMap(map);1304}1305}13061307TR::MemoryReference *J9::Power::PrivateLinkage::getOutgoingArgumentMemRef(int32_t argSize, TR::Register *argReg, TR::InstOpCode::Mnemonic opCode, TR::PPCMemoryArgument &memArg, uint32_t length)1308{1309TR::MemoryReference *result = TR::MemoryReference::createWithDisplacement(cg(), cg()->getStackPointerRegister(), argSize, length);1310memArg.argRegister = argReg;1311memArg.argMemory = result;1312memArg.opCode = opCode;1313return(result);1314}13151316void J9::Power::PrivateLinkage::createEpilogue(TR::Instruction *cursor)1317{1318TR::Machine *machine = cg()->machine();1319const TR::PPCLinkageProperties& properties = getProperties();1320TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();1321TR::RealRegister *stackPtr = cg()->getStackPointerRegister();1322TR::RealRegister *gr12 = machine->getRealRegister(TR::RealRegister::gr12);1323TR::RealRegister *gr0 = machine->getRealRegister(TR::RealRegister::gr0);1324TR::Node *currentNode = cursor->getNode();1325int32_t saveSize;1326int32_t frameSize = cg()->getFrameSizeInBytes();1327TR::RealRegister::RegNum savedFirst=TR::RealRegister::gr15;1328TR::RealRegister::RegNum regIndex;1329bool restoreLR = (cg()->getSnippetList().size()>1 ||1330(comp()->isDLT() && !cg()->getSnippetList().empty()) ||1331bodySymbol->isEHAware() ||1332cg()->canExceptByTrap() ||1333machine->getLinkRegisterKilled());13341335bool saveLR = restoreLR || machine->getLinkRegisterKilled();133613371338if (restoreLR && frameSize <= UPPER_IMMED)1339{1340cursor = generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, currentNode, gr0, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, frameSize, TR::Compiler->om.sizeofReferenceAddress()), cursor);1341cursor = generateSrc1Instruction(cg(), TR::InstOpCode::mtlr, currentNode, gr0, 0, cursor);1342}13431344if (0 && comp()->target().is64Bit())1345{1346saveSize = (cg()->getLargestOutgoingArgSize() * 2) + getOffsetToFirstParm();1347}1348else1349{1350saveSize = cg()->getLargestOutgoingArgSize() + getOffsetToFirstParm();1351}13521353while (savedFirst<=TR::RealRegister::LastGPR && !machine->getRealRegister(savedFirst)->getHasBeenAssignedInMethod())1354savedFirst=(TR::RealRegister::RegNum)((uint32_t)savedFirst+1);13551356if (savedFirst <= TR::RealRegister::LastGPR)1357{1358if (comp()->target().is64Bit() ||1359(TR::RealRegister::LastGPR - savedFirst <= 3))1360{1361for (regIndex=savedFirst; regIndex<=TR::RealRegister::LastGPR; regIndex=(TR::RealRegister::RegNum)((uint32_t)regIndex+1))1362{1363cursor = generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, currentNode, machine->getRealRegister(regIndex), TR::MemoryReference::createWithDisplacement(cg(), stackPtr, saveSize, TR::Compiler->om.sizeofReferenceAddress()), cursor);13641365saveSize = saveSize + TR::Compiler->om.sizeofReferenceAddress();1366}1367}1368else1369{1370cursor = generateTrg1MemInstruction(cg(), (savedFirst==TR::RealRegister::LastGPR)?TR::InstOpCode::lwz:TR::InstOpCode::lmw, currentNode, machine->getRealRegister(savedFirst), TR::MemoryReference::createWithDisplacement(cg(), stackPtr, saveSize, 4*(TR::RealRegister::LastGPR-savedFirst+1)), cursor);13711372saveSize += (TR::RealRegister::LastGPR - savedFirst + 1) * 4;1373}1374}13751376if (frameSize || saveLR)1377{1378saveSize = cg()->getFrameSizeInBytes() + TR::Compiler->om.sizeofReferenceAddress();1379if (saveSize > UPPER_IMMED)1380{1381cursor = loadConstant(cg(), currentNode, saveSize, gr12, cursor);1382cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::add, currentNode, stackPtr, stackPtr, gr12, cursor);1383}1384else1385{1386cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2, currentNode, stackPtr, stackPtr, saveSize, cursor);1387}13881389if (restoreLR && frameSize > UPPER_IMMED)1390{1391cursor = generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, currentNode, gr0, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, -TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()), cursor);1392cursor = generateSrc1Instruction(cg(), TR::InstOpCode::mtlr, currentNode, gr0, 0, cursor);1393}1394}1395}13961397int32_t J9::Power::PrivateLinkage::buildArgs(TR::Node *callNode,1398TR::RegisterDependencyConditions *dependencies)1399{1400return buildPrivateLinkageArgs(callNode, dependencies, TR_Private);1401}14021403int32_t J9::Power::PrivateLinkage::buildPrivateLinkageArgs(TR::Node *callNode,1404TR::RegisterDependencyConditions *dependencies,1405TR_LinkageConventions linkage)1406{1407TR_ASSERT(linkage == TR_Private || linkage == TR_Helper || linkage == TR_CHelper, "Unexpected linkage convention");14081409const TR::PPCLinkageProperties& properties = getProperties();1410TR::PPCMemoryArgument *pushToMemory = NULL;1411TR::Register *tempRegister;1412int32_t argIndex = 0, memArgs = 0, from, to, step;1413int32_t argSize = -getOffsetToFirstParm(), totalSize = 0;1414uint32_t numIntegerArgs = 0;1415uint32_t numFloatArgs = 0;1416uint32_t firstExplicitArg = 0;1417TR::Node *child;1418void *smark;1419uint32_t firstArgumentChild = callNode->getFirstArgumentIndex();1420TR::DataType resType = callNode->getType();1421TR_Array<TR::Register *>& tempLongRegisters = cg()->getTransientLongRegisters();1422TR::MethodSymbol *callSymbol = callNode->getSymbol()->castToMethodSymbol();14231424bool isHelperCall = linkage == TR_Helper || linkage == TR_CHelper;1425bool rightToLeft = isHelperCall &&1426//we want the arguments for induceOSR to be passed from left to right as in any other non-helper call1427!callNode->getSymbolReference()->isOSRInductionHelper();14281429if (rightToLeft)1430{1431from = callNode->getNumChildren() - 1;1432to = firstArgumentChild;1433step = -1;1434}1435else1436{1437from = firstArgumentChild;1438to = callNode->getNumChildren() - 1;1439step = 1;1440}14411442if (!properties.getPreserved(TR::RealRegister::gr2))1443{1444// Helper linkage preserves all registers that are not argument registers, so we don't need to spill them.1445if (linkage != TR_Helper)1446TR::addDependency(dependencies, NULL, TR::RealRegister::gr2, TR_GPR, cg());1447}14481449uint32_t numIntArgRegs = properties.getNumIntArgRegs();1450uint32_t numFloatArgRegs = properties.getNumFloatArgRegs();1451TR::RealRegister::RegNum specialArgReg = TR::RealRegister::NoReg;1452switch (callSymbol->getMandatoryRecognizedMethod())1453{1454// Node: special long args are still only passed in one GPR1455case TR::java_lang_invoke_ComputedCalls_dispatchJ9Method:1456specialArgReg = getProperties().getJ9MethodArgumentRegister();1457// Other args go in memory1458numIntArgRegs = 0;1459numFloatArgRegs = 0;1460break;1461case TR::java_lang_invoke_ComputedCalls_dispatchVirtual:1462case TR::com_ibm_jit_JITHelpers_dispatchVirtual:1463specialArgReg = getProperties().getVTableIndexArgumentRegister();1464break;1465}14661467if (specialArgReg != TR::RealRegister::NoReg)1468{1469if (comp()->getOption(TR_TraceCG))1470{1471traceMsg(comp(), "Special arg %s in %s\n",1472comp()->getDebug()->getName(callNode->getChild(from)),1473comp()->getDebug()->getName(cg()->machine()->getRealRegister(specialArgReg)));1474}1475// Skip the special arg in the first loop1476from += step;1477}14781479// C helpers have an implicit first argument (the VM thread) that we have to account for1480if (linkage == TR_CHelper)1481{1482TR_ASSERT(numIntArgRegs > 0, "This code doesn't handle passing this implicit arg on the stack");1483numIntegerArgs++;1484totalSize += TR::Compiler->om.sizeofReferenceAddress();1485}14861487for (int32_t i = from; (rightToLeft && i >= to) || (!rightToLeft && i <= to); i += step)1488{1489child = callNode->getChild(i);1490switch (child->getDataType())1491{1492case TR::Int8:1493case TR::Int16:1494case TR::Int32:1495case TR::Address:1496if (numIntegerArgs >= numIntArgRegs)1497memArgs++;1498numIntegerArgs++;1499totalSize += TR::Compiler->om.sizeofReferenceAddress();1500break;1501case TR::Int64:1502if (comp()->target().is64Bit())1503{1504if (numIntegerArgs >= numIntArgRegs)1505memArgs++;1506numIntegerArgs++;1507}1508else1509{1510if (numIntegerArgs+1 == numIntArgRegs)1511memArgs++;1512else if (numIntegerArgs+1 > numIntArgRegs)1513memArgs += 2;1514numIntegerArgs += 2;1515}1516totalSize += 2*TR::Compiler->om.sizeofReferenceAddress();1517break;1518case TR::Float:1519if (numFloatArgs >= numFloatArgRegs)1520memArgs++;1521numFloatArgs++;1522totalSize += TR::Compiler->om.sizeofReferenceAddress();1523break;1524case TR::Double:1525if (numFloatArgs >= numFloatArgRegs)1526memArgs++;1527numFloatArgs++;1528totalSize += 2*TR::Compiler->om.sizeofReferenceAddress();1529break;1530}1531}15321533// From here, down, any new stack allocations will expire / die when the function returns1534TR::StackMemoryRegion stackMemoryRegion(*trMemory());15351536if (memArgs > 0)1537{1538pushToMemory = new (trStackMemory()) TR::PPCMemoryArgument[memArgs];1539}15401541if (specialArgReg)1542from -= step; // we do want to process special args in the following loop15431544numIntegerArgs = 0;1545numFloatArgs = 0;15461547// C helpers have an implicit first argument (the VM thread) that we have to account for1548if (linkage == TR_CHelper)1549{1550TR_ASSERT(numIntArgRegs > 0, "This code doesn't handle passing this implicit arg on the stack");1551TR::Register *vmThreadArgRegister = cg()->allocateRegister();1552generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, vmThreadArgRegister, cg()->getMethodMetaDataRegister());1553dependencies->addPreCondition(vmThreadArgRegister, properties.getIntegerArgumentRegister(numIntegerArgs));1554if (resType.getDataType() == TR::NoType)1555dependencies->addPostCondition(vmThreadArgRegister, properties.getIntegerArgumentRegister(numIntegerArgs));1556numIntegerArgs++;1557firstExplicitArg = 1;1558}15591560// Helper linkage preserves all argument registers except the return register1561// TODO: C helper linkage does not, this code needs to make sure argument registers are killed in post dependencies1562for (int32_t i = from; (rightToLeft && i >= to) || (!rightToLeft && i <= to); i += step)1563{1564TR::MemoryReference *mref = NULL;1565TR::Register *argRegister;1566child = callNode->getChild(i);1567bool isSpecialArg = (i == from && specialArgReg != TR::RealRegister::NoReg);1568switch (child->getDataType())1569{1570case TR::Int8:1571case TR::Int16:1572case TR::Int32:1573case TR::Address: // have to do something for GC maps here1574if (i == firstArgumentChild && callNode->getOpCode().isIndirect())1575{1576argRegister = pushThis(child);1577}1578else1579{1580if (child->getDataType() == TR::Address)1581{1582argRegister = pushAddressArg(child);1583}1584else1585{1586argRegister = pushIntegerWordArg(child);1587}1588}1589if (isSpecialArg)1590{1591if (specialArgReg == properties.getIntegerReturnRegister(0))1592{1593TR::Register *resultReg;1594if (resType.isAddress())1595resultReg = cg()->allocateCollectedReferenceRegister();1596else1597resultReg = cg()->allocateRegister();1598dependencies->addPreCondition(argRegister, specialArgReg);1599dependencies->addPostCondition(resultReg, properties.getIntegerReturnRegister(0));1600}1601else1602{1603TR::addDependency(dependencies, argRegister, specialArgReg, TR_GPR, cg());1604}1605}1606else1607{1608argSize += TR::Compiler->om.sizeofReferenceAddress();1609if (numIntegerArgs < numIntArgRegs)1610{1611if (!cg()->canClobberNodesRegister(child, 0))1612{1613if (argRegister->containsCollectedReference())1614tempRegister = cg()->allocateCollectedReferenceRegister();1615else1616tempRegister = cg()->allocateRegister();1617generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, argRegister);1618argRegister = tempRegister;1619}1620if (numIntegerArgs == firstExplicitArg &&1621(resType.isInt32() || resType.isInt64() || resType.isAddress()))1622{1623TR::Register *resultReg;1624if (resType.isAddress())1625resultReg = cg()->allocateCollectedReferenceRegister();1626else1627resultReg = cg()->allocateRegister();1628dependencies->addPreCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));1629dependencies->addPostCondition(resultReg, TR::RealRegister::gr3);1630if (firstExplicitArg == 1)1631dependencies->addPostCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));1632}1633else if (comp()->target().is32Bit() && numIntegerArgs == (firstExplicitArg + 1) && resType.isInt64())1634{1635TR::Register *resultReg = cg()->allocateRegister();1636dependencies->addPreCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));1637dependencies->addPostCondition(resultReg, TR::RealRegister::gr4);1638if (firstExplicitArg == 1)1639dependencies->addPostCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));1640}1641else1642{1643TR::addDependency(dependencies, argRegister, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());1644}1645}1646else // numIntegerArgs >= numIntArgRegs1647{1648if (child->getDataType() == TR::Address)1649mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister,TR::InstOpCode::Op_st, pushToMemory[argIndex++], TR::Compiler->om.sizeofReferenceAddress());1650else1651mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister, TR::InstOpCode::stw, pushToMemory[argIndex++], 4);1652}1653numIntegerArgs++;1654}1655break;1656case TR::Int64:1657argRegister = pushLongArg(child);1658if (isSpecialArg)1659{1660// Note: special arg regs use only one reg even on 32-bit platforms.1661// If the special arg is of type TR::Int64, that only means we don't1662// care about the top 32 bits.1663TR::Register *specialArgRegister = argRegister->getRegisterPair()? argRegister->getLowOrder() : argRegister;1664if (specialArgReg == properties.getIntegerReturnRegister(0))1665{1666TR::Register *resultReg;1667if (resType.isAddress())1668resultReg = cg()->allocateCollectedReferenceRegister();1669else1670resultReg = cg()->allocateRegister();1671dependencies->addPreCondition(specialArgRegister, specialArgReg);1672dependencies->addPostCondition(resultReg, properties.getIntegerReturnRegister(0));1673}1674else1675{1676TR::addDependency(dependencies, specialArgRegister, specialArgReg, TR_GPR, cg());1677}1678}1679else1680{1681argSize += 2*TR::Compiler->om.sizeofReferenceAddress();1682if (numIntegerArgs < numIntArgRegs)1683{1684if (!cg()->canClobberNodesRegister(child, 0))1685{1686if (comp()->target().is64Bit())1687{1688if (argRegister->containsCollectedReference())1689tempRegister = cg()->allocateCollectedReferenceRegister();1690else1691tempRegister = cg()->allocateRegister();1692generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, argRegister);1693argRegister = tempRegister;1694}1695else1696{1697tempRegister = cg()->allocateRegister();1698generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, argRegister->getRegisterPair()->getHighOrder());1699argRegister = cg()->allocateRegisterPair(argRegister->getRegisterPair()->getLowOrder(), tempRegister);1700tempLongRegisters.add(argRegister);1701}1702}1703if (numIntegerArgs == firstExplicitArg && (resType.isInt32() || resType.isInt64() || resType.isAddress()))1704{1705TR::Register *resultReg;1706if (resType.isAddress())1707resultReg = cg()->allocateCollectedReferenceRegister();1708else1709resultReg = cg()->allocateRegister();1710if (comp()->target().is64Bit())1711dependencies->addPreCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));1712else1713dependencies->addPreCondition(argRegister->getRegisterPair()->getHighOrder(), properties.getIntegerArgumentRegister(numIntegerArgs));1714dependencies->addPostCondition(resultReg, TR::RealRegister::gr3);1715if (firstExplicitArg == 1)1716dependencies->addPostCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));1717}1718else if (comp()->target().is32Bit() && numIntegerArgs == (firstExplicitArg + 1) && resType.isInt64())1719{1720TR::Register *resultReg = cg()->allocateRegister();1721dependencies->addPreCondition(argRegister->getRegisterPair()->getHighOrder(), properties.getIntegerArgumentRegister(numIntegerArgs));1722dependencies->addPostCondition(resultReg, TR::RealRegister::gr4);1723if (firstExplicitArg == 1)1724dependencies->addPostCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));1725}1726else1727{1728if (comp()->target().is64Bit())1729TR::addDependency(dependencies, argRegister, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());1730else1731TR::addDependency(dependencies, argRegister->getRegisterPair()->getHighOrder(), properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());1732}1733if (comp()->target().is32Bit())1734{1735if (numIntegerArgs+1 < numIntArgRegs)1736{1737if (!cg()->canClobberNodesRegister(child, 0))1738{1739TR::Register *over_lowReg = argRegister->getRegisterPair()->getLowOrder();1740tempRegister = cg()->allocateRegister();1741generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, over_lowReg);1742argRegister->getRegisterPair()->setLowOrder(tempRegister, cg());1743}1744if (numIntegerArgs == firstExplicitArg && resType.isInt64())1745{1746TR::Register *resultReg = cg()->allocateRegister();1747dependencies->addPreCondition(argRegister->getRegisterPair()->getLowOrder(), properties.getIntegerArgumentRegister(numIntegerArgs + 1));1748dependencies->addPostCondition(resultReg, TR::RealRegister::gr4);1749if (firstExplicitArg == 1)1750dependencies->addPostCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs + 1));1751}1752else1753TR::addDependency(dependencies, argRegister->getRegisterPair()->getLowOrder(), properties.getIntegerArgumentRegister(numIntegerArgs+1), TR_GPR, cg());1754}1755else // numIntegerArgs+1 == numIntArgRegs1756mref = getOutgoingArgumentMemRef(totalSize-argSize+4, argRegister->getRegisterPair()->getLowOrder(), TR::InstOpCode::stw, pushToMemory[argIndex++], 4);1757numIntegerArgs++;1758}1759}1760else // numIntegerArgs >= numIntArgRegs1761{1762if (comp()->target().is64Bit())1763mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister, TR::InstOpCode::std, pushToMemory[argIndex++], 8);1764else1765{1766mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister->getRegisterPair()->getHighOrder(), TR::InstOpCode::stw, pushToMemory[argIndex++], 4);1767mref = getOutgoingArgumentMemRef(totalSize-argSize+4, argRegister->getRegisterPair()->getLowOrder(), TR::InstOpCode::stw, pushToMemory[argIndex++], 4);1768numIntegerArgs++;1769}1770}1771numIntegerArgs++;1772}1773break;1774case TR::Float:1775argSize += TR::Compiler->om.sizeofReferenceAddress();1776argRegister = pushFloatArg(child);1777if (numFloatArgs < numFloatArgRegs)1778{1779if (!cg()->canClobberNodesRegister(child, 0))1780{1781tempRegister = cg()->allocateRegister(TR_FPR);1782generateTrg1Src1Instruction(cg(), TR::InstOpCode::fmr, callNode, tempRegister, argRegister);1783argRegister = tempRegister;1784}1785if (numFloatArgs == 0 && resType.isFloatingPoint())1786{1787TR::Register *resultReg;1788if (resType.getDataType() == TR::Float)1789resultReg = cg()->allocateSinglePrecisionRegister();1790else1791resultReg = cg()->allocateRegister(TR_FPR);1792dependencies->addPreCondition(argRegister, TR::RealRegister::fp0);1793dependencies->addPostCondition(resultReg, TR::RealRegister::fp0);1794}1795else1796TR::addDependency(dependencies, argRegister, properties.getFloatArgumentRegister(numFloatArgs), TR_FPR, cg());1797}1798else // numFloatArgs >= numFloatArgRegs1799{1800mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister, TR::InstOpCode::stfs, pushToMemory[argIndex++], 4);1801}1802numFloatArgs++;1803break;1804case TR::Double:1805argSize += 2*TR::Compiler->om.sizeofReferenceAddress();1806argRegister = pushDoubleArg(child);1807if (numFloatArgs < numFloatArgRegs)1808{1809if (!cg()->canClobberNodesRegister(child, 0))1810{1811tempRegister = cg()->allocateRegister(TR_FPR);1812generateTrg1Src1Instruction(cg(), TR::InstOpCode::fmr, callNode, tempRegister, argRegister);1813argRegister = tempRegister;1814}1815if (numFloatArgs == 0 && resType.isFloatingPoint())1816{1817TR::Register *resultReg;1818if (resType.getDataType() == TR::Float)1819resultReg = cg()->allocateSinglePrecisionRegister();1820else1821resultReg = cg()->allocateRegister(TR_FPR);1822dependencies->addPreCondition(argRegister, TR::RealRegister::fp0);1823dependencies->addPostCondition(resultReg, TR::RealRegister::fp0);1824}1825else1826TR::addDependency(dependencies, argRegister, properties.getFloatArgumentRegister(numFloatArgs), TR_FPR, cg());1827}1828else // numFloatArgs >= numFloatArgRegs1829{1830mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister, TR::InstOpCode::stfd, pushToMemory[argIndex++], 8);1831}1832numFloatArgs++;1833break;1834}1835}18361837if (!dependencies->searchPreConditionRegister(TR::RealRegister::gr11))1838TR::addDependency(dependencies, NULL, TR::RealRegister::gr11, TR_GPR, cg());1839if (!dependencies->searchPreConditionRegister(TR::RealRegister::gr12))1840TR::addDependency(dependencies, NULL, TR::RealRegister::gr12, TR_GPR, cg());18411842for (int32_t i = TR::RealRegister::FirstGPR; i <= TR::RealRegister::LastGPR; ++i)1843{1844TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)i;1845if (properties.getPreserved(realReg))1846continue;1847if (realReg == specialArgReg)1848continue; // already added deps above. No need to add them here.1849if (callSymbol->isComputed() && i == getProperties().getComputedCallTargetRegister())1850continue; // will be handled elsewhere1851if (!dependencies->searchPreConditionRegister(realReg))1852{1853if (realReg == properties.getIntegerArgumentRegister(0) && callNode->getDataType() == TR::Address)1854{1855dependencies->addPreCondition(cg()->allocateRegister(), TR::RealRegister::gr3);1856dependencies->addPostCondition(cg()->allocateCollectedReferenceRegister(), TR::RealRegister::gr3);1857}1858else1859{1860// Helper linkage preserves all registers that are not argument registers, so we don't need to spill them.1861if (linkage != TR_Helper)1862TR::addDependency(dependencies, NULL, realReg, TR_GPR, cg());1863}1864}1865}18661867TR_LiveRegisters *lr = cg()->getLiveRegisters(TR_FPR);1868bool liveFPR, liveVSX, liveVMX;18691870liveFPR = (!lr || lr->getNumberOfLiveRegisters() > 0);18711872lr = cg()->getLiveRegisters(TR_VSX_SCALAR);1873liveVSX = (!lr || lr->getNumberOfLiveRegisters() > 0);1874lr = cg()->getLiveRegisters(TR_VSX_VECTOR);1875liveVSX |= (!lr || lr->getNumberOfLiveRegisters() > 0);18761877lr = cg()->getLiveRegisters(TR_VRF);1878liveVMX = (!lr || lr->getNumberOfLiveRegisters() > 0);18791880if (liveVSX || liveFPR)1881{1882while (numFloatArgs < 8)1883{1884TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0+numFloatArgs), TR_FPR, cg());1885numFloatArgs++;1886}18871888int32_t theLastOne = liveVSX ? TR::RealRegister::LastVSR : TR::RealRegister::LastFPR;1889for (int32_t i = TR::RealRegister::fp8; i <= theLastOne; i++)1890if (!properties.getPreserved((TR::RealRegister::RegNum)i))1891{1892TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)i, (i>TR::RealRegister::LastFPR)?TR_VSX_SCALAR:TR_FPR, cg());1893}1894}1895else if (callNode->getType().isFloatingPoint())1896{1897//add return floating-point register dependency1898TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)getProperties().getFloatReturnRegister(), TR_FPR, cg());1899}19001901if (!liveVSX && liveVMX)1902{1903for (int32_t i = TR::RealRegister::vr0; i <= TR::RealRegister::vr31; i++)1904if (!properties.getPreserved((TR::RealRegister::RegNum)i))1905TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)i, TR_VSX_SCALAR, cg());1906}1907190819091910/*1911PPC ABI --1912AIX 32-bit BE & AIX 64-bit BE & Linux 64-bit BE:1913These follow aix-style linkage.1914There is a TOC-base register (gr2) that needs to be loaded from function descriptor of that function that is called.1915If the callee function is in libj9jitxx.so module, (as in the case of CHelper functions are) then the module's TOC-base can be found in the J9VMThread jitTOC field.1916The TOC can be loaded from the jitTOC field of J9VMThread (pointed to by metaDataRegister).19171918Linux 64-bit LE: There exists a TOC (gr2), but there is no such function descriptor.1919The TOC-base set-up is defined by ABI to go through a function's global-entry (relocation).1920The global-entry address will be set up in gr12.19211922Registers r12, and r2 are always added to the dependency in the situations that they're used.1923R12 is added at all times, and is an unreserved register across all platforms.1924R2 is added to the dependency only if we're not dealing with a linux 32 bit platform, where it's system reserved.1925Ultimately, we don't need an assert or NULL check when searching for these registers within the dependency.1926*/1927if(linkage == TR_CHelper)1928{1929if(comp()->target().isLinux() && comp()->target().is64Bit() && comp()->target().cpu.isLittleEndian())1930{1931if (!comp()->getOption(TR_DisableTOC))1932{1933int32_t helperOffset = (callNode->getSymbolReference()->getReferenceNumber() - 1)*sizeof(intptr_t);1934generateTrg1MemInstruction(cg(), TR::InstOpCode::Op_load, callNode, dependencies->searchPreConditionRegister(TR::RealRegister::gr12),1935TR::MemoryReference::createWithDisplacement(cg(), cg()->getTOCBaseRegister(), helperOffset, TR::Compiler->om.sizeofReferenceAddress()));1936}1937else1938{1939loadAddressConstant(cg(), callNode, (int64_t)runtimeHelperValue((TR_RuntimeHelper)callNode->getSymbolReference()->getReferenceNumber()),1940dependencies->searchPreConditionRegister(TR::RealRegister::gr12), NULL, false, TR_AbsoluteHelperAddress);1941}19421943}1944else if (comp()->target().isAIX() || (comp()->target().isLinux() && comp()->target().is64Bit()))1945{1946generateTrg1MemInstruction(cg(), TR::InstOpCode::Op_load, callNode, dependencies->searchPreConditionRegister(TR::RealRegister::gr2),1947TR::MemoryReference::createWithDisplacement(cg(), cg()->getMethodMetaDataRegister(), offsetof(J9VMThread, jitTOC), TR::Compiler->om.sizeofReferenceAddress()));1948}1949}195019511952// This is a performance hack. CCRs are rarely live across calls,1953// particularly helper calls, but because we create scratch virtual1954// regs and re-use them during evaluation they appear live.1955// This is often made worse by OOL code, the SRM, internal control flow.1956// The cost of saving/restoring CCRs in particular is very high and1957// fixing this problem is otherwise is not easy, hence this hack.1958// If you need to disable this hack, use this env var.1959static bool forcePreserveCCRs = feGetEnv("TR_ppcForcePreserveCCRsOnCalls") != NULL;1960if (linkage == TR_Private || forcePreserveCCRs)1961{1962lr = cg()->getLiveRegisters(TR_CCR);1963if(!lr || lr->getNumberOfLiveRegisters() > 0 )1964{1965for (int32_t i = TR::RealRegister::FirstCCR; i <= TR::RealRegister::LastCCR; i++)1966if (!properties.getPreserved((TR::RealRegister::RegNum)i))1967{1968TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)i, TR_CCR, cg());1969}1970}1971else1972{1973//add the FirstCCR if there is no live CCR available,1974//because on buildVirtualDispatch(), it gets the CCR dependency from search1975if (!properties.getPreserved(TR::RealRegister::FirstCCR))1976{1977TR::addDependency(dependencies, NULL, TR::RealRegister::FirstCCR, TR_CCR, cg());1978}1979}1980}1981else if (comp()->getOption(TR_TraceCG))1982traceMsg(comp(), "Omitting CCR save/restore for helper calls\n");19831984if (memArgs > 0)1985{1986for (argIndex = 0; argIndex < memArgs; argIndex++)1987{1988TR::Register *aReg = pushToMemory[argIndex].argRegister;1989generateMemSrc1Instruction(cg(), pushToMemory[argIndex].opCode, callNode, pushToMemory[argIndex].argMemory, aReg);1990cg()->stopUsingRegister(aReg);1991}1992}19931994return totalSize;1995}19961997static bool getProfiledCallSiteInfo(TR::CodeGenerator *cg, TR::Node *callNode, uint32_t maxStaticPICs, TR_ScratchList<J9::PPCPICItem> &values)1998{1999TR::Compilation *comp = cg->comp();2000TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());2001if (comp->compileRelocatableCode())2002return false;20032004TR::SymbolReference *methodSymRef = callNode->getSymbolReference();2005TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();20062007if (!methodSymbol->isVirtual() && !methodSymbol->isInterface())2008return false;20092010TR_AddressInfo *info = static_cast<TR_AddressInfo*>(TR_ValueProfileInfoManager::getProfiledValueInfo(callNode, comp, AddressInfo));2011if (!info)2012return false;20132014uint32_t totalFreq = info->getTotalFrequency();2015if (totalFreq == 0 || info->getTopProbability() < MIN_PROFILED_CALL_FREQUENCY)2016return false;20172018TR_ScratchList<TR_ExtraAddressInfo> allValues(comp->trMemory());2019info->getSortedList(comp, &allValues);20202021TR_ResolvedMethod *owningMethod = methodSymRef->getOwningMethod(comp);2022TR_OpaqueClassBlock *callSiteMethodClass;20232024if (methodSymbol->isVirtual())2025callSiteMethodClass = methodSymRef->getSymbol()->getResolvedMethodSymbol()->getResolvedMethod()->classOfMethod();20262027ListIterator<TR_ExtraAddressInfo> valuesIt(&allValues);20282029uint32_t numStaticPics = 0;2030TR_ExtraAddressInfo *profiledInfo;2031for (profiledInfo = valuesIt.getFirst(); numStaticPics < maxStaticPICs && profiledInfo != NULL; profiledInfo = valuesIt.getNext())2032{2033float freq = (float)profiledInfo->_frequency / totalFreq;2034if (freq < MIN_PROFILED_CALL_FREQUENCY)2035break;20362037TR_OpaqueClassBlock *clazz = (TR_OpaqueClassBlock *)profiledInfo->_value;2038if (comp->getPersistentInfo()->isObsoleteClass(clazz, fej9))2039continue;20402041TR_ResolvedMethod *method;20422043if (methodSymbol->isVirtual())2044{2045TR_ASSERT(callSiteMethodClass, "Expecting valid callSiteMethodClass for virtual call");2046if (!cg->isProfiledClassAndCallSiteCompatible(clazz, callSiteMethodClass))2047continue;20482049method = owningMethod->getResolvedVirtualMethod(comp, clazz, methodSymRef->getOffset());2050}2051else2052{2053TR_ASSERT(methodSymbol->isInterface(), "Expecting virtual or interface method");2054method = owningMethod->getResolvedInterfaceMethod(comp, clazz, methodSymRef->getCPIndex());2055}20562057if (!method || method->isInterpreted())2058continue;20592060values.add(new (comp->trStackMemory()) J9::PPCPICItem(clazz, method, freq));2061++numStaticPics;2062}20632064return numStaticPics > 0;2065}20662067static TR::Instruction* buildStaticPICCall(TR::CodeGenerator *cg, TR::Node *callNode, uintptr_t profiledClass, TR_ResolvedMethod *profiledMethod,2068TR::Register *vftReg, TR::Register *tempReg, TR::Register *condReg, TR::LabelSymbol *missLabel,2069uint32_t regMapForGC)2070{2071TR::Compilation *comp = cg->comp();2072TR::SymbolReference *methodSymRef = callNode->getSymbolReference();2073TR::SymbolReference *profiledMethodSymRef = comp->getSymRefTab()->findOrCreateMethodSymbol(methodSymRef->getOwningMethodIndex(),2074-1,2075profiledMethod,2076TR::MethodSymbol::Virtual);20772078TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());2079loadAddressConstant(cg, comp->compileRelocatableCode(), callNode, profiledClass, tempReg, NULL, fej9->isUnloadAssumptionRequired((TR_OpaqueClassBlock *)profiledClass, comp->getCurrentMethod()));2080generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, callNode, condReg, vftReg, tempReg);2081generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, callNode, missLabel, condReg);2082TR::Instruction *gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, callNode, (uintptr_t)profiledMethod->startAddressForJittedMethod(),2083new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0,0, cg->trMemory()), profiledMethodSymRef);2084gcPoint->PPCNeedsGCMap(regMapForGC);2085fej9->reserveTrampolineIfNecessary(comp, profiledMethodSymRef, false);2086return gcPoint;2087}20882089static void buildVirtualCall(TR::CodeGenerator *cg, TR::Node *callNode, TR::Register *vftReg, TR::Register *gr12, uint32_t regMapForGC)2090{2091int32_t offset = callNode->getSymbolReference()->getOffset();2092TR::Compilation* comp = cg->comp();20932094// jitrt.dev/ppc/Recompilation.s is dependent on the code sequence2095// generated from here to the bctrl below!!2096// DO NOT MODIFY without also changing Recompilation.s!!2097if (offset < LOWER_IMMED || offset > UPPER_IMMED)2098{2099TR_ASSERT_FATAL_WITH_NODE(callNode, 0x00008000 != HI_VALUE(offset), "offset (0x%x) is unexpectedly high. Can not encode upper 16 bits into an addis instruction.", offset);2100generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, callNode, gr12, vftReg, HI_VALUE(offset));2101generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12, TR::MemoryReference::createWithDisplacement(cg, gr12, LO_VALUE(offset), TR::Compiler->om.sizeofReferenceAddress()));2102}2103else2104{2105generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12, TR::MemoryReference::createWithDisplacement(cg, vftReg, offset, TR::Compiler->om.sizeofReferenceAddress()));2106}21072108generateSrc1Instruction(cg, TR::InstOpCode::mtctr, callNode, gr12);2109TR::Instruction *gcPoint = generateInstruction(cg, TR::InstOpCode::bctrl, callNode);2110gcPoint->PPCNeedsGCMap(regMapForGC);2111}21122113static void buildInterfaceCall(TR::CodeGenerator *cg, TR::Node *callNode, TR::Register *vftReg, TR::Register *gr0, TR::Register *gr11, TR::Register *gr12, TR::Register *cr0, TR::PPCInterfaceCallSnippet *ifcSnippet, uint32_t regMapForGC)2114{2115TR::Compilation *comp = cg->comp();2116TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());21172118// jitrt.dev/ppc/Recompilation.s is dependent on the code sequence2119// generated from here to the bctrl below!!2120// DO NOT MODIFY without also changing Recompilation.s!!2121if (comp->target().is64Bit())2122{2123if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))2124{2125// Expecting the 64bit IPIC snippet shape2126generateTrg1MemInstruction(cg, TR::InstOpCode::paddi, callNode, gr12, TR::MemoryReference::createWithLabel(cg, ifcSnippet->getSnippetLabel(), 12+4*TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()));2127generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr11, TR::MemoryReference::createWithDisplacement(cg, gr12, 0, TR::Compiler->om.sizeofReferenceAddress()));2128}2129else2130{2131int32_t beginIndex = TR_PPCTableOfConstants::allocateChunk(1, cg);21322133if (beginIndex != PTOC_FULL_INDEX)2134{2135beginIndex *= TR::Compiler->om.sizeofReferenceAddress();2136if (beginIndex < LOWER_IMMED || beginIndex > UPPER_IMMED)2137{2138TR_ASSERT_FATAL_WITH_NODE(callNode, 0x00008000 != HI_VALUE(beginIndex), "TOC offset (0x%x) is unexpectedly high. Can not encode upper 16 bits into an addis instruction.", beginIndex);2139generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, callNode, gr12, cg->getTOCBaseRegister(), HI_VALUE(beginIndex));2140generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12, TR::MemoryReference::createWithDisplacement(cg, gr12, LO_VALUE(beginIndex), TR::Compiler->om.sizeofReferenceAddress()));2141}2142else2143{2144generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12, TR::MemoryReference::createWithDisplacement(cg, cg->getTOCBaseRegister(), beginIndex, TR::Compiler->om.sizeofReferenceAddress()));2145}2146generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr11, TR::MemoryReference::createWithDisplacement(cg, gr12, 0, TR::Compiler->om.sizeofReferenceAddress()));2147}2148else2149{2150TR::Instruction *q[4];2151fixedSeqMemAccess(cg, callNode, 0, q, gr11, gr12,TR::InstOpCode::Op_loadu, TR::Compiler->om.sizeofReferenceAddress(), NULL, gr11);2152ifcSnippet->setLowerInstruction(q[3]);2153ifcSnippet->setUpperInstruction(q[0]);2154}2155ifcSnippet->setTOCOffset(beginIndex);2156}2157}2158else2159{2160ifcSnippet->setUpperInstruction(generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, callNode, gr12, 0));2161ifcSnippet->setLowerInstruction(generateTrg1MemInstruction(cg, TR::InstOpCode::lwzu, callNode, gr11, TR::MemoryReference::createWithDisplacement(cg, gr12, 0, 4)));2162}2163TR::LabelSymbol *hitLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);2164TR::LabelSymbol *snippetLabel = ifcSnippet->getSnippetLabel();2165generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, callNode, cr0, vftReg, gr11);2166generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, callNode, hitLabel, cr0);21672168generateTrg1MemInstruction(cg,TR::InstOpCode::Op_loadu, callNode, gr11, TR::MemoryReference::createWithDisplacement(cg, gr12, 2 * TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()));2169generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, callNode, cr0, vftReg, gr11);21702171#ifdef INLINE_LASTITABLE_CHECK2172// Doing this check inline doesn't perform too well because it prevents the PIC cache slots from being populated with the best candidates.2173// This check is done in the _interfaceSlotsUnavailable helper instead.2174TR::LabelSymbol *callLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);2175TR_SymbolReference *methodSymRef = callNode->getSymbolReference();2176TR_ResolvedMethod *owningMethod = methodSymRef->getOwningMethod(comp);2177TR_OpaqueClassBlock *interfaceClassOfMethod;2178uintptr_t itableIndex;21792180interfaceClassOfMethod = owningMethod->getResolvedInterfaceMethod(methodSymRef->getCPIndex(), &itableIndex);21812182TR_ASSERT(fej9->getITableEntryJitVTableOffset() <= UPPER_IMMED &&2183fej9->getITableEntryJitVTableOffset() >= LOWER_IMMED, "ITable offset for JIT is too large, prevents lastITable dispatch from being generated");21842185if (!comp->getOption(TR_DisableLastITableCache) && interfaceClassOfMethod &&2186// Only do this if this offset can be loaded in a single instruction because this code may need to be2187// patched at runtime and we don't want to deal with too many variations2188fej9->getITableEntryJitVTableOffset() <= UPPER_IMMED &&2189fej9->getITableEntryJitVTableOffset() >= LOWER_IMMED)2190{2191generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, callNode, hitLabel, cr0);21922193// Check if the lastITable belongs to the interface class we're using at this call site2194//2195generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr11,2196TR::MemoryReference::createWithDisplacement(cg, vftReg, fej9->getOffsetOfLastITableFromClassField(), TR::Compiler->om.sizeofReferenceAddress()));2197// Load the interface class from the snippet rather than materializing it, again because we want to do this in a single instruction2198generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12,2199TR::MemoryReference::createWithDisplacement(cg, gr12, -4 * TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()));2200generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr0,2201TR::MemoryReference::createWithDisplacement(cg, gr11, fej9->getOffsetOfInterfaceClassFromITableField(), TR::Compiler->om.sizeofReferenceAddress()));2202generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, callNode, cr0, gr0, gr12);2203generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, callNode, snippetLabel, cr0);22042205// lastITable belongs to the interface class we're using at this call site2206// Use it to look up the VFT offset and use that to make a virtual call2207//2208generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12,2209TR::MemoryReference::createWithDisplacement(cg, gr11, fej9->convertITableIndexToOffset(itableIndex), TR::Compiler->om.sizeofReferenceAddress()));2210loadConstant(cg, callNode, fej9->getITableEntryJitVTableOffset(), gr11);2211generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, callNode, gr12, gr12, gr11);2212generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr11,2213TR::MemoryReference::createWithIndexReg(cg, vftReg, gr12, TR::Compiler->om.sizeofReferenceAddress()));2214generateLabelInstruction(cg, TR::InstOpCode::b, callNode, callLabel);2215}2216else2217#endif /* INLINE_LASTITABLE_CHECK */2218{2219generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, callNode, snippetLabel, cr0);2220}2221generateLabelInstruction(cg, TR::InstOpCode::label, callNode, hitLabel);2222generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr11, TR::MemoryReference::createWithDisplacement(cg, gr12, TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()));2223#ifdef INLINE_LASTITABLE_CHECK2224generateLabelInstruction(cg, TR::InstOpCode::label, callNode, callLabel);2225#endif /* INLINE_LASTITABLE_CHECK */2226generateSrc1Instruction(cg, TR::InstOpCode::mtctr, callNode, gr11);2227TR::Instruction *gcPoint = generateInstruction(cg, TR::InstOpCode::bctrl, callNode);2228gcPoint->PPCNeedsGCMap(regMapForGC);2229ifcSnippet->gcMap().setGCRegisterMask(regMapForGC);2230}22312232static TR::Register* evaluateUpToVftChild(TR::Node *callNode, TR::CodeGenerator *cg)2233{2234TR::Register *vftReg;2235uint32_t firstArgumentChild = callNode->getFirstArgumentIndex();2236for (uint32_t i = 0; i < firstArgumentChild; i++)2237{2238TR::Node *child = callNode->getChild(i);2239vftReg = cg->evaluate(child);2240cg->decReferenceCount(child);2241}2242return vftReg;2243}22442245void J9::Power::PrivateLinkage::buildVirtualDispatch(TR::Node *callNode,2246TR::RegisterDependencyConditions *dependencies,2247uint32_t sizeOfArguments)2248{2249TR::Register *cr0 = dependencies->searchPreConditionRegister(TR::RealRegister::cr0);2250TR::Register *gr0 = dependencies->searchPreConditionRegister(TR::RealRegister::gr0);2251TR::Register *gr11 = dependencies->searchPreConditionRegister(TR::RealRegister::gr11);2252TR::Register *gr12 = dependencies->searchPreConditionRegister(TR::RealRegister::gr12);2253TR::SymbolReference *methodSymRef = callNode->getSymbolReference();2254TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();2255TR::LabelSymbol *doneLabel = generateLabelSymbol(cg());2256uint32_t regMapForGC = getProperties().getPreservedRegisterMapForGC();2257void *thunk = NULL;22582259TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());22602261// Computed calls2262//2263if (methodSymbol->isComputed())2264{2265TR::Register *vftReg = evaluateUpToVftChild(callNode, cg());2266// On 32-bit, we can just ignore the top 32 bits of the 64-bit target address2267if (vftReg->getRegisterPair())2268vftReg = vftReg->getLowOrder();2269TR::addDependency(dependencies, vftReg, getProperties().getComputedCallTargetRegister(), TR_GPR, cg());22702271switch (methodSymbol->getMandatoryRecognizedMethod())2272{2273case TR::java_lang_invoke_ComputedCalls_dispatchVirtual:2274case TR::com_ibm_jit_JITHelpers_dispatchVirtual:2275{2276// Need a j2i thunk for the method that will ultimately be dispatched by this handle call2277char *j2iSignature = fej9->getJ2IThunkSignatureForDispatchVirtual(methodSymbol->getMethod()->signatureChars(), methodSymbol->getMethod()->signatureLength(), comp());2278int32_t signatureLen = strlen(j2iSignature);2279thunk = fej9->getJ2IThunk(j2iSignature, signatureLen, comp());2280if (!thunk)2281{2282thunk = fej9->setJ2IThunk(j2iSignature, signatureLen,2283TR::PPCCallSnippet::generateVIThunk(fej9->getEquivalentVirtualCallNodeForDispatchVirtual(callNode, comp()), sizeOfArguments, cg()), comp());2284}2285}2286default:2287if (fej9->needsInvokeExactJ2IThunk(callNode, comp()))2288{2289TR_J2IThunk *thunk = TR::PPCCallSnippet::generateInvokeExactJ2IThunk(callNode, sizeOfArguments, cg(), methodSymbol->getMethod()->signatureChars());2290fej9->setInvokeExactJ2IThunk(thunk, comp());2291}2292break;2293}22942295TR::Register *targetAddress = vftReg;2296generateSrc1Instruction(cg(), TR::InstOpCode::mtctr, callNode, targetAddress);2297TR::Instruction *gcPoint = generateInstruction(cg(), TR::InstOpCode::bctrl, callNode);2298generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies);22992300gcPoint->PPCNeedsGCMap(regMapForGC);2301return;2302}23032304// Virtual and interface calls2305//2306TR_ASSERT(methodSymbol->isVirtual() || methodSymbol->isInterface(), "Unexpected method type");23072308thunk = fej9->getJ2IThunk(methodSymbol->getMethod(), comp());2309if (!thunk)2310thunk = fej9->setJ2IThunk(methodSymbol->getMethod(), TR::PPCCallSnippet::generateVIThunk(callNode, sizeOfArguments, cg()), comp());23112312bool callIsSafe = methodSymRef != comp()->getSymRefTab()->findObjectNewInstanceImplSymbol();23132314if (methodSymbol->isVirtual())2315{2316// Handle unresolved/AOT virtual calls first2317//2318if (methodSymRef->isUnresolved() || comp()->compileRelocatableCode())2319{2320TR::Register *vftReg = evaluateUpToVftChild(callNode, cg());2321TR::addDependency(dependencies, vftReg, TR::RealRegister::NoReg, TR_GPR, cg());23222323TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg());2324TR::Snippet *snippet = new (trHeapMemory()) TR::PPCVirtualUnresolvedSnippet(cg(), callNode, snippetLabel, sizeOfArguments, doneLabel);2325cg()->addSnippet(snippet);23262327generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, gr12, vftReg);23282329// These two instructions will be ultimately modified to load the2330// method pointer. The branch should be a no-op if the offset turns2331// out to be within range (for most cases).2332generateLabelInstruction(cg(), TR::InstOpCode::b, callNode, snippetLabel);2333generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, callNode, gr12, TR::MemoryReference::createWithDisplacement(cg(), gr12, 0, TR::Compiler->om.sizeofReferenceAddress()));23342335generateSrc1Instruction(cg(), TR::InstOpCode::mtctr, callNode, gr12);2336TR::Instruction *gcPoint = generateInstruction(cg(), TR::InstOpCode::bctrl, callNode);2337generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies);23382339gcPoint->PPCNeedsGCMap(regMapForGC);2340snippet->gcMap().setGCRegisterMask(regMapForGC);2341return;2342}23432344// Handle guarded devirtualization next2345//2346if (callIsSafe)2347{2348TR::ResolvedMethodSymbol *resolvedMethodSymbol = methodSymRef->getSymbol()->getResolvedMethodSymbol();2349TR_ResolvedMethod *resolvedMethod = resolvedMethodSymbol->getResolvedMethod();23502351if (comp()->performVirtualGuardNOPing() &&2352comp()->isVirtualGuardNOPingRequired() &&2353!resolvedMethod->isInterpreted() &&2354!callNode->isTheVirtualCallNodeForAGuardedInlinedCall())2355{2356TR_VirtualGuard *virtualGuard = NULL;23572358if (!resolvedMethod->virtualMethodIsOverridden() &&2359!resolvedMethod->isAbstract())2360{2361virtualGuard = TR_VirtualGuard::createGuardedDevirtualizationGuard(TR_NonoverriddenGuard, comp(), callNode);2362}2363else2364{2365TR_DevirtualizedCallInfo *devirtualizedCallInfo = comp()->findDevirtualizedCall(callNode);2366TR_OpaqueClassBlock *refinedThisClass = devirtualizedCallInfo ? devirtualizedCallInfo->_thisType : NULL;2367TR_OpaqueClassBlock *thisClass = refinedThisClass ? refinedThisClass : resolvedMethod->containingClass();23682369TR_PersistentCHTable *chTable = comp()->getPersistentInfo()->getPersistentCHTable();2370/* Devirtualization is not currently supported for AOT compilations */2371if (thisClass && TR::Compiler->cls.isAbstractClass(comp(), thisClass) && !comp()->compileRelocatableCode())2372{2373TR_ResolvedMethod *calleeMethod = chTable->findSingleAbstractImplementer(thisClass, methodSymRef->getOffset(), methodSymRef->getOwningMethod(comp()), comp());2374if (calleeMethod &&2375(comp()->isRecursiveMethodTarget(calleeMethod) ||2376!calleeMethod->isInterpreted() ||2377calleeMethod->isJITInternalNative()))2378{2379resolvedMethod = calleeMethod;2380virtualGuard = TR_VirtualGuard::createGuardedDevirtualizationGuard(TR_AbstractGuard, comp(), callNode);2381}2382}2383else if (refinedThisClass &&2384resolvedMethod->virtualMethodIsOverridden() &&2385!chTable->isOverriddenInThisHierarchy(resolvedMethod, refinedThisClass, methodSymRef->getOffset(), comp()))2386{2387TR_ResolvedMethod *calleeMethod = methodSymRef->getOwningMethod(comp())->getResolvedVirtualMethod(comp(), refinedThisClass, methodSymRef->getOffset());2388if (calleeMethod &&2389(comp()->isRecursiveMethodTarget(calleeMethod) ||2390!calleeMethod->isInterpreted() ||2391calleeMethod->isJITInternalNative()))2392{2393resolvedMethod = calleeMethod;2394virtualGuard = TR_VirtualGuard::createGuardedDevirtualizationGuard(TR_HierarchyGuard, comp(), callNode);2395}2396}2397}23982399// If we have a virtual call guard generate a direct call2400// in the inline path and the virtual call out of line.2401// If the guard is later patched we'll go out of line path.2402//2403if (virtualGuard)2404{2405TR::Node *vftNode = callNode->getFirstChild();2406TR::Register *vftReg = NULL;24072408// We prefer to evaluate the VFT child in the out of line path if possible, but if we can't do it then, do it now instead2409if (vftNode->getReferenceCount() > 1 || vftNode->getRegister())2410{2411vftReg = evaluateUpToVftChild(callNode, cg());2412TR::addDependency(dependencies, vftReg, TR::RealRegister::NoReg, TR_GPR, cg());2413}2414else2415{2416// If we push evaluation of the VFT node off to the outlined code section we have to make sure that any of it's children2417// that are needed later are still evaluated. We could, in theory skip evaluating children with refcount == 1 for the same2418// reason as above, but would have to then look at the child's children, and so on, so just evaluate the VFT's children here and now.2419for (uint32_t i = 0; i < vftNode->getNumChildren(); i++)2420cg()->evaluate(vftNode->getChild(i));2421}24222423TR::LabelSymbol *virtualCallLabel = generateLabelSymbol(cg());2424generateVirtualGuardNOPInstruction(cg(), callNode, virtualGuard->addNOPSite(), new (trHeapMemory()) TR::RegisterDependencyConditions(0, 0, trMemory()), virtualCallLabel);2425if (comp()->getOption(TR_EnableHCR))2426{2427TR_VirtualGuard *HCRGuard = TR_VirtualGuard::createGuardedDevirtualizationGuard(TR_HCRGuard, comp(), callNode);2428generateVirtualGuardNOPInstruction(cg(), callNode, HCRGuard->addNOPSite(), new (trHeapMemory()) TR::RegisterDependencyConditions(0, 0, trMemory()), virtualCallLabel);2429}2430if (resolvedMethod != resolvedMethodSymbol->getResolvedMethod())2431{2432methodSymRef = comp()->getSymRefTab()->findOrCreateMethodSymbol(methodSymRef->getOwningMethodIndex(),2433-1,2434resolvedMethod,2435TR::MethodSymbol::Virtual);2436methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();2437resolvedMethodSymbol = methodSymbol->getResolvedMethodSymbol();2438resolvedMethod = resolvedMethodSymbol->getResolvedMethod();2439}2440uintptr_t methodAddress = comp()->isRecursiveMethodTarget(resolvedMethod) ? 0 : (uintptr_t)resolvedMethod->startAddressForJittedMethod();2441TR::Instruction *gcPoint = generateDepImmSymInstruction(cg(), TR::InstOpCode::bl, callNode, methodAddress,2442new (trHeapMemory()) TR::RegisterDependencyConditions(0, 0, trMemory()), methodSymRef);2443generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies);2444gcPoint->PPCNeedsGCMap(regMapForGC);2445fej9->reserveTrampolineIfNecessary(comp(), methodSymRef, false);24462447// Out of line virtual call2448//2449TR_PPCOutOfLineCodeSection *virtualCallOOL = new (trHeapMemory()) TR_PPCOutOfLineCodeSection(virtualCallLabel, doneLabel, cg());24502451virtualCallOOL->swapInstructionListsWithCompilation();2452TR::Instruction *OOLLabelInstr = generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, virtualCallLabel);24532454// XXX: Temporary fix, OOL instruction stream does not pick up live locals or monitors correctly.2455TR_ASSERT(!OOLLabelInstr->getLiveLocals() && !OOLLabelInstr->getLiveMonitors(), "Expecting first OOL instruction to not have live locals/monitors info");2456OOLLabelInstr->setLiveLocals(gcPoint->getLiveLocals());2457OOLLabelInstr->setLiveMonitors(gcPoint->getLiveMonitors());24582459TR::RegisterDependencyConditions *outlinedCallDeps;2460if (!vftReg)2461{2462vftReg = evaluateUpToVftChild(callNode, cg());2463outlinedCallDeps = new (trHeapMemory()) TR::RegisterDependencyConditions(1, 1, trMemory());2464// Normally we don't care which reg the VFT gets, but in this case we don't want to undo the assignments done by the main deps so we choose a reg that we know will not be needed2465TR::addDependency(outlinedCallDeps, vftReg, TR::RealRegister::gr11, TR_GPR, cg());2466}2467else2468outlinedCallDeps = new (trHeapMemory()) TR::RegisterDependencyConditions(0, 0, trMemory());246924702471buildVirtualCall(cg(), callNode, vftReg, gr12, regMapForGC);24722473TR::LabelSymbol *doneOOLLabel = generateLabelSymbol(cg());2474generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneOOLLabel, outlinedCallDeps);2475generateLabelInstruction(cg(), TR::InstOpCode::b, callNode, doneLabel);2476virtualCallOOL->swapInstructionListsWithCompilation();2477cg()->getPPCOutOfLineCodeSectionList().push_front(virtualCallOOL);24782479return;2480}2481}2482}2483}24842485// Profile-driven virtual and interface calls2486//2487// If the top value dominates everything else, generate a single static2488// PIC call inline and a virtual call or dynamic PIC call out of line.2489//2490// Otherwise generate a reasonable amount of static PIC calls and a2491// virtual call or dynamic PIC call all inline.2492//2493TR::Register *vftReg = evaluateUpToVftChild(callNode, cg());2494TR::addDependency(dependencies, vftReg, TR::RealRegister::NoReg, TR_GPR, cg());24952496if (callIsSafe && !callNode->isTheVirtualCallNodeForAGuardedInlinedCall() && !comp()->getOption(TR_DisableInterpreterProfiling))2497{2498static char *maxVirtualStaticPICsString = feGetEnv("TR_ppcMaxVirtualStaticPICs");2499static uint32_t maxVirtualStaticPICs = maxVirtualStaticPICsString ? atoi(maxVirtualStaticPICsString) : 1;2500static char *maxInterfaceStaticPICsString = feGetEnv("TR_ppcMaxInterfaceStaticPICs");2501static uint32_t maxInterfaceStaticPICs = maxInterfaceStaticPICsString ? atoi(maxInterfaceStaticPICsString) : 1;25022503TR_ScratchList<J9::PPCPICItem> values(cg()->trMemory());2504const uint32_t maxStaticPICs = methodSymbol->isInterface() ? maxInterfaceStaticPICs : maxVirtualStaticPICs;25052506if (getProfiledCallSiteInfo(cg(), callNode, maxStaticPICs, values))2507{2508ListIterator<J9::PPCPICItem> i(&values);2509J9::PPCPICItem *pic = i.getFirst();25102511// If this value is dominant, optimize exclusively for it2512if (pic->_frequency > MAX_PROFILED_CALL_FREQUENCY)2513{2514TR::LabelSymbol *slowCallLabel = generateLabelSymbol(cg());25152516TR::Instruction *gcPoint = buildStaticPICCall(cg(), callNode, (uintptr_t)pic->_clazz, pic->_method,2517vftReg, gr11, cr0, slowCallLabel, regMapForGC);2518generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies);25192520// Out of line virtual/interface call2521//2522TR_PPCOutOfLineCodeSection *slowCallOOL = new (trHeapMemory()) TR_PPCOutOfLineCodeSection(slowCallLabel, doneLabel, cg());25232524slowCallOOL->swapInstructionListsWithCompilation();2525TR::Instruction *OOLLabelInstr = generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, slowCallLabel);25262527// XXX: Temporary fix, OOL instruction stream does not pick up live locals or monitors correctly.2528TR_ASSERT(!OOLLabelInstr->getLiveLocals() && !OOLLabelInstr->getLiveMonitors(), "Expecting first OOL instruction to not have live locals/monitors info");2529OOLLabelInstr->setLiveLocals(gcPoint->getLiveLocals());2530OOLLabelInstr->setLiveMonitors(gcPoint->getLiveMonitors());25312532TR::LabelSymbol *doneOOLLabel = generateLabelSymbol(cg());25332534if (methodSymbol->isInterface())2535{2536TR::LabelSymbol *ifcSnippetLabel = generateLabelSymbol(cg());2537TR::PPCInterfaceCallSnippet *ifcSnippet = new (trHeapMemory()) TR::PPCInterfaceCallSnippet(cg(), callNode, ifcSnippetLabel, sizeOfArguments, doneOOLLabel, (uint8_t *)thunk);25382539cg()->addSnippet(ifcSnippet);2540buildInterfaceCall(cg(), callNode, vftReg, gr0, gr11, gr12, cr0, ifcSnippet, regMapForGC);2541}2542else2543{2544buildVirtualCall(cg(), callNode, vftReg, gr12, regMapForGC);2545}25462547generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneOOLLabel, new (trHeapMemory()) TR::RegisterDependencyConditions(0, 0, trMemory()));2548generateLabelInstruction(cg(), TR::InstOpCode::b, callNode, doneLabel);2549slowCallOOL->swapInstructionListsWithCompilation();2550cg()->getPPCOutOfLineCodeSectionList().push_front(slowCallOOL);25512552return;2553}2554else2555{2556// Build multiple static PIC calls2557while (pic)2558{2559TR::LabelSymbol *nextLabel = generateLabelSymbol(cg());25602561buildStaticPICCall(cg(), callNode, (uintptr_t)pic->_clazz, pic->_method,2562vftReg, gr11, cr0, nextLabel, regMapForGC);2563generateLabelInstruction(cg(), TR::InstOpCode::b, callNode, doneLabel);2564generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, nextLabel);2565pic = i.getNext();2566}2567// Regular virtual/interface call will be built below2568}2569}2570}25712572// Finally, regular virtual and interface calls2573//2574if (methodSymbol->isInterface())2575{2576TR::LabelSymbol *ifcSnippetLabel = generateLabelSymbol(cg());2577TR::PPCInterfaceCallSnippet *ifcSnippet = new (trHeapMemory()) TR::PPCInterfaceCallSnippet(cg(), callNode, ifcSnippetLabel, sizeOfArguments, doneLabel, (uint8_t *)thunk);25782579cg()->addSnippet(ifcSnippet);2580buildInterfaceCall(cg(), callNode, vftReg, gr0, gr11, gr12, cr0, ifcSnippet, regMapForGC);2581}2582else2583{2584buildVirtualCall(cg(), callNode, vftReg, gr12, regMapForGC);2585}2586generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies);2587}25882589void inlineCharacterIsMethod(TR::Node *node, TR::MethodSymbol* methodSymbol, TR::CodeGenerator *cg, TR::LabelSymbol *&doneLabel)2590{2591TR::Compilation *comp = cg->comp();25922593TR::LabelSymbol *inRangeLabel = generateLabelSymbol(cg);2594TR::Register *cnd0Reg = cg->allocateRegister(TR_CCR);2595TR::Register *cnd1Reg = cg->allocateRegister(TR_CCR);2596TR::Register *cnd2Reg = cg->allocateRegister(TR_CCR);2597TR::Register *srcReg = cg->evaluate(node->getFirstChild());2598TR::Register *rangeReg = cg->allocateRegister(TR_GPR);2599TR::Register *returnRegister = cg->allocateRegister(TR_GPR);2600TR::Register *tmpReg = cg->allocateRegister(TR_GPR);26012602TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(6, 6, cg->trMemory());2603TR::addDependency(dependencies, srcReg, TR::RealRegister::NoReg, TR_GPR, cg);2604TR::addDependency(dependencies, rangeReg, TR::RealRegister::NoReg, TR_GPR, cg);2605TR::addDependency(dependencies, returnRegister, TR::RealRegister::gr3, TR_GPR, cg);2606TR::addDependency(dependencies, cnd0Reg, TR::RealRegister::cr0, TR_CCR, cg);2607TR::addDependency(dependencies, cnd1Reg, TR::RealRegister::NoReg, TR_CCR, cg);2608TR::addDependency(dependencies, cnd2Reg, TR::RealRegister::NoReg, TR_CCR, cg);26092610int32_t imm = (TR::RealRegister::CRCC_GT << TR::RealRegister::pos_RT | TR::RealRegister::CRCC_GT << TR::RealRegister::pos_RA | TR::RealRegister::CRCC_GT << TR::RealRegister::pos_RB);26112612int64_t mask = 0xFFFF00;2613if (methodSymbol->getRecognizedMethod() == TR::java_lang_Character_isLetter ||2614methodSymbol->getRecognizedMethod() == TR::java_lang_Character_isAlphabetic )2615{2616mask = 0xFFFF80; // mask for ASCII2617}2618generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm_r, node, tmpReg, srcReg, 0, mask); // set cnd0Reg(cr0)26192620switch(methodSymbol->getRecognizedMethod())2621{2622case TR::java_lang_Character_isDigit:2623generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, rangeReg, 0x3930);2624generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd1Reg, srcReg, rangeReg, 0);2625break;2626case TR::java_lang_Character_isAlphabetic:2627case TR::java_lang_Character_isLetter:2628//ASCII only2629generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, rangeReg, 0x7A61);2630generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, rangeReg, rangeReg, 0x5A41);2631generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd1Reg, srcReg, rangeReg, 1);2632break;2633case TR::java_lang_Character_isWhitespace:2634generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, rangeReg, 0x0D09);2635generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, rangeReg, rangeReg, 0x201C);2636generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd1Reg, srcReg, rangeReg, 1);2637break;2638case TR::java_lang_Character_isUpperCase:2639generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, rangeReg, 0x5A41);2640generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, rangeReg, rangeReg, 0xD6C0);2641generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd1Reg, srcReg, rangeReg, 1);2642generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, rangeReg, (int16_t)0xDED8);2643generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd2Reg, srcReg, rangeReg, 0);2644generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cror, node, cnd1Reg, cnd2Reg, cnd1Reg, imm);2645break;2646case TR::java_lang_Character_isLowerCase:2647loadConstant(cg, node, (int32_t)0x7A61F6DF, rangeReg);2648generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd1Reg, srcReg, rangeReg, 1);2649loadConstant(cg, node, (int32_t)0xFFFFFFF8, rangeReg);2650generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd2Reg, srcReg, rangeReg, 0);2651generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cror, node, cnd1Reg, cnd2Reg, cnd1Reg, imm);2652loadConstant(cg, node, (int64_t)0xFFFFFFFFFFAAB5BA, rangeReg);2653generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpeqb, node, cnd2Reg, srcReg, rangeReg);2654generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cror, node, cnd1Reg, cnd2Reg, cnd1Reg, imm);2655break;2656}2657generateTrg1Src1Instruction(cg, TR::InstOpCode::setb, node, returnRegister, cnd1Reg);26582659generateDepConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, cnd0Reg, dependencies);26602661dependencies->stopUsingDepRegs(cg);2662cg->stopUsingRegister(returnRegister);2663cg->stopUsingRegister(cnd0Reg);2664cg->stopUsingRegister(cnd1Reg);2665cg->stopUsingRegister(cnd2Reg);2666cg->stopUsingRegister(srcReg);2667cg->stopUsingRegister(rangeReg);2668cg->stopUsingRegister(tmpReg);2669}26702671void J9::Power::PrivateLinkage::buildDirectCall(TR::Node *callNode,2672TR::SymbolReference *callSymRef,2673TR::RegisterDependencyConditions *dependencies,2674const TR::PPCLinkageProperties &pp,2675int32_t argSize)2676{2677TR::Instruction *gcPoint;2678TR::MethodSymbol *callSymbol = callSymRef->getSymbol()->castToMethodSymbol();2679TR::ResolvedMethodSymbol *sym = callSymbol->getResolvedMethodSymbol();2680TR_ResolvedMethod *vmm = (sym==NULL)?NULL:sym->getResolvedMethod();2681bool myself = comp()->isRecursiveMethodTarget(vmm);26822683TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());26842685if (callSymRef->getReferenceNumber() >= TR_PPCnumRuntimeHelpers)2686fej9->reserveTrampolineIfNecessary(comp(), callSymRef, false);26872688bool forceUnresolvedDispatch = !fej9->isResolvedDirectDispatchGuaranteed(comp());2689if ((callSymbol->isJITInternalNative() ||2690(!callSymRef->isUnresolved() && !callSymbol->isInterpreted() && ((forceUnresolvedDispatch && callSymbol->isHelper()) || !forceUnresolvedDispatch))))2691{2692gcPoint = generateDepImmSymInstruction(cg(), TR::InstOpCode::bl, callNode,2693myself?0:(uintptr_t)callSymbol->getMethodAddress(),2694dependencies, callSymRef?callSymRef:callNode->getSymbolReference());2695}2696else2697{2698TR::LabelSymbol *label = generateLabelSymbol(cg());2699TR::Snippet *snippet;27002701if (callSymRef->isUnresolved() || forceUnresolvedDispatch)2702{2703snippet = new (trHeapMemory()) TR::PPCUnresolvedCallSnippet(cg(), callNode, label, argSize);2704}2705else2706{2707snippet = new (trHeapMemory()) TR::PPCCallSnippet(cg(), callNode, label, callSymRef, argSize);2708snippet->gcMap().setGCRegisterMask(pp.getPreservedRegisterMapForGC());2709}27102711cg()->addSnippet(snippet);2712gcPoint = generateDepImmSymInstruction(cg(), TR::InstOpCode::bl, callNode,27130,2714dependencies,2715new (trHeapMemory()) TR::SymbolReference(comp()->getSymRefTab(), label),2716snippet);27172718// Nop is necessary due to confusion when resolving shared slots at a transition2719if (callSymRef->isOSRInductionHelper())2720cg()->generateNop(callNode);2721}27222723// Helper linkage needs to cover volatiles in the GC map at this point because, unlike private linkage calls,2724// volatiles are not spilled prior to the call.2725gcPoint->PPCNeedsGCMap(callSymbol->getLinkageConvention() == TR_Helper ? 0xffffffff : pp.getPreservedRegisterMapForGC());2726}272727282729TR::Register *J9::Power::PrivateLinkage::buildDirectDispatch(TR::Node *callNode)2730{2731TR::SymbolReference *callSymRef = callNode->getSymbolReference();27322733const TR::PPCLinkageProperties &pp = getProperties();2734TR::RegisterDependencyConditions *dependencies =2735new (trHeapMemory()) TR::RegisterDependencyConditions(2736pp.getNumberOfDependencyGPRegisters(),2737pp.getNumberOfDependencyGPRegisters(), trMemory());27382739TR::Register *returnRegister=NULL;2740TR::LabelSymbol *doneLabel = generateLabelSymbol(cg());27412742// SG - start2743int32_t argSize = buildArgs(callNode, dependencies);2744bool inlinedCharacterIsMethod = false;2745if (comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P9) && comp()->target().is64Bit())2746{2747switch(callNode->getSymbol()->castToMethodSymbol()->getRecognizedMethod())2748{2749case TR::java_lang_Character_isDigit:2750case TR::java_lang_Character_isLetter:2751case TR::java_lang_Character_isUpperCase:2752case TR::java_lang_Character_isLowerCase:2753case TR::java_lang_Character_isWhitespace:2754case TR::java_lang_Character_isAlphabetic:2755inlinedCharacterIsMethod = true;2756inlineCharacterIsMethod(callNode, callNode->getSymbol()->castToMethodSymbol(), cg(), doneLabel);2757break;2758}2759}27602761buildDirectCall(callNode, callSymRef, dependencies, pp, argSize);2762// SG - end27632764cg()->machine()->setLinkRegisterKilled(true);2765cg()->setHasCall();27662767TR::Register *lowReg=NULL, *highReg=NULL;2768switch(callNode->getOpCodeValue())2769{2770case TR::icall:2771case TR::acall:2772returnRegister = dependencies->searchPostConditionRegister(2773pp.getIntegerReturnRegister());2774break;2775case TR::lcall:2776{2777if (comp()->target().is64Bit())2778returnRegister = dependencies->searchPostConditionRegister(2779pp.getLongReturnRegister());2780else2781{2782lowReg = dependencies->searchPostConditionRegister(2783pp.getLongLowReturnRegister());2784highReg = dependencies->searchPostConditionRegister(2785pp.getLongHighReturnRegister());27862787returnRegister = cg()->allocateRegisterPair(lowReg, highReg);2788}2789}2790break;2791case TR::fcall:2792case TR::dcall:2793returnRegister = dependencies->searchPostConditionRegister(2794pp.getFloatReturnRegister());2795if (callNode->getDataType() == TR::Float)2796returnRegister->setIsSinglePrecision();2797break;2798case TR::call:2799returnRegister = NULL;2800break;2801default:2802returnRegister = NULL;2803TR_ASSERT(0, "Unknown direct call Opcode.");2804}28052806if (inlinedCharacterIsMethod)2807{2808generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies->cloneAndFix(cg()));2809}28102811callNode->setRegister(returnRegister);28122813cg()->freeAndResetTransientLongs();2814dependencies->stopUsingDepRegs(cg(), lowReg==NULL?returnRegister:highReg, lowReg);2815return(returnRegister);2816}28172818TR::Register *J9::Power::PrivateLinkage::buildIndirectDispatch(TR::Node *callNode)2819{2820const TR::PPCLinkageProperties &pp = getProperties();2821TR::RegisterDependencyConditions *dependencies =2822new (trHeapMemory()) TR::RegisterDependencyConditions(2823pp.getNumberOfDependencyGPRegisters()+1,2824pp.getNumberOfDependencyGPRegisters()+1, trMemory());28252826int32_t argSize = buildArgs(callNode, dependencies);2827TR::Register *returnRegister;28282829buildVirtualDispatch(callNode, dependencies, argSize);2830cg()->machine()->setLinkRegisterKilled(true);2831cg()->setHasCall();28322833TR::Register *lowReg=NULL, *highReg;2834switch(callNode->getOpCodeValue())2835{2836case TR::icalli:2837case TR::acalli:2838returnRegister = dependencies->searchPostConditionRegister(2839pp.getIntegerReturnRegister());2840break;2841case TR::lcalli:2842{2843if (comp()->target().is64Bit())2844returnRegister = dependencies->searchPostConditionRegister(2845pp.getLongReturnRegister());2846else2847{2848lowReg = dependencies->searchPostConditionRegister(2849pp.getLongLowReturnRegister());2850highReg = dependencies->searchPostConditionRegister(2851pp.getLongHighReturnRegister());28522853returnRegister = cg()->allocateRegisterPair(lowReg, highReg);2854}2855}2856break;2857case TR::fcalli:2858case TR::dcalli:2859returnRegister = dependencies->searchPostConditionRegister(2860pp.getFloatReturnRegister());2861if (callNode->getDataType() == TR::Float)2862returnRegister->setIsSinglePrecision();2863break;2864case TR::calli:2865returnRegister = NULL;2866break;2867default:2868returnRegister = NULL;2869TR_ASSERT(0, "Unknown indirect call Opcode.");2870}28712872callNode->setRegister(returnRegister);28732874cg()->freeAndResetTransientLongs();2875dependencies->stopUsingDepRegs(cg(), lowReg==NULL?returnRegister:highReg, lowReg);2876return(returnRegister);2877}28782879TR::Register *J9::Power::PrivateLinkage::buildalloca(TR::Node *BIFCallNode)2880{2881TR_ASSERT(0,"J9::Power::PrivateLinkage does not support alloca.\n");2882return NULL;2883}28842885int32_t J9::Power::HelperLinkage::buildArgs(TR::Node *callNode,2886TR::RegisterDependencyConditions *dependencies)2887{2888return buildPrivateLinkageArgs(callNode, dependencies, _helperLinkage);2889}28902891TR::MemoryReference *J9::Power::PrivateLinkage::getOutgoingArgumentMemRef(int32_t argSize, TR::Register *argReg, TR::InstOpCode::Mnemonic opCode, TR::PPCMemoryArgument &memArg, uint32_t length, const TR::PPCLinkageProperties& properties)2892{2893TR::Machine *machine = cg()->machine();28942895TR::MemoryReference *result = TR::MemoryReference::createWithDisplacement(cg(), machine->getRealRegister(properties.getNormalStackPointerRegister()),2896argSize+getOffsetToFirstParm(), length);2897memArg.argRegister = argReg;2898memArg.argMemory = result;2899memArg.opCode = opCode;2900return(result);2901}290229032904