Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/x/codegen/CheckFailureSnippet.cpp
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2020 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/CheckFailureSnippet.hpp"
24
25
#include "codegen/CodeGenerator.hpp"
26
#include "codegen/Instruction.hpp"
27
#include "codegen/Relocation.hpp"
28
#include "codegen/SnippetGCMap.hpp"
29
#include "env/IO.hpp"
30
#include "env/jittypes.h"
31
#include "env/VMJ9.h"
32
#include "il/LabelSymbol.hpp"
33
#include "il/MethodSymbol.hpp"
34
#include "il/Node.hpp"
35
#include "il/Node_inlines.hpp"
36
#include "il/RegisterMappedSymbol.hpp"
37
#include "il/ResolvedMethodSymbol.hpp"
38
#include "il/StaticSymbol.hpp"
39
#include "il/Symbol.hpp"
40
#include "infra/SimpleRegex.hpp"
41
#include "runtime/CodeCacheManager.hpp"
42
43
uint32_t TR::X86CheckFailureSnippet::getLength(int32_t estimatedSnippetStart)
44
{
45
uint32_t breakSize = 0;
46
if(_breakOnThrowType)
47
{
48
switch (getDestination()->getReferenceNumber())
49
{
50
case TR_nullCheck:
51
{
52
if (_breakOnThrowType&TR_BREAKONTHROW_NPE)
53
{
54
breakSize=1;
55
}
56
break;
57
}
58
case TR_arrayBoundsCheck:
59
{
60
if (_breakOnThrowType&TR_BREAKONTHROW_AIOB)
61
{
62
breakSize=1;
63
}
64
break;
65
}
66
}
67
68
}
69
return (_requiresFPstackPop ? 11 : 9) + breakSize;
70
}
71
72
uint8_t *TR::X86CheckFailureSnippet::emitSnippetBody()
73
{
74
uint8_t *buffer = cg()->getBinaryBufferCursor();
75
getSnippetLabel()->setCodeLocation(buffer);
76
buffer = emitCheckFailureSnippetBody(buffer);
77
return buffer;
78
}
79
80
81
void
82
TR_Debug::print(TR::FILE *pOutFile, TR::X86CheckFailureSnippet * snippet)
83
{
84
if (pOutFile == NULL)
85
return;
86
87
TR::SymbolReference *symRef = snippet->getDestination();
88
TR::MethodSymbol *sym = symRef->getSymbol()->castToMethodSymbol();
89
uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();
90
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet), getName(symRef));
91
92
if (snippet->getRequiredFPstackPop())
93
{
94
printPrefix(pOutFile, NULL, bufferPos, 2);
95
trfprintf(pOutFile, "fstp\tst(0)\t\t%s Discard top of FP stack",
96
commentString());
97
bufferPos += 2;
98
}
99
100
printPrefix(pOutFile, NULL, bufferPos, 5);
101
trfprintf(pOutFile, "call\t%s \t\t%s Helper Address = " POINTER_PRINTF_FORMAT,
102
getName(symRef),
103
commentString(),
104
sym->getMethodAddress());
105
bufferPos += 5;
106
107
printPrefix(pOutFile, NULL, bufferPos, 4);
108
trfprintf(pOutFile,
109
"%s \t%s%08x%s",
110
ddString(),
111
hexPrefixString(),
112
bufferPos - snippet->getCheckInstruction()->getBinaryEncoding(),
113
hexSuffixString());
114
}
115
116
117
uint8_t *TR::X86CheckFailureSnippet::emitCheckFailureSnippetBody(uint8_t *buffer)
118
{
119
TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg()->fe());
120
121
// add int3 instruction if breakOnThrow is set on NPE or AIOB
122
if(_breakOnThrowType)
123
{
124
switch (getDestination()->getReferenceNumber())
125
{
126
case TR_nullCheck:
127
{
128
if (_breakOnThrowType&TR_BREAKONTHROW_NPE)
129
{
130
*buffer++ = 0xcc;
131
}
132
break;
133
}
134
case TR_arrayBoundsCheck:
135
{
136
if (_breakOnThrowType&TR_BREAKONTHROW_AIOB)
137
{
138
*buffer++ = 0xcc;
139
}
140
break;
141
}
142
}
143
}
144
// Discard the top of the FP stack
145
//
146
if (_requiresFPstackPop)
147
{
148
*buffer++ = 0xdd; // FSTP st0,st0
149
*buffer++ = 0xd8;
150
}
151
152
*buffer++ = 0xe8; // CallImm4
153
intptr_t destinationAddress = (intptr_t)getDestination()->getMethodAddress();
154
155
if (NEEDS_TRAMPOLINE(destinationAddress, buffer+4, cg()))
156
{
157
destinationAddress = TR::CodeCacheManager::instance()->findHelperTrampoline(getDestination()->getReferenceNumber(), (void *)buffer);
158
TR_ASSERT(IS_32BIT_RIP(destinationAddress, buffer+4), "Local helper trampoline should be reachable directly.\n");
159
}
160
161
*(int32_t *)buffer = (int32_t)(destinationAddress - (intptr_t)(buffer+4));
162
cg()->addExternalRelocation(new (cg()->trHeapMemory())
163
TR::ExternalRelocation(
164
buffer,
165
(uint8_t *)getDestination(),
166
TR_HelperAddress,
167
cg()),
168
__FILE__, __LINE__, getCheckInstruction()->getNode());
169
170
buffer += 4;
171
uint8_t *checkSite = getCheckInstruction()->getBinaryEncoding();
172
*(uint32_t *)buffer = (uint32_t)(buffer - checkSite);
173
buffer += 4;
174
175
// Up until this point we haven't marked the jump instruction getCheckInstruction() as being a gc safe
176
// point and we've marked the snippet as being a gc point. This call to registerStackMap is going add
177
// the gc map to the atlas and associate it with the jump instruction. The flags on the instruction
178
// and snippet are set back to reflect this.
179
//
180
// The real fix is to change the helper and snippet to not do the return code adjust, have the return
181
// address be the snippet and associate the gc map with the snippet.
182
//
183
gcMap().registerStackMap(checkSite, cg());
184
if (gcMap().getStackMap())
185
{
186
getCheckInstruction()->setNeedsGCMap();
187
gcMap().resetGCSafePoint();
188
resetNeedsExceptionTableEntry();
189
}
190
191
return buffer;
192
}
193
194
195
void TR::X86CheckFailureSnippet::checkBreakOnThrowOption()
196
{
197
TR::SimpleRegex *r = cg()->comp()->getOptions()->getBreakOnThrow();
198
if (r && (TR::SimpleRegex::matchIgnoringLocale(r, "java/lang/NullPointerException")
199
|| TR::SimpleRegex::matchIgnoringLocale(r, "NPE", false)))
200
{
201
_breakOnThrowType|=TR_BREAKONTHROW_NPE;
202
}
203
if (r && (TR::SimpleRegex::matchIgnoringLocale(r, "java/lang/ArrayIndexOutOfBoundsException")
204
|| TR::SimpleRegex::matchIgnoringLocale(r, "AIOB", false)))
205
{
206
_breakOnThrowType|=TR_BREAKONTHROW_AIOB;
207
}
208
}
209
210
211
uint32_t TR::X86BoundCheckWithSpineCheckSnippet::getLength(int32_t estimatedSnippetStart)
212
{
213
return 0;
214
}
215
216
uint8_t *TR::X86BoundCheckWithSpineCheckSnippet::emitSnippetBody()
217
{
218
uint8_t *buffer = cg()->getBinaryBufferCursor();
219
getSnippetLabel()->setCodeLocation(buffer);
220
return buffer;
221
}
222
223
void
224
TR_Debug::print(TR::FILE *pOutFile, TR::X86BoundCheckWithSpineCheckSnippet *snippet)
225
{
226
if (pOutFile == NULL)
227
return;
228
229
TR::SymbolReference *symRef = snippet->getDestination();
230
TR::MethodSymbol *sym = symRef->getSymbol()->castToMethodSymbol();
231
uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();
232
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet), getName(symRef));
233
234
trfprintf(pOutFile, "\t\t\t\t\t\t\t\t\t%s bound check with spine check snippet", commentString());
235
236
}
237
238
uint32_t TR::X86SpineCheckSnippet::getLength(int32_t estimatedSnippetStart)
239
{
240
return 0;
241
}
242
243
uint8_t *TR::X86SpineCheckSnippet::emitSnippetBody()
244
{
245
uint8_t *buffer = cg()->getBinaryBufferCursor();
246
getSnippetLabel()->setCodeLocation(buffer);
247
return buffer;
248
}
249
250
void
251
TR_Debug::print(TR::FILE *pOutFile, TR::X86SpineCheckSnippet *snippet)
252
{
253
if (pOutFile == NULL)
254
return;
255
256
TR::SymbolReference *symRef = snippet->getDestination();
257
TR::MethodSymbol *sym = symRef->getSymbol()->castToMethodSymbol();
258
uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();
259
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet), getName(symRef));
260
261
trfprintf(pOutFile, "\t\t\t\t\t\t\t\t\t%s spine check snippet", commentString());
262
263
}
264
265
266
uint32_t TR::X86CheckFailureSnippetWithResolve::getLength(int32_t estimatedSnippetStart)
267
{
268
269
return getRequiredFPstackPop() ? 32 : 30;
270
}
271
272
enum
273
{
274
resolveHasLiveXMMRs = 0x10000000,
275
longPushTag = 0x00800000,
276
dontPatchTag = 0x00400000
277
};
278
279
uint8_t *TR::X86CheckFailureSnippetWithResolve::emitSnippetBody()
280
{
281
TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg()->fe());
282
uint8_t *buffer = cg()->getBinaryBufferCursor();
283
getSnippetLabel()->setCodeLocation(buffer);
284
285
*buffer++ = 0x68; // push imm4 (return address is the throw of the nullpointer)
286
*(int32_t *)buffer = (int32_t) (intptr_t) (buffer + 24);
287
buffer += 4;
288
289
int32_t cpIndexValue = getDataSymbolReference()->getCPIndex();
290
291
*buffer++ = 0x68; // push imm4
292
293
// Tag the value so that we can recognise the long case
294
//
295
if (getHasLiveXMMRs())
296
cpIndexValue |= resolveHasLiveXMMRs;
297
298
*(int32_t *)buffer = (getNumLiveX87Registers() << 24) | dontPatchTag | longPushTag | cpIndexValue;
299
buffer += 4;
300
301
302
// Push address of literal pool
303
//
304
*buffer++ = 0x68; // push imm4
305
*(int32_t *)buffer = (int32_t) (intptr_t) getDataSymbolReference()->getOwningMethod(cg()->comp())->constantPool();
306
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(buffer,
307
*(uint8_t **)buffer,
308
getCheckInstruction()->getNode() ? (uint8_t *)(uintptr_t)getCheckInstruction()->getNode()->getInlinedSiteIndex() : (uint8_t *)-1,
309
TR_ConstantPool, cg()),
310
__FILE__, __LINE__,
311
getCheckInstruction()->getNode());
312
buffer += 4;
313
314
// Call the glue routine
315
//
316
*buffer++ = 0xe8; // call Imm4 glue routine
317
318
TR::SymbolReference * glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(getHelper());
319
intptr_t glueAddress = (intptr_t)glueSymRef->getMethodAddress();
320
if (NEEDS_TRAMPOLINE(glueAddress, buffer+4, cg()))
321
{
322
glueAddress = TR::CodeCacheManager::instance()->findHelperTrampoline(glueSymRef->getReferenceNumber(), (void *)buffer);
323
TR_ASSERT(IS_32BIT_RIP(glueAddress, buffer+4), "Local helper trampoline should be reachable directly.\n");
324
}
325
*(int32_t *)buffer = (int32_t)(glueAddress - (intptr_t)(buffer+4));
326
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(buffer,
327
(uint8_t *)glueSymRef,
328
TR_HelperAddress, cg()),
329
__FILE__,
330
__LINE__,
331
getCheckInstruction()->getNode());
332
333
buffer += 4;
334
335
// Discard the top of the FP stack
336
//
337
if (getRequiredFPstackPop())
338
{
339
*buffer++ = 0xdd; // FSTP st0,st0
340
*buffer++ = 0xd8;
341
}
342
343
*buffer++ = 0xe8; // CallImm4
344
345
intptr_t destinationAddress = (intptr_t)getDestination()->getMethodAddress();
346
if (NEEDS_TRAMPOLINE(destinationAddress, buffer+4, cg()))
347
{
348
destinationAddress = TR::CodeCacheManager::instance()->findHelperTrampoline(getDestination()->getReferenceNumber(), (void *)buffer);
349
TR_ASSERT(IS_32BIT_RIP(destinationAddress, buffer+4), "Local helper trampoline should be reachable directly.\n");
350
}
351
*(int32_t *)buffer = (int32_t)(destinationAddress - (intptr_t)(buffer+4));
352
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(buffer,
353
(uint8_t *)getDestination(),
354
TR_HelperAddress,
355
cg()),
356
__FILE__,
357
__LINE__,
358
getCheckInstruction()->getNode());
359
buffer += 4;
360
uint8_t *checkSite = getCheckInstruction()->getBinaryEncoding();
361
*(uint32_t *)buffer = (uint32_t)(buffer - checkSite);
362
buffer += 4;
363
364
// Up until this point we haven't marked the jump instruction getCheckInstruction() as being a gc safe point and
365
// we've marked the snippet as being a gc point. This call to registerStackMap is going add the gc map to the atlas
366
// and associate it with the jump instruction. The flags on the instruction and snippet are set back to reflect this.
367
// The real fix is to change the helper and snippet to not do the return code adjust, have the return address be the
368
// snippet and associate the gc map with the snippet.
369
//
370
gcMap().registerStackMap(checkSite, cg());
371
if (gcMap().getStackMap())
372
{
373
getCheckInstruction()->setNeedsGCMap();
374
gcMap().resetGCSafePoint();
375
resetNeedsExceptionTableEntry();
376
}
377
378
return buffer;
379
}
380
381
382
void
383
TR_Debug::print(TR::FILE *pOutFile, TR::X86CheckFailureSnippetWithResolve * snippet)
384
{
385
386
enum
387
{
388
longPushTag = 0x00800000,
389
dontPatchTag = 0x00400000
390
};
391
392
if (pOutFile == NULL)
393
return;
394
TR::SymbolReference *symRef = snippet->getDestination();
395
TR::MethodSymbol *sym = symRef->getSymbol()->castToMethodSymbol();
396
uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();
397
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet), getName(symRef));
398
399
TR::SymbolReference *methodSymRef = snippet->getNode()->getSymbolReference();
400
TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
401
int32_t cpIndexValue = ((TR::X86CheckFailureSnippetWithResolve *)snippet)->getDataSymbolReference()->getCPIndex();
402
int32_t size = 5;
403
404
printPrefix(pOutFile, NULL, bufferPos, size);
405
trfprintf(pOutFile, "push\t" POINTER_PRINTF_FORMAT "\t\t%s push return address which is the throw bellow", bufferPos+24,
406
commentString());
407
bufferPos += 5;
408
409
cpIndexValue |= dontPatchTag;
410
cpIndexValue |= longPushTag;
411
printPrefix(pOutFile, NULL, bufferPos, size);
412
trfprintf(pOutFile, "push\t" POINTER_PRINTF_FORMAT "\t\t%s push cpIndex", cpIndexValue,
413
commentString());
414
bufferPos += size;
415
416
printPrefix(pOutFile, NULL, bufferPos, 5);
417
trfprintf(pOutFile,
418
"push\t" POINTER_PRINTF_FORMAT "\t\t%s push address of constant pool",
419
getOwningMethod(methodSymRef)->constantPool(),
420
commentString());
421
bufferPos += 5;
422
423
printPrefix(pOutFile, NULL, bufferPos, 5);
424
425
trfprintf(pOutFile, "call\tResolve Function For the Child to the NULLChk");
426
bufferPos += 5;
427
428
if (snippet->getRequiredFPstackPop())
429
{
430
printPrefix(pOutFile, NULL, bufferPos, 2);
431
trfprintf(pOutFile, "fstp\tst(0)\t\t%s Discard top of FP stack",
432
commentString());
433
bufferPos += 2;
434
}
435
436
printPrefix(pOutFile, NULL, bufferPos, 5);
437
trfprintf(pOutFile, "call\t%s \t\t%s Helper Address = " POINTER_PRINTF_FORMAT,
438
getName(symRef),
439
commentString(),
440
sym->getMethodAddress());
441
bufferPos += 5;
442
443
printPrefix(pOutFile, NULL, bufferPos, 4);
444
trfprintf(pOutFile,
445
"%s \t%s%08x%s",
446
ddString(),
447
hexPrefixString(),
448
bufferPos - snippet->getCheckInstruction()->getBinaryEncoding(),
449
hexSuffixString());
450
}
451
452