Path: blob/master/runtime/compiler/p/codegen/CallSnippet.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 "p/codegen/CallSnippet.hpp"2324#include "codegen/Linkage.hpp"25#include "codegen/Linkage_inlines.hpp"26#include "codegen/Machine.hpp"27#include "codegen/RealRegister.hpp"28#include "codegen/SnippetGCMap.hpp"29#include "compile/ResolvedMethod.hpp"30#include "env/CompilerEnv.hpp"31#include "env/IO.hpp"32#include "env/J2IThunk.hpp"33#include "env/jittypes.h"34#include "il/Node.hpp"35#include "il/Node_inlines.hpp"36#include "p/codegen/PPCAOTRelocation.hpp"37#include "p/codegen/PPCTableOfConstants.hpp"38#include "runtime/CodeCacheManager.hpp"3940uint8_t *flushArgumentsToStack(uint8_t *buffer, TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg)41{42int32_t intArgNum=0, floatArgNum=0, offset;43TR::Compilation *comp = cg->comp();44TR::InstOpCode::Mnemonic storeGPROp= comp->target().is64Bit() ? TR::InstOpCode::std : TR::InstOpCode::stw;45TR::Machine *machine = cg->machine();46TR::Linkage* linkage = cg->getLinkage(callNode->getSymbol()->castToMethodSymbol()->getLinkageConvention());47const TR::PPCLinkageProperties &linkageProperties = linkage->getProperties();48int32_t argStart = callNode->getFirstArgumentIndex();4950if (linkageProperties.getRightToLeft())51offset = linkage->getOffsetToFirstParm();52else53offset = argSize+linkage->getOffsetToFirstParm();5455for (int i=argStart; i<callNode->getNumChildren();i++)56{57TR::Node *child = callNode->getChild(i);58switch (child->getDataType())59{60case TR::Int8:61case TR::Int16:62case TR::Int32:63if (!linkageProperties.getRightToLeft())64offset -= TR::Compiler->om.sizeofReferenceAddress();65if (intArgNum < linkageProperties.getNumIntArgRegs())66{67buffer = storeArgumentItem(TR::InstOpCode::stw, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);68}69intArgNum++;70if (linkageProperties.getRightToLeft())71offset += TR::Compiler->om.sizeofReferenceAddress();72break;73case TR::Address:74if (!linkageProperties.getRightToLeft())75offset -= TR::Compiler->om.sizeofReferenceAddress();76if (intArgNum < linkageProperties.getNumIntArgRegs())77{78buffer = storeArgumentItem(storeGPROp, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);79}80intArgNum++;81if (linkageProperties.getRightToLeft())82offset += TR::Compiler->om.sizeofReferenceAddress();83break;84case TR::Int64:85if (!linkageProperties.getRightToLeft())86offset -= 2*TR::Compiler->om.sizeofReferenceAddress();87if (intArgNum < linkageProperties.getNumIntArgRegs())88{89buffer = storeArgumentItem(storeGPROp, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);90if (comp->target().is32Bit())91{92if (intArgNum < linkageProperties.getNumIntArgRegs()-1)93{94buffer = storeArgumentItem(TR::InstOpCode::stw, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum+1)), offset+4, cg);95}96}97}98intArgNum += comp->target().is64Bit() ? 1 : 2;99if (linkageProperties.getRightToLeft())100offset += 2*TR::Compiler->om.sizeofReferenceAddress();101break;102case TR::Float:103if (!linkageProperties.getRightToLeft())104offset -= TR::Compiler->om.sizeofReferenceAddress();105if (floatArgNum < linkageProperties.getNumFloatArgRegs())106{107buffer = storeArgumentItem(TR::InstOpCode::stfs, buffer, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), offset, cg);108}109floatArgNum++;110if (linkageProperties.getRightToLeft())111offset += TR::Compiler->om.sizeofReferenceAddress();112break;113case TR::Double:114if (!linkageProperties.getRightToLeft())115offset -= 2*TR::Compiler->om.sizeofReferenceAddress();116if (floatArgNum < linkageProperties.getNumFloatArgRegs())117{118buffer = storeArgumentItem(TR::InstOpCode::stfd, buffer, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), offset, cg);119}120floatArgNum++;121if (linkageProperties.getRightToLeft())122offset += 2*TR::Compiler->om.sizeofReferenceAddress();123break;124}125}126return(buffer);127}128129uint8_t *TR::PPCCallSnippet::setUpArgumentsInRegister(uint8_t *buffer, TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg)130{131int32_t intArgNum=0, floatArgNum=0, offset;132TR::Machine *machine = cg->machine();133TR::Compilation *comp = cg->comp();134TR::InstOpCode::Mnemonic loadGPROp= comp->target().is64Bit() ? TR::InstOpCode::ld : TR::InstOpCode::lwz;135TR::Linkage* linkage = cg->getLinkage(callNode->getSymbol()->castToMethodSymbol()->getLinkageConvention());136const TR::PPCLinkageProperties &linkageProperties = linkage->getProperties();137int32_t argStart = callNode->getFirstArgumentIndex();138139if (linkageProperties.getRightToLeft())140offset = linkage->getOffsetToFirstParm();141else142offset = argSize+linkage->getOffsetToFirstParm();143144for (int i=argStart; i<callNode->getNumChildren();i++)145{146TR::Node *child = callNode->getChild(i);147switch (child->getDataType())148{149case TR::Int8:150case TR::Int16:151case TR::Int32:152if (!linkageProperties.getRightToLeft())153offset -= TR::Compiler->om.sizeofReferenceAddress();154if (intArgNum < linkageProperties.getNumIntArgRegs())155{156buffer = loadArgumentItem(TR::InstOpCode::lwz, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);157}158intArgNum++;159if (linkageProperties.getRightToLeft())160offset += TR::Compiler->om.sizeofReferenceAddress();161break;162case TR::Address:163if (!linkageProperties.getRightToLeft())164offset -= TR::Compiler->om.sizeofReferenceAddress();165if (intArgNum < linkageProperties.getNumIntArgRegs())166{167buffer = loadArgumentItem(loadGPROp, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);168}169intArgNum++;170if (linkageProperties.getRightToLeft())171offset += TR::Compiler->om.sizeofReferenceAddress();172break;173case TR::Int64:174if (!linkageProperties.getRightToLeft())175offset -= 2*TR::Compiler->om.sizeofReferenceAddress();176if (intArgNum < linkageProperties.getNumIntArgRegs())177{178buffer = loadArgumentItem(loadGPROp, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);179if (comp->target().is32Bit() && (intArgNum < linkageProperties.getNumIntArgRegs()-1))180{181buffer = loadArgumentItem(TR::InstOpCode::lwz, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum+1)), offset+4, cg);182}183}184intArgNum += comp->target().is64Bit() ? 1 : 2;185if (linkageProperties.getRightToLeft())186offset += 2*TR::Compiler->om.sizeofReferenceAddress();187break;188case TR::Float:189if (!linkageProperties.getRightToLeft())190offset -= TR::Compiler->om.sizeofReferenceAddress();191if (floatArgNum < linkageProperties.getNumFloatArgRegs())192{193buffer = loadArgumentItem(TR::InstOpCode::lfs, buffer, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), offset, cg);194}195floatArgNum++;196if (linkageProperties.getRightToLeft())197offset += TR::Compiler->om.sizeofReferenceAddress();198break;199case TR::Double:200if (!linkageProperties.getRightToLeft())201offset -= 2*TR::Compiler->om.sizeofReferenceAddress();202if (floatArgNum < linkageProperties.getNumFloatArgRegs())203{204buffer = loadArgumentItem(TR::InstOpCode::lfd, buffer, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), offset, cg);205}206floatArgNum++;207if (linkageProperties.getRightToLeft())208offset += 2*TR::Compiler->om.sizeofReferenceAddress();209break;210}211}212return(buffer);213}214215int32_t TR::PPCCallSnippet::instructionCountForArguments(TR::Node *callNode, TR::CodeGenerator *cg)216{217TR::Compilation *comp = cg->comp();218int32_t intArgNum=0, floatArgNum=0, count=0;219const TR::PPCLinkageProperties &linkage = cg->getLinkage(callNode->getSymbol()->castToMethodSymbol()->getLinkageConvention())->getProperties();220int32_t argStart = callNode->getFirstArgumentIndex();221222for (int i=argStart; i<callNode->getNumChildren();i++)223{224TR::Node *child = callNode->getChild(i);225switch (child->getDataType())226{227case TR::Int8:228case TR::Int16:229case TR::Int32:230case TR::Address:231if (intArgNum < linkage.getNumIntArgRegs())232{233count++;234}235intArgNum++;236break;237case TR::Int64:238if (intArgNum < linkage.getNumIntArgRegs())239{240count++;241if (comp->target().is32Bit() && (intArgNum < linkage.getNumIntArgRegs()-1))242{243count++;244}245}246intArgNum += comp->target().is64Bit() ? 1 : 2;247break;248case TR::Float:249if (floatArgNum < linkage.getNumFloatArgRegs())250{251count++;252}253floatArgNum++;254break;255case TR::Double:256if (floatArgNum < linkage.getNumFloatArgRegs())257{258count++;259}260floatArgNum++;261break;262}263}264return(count);265}266267TR_RuntimeHelper TR::PPCCallSnippet::getInterpretedDispatchHelper(268TR::SymbolReference *methodSymRef,269TR::DataType type,270bool isSynchronised,271bool& isNativeStatic,272TR::CodeGenerator *cg)273{274TR::Compilation * comp = cg->comp();275TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());276TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();277bool isJitInduceOSRCall = false;278if (methodSymbol->isHelper() &&279methodSymRef->isOSRInductionHelper())280{281isJitInduceOSRCall = true;282}283284bool forceUnresolvedDispatch = !fej9->isResolvedDirectDispatchGuaranteed(comp);285if (methodSymRef->isUnresolved() || forceUnresolvedDispatch)286{287TR_ASSERT(!isJitInduceOSRCall || !forceUnresolvedDispatch, "calling jitInduceOSR is not supported yet under AOT\n");288289if (methodSymbol->isSpecial())290return TR_PPCinterpreterUnresolvedSpecialGlue;291else if (methodSymbol->isStatic())292return TR_PPCinterpreterUnresolvedStaticGlue;293else294return TR_PPCinterpreterUnresolvedDirectVirtualGlue;295}296else if (methodSymbol->isVMInternalNative() || methodSymbol->isJITInternalNative())297{298isNativeStatic = true;299return TR_PPCnativeStaticHelper;300}301else if (isJitInduceOSRCall)302return (TR_RuntimeHelper) methodSymRef->getReferenceNumber();303else304{305switch (type)306{307case TR::NoType:308return isSynchronised?TR_PPCinterpreterSyncVoidStaticGlue: TR_PPCinterpreterVoidStaticGlue;309case TR::Int32:310return isSynchronised?TR_PPCinterpreterSyncGPR3StaticGlue:TR_PPCinterpreterGPR3StaticGlue;311case TR::Address:312if (comp->target().is64Bit())313return isSynchronised?TR_PPCinterpreterSyncGPR3GPR4StaticGlue:TR_PPCinterpreterGPR3GPR4StaticGlue;314else315return isSynchronised?TR_PPCinterpreterSyncGPR3StaticGlue:TR_PPCinterpreterGPR3StaticGlue;316case TR::Int64:317return isSynchronised?TR_PPCinterpreterSyncGPR3GPR4StaticGlue:TR_PPCinterpreterGPR3GPR4StaticGlue;318case TR::Float:319return isSynchronised?TR_PPCinterpreterSyncFPR0FStaticGlue:TR_PPCinterpreterFPR0FStaticGlue;320case TR::Double:321return isSynchronised?TR_PPCinterpreterSyncFPR0DStaticGlue:TR_PPCinterpreterFPR0DStaticGlue;322default:323TR_ASSERT(0, "Bad return data type for a call node. DataType was %s\n",324comp->getDebug()->getName(type));325return (TR_RuntimeHelper)0;326}327}328}329330uint8_t *TR::PPCCallSnippet::emitSnippetBody()331{332333uint8_t *cursor = cg()->getBinaryBufferCursor();334TR::Node *callNode = getNode();335TR::SymbolReference *methodSymRef = (_realMethodSymbolReference)?_realMethodSymbolReference:callNode->getSymbolReference();336TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();337TR::SymbolReference *glueRef;338bool isNativeStatic = false;339TR::Compilation *comp = cg()->comp();340TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());341342getSnippetLabel()->setCodeLocation(cursor);343344// Flush in-register arguments back to the stack for interpreter345cursor = flushArgumentsToStack(cursor, callNode, getSizeOfArguments(), cg());346347TR_RuntimeHelper runtimeHelper = getInterpretedDispatchHelper(methodSymRef, callNode->getDataType(),348methodSymbol->isSynchronised(), isNativeStatic, cg());349glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(runtimeHelper);350351intptr_t helperAddress = (intptr_t)glueRef->getMethodAddress();352if (cg()->directCallRequiresTrampoline(helperAddress, (intptr_t)cursor))353{354helperAddress = TR::CodeCacheManager::instance()->findHelperTrampoline(glueRef->getReferenceNumber(), (void *)cursor);355TR_ASSERT_FATAL(comp->target().cpu.isTargetWithinIFormBranchRange(helperAddress, (intptr_t)cursor),356"Helper address is out of range");357}358359// 'b glueRef' for jitInduceOSRAtCurrentPC, 'bl glueRef' otherwise360// we use "b" for induceOSR because we want the helper to think that it's been called from the mainline code and not from the snippet.361int32_t branchInstruction = (glueRef->isOSRInductionHelper()) ? 0x48000000 : 0x48000001;362*(int32_t *)cursor = branchInstruction | ((helperAddress - (intptr_t)cursor) & 0x03fffffc);363cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,(uint8_t *)glueRef,TR_HelperAddress, cg()),364__FILE__, __LINE__, callNode);365366cursor += PPC_INSTRUCTION_LENGTH;367368if (isNativeStatic)369{370// Rather than placing the return address as data after the 'bl', place a 'b' back to main line code371// This insures that all 'blr's return to their corresponding 'bl's372*(int32_t *)cursor = 0x48000000 | ((intptr_t)(getCallRA() - (intptr_t)cursor) & 0x03fffffc);373TR_ASSERT(gcMap().isGCSafePoint() && gcMap().getStackMap(), "Native static call snippets must have GC maps when preserving the link stack");374gcMap().registerStackMap(cursor - PPC_INSTRUCTION_LENGTH, cg());375cursor += PPC_INSTRUCTION_LENGTH;376377// Padding; VM helper depends this gap being present378if (comp->target().is64Bit())379{380*(int32_t *)cursor = 0xdeadc0de;381cursor += PPC_INSTRUCTION_LENGTH;382}383}384else385{386// Store the code cache RA387*(intptr_t *)cursor = (intptr_t)getCallRA();388cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,NULL,TR_AbsoluteMethodAddress, cg()),389__FILE__, __LINE__, callNode);390391cursor += TR::Compiler->om.sizeofReferenceAddress();392}393//induceOSRAtCurrentPC is implemented in the VM, and it knows, by looking at the current PC, what method it needs to394//continue execution in interpreted mode. Therefore, it doesn't need the method pointer.395if (!glueRef->isOSRInductionHelper())396{397bool forceUnresolvedDispatch = !fej9->isResolvedDirectDispatchGuaranteed(comp);398399// Store the method pointer: it is NULL for unresolved400if (methodSymRef->isUnresolved() || forceUnresolvedDispatch)401{402*(intptr_t *)cursor = 0;403if (comp->getOption(TR_EnableHCR))404{405cg()->jitAddPicToPatchOnClassRedefinition((void*)-1, (void *)cursor, true);406cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation((uint8_t *)cursor, NULL,(uint8_t *)needsFullSizeRuntimeAssumption,407TR_HCR, cg()),__FILE__, __LINE__,408getNode());409}410}411else412{413*(intptr_t *)cursor = (intptr_t)methodSymbol->getMethodAddress();414if (comp->getOption(TR_EnableHCR))415cg()->jitAddPicToPatchOnClassRedefinition((void *)methodSymbol->getMethodAddress(), (void *)cursor);416417if (comp->compileRelocatableCode())418{419cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,420(uint8_t *)methodSymbol->getMethodAddress(),421(uint8_t *)TR::SymbolType::typeMethod,422TR_SymbolFromManager,423cg()), __FILE__, __LINE__, getNode());424cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,425(uint8_t *)methodSymbol->getMethodAddress(),426TR_ResolvedTrampolines,427cg()), __FILE__, __LINE__, getNode());428}429}430}431cursor += TR::Compiler->om.sizeofReferenceAddress();432433// Lock word initialized to 0434*(int32_t *)cursor = 0;435436return (cursor+4);437}438439uint32_t TR::PPCCallSnippet::getLength(int32_t estimatedSnippetStart)440{441return((instructionCountForArguments(getNode(), cg())*4) + 2*TR::Compiler->om.sizeofReferenceAddress() + 8);442}443444uint8_t *TR::PPCUnresolvedCallSnippet::emitSnippetBody()445{446TR::Compilation *comp = cg()->comp();447TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());448uint8_t *cursor = TR::PPCCallSnippet::emitSnippetBody();449450TR::SymbolReference *methodSymRef = (_realMethodSymbolReference)?_realMethodSymbolReference:getNode()->getSymbolReference();451TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();452int32_t helperLookupOffset;453454switch (getNode()->getDataType())455{456case TR::NoType:457helperLookupOffset = 0;458break;459case TR::Int32:460helperLookupOffset = TR::Compiler->om.sizeofReferenceAddress();461break;462case TR::Address:463if (comp->target().is64Bit())464helperLookupOffset = 2*TR::Compiler->om.sizeofReferenceAddress();465else466helperLookupOffset = TR::Compiler->om.sizeofReferenceAddress();467break;468case TR::Int64:469helperLookupOffset = 2*TR::Compiler->om.sizeofReferenceAddress();470break;471case TR::Float:472helperLookupOffset = 3*TR::Compiler->om.sizeofReferenceAddress();473break;474case TR::Double:475helperLookupOffset = 4*TR::Compiler->om.sizeofReferenceAddress();476break;477}478479*(uint32_t *)cursor = (helperLookupOffset<<24) | methodSymRef->getCPIndexForVM();480481cursor += 4;482*(intptr_t *)cursor = (intptr_t)methodSymRef->getOwningMethod(comp)->constantPool();483484if (comp->compileRelocatableCode() && comp->getOption(TR_TraceRelocatableDataDetailsCG))485{486traceMsg(comp, "<relocatableDataTrampolinesCG>\n");487traceMsg(comp, "%s\n", comp->signature());488traceMsg(comp, "%-8s", "cpIndex");489traceMsg(comp, "cp\n");490traceMsg(comp, "%-8x", methodSymRef->getCPIndexForVM());491traceMsg(comp, "%x\n", methodSymRef->getOwningMethod(comp)->constantPool());492traceMsg(comp, "</relocatableDataTrampolinesCG>\n");493}494495cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,496*(uint8_t **)cursor,497getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,498TR_Trampolines, cg()),499__FILE__, __LINE__, getNode());500501cursor += TR::Compiler->om.sizeofReferenceAddress();502503*(int32_t *)cursor = 0;504return cursor+4;505}506507uint32_t TR::PPCUnresolvedCallSnippet::getLength(int32_t estimatedSnippetStart)508{509return TR::PPCCallSnippet::getLength(estimatedSnippetStart) + 8 + TR::Compiler->om.sizeofReferenceAddress();510}511512uint8_t *TR::PPCVirtualSnippet::emitSnippetBody()513{514return(NULL);515}516517uint32_t TR::PPCVirtualSnippet::getLength(int32_t estimatedSnippetStart)518{519return(0);520}521522uint8_t *TR::PPCVirtualUnresolvedSnippet::emitSnippetBody()523{524uint8_t *cursor = cg()->getBinaryBufferCursor();525TR::Compilation *comp = cg()->comp();526TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());527TR::Node *callNode = getNode();528TR::SymbolReference *glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_PPCvirtualUnresolvedHelper);529void *thunk = fej9->getJ2IThunk(callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->getMethod(), comp);530uint8_t *j2iThunkRelocationPoint;531532// We want the data in the snippet to be naturally aligned533if (comp->target().is64Bit() && (((uint64_t)cursor % TR::Compiler->om.sizeofReferenceAddress()) == 4))534{535*(int32_t *)cursor = 0xdeadc0de;536cursor += 4;537}538539getSnippetLabel()->setCodeLocation(cursor);540541intptr_t helperAddress = (intptr_t)glueRef->getMethodAddress();542if (cg()->directCallRequiresTrampoline(helperAddress, (intptr_t)cursor))543{544helperAddress = TR::CodeCacheManager::instance()->findHelperTrampoline(glueRef->getReferenceNumber(), (void *)cursor);545TR_ASSERT_FATAL(comp->target().cpu.isTargetWithinIFormBranchRange(helperAddress, (intptr_t)cursor),546"Helper address is out of range");547}548549// bl glueRef550*(int32_t *)cursor = 0x48000001 | ((helperAddress - (intptr_t)cursor) & 0x03fffffc);551cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,(uint8_t *)glueRef,TR_HelperAddress, cg()),552__FILE__, __LINE__, callNode);553cursor += 4;554555/*556* Place a 'b' back to the main line code after the 'bl'.557* This is used to have 'blr's return to their corresponding 'bl's when handling private nestmate calls.558* Ideally, 'blr's return to their corresponding 'bl's in other cases as well but currently that does not happen.559*/560intptr_t distance = (intptr_t)getReturnLabel()->getCodeLocation() - (intptr_t)cursor;561*(int32_t *)cursor = 0x48000000 | (distance & 0x03fffffc);562563TR_ASSERT(gcMap().isGCSafePoint() && gcMap().getStackMap(), "Virtual call snippets must have GC maps when preserving the link stack");564gcMap().registerStackMap(cursor - 4, cg());565cursor += 4;566567// Store the code cache RA568*(intptr_t *)cursor = (intptr_t)getReturnLabel()->getCodeLocation();569cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,NULL,TR_AbsoluteMethodAddress, cg()),570__FILE__, __LINE__, callNode);571572cursor += TR::Compiler->om.sizeofReferenceAddress();573574// GJ - Swizzled the order of the following lines to conform to helper575intptr_t cpAddr = (intptr_t)callNode->getSymbolReference()->getOwningMethod(comp)->constantPool();576*(intptr_t *)cursor = cpAddr;577j2iThunkRelocationPoint = cursor;578579cursor += TR::Compiler->om.sizeofReferenceAddress();580581*(uintptr_t *)cursor = callNode->getSymbolReference()->getCPIndexForVM();582cursor += TR::Compiler->om.sizeofReferenceAddress();583584/*585* Reserved spot to hold J9Method pointer of the callee.586* This is used for private nestmate calls.587*/588*(intptr_t *)cursor = (intptr_t)0;589cursor += sizeof(intptr_t);590591/*592* J2I thunk address.593* This is used for private nestmate calls.594*/595*(intptr_t*)cursor = (intptr_t)thunk;596597auto info =598(TR_RelocationRecordInformation *)comp->trMemory()->allocateMemory(599sizeof (TR_RelocationRecordInformation),600heapAlloc);601602// data1 = constantPool603info->data1 = cpAddr;604605// data2 = inlined site index606info->data2 = callNode ? callNode->getInlinedSiteIndex() : (uintptr_t)-1;607608// data3 = distance in bytes from Constant Pool Pointer to J2I Thunk609info->data3 = (intptr_t)cursor - (intptr_t)j2iThunkRelocationPoint;610611cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(j2iThunkRelocationPoint, (uint8_t *)info, NULL, TR_J2IVirtualThunkPointer, cg()),612__FILE__, __LINE__, callNode);613614cursor += sizeof(intptr_t);615616*(int32_t *)cursor = 0; // Lock word617cursor += sizeof(int32_t);618619return cursor;620}621622uint32_t TR::PPCVirtualUnresolvedSnippet::getLength(int32_t estimatedSnippetStart)623{624/*625* 4 = Code alignment may add 4 to the length. To be conservative it is always part of the estimate.626* 8 = Two instructions. One bl and one b instruction.627* 5 address fields:628* - Call Site RA629* - Constant Pool Pointer630* - Constant Pool Index631* - Private J9Method pointer632* - J2I thunk address633* 4 = Lockword634*/635return(4 + 8 + (5 * TR::Compiler->om.sizeofReferenceAddress()) + 4);636}637638uint8_t *TR::PPCInterfaceCallSnippet::emitSnippetBody()639{640uint8_t *cursor = cg()->getBinaryBufferCursor();641uint8_t *blAddress;642TR::Node *callNode = getNode();643TR::Compilation *comp = cg()->comp();644TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());645TR::SymbolReference *glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_PPCinterfaceCallHelper);646void *thunk = fej9->getJ2IThunk(callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->getMethod(), comp);647uint8_t *j2iThunkRelocationPoint;648649// We want the data in the snippet to be naturally aligned650if (comp->target().is64Bit() && (((uint64_t)cursor % TR::Compiler->om.sizeofReferenceAddress()) == 0))651{652// icallVMprJavaSendPatchupVirtual needs to determine if it was called for virtual dispatch as opposed to interface dispatch653// To do that it checks for 'mtctr r12' at -8(LR), which points here when it's called for interface dispatch in 64 bit mode654// We make sure it doesn't contain that particular bit pattern by accident (which can actually happen)655*(int32_t *)cursor = 0xdeadc0de;656cursor += 4;657}658659getSnippetLabel()->setCodeLocation(cursor);660661intptr_t helperAddress = (intptr_t)glueRef->getMethodAddress();662if (cg()->directCallRequiresTrampoline(helperAddress, (intptr_t)cursor))663{664helperAddress = TR::CodeCacheManager::instance()->findHelperTrampoline(glueRef->getReferenceNumber(), (void *)cursor);665TR_ASSERT_FATAL(comp->target().cpu.isTargetWithinIFormBranchRange(helperAddress, (intptr_t)cursor),666"Helper address is out of range");667}668669// bl glueRef670*(int32_t *)cursor = 0x48000001 | ((helperAddress - (intptr_t)cursor) & 0x03fffffc);671cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, (uint8_t *)glueRef, TR_HelperAddress, cg()),672__FILE__, __LINE__, callNode);673blAddress = cursor;674cursor += PPC_INSTRUCTION_LENGTH;675676// Rather than placing the return address as data after the 'bl', place a 'b' back to main line code677// This insures that all 'blr's return to their corresponding 'bl's678intptr_t distance = (intptr_t)getReturnLabel()->getCodeLocation() - (intptr_t)cursor;679*(int32_t *)cursor = 0x48000000 | (distance & 0x03fffffc);680681TR_ASSERT(gcMap().isGCSafePoint() && gcMap().getStackMap(), "Interface call snippets must have GC maps when preserving the link stack");682gcMap().registerStackMap(cursor - PPC_INSTRUCTION_LENGTH, cg());683cursor += PPC_INSTRUCTION_LENGTH;684685// Padding; jitLookupInterfaceMethod depends on this gap being present686if (comp->target().is64Bit())687{688*(int32_t *)cursor = 0xdeadc0de;689cursor += PPC_INSTRUCTION_LENGTH;690}691692intptr_t cpAddr = (intptr_t)callNode->getSymbolReference()->getOwningMethod(comp)->constantPool();693*(intptr_t *)cursor = cpAddr;694j2iThunkRelocationPoint = cursor;695696cursor += TR::Compiler->om.sizeofReferenceAddress();697698*(uintptr_t *)cursor = callNode->getSymbolReference()->getCPIndexForVM();699cursor += TR::Compiler->om.sizeofReferenceAddress();700701// Add two slots for interface class & iTable index, keeping cp/cpindex around702((uintptr_t *)cursor)[0] = 0;703((uintptr_t *)cursor)[1] = 0;704cursor += 2*TR::Compiler->om.sizeofReferenceAddress();705706if (comp->target().is64Bit())707{708if (!comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))709{710if (getTOCOffset() != PTOC_FULL_INDEX)711{712TR_PPCTableOfConstants::setTOCSlot(getTOCOffset(), (uintptr_t)cursor);713}714else715{716int32_t *patchAddr = (int32_t *)getLowerInstruction()->getBinaryEncoding();717intptr_t addrValue = (intptr_t)cursor;718if (!comp->compileRelocatableCode()719#ifdef J9VM_OPT_JITSERVER720&& !comp->isOutOfProcessCompilation()721#endif722)723{724// If the high nibble is 0 and the next nibble's high bit is clear, change the first instruction to a nop and the third to a li725// Next nibble's high bit needs to be clear in order to use li (because li will sign extend the immediate)726if ((addrValue >> 48) == 0 && ((addrValue >> 32) & 0x8000) == 0)727{728*patchAddr |= addrValue & 0x0000ffff;729addrValue = cg()->hiValue(addrValue);730uint32_t ori = *(patchAddr-2);731uint32_t li = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::li) | (ori & 0x03e00000);732*(patchAddr-2) = li | ((addrValue>>16) & 0x0000ffff);733*(patchAddr-3) |= addrValue & 0x0000ffff;734*(patchAddr-4) = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::nop);735}736else737{738*patchAddr |= addrValue & 0x0000ffff;739addrValue = cg()->hiValue(addrValue);740*(patchAddr-2) |= (addrValue>>16) & 0x0000ffff;741*(patchAddr-3) |= addrValue & 0x0000ffff;742*(patchAddr-4) |= (addrValue>>32) & 0x0000ffff;743}744}745else746{747// We must take this path for all compiles that need to generate relocatable code (ex. AOT, outOfProcess).748// The immediate fields of relocatable instructions must be clear. This is because when performing the relocation,749// we OR the new address into the fields. So if the fields are not already clear, then OR'ing the new address can750// result in garbage data.751cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(getUpperInstruction(),752(uint8_t *)(addrValue),753(uint8_t *)fixedSequence4,754TR_FixedSequenceAddress2,755cg()),756__FILE__, __LINE__, callNode);757}758}759}760}761else762{763// Patch up the main line codes764int32_t *patchAddress1 = (int32_t *)getUpperInstruction()->getBinaryEncoding();765*patchAddress1 |= cg()->hiValue((int32_t)(intptr_t)cursor) & 0x0000ffff;766int32_t *patchAddress2 = (int32_t *)getLowerInstruction()->getBinaryEncoding();767*patchAddress2 |= (int32_t)(intptr_t)cursor & 0x0000ffff;768TR_RelocationRecordInformation *recordInfo = ( TR_RelocationRecordInformation *)comp->trMemory()->allocateMemory(sizeof( TR_RelocationRecordInformation), heapAlloc);769recordInfo->data3 = orderedPairSequence1;770cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalOrderedPair32BitRelocation((uint8_t *)patchAddress1,771(uint8_t *)patchAddress2,772(uint8_t *)recordInfo,773TR_AbsoluteMethodAddressOrderedPair, cg()),774__FILE__, __LINE__, callNode);775}776777// Initialize for: two class ptrs, two target addrs778// Initialize target addrs with the address of the bl. see 134322779*(intptr_t *)cursor = -1;780*(intptr_t *)(cursor+TR::Compiler->om.sizeofReferenceAddress()) = (intptr_t)blAddress;781*(intptr_t *)(cursor+2*TR::Compiler->om.sizeofReferenceAddress()) = -1;782*(intptr_t *)(cursor+3*TR::Compiler->om.sizeofReferenceAddress()) = (intptr_t)blAddress;783784// Register for relation of the 1st target address785cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor+TR::Compiler->om.sizeofReferenceAddress(), NULL, TR_AbsoluteMethodAddress, cg()),786__FILE__, __LINE__, callNode);787788// Register for relocation of the 2nd target address789cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor+3*TR::Compiler->om.sizeofReferenceAddress(), NULL, TR_AbsoluteMethodAddress, cg()),790__FILE__, __LINE__, callNode);791792cursor += 4 * TR::Compiler->om.sizeofReferenceAddress();793794/*795* J2I thunk address.796* This is used for private nestmate calls.797*/798*(intptr_t*)cursor = (intptr_t)thunk;799800if (comp->compileRelocatableCode())801{802auto info =803(TR_RelocationRecordInformation *)comp->trMemory()->allocateMemory(804sizeof (TR_RelocationRecordInformation),805heapAlloc);806807// data1 = constantPool808info->data1 = cpAddr;809810// data2 = inlined site index811info->data2 = callNode ? callNode->getInlinedSiteIndex() : (uintptr_t)-1;812813// data3 = distance in bytes from Constant Pool Pointer to J2I Thunk814info->data3 = (intptr_t)cursor - (intptr_t)j2iThunkRelocationPoint;815816cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(j2iThunkRelocationPoint, (uint8_t *)info, NULL, TR_J2IVirtualThunkPointer, cg()),817__FILE__, __LINE__, callNode);818}819cursor += sizeof(intptr_t);820821822return cursor;823}824825uint32_t TR::PPCInterfaceCallSnippet::getLength(int32_t estimatedSnippetStart)826{827/*828* 4 = Code alignment may add 4 to the length. To be conservative it is always part of the estimate.829* 8 = Two instructions. One bl and one b instruction.830* 0 or 4 = Padding. Only needed under 64 bit.831* 9 address fields:832* - CP Pointer833* - CP Index834* - Interface Class Pointer835* - ITable Index (may also contain a tagged J9Method* when handling nestmates)836* - First Class Pointer837* - First Class Target838* - Second Class Pointer839* - Second Class Target840* - J2I thunk address841*/842return(4 + 8 + (cg()->comp()->target().is64Bit() ? 4 : 0) + (9 * TR::Compiler->om.sizeofReferenceAddress()));843}844845uint8_t *TR::PPCCallSnippet::generateVIThunk(TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg)846{847TR::Compilation * comp = cg->comp();848TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());849int32_t codeSize = 4*(instructionCountForArguments(callNode, cg) + (comp->target().is64Bit()?7:4)) + 8; // Additional 4 bytes to hold size of thunk850uint8_t *thunk, *buffer, *returnValue;851intptr_t dispatcher;852int32_t sizeThunk;853854switch (callNode->getDataType())855{856case TR::NoType:857dispatcher = (intptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_PPCicallVMprJavaSendVirtual0)->getMethodAddress();858break;859case TR::Int32:860dispatcher = (intptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_PPCicallVMprJavaSendVirtual1)->getMethodAddress();861break;862case TR::Address:863if (comp->target().is64Bit())864dispatcher = (intptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_PPCicallVMprJavaSendVirtualJ)->getMethodAddress();865else866dispatcher = (intptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_PPCicallVMprJavaSendVirtual1)->getMethodAddress();867break;868case TR::Int64:869dispatcher = (intptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_PPCicallVMprJavaSendVirtualJ)->getMethodAddress();870break;871case TR::Float:872dispatcher = (intptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_PPCicallVMprJavaSendVirtualF)->getMethodAddress();873break;874case TR::Double:875dispatcher = (intptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_PPCicallVMprJavaSendVirtualD)->getMethodAddress();876break;877default:878TR_ASSERT(0, "Bad return data type for a call node. DataType was %s\n",879comp->getDebug()->getName(callNode->getDataType()));880}881882if (comp->target().is32Bit() && (((dispatcher&0x80008000) == 0x80008000) || comp->compileRelocatableCode()) )883codeSize += 4;884885if (comp->compileRelocatableCode())886thunk = (uint8_t *)comp->trMemory()->allocateMemory(codeSize, heapAlloc);887else888thunk = (uint8_t *)cg->allocateCodeMemory(codeSize, true, false);889buffer = returnValue = thunk + 8;890891buffer = flushArgumentsToStack(buffer, callNode, argSize, cg);892*((int32_t *)thunk + 1)= buffer - returnValue; // patch offset for AOT relocation893894// NOTE: modification of the layout of the following will require a corresponding change in AOT relocation code (codert/ppc/AOTRelocations.cpp)895if (comp->target().is64Bit())896{897// todo64: fix me, I'm just a temporary kludge898// lis gr4, upper 16-bits899*(int32_t *)buffer = 0x3c800000 | ((dispatcher>>48) & 0x0000ffff);900buffer += 4;901902// ori gr4, gr4, next 16-bits903*(int32_t *)buffer = 0x60840000 | ((dispatcher>>32) & 0x0000ffff);904buffer += 4;905906// rldicr gr4, gr4, 32, 31907*(int32_t *)buffer = 0x788403e6;908buffer += 4;909910// oris gr4, gr4, next 16-bits911*(int32_t *)buffer = 0x64840000 | ((dispatcher>>16) & 0x0000ffff);912buffer += 4;913914// ori gr4, gr4, last 16-bits915*(int32_t *)buffer = 0x60840000 | (dispatcher & 0x0000ffff);916buffer += 4;917}918else919{920// For POWER4 which has a problem with the CTR/LR cache when the upper921// bits are not 0 extended.. Use li/oris when the 16th bit is off922if( !(dispatcher & 0x00008000) )923{924// li r4, lower925*(int32_t *)buffer = 0x38800000 | (dispatcher & 0x0000ffff);926buffer += 4;927// oris r4, r4, upper928*(int32_t *)buffer = 0x64840000 | ((dispatcher>>16) & 0x0000ffff);929buffer += 4;930}931else932{933// lis gr4, upper934*(int32_t *)buffer = 0x3c800000 |935(((dispatcher>>16) + (dispatcher&(1<<15)?1:0)) & 0x0000ffff);936buffer += 4;937938// addi gr4, gr4, lower939*(int32_t *)buffer = 0x38840000 | (dispatcher & 0x0000ffff);940buffer += 4;941// Now, if highest bit is on we need to clear the sign extend bits on 64bit CPUs942// ** POWER4 pref fix **943if( dispatcher & 0x80000000 )944{945// rlwinm r4,r4,sh=0,mb=0,me=31946*(int32_t *)buffer = 0x5484003e;947buffer += 4;948}949}950}951952// mtctr gr4953*(int32_t *)buffer = 0x7c8903a6;954buffer += 4;955956// bcctr957*(int32_t *)buffer = 0x4e800420;958buffer += 4;959960sizeThunk = buffer - returnValue;961if (comp->target().is32Bit() && comp->compileRelocatableCode() && !((dispatcher&0x80008000) == 0x80008000)) // Make size of thunk larger for AOT even if extra instruction is not generated at compile time. The extra instruction could be needed for the runtime address.962sizeThunk += 4;963964// patch size of thunk965*(int32_t *)thunk = sizeThunk;966967ppcCodeSync(thunk, codeSize);968969return(returnValue);970}971972TR_J2IThunk *TR::PPCCallSnippet::generateInvokeExactJ2IThunk(TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg, char *signature)973{974TR::Compilation *comp = cg->comp();975TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());976int32_t codeSize = 4*(instructionCountForArguments(callNode, cg) + (comp->target().is64Bit()?7:4)) + 8; // Additional 4 bytes to hold size of thunk977intptr_t dispatcher;978int32_t sizeThunk;979980TR_J2IThunkTable *thunkTable = comp->getPersistentInfo()->getInvokeExactJ2IThunkTable();981TR_J2IThunk *thunk = TR_J2IThunk::allocate(codeSize, signature, cg, thunkTable);982uint8_t *buffer = thunk->entryPoint();983984TR::SymbolReference *dispatcherSymbol;985switch (callNode->getDataType())986{987case TR::NoType:988dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExact0);989break;990case TR::Int32:991dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExact1);992break;993case TR::Address:994if (comp->target().is64Bit())995dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactJ);996else997dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExact1);998break;999case TR::Int64:1000dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactJ);1001break;1002case TR::Float:1003dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactF);1004break;1005case TR::Double:1006dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactD);1007break;1008default:1009TR_ASSERT(0, "Bad return data type '%s' for call node [" POINTER_PRINTF_FORMAT "]\n",1010comp->getDebug()->getName(callNode->getDataType()),1011callNode);1012}10131014dispatcher = (intptr_t)(cg->fej9()->getInvokeExactThunkHelperAddress(comp, dispatcherSymbol, callNode->getDataType()));10151016if ( comp->target().is32Bit() && (((dispatcher&0x80008000) == 0x80008000) || comp->compileRelocatableCode()) )1017codeSize += 4;10181019buffer = flushArgumentsToStack(buffer, callNode, argSize, cg);10201021// NOTE: modification of the layout of the following will require a corresponding change in AOT relocation code (codert/ppc/AOTRelocations.cpp)1022if (comp->target().is64Bit())1023{1024// todo64: fix me, I'm just a temporary kludge1025// lis gr4, upper 16-bits1026*(int32_t *)buffer = 0x3c800000 | ((dispatcher>>48) & 0x0000ffff);1027buffer += 4;10281029// ori gr4, gr4, next 16-bits1030*(int32_t *)buffer = 0x60840000 | ((dispatcher>>32) & 0x0000ffff);1031buffer += 4;10321033// rldicr gr4, gr4, 32, 311034*(int32_t *)buffer = 0x788403e6;1035buffer += 4;10361037// oris gr4, gr4, next 16-bits1038*(int32_t *)buffer = 0x64840000 | ((dispatcher>>16) & 0x0000ffff);1039buffer += 4;10401041// ori gr4, gr4, last 16-bits1042*(int32_t *)buffer = 0x60840000 | (dispatcher & 0x0000ffff);1043buffer += 4;1044}1045else1046{1047// For POWER4 which has a problem with the CTR/LR cache when the upper1048// bits are not 0 extended.. Use li/oris when the 16th bit is off1049if( !(dispatcher & 0x00008000) )1050{1051// li r4, lower1052*(int32_t *)buffer = 0x38800000 | (dispatcher & 0x0000ffff);1053buffer += 4;1054// oris r4, r4, upper1055*(int32_t *)buffer = 0x64840000 | ((dispatcher>>16) & 0x0000ffff);1056buffer += 4;1057}1058else1059{1060// lis gr4, upper1061*(int32_t *)buffer = 0x3c800000 |1062(((dispatcher>>16) + (dispatcher&(1<<15)?1:0)) & 0x0000ffff);1063buffer += 4;10641065// addi gr4, gr4, lower1066*(int32_t *)buffer = 0x38840000 | (dispatcher & 0x0000ffff);1067buffer += 4;1068// Now, if highest bit is on we need to clear the sign extend bits on 64bit CPUs1069// ** POWER4 pref fix **1070if( dispatcher & 0x80000000 )1071{1072// rlwinm r4,r4,sh=0,mb=0,me=311073*(int32_t *)buffer = 0x5484003e;1074buffer += 4;1075}1076}1077}10781079// mtctr gr41080*(int32_t *)buffer = 0x7c8903a6;1081buffer += 4;10821083// bcctr1084*(int32_t *)buffer = 0x4e800420;1085buffer += 4;10861087ppcCodeSync(thunk->entryPoint(), codeSize);10881089return(thunk);1090}109110921093uint8_t *1094TR_Debug::printPPCArgumentsFlush(TR::FILE *pOutFile, TR::Node *node, uint8_t *cursor, int32_t argSize)1095{1096char *storeGPROpName;1097int32_t offset = 0,1098intArgNum = 0,1099floatArgNum = 0;11001101if (_comp->target().is64Bit())1102{1103storeGPROpName="std";1104}1105else1106{1107storeGPROpName="stw";1108}11091110TR::MethodSymbol *methodSymbol = node->getSymbol()->castToMethodSymbol();1111TR::Linkage* linkage = _cg->getLinkage(methodSymbol->getLinkageConvention());1112const TR::PPCLinkageProperties &linkageProperties = linkage->getProperties();11131114TR::Machine *machine = _cg->machine();1115TR::RealRegister *stackPtr = _cg->getStackPointerRegister();11161117if (linkageProperties.getRightToLeft())1118offset = linkage->getOffsetToFirstParm();1119else1120offset = argSize + linkage->getOffsetToFirstParm();11211122for (int i = node->getFirstArgumentIndex(); i < node->getNumChildren(); i++)1123{1124TR::Node *child = node->getChild(i);1125switch (child->getDataType())1126{1127case TR::Int8:1128case TR::Int16:1129case TR::Int32:1130if (!linkageProperties.getRightToLeft())1131offset -= sizeof(intptr_t);1132if (intArgNum < linkageProperties.getNumIntArgRegs())1133{1134printPrefix(pOutFile, NULL, cursor, 4);1135trfprintf(pOutFile, "stw [");1136print(pOutFile, stackPtr, TR_WordReg);1137trfprintf(pOutFile, ", %d], ", offset);1138print(pOutFile, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), TR_WordReg);1139cursor += 4;1140}1141intArgNum++;1142if (linkageProperties.getRightToLeft())1143offset += sizeof(intptr_t);1144break;1145case TR::Address:1146if (!linkageProperties.getRightToLeft())1147offset -= sizeof(intptr_t);1148if (intArgNum < linkageProperties.getNumIntArgRegs())1149{1150printPrefix(pOutFile, NULL, cursor, 4);1151trfprintf(pOutFile, "%s [", storeGPROpName);1152print(pOutFile, stackPtr, TR_WordReg);1153trfprintf(pOutFile, ", %d], ", offset);1154print(pOutFile, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), TR_WordReg);1155cursor += 4;1156}1157intArgNum++;1158if (linkageProperties.getRightToLeft())1159offset += sizeof(intptr_t);1160break;1161case TR::Int64:1162if (!linkageProperties.getRightToLeft())1163offset -= 2*sizeof(intptr_t);1164if (intArgNum < linkageProperties.getNumIntArgRegs())1165{1166printPrefix(pOutFile, NULL, cursor, 4);1167trfprintf(pOutFile, "%s [", storeGPROpName);1168print(pOutFile, stackPtr, TR_WordReg);1169trfprintf(pOutFile, ", %d], ", offset);1170print(pOutFile, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), TR_WordReg);1171cursor += 4;1172if (_comp->target().is32Bit() && (intArgNum < linkageProperties.getNumIntArgRegs() - 1))1173{1174printPrefix(pOutFile, NULL, cursor, 4);1175trfprintf(pOutFile, "stw [");1176print(pOutFile, stackPtr, TR_WordReg);1177trfprintf(pOutFile, ", %d], ", offset + 4);1178print(pOutFile, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum + 1)), TR_WordReg);1179cursor += 4;1180}1181}1182if (_comp->target().is64Bit())1183intArgNum += 1;1184else1185intArgNum += 2;1186if (linkageProperties.getRightToLeft())1187offset += 2*sizeof(intptr_t);1188break;1189case TR::Float:1190if (!linkageProperties.getRightToLeft())1191offset -= sizeof(intptr_t);1192if (floatArgNum < linkageProperties.getNumFloatArgRegs())1193{1194printPrefix(pOutFile, NULL, cursor, 4);1195trfprintf(pOutFile, "stfs [");1196print(pOutFile, stackPtr, TR_WordReg);1197trfprintf(pOutFile, ", %d], ", offset);1198print(pOutFile, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), TR_WordReg);1199cursor += 4;1200}1201floatArgNum++;1202if (linkageProperties.getRightToLeft())1203offset += sizeof(intptr_t);1204break;1205case TR::Double:1206if (!linkageProperties.getRightToLeft())1207offset -= 2*sizeof(intptr_t);1208if (floatArgNum < linkageProperties.getNumFloatArgRegs())1209{1210printPrefix(pOutFile, NULL, cursor, 4);1211trfprintf(pOutFile, "stfd [");1212print(pOutFile, stackPtr, TR_WordReg);1213trfprintf(pOutFile, ", %d], ", offset);1214print(pOutFile, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), TR_WordReg);1215cursor += 4;1216}1217floatArgNum++;1218if (linkageProperties.getRightToLeft())1219offset += 2*sizeof(intptr_t);1220break;1221}1222}1223return(cursor);1224}12251226void1227TR_Debug::print(TR::FILE *pOutFile, TR::PPCCallSnippet * snippet)1228{1229TR::Compilation *comp = _cg->comp();1230TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());1231uint8_t *cursor = snippet->getSnippetLabel()->getCodeLocation();1232TR::Node *callNode = snippet->getNode();1233TR::SymbolReference *methodSymRef = snippet->getRealMethodSymbolReference() ? snippet->getRealMethodSymbolReference() :1234callNode->getSymbolReference();1235TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();1236TR::SymbolReference *glueRef = NULL;1237const char *labelString = NULL;1238bool isNativeStatic = false;12391240bool forceUnresolvedDispatch = !fej9->isResolvedDirectDispatchGuaranteed(comp);1241if (methodSymbol->isHelper() &&1242methodSymRef->isOSRInductionHelper())1243{1244labelString = "Induce OSR Call Snippet";1245glueRef = methodSymRef;1246}1247else if (methodSymRef->isUnresolved() || forceUnresolvedDispatch)1248{1249labelString = "Unresolved Direct Call Snippet";1250if (methodSymbol->isSpecial())1251{1252glueRef = _cg->getSymRef(TR_PPCinterpreterUnresolvedSpecialGlue);1253}1254else if (methodSymbol->isStatic())1255{1256glueRef = _cg->getSymRef(TR_PPCinterpreterUnresolvedStaticGlue);1257}1258else1259{1260glueRef = _cg->getSymRef(TR_PPCinterpreterUnresolvedDirectVirtualGlue);1261}1262}1263else1264{1265if (methodSymbol->isVMInternalNative() || methodSymbol->isJITInternalNative())1266{1267labelString = "Native Static Direct Call Snippet";1268glueRef = _cg->getSymRef(TR_PPCnativeStaticHelper);1269isNativeStatic = true;1270}1271else1272{1273labelString = methodSymbol->isJNI() ? "Interpreted JNI Direct Call Snippet" : "Interpreted Direct Call Snippet";1274bool synchronised = methodSymbol->isSynchronised();1275switch (callNode->getDataType())1276{1277case TR::NoType:1278if (synchronised)1279glueRef = _cg->getSymRef(TR_PPCinterpreterSyncVoidStaticGlue);1280else1281glueRef = _cg->getSymRef(TR_PPCinterpreterVoidStaticGlue);1282break;12831284case TR::Int32:1285if (synchronised)1286glueRef = _cg->getSymRef(TR_PPCinterpreterSyncGPR3StaticGlue);1287else1288glueRef = _cg->getSymRef(TR_PPCinterpreterGPR3StaticGlue);1289break;12901291case TR::Address:1292if (_comp->target().is64Bit())1293{1294if (synchronised)1295glueRef = _cg->getSymRef(TR_PPCinterpreterSyncGPR3GPR4StaticGlue);1296else1297glueRef = _cg->getSymRef(TR_PPCinterpreterGPR3GPR4StaticGlue);1298}1299else1300{1301if (synchronised)1302glueRef = _cg->getSymRef(TR_PPCinterpreterSyncGPR3StaticGlue);1303else1304glueRef = _cg->getSymRef(TR_PPCinterpreterGPR3StaticGlue);1305}1306break;13071308case TR::Int64:1309if (synchronised)1310glueRef = _cg->getSymRef(TR_PPCinterpreterSyncGPR3GPR4StaticGlue);1311else1312glueRef = _cg->getSymRef(TR_PPCinterpreterGPR3GPR4StaticGlue);1313break;13141315case TR::Float:1316if (synchronised)1317glueRef = _cg->getSymRef(TR_PPCinterpreterSyncFPR0FStaticGlue);1318else1319glueRef = _cg->getSymRef(TR_PPCinterpreterFPR0FStaticGlue);1320break;13211322case TR::Double:1323if (synchronised)1324glueRef = _cg->getSymRef(TR_PPCinterpreterSyncFPR0DStaticGlue);1325else1326glueRef = _cg->getSymRef(TR_PPCinterpreterFPR0DStaticGlue);1327break;13281329default:1330TR_ASSERT(0, "Bad return data type for a call node. DataType was %s\n",1331getName(callNode->getDataType()));1332}1333}1334}13351336TR_ASSERT(glueRef && labelString, "Expecting to have symref and label string at this point");13371338printSnippetLabel(pOutFile, snippet->getSnippetLabel(), cursor, labelString);13391340cursor = printPPCArgumentsFlush(pOutFile, callNode, cursor, snippet->getSizeOfArguments());13411342char *info = "";1343int32_t distance;1344if (isBranchToTrampoline(glueRef, cursor, distance))1345info = " Through trampoline";13461347printPrefix(pOutFile, NULL, cursor, 4);1348distance = *((int32_t *) cursor) & 0x03fffffc;1349distance = (distance << 6) >> 6; // sign extend1350trfprintf(pOutFile, "bl \t" POINTER_PRINTF_FORMAT "\t\t;%s", (intptr_t)cursor + distance, info);1351cursor += 4;13521353if (isNativeStatic)1354{1355printPrefix(pOutFile, NULL, cursor, 4);1356distance = *((int32_t *) cursor) & 0x03fffffc;1357distance = (distance << 6) >> 6; // sign extend1358trfprintf(pOutFile, "b \t" POINTER_PRINTF_FORMAT "\t\t;%s", (intptr_t)cursor + distance, " back to program code");1359cursor += 4;13601361if (_comp->target().is64Bit())1362{1363printPrefix(pOutFile, NULL, cursor, 4);1364trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Padding", *(int32_t *)cursor);1365cursor += 4;1366}1367}1368else1369{1370printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1371trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Call Site RA", snippet->getCallRA());1372cursor += sizeof(intptr_t);1373}13741375printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1376trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Method Pointer", *(uintptr_t *)cursor);1377cursor += sizeof(intptr_t);13781379printPrefix(pOutFile, NULL, cursor, 4);1380trfprintf(pOutFile, ".long \t0x%08x\t\t; Lock Word For Compilation", *(int32_t *)cursor);1381}13821383void1384TR_Debug::print(TR::FILE *pOutFile, TR::PPCUnresolvedCallSnippet * snippet)1385{1386uint8_t *cursor = snippet->getSnippetLabel()->getCodeLocation() + snippet->getLength(0) - (8+sizeof(intptr_t));13871388TR::SymbolReference *methodSymRef = snippet->getNode()->getSymbolReference();1389TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();13901391int32_t helperLookupOffset;1392switch (snippet->getNode()->getDataType())1393{1394case TR::NoType:1395helperLookupOffset = 0;1396break;1397case TR::Int32:1398case TR::Address:1399helperLookupOffset = 4;1400break;1401case TR::Int64:1402helperLookupOffset = 8;1403break;1404case TR::Float:1405helperLookupOffset = 12;1406break;1407case TR::Double:1408helperLookupOffset = 16;1409break;1410}14111412print(pOutFile, (TR::PPCCallSnippet *) snippet);14131414printPrefix(pOutFile, NULL, cursor, 4);1415trfprintf(pOutFile,1416".long \t0x%08x\t\t; Offset | Flag | CP Index",1417(helperLookupOffset << 24) | methodSymRef->getCPIndexForVM());1418cursor += 4;14191420printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1421trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Pointer To Constant Pool", *(intptr_t *)cursor);1422cursor += sizeof(intptr_t);14231424printPrefix(pOutFile, NULL, cursor, 4);1425trfprintf(pOutFile, ".long \t0x%08x\t\t; Lock Word For Resolution", *(int32_t *)cursor);1426}14271428void1429TR_Debug::print(TR::FILE *pOutFile, TR::PPCVirtualSnippet * snippet)1430{1431}14321433void1434TR_Debug::print(TR::FILE *pOutFile, TR::PPCVirtualUnresolvedSnippet * snippet)1435{1436uint8_t *cursor = snippet->getSnippetLabel()->getCodeLocation();1437TR::Node *callNode = snippet->getNode();14381439printSnippetLabel(pOutFile, snippet->getSnippetLabel(), cursor, "Virtual Unresolved Call Snippet");14401441char *info = "";1442int32_t distance;1443if (isBranchToTrampoline(_cg->getSymRef(TR_PPCvirtualUnresolvedHelper), cursor, distance))1444info = " Through trampoline";14451446printPrefix(pOutFile, NULL, cursor, 4);1447distance = *((int32_t *) cursor) & 0x03fffffc;1448distance = (distance << 6) >> 6; // sign extend1449trfprintf(pOutFile, "bl \t" POINTER_PRINTF_FORMAT "\t\t;%s", (intptr_t)cursor + distance, info);1450cursor += 4;14511452printPrefix(pOutFile, NULL, cursor, 4);1453distance = *((int32_t *) cursor) & 0x03fffffc;1454distance = (distance << 6) >> 6; // sign extend1455trfprintf(pOutFile, "b \t" POINTER_PRINTF_FORMAT "\t\t; Back to program code", (intptr_t)cursor + distance);1456cursor += 4;14571458printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1459trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Call Site RA", (intptr_t)snippet->getReturnLabel()->getCodeLocation());1460cursor += sizeof(intptr_t);14611462printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1463trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Constant Pool Pointer", (intptr_t)getOwningMethod(callNode->getSymbolReference())->constantPool());1464cursor += sizeof(intptr_t);14651466printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1467trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Constant Pool Index", callNode->getSymbolReference()->getCPIndexForVM());1468cursor += sizeof(intptr_t);14691470printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1471trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Private J9Method pointer", *(intptr_t *)cursor);1472cursor += sizeof(intptr_t);14731474printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1475trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; J2I thunk address for private", *(intptr_t *)cursor);1476cursor += sizeof(intptr_t);14771478printPrefix(pOutFile, NULL, cursor, 4);1479trfprintf(pOutFile, ".long \t0x%08x\t\t; Lock Word For Resolution", *(int32_t *)cursor);1480}14811482void1483TR_Debug::print(TR::FILE *pOutFile, TR::PPCInterfaceCallSnippet * snippet)1484{1485uint8_t *cursor = snippet->getSnippetLabel()->getCodeLocation();1486TR::Node *callNode = snippet->getNode();14871488printSnippetLabel(pOutFile, snippet->getSnippetLabel(), cursor, "Interface Call Snippet");14891490char *info = "";1491int32_t distance;1492if (isBranchToTrampoline(_cg->getSymRef(TR_PPCinterfaceCallHelper), cursor, distance))1493info = " Through trampoline";14941495printPrefix(pOutFile, NULL, cursor, 4);1496distance = *((int32_t *) cursor) & 0x03fffffc;1497distance = (distance << 6) >> 6; // sign extend1498trfprintf(pOutFile, "bl \t" POINTER_PRINTF_FORMAT "\t\t;%s", (intptr_t)cursor + distance, info);1499cursor += 4;15001501printPrefix(pOutFile, NULL, cursor, 4);1502distance = *((int32_t *) cursor) & 0x03fffffc;1503distance = (distance << 6) >> 6; // sign extend1504trfprintf(pOutFile, "b \t" POINTER_PRINTF_FORMAT "\t\t; Back to program code", (intptr_t)cursor + distance);1505cursor += 4;15061507if (_comp->target().is64Bit())1508{1509printPrefix(pOutFile, NULL, cursor, 4);1510trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Padding", *(int32_t *)cursor);1511cursor += 4;1512}15131514printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1515trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Constant Pool Pointer", *(uintptr_t*)cursor);1516cursor += sizeof(intptr_t);15171518printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1519trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Constant Pool Index", *(uintptr_t*)cursor);1520cursor += sizeof(intptr_t);15211522printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1523trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Interface Class Pointer", *(uintptr_t*)cursor);1524cursor += sizeof(intptr_t);15251526printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1527trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; ITable Index", *(uintptr_t*)cursor);1528cursor += sizeof(intptr_t);15291530printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1531trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; First Class Pointer", *(int32_t *)cursor);1532cursor += sizeof(intptr_t);15331534printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1535trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; First Class Target", *(int32_t *)cursor);1536cursor += sizeof(intptr_t);15371538printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1539trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Second Class Pointer", *(int32_t *)cursor);1540cursor += sizeof(intptr_t);15411542printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1543trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; Second Class Target", *(int32_t *)cursor);1544cursor += sizeof(intptr_t);15451546printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));1547trfprintf(pOutFile, ".long \t" POINTER_PRINTF_FORMAT "\t\t; J2I thunk address for private", *(intptr_t *)cursor);1548}1549155015511552