Path: blob/master/runtime/compiler/x/amd64/codegen/AMD64PrivateLinkage.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#ifdef TR_TARGET_64BIT2324#include "codegen/AMD64PrivateLinkage.hpp"25#include "codegen/AMD64JNILinkage.hpp"2627#include <stdint.h>28#include "codegen/CodeGenerator.hpp"29#include "codegen/Linkage_inlines.hpp"30#include "codegen/Machine.hpp"31#include "compile/Method.hpp"32#include "control/Recompilation.hpp"33#include "control/RecompilationInfo.hpp"34#include "env/CHTable.hpp"35#include "env/IO.hpp"36#include "env/J2IThunk.hpp"37#include "env/VMJ9.h"38#include "env/VerboseLog.hpp"39#include "env/jittypes.h"40#include "il/Node.hpp"41#include "il/Node_inlines.hpp"42#include "il/ParameterSymbol.hpp"43#include "x/amd64/codegen/AMD64GuardedDevirtualSnippet.hpp"44#include "x/codegen/CallSnippet.hpp"45#include "x/codegen/CheckFailureSnippet.hpp"46#include "x/codegen/HelperCallSnippet.hpp"47#include "x/codegen/X86Instruction.hpp"48#include "codegen/InstOpCode.hpp"4950////////////////////////////////////////////////51//52// Helpful definitions53//54// These are only here to make the rest of the code below somewhat55// self-documenting.56//5758enum59{60RETURN_ADDRESS_SIZE=8,61NUM_INTEGER_LINKAGE_REGS=4,62NUM_FLOAT_LINKAGE_REGS=8,63};6465////////////////////////////////////////////////66//67// Hack markers68//69// These things may become unnecessary as the implementation matures70//7172// Hacks related to 8 byte slots73#define DOUBLE_SIZED_ARGS (1)7475// Misc76#define INTERPRETER_CLOBBERS_XMMS (!debug("interpreterClobbersXmms"))77// Note AOT relocations assumes that this value is 0. Shall this value change, the AOT relocations also need to reflect this change.78#define VM_NEEDS_8_BYTE_CPINDEX (0)798081////////////////////////////////////////////////82//83// Initialization84//8586J9::X86::AMD64::PrivateLinkage::PrivateLinkage(TR::CodeGenerator *cg)87: J9::X86::PrivateLinkage(cg)88{89TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());90const TR::RealRegister::RegNum noReg = TR::RealRegister::NoReg;91uint8_t r, p;9293TR::RealRegister::RegNum metaReg = TR::RealRegister::ebp;9495_properties._properties =96EightBytePointers | EightByteParmSlots97| IntegersInRegisters | LongsInRegisters | FloatsInRegisters98| NeedsThunksForIndirectCalls99| UsesRegsForHelperArgs100;101102if (!fej9->pushesOutgoingArgsAtCallSite(cg->comp()))103_properties._properties |= CallerCleanup | ReservesOutgoingArgsInPrologue;104105// Integer arguments106p=0;107_properties._firstIntegerArgumentRegister = p;108_properties._argumentRegisters[p++] = TR::RealRegister::eax;109_properties._argumentRegisters[p++] = TR::RealRegister::esi;110_properties._argumentRegisters[p++] = TR::RealRegister::edx;111_properties._argumentRegisters[p++] = TR::RealRegister::ecx;112TR_ASSERT(p == NUM_INTEGER_LINKAGE_REGS, "assertion failure");113_properties._numIntegerArgumentRegisters = NUM_INTEGER_LINKAGE_REGS;114115// Float arguments116_properties._firstFloatArgumentRegister = p;117for(r=0; r<=7; r++)118_properties._argumentRegisters[p++] = TR::RealRegister::xmmIndex(r);119TR_ASSERT(p == NUM_INTEGER_LINKAGE_REGS + NUM_FLOAT_LINKAGE_REGS, "assertion failure");120_properties._numFloatArgumentRegisters = NUM_FLOAT_LINKAGE_REGS;121122// Preserved123p=0;124_properties._preservedRegisters[p++] = TR::RealRegister::ebx;125_properties._preservedRegisterMapForGC = TR::RealRegister::ebxMask;126127int32_t lastPreservedRegister = 9; // changed to 9 for liberty, it used to be 15128129for (r=9; r<=lastPreservedRegister; r++)130{131_properties._preservedRegisters[p++] = TR::RealRegister::rIndex(r);132_properties._preservedRegisterMapForGC |= TR::RealRegister::gprMask(TR::RealRegister::rIndex(r));133}134_properties._numberOfPreservedGPRegisters = p;135136if (!INTERPRETER_CLOBBERS_XMMS)137for (r=8; r<=15; r++)138{139_properties._preservedRegisters[p++] = TR::RealRegister::xmmIndex(r);140_properties._preservedRegisterMapForGC |= TR::RealRegister::xmmrMask(TR::RealRegister::xmmIndex(r));141}142143_properties._numberOfPreservedXMMRegisters = p - _properties._numberOfPreservedGPRegisters;144_properties._maxRegistersPreservedInPrologue = p;145_properties._preservedRegisters[p++] = metaReg;146_properties._preservedRegisters[p++] = TR::RealRegister::esp;147_properties._numPreservedRegisters = p;148149// Other150_properties._returnRegisters[0] = TR::RealRegister::eax;151_properties._returnRegisters[1] = TR::RealRegister::xmm0;152_properties._returnRegisters[2] = noReg;153154_properties._scratchRegisters[0] = TR::RealRegister::edi;155_properties._scratchRegisters[1] = TR::RealRegister::r8;156_properties._numScratchRegisters = 2;157158_properties._vtableIndexArgumentRegister = TR::RealRegister::r8;159_properties._j9methodArgumentRegister = TR::RealRegister::edi;160_properties._framePointerRegister = TR::RealRegister::esp;161_properties._methodMetaDataRegister = metaReg;162163_properties._numberOfVolatileGPRegisters = 6; // rax, rsi, rdx, rcx, rdi, r8164_properties._numberOfVolatileXMMRegisters = INTERPRETER_CLOBBERS_XMMS? 16 : 8; // xmm0-xmm7165166// Offsets relative to where the frame pointer *would* point if we had one;167// namely, the local with the highest address (ie. the "first" local)168setOffsetToFirstParm(RETURN_ADDRESS_SIZE);169_properties._offsetToFirstLocal = 0;170171// TODO: Need a better way to build the flags so they match the info above172//173memset(_properties._registerFlags, 0, sizeof(_properties._registerFlags));174175// Integer arguments/return176_properties._registerFlags[TR::RealRegister::eax] = IntegerArgument | IntegerReturn;177_properties._registerFlags[TR::RealRegister::esi] = IntegerArgument;178_properties._registerFlags[TR::RealRegister::edx] = IntegerArgument;179_properties._registerFlags[TR::RealRegister::ecx] = IntegerArgument;180181// Float arguments/return182_properties._registerFlags[TR::RealRegister::xmm0] = FloatArgument | FloatReturn;183for(r=1; r <= 7; r++)184_properties._registerFlags[TR::RealRegister::xmmIndex(r)] = FloatArgument;185186// Preserved187_properties._registerFlags[TR::RealRegister::ebx] = Preserved;188_properties._registerFlags[TR::RealRegister::esp] = Preserved;189_properties._registerFlags[metaReg] = Preserved;190for(r=9; r <= lastPreservedRegister; r++)191_properties._registerFlags[TR::RealRegister::rIndex(r)] = Preserved;192if(!INTERPRETER_CLOBBERS_XMMS)193for(r=8; r <= 15; r++)194_properties._registerFlags[TR::RealRegister::xmmIndex(r)] = Preserved;195196197p = 0;198if (TR::Machine::enableNewPickRegister())199{200// Volatiles that aren't linkage regs201if (TR::Machine::numGPRRegsWithheld(cg) == 0)202{203_properties._allocationOrder[p++] = TR::RealRegister::edi;204_properties._allocationOrder[p++] = TR::RealRegister::r8;205}206else207{208TR_ASSERT(TR::Machine::numGPRRegsWithheld(cg) == 2, "numRegsWithheld: only 0 and 2 currently supported");209}210211// Linkage regs in reverse order212_properties._allocationOrder[p++] = TR::RealRegister::ecx;213_properties._allocationOrder[p++] = TR::RealRegister::edx;214_properties._allocationOrder[p++] = TR::RealRegister::esi;215_properties._allocationOrder[p++] = TR::RealRegister::eax;216}217// Preserved regs218_properties._allocationOrder[p++] = TR::RealRegister::ebx;219_properties._allocationOrder[p++] = TR::RealRegister::r9;220_properties._allocationOrder[p++] = TR::RealRegister::r10;221_properties._allocationOrder[p++] = TR::RealRegister::r11;222_properties._allocationOrder[p++] = TR::RealRegister::r12;223_properties._allocationOrder[p++] = TR::RealRegister::r13;224_properties._allocationOrder[p++] = TR::RealRegister::r14;225_properties._allocationOrder[p++] = TR::RealRegister::r15;226227TR_ASSERT(p == machine()->getNumGlobalGPRs(), "assertion failure");228229if (TR::Machine::enableNewPickRegister())230{231// Linkage regs in reverse order232if (TR::Machine::numRegsWithheld(cg) == 0)233{234_properties._allocationOrder[p++] = TR::RealRegister::xmm7;235_properties._allocationOrder[p++] = TR::RealRegister::xmm6;236}237else238{239TR_ASSERT(TR::Machine::numRegsWithheld(cg) == 2, "numRegsWithheld: only 0 and 2 currently supported");240}241_properties._allocationOrder[p++] = TR::RealRegister::xmm5;242_properties._allocationOrder[p++] = TR::RealRegister::xmm4;243_properties._allocationOrder[p++] = TR::RealRegister::xmm3;244_properties._allocationOrder[p++] = TR::RealRegister::xmm2;245_properties._allocationOrder[p++] = TR::RealRegister::xmm1;246_properties._allocationOrder[p++] = TR::RealRegister::xmm0;247}248// Preserved regs249_properties._allocationOrder[p++] = TR::RealRegister::xmm8;250_properties._allocationOrder[p++] = TR::RealRegister::xmm9;251_properties._allocationOrder[p++] = TR::RealRegister::xmm10;252_properties._allocationOrder[p++] = TR::RealRegister::xmm11;253_properties._allocationOrder[p++] = TR::RealRegister::xmm12;254_properties._allocationOrder[p++] = TR::RealRegister::xmm13;255_properties._allocationOrder[p++] = TR::RealRegister::xmm14;256_properties._allocationOrder[p++] = TR::RealRegister::xmm15;257258TR_ASSERT(p == (machine()->getNumGlobalGPRs() + machine()->_numGlobalFPRs), "assertion failure");259}260261262////////////////////////////////////////////////263//264// Argument manipulation265//266267static uint8_t *flushArgument(268uint8_t*cursor,269TR::InstOpCode::Mnemonic op,270TR::RealRegister::RegNum regIndex,271int32_t offset,272TR::CodeGenerator *cg)273{274/* TODO:AMD64: Share code with the other flushArgument */275cursor = TR::InstOpCode(op).binary(cursor);276277// Mod | Reg | R/M278//279// 01 r 100 (8 bit displacement)280// 10 r 100 (32 bit displacement)281//282uint8_t ModRM = 0x04;283ModRM |= (offset >= -128 && offset <= 127) ? 0x40 : 0x80;284285*(cursor - 1) = ModRM;286cg->machine()->getRealRegister(regIndex)->setRegisterFieldInModRM(cursor - 1);287288// Scale = 0x00, Index = none, Base = rsp289//290*cursor++ = 0x24;291292if (offset >= -128 && offset <= 127)293{294*cursor++ = (uint8_t)offset;295}296else297{298*(uint32_t *)cursor = offset;299cursor += 4;300}301302return cursor;303}304305static int32_t flushArgumentSize(306TR::InstOpCode::Mnemonic op,307int32_t offset)308{309int32_t size = TR::InstOpCode(op).length() + 1; // length including ModRM + 1 SIB310return size + (((offset >= -128 && offset <= 127)) ? 1 : 4);311}312313uint8_t *J9::X86::AMD64::PrivateLinkage::flushArguments(314TR::Node *callNode,315uint8_t *cursor,316bool calculateSizeOnly,317int32_t *sizeOfFlushArea,318bool isReturnAddressOnStack,319bool isLoad)320{321// TODO:AMD64: Share code with the other flushArguments322TR::MethodSymbol *methodSymbol = callNode->getSymbol()->castToMethodSymbol();323324int32_t numGPArgs = 0;325int32_t numFPArgs = 0;326int32_t argSize = argAreaSize(callNode);327int32_t offset = argSize;328bool needFlush = false;329330// account for the return address in thunks and snippets.331if (isReturnAddressOnStack)332offset += sizeof(intptr_t);333334TR::RealRegister::RegNum reg = TR::RealRegister::NoReg;335TR::InstOpCode::Mnemonic op = TR::InstOpCode::bad;336TR::DataType dt = TR::NoType;337338if (calculateSizeOnly)339*sizeOfFlushArea = 0;340341const uint8_t slotSize = DOUBLE_SIZED_ARGS? 8 : 4;342343for (int i = callNode->getFirstArgumentIndex(); i < callNode->getNumChildren(); i++)344{345TR::DataType type = callNode->getChild(i)->getType();346dt = type.getDataType();347op = TR::Linkage::movOpcodes(isLoad? RegMem : MemReg, movType(dt));348349switch (dt)350{351case TR::Int64:352offset -= slotSize;353354// Longs take two slots. Deliberate fall through.355356case TR::Int8:357case TR::Int16:358case TR::Int32:359case TR::Address:360offset -= slotSize;361if (numGPArgs < getProperties().getNumIntegerArgumentRegisters())362{363needFlush = true;364if (!calculateSizeOnly)365reg = getProperties().getIntegerArgumentRegister(numGPArgs);366}367numGPArgs++;368break;369370case TR::Float:371case TR::Double:372offset -= ((dt == TR::Double) ? 2 : 1) * slotSize;373374if (numFPArgs < getProperties().getNumFloatArgumentRegisters())375{376needFlush = true;377if (!calculateSizeOnly)378reg = getProperties().getFloatArgumentRegister(numFPArgs);379}380381numFPArgs++;382break;383default:384break;385}386387if (needFlush)388{389if (calculateSizeOnly)390*sizeOfFlushArea += flushArgumentSize(op, offset);391else392cursor = flushArgument(cursor, op, reg, offset, cg());393394needFlush = false;395}396}397398return cursor;399}400401TR::Instruction *402J9::X86::AMD64::PrivateLinkage::generateFlushInstruction(403TR::Instruction *prev,404TR_MovOperandTypes operandType,405TR::DataType dataType,406TR::RealRegister::RegNum regIndex,407TR::Register *espReg,408int32_t offset,409TR::CodeGenerator *cg410)411{412TR::Instruction *result;413414// Opcode415//416TR::InstOpCode::Mnemonic opCode = TR::Linkage::movOpcodes(operandType, movType(dataType));417418// Registers419//420TR::Register *argReg = cg->allocateRegister(movRegisterKind(movType(dataType)));421422TR::RegisterDependencyConditions *deps = generateRegisterDependencyConditions((uint8_t)2, 2, cg);423deps->addPreCondition (argReg, regIndex, cg);424deps->addPostCondition(argReg, regIndex, cg);425deps->addPreCondition (espReg, TR::RealRegister::esp, cg);426deps->addPostCondition(espReg, TR::RealRegister::esp, cg);427428// Generate the instruction429//430TR::MemoryReference *memRef = generateX86MemoryReference(espReg, offset, cg);431switch (operandType)432{433case RegMem:434result = new (cg->trHeapMemory()) TR::X86RegMemInstruction(prev, opCode, argReg, memRef, deps, cg);435break;436case MemReg:437result = new (cg->trHeapMemory()) TR::X86MemRegInstruction(prev, opCode, memRef, argReg, deps, cg);438break;439default:440TR_ASSERT(0, "Flush instruction must be RegMem or MemReg");441result = NULL;442break;443}444445// Cleanup446//447cg->stopUsingRegister(argReg);448449return result;450}451452TR::Instruction *453J9::X86::AMD64::PrivateLinkage::flushArguments(454TR::Instruction *prev,455TR::ResolvedMethodSymbol *methodSymbol,456bool isReturnAddressOnStack,457bool isLoad)458{459// TODO:AMD64: Share code with the other flushArguments460461int32_t numGPArgs = 0;462int32_t numFPArgs = 0;463int32_t offset = argAreaSize(methodSymbol);464bool needFlush = false;465466const uint8_t slotSize = DOUBLE_SIZED_ARGS? 8 : 4;467468// account for the return address in SwitchToInterpreterPrePrologue469if (isReturnAddressOnStack)470offset += sizeof(intptr_t);471472TR::RealRegister::RegNum reg;473TR::Register *espReg = cg()->allocateRegister();474475ListIterator<TR::ParameterSymbol> parameterIterator(&methodSymbol->getParameterList());476TR::ParameterSymbol *parmCursor;477for (parmCursor = parameterIterator.getFirst(); parmCursor; parmCursor = parameterIterator.getNext())478{479TR::DataType type = parmCursor->getType();480TR::DataType dt = type.getDataType();481TR_MovOperandTypes ot = isLoad? RegMem : MemReg;482483switch (dt)484{485case TR::Int64:486offset -= slotSize;487488// Deliberate fall through489490case TR::Int8:491case TR::Int16:492case TR::Int32:493case TR::Address:494offset -= slotSize;495if (numGPArgs < getProperties().getNumIntegerArgumentRegisters())496{497prev = generateFlushInstruction(prev, ot, dt, getProperties().getIntegerArgumentRegister(numGPArgs), espReg, offset, cg());498}499500numGPArgs++;501break;502503case TR::Double:504offset -= slotSize;505506// Deliberate fall through507508case TR::Float:509offset -= slotSize;510511if (numFPArgs < getProperties().getNumFloatArgumentRegisters())512{513prev = generateFlushInstruction(prev, ot, dt, getProperties().getFloatArgumentRegister(numFPArgs), espReg, offset, cg());514}515516numFPArgs++;517break;518default:519break;520}521522}523524cg()->stopUsingRegister(espReg);525526return prev;527}528529uint8_t *J9::X86::AMD64::PrivateLinkage::generateVirtualIndirectThunk(TR::Node *callNode)530{531int32_t codeSize;532TR::SymbolReference *glueSymRef;533uint8_t *thunk;534uint8_t *thunkEntry;535uint8_t *cursor;536TR::Compilation *comp = cg()->comp();537538(void)storeArguments(callNode, NULL, true, &codeSize);539codeSize += 12; // +10 TR::InstOpCode::MOV8RegImm64 +2 TR::InstOpCode::JMPReg540541TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg()->fe());542543// Allocate the thunk in the cold code section544//545if (fej9->storeOffsetToArgumentsInVirtualIndirectThunks())546{547codeSize += 8;548thunk = (uint8_t *)comp->trMemory()->allocateMemory(codeSize, heapAlloc);549cursor = thunkEntry = thunk + 8; // 4 bytes holding the size of storeArguments550}551else552{553thunk = (uint8_t *)cg()->allocateCodeMemory(codeSize, true);554cursor = thunkEntry = thunk;555}556557switch (callNode->getDataType())558{559case TR::NoType:560glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_AMD64icallVMprJavaSendVirtual0);561break;562case TR::Int64:563glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_AMD64icallVMprJavaSendVirtualJ);564break;565case TR::Address:566glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_AMD64icallVMprJavaSendVirtualL);567break;568case TR::Int32:569glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_AMD64icallVMprJavaSendVirtual1);570break;571case TR::Float:572glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_AMD64icallVMprJavaSendVirtualF);573break;574case TR::Double:575glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_AMD64icallVMprJavaSendVirtualD);576break;577default:578TR_ASSERT(0, "Bad return data type '%s' for call node [" POINTER_PRINTF_FORMAT "]\n",579comp->getDebug()->getName(callNode->getDataType()),580callNode);581}582583cursor = storeArguments(callNode, cursor, false, NULL);584585if (fej9->storeOffsetToArgumentsInVirtualIndirectThunks())586{587*((int32_t *)thunk + 1) = cursor - thunkEntry;588}589590// TR::InstOpCode::MOV8RegImm64 rdi, glueAddress591//592*(uint16_t *)cursor = 0xbf48;593cursor += 2;594*(uint64_t *)cursor = (uintptr_t)glueSymRef->getMethodAddress();595cursor += 8;596597// TR::InstOpCode::JMPReg rdi598//599*(uint8_t *)cursor++ = 0xff;600*(uint8_t *)cursor++ = 0xe7;601602if (fej9->storeOffsetToArgumentsInVirtualIndirectThunks())603*(int32_t *)thunk = cursor - thunkEntry;604605diagnostic("\n-- ( Created J2I thunk " POINTER_PRINTF_FORMAT " for node " POINTER_PRINTF_FORMAT " )\n", thunkEntry, callNode);606607return thunkEntry;608}609610TR_J2IThunk *J9::X86::AMD64::PrivateLinkage::generateInvokeExactJ2IThunk(TR::Node *callNode, char *signature)611{612TR::Compilation *comp = cg()->comp();613614// Allocate thunk storage615//616int32_t codeSize;617(void)storeArguments(callNode, NULL, true, &codeSize);618codeSize += 10; // TR::InstOpCode::MOV8RegImm64619if (comp->getOption(TR_BreakOnJ2IThunk))620codeSize += 1; // breakpoint opcode621if (comp->getOptions()->getVerboseOption(TR_VerboseJ2IThunks))622codeSize += 5; // JMPImm4623else624codeSize += 2; // TR::InstOpCode::JMPReg625626TR_J2IThunkTable *thunkTable = comp->getPersistentInfo()->getInvokeExactJ2IThunkTable();627TR_J2IThunk *thunk = TR_J2IThunk::allocate(codeSize, signature, cg(), thunkTable);628uint8_t *cursor = thunk->entryPoint();629630TR::SymbolReference *glueSymRef;631switch (callNode->getDataType())632{633case TR::NoType:634glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExact0);635break;636case TR::Int64:637glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactJ);638break;639case TR::Address:640glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactL);641break;642case TR::Int32:643glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExact1);644break;645case TR::Float:646glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactF);647break;648case TR::Double:649glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactD);650break;651default:652TR_ASSERT(0, "Bad return data type '%s' for call node [" POINTER_PRINTF_FORMAT "]\n",653comp->getDebug()->getName(callNode->getDataType()),654callNode);655}656657if (comp->getOption(TR_BreakOnJ2IThunk))658*cursor++ = 0xcc;659660// TR::InstOpCode::MOV8RegImm64 rdi, glueAddress661//662*(uint16_t *)cursor = 0xbf48;663cursor += 2;664*(uint64_t *)cursor = (uintptr_t) cg()->fej9()->getInvokeExactThunkHelperAddress(comp, glueSymRef, callNode->getDataType());665cursor += 8;666667// Arg stores668//669cursor = storeArguments(callNode, cursor, false, NULL);670671if (comp->getOptions()->getVerboseOption(TR_VerboseJ2IThunks))672{673// JMPImm4 helper674//675*(uint8_t *)cursor++ = 0xe9;676TR::SymbolReference *helper = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_methodHandleJ2IGlue);677int32_t disp32 = cg()->branchDisplacementToHelperOrTrampoline(cursor+4, helper);678*(int32_t *)cursor = disp32;679cursor += 4;680}681else682{683// TR::InstOpCode::JMPReg rdi684//685*(uint8_t *)cursor++ = 0xff;686*(uint8_t *)cursor++ = 0xe7;687}688689if (comp->getOption(TR_TraceCG))690{691traceMsg(comp, "\n-- ( Created invokeExact J2I thunk " POINTER_PRINTF_FORMAT " for node " POINTER_PRINTF_FORMAT " )", thunk, callNode);692}693694return thunk;695}696697TR::Instruction *J9::X86::AMD64::PrivateLinkage::savePreservedRegisters(TR::Instruction *cursor)698{699TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();700const int32_t localSize = _properties.getOffsetToFirstLocal() - bodySymbol->getLocalMappingCursor();701const int32_t pointerSize = _properties.getPointerSize();702703704int32_t offsetCursor = -localSize - pointerSize;705706int32_t preservedRegStoreBytesSaved = 0;707if (_properties.getOffsetToFirstLocal() - bodySymbol->getLocalMappingCursor() > 0)708preservedRegStoreBytesSaved -= 4; // There's an extra mov rsp709710for (int32_t pindex = _properties.getMaxRegistersPreservedInPrologue()-1;711pindex >= 0;712pindex--)713{714TR::RealRegister *scratch = machine()->getRealRegister(getProperties().getIntegerScratchRegister(0));715TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex);716TR::RealRegister::RegNum r8 = TR::RealRegister::r8;717TR::RealRegister *reg = machine()->getRealRegister(idx);718if (reg->getHasBeenAssignedInMethod() &&719(reg->getState() != TR::RealRegister::Locked))720{721cursor = generateMemRegInstruction(722cursor,723TR::Linkage::movOpcodes(MemReg, fullRegisterMovType(reg)),724generateX86MemoryReference(machine()->getRealRegister(TR::RealRegister::vfp), offsetCursor, cg()),725reg,726cg()727);728offsetCursor -= pointerSize;729}730}731732cursor = cg()->generateDebugCounter(cursor, "cg.prologues:no-preservedRegStoreBytesSaved", 1, TR::DebugCounter::Expensive);733734return cursor;735}736737TR::Instruction *J9::X86::AMD64::PrivateLinkage::restorePreservedRegisters(TR::Instruction *cursor)738{739TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();740const int32_t localSize = _properties.getOffsetToFirstLocal() - bodySymbol->getLocalMappingCursor();741const int32_t pointerSize = _properties.getPointerSize();742743int32_t pindex;744int32_t offsetCursor = -localSize - _properties.getPointerSize();745for (pindex = _properties.getMaxRegistersPreservedInPrologue()-1;746pindex >= 0;747pindex--)748{749TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex);750TR::RealRegister *reg = machine()->getRealRegister(idx);751if (reg->getHasBeenAssignedInMethod())752{753cursor = generateRegMemInstruction(754cursor,755TR::Linkage::movOpcodes(RegMem, fullRegisterMovType(reg)),756reg,757generateX86MemoryReference(machine()->getRealRegister(TR::RealRegister::vfp), offsetCursor, cg()),758cg()759);760offsetCursor -= _properties.getPointerSize();761}762}763cursor = cg()->generateDebugCounter(cursor, "cg.epilogues:no-preservedRegStoreBytesSaved", 1, TR::DebugCounter::Expensive);764return cursor;765}766767////////////////////////////////////////////////768//769// Call node evaluation770//771772int32_t J9::X86::AMD64::PrivateLinkage::argAreaSize(TR::ResolvedMethodSymbol *methodSymbol)773{774int32_t result = 0;775ListIterator<TR::ParameterSymbol> paramIterator(&(methodSymbol->getParameterList()));776TR::ParameterSymbol *paramCursor;777for (paramCursor = paramIterator.getFirst(); paramCursor; paramCursor = paramIterator.getNext())778{779result += paramCursor->getRoundedSize() * ((DOUBLE_SIZED_ARGS && paramCursor->getDataType() != TR::Address) ? 2 : 1);780}781return result;782}783784int32_t J9::X86::AMD64::PrivateLinkage::argAreaSize(TR::Node *callNode)785{786// TODO: We only need this function because unresolved calls don't have a787// TR::ResolvedMethodSymbol, and only TR::ResolvedMethodSymbol has788// getParameterList(). If getParameterList() ever moves to TR::MethodSymbol,789// then this function becomes unnecessary.790//791TR::Node *child;792int32_t i;793int32_t result = 0;794int32_t firstArgument = callNode->getFirstArgumentIndex();795int32_t lastArgument = callNode->getNumChildren() - 1;796for (i=firstArgument; i <= lastArgument; i++)797{798child = callNode->getChild(i);799result += child->getRoundedSize() * ((DOUBLE_SIZED_ARGS && child->getDataType() != TR::Address) ? 2 : 1);800}801return result;802}803804int32_t J9::X86::AMD64::PrivateLinkage::buildArgs(TR::Node *callNode,805TR::RegisterDependencyConditions *dependencies)806{807TR::MethodSymbol *methodSymbol = callNode->getSymbol()->getMethodSymbol();808TR::SymbolReference *methodSymRef = callNode->getSymbolReference();809bool passArgsOnStack;810bool rightToLeft = methodSymbol && methodSymbol->isHelper()811&& !methodSymRef->isOSRInductionHelper(); //we want the arguments for induceOSR to be passed from left to right as in any other non-helper call812if (callNode->getOpCode().isIndirect())813{814if (methodSymbol->isVirtual() &&815!methodSymRef->isUnresolved() &&816!comp()->getOption(TR_FullSpeedDebug) && // On FSD we need to call these through the vtable (because the methodIsOverridden flag is unreliable) so we need args to be in regs817methodSymbol->isVMInternalNative())818{819TR_ResolvedMethod *resolvedMethod = methodSymbol->castToResolvedMethodSymbol()->getResolvedMethod();820passArgsOnStack = (821!resolvedMethod->virtualMethodIsOverridden() &&822!resolvedMethod->isAbstract());823}824else825{826passArgsOnStack = false;827}828}829else830{831passArgsOnStack = methodSymbol->isVMInternalNative() && cg()->supportVMInternalNatives();832}833834switch (callNode->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod())835{836case TR::java_lang_invoke_ComputedCalls_dispatchJ9Method:837passArgsOnStack = true;838break;839default:840break;841}842843#ifdef J9VM_OPT_JAVA_CRYPTO_ACCELERATION844// Violate the right-to-left linkage requirement for JIT helpers for the AES helpers.845// Call them with Java method private linkage.846//847if (cg()->enableAESInHardwareTransformations())848{849if (methodSymbol && methodSymbol->isHelper())850{851switch (methodSymRef->getReferenceNumber())852{853case TR_doAESInHardwareInner:854case TR_expandAESKeyInHardwareInner:855rightToLeft = false;856break;857858default:859break;860}861}862}863#endif864865return buildPrivateLinkageArgs(callNode, dependencies, rightToLeft, passArgsOnStack);866}867868int32_t J9::X86::AMD64::PrivateLinkage::buildPrivateLinkageArgs(TR::Node *callNode,869TR::RegisterDependencyConditions *dependencies,870bool rightToLeft,871bool passArgsOnStack)872{873TR::RealRegister::RegNum noReg = TR::RealRegister::NoReg;874TR::RealRegister *stackPointer = machine()->getRealRegister(TR::RealRegister::esp);875int32_t firstArgument = callNode->getFirstArgumentIndex();876int32_t lastArgument = callNode->getNumChildren() - 1;877int32_t offset = 0;878879uint16_t numIntArgs = 0,880numFloatArgs = 0,881numSpecialArgs = 0;882883int numDupedArgRegs = 0;884TR::Register *dupedArgRegs[NUM_INTEGER_LINKAGE_REGS + NUM_FLOAT_LINKAGE_REGS];885886// Even though the parameters will be passed on the stack, create dummy linkage registers887// to ensure that if the call were to be made using the linkage registers (e.g., in a guarded888// devirtual snippet if it was overridden) then the registers would be available at this889// point.890//891bool createDummyLinkageRegisters = (callNode->getOpCode().isIndirect() && passArgsOnStack) ? true: false;892893int32_t parmAreaSize = argAreaSize(callNode);894895int32_t start, stop, step;896if (rightToLeft || getProperties().passArgsRightToLeft())897{898start = lastArgument;899stop = firstArgument - 1;900step = -1;901TR_ASSERT(stop <= start, "Loop must terminate");902}903else904{905start = firstArgument;906stop = lastArgument + 1;907step = 1;908TR_ASSERT(stop >= start, "Loop must terminate");909}910911// we're going to align the stack depend on the alignment property912// adjust = something913// allocateSize = parmAreaSize + adjust;914// then subtract stackpointer with allocateSize915uint32_t alignedParmAreaSize = parmAreaSize;916917if (!getProperties().getReservesOutgoingArgsInPrologue() && !callNode->getSymbol()->castToMethodSymbol()->isHelper())918{919// Align the stack for alignment larger than 16 bytes(stack is aligned to the multiple of sizeOfJavaPointer by default, which is 4 bytes on 32-bit, and 8 bytes on 64-bit)920// Basically, we're aligning the start of next frame (after the return address) to a multiple of staceFrameAlignmentInBytes921// Stack frame alignment is needed for stack allocated object alignment922uint32_t stackFrameAlignment = cg()->fej9()->getLocalObjectAlignmentInBytes();923if (stackFrameAlignment > TR::Compiler->om.sizeofReferenceAddress())924{925uint32_t frameSize = parmAreaSize + cg()->getFrameSizeInBytes() + getProperties().getRetAddressWidth();926frameSize += stackFrameAlignment - (frameSize % stackFrameAlignment);927alignedParmAreaSize = frameSize - cg()->getFrameSizeInBytes() - getProperties().getRetAddressWidth();928929if (comp()->getOption(TR_TraceCG))930{931traceMsg(comp(), "parm area size was %d, and is aligned to %d\n", parmAreaSize, alignedParmAreaSize);932}933}934if (alignedParmAreaSize > 0)935generateRegImmInstruction((alignedParmAreaSize <= 127 ? TR::InstOpCode::SUBRegImms() : TR::InstOpCode::SUBRegImm4()), callNode, stackPointer, alignedParmAreaSize, cg());936}937938int32_t i;939for (i = start; i != stop; i += step)940{941TR::Node *child = callNode->getChild(i);942TR::DataType type = child->getType();943TR::RealRegister::RegNum rregIndex = noReg;944TR::DataType dt = type.getDataType();945946switch (dt)947{948case TR::Float:949case TR::Double:950rregIndex =951(numFloatArgs < NUM_FLOAT_LINKAGE_REGS) && (!passArgsOnStack || createDummyLinkageRegisters)952? getProperties().getFloatArgumentRegister(numFloatArgs)953: noReg954;955numFloatArgs++;956break;957case TR::Address:958default:959{960if (i == firstArgument && !callNode->getSymbolReference()->isUnresolved())961{962// TODO:JSR292: This should really be in the front-end963TR::MethodSymbol *sym = callNode->getSymbol()->castToMethodSymbol();964switch (sym->getMandatoryRecognizedMethod())965{966case TR::java_lang_invoke_ComputedCalls_dispatchJ9Method:967rregIndex = getProperties().getJ9MethodArgumentRegister();968numSpecialArgs++;969break;970case TR::java_lang_invoke_ComputedCalls_dispatchVirtual:971case TR::com_ibm_jit_JITHelpers_dispatchVirtual:972rregIndex = getProperties().getVTableIndexArgumentRegister();973numSpecialArgs++;974break;975default:976break;977}978}979if (rregIndex == noReg)980{981rregIndex =982(numIntArgs < NUM_INTEGER_LINKAGE_REGS) && (!passArgsOnStack || createDummyLinkageRegisters)983? getProperties().getIntegerArgumentRegister(numIntArgs)984: noReg985;986numIntArgs++;987}988break;989}990}991992bool willKeepConstRegLiveAcrossCall = true;993rcount_t oldRefCount = child->getReferenceCount();994TR::Register *childReg = child->getRegister();995if (child->getOpCode().isLoadConst() &&996!childReg &&997(callNode->getSymbol()->castToMethodSymbol()->isStatic() ||998callNode->getChild(callNode->getFirstArgumentIndex()) != child))999{1000child->setReferenceCount(1);1001willKeepConstRegLiveAcrossCall = false;1002}10031004TR::Register *vreg = NULL;1005if ((rregIndex != noReg) ||1006(child->getOpCodeValue() != TR::iconst) ||1007(child->getOpCodeValue() == TR::iconst && childReg))1008vreg = cg()->evaluate(child);10091010if (rregIndex != noReg)1011{1012bool needsZeroExtension = (child->getDataType() == TR::Int32) && !vreg->areUpperBitsZero();1013TR::Register *preCondReg;10141015if (/*!child->getOpCode().isLoadConst() &&*/ (child->getReferenceCount() > 1))1016{1017preCondReg = cg()->allocateRegister(vreg->getKind());1018if (vreg->containsCollectedReference())1019preCondReg->setContainsCollectedReference();10201021generateRegRegInstruction(needsZeroExtension? TR::InstOpCode::MOVZXReg8Reg4 : TR::Linkage::movOpcodes(RegReg, movType(child->getDataType())), child, preCondReg, vreg, cg());1022vreg = preCondReg;10231024TR_ASSERT(numDupedArgRegs < NUM_INTEGER_LINKAGE_REGS + NUM_FLOAT_LINKAGE_REGS, "assertion failure");1025dupedArgRegs[numDupedArgRegs++] = preCondReg;1026}1027else1028{1029preCondReg = vreg;1030if (needsZeroExtension)1031generateRegRegInstruction(TR::InstOpCode::MOVZXReg8Reg4, child, preCondReg, vreg, cg());1032}10331034dependencies->addPreCondition(preCondReg, rregIndex, cg());1035}10361037offset += child->getRoundedSize() * ((DOUBLE_SIZED_ARGS && dt != TR::Address) ? 2 : 1);10381039if ((rregIndex == noReg) || (rregIndex != noReg && createDummyLinkageRegisters))1040{1041if (vreg)1042generateMemRegInstruction(1043TR::Linkage::movOpcodes(MemReg, fullRegisterMovType(vreg)),1044child,1045generateX86MemoryReference(stackPointer, parmAreaSize-offset, cg()),1046vreg,1047cg()1048);1049else1050{1051int32_t konst = child->getInt();1052generateMemImmInstruction(1053TR::InstOpCode::S8MemImm4,1054child,1055generateX86MemoryReference(stackPointer, parmAreaSize-offset, cg()),1056konst,1057cg()1058);1059}1060}10611062if (vreg)1063{1064cg()->decReferenceCount(child);1065////if (child->getOpCode().isLoadConst() && !childReg)1066if (!willKeepConstRegLiveAcrossCall)1067{1068child->setReferenceCount(oldRefCount-1);1069child->setRegister(NULL);1070}1071}1072else1073child->setReferenceCount(oldRefCount-1);1074}107510761077// Now that we're finished making the precondition, all the interferences1078// are established, and we can stopUsing these regs.1079//1080for (i = 0; i < numDupedArgRegs; i++)1081{1082cg()->stopUsingRegister(dupedArgRegs[i]);1083}10841085// Sanity check1086//1087TR_ASSERT(numIntArgs + numFloatArgs + numSpecialArgs == callNode->getNumChildren() - callNode->getFirstArgumentIndex(), "assertion failure");1088TR_ASSERT(offset == parmAreaSize, "assertion failure");10891090return alignedParmAreaSize;1091}109210931094static TR_AtomicRegion X86PicSlotAtomicRegion[] =1095{1096{ 0x0, 8 }, // Maximum instruction size that can be patched atomically.1097{ 0,0 }1098};109911001101TR::Instruction *J9::X86::AMD64::PrivateLinkage::buildPICSlot(TR::X86PICSlot picSlot, TR::LabelSymbol *mismatchLabel, TR::LabelSymbol *doneLabel, TR::X86CallSite &site)1102{1103TR::Register *cachedAddressRegister = cg()->allocateRegister();11041105TR::Node *node = site.getCallNode();1106uint64_t addrToBeCompared = (uint64_t) picSlot.getClassAddress();1107TR::Instruction *firstInstruction;1108if (picSlot.getMethodAddress())1109{1110addrToBeCompared = (uint64_t) picSlot.getMethodAddress();1111firstInstruction = generateRegImm64Instruction(TR::InstOpCode::MOV8RegImm64, node, cachedAddressRegister, addrToBeCompared, cg());1112}1113else1114firstInstruction = generateRegImm64Instruction(TR::InstOpCode::MOV8RegImm64, node, cachedAddressRegister, (uint64_t)picSlot.getClassAddress(), cg());111511161117firstInstruction->setNeedsGCMap(site.getPreservedRegisterMask());11181119if (!site.getFirstPICSlotInstruction())1120site.setFirstPICSlotInstruction(firstInstruction);11211122if (picSlot.needsPicSlotAlignment())1123{1124generateBoundaryAvoidanceInstruction(1125X86PicSlotAtomicRegion,11268,11278,1128firstInstruction,1129cg());1130}11311132TR::Register *vftReg = site.evaluateVFT();11331134// The ordering of these registers in this compare instruction is important in order to get the1135// VFT register into the ModRM r/m field of the generated instruction.1136//1137if (picSlot.getMethodAddress())1138generateMemRegInstruction(TR::InstOpCode::CMP8MemReg, node,1139generateX86MemoryReference(vftReg, picSlot.getSlot(), cg()), cachedAddressRegister, cg());1140else1141generateRegRegInstruction(TR::InstOpCode::CMP8RegReg, node, cachedAddressRegister, vftReg, cg());11421143cg()->stopUsingRegister(cachedAddressRegister);11441145if (picSlot.needsJumpOnNotEqual())1146{1147if (picSlot.needsLongConditionalBranch())1148{1149generateLongLabelInstruction(TR::InstOpCode::JNE4, node, mismatchLabel, cg());1150}1151else1152{1153TR::InstOpCode::Mnemonic op = picSlot.needsShortConditionalBranch() ? TR::InstOpCode::JNE1 : TR::InstOpCode::JNE4;1154generateLabelInstruction(op, node, mismatchLabel, cg());1155}1156}1157else if (picSlot.needsJumpOnEqual())1158{1159if (picSlot.needsLongConditionalBranch())1160{1161generateLongLabelInstruction(TR::InstOpCode::JE4, node, mismatchLabel, cg());1162}1163else1164{1165TR::InstOpCode::Mnemonic op = picSlot.needsShortConditionalBranch() ? TR::InstOpCode::JE1 : TR::InstOpCode::JE4;1166generateLabelInstruction(op, node, mismatchLabel, cg());1167}1168}11691170TR::Instruction *instr;1171if (picSlot.getMethod())1172{1173TR::SymbolReference * callSymRef = comp()->getSymRefTab()->findOrCreateMethodSymbol(1174node->getSymbolReference()->getOwningMethodIndex(), -1, picSlot.getMethod(), TR::MethodSymbol::Virtual);11751176instr = generateImmSymInstruction(TR::InstOpCode::CALLImm4, node, (intptr_t)picSlot.getMethod()->startAddressForJittedMethod(), callSymRef, cg());1177}1178else if (picSlot.getHelperMethodSymbolRef())1179{1180TR::MethodSymbol *helperMethod = picSlot.getHelperMethodSymbolRef()->getSymbol()->castToMethodSymbol();1181instr = generateImmSymInstruction(TR::InstOpCode::CALLImm4, node, (uint32_t)(uintptr_t)helperMethod->getMethodAddress(), picSlot.getHelperMethodSymbolRef(), cg());1182}1183else1184{1185instr = generateImmInstruction(TR::InstOpCode::CALLImm4, node, 0, cg());1186}11871188instr->setNeedsGCMap(site.getPreservedRegisterMask());11891190// Put a GC map on this label, since the instruction after it may provide1191// the return address in this stack frame while PicBuilder is active1192//1193// TODO: Can we get rid of some of these? Maybe they don't cost anything.1194//1195if (picSlot.needsJumpToDone())1196{1197instr = generateLabelInstruction(TR::InstOpCode::JMP4, node, doneLabel, cg());1198instr->setNeedsGCMap(site.getPreservedRegisterMask());1199}12001201if (picSlot.generateNextSlotLabelInstruction())1202{1203generateLabelInstruction(TR::InstOpCode::label, node, mismatchLabel, cg());1204}12051206return firstInstruction;1207}120812091210static TR_AtomicRegion amd64IPicAtomicRegions[] =1211{1212{ 0x02, 8 }, // Class test immediate 11213{ 0x1a, 8 }, // Class test immediate 21214{ 0x3b, 4 }, // IPICInit call displacement1215{ 0,0 } // (null terminator)12161217// Some other important regions1218//{ 0x10, 4 }, // Call displacement 1 (no race here)1219//{ 0x28, 4 }, // Call displacement 2 (no race here)1220};12211222void J9::X86::AMD64::PrivateLinkage::buildIPIC(TR::X86CallSite &site, TR::LabelSymbol *entryLabel, TR::LabelSymbol *doneLabel, uint8_t *thunk)1223{1224TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg()->fe());1225int32_t numIPICs = 0;12261227TR_ASSERT(doneLabel, "a doneLabel is required for PIC dispatches");12281229if (entryLabel)1230generateLabelInstruction(TR::InstOpCode::label, site.getCallNode(), entryLabel, cg());12311232int32_t numIPicSlots = IPicParameters.defaultNumberOfSlots;12331234TR::SymbolReference *callHelperSymRef =1235cg()->symRefTab()->findOrCreateRuntimeHelper(TR_X86populateIPicSlotCall, true, true, false);12361237static char *interfaceDispatchUsingLastITableStr = feGetEnv("TR_interfaceDispatchUsingLastITable");1238static char *numIPicSlotsStr = feGetEnv("TR_numIPicSlots");1239static char *numIPicSlotsBeforeLastITable = feGetEnv("TR_numIPicSlotsBeforeLastITable");1240static char *breakBeforeIPICUsingLastITable = feGetEnv("TR_breakBeforeIPICUsingLastITable");12411242if (numIPicSlotsStr)1243numIPicSlots = atoi(numIPicSlotsStr);12441245bool useLastITableCache = site.useLastITableCache() || interfaceDispatchUsingLastITableStr;1246if (useLastITableCache)1247{1248if (numIPicSlotsBeforeLastITable)1249{1250numIPicSlots = atoi(numIPicSlotsBeforeLastITable);1251}1252if (breakBeforeIPICUsingLastITable)1253{1254// This will occasionally put a break before an IPIC that does not use1255// the lastITable cache, because we might still change our mind1256// below. However, this is where we want the break instruction, so1257// let's just lay it down. It's likely not worth the effort to get1258// this exactly right in all cases.1259//1260generateInstruction(TR::InstOpCode::INT3, site.getCallNode(), cg());1261}1262}126312641265if (numIPicSlots > 1)1266{1267TR::X86PICSlot emptyPicSlot = TR::X86PICSlot(IPicParameters.defaultSlotAddress, NULL);1268emptyPicSlot.setNeedsShortConditionalBranch();1269emptyPicSlot.setJumpOnNotEqual();1270emptyPicSlot.setNeedsPicSlotAlignment();1271emptyPicSlot.setHelperMethodSymbolRef(callHelperSymRef);1272emptyPicSlot.setGenerateNextSlotLabelInstruction();12731274// Generate all slots except the last1275// (short branch to next slot, jump to doneLabel)1276//1277for (int32_t i = 1; i < numIPicSlots; i++)1278{1279TR::LabelSymbol *nextSlotLabel = generateLabelSymbol(cg());1280buildPICSlot(emptyPicSlot, nextSlotLabel, doneLabel, site);1281}1282}12831284// Configure the last slot1285//1286TR::LabelSymbol *lookupDispatchSnippetLabel = generateLabelSymbol(cg());1287TR::X86PICSlot lastPicSlot = TR::X86PICSlot(IPicParameters.defaultSlotAddress, NULL, false);1288lastPicSlot.setJumpOnNotEqual();1289lastPicSlot.setNeedsPicSlotAlignment();1290lastPicSlot.setHelperMethodSymbolRef(callHelperSymRef);1291TR::Instruction *slotPatchInstruction = NULL;12921293TR::Method *method = site.getMethodSymbol()->getMethod();1294TR_OpaqueClassBlock *declaringClass = NULL;1295uintptr_t itableIndex;1296if ( useLastITableCache1297&& (declaringClass = site.getSymbolReference()->getOwningMethod(comp())->getResolvedInterfaceMethod(site.getSymbolReference()->getCPIndex(), &itableIndex))1298&& performTransformation(comp(), "O^O useLastITableCache for n%dn itableIndex=%d: %.*s.%.*s%.*s\n",1299site.getCallNode()->getGlobalIndex(), (int)itableIndex,1300method->classNameLength(), method->classNameChars(),1301method->nameLength(), method->nameChars(),1302method->signatureLength(), method->signatureChars()))1303{1304buildInterfaceDispatchUsingLastITable (site, numIPicSlots, lastPicSlot, slotPatchInstruction, doneLabel, lookupDispatchSnippetLabel, declaringClass, itableIndex);1305}1306else1307{1308// Last PIC slot is long branch to lookup snippet, fall through to doneLabel1309lastPicSlot.setNeedsLongConditionalBranch();1310slotPatchInstruction = buildPICSlot(lastPicSlot, lookupDispatchSnippetLabel, NULL, site);1311}13121313TR::Instruction *startOfPicInstruction = site.getFirstPICSlotInstruction();1314TR::X86PicDataSnippet *snippet = new (trHeapMemory()) TR::X86PicDataSnippet(1315numIPicSlots,1316startOfPicInstruction,1317lookupDispatchSnippetLabel,1318doneLabel,1319site.getSymbolReference(),1320slotPatchInstruction,1321site.getThunkAddress(),1322true,1323cg());13241325snippet->gcMap().setGCRegisterMask(site.getPreservedRegisterMask());1326cg()->addSnippet(snippet);13271328cg()->incPicSlotCountBy(IPicParameters.defaultNumberOfSlots);1329numIPICs = IPicParameters.defaultNumberOfSlots;13301331cg()->reserveNTrampolines(numIPICs);1332}13331334void J9::X86::AMD64::PrivateLinkage::buildVirtualOrComputedCall(TR::X86CallSite &site, TR::LabelSymbol *entryLabel, TR::LabelSymbol *doneLabel, uint8_t *thunk)1335{1336TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());1337if (entryLabel)1338generateLabelInstruction(TR::InstOpCode::label, site.getCallNode(), entryLabel, cg());13391340TR::SymbolReference *methodSymRef = site.getSymbolReference();1341if (comp()->getOption(TR_TraceCG))1342{1343traceMsg(comp(), "buildVirtualOrComputedCall(%p), isComputed=%d\n", site.getCallNode(), methodSymRef->getSymbol()->castToMethodSymbol()->isComputed());1344}13451346bool evaluateVftEarly = methodSymRef->isUnresolved()1347|| !fej9->isResolvedVirtualDispatchGuaranteed(comp());13481349if (methodSymRef->getSymbol()->castToMethodSymbol()->isComputed())1350{1351buildVFTCall(site, TR::InstOpCode::CALLReg, site.evaluateVFT(), NULL);1352}1353else if (evaluateVftEarly)1354{1355site.evaluateVFT(); // We must evaluate the VFT here to avoid a later evaluation that pollutes the VPic shape.1356buildVPIC(site, entryLabel, doneLabel);1357}1358else if (site.resolvedVirtualShouldUseVFTCall())1359{1360// Call through VFT1361//1362if (comp()->compileRelocatableCode())1363{1364// Non-SVM AOT still has to force unresolved virtual dispatch, which1365// works there because it won't transform other things into virtual1366// calls, e.g. invokeinterface of an Object method.1367TR_ASSERT_FATAL(1368comp()->getOption(TR_UseSymbolValidationManager),1369"resolved virtual dispatch in AOT requires SVM");13701371void *thunk = site.getThunkAddress();1372TR_OpaqueMethodBlock *method = methodSymRef1373->getSymbol()1374->castToResolvedMethodSymbol()1375->getResolvedMethod()1376->getPersistentIdentifier();13771378comp()->getSymbolValidationManager()1379->addJ2IThunkFromMethodRecord(thunk, method);1380}13811382buildVFTCall(site, TR::InstOpCode::CALLMem, NULL, generateX86MemoryReference(site.evaluateVFT(), methodSymRef->getOffset(), cg()));1383}1384else1385{1386site.evaluateVFT(); // We must evaluate the VFT here to avoid a later evaluation that pollutes the VPic shape.1387buildVPIC(site, entryLabel, doneLabel);1388}1389}13901391TR::Register *J9::X86::AMD64::PrivateLinkage::buildJNIDispatch(TR::Node *callNode)1392{1393TR_ASSERT(0, "AMD64 implements JNI dispatch using a system linkage");1394return NULL;1395}13961397#endif139813991400