Path: blob/master/runtime/compiler/x/codegen/CallSnippet.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2000, 2022 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "x/codegen/CallSnippet.hpp"2324#include "codegen/CodeGenerator.hpp"25#include "codegen/Linkage_inlines.hpp"26#include "codegen/Relocation.hpp"27#include "codegen/SnippetGCMap.hpp"28#include "codegen/X86PrivateLinkage.hpp"29#include "env/CompilerEnv.hpp"30#include "env/IO.hpp"31#include "env/jittypes.h"32#include "env/VMJ9.h"33#include "il/LabelSymbol.hpp"34#include "il/MethodSymbol.hpp"35#include "il/Node.hpp"36#include "il/Node_inlines.hpp"37#include "il/RegisterMappedSymbol.hpp"38#include "il/ResolvedMethodSymbol.hpp"39#include "il/StaticSymbol.hpp"40#include "il/Symbol.hpp"4142bool TR::X86PicDataSnippet::shouldEmitJ2IThunkPointer()43{44if (!cg()->comp()->target().is64Bit())45return false; // no j2i thunks on 32-bit4647if (!isInterface())48return unresolvedDispatch(); // invokevirtual could be private4950// invokeinterface51if (cg()->comp()->compileRelocatableCode())52return true; // forced to assume it could be private/Object5354// Since interface method symrefs are always unresolved, check to see55// whether we know that it's a normal interface call. If we don't, then56// it could be private/Object.57uintptr_t itableIndex = (uintptr_t)-1;58int32_t cpIndex = _methodSymRef->getCPIndex();59TR_ResolvedMethod *owningMethod = _methodSymRef->getOwningMethod(cg()->comp());60TR_OpaqueClassBlock *interfaceClass =61owningMethod->getResolvedInterfaceMethod(cpIndex, &itableIndex);62return interfaceClass == NULL;63}6465uint8_t *TR::X86PicDataSnippet::encodeConstantPoolInfo(uint8_t *cursor)66{67TR::Compilation *comp = cg()->comp();68uintptr_t cpAddr = (uintptr_t)_methodSymRef->getOwningMethod(comp)->constantPool();69*(uintptr_t *)cursor = cpAddr;7071uintptr_t inlinedSiteIndex = (uintptr_t)-1;72if (_startOfPicInstruction->getNode() != NULL)73inlinedSiteIndex = _startOfPicInstruction->getNode()->getInlinedSiteIndex();7475if (_hasJ2IThunkInPicData)76{77TR_ASSERT(78comp->target().is64Bit(),79"expecting a 64-bit target for thunk relocations");8081auto info =82(TR_RelocationRecordInformation *)comp->trMemory()->allocateMemory(83sizeof (TR_RelocationRecordInformation),84heapAlloc);8586int offsetToJ2IVirtualThunk = isInterface() ? 0x22 : 0x18;8788info->data1 = cpAddr;89info->data2 = inlinedSiteIndex;90info->data3 = offsetToJ2IVirtualThunk;9192cg()->addExternalRelocation(93new (cg()->trHeapMemory()) TR::ExternalRelocation(94cursor,95(uint8_t *)info,96NULL,97TR_J2IVirtualThunkPointer,98cg()),99__FILE__,100__LINE__,101_startOfPicInstruction->getNode());102}103else if (_thunkAddress)104{105TR_ASSERT(comp->target().is64Bit(), "expecting a 64-bit target for thunk relocations");106cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,107*(uint8_t **)cursor,108(uint8_t *)inlinedSiteIndex,109TR_Thunks, cg()),110__FILE__,111__LINE__,112_startOfPicInstruction->getNode());113}114else115{116cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,117(uint8_t *)cpAddr,118(uint8_t *)inlinedSiteIndex,119TR_ConstantPool,120cg()),121__FILE__,122__LINE__,123_startOfPicInstruction->getNode());124}125126// DD/DQ cpIndex127//128cursor += sizeof(uintptr_t);129*(uintptr_t *)cursor = (uintptr_t)_methodSymRef->getCPIndexForVM();130cursor += sizeof(uintptr_t);131132return cursor;133}134135uint8_t *TR::X86PicDataSnippet::encodeJ2IThunkPointer(uint8_t *cursor)136{137TR_ASSERT_FATAL(_hasJ2IThunkInPicData, "did not expect j2i thunk pointer");138TR_ASSERT_FATAL(_thunkAddress != NULL, "null virtual j2i thunk");139140// DD/DQ j2iThunk141*(uintptr_t *)cursor = (uintptr_t)_thunkAddress;142cursor += sizeof(uintptr_t);143144return cursor;145}146147uint8_t *TR::X86PicDataSnippet::emitSnippetBody()148{149TR::Compilation *comp = cg()->comp();150151uint8_t *startOfSnippet = cg()->getBinaryBufferCursor();152153uint8_t *cursor = startOfSnippet;154155J9::X86::PrivateLinkage *x86Linkage = static_cast<J9::X86::PrivateLinkage *>(cg()->getLinkage());156157int32_t disp32;158159TR_RuntimeHelper resolveSlotHelper, populateSlotHelper;160int32_t sizeofPicSlot;161162if (isInterface())163{164// IPIC165//166// Slow interface lookup dispatch.167//168169// Align the IPIC data to a pointer-sized boundary to ensure that the170// interface class and itable offset are naturally aligned.171uintptr_t offsetToIpicData = 10;172uintptr_t unalignedIpicDataStart = (uintptr_t)cursor + offsetToIpicData;173uintptr_t alignMask = sizeof (uintptr_t) - 1;174uintptr_t alignedIpicDataStart =175(unalignedIpicDataStart + alignMask) & ~alignMask;176cursor += alignedIpicDataStart - unalignedIpicDataStart;177178getSnippetLabel()->setCodeLocation(cursor);179180// Slow path lookup dispatch181//182_dispatchSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_X86IPicLookupDispatch);183184*cursor++ = 0xe8; // CALL185disp32 = cg()->branchDisplacementToHelperOrTrampoline(cursor+4, _dispatchSymRef);186*(int32_t *)cursor = disp32;187188cg()->addExternalRelocation(new (cg()->trHeapMemory())189TR::ExternalRelocation(cursor,190(uint8_t *)_dispatchSymRef,191TR_HelperAddress,192cg()), __FILE__, __LINE__, _startOfPicInstruction->getNode());193cursor += 4;194195// Lookup dispatch needs its stack map here.196//197gcMap().registerStackMap(cursor, cg());198199// Restart jump (always long for predictable size).200//201disp32 = _doneLabel->getCodeLocation() - (cursor + 5);202*cursor++ = 0xe9;203*(int32_t *)cursor = disp32;204cursor += 4;205206// DD/DQ constantPool address207// DD/DQ cpIndex208//209if (unresolvedDispatch())210{211cursor = encodeConstantPoolInfo(cursor);212}213else214{215TR_ASSERT_FATAL(0, "Can't handle resolved IPICs here yet!");216}217218// Because the interface class and itable offset (immediately following)219// are written at runtime and might be read concurrently by another220// thread, they must be naturally aligned to guarantee that all accesses221// to them are atomic.222TR_ASSERT_FATAL(223((uintptr_t)cursor & (sizeof(uintptr_t) - 1)) == 0,224"interface class and itable offset IPIC data slots are unaligned");225226// Reserve space for resolved interface class and itable offset.227// These slots will be populated during interface class resolution.228// The itable offset slot doubles as a direct J9Method pointer slot.229//230// DD/DQ 0x00000000231// DD/DQ 0x00000000232//233*(uintptr_t*)cursor = 0;234cursor += sizeof(uintptr_t);235*(uintptr_t*)cursor = 0;236cursor += sizeof(uintptr_t);237238if (comp->target().is64Bit())239{240// REX+MOV of MOVRegImm64 instruction241//242uint16_t *slotPatchInstructionBytes = (uint16_t *)_slotPatchInstruction->getBinaryEncoding();243*(uint16_t *)cursor = *slotPatchInstructionBytes;244cursor += 2;245246if (unresolvedDispatch() && _hasJ2IThunkInPicData)247cursor = encodeJ2IThunkPointer(cursor);248}249else250{251// ModRM byte of TR::InstOpCode::CMPMemImm4 instruction252//253uint8_t *slotPatchInstructionBytes = _slotPatchInstruction->getBinaryEncoding();254*cursor = *(slotPatchInstructionBytes+1);255cursor++;256}257258resolveSlotHelper = TR_X86resolveIPicClass;259populateSlotHelper = TR_X86populateIPicSlotClass;260sizeofPicSlot = x86Linkage->IPicParameters.roundedSizeOfSlot;261}262else263{264// VPIC265//266// Slow path dispatch through vtable267//268269uint8_t callModRMByte = 0;270271// DD/DQ constantPool address272// DD/DQ cpIndex273//274if (unresolvedDispatch())275{276// Align the real snippet entry point because it will be patched with277// the vtable dispatch when the method is resolved.278//279intptr_t entryPoint = ((intptr_t)cursor +280((3 * sizeof(uintptr_t)) +281(hasJ2IThunkInPicData() ? sizeof(uintptr_t) : 0) +282(comp->target().is64Bit() ? 4 : 1)));283284intptr_t requiredEntryPoint =285(entryPoint + (cg()->getLowestCommonCodePatchingAlignmentBoundary()-1) &286(intptr_t)(~(cg()->getLowestCommonCodePatchingAlignmentBoundary()-1)));287288cursor += (requiredEntryPoint - entryPoint);289290// Put the narrow integers before the pointer-sized ones. This way,291// directMethod (which is mutable) will be aligned simply as a292// consequence of the alignment required for patching the code that293// immediately follows the VPIC data.294if (comp->target().is64Bit())295{296// REX prefix of MOVRegImm64 instruction297//298uint8_t *slotPatchInstructionBytes = (uint8_t *)_slotPatchInstruction->getBinaryEncoding();299*cursor++ = *slotPatchInstructionBytes++;300301// MOV op of MOVRegImm64 instruction302//303*cursor++ = *slotPatchInstructionBytes;304305// REX prefix for the TR::InstOpCode::CALLMem instruction.306//307*cursor++ = *(slotPatchInstructionBytes+9);308309// Convert the CMP ModRM byte into the ModRM byte for the TR::InstOpCode::CALLMem instruction.310//311slotPatchInstructionBytes += 11;312callModRMByte = (*slotPatchInstructionBytes & 7) + 0x90;313*cursor++ = callModRMByte;314}315else316{317// CMP ModRM byte318//319uint8_t *slotPatchInstructionBytes = (uint8_t *)_slotPatchInstruction->getBinaryEncoding();320*cursor++ = *(slotPatchInstructionBytes+1);321}322323// DD/DQ cpAddr324// DD/DQ cpIndex325//326cursor = encodeConstantPoolInfo(cursor);327328// Because directMethod (immediately following) is written at runtime329// and might be read concurrently by another thread, it must be330// naturally aligned to ensure that all accesses to it are atomic.331TR_ASSERT_FATAL(332((uintptr_t)cursor & (sizeof(uintptr_t) - 1)) == 0,333"directMethod VPIC data slot is unaligned");334335// DD/DQ directMethod (initially null)336*(uintptr_t *)cursor = 0;337cursor += sizeof(uintptr_t);338339if (comp->target().is64Bit())340{341// DD/DQ j2iThunk342cursor = encodeJ2IThunkPointer(cursor);343}344}345else346{347TR_ASSERT_FATAL(0, "Can't handle resolved VPICs here yet!");348}349350_dispatchSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_X86populateVPicVTableDispatch);351352getSnippetLabel()->setCodeLocation(cursor);353354if (!isInterface() && _methodSymRef->isUnresolved())355{356TR_ASSERT((((intptr_t)cursor & (cg()->getLowestCommonCodePatchingAlignmentBoundary()-1)) == 0),357"Mis-aligned VPIC snippet");358}359360*cursor++ = 0xe8; // CALL361disp32 = cg()->branchDisplacementToHelperOrTrampoline(cursor+4, _dispatchSymRef);362*(int32_t *)cursor = disp32;363364cg()->addExternalRelocation(new (cg()->trHeapMemory())365TR::ExternalRelocation(cursor,366(uint8_t *)_dispatchSymRef,367TR_HelperAddress,368cg()), __FILE__, __LINE__, _startOfPicInstruction->getNode());369cursor += 4;370371// Populate vtable dispatch needs its stack map here.372//373gcMap().registerStackMap(cursor, cg());374375// Add padding after the call to snippet to hold the eventual indirect call instruction.376//377if (comp->target().is64Bit())378{379*(uint16_t *)cursor = 0;380cursor += 2;381382if (callModRMByte == 0x94)383{384// SIB byte required for CMP385//386*(uint8_t *)cursor = 0;387cursor++;388}389}390else391{392*(uint8_t *)cursor = 0;393cursor++;394}395396// Restart jump (always long for predictable size).397//398// TODO: no longer the case since data moved before call.399//400disp32 = _doneLabel->getCodeLocation() - (cursor + 5);401*cursor++ = 0xe9;402*(int32_t *)cursor = disp32;403cursor += 4;404405resolveSlotHelper = TR_X86resolveVPicClass;406populateSlotHelper = TR_X86populateVPicSlotClass;407sizeofPicSlot = x86Linkage->VPicParameters.roundedSizeOfSlot;408}409410if (_numberOfSlots >= 1)411{412// Patch each Pic slot to route through the population helper413//414int32_t numPicSlots = _numberOfSlots;415uint8_t *picSlotCursor = _startOfPicInstruction->getBinaryEncoding();416417TR::SymbolReference *resolveSlotHelperSymRef =418cg()->symRefTab()->findOrCreateRuntimeHelper(resolveSlotHelper);419TR::SymbolReference *populateSlotHelperSymRef =420cg()->symRefTab()->findOrCreateRuntimeHelper(populateSlotHelper);421422// Patch first slot test with call to resolution helper.423//424*picSlotCursor++ = 0xe8; // CALL425disp32 = cg()->branchDisplacementToHelperOrTrampoline(picSlotCursor+4, resolveSlotHelperSymRef);426*(int32_t *)picSlotCursor = disp32;427428cg()->addExternalRelocation(new (cg()->trHeapMemory())429TR::ExternalRelocation(picSlotCursor,430(uint8_t *)resolveSlotHelperSymRef,431TR_HelperAddress,432cg()), __FILE__, __LINE__, _startOfPicInstruction->getNode());433434picSlotCursor = (uint8_t *)(picSlotCursor - 1 + sizeofPicSlot);435436// Patch remaining slots with call to populate helper.437//438while (--numPicSlots)439{440*picSlotCursor++ = 0xe8; // CALL441disp32 = cg()->branchDisplacementToHelperOrTrampoline(picSlotCursor+4, populateSlotHelperSymRef);442*(int32_t *)picSlotCursor = disp32;443444cg()->addExternalRelocation(new (cg()->trHeapMemory())445TR::ExternalRelocation(picSlotCursor,446(uint8_t *)populateSlotHelperSymRef,447TR_HelperAddress,448cg()), __FILE__, __LINE__, _startOfPicInstruction->getNode());449picSlotCursor = (uint8_t *)(picSlotCursor - 1 + sizeofPicSlot);450}451}452453return cursor;454}455456457void458TR_Debug::print(TR::FILE *pOutFile, TR::X86PicDataSnippet *snippet)459{460if (pOutFile == NULL)461return;462463TR_J9VMBase *fej9 = (TR_J9VMBase *)(_cg->fe());464465uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();466467// Account for VPic data appearing before the actual entry label.468//469if (!snippet->isInterface())470{471// TODO: clean this up!472//473bufferPos -= _comp->target().is64Bit() ? 4 : 1;474bufferPos -= 2 * sizeof(uintptr_t);475if (snippet->unresolvedDispatch())476{477bufferPos -= sizeof(uintptr_t);478if (snippet->hasJ2IThunkInPicData())479bufferPos -= sizeof(uintptr_t);480}481482uint32_t offset = bufferPos - _cg->getCodeStart();483trfprintf(pOutFile, "\n\n" POINTER_PRINTF_FORMAT " %08x %*s", bufferPos, offset, 65, " <<< VPic Data >>>");484}485else486{487printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet));488}489490TR::SymbolReference *methodSymRef = snippet->getMethodSymRef();491TR::SymbolReference *dispatchSymRef = snippet->getDispatchSymRef();492493if (snippet->isInterface())494{495// Call lookup dispatch.496//497printPrefix(pOutFile, NULL, bufferPos, 5);498trfprintf(pOutFile, "call\t%s \t\t%s " POINTER_PRINTF_FORMAT,499getName(dispatchSymRef),500commentString(),501dispatchSymRef->getMethodAddress());502bufferPos += 5;503504// Restart JMP (always 5 bytes).505//506printPrefix(pOutFile, NULL, bufferPos, 5);507printLabelInstruction(pOutFile, "jmp", snippet->getDoneLabel());508bufferPos += 5;509510if (methodSymRef->isUnresolved())511{512const char *op = (sizeof(uintptr_t) == 4) ? "DD" : "DQ";513514printPrefix(pOutFile, NULL, bufferPos, sizeof(uintptr_t));515trfprintf(516pOutFile,517"%s\t" POINTER_PRINTF_FORMAT "\t\t%s owning method cpAddr",518op,519(void*)*(uintptr_t*)bufferPos,520commentString());521bufferPos += sizeof(uintptr_t);522523printPrefix(pOutFile, NULL, bufferPos, sizeof(uintptr_t));524trfprintf(525pOutFile,526"%s\t" POINTER_PRINTF_FORMAT "\t\t%s cpIndex",527op,528(void*)*(uintptr_t*)bufferPos,529commentString());530bufferPos += sizeof(uintptr_t);531532printPrefix(pOutFile, NULL, bufferPos, sizeof(uintptr_t));533trfprintf(534pOutFile,535"%s\t" POINTER_PRINTF_FORMAT "\t\t%s interface class (initially null)",536op,537(void*)*(uintptr_t*)bufferPos,538commentString());539bufferPos += sizeof(uintptr_t);540541printPrefix(pOutFile, NULL, bufferPos, sizeof(uintptr_t));542trfprintf(543pOutFile,544"%s\t" POINTER_PRINTF_FORMAT "\t\t%s itable offset%s (initially zero)",545op,546(void*)*(uintptr_t*)bufferPos,547commentString(),548snippet->hasJ2IThunkInPicData() ? " or direct J9Method" : "");549bufferPos += sizeof(uintptr_t);550551if (_comp->target().is64Bit())552{553// REX+MOV of MOVRegImm64 instruction554//555printPrefix(pOutFile, NULL, bufferPos, 1);556trfprintf(pOutFile, "%s\t%s%02x%s\t\t\t\t\t\t\t\t%s REX of MOVRegImm64",557dbString(),558hexPrefixString(),559*bufferPos,560hexSuffixString(),561commentString());562bufferPos += 1;563564printPrefix(pOutFile, NULL, bufferPos, 1);565trfprintf(pOutFile, "%s\t%02x\t\t\t\t\t\t\t\t%s MOV opcode of MOVRegImm64",566dbString(),567*bufferPos,568commentString());569bufferPos += 1;570571if (snippet->hasJ2IThunkInPicData())572{573printPrefix(pOutFile, NULL, bufferPos, sizeof(uintptr_t));574trfprintf(575pOutFile,576"%s\t" POINTER_PRINTF_FORMAT "\t\t%s j2i virtual thunk",577op,578(void*)*(uintptr_t*)bufferPos,579commentString());580bufferPos += sizeof(uintptr_t);581}582}583else584{585// ModRM of TR::InstOpCode::CMPRegImm4586//587printPrefix(pOutFile, NULL, bufferPos, 1);588trfprintf(pOutFile, "%s\t%s%02x%s\t\t\t\t\t\t\t\t%s ModRM of CMP",589dbString(),590hexPrefixString(),591*bufferPos,592hexSuffixString(),593commentString());594bufferPos += 1;595}596}597}598else599{600uint8_t callModRM = 0;601602if (snippet->unresolvedDispatch())603{604const char *op = (sizeof(uintptr_t) == 4) ? "DD" : "DQ";605606if (_comp->target().is64Bit())607{608printPrefix(pOutFile, NULL, bufferPos, 1);609trfprintf(pOutFile, "%s\t%02x\t\t\t\t\t\t\t\t%s REX of MOVRegImm64",610dbString(),611*bufferPos,612commentString());613bufferPos += 1;614615printPrefix(pOutFile, NULL, bufferPos, 1);616trfprintf(pOutFile, "%s\t%02x\t\t\t\t\t\t\t\t%s MOV opcode of MOVRegImm64",617dbString(),618*bufferPos,619commentString());620bufferPos += 1;621622printPrefix(pOutFile, NULL, bufferPos, 1);623trfprintf(pOutFile, "%s\t%02x\t\t\t\t\t\t\t\t%s REX of CallMem",624dbString(),625*bufferPos,626commentString());627bufferPos += 1;628629callModRM = *bufferPos;630printPrefix(pOutFile, NULL, bufferPos, 1);631trfprintf(pOutFile, "%s\t%02x\t\t\t\t\t\t\t\t%s ModRM for TR::InstOpCode::CALLMem",632dbString(),633*bufferPos,634commentString());635bufferPos += 1;636}637else638{639printPrefix(pOutFile, NULL, bufferPos, 1);640trfprintf(pOutFile, "%s\t%02x\t\t\t\t\t\t\t\t%s ModRM for TR::InstOpCode::CMPRegImm4",641dbString(),642*bufferPos,643commentString());644bufferPos += 1;645}646647printPrefix(pOutFile, NULL, bufferPos, sizeof(uintptr_t));648trfprintf(649pOutFile,650"%s\t" POINTER_PRINTF_FORMAT "\t\t%s owning method cpAddr",651op,652(void*)*(uintptr_t*)bufferPos,653commentString());654bufferPos += sizeof(uintptr_t);655656printPrefix(pOutFile, NULL, bufferPos, sizeof(uintptr_t));657trfprintf(658pOutFile,659"%s\t" POINTER_PRINTF_FORMAT "\t\t%s cpIndex",660op,661(void*)*(uintptr_t*)bufferPos,662commentString());663bufferPos += sizeof(uintptr_t);664665printPrefix(pOutFile, NULL, bufferPos, sizeof(uintptr_t));666trfprintf(pOutFile,667"%s\t" POINTER_PRINTF_FORMAT "\t\t%s direct J9Method (initially null)",668op,669(void*)*(uintptr_t*)bufferPos,670commentString());671bufferPos += sizeof(uintptr_t);672673if (_comp->target().is64Bit())674{675printPrefix(pOutFile, NULL, bufferPos, sizeof(uintptr_t));676trfprintf(677pOutFile,678"%s\t" POINTER_PRINTF_FORMAT "\t\t%s j2i virtual thunk",679op,680(void*)*(uintptr_t*)bufferPos,681commentString());682bufferPos += sizeof(uintptr_t);683}684}685686if (_comp->target().is64Bit())687printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet));688689// Call through vtable.690//691int32_t length;692693if (_comp->target().is64Bit())694{695length = 7;696if (callModRM == 0x94)697length++;698}699else700{701length = 6;702}703704printPrefix(pOutFile, NULL, bufferPos, length);705trfprintf(pOutFile, "call\t%s \t\t%s " POINTER_PRINTF_FORMAT "\tpatched with vtable call",706getName(dispatchSymRef),707commentString(),708dispatchSymRef->getMethodAddress());709bufferPos += length;710711// Restart JMP (always 5 bytes).712//713printPrefix(pOutFile, NULL, bufferPos, 5);714printLabelInstruction(pOutFile, "jmp", snippet->getDoneLabel());715bufferPos += 5;716717}718}719720721722uint32_t TR::X86PicDataSnippet::getLength(int32_t estimatedSnippetStart)723{724TR::Compilation *comp = cg()->comp();725726if (isInterface())727{728return 5 // Lookup dispatch729+ 5 // JMP done730+ (4 * sizeof(uintptr_t)) // Resolve slots731+ (comp->target().is64Bit() ? 2 : 1) // ModRM or REX+MOV732+ (_hasJ2IThunkInPicData ? sizeof(uintptr_t) : 0) // j2i thunk pointer733+ sizeof (uintptr_t) - 1; // alignment734}735else736{737return 6 // CALL [Mem] (pessimistically assume a SIB is needed)738+ (comp->target().is64Bit() ? 2 : 0) // REX for CALL + SIB for CALL (64-bit)739+ 5 // JMP done740+ (2 * sizeof(uintptr_t)) // cpAddr, cpIndex741+ (unresolvedDispatch() ? sizeof(uintptr_t) : 0) // directMethod742+ (_hasJ2IThunkInPicData ? sizeof(uintptr_t) : 0) // j2i thunk743744// 64-bit Data745// -----------746// 2 (REX+MOV)747// +2 (REX+ModRM for CALL)748//749// 32-bit Data750// -----------751// 1 (ModRM for CMP)752//753+ (comp->target().is64Bit() ? 4 : 1)754+ cg()->getLowestCommonCodePatchingAlignmentBoundary()-1;755}756}757758759uint8_t *760TR::X86CallSnippet::alignCursorForCodePatching(761uint8_t *cursor,762bool alignWithNOPs)763{764intptr_t alignedCursor =765((intptr_t)cursor + (cg()->getLowestCommonCodePatchingAlignmentBoundary()-1) &766(intptr_t)(~(cg()->getLowestCommonCodePatchingAlignmentBoundary()-1)));767768intptr_t paddingLength = alignedCursor - (intptr_t)cursor;769770if (alignWithNOPs && (paddingLength > 0))771{772return (uint8_t *)(cg()->generatePadding(cursor, paddingLength));773}774else775{776return (uint8_t *)alignedCursor;777}778}779780781uint8_t *TR::X86CallSnippet::emitSnippetBody()782{783TR::Compilation *comp = cg()->comp();784TR_J9VMBase* fej9 = (TR_J9VMBase *)(cg()->fe());785TR::SymbolReference* methodSymRef = _realMethodSymbolReference ? _realMethodSymbolReference : getNode()->getSymbolReference();786TR::MethodSymbol* methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();787uint8_t* cursor = cg()->getBinaryBufferCursor();788789bool needToSetCodeLocation = true;790bool isJitInduceOSRCall = false;791792if (comp->target().is64Bit() &&793methodSymbol->isHelper() &&794methodSymRef->isOSRInductionHelper())795{796isJitInduceOSRCall = true;797}798799if (comp->target().is64Bit())800{801// Backspill register linkage arguments to the stack.802//803TR::Linkage *linkage = cg()->getLinkage(methodSymbol->getLinkageConvention());804getSnippetLabel()->setCodeLocation(cursor);805cursor = linkage->storeArguments(getNode(), cursor, false, NULL);806needToSetCodeLocation = false;807808if (cg()->hasCodeCacheSwitched() &&809(methodSymRef->getReferenceNumber()>=TR_AMD64numRuntimeHelpers))810{811fej9->reserveTrampolineIfNecessary(comp, methodSymRef, true);812}813}814815bool forceUnresolvedDispatch = !fej9->isResolvedDirectDispatchGuaranteed(comp);816if (methodSymRef->isUnresolved() || forceUnresolvedDispatch)817{818// Unresolved interpreted dispatch snippet shape:819//820// 64-bit821// ======822// align 8823// (10) CALL interpreterUnresolved{Static|Special}Glue ; replaced with "mov rdi, 0x0000aabbccddeeff"824// (5) JMP interpreterStaticAndSpecialGlue825// (2) DW 2-byte glue method helper index826// (8) DQ cpAddr827// (4) DD cpIndex828//829// 32-bit830// ======831// align 8832// (5) CALL interpreterUnresolved{Static|Special}Glue ; replaced with "mov edi, 0xaabbccdd"833// (3) NOP834// (5) JMP interpreterStaticAndSpecialGlue835// (2) DW 2-byte glue method helper index836// (4) DD cpAddr837// (4) DD cpIndex838//839840TR_ASSERT(!isJitInduceOSRCall || !forceUnresolvedDispatch, "calling jitInduceOSR is not supported yet under AOT\n");841cursor = alignCursorForCodePatching(cursor, comp->target().is64Bit());842843if (comp->getOption(TR_EnableHCR))844{845cg()->jitAddUnresolvedAddressMaterializationToPatchOnClassRedefinition(cursor);846}847848if (needToSetCodeLocation)849{850getSnippetLabel()->setCodeLocation(cursor);851}852853TR_ASSERT((methodSymbol->isStatic() || methodSymbol->isSpecial() || forceUnresolvedDispatch), "Unexpected unresolved dispatch");854855// CALL interpreterUnresolved{Static|Special}Glue856//857TR_RuntimeHelper resolutionHelper = methodSymbol->isStatic() ?858TR_X86interpreterUnresolvedStaticGlue : TR_X86interpreterUnresolvedSpecialGlue;859860TR::SymbolReference *helperSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(resolutionHelper);861862*cursor++ = 0xe8; // CALL863*(int32_t *)cursor = cg()->branchDisplacementToHelperOrTrampoline(cursor + 4, helperSymRef);864865cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,866(uint8_t *)helperSymRef,867TR_HelperAddress,868cg()),869__FILE__, __LINE__, getNode());870cursor += 4;871872if (comp->target().is64Bit())873{874// 5 bytes of zeros to fill out the MOVRegImm64 instruction.875//876*(int32_t *)cursor = 0;877cursor += 4;878*cursor++ = 0x00;879}880else881{882// 3-byte NOP (executable).883//884cursor = cg()->generatePadding(cursor, 3);885}886887// JMP interpreterStaticAndSpecialGlue888//889helperSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_X86interpreterStaticAndSpecialGlue);890891*cursor++ = 0xe9; // JMP892*(int32_t *)cursor = cg()->branchDisplacementToHelperOrTrampoline(cursor + 4, helperSymRef);893894cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,895(uint8_t*)helperSymRef,896TR_HelperAddress,897cg()),898__FILE__, __LINE__, getNode());899cursor += 4;900901// DW dispatch helper index for the method's return type.902// this argument is not in use and hence will be cleaned-up in a subsequent changeset.903cursor += 2;904905// DD/DQ cpAddr906//907intptr_t cpAddr = (intptr_t)methodSymRef->getOwningMethod(comp)->constantPool();908*(intptr_t *)cursor = cpAddr;909910cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,911*(uint8_t **)cursor,912getNode() ? (uint8_t *)(uintptr_t)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,913TR_ConstantPool,914cg()),915__FILE__, __LINE__, getNode());916cursor += sizeof(intptr_t);917918// DD cpIndex919//920*(uint32_t *)cursor = methodSymRef->getCPIndexForVM();921cursor += 4;922}923else924{925// Resolved method dispatch.926//927// 64-bit928// ======929930// (10) MOV rdi, 0x0000aabbccddeeff ; load RAM method931// (5) JMP interpreterStaticAndSpecialGlue932//933// 32-bit934// ======935//936// (5) MOV edi, 0xaabbccdd ; load RAM method937// (5) JMP interpreterStaticAndSpecialGlue938//939940if (needToSetCodeLocation)941{942getSnippetLabel()->setCodeLocation(cursor);943}944945//SD: for jitInduceOSR we don't need to set the RAM method (the method that the VM needs to start executing)946//because VM is going to figure what method to execute by looking up the jitPC in the GC map and finding947//the desired invoke bytecode.948if (!isJitInduceOSRCall)949{950#if defined(J9VM_OPT_JITSERVER)951intptr_t ramMethod = comp->isOutOfProcessCompilation() && !methodSymbol->isInterpreted() ?952(intptr_t)methodSymRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->getPersistentIdentifier() :953(intptr_t)methodSymbol->getMethodAddress();954#else955intptr_t ramMethod = (intptr_t)methodSymbol->getMethodAddress();956#endif /* defined(J9VM_OPT_JITSERVER) */957958if (comp->target().is64Bit())959{960// MOV rdi, Imm64961//962*(uint16_t *)cursor = 0xbf48;963cursor += 2;964}965else966{967// MOV edi, Imm32968//969*cursor++ = 0xbf;970}971972*(intptr_t *)cursor = ramMethod;973974if (comp->getOption(TR_UseSymbolValidationManager))975{976cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,977(uint8_t *)ramMethod,978(uint8_t *)TR::SymbolType::typeMethod,979TR_SymbolFromManager,980cg()),981__FILE__, __LINE__, getNode());982}983984// HCR in TR::X86CallSnippet::emitSnippetBody register the method address985//986if (comp->getOption(TR_EnableHCR))987cg()->jitAddPicToPatchOnClassRedefinition((void *)ramMethod, (void *)cursor);988989cursor += sizeof(intptr_t);990}991992// JMP interpreterStaticAndSpecialGlue993//994*cursor++ = 0xe9;995996TR::SymbolReference* dispatchSymRef =997methodSymbol->isHelper() && methodSymRef->isOSRInductionHelper() ? methodSymRef :998cg()->symRefTab()->findOrCreateRuntimeHelper(TR_X86interpreterStaticAndSpecialGlue);9991000*(int32_t *)cursor = cg()->branchDisplacementToHelperOrTrampoline(cursor + 4, dispatchSymRef);10011002cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,1003(uint8_t *)dispatchSymRef,1004TR_HelperAddress,1005cg()),1006__FILE__, __LINE__, getNode());1007cursor += 4;1008}10091010return cursor;1011}101210131014uint32_t TR::X86CallSnippet::getLength(int32_t estimatedSnippetStart)1015{1016TR::Compilation *comp = cg()->comp();1017TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg()->fe());1018uint32_t length = 0;10191020TR::SymbolReference *methodSymRef = _realMethodSymbolReference ? _realMethodSymbolReference : getNode()->getSymbolReference();1021TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();10221023if (comp->target().is64Bit())1024{1025TR::Linkage *linkage = cg()->getLinkage(methodSymbol->getLinkageConvention());10261027int32_t codeSize;1028(void)linkage->storeArguments(getNode(), NULL, true, &codeSize);1029length += codeSize;1030}10311032bool forceUnresolvedDispatch = !fej9->isResolvedDirectDispatchGuaranteed(comp);1033if (methodSymRef->isUnresolved() || forceUnresolvedDispatch)1034{1035// +7 accounts for maximum length alignment padding.1036//1037if (comp->target().is64Bit())1038length += (7+10+5+2+8+4);1039else1040length += (7+5+3+5+2+4+4);1041}1042else1043{1044if (comp->target().is64Bit())1045length += (10+5);1046else1047length += (5+5);1048}10491050return length;1051}105210531054