Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/x/codegen/J9CodeGenerator.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 "codegen/AheadOfTimeCompile.hpp"
24
#include "codegen/CodeGenerator.hpp"
25
#include "codegen/CodeGenerator_inlines.hpp"
26
#include "codegen/Machine.hpp"
27
#include "codegen/Linkage.hpp"
28
#include "codegen/Linkage_inlines.hpp"
29
#include "compile/Compilation.hpp"
30
#include "control/Recompilation.hpp"
31
#include "control/RecompilationInfo.hpp"
32
#include "env/CompilerEnv.hpp"
33
#include "env/VMJ9.h"
34
#include "env/jittypes.h"
35
#include "il/Node.hpp"
36
#include "il/Node_inlines.hpp"
37
#include "il/TreeTop.hpp"
38
#include "il/TreeTop_inlines.hpp"
39
#include "runtime/CodeCache.hpp"
40
#include "runtime/CodeCacheConfig.hpp"
41
#include "runtime/CodeCacheExceptions.hpp"
42
#include "runtime/CodeCacheManager.hpp"
43
#include "runtime/CodeCacheTypes.hpp"
44
#include "runtime/J9Runtime.hpp"
45
#include "x/codegen/CallSnippet.hpp"
46
#include "x/codegen/X86Recompilation.hpp"
47
#include "x/codegen/FPTreeEvaluator.hpp"
48
#include "x/codegen/X86Instruction.hpp"
49
50
extern void TEMPORARY_initJ9X86TreeEvaluatorTable(TR::CodeGenerator *cg);
51
52
J9::X86::CodeGenerator::CodeGenerator(TR::Compilation *comp) :
53
J9::CodeGenerator(comp),
54
_stackFramePaddingSizeInBytes(0)
55
{
56
/**
57
* Do not add CodeGenerator initialization logic here.
58
* Use the \c initialize() method instead.
59
*/
60
}
61
62
void
63
J9::X86::CodeGenerator::initialize()
64
{
65
self()->J9::CodeGenerator::initialize();
66
67
TR::CodeGenerator *cg = self();
68
TR::Compilation *comp = cg->comp();
69
TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());
70
TR::ResolvedMethodSymbol *methodSymbol = comp->getJittedMethodSymbol();
71
TR_ResolvedMethod * jittedMethod = methodSymbol->getResolvedMethod();
72
73
cg->setAheadOfTimeCompile(new (cg->trHeapMemory()) TR::AheadOfTimeCompile(cg));
74
75
if (!TR::Compiler->om.canGenerateArraylets())
76
{
77
cg->setSupportsReferenceArrayCopy();
78
cg->setSupportsInlineStringLatin1Inflate();
79
}
80
81
if (comp->requiresSpineChecks())
82
{
83
// Spine check code doesn't officially support codegen register rematerialization
84
// yet. Better spill placement interferes with tracking live spills.
85
//
86
cg->setUseNonLinearRegisterAssigner();
87
cg->resetEnableRematerialisation();
88
cg->resetEnableBetterSpillPlacements();
89
}
90
91
static char *disableMonitorCacheLookup = feGetEnv("TR_disableMonitorCacheLookup");
92
if (!disableMonitorCacheLookup)
93
{
94
comp->setOption(TR_EnableMonitorCacheLookup);
95
}
96
97
cg->setSupportsPartialInlineOfMethodHooks();
98
cg->setSupportsInliningOfTypeCoersionMethods();
99
cg->setSupportsNewInstanceImplOpt();
100
101
TR_ASSERT_FATAL(comp->compileRelocatableCode() || comp->isOutOfProcessCompilation() || comp->compilePortableCode() || comp->target().cpu.supportsFeature(OMR_FEATURE_X86_SSE4_1) == cg->getX86ProcessorInfo().supportsSSE4_1(), "supportsSSE4_1() failed\n");
102
TR_ASSERT_FATAL(comp->compileRelocatableCode() || comp->isOutOfProcessCompilation() || comp->compilePortableCode() || comp->target().cpu.supportsFeature(OMR_FEATURE_X86_SSSE3) == cg->getX86ProcessorInfo().supportsSSSE3(), "supportsSSSE3() failed\n");
103
104
if (comp->target().cpu.supportsFeature(OMR_FEATURE_X86_SSE4_1) &&
105
!comp->getOption(TR_DisableSIMDStringCaseConv) &&
106
!TR::Compiler->om.canGenerateArraylets())
107
cg->setSupportsInlineStringCaseConversion();
108
109
if (comp->target().cpu.supportsFeature(OMR_FEATURE_X86_SSSE3) &&
110
!comp->getOption(TR_DisableFastStringIndexOf) &&
111
!TR::Compiler->om.canGenerateArraylets())
112
{
113
cg->setSupportsInlineStringIndexOf();
114
}
115
116
if (comp->target().cpu.supportsFeature(OMR_FEATURE_X86_SSE4_1) &&
117
!comp->getOption(TR_DisableSIMDStringHashCode) &&
118
!TR::Compiler->om.canGenerateArraylets())
119
{
120
cg->setSupportsInlineStringHashCode();
121
}
122
123
if (comp->generateArraylets() && !comp->getOptions()->realTimeGC())
124
{
125
cg->setSupportsStackAllocationOfArraylets();
126
}
127
128
if (!comp->getOption(TR_FullSpeedDebug))
129
cg->setSupportsDirectJNICalls();
130
131
if (!comp->getOption(TR_DisableBDLLVersioning))
132
{
133
cg->setSupportsBigDecimalLongLookasideVersioning();
134
cg->setSupportsBDLLHardwareOverflowCheck();
135
}
136
137
// Disable fast gencon barriers for AOT compiles because relocations on
138
// the inlined heap addresses are not available (yet).
139
//
140
if (!fej9->supportsEmbeddedHeapBounds())
141
{
142
comp->setOption(TR_DisableWriteBarriersRangeCheck);
143
}
144
145
// Enable copy propagation of floats.
146
//
147
cg->setSupportsJavaFloatSemantics();
148
149
/*
150
* "Statically" initialize the FE-specific tree evaluator functions.
151
* This code only needs to execute once per JIT lifetime.
152
*/
153
static bool initTreeEvaluatorTable = false;
154
if (!initTreeEvaluatorTable)
155
{
156
TEMPORARY_initJ9X86TreeEvaluatorTable(cg);
157
initTreeEvaluatorTable = true;
158
}
159
160
// Set return type info here so that we always set it in case the return is optimized out
161
TR_ReturnInfo returnInfo;
162
switch (jittedMethod->returnType())
163
{
164
case TR::NoType:
165
returnInfo = TR_VoidReturn;
166
break;
167
case TR::Int8:
168
case TR::Int16:
169
case TR::Int32:
170
returnInfo = TR_IntReturn;
171
break;
172
case TR::Int64:
173
returnInfo = TR_LongReturn;
174
break;
175
case TR::Address:
176
returnInfo = comp->target().is64Bit() ? TR_ObjectReturn : TR_IntReturn;
177
break;
178
case TR::Float:
179
returnInfo = TR_FloatXMMReturn;
180
break;
181
case TR::Double:
182
returnInfo = TR_DoubleXMMReturn;
183
break;
184
}
185
186
comp->setReturnInfo(returnInfo);
187
}
188
189
TR::Recompilation *
190
J9::X86::CodeGenerator::allocateRecompilationInfo()
191
{
192
return TR_X86Recompilation::allocate(self()->comp());
193
}
194
195
void
196
J9::X86::CodeGenerator::beginInstructionSelection()
197
{
198
TR::Compilation *comp = self()->comp();
199
_returnTypeInfoInstruction = NULL;
200
TR::ResolvedMethodSymbol *methodSymbol = comp->getJittedMethodSymbol();
201
TR::Recompilation *recompilation = comp->getRecompilationInfo();
202
TR::Node *startNode = comp->getStartTree()->getNode();
203
204
if (recompilation && recompilation->generatePrePrologue() != NULL)
205
{
206
// Return type info will have been generated by recompilation info
207
//
208
if (methodSymbol->getLinkageConvention() == TR_Private)
209
_returnTypeInfoInstruction = (TR::X86ImmInstruction*)self()->getAppendInstruction();
210
211
if (methodSymbol->getLinkageConvention() == TR_System)
212
_returnTypeInfoInstruction = (TR::X86ImmInstruction*)self()->getAppendInstruction();
213
}
214
else if (comp->getOption(TR_FullSpeedDebug) || comp->getOption(TR_SupportSwitchToInterpreter))
215
{
216
int32_t alignmentMargin = comp->target().is64Bit()? 2 : 0; // # bytes between the alignment instruction and the address that needs to be aligned
217
if (methodSymbol->getLinkageConvention() == TR_Private)
218
alignmentMargin += 4; // The linkageInfo word
219
220
// Make sure the startPC is at least 8-byte aligned. The VM needs to be
221
// able to low-tag the pointer, and also for code patching on IA32, this
222
// is how we make sure the first instruction doesn't cross a patching boundary (see 175746).
223
//
224
int32_t alignmentBoundary = 8;
225
226
TR::Instruction *cursor = self()->generateSwitchToInterpreterPrePrologue(NULL, alignmentBoundary, alignmentMargin);
227
if (comp->target().is64Bit())
228
{
229
// A copy of the first two bytes of the method, in case we need to un-patch them
230
//
231
new (self()->trHeapMemory()) TR::X86ImmInstruction(cursor, TR::InstOpCode::DWImm2, 0xcccc, self());
232
}
233
}
234
else if (methodSymbol->isJNI())
235
{
236
237
intptr_t methodAddress = (intptr_t)methodSymbol->getResolvedMethod()->startAddressForJNIMethod(comp);
238
239
if (comp->target().is64Bit())
240
new (self()->trHeapMemory()) TR::AMD64Imm64Instruction ((TR::Instruction *)NULL, TR::InstOpCode::DQImm64, methodAddress, self());
241
else
242
new (self()->trHeapMemory()) TR::X86ImmInstruction ((TR::Instruction *)NULL, TR::InstOpCode::DDImm4, methodAddress, self());
243
}
244
245
if (methodSymbol->getLinkageConvention() == TR_Private && !_returnTypeInfoInstruction)
246
{
247
// linkageInfo word
248
if (self()->getAppendInstruction())
249
_returnTypeInfoInstruction = generateImmInstruction(TR::InstOpCode::DDImm4, startNode, 0, self());
250
else
251
_returnTypeInfoInstruction = new (self()->trHeapMemory()) TR::X86ImmInstruction((TR::Instruction *)NULL, TR::InstOpCode::DDImm4, 0, self());
252
}
253
254
if (methodSymbol->getLinkageConvention() == TR_System && !_returnTypeInfoInstruction)
255
{
256
// linkageInfo word
257
if (self()->getAppendInstruction())
258
_returnTypeInfoInstruction = generateImmInstruction(TR::InstOpCode::DDImm4, startNode, 0, self());
259
else
260
_returnTypeInfoInstruction = new (self()->trHeapMemory()) TR::X86ImmInstruction((TR::Instruction *)NULL, TR::InstOpCode::DDImm4, 0, self());
261
}
262
263
TR::RegisterDependencyConditions *deps = generateRegisterDependencyConditions((uint8_t)0, (uint8_t)1, self());
264
if (_linkageProperties->getMethodMetaDataRegister() != TR::RealRegister::NoReg)
265
{
266
deps->addPostCondition(self()->getVMThreadRegister(),
267
(TR::RealRegister::RegNum)self()->getVMThreadRegister()->getAssociation(), self());
268
}
269
deps->stopAddingPostConditions();
270
271
if (self()->getAppendInstruction())
272
generateInstruction(TR::InstOpCode::proc, startNode, deps, self());
273
else
274
new (self()->trHeapMemory()) TR::Instruction(deps, TR::InstOpCode::proc, (TR::Instruction *)NULL, self());
275
276
// Set the default FPCW to single precision mode if we are allowed to.
277
//
278
if (self()->enableSinglePrecisionMethods() && comp->getJittedMethodSymbol()->usesSinglePrecisionMode())
279
{
280
auto cds = self()->findOrCreate2ByteConstant(startNode, SINGLE_PRECISION_ROUND_TO_NEAREST);
281
generateMemInstruction(TR::InstOpCode::LDCWMem, startNode, generateX86MemoryReference(cds, self()), self());
282
}
283
}
284
285
void
286
J9::X86::CodeGenerator::endInstructionSelection()
287
{
288
TR::Compilation *comp = self()->comp();
289
if (_returnTypeInfoInstruction != NULL)
290
{
291
TR_ReturnInfo returnInfo = comp->getReturnInfo();
292
293
// Note: this will get clobbered again in code generation on AMD64
294
_returnTypeInfoInstruction->setSourceImmediate(returnInfo);
295
}
296
297
// Reset the FPCW in the dummy finally block.
298
//
299
if (self()->enableSinglePrecisionMethods() &&
300
comp->getJittedMethodSymbol()->usesSinglePrecisionMode())
301
{
302
TR_ASSERT(self()->getLastCatchAppendInstruction(),
303
"endInstructionSelection() ==> Could not find the dummy finally block!\n");
304
305
auto cds = self()->findOrCreate2ByteConstant(self()->getLastCatchAppendInstruction()->getNode(), DOUBLE_PRECISION_ROUND_TO_NEAREST);
306
generateMemInstruction(self()->getLastCatchAppendInstruction(), TR::InstOpCode::LDCWMem, generateX86MemoryReference(cds, self()), self());
307
}
308
}
309
310
TR::Instruction *
311
J9::X86::CodeGenerator::generateSwitchToInterpreterPrePrologue(
312
TR::Instruction *prev,
313
uint8_t alignment,
314
uint8_t alignmentMargin)
315
{
316
TR::Compilation *comp = self()->comp();
317
TR::Register *ediRegister = self()->allocateRegister();
318
TR::ResolvedMethodSymbol *methodSymbol = comp->getJittedMethodSymbol();
319
intptr_t feMethod = (intptr_t)methodSymbol->getResolvedMethod()->resolvedMethodAddress();
320
TR::LabelSymbol *startLabel = NULL;
321
322
if (comp->target().is32Bit())
323
{
324
// Put the alignment before the interpreter jump so the jump's offset is fixed
325
//
326
alignmentMargin += 6; // TR::InstOpCode::MOV4RegImm4 below
327
prev = generateAlignmentInstruction(prev, alignment, alignmentMargin, self());
328
}
329
330
startLabel = generateLabelSymbol(self());
331
prev = generateLabelInstruction(prev, TR::InstOpCode::label, startLabel, self());
332
self()->setSwitchToInterpreterLabel(startLabel);
333
334
TR::RegisterDependencyConditions *deps =
335
generateRegisterDependencyConditions((uint8_t)1, (uint8_t)0, self());
336
deps->addPreCondition(ediRegister, TR::RealRegister::edi, self());
337
338
TR::SymbolReference *helperSymRef =
339
self()->symRefTab()->findOrCreateRuntimeHelper(TR_j2iTransition);
340
341
if (comp->target().is64Bit())
342
{
343
prev = generateRegImm64Instruction(prev, TR::InstOpCode::MOV8RegImm64, ediRegister, feMethod, self(), TR_RamMethod);
344
if (comp->getOption(TR_EnableHCR))
345
comp->getStaticHCRPICSites()->push_front(prev);
346
prev = self()->getLinkage(methodSymbol->getLinkageConvention())->storeArguments(prev, methodSymbol);
347
}
348
else
349
{
350
prev = generateRegImmInstruction(prev, TR::InstOpCode::MOV4RegImm4, ediRegister, feMethod, self(), TR_RamMethod);
351
if (comp->getOption(TR_EnableHCR))
352
comp->getStaticHCRPICSites()->push_front(prev);
353
}
354
355
prev = new (self()->trHeapMemory()) TR::X86ImmSymInstruction(prev, TR::InstOpCode::JMP4, (uintptr_t)helperSymRef->getMethodAddress(), helperSymRef, deps, self());
356
self()->stopUsingRegister(ediRegister);
357
358
if (comp->target().is64Bit())
359
{
360
// Generate a mini-trampoline jump to the start of the
361
// SwitchToInterpreterPrePrologue. This comes after the alignment
362
// instruction so we know where it will be relative to startPC. Note
363
// that it ought to be a TR::InstOpCode::JMP1 despite the fact that we're using a TR::InstOpCode::JMP4
364
// opCode; otherwise, this instruction is not 2 bytes long, so it will
365
// mess up alignment.
366
//
367
alignmentMargin += 2; // Size of the mini-trampoline
368
prev = generateAlignmentInstruction(prev, alignment, alignmentMargin, self());
369
prev = new (self()->trHeapMemory()) TR::X86LabelInstruction(prev, TR::InstOpCode::JMP4, startLabel, self());
370
}
371
372
return prev;
373
}
374
375
bool
376
J9::X86::CodeGenerator::nopsAlsoProcessedByRelocations()
377
{
378
return self()->fej9()->nopsAlsoProcessedByRelocations();
379
}
380
381
382
bool
383
J9::X86::CodeGenerator::enableAESInHardwareTransformations()
384
{
385
if (self()->comp()->target().cpu.supportsFeature(OMR_FEATURE_X86_AESNI) && !self()->comp()->getOption(TR_DisableAESInHardware) && !self()->comp()->getCurrentMethod()->isJNINative())
386
return true;
387
else
388
return false;
389
}
390
391
bool
392
J9::X86::CodeGenerator::suppressInliningOfRecognizedMethod(TR::RecognizedMethod method)
393
{
394
switch (method)
395
{
396
case TR::java_lang_Object_clone:
397
return true;
398
default:
399
return false;
400
}
401
}
402
403
bool
404
J9::X86::CodeGenerator::supportsInliningOfIsAssignableFrom()
405
{
406
static const bool disableInliningOfIsAssignableFrom = feGetEnv("TR_disableInlineIsAssignableFrom") != NULL;
407
return !disableInliningOfIsAssignableFrom;
408
}
409
410
bool
411
J9::X86::CodeGenerator::canEmitBreakOnDFSet()
412
{
413
static const bool enableBreakOnDFSet = feGetEnv("TR_enableBreakOnDFSet") != NULL;
414
return enableBreakOnDFSet;
415
}
416
417
void
418
J9::X86::CodeGenerator::reserveNTrampolines(int32_t numTrampolines)
419
{
420
TR_J9VMBase *fej9 = (TR_J9VMBase *)(self()->fe());
421
TR::Compilation *comp = self()->comp();
422
423
if (!TR::CodeCacheManager::instance()->codeCacheConfig().needsMethodTrampolines())
424
return;
425
426
bool hadClassUnloadMonitor;
427
bool hadVMAccess = fej9->releaseClassUnloadMonitorAndAcquireVMaccessIfNeeded(comp, &hadClassUnloadMonitor);
428
429
TR::CodeCache *curCache = self()->getCodeCache();
430
TR::CodeCache *newCache = curCache;
431
OMR::CodeCacheErrorCode::ErrorCode status = OMR::CodeCacheErrorCode::ERRORCODE_SUCCESS;
432
433
TR_ASSERT(curCache->isReserved(), "Current CodeCache is not reserved");
434
435
if (!fej9->isAOT_DEPRECATED_DO_NOT_USE())
436
{
437
status = curCache->reserveSpaceForTrampoline_bridge(numTrampolines);
438
if (status != OMR::CodeCacheErrorCode::ERRORCODE_SUCCESS)
439
{
440
// Current code cache is no good. Must unreserve
441
curCache->unreserve();
442
newCache = 0;
443
if (self()->getCodeGeneratorPhase() != TR::CodeGenPhase::BinaryEncodingPhase)
444
{
445
newCache = TR::CodeCacheManager::instance()->getNewCodeCache(comp->getCompThreadID());
446
if (newCache)
447
{
448
status = newCache->reserveSpaceForTrampoline_bridge(numTrampolines);
449
450
if (status != OMR::CodeCacheErrorCode::ERRORCODE_SUCCESS)
451
{
452
TR_ASSERT(0, "Failed to reserve trampolines in fresh code cache.");
453
newCache->unreserve();
454
}
455
}
456
}
457
}
458
}
459
460
fej9->acquireClassUnloadMonitorAndReleaseVMAccessIfNeeded(comp, hadVMAccess, hadClassUnloadMonitor);
461
462
if (!newCache)
463
{
464
comp->failCompilation<TR::TrampolineError>("Failed to allocate code cache in reserveNTrampolines");
465
}
466
467
if (newCache != curCache)
468
{
469
// We keep track of number of IPIC trampolines that are present in the current code cache
470
// If the code caches have been switched we have to reset this number, the setCodeCacheSwitched helper called
471
// in switchCodeCacheTo resets the count
472
// If we are in binaryEncoding we will kill this compilation anyway
473
//
474
self()->switchCodeCacheTo(newCache);
475
}
476
else
477
{
478
self()->setNumReservedIPICTrampolines(self()->getNumReservedIPICTrampolines() + numTrampolines);
479
}
480
481
TR_ASSERT(newCache->isReserved(), "New CodeCache is not reserved");
482
}
483
484