Path: blob/master/runtime/compiler/arm/codegen/CallSnippet.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2000, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "codegen/CallSnippet.hpp"23#include "codegen/Linkage.hpp"24#include "codegen/Linkage_inlines.hpp"25#include "codegen/Machine.hpp"26#include "codegen/Register.hpp"27#include "codegen/ARMAOTRelocation.hpp"28#include "env/CompilerEnv.hpp"29#include "env/J2IThunk.hpp"30#include "env/VMJ9.h"31#include "codegen/CodeGenerator.hpp" /* @@@@ */32#include "il/Node.hpp"33#include "il/Node_inlines.hpp"3435#define TR_ARM_ARG_SLOT_SIZE 43637static uint8_t *flushArgumentsToStack(uint8_t *buffer, TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg)38{39uint32_t intArgNum=0, floatArgNum=0, offset;40TR::Machine *machine = cg->machine();41TR::Linkage* linkage = cg->getLinkage(callNode->getSymbol()->castToMethodSymbol()->getLinkageConvention());42const TR::ARMLinkageProperties &linkageProperties = linkage->getProperties();43int32_t argStart = callNode->getFirstArgumentIndex();4445if (linkageProperties.getRightToLeft())46offset = linkage->getOffsetToFirstParm();47else48offset = argSize+linkage->getOffsetToFirstParm();4950for (int i=argStart; i<callNode->getNumChildren();i++)51{52TR::Node *child = callNode->getChild(i);53switch (child->getDataType())54{55case TR::Int8:56case TR::Int16:57case TR::Int32:58case TR::Address:59#if (defined(__VFP_FP__) && !defined(__SOFTFP__))60case TR::Float:61#endif62if (!linkageProperties.getRightToLeft())63offset -= 4;64if (intArgNum < linkageProperties.getNumIntArgRegs())65{66buffer = storeArgumentItem(TR::InstOpCode::str, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);67}68intArgNum++;69if (linkageProperties.getRightToLeft())70offset += 4;71break;72case TR::Int64:73#if (defined(__VFP_FP__) && !defined(__SOFTFP__))74case TR::Double:75#endif76if (!linkageProperties.getRightToLeft())77offset -= 8;78if (intArgNum < linkageProperties.getNumIntArgRegs())79{80buffer = storeArgumentItem(TR::InstOpCode::str, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);81if (intArgNum < linkageProperties.getNumIntArgRegs()-1)82{83buffer = storeArgumentItem(TR::InstOpCode::str, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum+1)), offset+4, cg);84}85}86intArgNum += 2;87if (linkageProperties.getRightToLeft())88offset += 8;89break;90#if !defined(__VFP_FP__) || defined(__SOFTFP__)91case TR::Float:92/* TODO93if (!linkageProperties.getRightToLeft())94offset -= 4;95if (floatArgNum < linkageProperties.getNumFloatArgRegs())96{97buffer = storeArgumentItem(TR::InstOpCode::stfs, buffer, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), offset, cg);98}99floatArgNum++;100if (linkageProperties.getRightToLeft())101offset += 4;102*/103break;104case TR::Double:105/* TODO106if (!linkageProperties.getRightToLeft())107offset -= 8;108if (floatArgNum < linkageProperties.getNumFloatArgRegs())109{110buffer = storeArgumentItem(TR::InstOpCode::stfd, buffer, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), offset, cg);111}112floatArgNum++;113if (linkageProperties.getRightToLeft())114offset += 8;115*/116break;117#endif118}119}120return(buffer);121}122123static int32_t instructionCountForArguments(TR::Node *callNode, TR::CodeGenerator *cg)124{125uint32_t intArgNum=0, floatArgNum=0, count=0;126const TR::ARMLinkageProperties &linkage = cg->getLinkage(callNode->getSymbol()->castToMethodSymbol()->getLinkageConvention())->getProperties();127int32_t argStart = callNode->getFirstArgumentIndex();128129for (int i=argStart; i<callNode->getNumChildren();i++)130{131TR::Node *child = callNode->getChild(i);132switch (child->getDataType())133{134case TR::Int8:135case TR::Int16:136case TR::Int32:137case TR::Address:138#if (defined(__VFP_FP__) && !defined(__SOFTFP__))139case TR::Float:140#endif141if (intArgNum < linkage.getNumIntArgRegs())142{143count++;144}145intArgNum++;146break;147case TR::Int64:148#if (defined(__VFP_FP__) && !defined(__SOFTFP__))149case TR::Double:150#endif151if (intArgNum < linkage.getNumIntArgRegs())152{153count++;154if (intArgNum < linkage.getNumIntArgRegs()-1)155{156count++;157}158}159intArgNum += 2;160break;161#if !defined(__VFP_FP__) || defined(__SOFTFP__)162case TR::Float:163if (floatArgNum < linkage.getNumFloatArgRegs())164{165count++;166}167floatArgNum++;168break;169case TR::Double:170if (floatArgNum < linkage.getNumFloatArgRegs())171{172count++;173}174floatArgNum++;175break;176#endif177}178}179return(count);180}181182TR_RuntimeHelper183TR::ARMCallSnippet::getHelper()184{185TR::Compilation * comp = cg()->comp();186TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg()->fe());187TR::Node *callNode = getNode();188TR::SymbolReference *methodSymRef = callNode->getSymbolReference();189TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();190TR::SymbolReference *glueRef = NULL;191192if (methodSymRef->isUnresolved() || comp->compileRelocatableCode())193{194if (methodSymbol->isSpecial())195return TR_ARMinterpreterUnresolvedSpecialGlue;196if (methodSymbol->isStatic())197return TR_ARMinterpreterUnresolvedStaticGlue;198return TR_ARMinterpreterUnresolvedDirectVirtualGlue;199}200201bool synchronised = methodSymbol->isSynchronised();202203if (methodSymbol->isVMInternalNative() || methodSymbol->isJITInternalNative())204return TR_ARMnativeStaticHelper;205206TR::DataType dataType = callNode->getDataType();207switch (dataType)208{209case TR::NoType:210if (synchronised)211return TR_ARMinterpreterSyncVoidStaticGlue;212return TR_ARMinterpreterVoidStaticGlue;213214case TR::Int32:215case TR::Address:216#if (defined(__VFP_FP__) && !defined(__SOFTFP__))217case TR::Float:218#endif219if (synchronised)220return TR_ARMinterpreterSyncGPR3StaticGlue;221return TR_ARMinterpreterGPR3StaticGlue;222223case TR::Int64:224#if (defined(__VFP_FP__) && !defined(__SOFTFP__))225case TR::Double:226#endif227if (synchronised)228return TR_ARMinterpreterSyncGPR3GPR4StaticGlue;229return TR_ARMinterpreterGPR3GPR4StaticGlue;230#if !defined(__VFP_FP__) || defined(__SOFTFP__)231case TR::Float:232if (synchronised)233return TR_ARMinterpreterSyncFPR0FStaticGlue;234return TR_ARMinterpreterFPR0FStaticGlue;235236case TR::Double:237if (synchronised)238return TR_ARMinterpreterSyncFPR0DStaticGlue;239return TR_ARMinterpreterFPR0DStaticGlue;240#endif241default:242TR_ASSERT(false, "Bad return data type for a call node. DataType was %s\n",243cg()->getDebug()->getName(dataType));244return (TR_RuntimeHelper)0;245}246}247248uint8_t *TR::ARMCallSnippet::emitSnippetBody()249{250TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg()->fe());251uint8_t *cursor = cg()->getBinaryBufferCursor();252TR::Node *callNode = getNode();253TR::SymbolReference *methodSymRef = callNode->getSymbolReference();254TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();255TR::SymbolReference *glueRef;256TR::Compilation *comp = cg()->comp();257void *trmpln = NULL;258259getSnippetLabel()->setCodeLocation(cursor);260261// Flush in-register arguments back to the stack for interpreter262cursor = flushArgumentsToStack(cursor, callNode, getSizeOfArguments(), cg());263264glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(getHelper());265266// bl glueRef267*(int32_t *)cursor = encodeHelperBranchAndLink(glueRef, cursor, callNode, cg());268cursor += 4;269270// Store the code cache RA271*(int32_t *)cursor = (intptr_t)getCallRA();272cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(273cursor,274NULL,275TR_AbsoluteMethodAddress, cg()), __FILE__, __LINE__, getNode());276cursor += 4;277278// Store the method pointer: it is NULL for unresolved279if (methodSymRef->isUnresolved() || comp->compileRelocatableCode())280{281*(int32_t *)cursor = 0;282if (comp->getOption(TR_EnableHCR))283{284cg()->jitAddPicToPatchOnClassRedefinition((void*)-1, (void *)cursor, true);285cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation((uint8_t *)cursor, NULL,(uint8_t *)needsFullSizeRuntimeAssumption,286TR_HCR, cg()),__FILE__, __LINE__,287getNode());288}289}290else291{292*(int32_t *)cursor = (uintptr_t)methodSymbol->getMethodAddress();293if (comp->getOption(TR_EnableHCR))294cg()->jitAddPicToPatchOnClassRedefinition((void *)methodSymbol->getMethodAddress(), (void *)cursor);295cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, (uint8_t *)methodSymRef,296getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,297TR_MethodObject, cg()),298__FILE__, __LINE__, callNode);299/*300TR_RelocationRecordInformation *recordInfo = ( TR_RelocationRecordInformation *)comp->trMemory()->allocateMemory(sizeof( TR_RelocationRecordInformation), heapAlloc);301recordInfo->data1 = (uintptr_t)methodSymRef;302recordInfo->data2 = (uintptr_t)(getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1);303recordInfo->data3 = (uintptr_t)fixedSequence1;304305cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(306cursor,307(uint8_t *)recordInfo,308TR_MethodObject, cg()), __FILE__, __LINE__, getNode());309*/310}311cursor += TR::Compiler->om.sizeofReferenceAddress();312313// Lock word initialized to 0314*(int32_t *)cursor = 0;315316return (cursor+4);317}318319uint32_t TR::ARMCallSnippet::getLength(int32_t estimatedSnippetStart)320{321return((instructionCountForArguments(getNode(), cg()) + 4) * 4);322}323324325uint8_t *TR::ARMUnresolvedCallSnippet::emitSnippetBody()326{327TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg()->fe());328uint8_t *cursor = TR::ARMCallSnippet::emitSnippetBody();329330TR::SymbolReference *methodSymRef = getNode()->getSymbolReference();331TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();332int32_t helperLookupOffset;333334TR::Compilation* comp = cg()->comp();335336switch (getNode()->getDataType())337{338case TR::NoType:339helperLookupOffset = 0;340break;341case TR::Int32:342case TR::Address:343#if (defined(__VFP_FP__) && !defined(__SOFTFP__))344case TR::Float:345#endif346helperLookupOffset = 4;347break;348case TR::Int64:349#if (defined(__VFP_FP__) && !defined(__SOFTFP__))350case TR::Double:351#endif352helperLookupOffset = 8;353break;354#if !defined(__VFP_FP__) || defined(__SOFTFP__)355case TR::Float:356helperLookupOffset = 12;357break;358case TR::Double:359helperLookupOffset = 16;360break;361#endif362}363364*(int32_t *)cursor = (helperLookupOffset<<24) | methodSymRef->getCPIndexForVM();365cursor += 4;366*(int32_t *)cursor = (intptr_t)methodSymRef->getOwningMethod(comp)->constantPool();367368if (comp->compileRelocatableCode() && comp->getOption(TR_TraceRelocatableDataDetailsCG))369{370traceMsg(comp, "<relocatableDataTrampolinesCG>\n");371traceMsg(comp, "%s\n", comp->signature());372traceMsg(comp, "%-8s", "cpIndex");373traceMsg(comp, "cp\n");374traceMsg(comp, "%-8x", methodSymRef->getCPIndexForVM());375traceMsg(comp, "%x\n", methodSymRef->getOwningMethod(comp)->constantPool());376traceMsg(comp, "</relocatableDataTrampolinesCG>\n");377}378379cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(380cursor,381*(uint8_t **)cursor,382getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,383TR_Trampolines, cg()), __FILE__, __LINE__, getNode());384385return cursor+4;386}387388uint32_t TR::ARMUnresolvedCallSnippet::getLength(int32_t estimatedSnippetStart)389{390return TR::ARMCallSnippet::getLength(estimatedSnippetStart) + 8;391}392393uint8_t *TR::ARMVirtualUnresolvedSnippet::emitSnippetBody()394{395uint8_t *cursor = cg()->getBinaryBufferCursor();396TR::SymbolReference *methodSymRef = getNode()->getSymbolReference();397TR::SymbolReference *glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_ARMvirtualUnresolvedHelper);398399TR::Compilation* comp = cg()->comp();400401getSnippetLabel()->setCodeLocation(cursor);402403// bl glueRef404*(int32_t *)cursor = encodeHelperBranchAndLink(glueRef, cursor, getNode(), cg());405cursor += 4;406407// Store the code cache RA408*(int32_t *)cursor = (intptr_t)getReturnLabel()->getCodeLocation();409cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(410cursor,411NULL,412TR_AbsoluteMethodAddress, cg()), __FILE__, __LINE__, getNode());413cursor += 4;414415// CP416*(int32_t *)cursor = (intptr_t)methodSymRef->getOwningMethod(comp)->constantPool();417418cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(419cursor,420*(uint8_t **)cursor,421getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,422TR_Thunks, cg()), __FILE__, __LINE__, getNode());423424cursor += 4;425426// CP index427*(int32_t *)cursor = methodSymRef->getCPIndexForVM();428429return (cursor + 4);430}431432uint32_t TR::ARMVirtualUnresolvedSnippet::getLength(int32_t estimatedSnippetStart)433{434return 16;435}436437uint8_t *TR::ARMInterfaceCallSnippet::emitSnippetBody()438{439uint8_t *cursor = cg()->getBinaryBufferCursor();440TR::SymbolReference *methodSymRef = getNode()->getSymbolReference();441TR::SymbolReference *glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_ARMinterfaceCallHelper);442443getSnippetLabel()->setCodeLocation(cursor);444445// bl glueRef446*(int32_t *)cursor = encodeHelperBranchAndLink(glueRef, cursor, getNode(), cg());447cursor += 4;448449// Store the code cache RA450*(int32_t *)cursor = (intptr_t)getReturnLabel()->getCodeLocation();451cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(452cursor,453NULL,454TR_AbsoluteMethodAddress, cg()), __FILE__, __LINE__, getNode());455cursor += 4;456457*(int32_t *)cursor = (intptr_t)methodSymRef->getOwningMethod(cg()->comp())->constantPool();458459cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(460cursor,461*(uint8_t **)cursor,462getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,463TR_Thunks, cg()), __FILE__, __LINE__, getNode());464465cursor += 4;466467*(int32_t *)cursor = methodSymRef->getCPIndexForVM();468cursor += 4;469470// Add 2 more slots for resolved values471*(int32_t *)cursor = 0;472cursor += 4;473*(int32_t *)cursor = 0;474cursor += 4;475476#if 0477// AOT TODO478// Patch up the main line codes479int32_t *patchAddress1 = NULL; // TODO (int32_t *)getUpperInstruction()->getBinaryEncoding();480*patchAddress1 |= (((int32_t)cursor>>16) + (((int32_t)cursor & (1<<15))?1:0)) & 0x0000ffff;481482int32_t *patchAddress2 = NULL; // TODO (int32_t *)getLowerInstruction()->getBinaryEncoding();483*patchAddress2 |= (int32_t)cursor & 0x0000ffff;484cg()->addRelocation(new (cg()->trHeapMemory()) TR::ExternalOrderedPair32BitRelocation(485(uint8_t *)patchAddress1,486(uint8_t *)patchAddress2,487NULL,488TR_AbsoluteMethodAddress));489#endif490491return cursor;492}493494uint32_t TR::ARMInterfaceCallSnippet::getLength(int32_t estimatedSnippetStart)495{496return 24;497}498499uint8_t *TR::ARMCallSnippet::generateVIThunk(TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg)500{501TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());502int32_t codeSize = 4*(instructionCountForArguments(callNode, cg) + 2) + 8; // Additional 4 bytes to hold size of thunk503uint8_t *thunk, *buffer, *returnValue;504int32_t dispatcher;505506if (cg->comp()->compileRelocatableCode())507thunk = (uint8_t *)TR::comp()->trMemory()->allocateMemory(codeSize, heapAlloc);508else509thunk = (uint8_t *)cg->allocateCodeMemory(codeSize, true, false);510buffer = returnValue = thunk + 8;511TR_RuntimeHelper helper;512TR::DataType dataType = callNode->getDataType();513514switch (dataType)515{516case TR::NoType:517helper = TR_ARMicallVMprJavaSendVirtual0;518break;519case TR::Int32:520case TR::Address:521#if (defined(__VFP_FP__) && !defined(__SOFTFP__))522case TR::Float:523#endif524helper = TR_ARMicallVMprJavaSendVirtual1;525break;526case TR::Int64:527#if (defined(__VFP_FP__) && !defined(__SOFTFP__))528case TR::Double:529#endif530helper = TR_ARMicallVMprJavaSendVirtualJ;531break;532#if !defined(__VFP_FP__) || defined(__SOFTFP__)533case TR::Float:534helper = TR_ARMicallVMprJavaSendVirtualF;535break;536case TR::Double:537helper = TR_ARMicallVMprJavaSendVirtualD;538break;539#endif540default:541TR_ASSERT(false, "Bad return data type for a call node. DataType was %s\n",542cg->getDebug()->getName(dataType));543}544545dispatcher = (intptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(helper)->getMethodAddress();546547buffer = flushArgumentsToStack(buffer, callNode, argSize, cg);548549*(int32_t *)buffer = 0xE51FF004; // ldr r15, [r15, #-4]550buffer += 4;551552*((int32_t *)thunk + 1) = buffer - returnValue; // patch offset for AOT relocation553554*(int32_t *)buffer = dispatcher; // address of transition target555buffer += 4;556557*(int32_t *)thunk = buffer - returnValue; // patch size of thunk558559#ifdef TR_HOST_ARM560armCodeSync(thunk, codeSize);561#endif562563return(returnValue);564}565566TR_J2IThunk *TR::ARMCallSnippet::generateInvokeExactJ2IThunk(TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg, char *signature)567{568int32_t codeSize = 4*(instructionCountForArguments(callNode, cg) + 2) + 8; // Additional 4 bytes to hold size of thunk569int32_t dispatcher;570TR_J2IThunkTable *thunkTable = TR::comp()->getPersistentInfo()->getInvokeExactJ2IThunkTable();571TR_J2IThunk *thunk = TR_J2IThunk::allocate(codeSize, signature, cg, thunkTable);572uint8_t *buffer = thunk->entryPoint();573574TR_RuntimeHelper helper;575TR::DataType dataType = callNode->getDataType();576577switch (dataType)578{579case TR::NoType:580helper = TR_icallVMprJavaSendInvokeExact0;581break;582case TR::Int32:583case TR::Address:584#if (defined(__VFP_FP__) && !defined(__SOFTFP__))585case TR::Float:586#endif587helper = TR_icallVMprJavaSendInvokeExact1;588break;589case TR::Int64:590#if (defined(__VFP_FP__) && !defined(__SOFTFP__))591case TR::Double:592#endif593helper = TR_icallVMprJavaSendInvokeExactJ;594break;595#if !defined(__VFP_FP__) || defined(__SOFTFP__)596case TR::Float:597helper = TR_icallVMprJavaSendInvokeExactF;598break;599case TR::Double:600helper = TR_icallVMprJavaSendInvokeExactD;601break;602#endif603default:604TR_ASSERT(false, "Bad return data type for a call node. DataType was %s\n",605cg->getDebug()->getName(dataType));606}607608dispatcher = (intptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(helper)->getMethodAddress();609610buffer = flushArgumentsToStack(buffer, callNode, argSize, cg);611612*(int32_t *)buffer = 0xE51FF004; // ldr r15, [r15, #-4]613buffer += 4;614615*(int32_t *)buffer = dispatcher; // address of transition target616buffer += 4;617618#ifdef TR_HOST_ARM619armCodeSync(thunk->entryPoint(), codeSize);620#endif621622return(thunk);623}624625626627