Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/x/codegen/J9UnresolvedDataSnippet.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/UnresolvedDataSnippet.hpp"
24
#include "codegen/UnresolvedDataSnippet_inlines.hpp"
25
26
#include <algorithm>
27
#include "codegen/CodeGenerator.hpp"
28
#include "codegen/Instruction.hpp"
29
#include "compile/SymbolReferenceTable.hpp"
30
#include "env/CompilerEnv.hpp"
31
#include "env/IO.hpp"
32
#include "env/TRMemory.hpp"
33
#include "env/jittypes.h"
34
#include "env/VMJ9.h"
35
#include "il/Node.hpp"
36
#include "il/Node_inlines.hpp"
37
#include "il/StaticSymbol.hpp"
38
#include "il/StaticSymbol_inlines.hpp"
39
#include "il/Symbol.hpp"
40
#include "runtime/CodeCacheManager.hpp"
41
#include "runtime/J9Runtime.hpp"
42
#include "x/codegen/X86Instruction.hpp"
43
#include "codegen/InstOpCode.hpp"
44
45
J9::X86::UnresolvedDataSnippet::UnresolvedDataSnippet(
46
TR::CodeGenerator *cg,
47
TR::Node *node,
48
TR::SymbolReference *symRef,
49
bool isStore,
50
bool isGCSafePoint) :
51
J9::UnresolvedDataSnippet(cg, node, symRef, isStore, isGCSafePoint),
52
_numLiveX87Registers(0),
53
_glueSymRef(NULL)
54
{
55
TR_ASSERT(symRef->getSymbol(), "symbol should not be NULL");
56
57
if (symRef->getSymbol()->getDataType()==TR::Float ||
58
symRef->getSymbol()->getDataType()==TR::Double)
59
{
60
setIsFloatData();
61
}
62
}
63
64
65
TR_RuntimeHelper
66
J9::X86::UnresolvedDataSnippet::getHelper()
67
{
68
if (getDataSymbol()->isShadow())
69
return isUnresolvedStore() ? TR_X86interpreterUnresolvedFieldSetterGlue :
70
TR_X86interpreterUnresolvedFieldGlue;
71
72
if (getDataSymbol()->isClassObject())
73
return getDataSymbol()->addressIsCPIndexOfStatic() ? TR_X86interpreterUnresolvedClassFromStaticFieldGlue :
74
TR_X86interpreterUnresolvedClassGlue;
75
76
if (getDataSymbol()->isConstString())
77
return TR_X86interpreterUnresolvedStringGlue;
78
79
if (getDataSymbol()->isConstMethodType())
80
return TR_interpreterUnresolvedMethodTypeGlue;
81
82
if (getDataSymbol()->isConstMethodHandle())
83
return TR_interpreterUnresolvedMethodHandleGlue;
84
85
if (getDataSymbol()->isCallSiteTableEntry())
86
return TR_interpreterUnresolvedCallSiteTableEntryGlue;
87
88
if (getDataSymbol()->isMethodTypeTableEntry())
89
return TR_interpreterUnresolvedMethodTypeTableEntryGlue;
90
91
if (getDataSymbol()->isConstantDynamic())
92
return TR_X86interpreterUnresolvedConstantDynamicGlue;
93
94
// Must be a static data reference
95
96
return isUnresolvedStore() ? TR_X86interpreterUnresolvedStaticFieldSetterGlue :
97
TR_X86interpreterUnresolvedStaticFieldGlue;
98
}
99
100
101
uint8_t *
102
J9::X86::UnresolvedDataSnippet::emitSnippetBody()
103
{
104
uint8_t *cursor = cg()->getBinaryBufferCursor();
105
106
uint8_t *snippetStart = cursor;
107
getSnippetLabel()->setCodeLocation(snippetStart);
108
TR::Instruction *stackMapInstr = getDataReferenceInstruction();
109
110
if (!stackMapInstr)
111
{
112
return TR::InstOpCode(TR::InstOpCode::bad).binary(cursor);
113
}
114
115
_glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(getHelper());
116
117
if (cg()->comp()->target().is64Bit())
118
{
119
cursor = emitResolveHelperCall(cursor);
120
cursor = emitConstantPoolAddress(cursor);
121
cursor = emitConstantPoolIndex(cursor);
122
cursor = emitUnresolvedInstructionDescriptor(cursor);
123
}
124
else
125
{
126
cursor = emitConstantPoolIndex(cursor);
127
cursor = emitConstantPoolAddress(cursor);
128
cursor = emitResolveHelperCall(cursor);
129
cursor = emitUnresolvedInstructionDescriptor(cursor);
130
}
131
132
cursor = fixupDataReferenceInstruction(cursor);
133
134
// If there is a GC map for this snippet, register it at the point that this
135
// snippet is called.
136
//
137
gcMap().registerStackMap(stackMapInstr, cg());
138
139
return cursor;
140
}
141
142
143
144
uint8_t *
145
J9::X86::UnresolvedDataSnippet::emitResolveHelperCall(uint8_t *cursor)
146
{
147
// Get the address for the glue routine (or its trampoline)
148
//
149
intptr_t glueAddress = (intptr_t)_glueSymRef->getMethodAddress();
150
151
cg()->addProjectSpecializedRelocation(cursor+1, (uint8_t *)_glueSymRef, NULL, TR_HelperAddress,
152
__FILE__, __LINE__, getNode());
153
154
// Call to the glue routine
155
//
156
const intptr_t rip = (intptr_t)(cursor+5);
157
if ((cg()->needRelocationsForHelpers() && cg()->comp()->target().is64Bit()) ||
158
NEEDS_TRAMPOLINE(glueAddress, rip, cg()))
159
{
160
TR_ASSERT(cg()->comp()->target().is64Bit(), "should not require a trampoline on 32-bit");
161
glueAddress = TR::CodeCacheManager::instance()->findHelperTrampoline(_glueSymRef->getReferenceNumber(), (void *)cursor);
162
TR_ASSERT(IS_32BIT_RIP(glueAddress, rip), "Local helper trampoline should be reachable directly.\n");
163
}
164
165
*cursor++ = 0xe8; // TR::InstOpCode::CALLImm4
166
167
int32_t offset = (int32_t)((intptr_t)glueAddress - rip);
168
*(int32_t *)cursor = offset;
169
cursor += 4;
170
171
TR_ASSERT((intptr_t)cursor == rip, "assertion failure");
172
173
return cursor;
174
}
175
176
177
uint32_t
178
J9::X86::UnresolvedDataSnippet::getUnresolvedStaticStoreDeltaWithMemBarrier()
179
{
180
// If the this is not a store operation on an unresolved static field, return.
181
//
182
if (getDataSymbol()->isClassObject() || getDataSymbol()->isConstObjectRef())
183
{
184
return 0;
185
}
186
187
// Find the delta between the start of the memory barrier that should be guarding the store to the static field, and the start of the store instruction
188
//
189
TR::Instruction *instIter = getDataReferenceInstruction();
190
uint8_t *dataRefInstOffset = getDataReferenceInstruction()->getBinaryEncoding();
191
192
instIter = instIter->getNext();
193
uint8_t delta = instIter->getBinaryEncoding() - dataRefInstOffset;
194
195
if (cg()->comp()->getOption(TR_X86UseMFENCE))
196
{
197
while ( instIter->getOpCode().getOpCodeValue() != TR::InstOpCode::MFENCE && delta <= 20)
198
{
199
instIter = instIter->getNext();
200
delta = instIter->getBinaryEncoding() - dataRefInstOffset;
201
}
202
203
// Return the appropriate offset flag.
204
//
205
if (delta == 20 && instIter->getOpCode().getOpCodeValue() == TR::InstOpCode::MFENCE)
206
{
207
return cpIndex_extremeStaticMemBarPos;
208
}
209
else if (delta == 16 && instIter->getOpCode().getOpCodeValue() == TR::InstOpCode::MFENCE)
210
{
211
return cpIndex_genStaticMemBarPos;
212
}
213
else
214
{
215
TR_ASSERT(0, "Invalid computed offset between start of store to static field and start of memory barrier: %d. Should be 16 or 20.", delta);
216
return 0;
217
}
218
}
219
else
220
{
221
while ( instIter->getOpCode().getOpCodeValue() != TR::InstOpCode::LOR4MemImms && delta <= 24)
222
{
223
instIter = instIter->getNext();
224
delta = instIter->getBinaryEncoding() - dataRefInstOffset;
225
}
226
227
// Return the appropriate offset flag.
228
//
229
if (delta == 24 && instIter->getOpCode().getOpCodeValue() == TR::InstOpCode::LOR4MemImms)
230
{
231
return cpIndex_extremeStaticMemBarPos;
232
}
233
else if (delta == 16 && instIter->getOpCode().getOpCodeValue() == TR::InstOpCode::LOR4MemImms)
234
{
235
return cpIndex_genStaticMemBarPos;
236
}
237
else
238
{
239
TR_ASSERT(0, "Invalid computed offset between start of store to static field and start of memory barrier: %d. Should be 16 or 24.", delta);
240
return 0;
241
}
242
}
243
}
244
245
246
uint8_t *
247
J9::X86::UnresolvedDataSnippet::emitUnresolvedInstructionDescriptor(uint8_t *cursor)
248
{
249
// On 64-bit a descriptor byte is only required for unresolved fields because
250
// the 4-byte disp32 field
251
//
252
if (cg()->comp()->target().is64Bit() && !getDataSymbol()->isShadow())
253
return cursor;
254
255
// Descriptor
256
// Bits:
257
// 7-4: template instruction length
258
// 3-0: offset of data reference from start of instruction
259
//
260
uint8_t *instructionStart = getDataReferenceInstruction()->getBinaryEncoding();
261
const uint8_t instructionLength = getDataReferenceInstruction()->getBinaryLength();
262
const size_t dataReferenceOffset = getAddressOfDataReference() - instructionStart;
263
264
TR_ASSERT(instructionLength != 0, "getDataReferenceInstruction()->getBinaryLength() should not be zero");
265
266
const int32_t maxLen = 15;
267
TR_ASSERT(instructionLength <= maxLen, "Instruction length (%d) must fit in descriptor", instructionLength);
268
TR_ASSERT(dataReferenceOffset <= maxLen, "Data reference offset (%d) must fit in descriptor", dataReferenceOffset);
269
270
*cursor++ = (uint8_t)((instructionLength << 4) | dataReferenceOffset);
271
272
return cursor;
273
}
274
275
276
uint8_t *
277
J9::X86::UnresolvedDataSnippet::emitConstantPoolAddress(uint8_t *cursor)
278
{
279
TR::Compilation *comp = cg()->comp();
280
if (comp->target().is32Bit())
281
{
282
*cursor++ = 0x68; // push imm4
283
}
284
285
*(intptr_t *)cursor = (intptr_t)getDataSymbolReference()->getOwningMethod(comp)->constantPool();
286
// in MT JRE, it might have no data reference instruction
287
if (getDataReferenceInstruction())
288
{
289
TR::Node *node = getDataReferenceInstruction()->getNode();
290
if (node && ((node->getOpCodeValue() == TR::checkcastAndNULLCHK) || (node->getOpCodeValue() == TR::NULLCHK)))
291
{
292
node = node->getChild(0);
293
}
294
295
cg()->addProjectSpecializedRelocation(cursor,(uint8_t *)getDataSymbolReference()->getOwningMethod(comp)->constantPool(),
296
node ? (uint8_t *)(uintptr_t)node->getInlinedSiteIndex() : (uint8_t *)-1, TR_ConstantPool,
297
__FILE__, __LINE__, node);
298
}
299
300
cursor += TR::Compiler->om.sizeofReferenceAddress();
301
return cursor;
302
}
303
304
305
uint8_t *
306
J9::X86::UnresolvedDataSnippet::emitConstantPoolIndex(uint8_t *cursor)
307
{
308
309
// Anatomy of a cpIndex passed to the runtime:
310
//
311
// byte 3 byte 2 byte 1 byte 0
312
//
313
// 3 222 2 222 1 1 0 0 0
314
// 10987654 32109876 54321098 76543210
315
// ||||__| ||| |_________________|
316
// ||| | ||| |
317
// ||| | ||| +---------------- cpIndex (0-16)
318
// |||| | ||| ||+-------------------------- upper long dword resolution (17)
319
// |||| | ||| |+--------------------------- lower long dword resolution (18)
320
// |||| | ||| +---------------------------- check volatility (19)
321
// |||| | ||+------------------------------ resolve, but do not patch snippet template (21)
322
// |||| | |+------------------------------- resolve, but do not patch mainline code (22)
323
// |||| | +-------------------------------- long push instruction (23)
324
// |||| +------------------------------------ number of live X87 registers across this resolution (24-27)
325
// |||+-------------------------------------- has live XMM registers (28)
326
// ||+--------------------------------------- static resolution (29)
327
// |+---------------------------------------- 64-bit: resolved value is 8 bytes (30)
328
// | 32-bit: resolved value is high word of long pair (30)
329
// +----------------------------------------- 64 bit: extreme static memory barrier position (31)
330
331
TR::Compilation *comp = cg()->comp();
332
TR::Symbol *dataSymbol = getDataSymbolReference()->getSymbol();
333
int32_t cpIndex;
334
if (dataSymbol->isCallSiteTableEntry())
335
{
336
cpIndex = dataSymbol->castToCallSiteTableEntrySymbol()->getCallSiteIndex();
337
}
338
else if (dataSymbol->isMethodTypeTableEntry())
339
{
340
cpIndex = dataSymbol->castToMethodTypeTableEntrySymbol()->getMethodTypeIndex();
341
}
342
else // constant pool index
343
{
344
cpIndex = getDataSymbolReference()->getCPIndex();
345
}
346
347
if (getNumLiveX87Registers() > 0) cpIndex |= (getNumLiveX87Registers() << 24);
348
if (hasLiveXMMRegisters() && comp->target().is32Bit()) cpIndex |= cpIndex_hasLiveXMMRegisters;
349
350
// For unresolved object refs, the snippet need not be patched because its
351
// data is already correct.
352
//
353
if (getDataSymbol()->isConstObjectRef()) cpIndex |= cpIndex_doNotPatchSnippet;
354
355
// Identify static resolution.
356
//
357
if (!getDataSymbol()->isShadow() && !getDataSymbol()->isClassObject() && !getDataSymbol()->isConstObjectRef())
358
{
359
cpIndex |= cpIndex_isStaticResolution;
360
}
361
362
if (resolveMustPatch8Bytes())
363
{
364
TR_ASSERT(comp->target().is64Bit(), "resolveMustPatch8Bytes must only be set on 64-bit");
365
cpIndex |= cpIndex_patch8ByteResolution;
366
}
367
368
if (comp->target().is32Bit())
369
{
370
if (getDataSymbolReference()->getOffset() == 4)
371
{
372
TR_ASSERT(((!getDataSymbol()->isShadow() && !getDataSymbol()->isClassObject() && !getDataSymbol()->isConstObjectRef()) || getDataSymbol()->isShadow()),
373
"unexpected symbol kind for offset 4, instruction=%x\n", getDataReferenceInstruction());
374
375
// On 32-bit, an unresolved reference with a 4-byte offset is the high word
376
// of an unresolved long. The offset will be added at runtime.
377
//
378
cpIndex |= cpIndex_isHighWordOfLongPair;
379
}
380
}
381
382
if (!comp->getOption(TR_DisableNewX86VolatileSupport) && getDataReferenceInstruction() != NULL)
383
{
384
TR::Instruction *dataRefInst = getDataReferenceInstruction();
385
TR::InstOpCode::Mnemonic opCode = dataRefInst->getOpCode().getOpCodeValue();
386
387
// If this is a store operation on an unresolved field, set the volatility check flag.
388
//
389
if (comp->target().isSMP())
390
{
391
if (!getDataSymbol()->isClassObject() && !getDataSymbol()->isConstObjectRef() && isUnresolvedStore() && opCode != TR::InstOpCode::CMPXCHG8BMem && getDataSymbol()->isVolatile())
392
{
393
cpIndex |= cpIndex_checkVolatility;
394
395
if (comp->target().is64Bit() && ((TR::X86MemInstruction *)dataRefInst)->getMemoryReference())
396
{
397
if (((TR::X86MemInstruction *)dataRefInst)->getMemoryReference()->processAsFPVolatile())
398
{
399
cpIndex |= cpIndex_isFloatStore;
400
}
401
}
402
403
if (comp->target().is64Bit() && !getDataSymbol()->isShadow())
404
{
405
//If this is a store into a static field, we need to know the offset between the start of the store instruction and the memory barrier.
406
//
407
cpIndex |= getUnresolvedStaticStoreDeltaWithMemBarrier();
408
}
409
}
410
411
if (comp->target().is32Bit())
412
{
413
// If this is a portion of a long store, flag which half of the long
414
// is being stored
415
//
416
if (dataRefInst->getKind() == TR::Instruction::IsRegMem)
417
{
418
if (((TR::X86RegMemInstruction *)dataRefInst)->getMemoryReference()->processAsLongVolatileLow())
419
{
420
cpIndex |= cpIndex_procAsLongLow | cpIndex_checkVolatility;
421
}
422
else if (((TR::X86RegMemInstruction *)dataRefInst)->getMemoryReference()->processAsLongVolatileHigh())
423
{
424
cpIndex |= cpIndex_procAsLongHigh | cpIndex_checkVolatility;
425
}
426
}
427
}
428
}
429
}
430
431
if (comp->target().is32Bit())
432
{
433
if (cpIndex <= 127 && cpIndex >= -128)
434
{
435
*cursor++ = 0x6a; // push imms
436
*(int8_t *)cursor++ = (int8_t)cpIndex;
437
}
438
else
439
{
440
*cursor++ = 0x68; // push imm4
441
*(int32_t *)cursor = (cpIndex | cpIndex_longPushTag);
442
cursor += 4;
443
}
444
}
445
else
446
{
447
*(int32_t *)cursor = cpIndex;
448
cursor += 4;
449
}
450
return cursor;
451
}
452
453
454
uint8_t *
455
J9::X86::UnresolvedDataSnippet::fixupDataReferenceInstruction(uint8_t *cursor)
456
{
457
uint8_t *instructionStart = getDataReferenceInstruction()->getBinaryEncoding();
458
uint8_t bytesToCopy;
459
TR::Compilation *comp = cg()->comp();
460
461
// Only for unresolved statics whose reference instruction may be executed in place
462
// in the snippet should the entire reference instruction be copied. All other
463
// unresolved references should copy 8 bytes only (this may include bytes from
464
// the following instruction).
465
//
466
if (!getDataSymbol()->isShadow() && !getDataSymbol()->isClassObject() && !getDataSymbol()->isConstObjectRef())
467
{
468
// Unresolved statics may result in the instruction being patched and executed in the snippet
469
// rather than the mainline code. A return instruction is necessary in this case.
470
//
471
uint8_t length = getDataReferenceInstruction()->getBinaryLength();
472
473
bytesToCopy = std::max<uint8_t>(8, length);
474
memcpy(cursor, instructionStart, bytesToCopy);
475
476
// If the TR::InstOpCode::RET will overwrite one of the eight bytes that will eventually be patched
477
// then the byte it overwrites needs to be preserved.
478
//
479
if (length < 8)
480
{
481
uint8_t b = *(cursor+length);
482
*(cursor+length) = 0xc3; // TR::InstOpCode::RET
483
cursor += bytesToCopy;
484
*cursor++ = b;
485
}
486
else
487
{
488
*(cursor+length) = 0xc3; // TR::InstOpCode::RET
489
cursor += (bytesToCopy + 1);
490
}
491
}
492
else
493
{
494
if (comp->target().is64Bit())
495
{
496
// Unresolved instance fields require 4 byte patching at a variable instruction
497
// offset so the 8 bytes following the start of the instruction need to be
498
// cached.
499
//
500
// For unresolved strings and classes only 2 bytes (REX+Op) are necessary.
501
//
502
bytesToCopy = getDataSymbol()->isShadow() ? 8 : 2;
503
}
504
else
505
{
506
if (getDataSymbol()->isConstObjectRef())
507
{
508
bytesToCopy = std::max<uint8_t>(8, getDataReferenceInstruction()->getBinaryLength());
509
}
510
else
511
{
512
bytesToCopy = 8;
513
}
514
}
515
516
memcpy(cursor, instructionStart, bytesToCopy);
517
cursor += bytesToCopy;
518
519
// For object ref constants, the original instruction already loaded a valid constant pool
520
// address and since it was copied to the snippet it needs a relocation here.
521
//
522
// This assumes that the string reference instruction is a MOV Reg, Imm32 (32-bit)
523
// or a MOV Reg, Imm64 (64-bit) instruction.
524
//
525
if (comp->target().is32Bit() && getDataSymbol()->isConstObjectRef())
526
{
527
uint8_t *stringConstantPtr = (cursor - bytesToCopy) + getDataReferenceInstruction()->getBinaryLength() - TR::Compiler->om.sizeofReferenceAddress();
528
529
cg()->addProjectSpecializedRelocation(stringConstantPtr, (uint8_t *)getDataSymbolReference()->getOwningMethod(comp)->constantPool(),
530
getDataReferenceInstruction()->getNode() ? (uint8_t *)(uintptr_t)getDataReferenceInstruction()->getNode()->getInlinedSiteIndex() : (uint8_t *)-1, TR_ConstantPool,
531
__FILE__, __LINE__, getDataReferenceInstruction()->getNode());
532
}
533
}
534
535
// Write a call to this snippet over the original data reference instruction
536
//
537
uint8_t *originalInstruction = getDataReferenceInstruction()->getBinaryEncoding();
538
*originalInstruction = 0xe8; // CallImm32
539
*(int32_t *)(originalInstruction+1) = (int32_t)(cg()->getBinaryBufferCursor() - 5 - originalInstruction);
540
541
return cursor;
542
}
543
544
545
uint32_t
546
J9::X86::UnresolvedDataSnippet::getLength(int32_t estimatedSnippetStart)
547
{
548
uint32_t length;
549
550
length = 5; // TR::InstOpCode::CALLImm4 to resolve helper
551
552
// cpAddr
553
//
554
length += sizeof(intptr_t);
555
556
// cpIndex
557
//
558
// This is a conservative approximation.
559
//
560
length += 4;
561
562
// 32-bit adjustments
563
//
564
if (cg()->comp()->target().is32Bit())
565
{
566
length += (
567
1 // TR::InstOpCode::PUSHImm4 for cpAddr
568
+1 // TR::InstOpCode::PUSHImm4 for cpIndex
569
+1 // descriptor byte
570
);
571
}
572
573
if (!getDataSymbol()->isShadow() && !getDataSymbol()->isClassObject() && !getDataSymbol()->isConstObjectRef())
574
{
575
// Static reference.
576
//
577
uint32_t instructionLength = getDataReferenceInstruction()->getBinaryLength();
578
579
// +1 is for either a TR::InstOpCode::RET instruction if instructionLength > 7 or for a copy of
580
// the byte that the TR::InstOpCode::RET instruction overwrites if instructionLength < 8.
581
//
582
length += std::max<uint32_t>(8, instructionLength) + 1;
583
}
584
else
585
{
586
if (cg()->comp()->target().is32Bit())
587
{
588
if (getDataSymbol()->isConstObjectRef())
589
{
590
uint32_t instructionLength = getDataReferenceInstruction()->getBinaryLength();
591
length += std::max<uint32_t>(8, instructionLength);
592
}
593
else
594
{
595
length += 8;
596
}
597
}
598
else
599
{
600
if (getDataSymbol()->isShadow())
601
{
602
length += (
603
8 // cached instruction bytes
604
+1 // descriptor byte
605
);
606
}
607
else
608
{
609
length += 2; // REX+opcode
610
}
611
}
612
}
613
614
return length;
615
}
616
617
618
void
619
TR_Debug::print(TR::FILE *pOutFile, TR::UnresolvedDataSnippet * snippet)
620
{
621
if (pOutFile == NULL)
622
return;
623
624
uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();
625
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet));
626
trfprintf(pOutFile, " for instr [%s]", getName(snippet->getDataReferenceInstruction()));
627
628
if (_comp->target().is64Bit())
629
{
630
printPrefix(pOutFile, NULL, bufferPos, 5);
631
632
TR_RuntimeHelper helperIndex = snippet->getHelper();
633
TR::SymbolReference *glueSymRef = _cg->getSymRef(helperIndex);
634
trfprintf(pOutFile, "call\t%s", getName(glueSymRef));
635
bufferPos += 5;
636
637
printPrefix(pOutFile, NULL, bufferPos, 8);
638
trfprintf(pOutFile,
639
"%s\t" POINTER_PRINTF_FORMAT "\t%s address of constant pool for this method",
640
dqString(),
641
getOwningMethod(snippet->getDataSymbolReference())->constantPool(),
642
commentString());
643
bufferPos += 8;
644
645
printPrefix(pOutFile, NULL, bufferPos, 4);
646
trfprintf(pOutFile,
647
"%s\t0x%08x\t\t\t\t%s constant pool index",
648
ddString(),
649
snippet->getDataSymbolReference()->getCPIndex(),
650
commentString());
651
bufferPos += 4;
652
653
if (snippet->getDataSymbol()->isShadow())
654
{
655
printPrefix(pOutFile, NULL, bufferPos, 1);
656
657
uint8_t descriptor = *bufferPos;
658
uint8_t length = (descriptor >> 4) & 0xf;
659
uint8_t offset = (descriptor & 0xf);
660
661
trfprintf(
662
pOutFile,
663
"%s\t%02x\t\t\t\t\t\t\t%s instruction descriptor: length=%d, disp32 offset=%d",
664
dbString(),
665
descriptor,
666
commentString(),
667
length,
668
offset
669
);
670
671
bufferPos++;
672
}
673
674
}
675
else
676
{
677
if (!snippet->getDataReferenceInstruction())
678
{
679
// when do not patch mainline flag on, there is no data reference instruction copy in snippet
680
printPrefix(pOutFile, NULL, bufferPos, 1);
681
trfprintf(pOutFile, "int \t3\t\t\t%s (No data reference instruction; NEVER CALLED)",
682
commentString());
683
return;
684
}
685
686
// 0x68 == PUSHImm32
687
//
688
int32_t size = (*bufferPos == 0x68) ? 5 : 2;
689
printPrefix(pOutFile, NULL, bufferPos, size);
690
trfprintf(
691
pOutFile,
692
"push\t" POINTER_PRINTF_FORMAT "\t\t%s constant pool index",
693
snippet->getDataSymbolReference()->getCPIndex(),
694
commentString());
695
bufferPos += size;
696
697
printPrefix(pOutFile, NULL, bufferPos, 5);
698
trfprintf(
699
pOutFile,
700
"push\t" POINTER_PRINTF_FORMAT "\t\t%s address of constant pool for this method",
701
getOwningMethod(snippet->getDataSymbolReference())->constantPool(),
702
commentString());
703
bufferPos += 5;
704
705
printPrefix(pOutFile, NULL, bufferPos, 5);
706
TR::SymbolReference *glueSymRef = _cg->getSymRef(snippet->getHelper());
707
trfprintf(pOutFile, "call\t%s", getName(glueSymRef));
708
bufferPos += 5;
709
}
710
711
if (!snippet->getDataSymbol()->isShadow() &&
712
!snippet->getDataSymbol()->isClassObject() &&
713
!snippet->getDataSymbol()->isConstObjectRef() &&
714
!snippet->getDataSymbol()->isMethodTypeTableEntry())
715
{
716
int32_t length = snippet->getDataReferenceInstruction()->getBinaryLength();
717
int32_t bytesToCopy = std::max<int32_t>(8, length);
718
719
if (length < 8)
720
{
721
printPrefix(pOutFile, NULL, bufferPos, bytesToCopy);
722
bufferPos += bytesToCopy;
723
trfprintf(pOutFile, "%s\t(%d)\t\t\t%s patch instruction bytes + TR::InstOpCode::RET + residue",
724
dbString(),
725
bytesToCopy,
726
commentString());
727
printPrefix(pOutFile, NULL, bufferPos, 1);
728
trfprintf(pOutFile, "%s\t\t\t\t\t\t%s byte that TR::InstOpCode::RET overwrote",
729
dbString(),
730
commentString());
731
bufferPos ++;
732
}
733
else
734
{
735
printPrefix(pOutFile, NULL, bufferPos, bytesToCopy+1);
736
bufferPos += (bytesToCopy + 1);
737
trfprintf(pOutFile, "%s\t(%d)\t\t\t\t%s patch instruction bytes + TR::InstOpCode::RET",
738
dbString(),
739
(bytesToCopy+1),
740
commentString());
741
}
742
}
743
else
744
{
745
int32_t bytesToCopy;
746
747
if (_comp->target().is64Bit())
748
{
749
if (snippet->getDataSymbol()->isShadow())
750
{
751
bytesToCopy = 8;
752
printPrefix(pOutFile, NULL, bufferPos, bytesToCopy);
753
bufferPos += bytesToCopy;
754
trfprintf(pOutFile, "%s\t(%d)\t\t\t\t\t\t%s patch instruction bytes",
755
dbString(),
756
bytesToCopy,
757
commentString());
758
}
759
else
760
{
761
bytesToCopy = 2;
762
printPrefix(pOutFile, NULL, bufferPos, bytesToCopy);
763
bufferPos += bytesToCopy;
764
trfprintf(pOutFile, "%s\t\t\t\t\t\t\t\t%s REX + op of TR::InstOpCode::MOV8RegImm64",
765
dwString(),
766
commentString());
767
}
768
}
769
else
770
{
771
if (snippet->getDataSymbol()->isConstString())
772
{
773
// TODO:JSR292: isConstMethodType
774
// TODO:JSR292: isConstMethodHandle
775
bytesToCopy = std::max<int32_t>(8, snippet->getDataReferenceInstruction()->getBinaryLength());
776
printPrefix(pOutFile, NULL, bufferPos, bytesToCopy);
777
bufferPos += bytesToCopy;
778
trfprintf(pOutFile, "%s\t(%d)\t\t\t\t\t\t%s patched string instruction bytes",
779
dbString(),
780
bytesToCopy,
781
commentString());
782
}
783
else
784
{
785
bytesToCopy = 8;
786
printPrefix(pOutFile, NULL, bufferPos, bytesToCopy);
787
bufferPos += bytesToCopy;
788
trfprintf(pOutFile, "%s\t(%d)\t\t\t\t\t\t%s patch instruction bytes",
789
dbString(),
790
bytesToCopy,
791
commentString());
792
}
793
}
794
}
795
}
796
797