Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/x/codegen/X86Recompilation.cpp
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* 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-exception
21
*******************************************************************************/
22
23
#include "x/codegen/X86Recompilation.hpp"
24
25
#include "codegen/CodeGenerator.hpp"
26
#include "codegen/Machine.hpp"
27
#include "codegen/Linkage.hpp"
28
#include "codegen/Linkage_inlines.hpp"
29
#include "codegen/PrivateLinkage.hpp"
30
#include "codegen/Snippet.hpp"
31
#include "codegen/PreprologueConst.hpp"
32
#include "compile/ResolvedMethod.hpp"
33
#include "env/CompilerEnv.hpp"
34
#include "env/jittypes.h"
35
#include "env/j9method.h"
36
#include "env/VMJ9.h"
37
#include "il/Node.hpp"
38
#include "il/Node_inlines.hpp"
39
#include "il/TreeTop.hpp"
40
#include "il/TreeTop_inlines.hpp"
41
#include "x/codegen/RecompilationSnippet.hpp"
42
#include "x/codegen/X86Instruction.hpp"
43
44
// ***************************************************************************
45
//
46
// Implementation of TR_X86Recompilation
47
//
48
// ***************************************************************************
49
50
// Allocate a machine-specific recompilation processor for this compilation
51
//
52
TR::Recompilation *TR_X86Recompilation::allocate(TR::Compilation *comp)
53
{
54
if (comp->isRecompilationEnabled())
55
{
56
return new (comp->trHeapMemory()) TR_X86Recompilation(comp);
57
}
58
59
return NULL;
60
}
61
62
TR_X86Recompilation::TR_X86Recompilation(TR::Compilation * comp)
63
: TR::Recompilation(comp)
64
{
65
_countingSupported = true;
66
67
setupMethodInfo();
68
}
69
70
TR_PersistentMethodInfo *TR_X86Recompilation::getExistingMethodInfo(TR_ResolvedMethod *method)
71
{
72
// The method was previously compiled. Find its method info block from the
73
// start PC address. The mechanism is different depending on whether the
74
// method was compiled for sampling or counting.
75
//
76
TR_PersistentJittedBodyInfo *bodyInfo = ((TR_ResolvedJ9Method*) method)->getExistingJittedBodyInfo();
77
return bodyInfo ? bodyInfo->getMethodInfo() : NULL;
78
}
79
80
TR::Instruction *TR_X86Recompilation::generatePrePrologue()
81
{
82
TR_J9VMBase *fej9 = (TR_J9VMBase *)(_compilation->fe());
83
84
if (!couldBeCompiledAgain())
85
return NULL;
86
87
TR::Node * startNode = _compilation->getStartTree()->getNode();
88
TR::Instruction *prev = 0;
89
90
uint8_t alignmentMargin = useSampling()? SAMPLING_CALL_SIZE /* allow for the helper call */ : 0;
91
if (cg()->comp()->target().is64Bit())
92
alignmentMargin += SAVE_AREA_SIZE +JITTED_BODY_INFO_SIZE + LINKAGE_INFO_SIZE; // save area for the first two bytes of the method + jitted body info pointer + linkageinfo
93
else
94
alignmentMargin += JITTED_BODY_INFO_SIZE + LINKAGE_INFO_SIZE; // jitted body info pointer + linkageinfo
95
96
TR::LabelSymbol *startLabel = NULL;
97
98
// Make sure the startPC at least 4-byte aligned. This is important, since the VM
99
// depends on the alignment (it uses the low order bits as tag bits).
100
//
101
int32_t alignmentBoundary = 8;
102
if (cg()->mustGenerateSwitchToInterpreterPrePrologue())
103
{
104
// The SwitchToInterpreterPrePrologue will do the alignment for us.
105
//
106
prev = cg()->generateSwitchToInterpreterPrePrologue(prev, alignmentBoundary, alignmentMargin);
107
}
108
else
109
{
110
prev = generateAlignmentInstruction(prev, alignmentBoundary, alignmentMargin, cg());
111
}
112
113
if (cg()->comp()->target().is64Bit())
114
{
115
// A copy of the first two bytes of the method, in case we need to un-patch them
116
//
117
prev = new (trHeapMemory()) TR::X86ImmInstruction(prev, TR::InstOpCode::DWImm2, 0xcccc, cg());
118
}
119
120
if (useSampling())
121
{
122
// Note: the displacement of this call gets patched, but thanks to the
123
// alignment constraint on the startPC, it is automatically aligned to a
124
// 4-byte boundary, which is more than enough to ensure it can be patched
125
// atomically.
126
//
127
prev = generateHelperCallInstruction(prev, SAMPLING_RECOMPILE_METHOD, cg());
128
}
129
130
// The address of the persistent method info is inserted in the pre-prologue
131
// information. If the method is not to be compiled again a null value is
132
// inserted.
133
//
134
if (cg()->comp()->target().is64Bit())
135
{
136
// TODO:AMD64: This ought to be a relative address, but that requires
137
// binary-encoding-time support. If you change this, be sure to adjust
138
// the alignmentMargin above.
139
//
140
prev = new (trHeapMemory()) TR::AMD64Imm64Instruction(prev, TR::InstOpCode::DQImm64, (uintptr_t)getJittedBodyInfo(), cg());
141
prev->setNeedsAOTRelocation();
142
}
143
else
144
{
145
prev = new (trHeapMemory()) TR::X86ImmInstruction(prev, TR::InstOpCode::DDImm4, (uint32_t)(uintptr_t)getJittedBodyInfo(), cg());
146
prev->setNeedsAOTRelocation();
147
}
148
149
150
// Allow 4 bytes for private linkage return type info. Allocate the 4 bytes
151
// even if the linkage is not private, so that all the offsets are
152
// predictable.
153
//
154
return generateImmInstruction(TR::InstOpCode::DDImm4, startNode, 0, cg());
155
}
156
157
TR::Instruction *TR_X86Recompilation::generatePrologue(TR::Instruction *cursor)
158
{
159
TR::Machine *machine = cg()->machine();
160
TR::Linkage *linkage = cg()->getLinkage();
161
if (couldBeCompiledAgain())
162
{
163
if (!useSampling())
164
{
165
// We're generating the first instruction ourselves.
166
//
167
TR::MemoryReference *mRef;
168
169
if (cg()->comp()->target().is64Bit())
170
{
171
TR_ASSERT(linkage->getMinimumFirstInstructionSize() <= 10, "Can't satisfy first instruction size constraint");
172
TR::RealRegister *scratchReg = machine->getRealRegister(TR::RealRegister::edi);
173
cursor = new (trHeapMemory()) TR::AMD64RegImm64Instruction(cursor, TR::InstOpCode::MOV8RegImm64, scratchReg, (uintptr_t)getCounterAddress(), cg());
174
mRef = generateX86MemoryReference(scratchReg, 0, cg());
175
}
176
else
177
{
178
TR_ASSERT(linkage->getMinimumFirstInstructionSize() <= 5, "Can't satisfy first instruction size constraint");
179
mRef = generateX86MemoryReference((intptr_t)getCounterAddress(), cg());
180
}
181
182
if (!isProfilingCompilation())
183
cursor = new (trHeapMemory()) TR::X86MemImmInstruction(cursor, TR::InstOpCode::SUB4MemImms, mRef, 1, cg());
184
else
185
{
186
// This only applies to JitProfiling, as JProfiling uses sampling
187
TR_ASSERT(_compilation->getProfilingMode() == JitProfiling, "JProfiling should not use counting mechanism to trigger recompilation");
188
cursor = new (trHeapMemory()) TR::X86MemImmInstruction(cursor, TR::InstOpCode::CMP4MemImms, mRef, 0, cg());
189
}
190
191
TR::Instruction *counterInstruction = cursor;
192
TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg());
193
194
cursor = new (trHeapMemory()) TR::X86LabelInstruction(cursor, TR::InstOpCode::JL4, snippetLabel, cg());
195
((TR::X86LabelInstruction*)cursor)->prohibitShortening();
196
TR::Snippet *snippet =
197
new (trHeapMemory()) TR::X86RecompilationSnippet(snippetLabel, counterInstruction->getNode(), cg());
198
cg()->addSnippet(snippet);
199
}
200
}
201
202
return cursor;
203
}
204
205
void TR_X86Recompilation::postCompilation()
206
{
207
setMethodReturnInfoBits();
208
}
209
210
void TR_X86Recompilation::setMethodReturnInfoBits()
211
{
212
213
if (!couldBeCompiledAgain())
214
return;
215
216
// Sets up bits inside the linkage info field of the method. Linkage info
217
// is the dword immediately before the startPC
218
//
219
// The bits contain information about a) what kind of method header this
220
// is (counting/sampling), and, b) what kind of
221
// instruction was used as the first instruction.
222
//
223
// a) header type: the bits are used by getMethodInfoFromPC (above).
224
// the presence of bits guaranteed that the ptr to the PersistentMethodInfo
225
// would be located at the particular offset from startPC.
226
//
227
// b) In case a future compilation fails, we may need to restore the original first
228
// instruction of the method (this is done by OMR::Recompilation::methodCannotBeRecompiled)
229
//
230
uint8_t *startPC = _compilation->cg()->getCodeStart();
231
J9::PrivateLinkage::LinkageInfo *linkageInfo = J9::PrivateLinkage::LinkageInfo::get(startPC);
232
233
if (useSampling())
234
{
235
linkageInfo->setSamplingMethodBody();
236
saveFirstTwoBytes(startPC, START_PC_TO_ORIGINAL_ENTRY_BYTES);
237
238
// TODO: It would be best if we didn't have to update the instruction object here, ideal
239
// solution would be have these bits set as lazily as possible and remove them from consideration
240
// prior to runtime, but race conditions for the update need to be considered.
241
//
242
if (comp()->getDebug())
243
{
244
cg()->getReturnTypeInfoInstruction()->setSourceImmediate(*(uint32_t*)linkageInfo);
245
}
246
}
247
else
248
{
249
linkageInfo->setCountingMethodBody();
250
}
251
}
252
253
254