Path: blob/master/runtime/compiler/x/codegen/X86HelperLinkage.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2000, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "codegen/X86HelperLinkage.hpp"2324#include "codegen/Linkage_inlines.hpp"25#include "codegen/Machine.hpp"26#include "codegen/Register.hpp"27#include "codegen/RegisterDependency.hpp"28#include "codegen/RegisterPair.hpp"29#include "env/jittypes.h"30#include "env/VMJ9.h"31#include "il/DataTypes.hpp"32#include "il/Node.hpp"33#include "il/Node_inlines.hpp"34#include "il/TreeTop.hpp"35#include "il/TreeTop_inlines.hpp"36#include "env/VMJ9.h"37#include "x/codegen/X86Instruction.hpp"3839// An utility to manage real registers and their corresponding virtual registers40class RealRegisterManager41{42public:43RealRegisterManager(TR::CodeGenerator* cg) :44_cg(cg),45_NumberOfRegistersInUse(0)46{47memset(_Registers, 0x0, sizeof(_Registers));48}49~RealRegisterManager()50{51// RAII: stop using all registers52for (uint8_t i = (uint8_t)TR::RealRegister::NoReg; i < (uint8_t)TR::RealRegister::NumRegisters; i++)53{54if (_Registers[i] != NULL)55{56_cg->stopUsingRegister(_Registers[i]);57}58}59}60// Find or allocate a virtual register which is bind to the given real register61TR::Register* Use(TR::RealRegister::RegNum RealRegister)62{63if (_Registers[RealRegister] == NULL)64{65bool isGPR = RealRegister >= TR::RealRegister::FirstGPR && RealRegister <= TR::RealRegister::LastGPR;66_Registers[RealRegister] = _cg->allocateRegister(isGPR ? TR_GPR : TR_FPR);67_NumberOfRegistersInUse++;68}69return _Registers[RealRegister];70}71// Build the dependencies for each virtual-real register pair72TR::RegisterDependencyConditions* BuildRegisterDependencyConditions()73{74TR::RegisterDependencyConditions* deps = generateRegisterDependencyConditions(NumberOfRegistersInUse() + 1, // For VMThread75NumberOfRegistersInUse() + 1, // For VMThread76_cg);77for (uint8_t i = (uint8_t)TR::RealRegister::NoReg; i < (uint8_t)TR::RealRegister::NumRegisters; i++)78{79if (_Registers[i] != NULL)80{81deps->addPreCondition(_Registers[i], (TR::RealRegister::RegNum)i, _cg);82deps->addPostCondition(_Registers[i], (TR::RealRegister::RegNum)i, _cg);83}84}85TR::Register* vmThread = _cg->getVMThreadRegister();86deps->addPreCondition(vmThread, (TR::RealRegister::RegNum)vmThread->getAssociation(), _cg);87deps->addPostCondition(vmThread, (TR::RealRegister::RegNum)vmThread->getAssociation(), _cg);88return deps;89}90inline uint8_t NumberOfRegistersInUse() const91{92return _NumberOfRegistersInUse;93}9495private:96uint8_t _NumberOfRegistersInUse;97TR::Register* _Registers[TR::RealRegister::NumRegisters];98TR::CodeGenerator* _cg;99};100101// On X86-32, fastcall is in-use for both Linux and Windows102// On X86-64 Windows, Microsoft x64 calling convention is an extension of fastcall; and hence this code goes through USE_FASTCALL path103// On X86-64 Linux, the linkage is System V AMD64 ABI.104#if defined(WINDOWS) || defined(TR_TARGET_32BIT)105#define USE_FASTCALL106#endif107108const TR::RealRegister::RegNum J9::X86::HelperCallSite::IntParamRegisters[] =109{110#ifdef USE_FASTCALL111TR::RealRegister::ecx,112TR::RealRegister::edx,113#ifdef TR_TARGET_64BIT114TR::RealRegister::r8,115TR::RealRegister::r9,116#endif117#else118TR::RealRegister::edi,119TR::RealRegister::esi,120TR::RealRegister::edx,121TR::RealRegister::ecx,122TR::RealRegister::r8,123TR::RealRegister::r9,124#endif125};126127const TR::RealRegister::RegNum J9::X86::HelperCallSite::CallerSavedRegisters[] =128{129TR::RealRegister::eax,130TR::RealRegister::ecx,131TR::RealRegister::edx,132#ifndef USE_FASTCALL133TR::RealRegister::edi,134TR::RealRegister::esi,135#endif136#ifdef TR_TARGET_64BIT137TR::RealRegister::r8,138TR::RealRegister::r9,139TR::RealRegister::r10,140TR::RealRegister::r11,141#endif142143TR::RealRegister::xmm0,144TR::RealRegister::xmm1,145TR::RealRegister::xmm2,146TR::RealRegister::xmm3,147TR::RealRegister::xmm4,148TR::RealRegister::xmm5,149TR::RealRegister::xmm6,150TR::RealRegister::xmm7,151#ifdef TR_TARGET_64BIT152TR::RealRegister::xmm8,153TR::RealRegister::xmm9,154TR::RealRegister::xmm10,155TR::RealRegister::xmm11,156TR::RealRegister::xmm12,157TR::RealRegister::xmm13,158TR::RealRegister::xmm14,159TR::RealRegister::xmm15,160#endif161};162163const TR::RealRegister::RegNum J9::X86::HelperCallSite::CalleeSavedRegisters[] =164{165TR::RealRegister::ebx,166#ifdef USE_FASTCALL167TR::RealRegister::edi,168TR::RealRegister::esi,169#endif170TR::RealRegister::ebp,171TR::RealRegister::esp,172#ifdef TR_TARGET_64BIT173TR::RealRegister::r12,174TR::RealRegister::r13,175TR::RealRegister::r14,176TR::RealRegister::r15,177#endif178};179180#undef USE_FASTCALL181182// X86-32 requires callee to cleanup stack, X86-64 requires caller to cleanup stack183// Stack slot size is 4 bytes on X86-32 and 8 bytes on X86-64184#ifdef TR_TARGET_32BIT185const bool J9::X86::HelperCallSite::CalleeCleanup = true;186const size_t J9::X86::HelperCallSite::StackSlotSize = 4;187#else188const bool J9::X86::HelperCallSite::CalleeCleanup = false;189const size_t J9::X86::HelperCallSite::StackSlotSize = 8;190#endif191// Windows X86-64 requires caller reserves shadow space for parameters passed via registers192#if defined(WINDOWS) && defined(TR_TARGET_64BIT)193const bool J9::X86::HelperCallSite::RegisterParameterShadowOnStack = true;194#else195const bool J9::X86::HelperCallSite::RegisterParameterShadowOnStack = false;196#endif197const size_t J9::X86::HelperCallSite::NumberOfIntParamRegisters = sizeof(IntParamRegisters) / sizeof(IntParamRegisters[0]);198const size_t J9::X86::HelperCallSite::StackIndexAdjustment = RegisterParameterShadowOnStack ? 0 : NumberOfIntParamRegisters;199200// Code below should not need the #define201202// Calculate preserved register map.203// The map is a constant that the C++ compiler *should* be able to determine at compile time204static uint32_t X86HelperCallSiteCalculatePreservedRegisterMapForGC()205{206uint32_t ret = 0;207for (size_t i = 0;208i < sizeof(J9::X86::HelperCallSite::CalleeSavedRegisters) / sizeof(J9::X86::HelperCallSite::CalleeSavedRegisters[0]);209i++)210{211ret |= TR::RealRegister::gprMask(J9::X86::HelperCallSite::CalleeSavedRegisters[i]);212}213return ret;214}215const uint32_t J9::X86::HelperCallSite::PreservedRegisterMapForGC = X86HelperCallSiteCalculatePreservedRegisterMapForGC();216217TR::Register* J9::X86::HelperCallSite::BuildCall()218{219TR_ASSERT(CalleeCleanup || cg()->getLinkage()->getProperties().getReservesOutgoingArgsInPrologue(),220"Caller must reserve outgoing args in prologue unless callee cleans up stack");221222if (cg()->comp()->getOption(TR_TraceCG))223{224traceMsg(cg()->comp(), "X86 HelperCall: [%04d] %s\n", _SymRef->getReferenceNumber(), cg()->getDebug()->getName(_SymRef));225}226RealRegisterManager RealRegisters(cg());227TR::RealRegister* ESP = cg()->machine()->getRealRegister(TR::RealRegister::esp);228229// Preserve caller saved registers230for (size_t i = 0;231i < sizeof(CallerSavedRegisters) / sizeof(CallerSavedRegisters[0]);232i++)233{234RealRegisters.Use(CallerSavedRegisters[i]);235}236// Find the return register, EAX/RAX237TR::Register* EAX = RealRegisters.Use(TR::RealRegister::eax);238239// Build parameters, parameters in _Params are Right-to-Left (RTL)240int NumberOfParamOnStack = 0;241for (size_t i = 0; i < _Params.size(); i++)242{243size_t index = _Params.size() - i - 1;244if (index < NumberOfIntParamRegisters)245{246generateRegRegInstruction(TR::InstOpCode::MOVRegReg(),247_Node,248RealRegisters.Use(IntParamRegisters[index]),249_Params[i],250cg());251}252else253{254NumberOfParamOnStack++;255if (CalleeCleanup)256{257generateRegInstruction(TR::InstOpCode::PUSHReg, _Node, _Params[i], cg());258}259else260{261size_t offset = StackSlotSize * (index - StackIndexAdjustment);262generateMemRegInstruction(TR::InstOpCode::SMemReg(),263_Node,264generateX86MemoryReference(ESP, offset, cg()),265_Params[i],266cg());267}268}269}270271// Call helper272TR::X86ImmInstruction* instr = generateImmSymInstruction(TR::InstOpCode::CALLImm4,273_Node,274(uintptr_t)_SymRef->getMethodAddress(),275_SymRef,276RealRegisters.BuildRegisterDependencyConditions(),277cg());278instr->setNeedsGCMap(PreservedRegisterMapForGC);279280// Stack adjustment281{282int SizeOfParamOnStack = StackSlotSize * (NumberOfParamOnStack + NumberOfIntParamRegisters - StackIndexAdjustment);283if (CalleeCleanup)284{285instr->setAdjustsFramePointerBy(-SizeOfParamOnStack);286}287else288{289if (SizeOfParamOnStack > cg()->getLargestOutgoingArgSize())290{291cg()->setLargestOutgoingArgSize(SizeOfParamOnStack);292}293}294}295296// Return value297TR::Register* ret = NULL;298switch (_ReturnType)299{300case TR::NoType:301break;302case TR::Address:303ret = cg()->allocateCollectedReferenceRegister();304break;305case TR::Int8:306case TR::Int16:307case TR::Int32:308#ifdef TR_TARGET_64BIT309case TR::Int64:310#endif311ret = cg()->allocateRegister();312break;313default:314TR_ASSERT(false, "Unsupported call return data type: #%d", (int)_ReturnType);315break;316}317if (ret)318{319generateRegRegInstruction(TR::InstOpCode::MOVRegReg(), _Node, ret, EAX, cg());320}321322if (cg()->canEmitBreakOnDFSet())323generateBreakOnDFSet(cg());324325return ret;326}327328329