Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/x/i386/codegen/IA32PrivateLinkage.cpp
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2022 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/IA32PrivateLinkage.hpp"
24
25
#include "codegen/CodeGenerator.hpp"
26
#include "codegen/Linkage_inlines.hpp"
27
#include "codegen/LiveRegister.hpp"
28
#include "codegen/Machine.hpp"
29
#include "codegen/MemoryReference.hpp"
30
#include "codegen/RealRegister.hpp"
31
#include "codegen/Register.hpp"
32
#include "codegen/RegisterPair.hpp"
33
#include "codegen/Snippet.hpp"
34
#include "compile/Method.hpp"
35
#include "compile/ResolvedMethod.hpp"
36
#include "control/Recompilation.hpp"
37
#include "control/RecompilationInfo.hpp"
38
#include "env/CHTable.hpp"
39
#include "env/jittypes.h"
40
#include "env/CompilerEnv.hpp"
41
#include "il/Node.hpp"
42
#include "il/Node_inlines.hpp"
43
#include "env/VMJ9.h"
44
#include "x/codegen/CallSnippet.hpp"
45
#include "x/codegen/CheckFailureSnippet.hpp"
46
#include "x/codegen/FPTreeEvaluator.hpp"
47
#include "x/codegen/HelperCallSnippet.hpp"
48
#include "x/codegen/IA32LinkageUtils.hpp"
49
#include "x/codegen/X86Instruction.hpp"
50
51
J9::X86::I386::PrivateLinkage::PrivateLinkage(TR::CodeGenerator *cg)
52
: J9::X86::PrivateLinkage(cg)
53
{
54
_properties._properties = 0;
55
_properties._registerFlags[TR::RealRegister::NoReg] = 0;
56
_properties._registerFlags[TR::RealRegister::eax] = IntegerReturn;
57
_properties._registerFlags[TR::RealRegister::ebx] = Preserved;
58
_properties._registerFlags[TR::RealRegister::ecx] = Preserved;
59
_properties._registerFlags[TR::RealRegister::edx] = IntegerReturn;
60
_properties._registerFlags[TR::RealRegister::edi] = 0;
61
_properties._registerFlags[TR::RealRegister::esi] = Preserved;
62
_properties._registerFlags[TR::RealRegister::ebp] = Preserved;
63
_properties._registerFlags[TR::RealRegister::esp] = Preserved;
64
65
for (int i = 0; i <= 7; i++)
66
{
67
_properties._registerFlags[TR::RealRegister::xmmIndex(i)] = 0;
68
}
69
70
_properties._registerFlags[TR::RealRegister::xmm0] = FloatReturn;
71
72
_properties._preservedRegisters[0] = TR::RealRegister::ebx;
73
_properties._preservedRegisters[1] = TR::RealRegister::ecx;
74
_properties._preservedRegisters[2] = TR::RealRegister::esi;
75
_properties._maxRegistersPreservedInPrologue = 3;
76
_properties._preservedRegisters[3] = TR::RealRegister::ebp;
77
_properties._preservedRegisters[4] = TR::RealRegister::esp;
78
_properties._numPreservedRegisters = 5;
79
80
_properties._argumentRegisters[0] = TR::RealRegister::NoReg;
81
82
_properties._numIntegerArgumentRegisters = 0;
83
_properties._firstIntegerArgumentRegister = 0;
84
_properties._numFloatArgumentRegisters = 0;
85
_properties._firstFloatArgumentRegister = 0;
86
87
_properties._returnRegisters[0] = TR::RealRegister::eax;
88
_properties._returnRegisters[1] = TR::RealRegister::xmm0;
89
_properties._returnRegisters[2] = TR::RealRegister::edx;
90
91
_properties._scratchRegisters[0] = TR::RealRegister::edi;
92
_properties._scratchRegisters[1] = TR::RealRegister::edx;
93
_properties._numScratchRegisters = 2;
94
95
_properties._preservedRegisterMapForGC = // TODO:AMD64: Use the proper mask value
96
( (1 << (TR::RealRegister::ebx-1)) | // Preserved register map for GC
97
(1 << (TR::RealRegister::ecx-1)) |
98
(1 << (TR::RealRegister::esi-1)) |
99
(1 << (TR::RealRegister::ebp-1)) |
100
(1 << (TR::RealRegister::esp-1))),
101
102
_properties._vtableIndexArgumentRegister = TR::RealRegister::edx;
103
_properties._j9methodArgumentRegister = TR::RealRegister::edi;
104
_properties._framePointerRegister = TR::RealRegister::ebx;
105
_properties._methodMetaDataRegister = TR::RealRegister::ebp;
106
107
_properties._numberOfVolatileGPRegisters = 3;
108
_properties._numberOfVolatileXMMRegisters = 8; // xmm0-xmm7
109
setOffsetToFirstParm(4);
110
_properties._offsetToFirstLocal = 0;
111
112
113
// 173135: If we are too eager picking the byte regs, we won't have any
114
// available for byte operations in the code, and we'll need register
115
// shuffles. Normally, shuffles are no big deal, but if they occur right
116
// before byte operations, we can end up with partial register stalls which
117
// are as bad as spills.
118
//
119
// Most byte operations in Java come from byte array element operations.
120
// Array indexing expressions practically never need byte registers, so
121
// while favouring non-byte regs for GRA could hurt byte candidates from
122
// array elements, it should practically never hurt indexing expressions.
123
// We expect array indexing expressions to need global regs far more often
124
// than array elements, so favouring non-byte registers makes sense, all
125
// else being equal.
126
//
127
// Ideally, pickRegister would detect the use of byte expressions and do
128
// the right thing.
129
130
// volatiles, non-byte-reg first
131
_properties._allocationOrder[0] = TR::RealRegister::edi;
132
_properties._allocationOrder[1] = TR::RealRegister::edx;
133
_properties._allocationOrder[2] = TR::RealRegister::eax;
134
// preserved, non-byte-reg first
135
_properties._allocationOrder[3] = TR::RealRegister::esi;
136
_properties._allocationOrder[4] = TR::RealRegister::ebx;
137
_properties._allocationOrder[5] = TR::RealRegister::ecx;
138
_properties._allocationOrder[6] = TR::RealRegister::ebp;
139
// floating point
140
_properties._allocationOrder[7] = TR::RealRegister::st0;
141
_properties._allocationOrder[8] = TR::RealRegister::st1;
142
_properties._allocationOrder[9] = TR::RealRegister::st2;
143
_properties._allocationOrder[10] = TR::RealRegister::st3;
144
_properties._allocationOrder[11] = TR::RealRegister::st4;
145
_properties._allocationOrder[12] = TR::RealRegister::st5;
146
_properties._allocationOrder[13] = TR::RealRegister::st6;
147
_properties._allocationOrder[14] = TR::RealRegister::st7;
148
}
149
150
TR::Instruction *J9::X86::I386::PrivateLinkage::savePreservedRegisters(TR::Instruction *cursor)
151
{
152
TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();
153
const int32_t localSize = _properties.getOffsetToFirstLocal() - bodySymbol->getLocalMappingCursor();
154
const int32_t pointerSize = _properties.getPointerSize();
155
156
int32_t offsetCursor = -localSize - _properties.getPointerSize();
157
int32_t numPreserved = getProperties().getMaxRegistersPreservedInPrologue();
158
159
for (int32_t pindex = numPreserved-1;
160
pindex >= 0;
161
pindex--)
162
{
163
TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex);
164
TR::RealRegister *reg = machine()->getRealRegister(idx);
165
if (reg->getHasBeenAssignedInMethod() && reg->getState() != TR::RealRegister::Locked)
166
{
167
cursor = generateMemRegInstruction(
168
cursor,
169
TR::InstOpCode::S4MemReg,
170
generateX86MemoryReference(machine()->getRealRegister(TR::RealRegister::vfp), offsetCursor, cg()),
171
reg,
172
cg()
173
);
174
offsetCursor -= pointerSize;
175
}
176
}
177
return cursor;
178
}
179
180
TR::Instruction *J9::X86::I386::PrivateLinkage::restorePreservedRegisters(TR::Instruction *cursor)
181
{
182
TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();
183
const int32_t localSize = _properties.getOffsetToFirstLocal() - bodySymbol->getLocalMappingCursor();
184
const int32_t pointerSize = _properties.getPointerSize();
185
186
int32_t offsetCursor = -localSize - _properties.getPointerSize();
187
int32_t numPreserved = getProperties().getMaxRegistersPreservedInPrologue();
188
for (int32_t pindex = numPreserved-1;
189
pindex >= 0;
190
pindex--)
191
{
192
TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex);
193
TR::RealRegister *reg = machine()->getRealRegister(idx);
194
if (reg->getHasBeenAssignedInMethod())
195
{
196
cursor = generateRegMemInstruction(
197
cursor,
198
TR::InstOpCode::L4RegMem,
199
reg,
200
generateX86MemoryReference(machine()->getRealRegister(TR::RealRegister::vfp), offsetCursor, cg()),
201
cg()
202
);
203
offsetCursor -= pointerSize;
204
}
205
}
206
return cursor;
207
}
208
209
210
int32_t J9::X86::I386::PrivateLinkage::buildArgs(
211
TR::Node *callNode,
212
TR::RegisterDependencyConditions *dependencies)
213
{
214
int32_t argSize = 0;
215
TR::Register *eaxRegister = NULL;
216
TR::Node *thisChild = NULL;
217
int32_t firstArgumentChild = callNode->getFirstArgumentIndex();
218
int32_t linkageRegChildIndex = -1;
219
220
int32_t receiverChildIndex = -1;
221
if (callNode->getSymbol()->castToMethodSymbol()->firstArgumentIsReceiver() && callNode->getOpCode().isIndirect())
222
receiverChildIndex = firstArgumentChild;
223
224
if (!callNode->getSymbolReference()->isUnresolved())
225
switch(callNode->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod())
226
{
227
case TR::java_lang_invoke_ComputedCalls_dispatchJ9Method:
228
case TR::java_lang_invoke_ComputedCalls_dispatchVirtual:
229
case TR::com_ibm_jit_JITHelpers_dispatchVirtual:
230
linkageRegChildIndex = firstArgumentChild;
231
receiverChildIndex = callNode->getOpCode().isIndirect()? firstArgumentChild+1 : -1;
232
}
233
234
for (int i = firstArgumentChild; i < callNode->getNumChildren(); i++)
235
{
236
TR::Node *child = callNode->getChild(i);
237
switch (child->getDataType())
238
{
239
case TR::Int8:
240
case TR::Int16:
241
case TR::Int32:
242
case TR::Address:
243
if (i == receiverChildIndex)
244
{
245
eaxRegister = pushThis(child);
246
thisChild = child;
247
}
248
else
249
{
250
pushIntegerWordArg(child);
251
}
252
argSize += 4;
253
break;
254
case TR::Int64:
255
{
256
TR::Register *reg = NULL;
257
if (i == linkageRegChildIndex)
258
{
259
// TODO:JSR292: This should really be in the front-end
260
TR::MethodSymbol *sym = callNode->getSymbol()->castToMethodSymbol();
261
switch (sym->getMandatoryRecognizedMethod())
262
{
263
case TR::java_lang_invoke_ComputedCalls_dispatchJ9Method:
264
reg = cg()->evaluate(child);
265
if (reg->getRegisterPair())
266
reg = reg->getRegisterPair()->getLowOrder();
267
dependencies->addPreCondition(reg, getProperties().getJ9MethodArgumentRegister(), cg());
268
cg()->decReferenceCount(child);
269
break;
270
case TR::java_lang_invoke_ComputedCalls_dispatchVirtual:
271
case TR::com_ibm_jit_JITHelpers_dispatchVirtual:
272
reg = cg()->evaluate(child);
273
if (reg->getRegisterPair())
274
reg = reg->getRegisterPair()->getLowOrder();
275
dependencies->addPreCondition(reg, getProperties().getVTableIndexArgumentRegister(), cg());
276
cg()->decReferenceCount(child);
277
break;
278
}
279
}
280
if (!reg)
281
{
282
TR::IA32LinkageUtils::pushLongArg(child, cg());
283
argSize += 8;
284
}
285
break;
286
}
287
case TR::Float:
288
TR::IA32LinkageUtils::pushFloatArg(child, cg());
289
argSize += 4;
290
break;
291
case TR::Double:
292
TR::IA32LinkageUtils::pushDoubleArg(child, cg());
293
argSize += 8;
294
break;
295
}
296
}
297
298
if (thisChild)
299
{
300
TR::Register *rcvrReg = cg()->evaluate(thisChild);
301
302
if (thisChild->getReferenceCount() > 1)
303
{
304
eaxRegister = cg()->allocateCollectedReferenceRegister();
305
generateRegRegInstruction(TR::InstOpCode::MOV4RegReg, thisChild, eaxRegister, rcvrReg, cg());
306
}
307
else
308
{
309
eaxRegister = rcvrReg;
310
}
311
312
dependencies->addPreCondition(eaxRegister, TR::RealRegister::eax, cg());
313
cg()->stopUsingRegister(eaxRegister);
314
cg()->decReferenceCount(thisChild);
315
}
316
317
return argSize;
318
319
}
320
321
322
TR::UnresolvedDataSnippet *J9::X86::I386::PrivateLinkage::generateX86UnresolvedDataSnippetWithCPIndex(
323
TR::Node *child,
324
TR::SymbolReference *symRef,
325
int32_t cpIndex)
326
{
327
// We know the symbol must have already been resolved, so no GC can
328
// happen (unless the gcOnResolve option is being used).
329
//
330
TR::UnresolvedDataSnippet *snippet = TR::UnresolvedDataSnippet::create(cg(), child, symRef, false, (debug("gcOnResolve") != NULL));
331
cg()->addSnippet(snippet);
332
333
TR::Instruction *dataReferenceInstruction = generateImmSnippetInstruction(TR::InstOpCode::PUSHImm4, child, cpIndex, snippet, cg());
334
snippet->setDataReferenceInstruction(dataReferenceInstruction);
335
generateBoundaryAvoidanceInstruction(TR::X86BoundaryAvoidanceInstruction::unresolvedAtomicRegions, 8, 8, dataReferenceInstruction, cg());
336
337
return snippet;
338
}
339
340
TR::Register *J9::X86::I386::PrivateLinkage::pushIntegerWordArg(TR::Node *child)
341
{
342
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
343
if (child->getRegister() == NULL)
344
{
345
if (child->getOpCode().isLoadConst())
346
{
347
int32_t value = child->getInt();
348
TR::InstOpCode::Mnemonic pushOp;
349
if (value >= -128 && value <= 127)
350
{
351
pushOp = TR::InstOpCode::PUSHImms;
352
}
353
else
354
{
355
pushOp = TR::InstOpCode::PUSHImm4;
356
}
357
358
if (child->getOpCodeValue() == TR::aconst && child->isMethodPointerConstant() &&
359
cg()->needClassAndMethodPointerRelocations())
360
{
361
generateImmInstruction(pushOp, child, value, cg(), TR_MethodPointer);
362
}
363
else
364
{
365
generateImmInstruction(pushOp, child, value, cg());
366
}
367
cg()->decReferenceCount(child);
368
return NULL;
369
}
370
else if (child->getOpCodeValue() == TR::loadaddr)
371
{
372
// Special casing for instanceof under an if relies on this push of unresolved being
373
// implemented as a push imm, so don't change unless that code is changed to match.
374
//
375
TR::SymbolReference * symRef = child->getSymbolReference();
376
TR::StaticSymbol *sym = symRef->getSymbol()->getStaticSymbol();
377
if (sym)
378
{
379
if (symRef->isUnresolved())
380
{
381
generateX86UnresolvedDataSnippetWithCPIndex(child, symRef, 0);
382
}
383
else
384
{
385
// Must pass symbol reference so that aot can put out a relocation for it
386
//
387
TR::Instruction *instr = generateImmSymInstruction(TR::InstOpCode::PUSHImm4, child, (uintptr_t)sym->getStaticAddress(), symRef, cg());
388
389
// HCR register the class passed as a parameter
390
//
391
if ((sym->isClassObject() || sym->isAddressOfClassObject())
392
&& cg()->wantToPatchClassPointer((TR_OpaqueClassBlock*)sym->getStaticAddress(), child))
393
{
394
comp()->getStaticHCRPICSites()->push_front(instr);
395
}
396
}
397
398
cg()->decReferenceCount(child);
399
return NULL;
400
}
401
}
402
}
403
404
return TR::IA32LinkageUtils::pushIntegerWordArg(child, cg());
405
}
406
407
TR::Register *J9::X86::I386::PrivateLinkage::pushThis(TR::Node *child)
408
{
409
// Don't decrement the reference count on the "this" child until we've
410
// had a chance to set up its dependency conditions
411
//
412
TR::Register *tempRegister = cg()->evaluate(child);
413
generateRegInstruction(TR::InstOpCode::PUSHReg, child, tempRegister, cg());
414
return tempRegister;
415
}
416
417
418
static TR_AtomicRegion X86PicSlotAtomicRegion[] =
419
{
420
{ 0x0, 8 }, // Maximum instruction size that can be patched atomically.
421
{ 0,0 }
422
};
423
424
static TR_AtomicRegion X86PicCallAtomicRegion[] =
425
{
426
{ 1, 4 }, // disp32 of a CALL instruction
427
{ 0,0 }
428
};
429
430
431
TR::Instruction *J9::X86::I386::PrivateLinkage::buildPICSlot(
432
TR::X86PICSlot picSlot,
433
TR::LabelSymbol *mismatchLabel,
434
TR::LabelSymbol *doneLabel,
435
TR::X86CallSite &site)
436
{
437
TR::Node *node = site.getCallNode();
438
TR::Register *vftReg = site.evaluateVFT();
439
uintptr_t addrToBeCompared = picSlot.getClassAddress();
440
TR::Instruction *firstInstruction;
441
if (picSlot.getMethodAddress())
442
{
443
addrToBeCompared = (uintptr_t) picSlot.getMethodAddress();
444
firstInstruction = generateMemImmInstruction(TR::InstOpCode::CMPMemImm4(false), node,
445
generateX86MemoryReference(vftReg, picSlot.getSlot(), cg()), (uint32_t) addrToBeCompared, cg());
446
}
447
else
448
firstInstruction = generateRegImmInstruction(TR::InstOpCode::CMP4RegImm4, node, vftReg, addrToBeCompared, cg());
449
450
firstInstruction->setNeedsGCMap(site.getPreservedRegisterMask());
451
452
if (!site.getFirstPICSlotInstruction())
453
site.setFirstPICSlotInstruction(firstInstruction);
454
455
if (picSlot.needsPicSlotAlignment())
456
{
457
generateBoundaryAvoidanceInstruction(
458
X86PicSlotAtomicRegion,
459
8,
460
8,
461
firstInstruction,
462
cg());
463
}
464
465
if (picSlot.needsJumpOnNotEqual())
466
{
467
if (picSlot.needsLongConditionalBranch())
468
{
469
generateLongLabelInstruction(TR::InstOpCode::JNE4, node, mismatchLabel, cg());
470
}
471
else
472
{
473
TR::InstOpCode::Mnemonic op = picSlot.needsShortConditionalBranch() ? TR::InstOpCode::JNE1 : TR::InstOpCode::JNE4;
474
generateLabelInstruction(op, node, mismatchLabel, cg());
475
}
476
}
477
else if (picSlot.needsJumpOnEqual())
478
{
479
if (picSlot.needsLongConditionalBranch())
480
{
481
generateLongLabelInstruction(TR::InstOpCode::JE4, node, mismatchLabel, cg());
482
}
483
else
484
{
485
TR::InstOpCode::Mnemonic op = picSlot.needsShortConditionalBranch() ? TR::InstOpCode::JE1 : TR::InstOpCode::JE4;
486
generateLabelInstruction(op, node, mismatchLabel, cg());
487
}
488
}
489
else if (picSlot.needsNopAndJump())
490
{
491
generatePaddingInstruction(1, node, cg())->setNeedsGCMap((site.getArgSize()<<14) | site.getPreservedRegisterMask());
492
generateLongLabelInstruction(TR::InstOpCode::JMP4, node, mismatchLabel, cg());
493
}
494
495
TR::Instruction *instr;
496
if (picSlot.getMethod())
497
{
498
instr = generateImmInstruction(TR::InstOpCode::CALLImm4, node, (uint32_t)(uintptr_t)picSlot.getMethod()->startAddressForJittedMethod(), cg());
499
}
500
else if (picSlot.getHelperMethodSymbolRef())
501
{
502
TR::MethodSymbol *helperMethod = picSlot.getHelperMethodSymbolRef()->getSymbol()->castToMethodSymbol();
503
instr = generateImmSymInstruction(TR::InstOpCode::CALLImm4, node, (uint32_t)(uintptr_t)helperMethod->getMethodAddress(), picSlot.getHelperMethodSymbolRef(), cg());
504
}
505
else
506
{
507
instr = generateImmInstruction(TR::InstOpCode::CALLImm4, node, 0, cg());
508
}
509
510
instr->setNeedsGCMap(site.getPreservedRegisterMask());
511
512
if (picSlot.needsPicCallAlignment())
513
{
514
generateBoundaryAvoidanceInstruction(
515
X86PicCallAtomicRegion,
516
8,
517
8,
518
instr,
519
cg());
520
}
521
522
// Put a GC map on this label, since the instruction after it may provide
523
// the return address in this stack frame while PicBuilder is active
524
//
525
// TODO: Can we get rid of some of these? Maybe they don't cost anything.
526
//
527
if (picSlot.needsJumpToDone())
528
{
529
instr = generateLabelInstruction(TR::InstOpCode::JMP4, node, doneLabel, cg());
530
instr->setNeedsGCMap(site.getPreservedRegisterMask());
531
}
532
533
if (picSlot.generateNextSlotLabelInstruction())
534
{
535
generateLabelInstruction(TR::InstOpCode::label, node, mismatchLabel, cg());
536
}
537
538
return firstInstruction;
539
}
540
541
static TR_AtomicRegion ia32VPicAtomicRegions[] =
542
{
543
{ 0x02, 4 }, // Class test immediate 1
544
{ 0x09, 4 }, // Call displacement 1
545
{ 0x17, 2 }, // VPICInit call instruction patched via self-loop
546
{ 0,0 } // (null terminator)
547
};
548
549
static TR_AtomicRegion ia32VPicAtomicRegionsRT[] =
550
{
551
{ 0x02, 4 }, // Class test immediate 1
552
{ 0x06, 2 }, // nop+jmp opcodes
553
{ 0x08, 4 }, // Jne displacement 1
554
{ 0x0d, 2 }, // first two bytes of call instruction are atomically patched by virtualJitToInterpreted
555
{ 0,0 } // (null terminator)
556
};
557
558
static TR_AtomicRegion ia32IPicAtomicRegions[] =
559
{
560
{ 0x02, 4 }, // Class test immediate 1
561
{ 0x09, 4 }, // Call displacement 1
562
{ 0x11, 4 }, // Class test immediate 2
563
{ 0x18, 4 }, // Call displacement 2
564
{ 0x27, 4 }, // IPICInit call displacement
565
{ 0,0 } // (null terminator)
566
};
567
568
static TR_AtomicRegion ia32IPicAtomicRegionsRT[] =
569
{
570
{ 0x02, 4 }, // Class test immediate 1
571
{ 0x09, 4 }, // Call displacement 1
572
{ 0x11, 4 }, // Class test immediate 2
573
{ 0x18, 4 }, // Call displacement 2
574
{ 0x2f, 4 }, // IPICInit call displacement
575
{ 0,0 } // (null terminator)
576
};
577
578
void J9::X86::I386::PrivateLinkage::buildIPIC(
579
TR::X86CallSite &site,
580
TR::LabelSymbol *entryLabel,
581
TR::LabelSymbol *doneLabel,
582
uint8_t *thunk)
583
{
584
TR_ASSERT(doneLabel, "a doneLabel is required for IPIC dispatches");
585
586
if (entryLabel)
587
generateLabelInstruction(TR::InstOpCode::label, site.getCallNode(), entryLabel, cg());
588
589
TR::Instruction *startOfPicInstruction = cg()->getAppendInstruction();
590
591
int32_t numIPicSlots = IPicParameters.defaultNumberOfSlots;
592
593
TR::SymbolReference *callHelperSymRef =
594
cg()->symRefTab()->findOrCreateRuntimeHelper(TR_X86populateIPicSlotCall, true, true, false);
595
596
static char *interfaceDispatchUsingLastITableStr = feGetEnv("TR_interfaceDispatchUsingLastITable");
597
static char *numIPicSlotsStr = feGetEnv("TR_numIPicSlots");
598
static char *numIPicSlotsBeforeLastITable = feGetEnv("TR_numIPicSlotsBeforeLastITable");
599
static char *breakBeforeIPICUsingLastITable = feGetEnv("TR_breakBeforeIPICUsingLastITable");
600
601
if (numIPicSlotsStr)
602
numIPicSlots = atoi(numIPicSlotsStr);
603
604
bool useLastITableCache = site.useLastITableCache() || interfaceDispatchUsingLastITableStr;
605
606
if (useLastITableCache)
607
{
608
if (breakBeforeIPICUsingLastITable)
609
generateInstruction(TR::InstOpCode::INT3, site.getCallNode(), cg());
610
if (numIPicSlotsBeforeLastITable)
611
numIPicSlots = atoi(numIPicSlotsBeforeLastITable);
612
}
613
614
if (numIPicSlots > 1)
615
{
616
TR::X86PICSlot emptyPicSlot = TR::X86PICSlot(-1, NULL);
617
emptyPicSlot.setNeedsShortConditionalBranch();
618
emptyPicSlot.setJumpOnNotEqual();
619
emptyPicSlot.setNeedsPicSlotAlignment();
620
emptyPicSlot.setNeedsPicCallAlignment();
621
emptyPicSlot.setHelperMethodSymbolRef(callHelperSymRef);
622
emptyPicSlot.setGenerateNextSlotLabelInstruction();
623
624
// Generate all slots except the last
625
// (short branch to next slot, jump to doneLabel)
626
//
627
for (int32_t i = 1; i < numIPicSlots; i++)
628
{
629
TR::LabelSymbol *nextSlotLabel = generateLabelSymbol(cg());
630
buildPICSlot(emptyPicSlot, nextSlotLabel, doneLabel, site);
631
}
632
}
633
634
// Generate the last slot
635
// (long branch to lookup snippet, fall through to doneLabel)
636
//
637
TR::X86PICSlot lastPicSlot = TR::X86PICSlot(-1, NULL, false);
638
lastPicSlot.setJumpOnNotEqual();
639
lastPicSlot.setNeedsPicSlotAlignment();
640
lastPicSlot.setHelperMethodSymbolRef(callHelperSymRef);
641
642
TR::LabelSymbol *lookupDispatchSnippetLabel = generateLabelSymbol(cg());
643
644
TR::Instruction *slotPatchInstruction = NULL;
645
646
TR::Method *method = site.getMethodSymbol()->getMethod();
647
TR_OpaqueClassBlock *declaringClass = NULL;
648
uintptr_t itableIndex;
649
if ( useLastITableCache
650
&& (declaringClass = site.getSymbolReference()->getOwningMethod(comp())->getResolvedInterfaceMethod(site.getSymbolReference()->getCPIndex(), &itableIndex))
651
&& performTransformation(comp(), "O^O useLastITableCache for n%dn itableIndex=%d: %.*s.%.*s%.*s\n",
652
site.getCallNode()->getGlobalIndex(), (int)itableIndex,
653
method->classNameLength(), method->classNameChars(),
654
method->nameLength(), method->nameChars(),
655
method->signatureLength(), method->signatureChars()))
656
{
657
buildInterfaceDispatchUsingLastITable (site, numIPicSlots, lastPicSlot, slotPatchInstruction, doneLabel, lookupDispatchSnippetLabel, declaringClass, itableIndex);
658
}
659
else
660
{
661
// Last PIC slot is long branch to lookup snippet, fall through to doneLabel
662
lastPicSlot.setNeedsPicCallAlignment();
663
lastPicSlot.setNeedsLongConditionalBranch();
664
slotPatchInstruction = buildPICSlot(lastPicSlot, lookupDispatchSnippetLabel, NULL, site);
665
}
666
667
// Skip past any boundary avoidance padding to get to the real first instruction
668
// of the PIC.
669
//
670
startOfPicInstruction = startOfPicInstruction->getNext();
671
while (startOfPicInstruction->getOpCodeValue() == TR::InstOpCode::bad)
672
{
673
startOfPicInstruction = startOfPicInstruction->getNext();
674
}
675
676
TR::X86PicDataSnippet *snippet = new (trHeapMemory()) TR::X86PicDataSnippet(
677
IPicParameters.defaultNumberOfSlots,
678
startOfPicInstruction,
679
lookupDispatchSnippetLabel,
680
doneLabel,
681
site.getSymbolReference(),
682
slotPatchInstruction,
683
site.getThunkAddress(),
684
true,
685
cg());
686
687
snippet->gcMap().setGCRegisterMask((site.getArgSize()<<14) | site.getPreservedRegisterMask());
688
cg()->addSnippet(snippet);
689
}
690
691
void J9::X86::I386::PrivateLinkage::buildVirtualOrComputedCall(
692
TR::X86CallSite &site,
693
TR::LabelSymbol *entryLabel,
694
TR::LabelSymbol *doneLabel,
695
uint8_t *thunk)
696
{
697
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
698
bool resolvedSite = !site.getSymbolReference()->isUnresolved()
699
&& fej9->isResolvedVirtualDispatchGuaranteed(comp());
700
701
if (site.getSymbolReference()->getSymbol()->castToMethodSymbol()->isComputed())
702
{
703
// TODO:JSR292: Try to avoid the explicit VFT load
704
TR::Register *targetAddress = site.evaluateVFT();
705
if (targetAddress->getRegisterPair())
706
targetAddress = targetAddress->getRegisterPair()->getLowOrder();
707
buildVFTCall(site, TR::InstOpCode::CALLReg, targetAddress, NULL);
708
}
709
else if (resolvedSite && site.resolvedVirtualShouldUseVFTCall())
710
{
711
// There are no J2I thunks on x86-32, so no J2I thunk validation is needed
712
713
if (entryLabel)
714
generateLabelInstruction(TR::InstOpCode::label, site.getCallNode(), entryLabel, cg());
715
716
intptr_t offset=site.getSymbolReference()->getOffset();
717
if (!resolvedSite)
718
offset = 0;
719
720
buildVFTCall(site, TR::InstOpCode::CALLMem, NULL, generateX86MemoryReference(site.evaluateVFT(), offset, cg()));
721
}
722
else
723
{
724
J9::X86::PrivateLinkage::buildVPIC(site, entryLabel, doneLabel);
725
}
726
}
727
728
intptr_t
729
J9::X86::I386::PrivateLinkage::entryPointFromCompiledMethod()
730
{
731
return reinterpret_cast<intptr_t>(cg()->getCodeStart());
732
}
733
734