Path: blob/master/runtime/compiler/x/i386/codegen/IA32PrivateLinkage.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 "codegen/IA32PrivateLinkage.hpp"2324#include "codegen/CodeGenerator.hpp"25#include "codegen/Linkage_inlines.hpp"26#include "codegen/LiveRegister.hpp"27#include "codegen/Machine.hpp"28#include "codegen/MemoryReference.hpp"29#include "codegen/RealRegister.hpp"30#include "codegen/Register.hpp"31#include "codegen/RegisterPair.hpp"32#include "codegen/Snippet.hpp"33#include "compile/Method.hpp"34#include "compile/ResolvedMethod.hpp"35#include "control/Recompilation.hpp"36#include "control/RecompilationInfo.hpp"37#include "env/CHTable.hpp"38#include "env/jittypes.h"39#include "env/CompilerEnv.hpp"40#include "il/Node.hpp"41#include "il/Node_inlines.hpp"42#include "env/VMJ9.h"43#include "x/codegen/CallSnippet.hpp"44#include "x/codegen/CheckFailureSnippet.hpp"45#include "x/codegen/FPTreeEvaluator.hpp"46#include "x/codegen/HelperCallSnippet.hpp"47#include "x/codegen/IA32LinkageUtils.hpp"48#include "x/codegen/X86Instruction.hpp"4950J9::X86::I386::PrivateLinkage::PrivateLinkage(TR::CodeGenerator *cg)51: J9::X86::PrivateLinkage(cg)52{53_properties._properties = 0;54_properties._registerFlags[TR::RealRegister::NoReg] = 0;55_properties._registerFlags[TR::RealRegister::eax] = IntegerReturn;56_properties._registerFlags[TR::RealRegister::ebx] = Preserved;57_properties._registerFlags[TR::RealRegister::ecx] = Preserved;58_properties._registerFlags[TR::RealRegister::edx] = IntegerReturn;59_properties._registerFlags[TR::RealRegister::edi] = 0;60_properties._registerFlags[TR::RealRegister::esi] = Preserved;61_properties._registerFlags[TR::RealRegister::ebp] = Preserved;62_properties._registerFlags[TR::RealRegister::esp] = Preserved;6364for (int i = 0; i <= 7; i++)65{66_properties._registerFlags[TR::RealRegister::xmmIndex(i)] = 0;67}6869_properties._registerFlags[TR::RealRegister::xmm0] = FloatReturn;7071_properties._preservedRegisters[0] = TR::RealRegister::ebx;72_properties._preservedRegisters[1] = TR::RealRegister::ecx;73_properties._preservedRegisters[2] = TR::RealRegister::esi;74_properties._maxRegistersPreservedInPrologue = 3;75_properties._preservedRegisters[3] = TR::RealRegister::ebp;76_properties._preservedRegisters[4] = TR::RealRegister::esp;77_properties._numPreservedRegisters = 5;7879_properties._argumentRegisters[0] = TR::RealRegister::NoReg;8081_properties._numIntegerArgumentRegisters = 0;82_properties._firstIntegerArgumentRegister = 0;83_properties._numFloatArgumentRegisters = 0;84_properties._firstFloatArgumentRegister = 0;8586_properties._returnRegisters[0] = TR::RealRegister::eax;87_properties._returnRegisters[1] = TR::RealRegister::xmm0;88_properties._returnRegisters[2] = TR::RealRegister::edx;8990_properties._scratchRegisters[0] = TR::RealRegister::edi;91_properties._scratchRegisters[1] = TR::RealRegister::edx;92_properties._numScratchRegisters = 2;9394_properties._preservedRegisterMapForGC = // TODO:AMD64: Use the proper mask value95( (1 << (TR::RealRegister::ebx-1)) | // Preserved register map for GC96(1 << (TR::RealRegister::ecx-1)) |97(1 << (TR::RealRegister::esi-1)) |98(1 << (TR::RealRegister::ebp-1)) |99(1 << (TR::RealRegister::esp-1))),100101_properties._vtableIndexArgumentRegister = TR::RealRegister::edx;102_properties._j9methodArgumentRegister = TR::RealRegister::edi;103_properties._framePointerRegister = TR::RealRegister::ebx;104_properties._methodMetaDataRegister = TR::RealRegister::ebp;105106_properties._numberOfVolatileGPRegisters = 3;107_properties._numberOfVolatileXMMRegisters = 8; // xmm0-xmm7108setOffsetToFirstParm(4);109_properties._offsetToFirstLocal = 0;110111112// 173135: If we are too eager picking the byte regs, we won't have any113// available for byte operations in the code, and we'll need register114// shuffles. Normally, shuffles are no big deal, but if they occur right115// before byte operations, we can end up with partial register stalls which116// are as bad as spills.117//118// Most byte operations in Java come from byte array element operations.119// Array indexing expressions practically never need byte registers, so120// while favouring non-byte regs for GRA could hurt byte candidates from121// array elements, it should practically never hurt indexing expressions.122// We expect array indexing expressions to need global regs far more often123// than array elements, so favouring non-byte registers makes sense, all124// else being equal.125//126// Ideally, pickRegister would detect the use of byte expressions and do127// the right thing.128129// volatiles, non-byte-reg first130_properties._allocationOrder[0] = TR::RealRegister::edi;131_properties._allocationOrder[1] = TR::RealRegister::edx;132_properties._allocationOrder[2] = TR::RealRegister::eax;133// preserved, non-byte-reg first134_properties._allocationOrder[3] = TR::RealRegister::esi;135_properties._allocationOrder[4] = TR::RealRegister::ebx;136_properties._allocationOrder[5] = TR::RealRegister::ecx;137_properties._allocationOrder[6] = TR::RealRegister::ebp;138// floating point139_properties._allocationOrder[7] = TR::RealRegister::st0;140_properties._allocationOrder[8] = TR::RealRegister::st1;141_properties._allocationOrder[9] = TR::RealRegister::st2;142_properties._allocationOrder[10] = TR::RealRegister::st3;143_properties._allocationOrder[11] = TR::RealRegister::st4;144_properties._allocationOrder[12] = TR::RealRegister::st5;145_properties._allocationOrder[13] = TR::RealRegister::st6;146_properties._allocationOrder[14] = TR::RealRegister::st7;147}148149TR::Instruction *J9::X86::I386::PrivateLinkage::savePreservedRegisters(TR::Instruction *cursor)150{151TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();152const int32_t localSize = _properties.getOffsetToFirstLocal() - bodySymbol->getLocalMappingCursor();153const int32_t pointerSize = _properties.getPointerSize();154155int32_t offsetCursor = -localSize - _properties.getPointerSize();156int32_t numPreserved = getProperties().getMaxRegistersPreservedInPrologue();157158for (int32_t pindex = numPreserved-1;159pindex >= 0;160pindex--)161{162TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex);163TR::RealRegister *reg = machine()->getRealRegister(idx);164if (reg->getHasBeenAssignedInMethod() && reg->getState() != TR::RealRegister::Locked)165{166cursor = generateMemRegInstruction(167cursor,168TR::InstOpCode::S4MemReg,169generateX86MemoryReference(machine()->getRealRegister(TR::RealRegister::vfp), offsetCursor, cg()),170reg,171cg()172);173offsetCursor -= pointerSize;174}175}176return cursor;177}178179TR::Instruction *J9::X86::I386::PrivateLinkage::restorePreservedRegisters(TR::Instruction *cursor)180{181TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();182const int32_t localSize = _properties.getOffsetToFirstLocal() - bodySymbol->getLocalMappingCursor();183const int32_t pointerSize = _properties.getPointerSize();184185int32_t offsetCursor = -localSize - _properties.getPointerSize();186int32_t numPreserved = getProperties().getMaxRegistersPreservedInPrologue();187for (int32_t pindex = numPreserved-1;188pindex >= 0;189pindex--)190{191TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex);192TR::RealRegister *reg = machine()->getRealRegister(idx);193if (reg->getHasBeenAssignedInMethod())194{195cursor = generateRegMemInstruction(196cursor,197TR::InstOpCode::L4RegMem,198reg,199generateX86MemoryReference(machine()->getRealRegister(TR::RealRegister::vfp), offsetCursor, cg()),200cg()201);202offsetCursor -= pointerSize;203}204}205return cursor;206}207208209int32_t J9::X86::I386::PrivateLinkage::buildArgs(210TR::Node *callNode,211TR::RegisterDependencyConditions *dependencies)212{213int32_t argSize = 0;214TR::Register *eaxRegister = NULL;215TR::Node *thisChild = NULL;216int32_t firstArgumentChild = callNode->getFirstArgumentIndex();217int32_t linkageRegChildIndex = -1;218219int32_t receiverChildIndex = -1;220if (callNode->getSymbol()->castToMethodSymbol()->firstArgumentIsReceiver() && callNode->getOpCode().isIndirect())221receiverChildIndex = firstArgumentChild;222223if (!callNode->getSymbolReference()->isUnresolved())224switch(callNode->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod())225{226case TR::java_lang_invoke_ComputedCalls_dispatchJ9Method:227case TR::java_lang_invoke_ComputedCalls_dispatchVirtual:228case TR::com_ibm_jit_JITHelpers_dispatchVirtual:229linkageRegChildIndex = firstArgumentChild;230receiverChildIndex = callNode->getOpCode().isIndirect()? firstArgumentChild+1 : -1;231}232233for (int i = firstArgumentChild; i < callNode->getNumChildren(); i++)234{235TR::Node *child = callNode->getChild(i);236switch (child->getDataType())237{238case TR::Int8:239case TR::Int16:240case TR::Int32:241case TR::Address:242if (i == receiverChildIndex)243{244eaxRegister = pushThis(child);245thisChild = child;246}247else248{249pushIntegerWordArg(child);250}251argSize += 4;252break;253case TR::Int64:254{255TR::Register *reg = NULL;256if (i == linkageRegChildIndex)257{258// TODO:JSR292: This should really be in the front-end259TR::MethodSymbol *sym = callNode->getSymbol()->castToMethodSymbol();260switch (sym->getMandatoryRecognizedMethod())261{262case TR::java_lang_invoke_ComputedCalls_dispatchJ9Method:263reg = cg()->evaluate(child);264if (reg->getRegisterPair())265reg = reg->getRegisterPair()->getLowOrder();266dependencies->addPreCondition(reg, getProperties().getJ9MethodArgumentRegister(), cg());267cg()->decReferenceCount(child);268break;269case TR::java_lang_invoke_ComputedCalls_dispatchVirtual:270case TR::com_ibm_jit_JITHelpers_dispatchVirtual:271reg = cg()->evaluate(child);272if (reg->getRegisterPair())273reg = reg->getRegisterPair()->getLowOrder();274dependencies->addPreCondition(reg, getProperties().getVTableIndexArgumentRegister(), cg());275cg()->decReferenceCount(child);276break;277}278}279if (!reg)280{281TR::IA32LinkageUtils::pushLongArg(child, cg());282argSize += 8;283}284break;285}286case TR::Float:287TR::IA32LinkageUtils::pushFloatArg(child, cg());288argSize += 4;289break;290case TR::Double:291TR::IA32LinkageUtils::pushDoubleArg(child, cg());292argSize += 8;293break;294}295}296297if (thisChild)298{299TR::Register *rcvrReg = cg()->evaluate(thisChild);300301if (thisChild->getReferenceCount() > 1)302{303eaxRegister = cg()->allocateCollectedReferenceRegister();304generateRegRegInstruction(TR::InstOpCode::MOV4RegReg, thisChild, eaxRegister, rcvrReg, cg());305}306else307{308eaxRegister = rcvrReg;309}310311dependencies->addPreCondition(eaxRegister, TR::RealRegister::eax, cg());312cg()->stopUsingRegister(eaxRegister);313cg()->decReferenceCount(thisChild);314}315316return argSize;317318}319320321TR::UnresolvedDataSnippet *J9::X86::I386::PrivateLinkage::generateX86UnresolvedDataSnippetWithCPIndex(322TR::Node *child,323TR::SymbolReference *symRef,324int32_t cpIndex)325{326// We know the symbol must have already been resolved, so no GC can327// happen (unless the gcOnResolve option is being used).328//329TR::UnresolvedDataSnippet *snippet = TR::UnresolvedDataSnippet::create(cg(), child, symRef, false, (debug("gcOnResolve") != NULL));330cg()->addSnippet(snippet);331332TR::Instruction *dataReferenceInstruction = generateImmSnippetInstruction(TR::InstOpCode::PUSHImm4, child, cpIndex, snippet, cg());333snippet->setDataReferenceInstruction(dataReferenceInstruction);334generateBoundaryAvoidanceInstruction(TR::X86BoundaryAvoidanceInstruction::unresolvedAtomicRegions, 8, 8, dataReferenceInstruction, cg());335336return snippet;337}338339TR::Register *J9::X86::I386::PrivateLinkage::pushIntegerWordArg(TR::Node *child)340{341TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());342if (child->getRegister() == NULL)343{344if (child->getOpCode().isLoadConst())345{346int32_t value = child->getInt();347TR::InstOpCode::Mnemonic pushOp;348if (value >= -128 && value <= 127)349{350pushOp = TR::InstOpCode::PUSHImms;351}352else353{354pushOp = TR::InstOpCode::PUSHImm4;355}356357if (child->getOpCodeValue() == TR::aconst && child->isMethodPointerConstant() &&358cg()->needClassAndMethodPointerRelocations())359{360generateImmInstruction(pushOp, child, value, cg(), TR_MethodPointer);361}362else363{364generateImmInstruction(pushOp, child, value, cg());365}366cg()->decReferenceCount(child);367return NULL;368}369else if (child->getOpCodeValue() == TR::loadaddr)370{371// Special casing for instanceof under an if relies on this push of unresolved being372// implemented as a push imm, so don't change unless that code is changed to match.373//374TR::SymbolReference * symRef = child->getSymbolReference();375TR::StaticSymbol *sym = symRef->getSymbol()->getStaticSymbol();376if (sym)377{378if (symRef->isUnresolved())379{380generateX86UnresolvedDataSnippetWithCPIndex(child, symRef, 0);381}382else383{384// Must pass symbol reference so that aot can put out a relocation for it385//386TR::Instruction *instr = generateImmSymInstruction(TR::InstOpCode::PUSHImm4, child, (uintptr_t)sym->getStaticAddress(), symRef, cg());387388// HCR register the class passed as a parameter389//390if ((sym->isClassObject() || sym->isAddressOfClassObject())391&& cg()->wantToPatchClassPointer((TR_OpaqueClassBlock*)sym->getStaticAddress(), child))392{393comp()->getStaticHCRPICSites()->push_front(instr);394}395}396397cg()->decReferenceCount(child);398return NULL;399}400}401}402403return TR::IA32LinkageUtils::pushIntegerWordArg(child, cg());404}405406TR::Register *J9::X86::I386::PrivateLinkage::pushThis(TR::Node *child)407{408// Don't decrement the reference count on the "this" child until we've409// had a chance to set up its dependency conditions410//411TR::Register *tempRegister = cg()->evaluate(child);412generateRegInstruction(TR::InstOpCode::PUSHReg, child, tempRegister, cg());413return tempRegister;414}415416417static TR_AtomicRegion X86PicSlotAtomicRegion[] =418{419{ 0x0, 8 }, // Maximum instruction size that can be patched atomically.420{ 0,0 }421};422423static TR_AtomicRegion X86PicCallAtomicRegion[] =424{425{ 1, 4 }, // disp32 of a CALL instruction426{ 0,0 }427};428429430TR::Instruction *J9::X86::I386::PrivateLinkage::buildPICSlot(431TR::X86PICSlot picSlot,432TR::LabelSymbol *mismatchLabel,433TR::LabelSymbol *doneLabel,434TR::X86CallSite &site)435{436TR::Node *node = site.getCallNode();437TR::Register *vftReg = site.evaluateVFT();438uintptr_t addrToBeCompared = picSlot.getClassAddress();439TR::Instruction *firstInstruction;440if (picSlot.getMethodAddress())441{442addrToBeCompared = (uintptr_t) picSlot.getMethodAddress();443firstInstruction = generateMemImmInstruction(TR::InstOpCode::CMPMemImm4(false), node,444generateX86MemoryReference(vftReg, picSlot.getSlot(), cg()), (uint32_t) addrToBeCompared, cg());445}446else447firstInstruction = generateRegImmInstruction(TR::InstOpCode::CMP4RegImm4, node, vftReg, addrToBeCompared, cg());448449firstInstruction->setNeedsGCMap(site.getPreservedRegisterMask());450451if (!site.getFirstPICSlotInstruction())452site.setFirstPICSlotInstruction(firstInstruction);453454if (picSlot.needsPicSlotAlignment())455{456generateBoundaryAvoidanceInstruction(457X86PicSlotAtomicRegion,4588,4598,460firstInstruction,461cg());462}463464if (picSlot.needsJumpOnNotEqual())465{466if (picSlot.needsLongConditionalBranch())467{468generateLongLabelInstruction(TR::InstOpCode::JNE4, node, mismatchLabel, cg());469}470else471{472TR::InstOpCode::Mnemonic op = picSlot.needsShortConditionalBranch() ? TR::InstOpCode::JNE1 : TR::InstOpCode::JNE4;473generateLabelInstruction(op, node, mismatchLabel, cg());474}475}476else if (picSlot.needsJumpOnEqual())477{478if (picSlot.needsLongConditionalBranch())479{480generateLongLabelInstruction(TR::InstOpCode::JE4, node, mismatchLabel, cg());481}482else483{484TR::InstOpCode::Mnemonic op = picSlot.needsShortConditionalBranch() ? TR::InstOpCode::JE1 : TR::InstOpCode::JE4;485generateLabelInstruction(op, node, mismatchLabel, cg());486}487}488else if (picSlot.needsNopAndJump())489{490generatePaddingInstruction(1, node, cg())->setNeedsGCMap((site.getArgSize()<<14) | site.getPreservedRegisterMask());491generateLongLabelInstruction(TR::InstOpCode::JMP4, node, mismatchLabel, cg());492}493494TR::Instruction *instr;495if (picSlot.getMethod())496{497instr = generateImmInstruction(TR::InstOpCode::CALLImm4, node, (uint32_t)(uintptr_t)picSlot.getMethod()->startAddressForJittedMethod(), cg());498}499else if (picSlot.getHelperMethodSymbolRef())500{501TR::MethodSymbol *helperMethod = picSlot.getHelperMethodSymbolRef()->getSymbol()->castToMethodSymbol();502instr = generateImmSymInstruction(TR::InstOpCode::CALLImm4, node, (uint32_t)(uintptr_t)helperMethod->getMethodAddress(), picSlot.getHelperMethodSymbolRef(), cg());503}504else505{506instr = generateImmInstruction(TR::InstOpCode::CALLImm4, node, 0, cg());507}508509instr->setNeedsGCMap(site.getPreservedRegisterMask());510511if (picSlot.needsPicCallAlignment())512{513generateBoundaryAvoidanceInstruction(514X86PicCallAtomicRegion,5158,5168,517instr,518cg());519}520521// Put a GC map on this label, since the instruction after it may provide522// the return address in this stack frame while PicBuilder is active523//524// TODO: Can we get rid of some of these? Maybe they don't cost anything.525//526if (picSlot.needsJumpToDone())527{528instr = generateLabelInstruction(TR::InstOpCode::JMP4, node, doneLabel, cg());529instr->setNeedsGCMap(site.getPreservedRegisterMask());530}531532if (picSlot.generateNextSlotLabelInstruction())533{534generateLabelInstruction(TR::InstOpCode::label, node, mismatchLabel, cg());535}536537return firstInstruction;538}539540static TR_AtomicRegion ia32VPicAtomicRegions[] =541{542{ 0x02, 4 }, // Class test immediate 1543{ 0x09, 4 }, // Call displacement 1544{ 0x17, 2 }, // VPICInit call instruction patched via self-loop545{ 0,0 } // (null terminator)546};547548static TR_AtomicRegion ia32VPicAtomicRegionsRT[] =549{550{ 0x02, 4 }, // Class test immediate 1551{ 0x06, 2 }, // nop+jmp opcodes552{ 0x08, 4 }, // Jne displacement 1553{ 0x0d, 2 }, // first two bytes of call instruction are atomically patched by virtualJitToInterpreted554{ 0,0 } // (null terminator)555};556557static TR_AtomicRegion ia32IPicAtomicRegions[] =558{559{ 0x02, 4 }, // Class test immediate 1560{ 0x09, 4 }, // Call displacement 1561{ 0x11, 4 }, // Class test immediate 2562{ 0x18, 4 }, // Call displacement 2563{ 0x27, 4 }, // IPICInit call displacement564{ 0,0 } // (null terminator)565};566567static TR_AtomicRegion ia32IPicAtomicRegionsRT[] =568{569{ 0x02, 4 }, // Class test immediate 1570{ 0x09, 4 }, // Call displacement 1571{ 0x11, 4 }, // Class test immediate 2572{ 0x18, 4 }, // Call displacement 2573{ 0x2f, 4 }, // IPICInit call displacement574{ 0,0 } // (null terminator)575};576577void J9::X86::I386::PrivateLinkage::buildIPIC(578TR::X86CallSite &site,579TR::LabelSymbol *entryLabel,580TR::LabelSymbol *doneLabel,581uint8_t *thunk)582{583TR_ASSERT(doneLabel, "a doneLabel is required for IPIC dispatches");584585if (entryLabel)586generateLabelInstruction(TR::InstOpCode::label, site.getCallNode(), entryLabel, cg());587588TR::Instruction *startOfPicInstruction = cg()->getAppendInstruction();589590int32_t numIPicSlots = IPicParameters.defaultNumberOfSlots;591592TR::SymbolReference *callHelperSymRef =593cg()->symRefTab()->findOrCreateRuntimeHelper(TR_X86populateIPicSlotCall, true, true, false);594595static char *interfaceDispatchUsingLastITableStr = feGetEnv("TR_interfaceDispatchUsingLastITable");596static char *numIPicSlotsStr = feGetEnv("TR_numIPicSlots");597static char *numIPicSlotsBeforeLastITable = feGetEnv("TR_numIPicSlotsBeforeLastITable");598static char *breakBeforeIPICUsingLastITable = feGetEnv("TR_breakBeforeIPICUsingLastITable");599600if (numIPicSlotsStr)601numIPicSlots = atoi(numIPicSlotsStr);602603bool useLastITableCache = site.useLastITableCache() || interfaceDispatchUsingLastITableStr;604605if (useLastITableCache)606{607if (breakBeforeIPICUsingLastITable)608generateInstruction(TR::InstOpCode::INT3, site.getCallNode(), cg());609if (numIPicSlotsBeforeLastITable)610numIPicSlots = atoi(numIPicSlotsBeforeLastITable);611}612613if (numIPicSlots > 1)614{615TR::X86PICSlot emptyPicSlot = TR::X86PICSlot(-1, NULL);616emptyPicSlot.setNeedsShortConditionalBranch();617emptyPicSlot.setJumpOnNotEqual();618emptyPicSlot.setNeedsPicSlotAlignment();619emptyPicSlot.setNeedsPicCallAlignment();620emptyPicSlot.setHelperMethodSymbolRef(callHelperSymRef);621emptyPicSlot.setGenerateNextSlotLabelInstruction();622623// Generate all slots except the last624// (short branch to next slot, jump to doneLabel)625//626for (int32_t i = 1; i < numIPicSlots; i++)627{628TR::LabelSymbol *nextSlotLabel = generateLabelSymbol(cg());629buildPICSlot(emptyPicSlot, nextSlotLabel, doneLabel, site);630}631}632633// Generate the last slot634// (long branch to lookup snippet, fall through to doneLabel)635//636TR::X86PICSlot lastPicSlot = TR::X86PICSlot(-1, NULL, false);637lastPicSlot.setJumpOnNotEqual();638lastPicSlot.setNeedsPicSlotAlignment();639lastPicSlot.setHelperMethodSymbolRef(callHelperSymRef);640641TR::LabelSymbol *lookupDispatchSnippetLabel = generateLabelSymbol(cg());642643TR::Instruction *slotPatchInstruction = NULL;644645TR::Method *method = site.getMethodSymbol()->getMethod();646TR_OpaqueClassBlock *declaringClass = NULL;647uintptr_t itableIndex;648if ( useLastITableCache649&& (declaringClass = site.getSymbolReference()->getOwningMethod(comp())->getResolvedInterfaceMethod(site.getSymbolReference()->getCPIndex(), &itableIndex))650&& performTransformation(comp(), "O^O useLastITableCache for n%dn itableIndex=%d: %.*s.%.*s%.*s\n",651site.getCallNode()->getGlobalIndex(), (int)itableIndex,652method->classNameLength(), method->classNameChars(),653method->nameLength(), method->nameChars(),654method->signatureLength(), method->signatureChars()))655{656buildInterfaceDispatchUsingLastITable (site, numIPicSlots, lastPicSlot, slotPatchInstruction, doneLabel, lookupDispatchSnippetLabel, declaringClass, itableIndex);657}658else659{660// Last PIC slot is long branch to lookup snippet, fall through to doneLabel661lastPicSlot.setNeedsPicCallAlignment();662lastPicSlot.setNeedsLongConditionalBranch();663slotPatchInstruction = buildPICSlot(lastPicSlot, lookupDispatchSnippetLabel, NULL, site);664}665666// Skip past any boundary avoidance padding to get to the real first instruction667// of the PIC.668//669startOfPicInstruction = startOfPicInstruction->getNext();670while (startOfPicInstruction->getOpCodeValue() == TR::InstOpCode::bad)671{672startOfPicInstruction = startOfPicInstruction->getNext();673}674675TR::X86PicDataSnippet *snippet = new (trHeapMemory()) TR::X86PicDataSnippet(676IPicParameters.defaultNumberOfSlots,677startOfPicInstruction,678lookupDispatchSnippetLabel,679doneLabel,680site.getSymbolReference(),681slotPatchInstruction,682site.getThunkAddress(),683true,684cg());685686snippet->gcMap().setGCRegisterMask((site.getArgSize()<<14) | site.getPreservedRegisterMask());687cg()->addSnippet(snippet);688}689690void J9::X86::I386::PrivateLinkage::buildVirtualOrComputedCall(691TR::X86CallSite &site,692TR::LabelSymbol *entryLabel,693TR::LabelSymbol *doneLabel,694uint8_t *thunk)695{696TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());697bool resolvedSite = !site.getSymbolReference()->isUnresolved()698&& fej9->isResolvedVirtualDispatchGuaranteed(comp());699700if (site.getSymbolReference()->getSymbol()->castToMethodSymbol()->isComputed())701{702// TODO:JSR292: Try to avoid the explicit VFT load703TR::Register *targetAddress = site.evaluateVFT();704if (targetAddress->getRegisterPair())705targetAddress = targetAddress->getRegisterPair()->getLowOrder();706buildVFTCall(site, TR::InstOpCode::CALLReg, targetAddress, NULL);707}708else if (resolvedSite && site.resolvedVirtualShouldUseVFTCall())709{710// There are no J2I thunks on x86-32, so no J2I thunk validation is needed711712if (entryLabel)713generateLabelInstruction(TR::InstOpCode::label, site.getCallNode(), entryLabel, cg());714715intptr_t offset=site.getSymbolReference()->getOffset();716if (!resolvedSite)717offset = 0;718719buildVFTCall(site, TR::InstOpCode::CALLMem, NULL, generateX86MemoryReference(site.evaluateVFT(), offset, cg()));720}721else722{723J9::X86::PrivateLinkage::buildVPIC(site, entryLabel, doneLabel);724}725}726727intptr_t728J9::X86::I386::PrivateLinkage::entryPointFromCompiledMethod()729{730return reinterpret_cast<intptr_t>(cg()->getCodeStart());731}732733734