Path: blob/master/runtime/compiler/x/i386/codegen/IA32J9SystemLinkage.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2000, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#if defined(TR_TARGET_32BIT)2324#include "codegen/IA32J9SystemLinkage.hpp"25#include "codegen/Linkage_inlines.hpp"26#include "codegen/RegisterDependency.hpp"27#include "codegen/X86Instruction.hpp"28#include "x/codegen/IA32LinkageUtils.hpp"29#include "codegen/LiveRegister.hpp"30#include "x/codegen/J9LinkageUtils.hpp"31#include "codegen/CodeGenerator.hpp"32#include "il/Node.hpp"33#include "il/Node_inlines.hpp"3435TR::IA32J9SystemLinkage::IA32J9SystemLinkage(TR::CodeGenerator *cg) : TR::IA32SystemLinkage(cg)36{37_properties._framePointerRegister = TR::RealRegister::ebx;38_properties._methodMetaDataRegister = TR::RealRegister::ebp;39}404142TR::Register*43TR::IA32J9SystemLinkage::buildVolatileAndReturnDependencies(TR::Node *callNode, TR::RegisterDependencyConditions *deps)44{45TR::Register* returnReg = TR::IA32SystemLinkage::buildVolatileAndReturnDependencies(callNode, deps);4647deps->addPostCondition(cg()->getMethodMetaDataRegister(), TR::RealRegister::ebp, cg());4849uint8_t numXmmRegs = 0;50TR_LiveRegisters *lr = cg()->getLiveRegisters(TR_FPR);51if (!lr || lr->getNumberOfLiveRegisters() > 0)52numXmmRegs = (uint8_t)(TR::RealRegister::LastXMMR - TR::RealRegister::FirstXMMR+1);5354if (numXmmRegs > 0)55{56for (int regIndex = TR::RealRegister::FirstXMMR; regIndex <= TR::RealRegister::LastXMMR; regIndex++)57{58TR::Register *dummy = cg()->allocateRegister(TR_FPR);59dummy->setPlaceholderReg();60deps->addPostCondition(dummy, (TR::RealRegister::RegNum)regIndex, cg());61cg()->stopUsingRegister(dummy);62}63}6465deps->stopAddingConditions();66return returnReg;67}68697071TR::Register*72TR::IA32J9SystemLinkage::buildDirectDispatch(TR::Node *callNode, bool spillFPRegs)73{74#ifdef DEBUG75if (debug("reportSysDispatch"))76{77printf("System Linkage Dispatch: %s calling %s\n", comp()->signature(), comp()->getDebug()->getName(callNode->getSymbolReference()));78}79#endif8081TR::RealRegister *espReal = machine()->getRealRegister(TR::RealRegister::esp);82TR::SymbolReference *methodSymRef = callNode->getSymbolReference();83TR::MethodSymbol *methodSymbol = callNode->getSymbol()->castToMethodSymbol();84uint8_t numXmmRegs = 0;8586if (!methodSymbol->isHelper())87diagnostic("Building call site for %s\n", methodSymbol->getMethod()->signature(trMemory()));8889int32_t argSize = buildParametersOnCStack(callNode, 0);9091TR::LabelSymbol* begLabel = generateLabelSymbol(cg());92TR::LabelSymbol* endLabel = generateLabelSymbol(cg());93begLabel->setStartInternalControlFlow();94endLabel->setEndInternalControlFlow();9596generateLabelInstruction(TR::InstOpCode::label, callNode, begLabel, cg());9798// Save VFP99TR::X86VFPSaveInstruction* vfpSave = generateVFPSaveInstruction(callNode, cg());100101TR::J9LinkageUtils::switchToMachineCStack(callNode, cg());102103// check to see if we need to set XMM register dependencies104TR_LiveRegisters *lr = cg()->getLiveRegisters(TR_FPR);105if (!lr || lr->getNumberOfLiveRegisters() > 0)106numXmmRegs = (uint8_t)(TR::RealRegister::LastXMMR - TR::RealRegister::FirstXMMR+1);107108TR::RegisterDependencyConditions *deps;109deps = generateRegisterDependencyConditions((uint8_t)0, (uint8_t)6 + numXmmRegs, cg());110TR::Register *returnReg = buildVolatileAndReturnDependencies(callNode, deps);111112TR::RegisterDependencyConditions *dummy = generateRegisterDependencyConditions((uint8_t)0, (uint8_t)0, cg());113114// Call-out115generateRegImmInstruction(argSize >= -128 && argSize <= 127 ? TR::InstOpCode::SUB4RegImms : TR::InstOpCode::SUB4RegImm4, callNode, espReal, argSize, cg());116generateImmSymInstruction(TR::InstOpCode::CALLImm4, callNode, (uintptr_t)methodSymbol->getMethodAddress(), methodSymRef, cg());117118if (returnReg && !(methodSymbol->isHelper()))119TR::J9LinkageUtils::cleanupReturnValue(callNode, returnReg, returnReg, cg());120121TR::J9LinkageUtils::switchToJavaStack(callNode, cg());122123// Restore VFP124generateVFPRestoreInstruction(vfpSave, callNode, cg());125generateLabelInstruction(TR::InstOpCode::label, callNode, endLabel, deps, cg());126127// Stop using the killed registers that are not going to persist128//129if (deps)130stopUsingKilledRegisters(deps, returnReg);131132if (callNode->getOpCode().isFloat())133{134TR::MemoryReference *tempMR = machine()->getDummyLocalMR(TR::Float);135generateFPMemRegInstruction(TR::InstOpCode::FSTPMemReg, callNode, tempMR, returnReg, cg());136cg()->stopUsingRegister(returnReg); // zhxingl: this is added by me137returnReg = cg()->allocateSinglePrecisionRegister(TR_FPR);138generateRegMemInstruction(TR::InstOpCode::MOVSSRegMem, callNode, returnReg, generateX86MemoryReference(*tempMR, 0, cg()), cg());139}140else if (callNode->getOpCode().isDouble())141{142TR::MemoryReference *tempMR = machine()->getDummyLocalMR(TR::Double);143generateFPMemRegInstruction(TR::InstOpCode::DSTPMemReg, callNode, tempMR, returnReg, cg());144cg()->stopUsingRegister(returnReg); // zhxingl: this is added by me145returnReg = cg()->allocateRegister(TR_FPR);146generateRegMemInstruction(cg()->getXMMDoubleLoadOpCode(), callNode, returnReg, generateX86MemoryReference(*tempMR, 0, cg()), cg());147}148149if (cg()->enableRegisterAssociations())150associatePreservedRegisters(deps, returnReg);151152return returnReg;153}154155int32_t TR::IA32J9SystemLinkage::buildParametersOnCStack(TR::Node *callNode, int firstParamIndex, bool passVMThread, bool wrapAddress)156{157TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());158TR_Stack<TR::MemoryReference*> paramsSlotsOnStack(trMemory(), callNode->getNumChildren()*2, false, stackAlloc);159// Evaluate children that are not part of parameters160for (size_t i = 0; i < firstParamIndex; i++)161{162auto child = callNode->getChild(i);163cg()->evaluate(child);164cg()->decReferenceCount(child);165}166// Load C Stack Pointer167auto cSP = cg()->allocateRegister();168generateRegMemInstruction(TR::InstOpCode::L4RegMem, callNode, cSP, generateX86MemoryReference(cg()->getVMThreadRegister(), fej9->thisThreadGetMachineSPOffset(), cg()), cg());169// Pass in the env to the jni method as the lexically first arg.170if (passVMThread)171{172auto slot = generateX86MemoryReference(cSP, 0, cg());173generateMemRegInstruction(TR::InstOpCode::S4MemReg, callNode, slot, cg()->getVMThreadRegister(), cg());174paramsSlotsOnStack.push(slot);175}176// Evaluate params177for (size_t i = firstParamIndex; i < callNode->getNumChildren(); i++)178{179auto child = callNode->getChild(i);180auto param = cg()->evaluate(child);181auto slot = generateX86MemoryReference(cSP, 0, cg());182paramsSlotsOnStack.push(slot);183switch (child->getDataType())184{185case TR::Int8:186case TR::Int16:187case TR::Int32:188generateMemRegInstruction(TR::InstOpCode::S4MemReg, callNode, slot, param, cg());189break;190case TR::Address:191if (wrapAddress && child->getOpCodeValue() == TR::loadaddr)192{193TR::StaticSymbol* sym = child->getSymbolReference()->getSymbol()->getStaticSymbol();194if (sym && sym->isAddressOfClassObject())195{196generateMemRegInstruction(TR::InstOpCode::S4MemReg, callNode, slot, param, cg());197}198else // must be loadaddr of parm or local199{200TR::Register *tmp = cg()->allocateRegister();201generateRegRegInstruction(TR::InstOpCode::XOR4RegReg, child, tmp, tmp, cg());202generateMemImmInstruction(TR::InstOpCode::CMP4MemImms, child, generateX86MemoryReference(child->getRegister(), 0, cg()), 0, cg());203generateRegRegInstruction(TR::InstOpCode::CMOVNE4RegReg, child, tmp, child->getRegister(), cg());204generateMemRegInstruction(TR::InstOpCode::S4MemReg, callNode, slot, tmp, cg());205cg()->stopUsingRegister(tmp);206}207}208else209{210generateMemRegInstruction(TR::InstOpCode::S4MemReg, callNode, slot, param, cg());211}212break;213case TR::Int64:214generateMemRegInstruction(TR::InstOpCode::S4MemReg, callNode, slot, param->getLowOrder(), cg());215{216auto highslot = generateX86MemoryReference(cSP, 0, cg());217paramsSlotsOnStack.push(highslot);218generateMemRegInstruction(TR::InstOpCode::S4MemReg, callNode, highslot, param->getHighOrder(), cg());219}220break;221case TR::Float:222generateMemRegInstruction(TR::InstOpCode::MOVSSMemReg, callNode, slot, param, cg());223break;224case TR::Double:225paramsSlotsOnStack.push(NULL);226generateMemRegInstruction(TR::InstOpCode::MOVSDMemReg, callNode, slot, param, cg());227break;228}229cg()->decReferenceCount(child);230}231cg()->stopUsingRegister(cSP);232int32_t argSize = paramsSlotsOnStack.size() * 4;233int32_t adjustedArgSize = 0;234if (argSize % 16 != 0)235{236adjustedArgSize = 16 - (argSize % 16);237argSize = argSize + adjustedArgSize;238if (comp()->getOption(TR_TraceCG))239traceMsg(comp(), "adjust arguments size by %d to make arguments 16 byte aligned \n", adjustedArgSize);240}241for(int offset = adjustedArgSize; !paramsSlotsOnStack.isEmpty(); offset += TR::Compiler->om.sizeofReferenceAddress())242{243auto param = paramsSlotsOnStack.pop();244if (param)245{246param->getSymbolReference().setOffset(-offset-4);247}248}249return argSize;250}251252#endif253254255