Path: blob/master/runtime/compiler/x/codegen/X86Recompilation.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 "x/codegen/X86Recompilation.hpp"2324#include "codegen/CodeGenerator.hpp"25#include "codegen/Machine.hpp"26#include "codegen/Linkage.hpp"27#include "codegen/Linkage_inlines.hpp"28#include "codegen/PrivateLinkage.hpp"29#include "codegen/Snippet.hpp"30#include "codegen/PreprologueConst.hpp"31#include "compile/ResolvedMethod.hpp"32#include "env/CompilerEnv.hpp"33#include "env/jittypes.h"34#include "env/j9method.h"35#include "env/VMJ9.h"36#include "il/Node.hpp"37#include "il/Node_inlines.hpp"38#include "il/TreeTop.hpp"39#include "il/TreeTop_inlines.hpp"40#include "x/codegen/RecompilationSnippet.hpp"41#include "x/codegen/X86Instruction.hpp"4243// ***************************************************************************44//45// Implementation of TR_X86Recompilation46//47// ***************************************************************************4849// Allocate a machine-specific recompilation processor for this compilation50//51TR::Recompilation *TR_X86Recompilation::allocate(TR::Compilation *comp)52{53if (comp->isRecompilationEnabled())54{55return new (comp->trHeapMemory()) TR_X86Recompilation(comp);56}5758return NULL;59}6061TR_X86Recompilation::TR_X86Recompilation(TR::Compilation * comp)62: TR::Recompilation(comp)63{64_countingSupported = true;6566setupMethodInfo();67}6869TR_PersistentMethodInfo *TR_X86Recompilation::getExistingMethodInfo(TR_ResolvedMethod *method)70{71// The method was previously compiled. Find its method info block from the72// start PC address. The mechanism is different depending on whether the73// method was compiled for sampling or counting.74//75TR_PersistentJittedBodyInfo *bodyInfo = ((TR_ResolvedJ9Method*) method)->getExistingJittedBodyInfo();76return bodyInfo ? bodyInfo->getMethodInfo() : NULL;77}7879TR::Instruction *TR_X86Recompilation::generatePrePrologue()80{81TR_J9VMBase *fej9 = (TR_J9VMBase *)(_compilation->fe());8283if (!couldBeCompiledAgain())84return NULL;8586TR::Node * startNode = _compilation->getStartTree()->getNode();87TR::Instruction *prev = 0;8889uint8_t alignmentMargin = useSampling()? SAMPLING_CALL_SIZE /* allow for the helper call */ : 0;90if (cg()->comp()->target().is64Bit())91alignmentMargin += SAVE_AREA_SIZE +JITTED_BODY_INFO_SIZE + LINKAGE_INFO_SIZE; // save area for the first two bytes of the method + jitted body info pointer + linkageinfo92else93alignmentMargin += JITTED_BODY_INFO_SIZE + LINKAGE_INFO_SIZE; // jitted body info pointer + linkageinfo9495TR::LabelSymbol *startLabel = NULL;9697// Make sure the startPC at least 4-byte aligned. This is important, since the VM98// depends on the alignment (it uses the low order bits as tag bits).99//100int32_t alignmentBoundary = 8;101if (cg()->mustGenerateSwitchToInterpreterPrePrologue())102{103// The SwitchToInterpreterPrePrologue will do the alignment for us.104//105prev = cg()->generateSwitchToInterpreterPrePrologue(prev, alignmentBoundary, alignmentMargin);106}107else108{109prev = generateAlignmentInstruction(prev, alignmentBoundary, alignmentMargin, cg());110}111112if (cg()->comp()->target().is64Bit())113{114// A copy of the first two bytes of the method, in case we need to un-patch them115//116prev = new (trHeapMemory()) TR::X86ImmInstruction(prev, TR::InstOpCode::DWImm2, 0xcccc, cg());117}118119if (useSampling())120{121// Note: the displacement of this call gets patched, but thanks to the122// alignment constraint on the startPC, it is automatically aligned to a123// 4-byte boundary, which is more than enough to ensure it can be patched124// atomically.125//126prev = generateHelperCallInstruction(prev, SAMPLING_RECOMPILE_METHOD, cg());127}128129// The address of the persistent method info is inserted in the pre-prologue130// information. If the method is not to be compiled again a null value is131// inserted.132//133if (cg()->comp()->target().is64Bit())134{135// TODO:AMD64: This ought to be a relative address, but that requires136// binary-encoding-time support. If you change this, be sure to adjust137// the alignmentMargin above.138//139prev = new (trHeapMemory()) TR::AMD64Imm64Instruction(prev, TR::InstOpCode::DQImm64, (uintptr_t)getJittedBodyInfo(), cg());140prev->setNeedsAOTRelocation();141}142else143{144prev = new (trHeapMemory()) TR::X86ImmInstruction(prev, TR::InstOpCode::DDImm4, (uint32_t)(uintptr_t)getJittedBodyInfo(), cg());145prev->setNeedsAOTRelocation();146}147148149// Allow 4 bytes for private linkage return type info. Allocate the 4 bytes150// even if the linkage is not private, so that all the offsets are151// predictable.152//153return generateImmInstruction(TR::InstOpCode::DDImm4, startNode, 0, cg());154}155156TR::Instruction *TR_X86Recompilation::generatePrologue(TR::Instruction *cursor)157{158TR::Machine *machine = cg()->machine();159TR::Linkage *linkage = cg()->getLinkage();160if (couldBeCompiledAgain())161{162if (!useSampling())163{164// We're generating the first instruction ourselves.165//166TR::MemoryReference *mRef;167168if (cg()->comp()->target().is64Bit())169{170TR_ASSERT(linkage->getMinimumFirstInstructionSize() <= 10, "Can't satisfy first instruction size constraint");171TR::RealRegister *scratchReg = machine->getRealRegister(TR::RealRegister::edi);172cursor = new (trHeapMemory()) TR::AMD64RegImm64Instruction(cursor, TR::InstOpCode::MOV8RegImm64, scratchReg, (uintptr_t)getCounterAddress(), cg());173mRef = generateX86MemoryReference(scratchReg, 0, cg());174}175else176{177TR_ASSERT(linkage->getMinimumFirstInstructionSize() <= 5, "Can't satisfy first instruction size constraint");178mRef = generateX86MemoryReference((intptr_t)getCounterAddress(), cg());179}180181if (!isProfilingCompilation())182cursor = new (trHeapMemory()) TR::X86MemImmInstruction(cursor, TR::InstOpCode::SUB4MemImms, mRef, 1, cg());183else184{185// This only applies to JitProfiling, as JProfiling uses sampling186TR_ASSERT(_compilation->getProfilingMode() == JitProfiling, "JProfiling should not use counting mechanism to trigger recompilation");187cursor = new (trHeapMemory()) TR::X86MemImmInstruction(cursor, TR::InstOpCode::CMP4MemImms, mRef, 0, cg());188}189190TR::Instruction *counterInstruction = cursor;191TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg());192193cursor = new (trHeapMemory()) TR::X86LabelInstruction(cursor, TR::InstOpCode::JL4, snippetLabel, cg());194((TR::X86LabelInstruction*)cursor)->prohibitShortening();195TR::Snippet *snippet =196new (trHeapMemory()) TR::X86RecompilationSnippet(snippetLabel, counterInstruction->getNode(), cg());197cg()->addSnippet(snippet);198}199}200201return cursor;202}203204void TR_X86Recompilation::postCompilation()205{206setMethodReturnInfoBits();207}208209void TR_X86Recompilation::setMethodReturnInfoBits()210{211212if (!couldBeCompiledAgain())213return;214215// Sets up bits inside the linkage info field of the method. Linkage info216// is the dword immediately before the startPC217//218// The bits contain information about a) what kind of method header this219// is (counting/sampling), and, b) what kind of220// instruction was used as the first instruction.221//222// a) header type: the bits are used by getMethodInfoFromPC (above).223// the presence of bits guaranteed that the ptr to the PersistentMethodInfo224// would be located at the particular offset from startPC.225//226// b) In case a future compilation fails, we may need to restore the original first227// instruction of the method (this is done by OMR::Recompilation::methodCannotBeRecompiled)228//229uint8_t *startPC = _compilation->cg()->getCodeStart();230J9::PrivateLinkage::LinkageInfo *linkageInfo = J9::PrivateLinkage::LinkageInfo::get(startPC);231232if (useSampling())233{234linkageInfo->setSamplingMethodBody();235saveFirstTwoBytes(startPC, START_PC_TO_ORIGINAL_ENTRY_BYTES);236237// TODO: It would be best if we didn't have to update the instruction object here, ideal238// solution would be have these bits set as lazily as possible and remove them from consideration239// prior to runtime, but race conditions for the update need to be considered.240//241if (comp()->getDebug())242{243cg()->getReturnTypeInfoInstruction()->setSourceImmediate(*(uint32_t*)linkageInfo);244}245}246else247{248linkageInfo->setCountingMethodBody();249}250}251252253254