Path: blob/master/runtime/compiler/aarch64/codegen/CallSnippet.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2019, 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/CallSnippet.hpp"23#include "codegen/ARM64AOTRelocation.hpp"24#include "codegen/ARM64Instruction.hpp"25#include "codegen/CodeGenerator.hpp"26#include "codegen/InstOpCode.hpp"27#include "codegen/Linkage.hpp"28#include "codegen/Linkage_inlines.hpp"29#include "codegen/Machine.hpp"30#include "codegen/Register.hpp"31#include "env/CompilerEnv.hpp"32#include "env/J2IThunk.hpp"33#include "il/LabelSymbol.hpp"34#include "il/Node.hpp"35#include "il/Node_inlines.hpp"3637static uint8_t *storeArgumentItem(TR::InstOpCode::Mnemonic op, uint8_t *buffer, TR::RealRegister *reg, int32_t offset, TR::CodeGenerator *cg)38{39TR::RealRegister *stackPtr = cg->getStackPointerRegister();40TR::InstOpCode opCode(op);41uint32_t enc = (uint32_t)opCode.getOpCodeBinaryEncoding();42TR_ASSERT((enc & 0x3b200000) == 0x39000000, "Instruction not supported in storeArgumentItem()");4344uint32_t size = (enc >> 30) & 3; /* b=0, h=1, w=2, x=3 */45uint32_t shifted = offset >> size;46uint32_t *wcursor = (uint32_t *)buffer;4748opCode.copyBinaryToBuffer(buffer);49reg->setRegisterFieldRT(wcursor);50stackPtr->setRegisterFieldRN(wcursor);51*wcursor |= (shifted & 0xfff) << 10; /* imm12 */5253return buffer+4;54}5556static uint8_t *flushArgumentsToStack(uint8_t *buffer, TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg)57{58uint32_t intArgNum=0, floatArgNum=0, offset;59TR::Machine *machine = cg->machine();60TR::Linkage* linkage = cg->getLinkage(callNode->getSymbol()->castToMethodSymbol()->getLinkageConvention());61const TR::ARM64LinkageProperties &linkageProperties = linkage->getProperties();62int32_t argStart = callNode->getFirstArgumentIndex();6364if (linkageProperties.getRightToLeft())65offset = linkage->getOffsetToFirstParm();66else67offset = argSize+linkage->getOffsetToFirstParm();6869for (int32_t i=argStart; i<callNode->getNumChildren();i++)70{71TR::Node *child = callNode->getChild(i);72switch (child->getDataType())73{74case TR::Int8:75case TR::Int16:76case TR::Int32:77if (!linkageProperties.getRightToLeft())78offset -= TR::Compiler->om.sizeofReferenceAddress();79if (intArgNum < linkageProperties.getNumIntArgRegs())80{81buffer = storeArgumentItem(TR::InstOpCode::strimmw, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);82}83intArgNum++;84if (linkageProperties.getRightToLeft())85offset += TR::Compiler->om.sizeofReferenceAddress();86break;87case TR::Address:88if (!linkageProperties.getRightToLeft())89offset -= TR::Compiler->om.sizeofReferenceAddress();90if (intArgNum < linkageProperties.getNumIntArgRegs())91{92buffer = storeArgumentItem(TR::InstOpCode::strimmx, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);93}94intArgNum++;95if (linkageProperties.getRightToLeft())96offset += TR::Compiler->om.sizeofReferenceAddress();97break;98case TR::Int64:99if (!linkageProperties.getRightToLeft())100offset -= 2*TR::Compiler->om.sizeofReferenceAddress();101if (intArgNum < linkageProperties.getNumIntArgRegs())102{103buffer = storeArgumentItem(TR::InstOpCode::strimmx, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);104}105intArgNum++;106if (linkageProperties.getRightToLeft())107offset += 2*TR::Compiler->om.sizeofReferenceAddress();108break;109case TR::Float:110if (!linkageProperties.getRightToLeft())111offset -= TR::Compiler->om.sizeofReferenceAddress();112if (floatArgNum < linkageProperties.getNumFloatArgRegs())113{114buffer = storeArgumentItem(TR::InstOpCode::vstrimms, buffer, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), offset, cg);115}116floatArgNum++;117if (linkageProperties.getRightToLeft())118offset += TR::Compiler->om.sizeofReferenceAddress();119break;120case TR::Double:121if (!linkageProperties.getRightToLeft())122offset -= 2*TR::Compiler->om.sizeofReferenceAddress();123if (floatArgNum < linkageProperties.getNumFloatArgRegs())124{125buffer = storeArgumentItem(TR::InstOpCode::vstrimmd, buffer, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), offset, cg);126}127floatArgNum++;128if (linkageProperties.getRightToLeft())129offset += 2*TR::Compiler->om.sizeofReferenceAddress();130break;131}132}133134return buffer;135}136137static int32_t instructionCountForArguments(TR::Node *callNode, TR::CodeGenerator *cg)138{139uint32_t intArgNum=0, floatArgNum=0, count=0;140const TR::ARM64LinkageProperties &linkage = cg->getLinkage(callNode->getSymbol()->castToMethodSymbol()->getLinkageConvention())->getProperties();141int32_t argStart = callNode->getFirstArgumentIndex();142143for (int32_t i = argStart; i < callNode->getNumChildren(); i++)144{145TR::Node *child = callNode->getChild(i);146switch (child->getDataType())147{148case TR::Int8:149case TR::Int16:150case TR::Int32:151case TR::Int64:152case TR::Address:153if (intArgNum < linkage.getNumIntArgRegs())154{155count++;156}157intArgNum++;158break;159case TR::Float:160case TR::Double:161if (floatArgNum < linkage.getNumFloatArgRegs())162{163count++;164}165floatArgNum++;166break;167}168}169170return count;171}172173static int32_t174getBLDistance(uint8_t *cursor)175{176// branch distance of BL instruction177int32_t distance;178distance = *((int32_t *)cursor) & 0x03ffffff; // imm26179distance = (distance << 6) >> 4; // sign extend and add two 0 bits180return distance;181}182183TR_RuntimeHelper TR::ARM64CallSnippet::getHelper()184{185TR::Compilation * comp = cg()->comp();186TR::Node *callNode = getNode();187TR::SymbolReference *methodSymRef = callNode->getSymbolReference();188TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();189TR::SymbolReference *glueRef = NULL;190bool isJitInduceOSRCall = false;191if (methodSymbol->isHelper() &&192methodSymRef->isOSRInductionHelper())193{194isJitInduceOSRCall = true;195}196197if (methodSymRef->isUnresolved() || comp->compileRelocatableCode())198{199if (methodSymbol->isSpecial())200return TR_ARM64interpreterUnresolvedSpecialGlue;201if (methodSymbol->isStatic())202return TR_ARM64interpreterUnresolvedStaticGlue;203return TR_ARM64interpreterUnresolvedDirectVirtualGlue;204}205206if (methodSymbol->isVMInternalNative() || methodSymbol->isJITInternalNative())207return TR_ARM64nativeStaticHelper;208209if (isJitInduceOSRCall)210return (TR_RuntimeHelper) methodSymRef->getReferenceNumber();211212bool synchronised = methodSymbol->isSynchronised();213214TR::DataType dataType = callNode->getDataType();215switch (dataType)216{217case TR::NoType:218return synchronised ? TR_ARM64interpreterSyncVoidStaticGlue : TR_ARM64interpreterVoidStaticGlue;219case TR::Int32:220return synchronised ? TR_ARM64interpreterSyncIntStaticGlue : TR_ARM64interpreterIntStaticGlue;221case TR::Int64:222case TR::Address:223return synchronised ? TR_ARM64interpreterSyncLongStaticGlue : TR_ARM64interpreterLongStaticGlue;224case TR::Float:225return synchronised ? TR_ARM64interpreterSyncFloatStaticGlue : TR_ARM64interpreterFloatStaticGlue;226case TR::Double:227return synchronised ? TR_ARM64interpreterSyncDoubleStaticGlue : TR_ARM64interpreterDoubleStaticGlue;228default:229TR_ASSERT_FATAL(false, "Bad return data type '%s' for a call node.\n",230cg()->getDebug()->getName(dataType));231return (TR_RuntimeHelper)0;232}233}234235uint8_t *TR::ARM64CallSnippet::emitSnippetBody()236{237uint8_t *cursor = cg()->getBinaryBufferCursor();238TR::Node *callNode = getNode();239TR::SymbolReference *methodSymRef = callNode->getSymbolReference();240TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();241TR::SymbolReference *glueRef;242TR::Compilation *comp = cg()->comp();243void *trmpln = NULL;244245getSnippetLabel()->setCodeLocation(cursor);246247// Flush in-register arguments back to the stack for interpreter248cursor = flushArgumentsToStack(cursor, callNode, getSizeOfArguments(), cg());249250glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(getHelper());251252// 'b glueRef' for jitInduceOSRAtCurrentPC, 'bl glueRef' otherwise253// 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.254*(int32_t *)cursor = cg()->encodeHelperBranchAndLink(glueRef, cursor, callNode, glueRef->isOSRInductionHelper());255cursor += 4;256257// Store the code cache RA258*(intptr_t *)cursor = (intptr_t)getCallRA();259cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(260cursor,261NULL,262TR_AbsoluteMethodAddress, cg()),263__FILE__, __LINE__, getNode());264cursor += 8;265266//induceOSRAtCurrentPC is implemented in the VM, and it knows, by looking at the current PC, what method it needs to267//continue execution in interpreted mode. Therefore, it doesn't need the method pointer.268if (!glueRef->isOSRInductionHelper())269{270// Store the method pointer: it is NULL for unresolved271if (methodSymRef->isUnresolved() || comp->compileRelocatableCode())272{273*(intptr_t *)cursor = 0;274if (comp->getOption(TR_EnableHCR))275{276cg()->jitAddPicToPatchOnClassRedefinition((void*)-1, (void *)cursor, true);277cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation((uint8_t *)cursor, NULL,(uint8_t *)needsFullSizeRuntimeAssumption,278TR_HCR, cg()),279__FILE__, __LINE__, getNode());280}281}282else283{284*(intptr_t *)cursor = (intptr_t)methodSymbol->getMethodAddress();285if (comp->getOption(TR_EnableHCR))286{287cg()->jitAddPicToPatchOnClassRedefinition((void *)methodSymbol->getMethodAddress(), (void *)cursor);288cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, (uint8_t *)methodSymRef,289getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,290TR_MethodObject, cg()),291__FILE__, __LINE__, callNode);292}293}294}295cursor += 8;296297// Lock word initialized to 0298*(int32_t *)cursor = 0;299300return cursor+4;301}302303static void304printArgumentFlush(TR_Debug *debug, TR::FILE *pOutFile, uint8_t *cursor, const char *mnemonic, uint32_t offset, TR::Register *reg, TR::Register *stackReg)305{306debug->printPrefix(pOutFile, NULL, cursor, 4);307trfprintf(pOutFile, "%s \t", mnemonic);308debug->print(pOutFile, reg, TR_WordReg);309trfprintf(pOutFile, ", [");310debug->print(pOutFile, stackReg, TR_WordReg);311trfprintf(pOutFile, ", %d]", offset);312}313314uint8_t *315TR_Debug::printARM64ArgumentsFlush(TR::FILE *pOutFile, TR::Node *callNode, uint8_t *cursor, int32_t argSize)316{317uint32_t intArgNum=0, floatArgNum=0, offset;318TR::Machine *machine = _cg->machine();319TR::Linkage* linkage = _cg->getLinkage(callNode->getSymbol()->castToMethodSymbol()->getLinkageConvention());320const TR::ARM64LinkageProperties &linkageProperties = linkage->getProperties();321int32_t argStart = callNode->getFirstArgumentIndex();322TR::RealRegister *stackPtr = _cg->getStackPointerRegister();323324if (linkageProperties.getRightToLeft())325offset = linkage->getOffsetToFirstParm();326else327offset = argSize+linkage->getOffsetToFirstParm();328329for (int32_t i=argStart; i<callNode->getNumChildren();i++)330{331TR::Node *child = callNode->getChild(i);332switch (child->getDataType())333{334case TR::Int8:335case TR::Int16:336case TR::Int32:337if (!linkageProperties.getRightToLeft())338offset -= TR::Compiler->om.sizeofReferenceAddress();339if (intArgNum < linkageProperties.getNumIntArgRegs())340{341printArgumentFlush(this, pOutFile, cursor, "strimmw", offset, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), stackPtr);342cursor += 4;343}344intArgNum++;345if (linkageProperties.getRightToLeft())346offset += TR::Compiler->om.sizeofReferenceAddress();347break;348case TR::Address:349if (!linkageProperties.getRightToLeft())350offset -= TR::Compiler->om.sizeofReferenceAddress();351if (intArgNum < linkageProperties.getNumIntArgRegs())352{353printArgumentFlush(this, pOutFile, cursor, "strimmx", offset, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), stackPtr);354cursor += 4;355}356intArgNum++;357if (linkageProperties.getRightToLeft())358offset += TR::Compiler->om.sizeofReferenceAddress();359break;360case TR::Int64:361if (!linkageProperties.getRightToLeft())362offset -= 2*TR::Compiler->om.sizeofReferenceAddress();363if (intArgNum < linkageProperties.getNumIntArgRegs())364{365printArgumentFlush(this, pOutFile, cursor, "strimmx", offset, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), stackPtr);366cursor += 4;367}368intArgNum++;369if (linkageProperties.getRightToLeft())370offset += 2*TR::Compiler->om.sizeofReferenceAddress();371break;372case TR::Float:373if (!linkageProperties.getRightToLeft())374offset -= TR::Compiler->om.sizeofReferenceAddress();375if (floatArgNum < linkageProperties.getNumFloatArgRegs())376{377printArgumentFlush(this, pOutFile, cursor, "vstrimms", offset, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), stackPtr);378cursor += 4;379}380floatArgNum++;381if (linkageProperties.getRightToLeft())382offset += TR::Compiler->om.sizeofReferenceAddress();383break;384case TR::Double:385if (!linkageProperties.getRightToLeft())386offset -= 2*TR::Compiler->om.sizeofReferenceAddress();387if (floatArgNum < linkageProperties.getNumFloatArgRegs())388{389printArgumentFlush(this, pOutFile, cursor, "vstrimmd", offset, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), stackPtr);390cursor += 4;391}392floatArgNum++;393if (linkageProperties.getRightToLeft())394offset += 2*TR::Compiler->om.sizeofReferenceAddress();395break;396397default:398TR_ASSERT_FATAL(false, "Unknown argument type %d", child->getDataType());399break;400}401}402return cursor;403}404405void406TR_Debug::print(TR::FILE *pOutFile, TR::ARM64CallSnippet *snippet)407{408TR::Node *callNode = snippet->getNode();409TR::SymbolReference *glueRef = _cg->getSymRef(snippet->getHelper());410TR::SymbolReference *methodSymRef = callNode->getSymbolReference();411TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();412413uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();414printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet), getName(methodSymRef));415416bufferPos = printARM64ArgumentsFlush(pOutFile, callNode, bufferPos, snippet->getSizeOfArguments());417418char *info = "";419intptr_t target = reinterpret_cast<intptr_t>(glueRef->getMethodAddress());420int32_t distance;421if (isBranchToTrampoline(glueRef, bufferPos, distance))422{423target = static_cast<intptr_t>(distance) + reinterpret_cast<intptr_t>(bufferPos);424info = " Through trampoline";425TR_ASSERT_FATAL(constantIsSignedImm28(distance), "Trampoline too far away.");426}427428printPrefix(pOutFile, NULL, bufferPos, 4);429trfprintf(pOutFile, "%s \t" POINTER_PRINTF_FORMAT "\t\t; %s%s", (glueRef->isOSRInductionHelper() ? "b" : "bl"), target, getName(glueRef), info);430bufferPos += 4;431432printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));433trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Code cache return address", snippet->getCallRA());434bufferPos += sizeof(intptr_t);435436if (!glueRef->isOSRInductionHelper())437{438printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));439trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Method Pointer", *(reinterpret_cast<uintptr_t *>(bufferPos)));440bufferPos += sizeof(intptr_t);441}442443printPrefix(pOutFile, NULL, bufferPos, 4);444trfprintf(pOutFile, ".word \t0x%08x\t\t; Lock Word For Compilation", *(reinterpret_cast<int32_t *>(bufferPos)));445}446447uint32_t TR::ARM64CallSnippet::getLength(int32_t estimatedSnippetStart)448{449return (instructionCountForArguments(getNode(), cg()) + 6) * 4;450}451452uint8_t *TR::ARM64VirtualSnippet::emitSnippetBody()453{454return NULL;455}456457uint32_t TR::ARM64VirtualSnippet::getLength(int32_t estimatedSnippetStart)458{459return 0;460}461462uint8_t *TR::ARM64UnresolvedCallSnippet::emitSnippetBody()463{464uint8_t *cursor = TR::ARM64CallSnippet::emitSnippetBody();465466TR::SymbolReference *methodSymRef = getNode()->getSymbolReference();467TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();468intptr_t helperLookupOffset;469470TR::Compilation* comp = cg()->comp();471472// CP473*(intptr_t *)cursor = (intptr_t)methodSymRef->getOwningMethod(comp)->constantPool();474475if (comp->compileRelocatableCode() && comp->getOption(TR_TraceRelocatableDataDetailsCG))476{477traceMsg(comp, "<relocatableDataTrampolinesCG>\n");478traceMsg(comp, "%s\n", comp->signature());479traceMsg(comp, "%-8s", "cpIndex");480traceMsg(comp, "cp\n");481traceMsg(comp, "%-8x", methodSymRef->getCPIndexForVM());482traceMsg(comp, "%x\n", methodSymRef->getOwningMethod(comp)->constantPool());483traceMsg(comp, "</relocatableDataTrampolinesCG>\n");484}485486cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(487cursor,488*(uint8_t **)cursor,489getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,490TR_Trampolines, cg()),491__FILE__, __LINE__, getNode());492cursor += 8;493494switch (getNode()->getDataType())495{496case TR::NoType:497helperLookupOffset = 0;498break;499case TR::Int32:500helperLookupOffset = 8;501break;502case TR::Int64:503case TR::Address:504helperLookupOffset = 16;505break;506case TR::Float:507helperLookupOffset = 24;508break;509case TR::Double:510helperLookupOffset = 32;511break;512}513514// CP index and helper offset515*(intptr_t *)cursor = (helperLookupOffset<<56) | methodSymRef->getCPIndexForVM();516517return cursor + 8;518}519520void521TR_Debug::print(TR::FILE *pOutFile, TR::ARM64UnresolvedCallSnippet *snippet)522{523print(pOutFile, (TR::ARM64CallSnippet *) snippet);524525uint8_t *cursor = snippet->getSnippetLabel()->getCodeLocation() + snippet->getLength(0) - (sizeof(intptr_t) * 2);526527TR::SymbolReference *methodSymRef = snippet->getNode()->getSymbolReference();528TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();529530intptr_t helperLookupOffset;531switch (snippet->getNode()->getDataType())532{533case TR::NoType:534helperLookupOffset = 0;535break;536case TR::Int32:537helperLookupOffset = 8;538break;539case TR::Int64:540case TR::Address:541helperLookupOffset = 16;542break;543case TR::Float:544helperLookupOffset = 24;545break;546case TR::Double:547helperLookupOffset = 32;548break;549}550551printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));552trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Pointer To Constant Pool", *(reinterpret_cast<intptr_t *>(cursor)));553cursor += sizeof(intptr_t);554555printPrefix(pOutFile, NULL, cursor, 8);556trfprintf(pOutFile,557".dword \t%016llx\t\t; Offset | Flag | CP Index",558(helperLookupOffset << 56) | methodSymRef->getCPIndexForVM());559cursor += 8;560}561562uint32_t TR::ARM64UnresolvedCallSnippet::getLength(int32_t estimatedSnippetStart)563{564return TR::ARM64CallSnippet::getLength(estimatedSnippetStart) + 16;565}566567uint8_t *TR::ARM64VirtualUnresolvedSnippet::emitSnippetBody()568{569TR::Compilation* comp = cg()->comp();570uint8_t *cursor = cg()->getBinaryBufferCursor();571TR::Node *callNode = getNode();572TR::SymbolReference *methodSymRef = callNode->getSymbolReference();573TR::SymbolReference *glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_ARM64virtualUnresolvedHelper);574TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());575void *thunk = fej9->getJ2IThunk(callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->getMethod(), comp);576577// for alignment of intptr_t data578if (((uint64_t)cursor % sizeof(intptr_t)) == 0)579{580*(int32_t *)cursor = 0xdeadc0de;581cursor += sizeof(int32_t);582}583584getSnippetLabel()->setCodeLocation(cursor);585586// bl glueRef587*(int32_t *)cursor = cg()->encodeHelperBranchAndLink(glueRef, cursor, callNode);588cursor += ARM64_INSTRUCTION_LENGTH;589TR_ASSERT(((uint64_t)cursor % sizeof(intptr_t)) == 0, "Snippet data is not aligned");590591// Store the code cache RA592*(intptr_t *)cursor = (intptr_t)getReturnLabel()->getCodeLocation();593cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(594cursor,595NULL,596TR_AbsoluteMethodAddress, cg()),597__FILE__, __LINE__, callNode);598cursor += sizeof(intptr_t);599600// CP601intptr_t cpAddr = (intptr_t)methodSymRef->getOwningMethod(comp)->constantPool();602*(intptr_t *)cursor = cpAddr;603uint8_t *j2iThunkRelocationPoint = cursor;604cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(605cursor,606*(uint8_t **)cursor,607getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,608TR_Thunks, cg()),609__FILE__, __LINE__, getNode());610cursor += sizeof(intptr_t);611612// CP index613*(intptr_t *)cursor = methodSymRef->getCPIndexForVM();614cursor += sizeof(intptr_t);615616// Reserved spot to hold J9Method pointer of the callee617// This is used for private nestmate calls618// Initial value is 0619*(intptr_t *)cursor = 0;620cursor += sizeof(intptr_t);621622// J2I thunk address623// This is used for private nestmate calls624*(intptr_t*)cursor = (intptr_t)thunk;625626auto info =627(TR_RelocationRecordInformation *)comp->trMemory()->allocateMemory(628sizeof (TR_RelocationRecordInformation),629heapAlloc);630631// data1 = constantPool632info->data1 = cpAddr;633634// data2 = inlined site index635info->data2 = callNode ? callNode->getInlinedSiteIndex() : (uintptr_t)-1;636637// data3 = distance in bytes from Constant Pool Pointer to J2I Thunk638info->data3 = (intptr_t)cursor - (intptr_t)j2iThunkRelocationPoint;639640cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(641j2iThunkRelocationPoint,642(uint8_t *)info,643NULL,644TR_J2IVirtualThunkPointer, cg()),645__FILE__, __LINE__, callNode);646647cursor += sizeof(intptr_t);648649// Lock word650*(int32_t *)cursor = 0;651652return cursor + sizeof(int32_t);653}654655void656TR_Debug::print(TR::FILE *pOutFile, TR::ARM64VirtualUnresolvedSnippet * snippet)657{658TR::SymbolReference *callSymRef = snippet->getNode()->getSymbolReference();659uint8_t *cursor = snippet->getSnippetLabel()->getCodeLocation();660661printSnippetLabel(pOutFile, snippet->getSnippetLabel(), cursor, getName(snippet), getName(callSymRef));662663int32_t distance = getBLDistance(cursor);664printPrefix(pOutFile, NULL, cursor, ARM64_INSTRUCTION_LENGTH);665trfprintf(pOutFile, "bl \t" POINTER_PRINTF_FORMAT "\t\t; %s",666(intptr_t)cursor + distance, getRuntimeHelperName(TR_ARM64virtualUnresolvedHelper));667cursor += ARM64_INSTRUCTION_LENGTH;668669printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));670trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Code cache return address", *(intptr_t *)cursor);671cursor += sizeof(intptr_t);672673printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));674trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Constant pool address", *(intptr_t *)cursor);675cursor += sizeof(intptr_t);676677printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));678trfprintf(pOutFile, ".dword \t0x%08x\t\t; cpIndex", *(intptr_t *)cursor);679cursor += sizeof(intptr_t);680681printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));682trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Private J9Method pointer", *(intptr_t *)cursor);683cursor += sizeof(intptr_t);684685printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));686trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; J2I thunk address for private", *(intptr_t *)cursor);687cursor += sizeof(intptr_t);688689printPrefix(pOutFile, NULL, cursor, sizeof(int32_t));690trfprintf(pOutFile, ".word \t0x%08x\t\t; Lock Word For Resolution", *(int32_t *)cursor);691}692693uint32_t TR::ARM64VirtualUnresolvedSnippet::getLength(int32_t estimatedSnippetStart)694{695/*696* (1 word for alignment)697* 1 instruction698* 5 address fields:699* - Code cache RA700* - CP pointer701* - CP index702* - Private J9Method pointer703* - J2I thunk address704* 1 lock word705*/706return ARM64_INSTRUCTION_LENGTH + sizeof(intptr_t)*5 + sizeof(int32_t)*2;707}708709uint8_t *TR::ARM64InterfaceCallSnippet::emitSnippetBody()710{711TR::Compilation *comp = cg()->comp();712uint8_t *cursor = cg()->getBinaryBufferCursor();713uint8_t *blAddress;714TR::Node *callNode = getNode();715TR::SymbolReference *methodSymRef = getNode()->getSymbolReference();716TR::SymbolReference *glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_ARM64interfaceCallHelper);717TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(comp->fe());718void* thunk = fej9->getJ2IThunk(callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->getMethod(), comp);719720// for alignment of intptr_t data721if ((reinterpret_cast<uint64_t>(cursor) % sizeof(intptr_t)) == 0)722{723*reinterpret_cast<int32_t *>(cursor) = 0xdeadc0de;724cursor += sizeof(int32_t);725}726727getSnippetLabel()->setCodeLocation(cursor);728729// bl glueRef730*reinterpret_cast<uint32_t *>(cursor) = cg()->encodeHelperBranchAndLink(glueRef, cursor, callNode);731blAddress = cursor;732cursor += ARM64_INSTRUCTION_LENGTH;733TR_ASSERT_FATAL((reinterpret_cast<uint64_t>(cursor) % sizeof(intptr_t)) == 0, "Snippet data is not aligned");734735// Store the code cache RA736*(intptr_t *)cursor = (intptr_t)getReturnLabel()->getCodeLocation();737cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(738cursor,739NULL,740TR_AbsoluteMethodAddress, cg()),741__FILE__, __LINE__, callNode);742cursor += sizeof(intptr_t);743744// CP745intptr_t cpAddr = reinterpret_cast<intptr_t>(methodSymRef->getOwningMethod(comp)->constantPool());746*reinterpret_cast<intptr_t *>(cursor) = cpAddr;747uint8_t *j2iThunkRelocationPoint = cursor;748cursor += sizeof(intptr_t);749750// CP index751*reinterpret_cast<intptr_t *>(cursor) = methodSymRef->getCPIndexForVM();752cursor += sizeof(intptr_t);753754// 2 slots for resolved values (interface class and iTable index)755*reinterpret_cast<intptr_t *>(cursor) = 0;756cursor += sizeof(intptr_t);757*reinterpret_cast<intptr_t *>(cursor) = 0;758cursor += sizeof(intptr_t);759760_firstClassCacheSlotLabel->setCodeLocation(cursor);761_firstBranchAddressCacheSlotLabel->setCodeLocation(cursor + sizeof(intptr_t));762_secondClassCacheSlotLabel->setCodeLocation(cursor + 2*sizeof(intptr_t));763_secondBranchAddressCacheSlotLabel->setCodeLocation(cursor + 3*sizeof(intptr_t));764// Initialize for: two class ptrs, two target addrs765// Initialize target addrs with the address of the bl766*reinterpret_cast<intptr_t *>(cursor) = -1;767*reinterpret_cast<intptr_t *>(cursor + sizeof(intptr_t)) = reinterpret_cast<intptr_t>(blAddress);768*reinterpret_cast<intptr_t *>(cursor + 2*sizeof(intptr_t)) = -1;769*reinterpret_cast<intptr_t *>(cursor + 3*sizeof(intptr_t)) = reinterpret_cast<intptr_t>(blAddress);770771// Register for relocation of the 1st target address772cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor + sizeof(intptr_t), NULL, TR_AbsoluteMethodAddress, cg()),773__FILE__, __LINE__, callNode);774775// Register for relocation of the 2nd target address776cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor + 3*sizeof(intptr_t), NULL, TR_AbsoluteMethodAddress, cg()),777__FILE__, __LINE__, callNode);778779cursor += 4*sizeof(intptr_t);780781/*782* J2I thunk address.783* This is used for private nestmate calls.784*/785*reinterpret_cast<intptr_t*>(cursor) = reinterpret_cast<intptr_t>(thunk);786if (comp->compileRelocatableCode())787{788auto info =789(TR_RelocationRecordInformation *)comp->trMemory()->allocateMemory(790sizeof(TR_RelocationRecordInformation),791heapAlloc);792793// data1 = constantPool794info->data1 = cpAddr;795796// data2 = inlined site index797info->data2 = callNode ? callNode->getInlinedSiteIndex() : static_cast<uintptr_t>(-1);798799// data3 = distance in bytes from Constant Pool Pointer to J2I Thunk800info->data3 = reinterpret_cast<intptr_t>(cursor) - reinterpret_cast<intptr_t>(j2iThunkRelocationPoint);801802cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(803j2iThunkRelocationPoint,804reinterpret_cast<uint8_t *>(info),805NULL,806TR_J2IVirtualThunkPointer, cg()),807__FILE__, __LINE__, callNode);808}809cursor += sizeof(intptr_t);810811return cursor;812}813814void815TR_Debug::print(TR::FILE *pOutFile, TR::ARM64InterfaceCallSnippet * snippet)816{817TR::SymbolReference *callSymRef = snippet->getNode()->getSymbolReference();818uint8_t *cursor = snippet->getSnippetLabel()->getCodeLocation();819820printSnippetLabel(pOutFile, snippet->getSnippetLabel(), cursor, getName(snippet), getName(callSymRef));821822int32_t distance = getBLDistance(cursor);823printPrefix(pOutFile, NULL, cursor, ARM64_INSTRUCTION_LENGTH);824trfprintf(pOutFile, "bl \t" POINTER_PRINTF_FORMAT "\t\t; %s",825(intptr_t)cursor + distance, getRuntimeHelperName(TR_ARM64interfaceCallHelper));826cursor += ARM64_INSTRUCTION_LENGTH;827828printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));829trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Code cache return address", *(intptr_t *)cursor);830cursor += sizeof(intptr_t);831832printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));833trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Constant pool address", *(intptr_t *)cursor);834cursor += sizeof(intptr_t);835836printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));837trfprintf(pOutFile, ".dword \t0x%08x\t\t; cpIndex", *(intptr_t *)cursor);838cursor += sizeof(intptr_t);839840printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));841trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Interface class", *(intptr_t *)cursor);842cursor += sizeof(intptr_t);843844printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));845trfprintf(pOutFile, ".dword \t0x%08x\t\t; itable index", *(intptr_t *)cursor);846cursor += sizeof(intptr_t);847848printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));849trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; First Class Pointer", *(intptr_t *)cursor);850cursor += sizeof(intptr_t);851852printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));853trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; First Class Target", *(intptr_t *)cursor);854cursor += sizeof(intptr_t);855856printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));857trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Second Class Pointer", *(intptr_t *)cursor);858cursor += sizeof(intptr_t);859860printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));861trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Second Class Target", *(intptr_t *)cursor);862cursor += sizeof(intptr_t);863864printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));865trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; J2I thunk address for private", *(intptr_t *)cursor);866}867868uint32_t TR::ARM64InterfaceCallSnippet::getLength(int32_t estimatedSnippetStart)869{870/*871* (1 word for alignment)872* 1 instruction873* 10 address fields:874* - Code cache RA875* - CP Pointer876* - CP Index877* - Interface Class Pointer878* - ITable Index (may also contain a tagged J9Method* when handling nestmates)879* - First Class Pointer880* - First Class Target881* - Second Class Pointer882* - Second Class Target883* - J2I thunk address884*/885return ARM64_INSTRUCTION_LENGTH + sizeof(intptr_t)*10 + sizeof(int32_t);886}887888uint8_t *TR::ARM64CallSnippet::generateVIThunk(TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg)889{890int32_t codeSize = 4 * (instructionCountForArguments(callNode, cg) + 5) + 8; // 5 instructions for branch, Additional 8 bytes to hold size of thunk891uint8_t *thunk, *buffer, *returnValue;892uintptr_t dispatcher;893894if (cg->comp()->compileRelocatableCode())895thunk = (uint8_t *)cg->comp()->trMemory()->allocateMemory(codeSize, heapAlloc);896else897thunk = (uint8_t *)cg->allocateCodeMemory(codeSize, true, false);898buffer = returnValue = thunk + 8;899TR_RuntimeHelper helper;900TR::DataType dataType = callNode->getDataType();901902switch (dataType)903{904case TR::NoType:905helper = TR_ARM64icallVMprJavaSendVirtual0;906break;907case TR::Int32:908helper = TR_ARM64icallVMprJavaSendVirtual1;909break;910case TR::Int64:911case TR::Address:912helper = TR_ARM64icallVMprJavaSendVirtualJ;913break;914case TR::Float:915helper = TR_ARM64icallVMprJavaSendVirtualF;916break;917case TR::Double:918helper = TR_ARM64icallVMprJavaSendVirtualD;919break;920default:921TR_ASSERT_FATAL(false, "Bad return data type '%s' for a call node.\n",922cg->getDebug()->getName(dataType));923}924925#if defined(OSX)926pthread_jit_write_protect_np(0);927#endif928929dispatcher = (uintptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(helper)->getMethodAddress();930931buffer = flushArgumentsToStack(buffer, callNode, argSize, cg);932933TR::RealRegister *x15reg = cg->machine()->getRealRegister(TR::RealRegister::x15);934935*((int32_t *)thunk + 1) = buffer - returnValue; // patch offset for AOT relocation936// movz x15, low 16 bits937*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movzx) | ((dispatcher & 0xFFFF) << 5);938x15reg->setRegisterFieldRD((uint32_t *)buffer);939buffer += ARM64_INSTRUCTION_LENGTH;940// movk x15, next 16 bits, lsl #16941*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL16 << 5) | (((dispatcher >> 16) & 0xFFFF) << 5);942x15reg->setRegisterFieldRD((uint32_t *)buffer);943buffer += ARM64_INSTRUCTION_LENGTH;944// movk x15, next 16 bits, lsl #32945*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL32 << 5) | (((dispatcher >> 32) & 0xFFFF) << 5);946x15reg->setRegisterFieldRD((uint32_t *)buffer);947buffer += ARM64_INSTRUCTION_LENGTH;948// movk x15, next 16 bits, lsl #48949*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL48 << 5) | (((dispatcher >> 48) & 0xFFFF) << 5);950x15reg->setRegisterFieldRD((uint32_t *)buffer);951buffer += ARM64_INSTRUCTION_LENGTH;952// br x15953*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::br);954x15reg->setRegisterFieldRN((uint32_t *)buffer);955buffer += ARM64_INSTRUCTION_LENGTH;956957*(int32_t *)thunk = buffer - returnValue; // patch size of thunk958959#ifdef TR_HOST_ARM64960arm64CodeSync(thunk, codeSize);961#endif962963#if defined(OSX)964pthread_jit_write_protect_np(1);965#endif966967return returnValue;968}969970TR_J2IThunk *TR::ARM64CallSnippet::generateInvokeExactJ2IThunk(TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg, char *signature)971{972int32_t codeSize = 4 * (instructionCountForArguments(callNode, cg) + 5); // 5 instructions for branch973uintptr_t dispatcher;974TR::Compilation *comp = cg->comp();975TR_J2IThunkTable *thunkTable = comp->getPersistentInfo()->getInvokeExactJ2IThunkTable();976TR_J2IThunk *thunk = TR_J2IThunk::allocate(codeSize, signature, cg, thunkTable);977uint8_t *buffer = thunk->entryPoint();978979TR_RuntimeHelper helper;980TR::DataType dataType = callNode->getDataType();981982switch (dataType)983{984case TR::NoType:985helper = TR_icallVMprJavaSendInvokeExact0;986break;987case TR::Int32:988helper = TR_icallVMprJavaSendInvokeExact1;989break;990case TR::Int64:991case TR::Address:992helper = TR_icallVMprJavaSendInvokeExactJ;993break;994case TR::Float:995helper = TR_icallVMprJavaSendInvokeExactF;996break;997case TR::Double:998helper = TR_icallVMprJavaSendInvokeExactD;999break;1000default:1001TR_ASSERT(false, "Bad return data type '%s' for a call node.\n",1002cg->getDebug()->getName(dataType));1003}10041005#if defined(OSX)1006pthread_jit_write_protect_np(0);1007#endif10081009dispatcher = (intptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(helper)->getMethodAddress();10101011buffer = flushArgumentsToStack(buffer, callNode, argSize, cg);10121013TR::RealRegister *x15reg = cg->machine()->getRealRegister(TR::RealRegister::x15);10141015// movz x15, low 16 bits1016*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movzx) | ((dispatcher & 0xFFFF) << 5);1017x15reg->setRegisterFieldRD((uint32_t *)buffer);1018buffer += ARM64_INSTRUCTION_LENGTH;1019// movk x15, next 16 bits, lsl #161020*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL16 << 5) | (((dispatcher >> 16) & 0xFFFF) << 5);1021x15reg->setRegisterFieldRD((uint32_t *)buffer);1022buffer += ARM64_INSTRUCTION_LENGTH;1023// movk x15, next 16 bits, lsl #321024*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL32 << 5) | (((dispatcher >> 32) & 0xFFFF) << 5);1025x15reg->setRegisterFieldRD((uint32_t *)buffer);1026buffer += ARM64_INSTRUCTION_LENGTH;1027// movk x15, next 16 bits, lsl #481028*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL48 << 5) | (((dispatcher >> 48) & 0xFFFF) << 5);1029x15reg->setRegisterFieldRD((uint32_t *)buffer);1030buffer += ARM64_INSTRUCTION_LENGTH;1031// br x151032*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::br);1033x15reg->setRegisterFieldRN((uint32_t *)buffer);1034buffer += ARM64_INSTRUCTION_LENGTH;10351036#ifdef TR_HOST_ARM641037arm64CodeSync(thunk->entryPoint(), codeSize);1038#endif10391040#if defined(OSX)1041pthread_jit_write_protect_np(1);1042#endif10431044return thunk;1045}1046104710481049