Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/ilgen/Walker.cpp
6000 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 <algorithm>
24
#include "codegen/CodeGenerator.hpp"
25
#include "compile/InlineBlock.hpp"
26
#include "compile/Method.hpp"
27
#include "compile/ResolvedMethod.hpp"
28
#include "control/Recompilation.hpp"
29
#include "control/RecompilationInfo.hpp"
30
#include "env/CompilerEnv.hpp"
31
#include "env/PersistentCHTable.hpp"
32
#include "env/StackMemoryRegion.hpp"
33
#include "env/TypeLayout.hpp"
34
#include "env/jittypes.h"
35
#include "env/VMAccessCriticalSection.hpp"
36
#include "env/VerboseLog.hpp"
37
#include "exceptions/AOTFailure.hpp"
38
#include "exceptions/FSDFailure.hpp"
39
#include "exceptions/RuntimeFailure.hpp"
40
#include "optimizer/TransformUtil.hpp"
41
#include "il/Node.hpp"
42
#include "il/Node_inlines.hpp"
43
#include "il/TreeTop.hpp"
44
#include "il/TreeTop_inlines.hpp"
45
#include "env/j9fieldsInfo.h"
46
#include "env/VMJ9.h"
47
#include "ilgen/ClassLookahead.hpp"
48
#include "ilgen/J9ByteCode.hpp"
49
#include "ilgen/J9ByteCodeIlGenerator.hpp"
50
#include "infra/Bit.hpp" //for trailingZeroes
51
#include "env/JSR292Methods.h"
52
53
#if defined(J9VM_OPT_JITSERVER)
54
#include "env/j9methodServer.hpp"
55
#endif
56
57
#define JAVA_SERIAL_CLASS_NAME "Ljava/io/ObjectInputStream;"
58
#define JAVA_SERIAL_CLASS_NAME_LEN 27
59
#define JAVA_SERIAL_CALLEE_METHOD_NAME_LEN 10
60
#define JAVA_SERIAL_CALLEE_METHOD_NAME "readObject"
61
#define JAVA_SERIAL_CALLEE_METHOD_SIG_LEN 20
62
#define JAVA_SERIAL_CALLEE_METHOD_SIG "()Ljava/lang/Object;"
63
#define JAVA_SERIAL_REPLACE_CLASS_LEN 25
64
#define JAVA_SERIAL_REPLACE_CLASS_NAME "java/io/ObjectInputStream"
65
#define JAVA_SERIAL_REPLACE_METHOD_SIG_LEN 64
66
#define JAVA_SERIAL_REPLACE_METHOD_SIG "(Ljava/io/ObjectInputStream;Ljava/lang/Class;)Ljava/lang/Object;"
67
#define JAVA_SERIAL_REPLACE_METHOD_NAME_LEN 20
68
#define JAVA_SERIAL_REPLACE_METHOD_NAME "redirectedReadObject"
69
70
#define ORB_CALLER_METHOD_NAME_LEN 10
71
#define ORB_CALLER_METHOD_NAME "readObject"
72
#define ORB_CALLER_METHOD_SIG_LEN 30
73
#define ORB_CALLER_METHOD_SIG "(Ljava/io/ObjectInputStream;)V"
74
75
#define ORB_CALLEE_METHOD_NAME_LEN 10
76
#define ORB_CALLEE_METHOD_NAME "readObject"
77
#define ORB_CALLEE_METHOD_SIG_LEN 20
78
#define ORB_CALLEE_METHOD_SIG "()Ljava/lang/Object;"
79
80
#define ORB_REPLACE_CLASS_LEN 30
81
#define ORB_REPLACE_CLASS_NAME "com/ibm/rmi/io/IIOPInputStream"
82
#define ORB_REPLACE_METHOD_SIG_LEN 64
83
#define ORB_REPLACE_METHOD_SIG "(Ljava/io/ObjectInputStream;Ljava/lang/Class;)Ljava/lang/Object;"
84
#define ORB_REPLACE_METHOD_NAME_LEN 20
85
#define ORB_REPLACE_METHOD_NAME "redirectedReadObject"
86
87
#define JSR292_ILGenMacros "java/lang/invoke/ILGenMacros"
88
#define JSR292_placeholder "placeholder"
89
#define JSR292_placeholderSig "(I)I"
90
91
#define JSR292_MethodHandle "java/lang/invoke/MethodHandle"
92
#define JSR292_invokeExactTargetAddress "invokeExactTargetAddress"
93
#define JSR292_invokeExactTargetAddressSig "()J"
94
#define JSR292_getType "type"
95
#define JSR292_getTypeSig "()Ljava/lang/invoke/MethodType;"
96
97
#define JSR292_invokeExact "invokeExact"
98
#define JSR292_invokeExactSig "([Ljava/lang/Object;)Ljava/lang/Object;"
99
100
#define JSR292_ComputedCalls "java/lang/invoke/ComputedCalls"
101
#define JSR292_dispatchDirectPrefix "dispatchDirect_"
102
#define JSR292_dispatchDirectArgSig "(JI)"
103
104
#define JSR292_asType "asType"
105
#define JSR292_asTypeSig "(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;"
106
#define JSR292_forGenericInvoke "forGenericInvoke"
107
#define JSR292_forGenericInvokeSig "(Ljava/lang/invoke/MethodType;Z)Ljava/lang/invoke/MethodHandle;"
108
109
110
static void printStack(TR::Compilation *comp, TR_Stack<TR::Node*> *stack, const char *message)
111
{
112
// TODO: This should be in the debug DLL
113
if (stack->isEmpty())
114
{
115
traceMsg(comp, " ---- %s: empty -----------------\n", message);
116
}
117
else
118
{
119
TR_BitVector nodesAlreadyPrinted(comp->getNodeCount(), comp->trMemory(), stackAlloc, growable);
120
comp->getDebug()->saveNodeChecklist(nodesAlreadyPrinted);
121
char buf[30];
122
traceMsg(comp, " /--- %s ------------------------", message);
123
for (int i = stack->topIndex(); i >= 0; --i)
124
{
125
TR::Node *node = stack->element(i);
126
traceMsg(comp, "\n");
127
sprintf(buf, " @%-2d", i);
128
comp->getDebug()->printWithFixedPrefix(comp->getOutFile(), node, 1, false, true, buf);
129
if (!nodesAlreadyPrinted.isSet(node->getGlobalIndex()))
130
{
131
for (int j = 0; j < node->getNumChildren(); ++j)
132
{
133
traceMsg(comp, "\n");
134
comp->getDebug()->printWithFixedPrefix(comp->getOutFile(), node->getChild(j), 3, true, true, " ");
135
}
136
}
137
}
138
traceMsg(comp, "\n");
139
}
140
}
141
142
static void printTrees(TR::Compilation *comp, TR::TreeTop *firstTree, TR::TreeTop *stopTree, const char *message)
143
{
144
// TODO: This should be in the debug DLL
145
if (firstTree == stopTree)
146
{
147
traceMsg(comp, " ---- %s: none ------------------\n", message);
148
}
149
else
150
{
151
traceMsg(comp, " /--- %s ------------------------", message);
152
for (TR::TreeTop *tt = firstTree; tt && tt != stopTree; tt = tt->getNextTreeTop())
153
{
154
traceMsg(comp, "\n");
155
comp->getDebug()->printWithFixedPrefix(comp->getOutFile(), tt->getNode(), 1, true, true, " ");
156
}
157
traceMsg(comp, "\n");
158
}
159
}
160
161
static TR::ILOpCodes getCallOpForType(TR::DataType type)
162
{
163
switch(type)
164
{
165
case TR::Address: return TR::acall;
166
case TR::Float : return TR::fcall;
167
case TR::Double: return TR::dcall;
168
case TR::Int32:
169
case TR::Int16:
170
case TR::Int8: return TR::icall;
171
case TR::Int64:return TR::lcall;
172
default: TR_ASSERT(false, "assertion failure");
173
}
174
return TR::BadILOp;
175
}
176
177
#define DCAS_AVAILABLE_FLAG "dWordCASSupported"
178
#define DCAS_AVAILABLE_FLAG_LEN 17
179
#define DCAS_AVAILABLE_FLAG_SIG "Z"
180
#define DCAS_AVAILABLE_FLAG_SIG_LEN 1
181
182
#define DSET_AVAILABLE_FLAG "dWordSetSupported"
183
#define DSET_AVAILABLE_FLAG_LEN 17
184
#define DSET_AVAILABLE_FLAG_SIG "Z"
185
#define DSET_AVAILABLE_FLAG_SIG_LEN 1
186
187
TR::Block * TR_J9ByteCodeIlGenerator::walker(TR::Block * prevBlock)
188
{
189
int32_t i, lastIndex = _bcIndex, firstIndex = _bcIndex;
190
191
if (comp()->getOption(TR_TraceILGen))
192
{
193
comp()->getDebug()->clearNodeChecklist();
194
traceMsg(comp(), "==== Starting ILGen walker at bytecode %x", _bcIndex);
195
if (_argPlaceholderSlot != -1)
196
traceMsg(comp(), " argPlaceholderSlot=%d", _argPlaceholderSlot);
197
traceMsg(comp(), "\n");
198
}
199
200
201
#if defined(J9VM_OPT_JITSERVER)
202
if (prevBlock == 0 && comp()->isOutOfProcessCompilation() && _methodSymbol->getResolvedMethod())
203
{
204
// Every J9BCinvoke* bytecode requires a corresponding resolved method for its method symbol.
205
// Prefetch resolved methods in one message.
206
// For unresolved methods, allow the next 2 requests to return NULL without asking the client,
207
// since they happen almost immediately after this one and method is unlikely to become resolved.
208
//
209
// NOTE: first request occurs in the switch statement over bytecodes,
210
// second request occurs in stashArgumentsForOSR
211
if (_methodSymbol->getResolvedMethod() == comp()->getMethodBeingCompiled())
212
static_cast<TR_ResolvedJ9JITServerMethod *>(_methodSymbol->getResolvedMethod())->cacheResolvedMethodsCallees(2);
213
214
215
// Cache field info for every field/static loaded/stored in this method, which are later used by
216
// jitFieldsAreSame/jitStaticAreSame when creating symbol references.
217
static_cast<TR_ResolvedJ9JITServerMethod *>(_methodSymbol->getResolvedMethod())->cacheFields();
218
}
219
#endif
220
221
while (_bcIndex < _maxByteCodeIndex)
222
{
223
if (blocks(_bcIndex) && blocks(_bcIndex) != _block)
224
{
225
if (isGenerated(_bcIndex))
226
_bcIndex = genGoto(_bcIndex);
227
else
228
_bcIndex = genBBEndAndBBStart();
229
if (_bcIndex >= _maxByteCodeIndex)
230
break;
231
}
232
233
if (_bcIndex < firstIndex)
234
firstIndex = _bcIndex;
235
else if (_bcIndex > lastIndex)
236
lastIndex = _bcIndex;
237
238
TR_ASSERT(!isGenerated(_bcIndex), "Walker error");
239
setIsGenerated(_bcIndex);
240
241
uint8_t opcode = _code[_bcIndex];
242
243
TR::TreeTop *traceStop = _block->getExit();
244
TR::TreeTop *traceStart = traceStop->getPrevTreeTop();
245
if (comp()->getOption(TR_TraceILGen))
246
traceMsg(comp(), "%4x: %s\n", _bcIndex, ((TR_J9VM *)fej9())->getByteCodeName(opcode));
247
248
_bc = convertOpCodeToByteCodeEnum(opcode);
249
stashArgumentsForOSR(_bc);
250
switch (_bc)
251
{
252
case J9BCinvokeinterface2:
253
case J9BCnop: _bcIndex += 1; break;
254
255
case J9BCaconstnull: loadConstant(TR::aconst, (void *)0); _bcIndex += 1; break;
256
case J9BCiconstm1: loadConstant(TR::iconst, -1); _bcIndex += 1; break;
257
258
case J9BCiconst0: loadConstant(TR::iconst, 0); _bcIndex += 1; break;
259
case J9BCiconst1: loadConstant(TR::iconst, 1); _bcIndex += 1; break;
260
case J9BCiconst2: loadConstant(TR::iconst, 2); _bcIndex += 1; break;
261
case J9BCiconst3: loadConstant(TR::iconst, 3); _bcIndex += 1; break;
262
case J9BCiconst4: loadConstant(TR::iconst, 4); _bcIndex += 1; break;
263
case J9BCiconst5: loadConstant(TR::iconst, 5); _bcIndex += 1; break;
264
265
case J9BClconst0: loadConstant(TR::lconst, (int64_t)0); _bcIndex += 1; break;
266
case J9BClconst1: loadConstant(TR::lconst, (int64_t)1); _bcIndex += 1; break;
267
268
case J9BCfconst0: loadConstant(TR::fconst, 0.0f); _bcIndex += 1; break;
269
case J9BCfconst1: loadConstant(TR::fconst, 1.0f); _bcIndex += 1; break;
270
case J9BCfconst2: loadConstant(TR::fconst, 2.0f); _bcIndex += 1; break;
271
272
case J9BCdconst0: loadConstant(TR::dconst, 0.0); _bcIndex += 1; break;
273
case J9BCdconst1: loadConstant(TR::dconst, 1.0); _bcIndex += 1; break;
274
275
case J9BCldc: loadFromCP(TR::NoType, nextByte()); _bcIndex += 2; break;
276
case J9BCldcw: loadFromCP(TR::NoType, next2Bytes()); _bcIndex += 3; break;
277
case J9BCldc2lw: loadFromCP(TR::NoType, next2Bytes()); _bcIndex += 3; break;
278
case J9BCldc2dw: loadFromCP(TR::NoType, next2Bytes()); _bcIndex += 3; break;
279
280
case J9BCiload0: loadAuto(TR::Int32, 0); _bcIndex += 1; break;
281
case J9BCiload1: loadAuto(TR::Int32, 1); _bcIndex += 1; break;
282
case J9BCiload2: loadAuto(TR::Int32, 2); _bcIndex += 1; break;
283
case J9BCiload3: loadAuto(TR::Int32, 3); _bcIndex += 1; break;
284
285
case J9BClload0: loadAuto(TR::Int64, 0); _bcIndex += 1; break;
286
case J9BClload1: loadAuto(TR::Int64, 1); _bcIndex += 1; break;
287
case J9BClload2: loadAuto(TR::Int64, 2); _bcIndex += 1; break;
288
case J9BClload3: loadAuto(TR::Int64, 3); _bcIndex += 1; break;
289
290
case J9BCfload0: loadAuto(TR::Float, 0); _bcIndex += 1; break;
291
case J9BCfload1: loadAuto(TR::Float, 1); _bcIndex += 1; break;
292
case J9BCfload2: loadAuto(TR::Float, 2); _bcIndex += 1; break;
293
case J9BCfload3: loadAuto(TR::Float, 3); _bcIndex += 1; break;
294
295
case J9BCdload0: loadAuto(TR::Double, 0); _bcIndex += 1; break;
296
case J9BCdload1: loadAuto(TR::Double, 1); _bcIndex += 1; break;
297
case J9BCdload2: loadAuto(TR::Double, 2); _bcIndex += 1; break;
298
case J9BCdload3: loadAuto(TR::Double, 3); _bcIndex += 1; break;
299
300
case J9BCaload0: loadAuto(TR::Address, 0); _bcIndex += 1; break;
301
case J9BCaload1: loadAuto(TR::Address, 1); _bcIndex += 1; break;
302
case J9BCaload2: loadAuto(TR::Address, 2); _bcIndex += 1; break;
303
case J9BCaload3: loadAuto(TR::Address, 3); _bcIndex += 1; break;
304
305
case J9BCiaload: loadArrayElement(TR::Int32); _bcIndex += 1; break;
306
case J9BClaload: loadArrayElement(TR::Int64); _bcIndex += 1; break;
307
case J9BCfaload: loadArrayElement(TR::Float); _bcIndex += 1; break;
308
case J9BCdaload: loadArrayElement(TR::Double); _bcIndex += 1; break;
309
case J9BCaaload: loadArrayElement(TR::Address); _bcIndex += 1; break;
310
case J9BCbaload: loadArrayElement(TR::Int8); genUnary(TR::b2i); _bcIndex += 1; break;
311
case J9BCcaload: loadArrayElement(TR::Int16); genUnary(TR::su2i); _bcIndex += 1; break;
312
case J9BCsaload: loadArrayElement(TR::Int16); genUnary(TR::s2i); _bcIndex += 1; break;
313
314
case J9BCiloadw: loadAuto(TR::Int32, next2Bytes()); _bcIndex += 3; break;
315
case J9BClloadw: loadAuto(TR::Int64, next2Bytes()); _bcIndex += 3; break;
316
case J9BCfloadw: loadAuto(TR::Float, next2Bytes()); _bcIndex += 3; break;
317
case J9BCdloadw: loadAuto(TR::Double, next2Bytes()); _bcIndex += 3; break;
318
case J9BCaloadw: loadAuto(TR::Address, next2Bytes()); _bcIndex += 3; break;
319
320
case J9BCbipush: loadConstant(TR::iconst, nextByteSigned()); _bcIndex += 2; break;
321
case J9BCsipush: loadConstant(TR::iconst, next2BytesSigned()); _bcIndex += 3; break;
322
323
case J9BCiload: loadAuto(TR::Int32, nextByte()); _bcIndex += 2; break;
324
case J9BClload: loadAuto(TR::Int64, nextByte()); _bcIndex += 2; break;
325
case J9BCfload: loadAuto(TR::Float, nextByte()); _bcIndex += 2; break;
326
case J9BCdload: loadAuto(TR::Double, nextByte()); _bcIndex += 2; break;
327
case J9BCaload: loadAuto(TR::Address, nextByte()); _bcIndex += 2; break;
328
329
case J9BCistore: storeAuto(TR::Int32, nextByte()); _bcIndex += 2; break;
330
case J9BClstore: storeAuto(TR::Int64, nextByte()); _bcIndex += 2; break;
331
case J9BCfstore: storeAuto(TR::Float, nextByte()); _bcIndex += 2; break;
332
case J9BCdstore: storeAuto(TR::Double, nextByte()); _bcIndex += 2; break;
333
case J9BCastore: storeAuto(TR::Address, nextByte()); _bcIndex += 2; break;
334
335
case J9BCistore0: storeAuto(TR::Int32, 0); _bcIndex += 1; break;
336
case J9BCistore1: storeAuto(TR::Int32, 1); _bcIndex += 1; break;
337
case J9BCistore2: storeAuto(TR::Int32, 2); _bcIndex += 1; break;
338
case J9BCistore3: storeAuto(TR::Int32, 3); _bcIndex += 1; break;
339
340
case J9BClstore0: storeAuto(TR::Int64, 0); _bcIndex += 1; break;
341
case J9BClstore1: storeAuto(TR::Int64, 1); _bcIndex += 1; break;
342
case J9BClstore2: storeAuto(TR::Int64, 2); _bcIndex += 1; break;
343
case J9BClstore3: storeAuto(TR::Int64, 3); _bcIndex += 1; break;
344
345
case J9BCfstore0: storeAuto(TR::Float, 0); _bcIndex += 1; break;
346
case J9BCfstore1: storeAuto(TR::Float, 1); _bcIndex += 1; break;
347
case J9BCfstore2: storeAuto(TR::Float, 2); _bcIndex += 1; break;
348
case J9BCfstore3: storeAuto(TR::Float, 3); _bcIndex += 1; break;
349
350
case J9BCdstore0: storeAuto(TR::Double, 0); _bcIndex += 1; break;
351
case J9BCdstore1: storeAuto(TR::Double, 1); _bcIndex += 1; break;
352
case J9BCdstore2: storeAuto(TR::Double, 2); _bcIndex += 1; break;
353
case J9BCdstore3: storeAuto(TR::Double, 3); _bcIndex += 1; break;
354
355
case J9BCastore0: storeAuto(TR::Address, 0); _bcIndex += 1; break;
356
case J9BCastore1: storeAuto(TR::Address, 1); _bcIndex += 1; break;
357
case J9BCastore2: storeAuto(TR::Address, 2); _bcIndex += 1; break;
358
case J9BCastore3: storeAuto(TR::Address, 3); _bcIndex += 1; break;
359
360
case J9BCiastore: storeArrayElement(TR::Int32); _bcIndex += 1; break;
361
case J9BClastore: storeArrayElement(TR::Int64); _bcIndex += 1; break;
362
case J9BCfastore: storeArrayElement(TR::Float); _bcIndex += 1; break;
363
case J9BCdastore: storeArrayElement(TR::Double); _bcIndex += 1; break;
364
case J9BCaastore: storeArrayElement(TR::Address); _bcIndex += 1; break;
365
case J9BCbastore: genUnary(TR::i2b); storeArrayElement(TR::Int8); _bcIndex += 1; break;
366
case J9BCcastore: genUnary(TR::i2s); storeArrayElement(TR::Int16);_bcIndex += 1; break;
367
case J9BCsastore: genUnary(TR::i2s); storeArrayElement(TR::Int16); _bcIndex += 1; break;
368
369
case J9BCistorew: storeAuto(TR::Int32, next2Bytes()); _bcIndex += 3; break;
370
case J9BClstorew: storeAuto(TR::Int64, next2Bytes()); _bcIndex += 3; break;
371
case J9BCfstorew: storeAuto(TR::Float, next2Bytes()); _bcIndex += 3; break;
372
case J9BCdstorew: storeAuto(TR::Double, next2Bytes()); _bcIndex += 3; break;
373
case J9BCastorew: storeAuto(TR::Address, next2Bytes()); _bcIndex += 3; break;
374
375
case J9BCpop: eat1(); _bcIndex += 1; break;
376
case J9BCpop2: eat2(); _bcIndex += 1; break;
377
case J9BCdup: dup(); _bcIndex += 1; break;
378
case J9BCdup2: dup2(); _bcIndex += 1; break;
379
case J9BCdupx1: dupx1(); _bcIndex += 1; break;
380
case J9BCdup2x1: dup2x1(); _bcIndex += 1; break;
381
case J9BCdupx2: dupx2(); _bcIndex += 1; break;
382
case J9BCdup2x2: dup2x2(); _bcIndex += 1; break;
383
case J9BCswap: swap(); _bcIndex += 1; break;
384
385
case J9BCiadd: genBinary(TR::iadd); _bcIndex += 1; break;
386
case J9BCladd: genBinary(TR::ladd); _bcIndex += 1; break;
387
case J9BCfadd: genBinary(TR::fadd); _bcIndex += 1; break;
388
case J9BCdadd: genBinary(TR::dadd); _bcIndex += 1; break;
389
390
case J9BCisub: genBinary(TR::isub); _bcIndex += 1; break;
391
case J9BClsub: genBinary(TR::lsub); _bcIndex += 1; break;
392
case J9BCfsub: genBinary(TR::fsub); _bcIndex += 1; break;
393
case J9BCdsub: genBinary(TR::dsub); _bcIndex += 1; break;
394
395
case J9BCimul: genBinary(TR::imul); _bcIndex += 1; break;
396
case J9BClmul: genBinary(TR::lmul); _bcIndex += 1; break;
397
case J9BCfmul: genBinary(TR::fmul); _bcIndex += 1; break;
398
case J9BCdmul: genBinary(TR::dmul); _bcIndex += 1; break;
399
400
case J9BCidiv: genIDiv(); _bcIndex += 1; break;
401
case J9BCldiv: genLDiv(); _bcIndex += 1; break;
402
403
case J9BCirem: genIRem(); _bcIndex += 1; break;
404
case J9BClrem: genLRem(); _bcIndex += 1; break;
405
406
case J9BCfdiv: genBinary(TR::fdiv); _bcIndex += 1; break;
407
case J9BCddiv: genBinary(TR::ddiv); _bcIndex += 1; break;
408
case J9BCfrem: genBinary(TR::frem); _bcIndex += 1; break;
409
case J9BCdrem: genBinary(TR::drem); _bcIndex += 1; break;
410
411
case J9BCineg: genUnary(TR::ineg); _bcIndex += 1; break;
412
case J9BClneg: genUnary(TR::lneg); _bcIndex += 1; break;
413
case J9BCfneg: genUnary(TR::fneg); _bcIndex += 1; break;
414
case J9BCdneg: genUnary(TR::dneg); _bcIndex += 1; break;
415
416
case J9BCishl: genBinary(TR::ishl); _bcIndex += 1; break;
417
case J9BCishr: genBinary(TR::ishr); _bcIndex += 1; break;
418
case J9BCiushr: genBinary(TR::iushr); _bcIndex += 1; break;
419
case J9BClshl: genBinary(TR::lshl); _bcIndex += 1; break;
420
case J9BClshr: genBinary(TR::lshr); _bcIndex += 1; break;
421
case J9BClushr: genBinary(TR::lushr); _bcIndex += 1; break;
422
423
case J9BCiand: genBinary(TR::iand); _bcIndex += 1; break;
424
case J9BCior: genBinary(TR::ior); _bcIndex += 1; break;
425
case J9BCixor: genBinary(TR::ixor); _bcIndex += 1; break;
426
case J9BCland: genBinary(TR::land); _bcIndex += 1; break;
427
case J9BClor: genBinary(TR::lor); _bcIndex += 1; break;
428
case J9BClxor: genBinary(TR::lxor); _bcIndex += 1; break;
429
430
case J9BCi2l: genUnary(TR::i2l); _bcIndex += 1; break;
431
case J9BCi2f: genUnary(TR::i2f); _bcIndex += 1; break;
432
case J9BCi2d: genUnary(TR::i2d); _bcIndex += 1; break;
433
434
case J9BCl2i: genUnary(TR::l2i); _bcIndex += 1; break;
435
case J9BCl2f: genUnary(TR::l2f); _bcIndex += 1; break;
436
case J9BCl2d: genUnary(TR::l2d); _bcIndex += 1; break;
437
case J9BCf2i: genUnary(TR::f2i); _bcIndex += 1; break;
438
439
case J9BCf2d: genUnary(TR::f2d); _bcIndex += 1; break;
440
case J9BCd2i: genUnary(TR::d2i); _bcIndex += 1; break;
441
case J9BCd2f: genUnary(TR::d2f); _bcIndex += 1; break;
442
case J9BCf2l: genUnary(TR::f2l); _bcIndex += 1; break;
443
case J9BCd2l: genUnary(TR::d2l); _bcIndex += 1; break;
444
445
case J9BCi2b: genUnary(TR::i2b); genUnary(TR::b2i); _bcIndex += 1; break;
446
case J9BCi2c: genUnary(TR::i2s); genUnary(TR::su2i); _bcIndex += 1; break;
447
case J9BCi2s: genUnary(TR::i2s); genUnary(TR::s2i); _bcIndex += 1; break;
448
449
case J9BCinvokevirtual: genInvokeVirtual(next2Bytes()); _bcIndex += 3; break;
450
case J9BCinvokespecial: genInvokeSpecial(next2Bytes()); _bcIndex += 3; break;
451
case J9BCinvokestatic: genInvokeStatic(next2Bytes()); _bcIndex += 3; break;
452
case J9BCinvokeinterface: genInvokeInterface(next2Bytes()); _bcIndex += 3; break;
453
case J9BCinvokedynamic:
454
genInvokeDynamic(next2Bytes());
455
_bcIndex += 3; break; // Could eventually need next3bytes
456
case J9BCinvokehandle:
457
genInvokeHandle(next2Bytes());
458
_bcIndex += 3; break;
459
case J9BCinvokehandlegeneric:
460
genInvokeHandleGeneric(next2Bytes());
461
_bcIndex += 3; break;
462
case J9BCinvokespecialsplit: genInvokeSpecial(next2Bytes() | J9_SPECIAL_SPLIT_TABLE_INDEX_FLAG); _bcIndex += 3; break;
463
case J9BCinvokestaticsplit: genInvokeStatic(next2Bytes() | J9_STATIC_SPLIT_TABLE_INDEX_FLAG); _bcIndex += 3; break;
464
465
case J9BCifeq: _bcIndex = genIfOneOperand(TR::ificmpeq); break;
466
case J9BCifne: _bcIndex = genIfOneOperand(TR::ificmpne); break;
467
case J9BCiflt: _bcIndex = genIfOneOperand(TR::ificmplt); break;
468
case J9BCifge: _bcIndex = genIfOneOperand(TR::ificmpge); break;
469
case J9BCifgt: _bcIndex = genIfOneOperand(TR::ificmpgt); break;
470
case J9BCifle: _bcIndex = genIfOneOperand(TR::ificmple); break;
471
case J9BCifnull: _bcIndex = genIfOneOperand(TR::ifacmpeq); break;
472
case J9BCifnonnull: _bcIndex = genIfOneOperand(TR::ifacmpne); break;
473
474
case J9BCificmpeq: _bcIndex = genIfTwoOperand(TR::ificmpeq); break;
475
case J9BCificmpne: _bcIndex = genIfTwoOperand(TR::ificmpne); break;
476
case J9BCificmplt: _bcIndex = genIfTwoOperand(TR::ificmplt); break;
477
case J9BCificmpge: _bcIndex = genIfTwoOperand(TR::ificmpge); break;
478
case J9BCificmpgt: _bcIndex = genIfTwoOperand(TR::ificmpgt); break;
479
case J9BCificmple: _bcIndex = genIfTwoOperand(TR::ificmple); break;
480
case J9BCifacmpeq: _bcIndex = genIfAcmpEqNe(TR::ifacmpeq); break;
481
case J9BCifacmpne: _bcIndex = genIfAcmpEqNe(TR::ifacmpne); break;
482
483
case J9BClcmp: _bcIndex = cmp(TR::lcmp, _lcmpOps, lastIndex); break;
484
case J9BCfcmpl: _bcIndex = cmp(TR::fcmpl, _fcmplOps, lastIndex); break;
485
case J9BCfcmpg: _bcIndex = cmp(TR::fcmpg, _fcmpgOps, lastIndex); break;
486
case J9BCdcmpl: _bcIndex = cmp(TR::dcmpl, _dcmplOps, lastIndex); break;
487
case J9BCdcmpg: _bcIndex = cmp(TR::dcmpg, _dcmpgOps, lastIndex); break;
488
489
case J9BCtableswitch: _bcIndex = genTableSwitch (); break;
490
case J9BClookupswitch: _bcIndex = genLookupSwitch(); break;
491
492
case J9BCgoto: _bcIndex = genGoto(_bcIndex + next2BytesSigned()); break;
493
case J9BCgotow: _bcIndex = genGoto(_bcIndex + next4BytesSigned()); break;
494
495
case J9BCmonitorenter: genMonitorEnter(); _bcIndex += 1; break;
496
case J9BCmonitorexit: genMonitorExit(false); _bcIndex += 1; break;
497
498
case J9BCathrow: _bcIndex = genAThrow(); break;
499
case J9BCarraylength: genArrayLength(); _bcIndex += 1; break;
500
501
case J9BCgetstatic: loadStatic(next2Bytes()); _bcIndex += 3; break;
502
case J9BCgetfield: loadInstance(next2Bytes()); _bcIndex += 3; break;
503
case J9BCputstatic: storeStatic(next2Bytes()); _bcIndex += 3; break;
504
case J9BCputfield: storeInstance(next2Bytes()); _bcIndex += 3; break;
505
506
case J9BCcheckcast: genCheckCast(next2Bytes()); _bcIndex += 3; break;
507
case J9BCinstanceof: genInstanceof(next2Bytes()); _bcIndex += 3; break;
508
509
case J9BCnew: genNew(next2Bytes()); _bcIndex += 3; break;
510
case J9BCnewarray: genNewArray(nextByte()); _bcIndex += 2; break;
511
case J9BCanewarray: genANewArray(next2Bytes()); _bcIndex += 3; break;
512
case J9BCmultianewarray: genMultiANewArray(next2Bytes(), _code[_bcIndex+3]); _bcIndex += 4; break;
513
514
case J9BCiinc: genInc(); _bcIndex += 3; break;
515
case J9BCiincw: genIncLong(); _bcIndex += 5; break;
516
517
case J9BCwide:
518
{
519
int32_t wopcode = _code[++_bcIndex];
520
TR_J9ByteCode wbc = convertOpCodeToByteCodeEnum(wopcode);
521
if (_bcIndex > lastIndex)
522
lastIndex = _bcIndex;
523
if (wbc == J9BCiinc)
524
{ genIncLong(); _bcIndex += 5; break; }
525
526
switch (wbc)
527
{
528
case J9BCiload: loadAuto(TR::Int32, next2Bytes()); break;
529
case J9BClload: loadAuto(TR::Int64, next2Bytes()); break;
530
case J9BCfload: loadAuto(TR::Float, next2Bytes()); break;
531
case J9BCdload: loadAuto(TR::Double, next2Bytes()); break;
532
case J9BCaload: loadAuto(TR::Address, next2Bytes()); break;
533
534
case J9BCistore: storeAuto(TR::Int32, next2Bytes()); break;
535
case J9BClstore: storeAuto(TR::Int64, next2Bytes()); break;
536
case J9BCfstore: storeAuto(TR::Float, next2Bytes()); break;
537
case J9BCdstore: storeAuto(TR::Double, next2Bytes()); break;
538
case J9BCastore: storeAuto(TR::Address, next2Bytes()); break;
539
default: break;
540
}
541
_bcIndex += 3;
542
break;
543
}
544
545
case J9BCgenericReturn:
546
case J9BCReturnC:
547
case J9BCReturnS:
548
case J9BCReturnB:
549
case J9BCReturnZ:
550
_bcIndex = genReturn(method()->returnOpCode(), method()->isSynchronized());
551
break;
552
553
case J9BCaconst_init:
554
{
555
if (TR::Compiler->om.areValueTypesEnabled())
556
{
557
genAconst_init(next2Bytes());
558
_bcIndex += 3;
559
}
560
else
561
{
562
fej9()->unsupportedByteCode(comp(), opcode);
563
}
564
break;
565
}
566
case J9BCwithfield:
567
if (TR::Compiler->om.areValueTypesEnabled())
568
{
569
genWithField(next2Bytes());
570
_bcIndex += 3;
571
}
572
else
573
{
574
fej9()->unsupportedByteCode(comp(), opcode);
575
}
576
break;
577
case J9BCbreakpoint:
578
fej9()->unsupportedByteCode(comp(), opcode);
579
case J9BCunknown:
580
fej9()->unknownByteCode(comp(), opcode);
581
break;
582
default:
583
break;
584
}
585
586
if (comp()->getOption(TR_TraceILGen))
587
{
588
TR::StackMemoryRegion stackMemoryRegion(*comp()->trMemory());
589
590
TR_BitVector beforeTreesInserted(comp()->getNodeCount(), trMemory(), stackAlloc, growable);
591
TR_BitVector afterTreesInserted (comp()->getNodeCount(), trMemory(), stackAlloc, growable);
592
593
comp()->getDebug()->saveNodeChecklist(beforeTreesInserted);
594
printTrees(comp(), traceStart->getNextTreeTop(), traceStop, "trees inserted");
595
comp()->getDebug()->saveNodeChecklist(afterTreesInserted);
596
597
// Commoning in the "stack after" printout should match that in the
598
// "trees inserted" printout.
599
//
600
// NOTE: this is disabled because it prints (potentially large) trees
601
// twice for no particular benefit. Instead, we have opted to have
602
// the "stack after" printout appear to be "commoned" with the "trees
603
// inserted" printout. This might cause some minor confusion when the
604
// "stack after" section contains nodes with refcount=1 that appear to
605
// be commoned, but this overall clarity seems to favour the terser format.
606
//
607
//comp()->getDebug()->restoreNodeChecklist(beforeTreesInserted);
608
printStack(comp(), _stack, "stack after");
609
610
traceMsg(comp(), " ============================================================\n");
611
612
// Commoning from now on will reflect trees already inserted, not
613
// those that happened to appear on the stack. (The desirability
614
// of the resulting verbosity is debatable.)
615
//
616
comp()->getDebug()->restoreNodeChecklist(afterTreesInserted);
617
}
618
}
619
620
if( _blocksToInline) // partial inlining - only generate goto if its in the list of blocks.
621
{
622
if(_blocksToInline->getHighestBCIndex() > lastIndex)
623
{
624
lastIndex = _blocksToInline->getHighestBCIndex();
625
//printf("Walker: setting lastIndex to %d\n",lastIndex);
626
}
627
if(_blocksToInline->getLowestBCIndex() < firstIndex)
628
{
629
firstIndex = _blocksToInline->getLowestBCIndex();
630
//printf("Walker: setting firstIndex to %d\n",firstIndex);
631
}
632
}
633
634
// join the basic blocks
635
//
636
TR::Block * lastBlock = NULL, * nextBlock, * block = blocks(firstIndex);
637
if (firstIndex == 0)
638
cfg()->addEdge(cfg()->getStart(), block);
639
else
640
prevBlock->getExit()->join(block->getEntry());
641
for (i = firstIndex; block; lastBlock = block, block = nextBlock)
642
{
643
while (block->getNextBlock())
644
{
645
TR_ASSERT( block->isAdded(), "Block should have already been added\n" );
646
block = block->getNextBlock();
647
}
648
649
block->setIsAdded();
650
651
for (nextBlock = 0; !nextBlock && ++i <= lastIndex; )
652
if (isGenerated(i) && blocks(i) && !blocks(i)->isAdded())
653
nextBlock = blocks(i);
654
655
// If an exception range ends with an if and the fall through is
656
// in the main-line code then we have to generate a fall through block
657
// which contains a goto to jump back to the main-line code.
658
//
659
TR::Node * lastRealNode = block->getLastRealTreeTop()->getNode();
660
if (!nextBlock && lastRealNode->getOpCode().isIf())
661
{
662
nextBlock = TR::Block::createEmptyBlock(comp());
663
i = lastIndex;
664
if(_blocksToInline)
665
{
666
if(!blocks(i+3))
667
{
668
TR_ASSERT(_blocksToInline->hasGeneratedRestartTree(),"Fall Thru Block doesn't exist and we don't have a restart tree.\n");
669
nextBlock->append(
670
TR::TreeTop::create(comp(),
671
TR::Node::create(lastRealNode, TR::Goto, 0, _blocksToInline->getGeneratedRestartTree())));
672
}
673
else
674
{
675
nextBlock->append(
676
TR::TreeTop::create(comp(),
677
TR::Node::create(lastRealNode, TR::Goto, 0, blocks(i + 3)->getEntry())));
678
}
679
}
680
else
681
{
682
TR_ASSERT(blocks(i + 3), "can't find the fall thru block");
683
nextBlock->append(
684
TR::TreeTop::create(comp(),
685
TR::Node::create(lastRealNode, TR::Goto, 0, blocks(i + 3)->getEntry())));
686
}
687
}
688
block->getExit()->getNode()->copyByteCodeInfo(lastRealNode);
689
cfg()->insertBefore(block, nextBlock);
690
}
691
692
if(_blocksToInline && _blocksToInline->hasGeneratedRestartTree())
693
{
694
_blocksToInline->getGeneratedRestartTree()->getEnclosingBlock()->setIsCold();
695
_blocksToInline->getGeneratedRestartTree()->getEnclosingBlock()->setFrequency(1);
696
}
697
698
return lastBlock;
699
}
700
701
//----------------------------------------------
702
// walker helper routines
703
//----------------------------------------------
704
705
int32_t
706
TR_J9ByteCodeIlGenerator::cmp(TR::ILOpCodes cmpOpcode, TR::ILOpCodes * combinedOpcodes, int32_t & lastIndex)
707
{
708
int32_t nextBCIndex = _bcIndex + 1;
709
uint8_t nextOpcode = _code[nextBCIndex];
710
711
// can't generate the async check here if someone is jumping to it
712
//
713
if (convertOpCodeToByteCodeEnum(nextOpcode) == J9BCasyncCheck && blocks(nextBCIndex) == 0)
714
{
715
genAsyncCheck();
716
nextBCIndex = ++_bcIndex + 1;
717
nextOpcode = _code[nextBCIndex];
718
if (_bcIndex > lastIndex)
719
lastIndex = _bcIndex;
720
}
721
722
TR::ILOpCodes combinedOpcode;
723
switch (convertOpCodeToByteCodeEnum(nextOpcode))
724
{
725
case J9BCifeq: combinedOpcode = combinedOpcodes[0]; break;
726
case J9BCifne: combinedOpcode = combinedOpcodes[1]; break;
727
case J9BCiflt: combinedOpcode = combinedOpcodes[2]; break;
728
case J9BCifge: combinedOpcode = combinedOpcodes[3]; break;
729
case J9BCifgt: combinedOpcode = combinedOpcodes[4]; break;
730
case J9BCifle: combinedOpcode = combinedOpcodes[5]; break;
731
default: combinedOpcode = TR::BadILOp; break;
732
}
733
734
// don't combine the opcodes if someone is jumping to the if
735
//
736
if (combinedOpcode != TR::BadILOp && blocks(nextBCIndex) == 0)
737
return cmpFollowedByIf(nextOpcode, combinedOpcode, lastIndex);
738
739
genBinary(cmpOpcode);
740
genUnary(TR::b2i);
741
return _bcIndex + 1;
742
}
743
744
int32_t
745
TR_J9ByteCodeIlGenerator::cmpFollowedByIf(uint8_t ifOpcode, TR::ILOpCodes combinedOpcode, int32_t & lastIndex)
746
{
747
int32_t branchOffset = next2BytesSigned(2); // The 2 bytes after the compare bytecode is the branch offset
748
749
// If asynccheck is needed, generate it before incrementing _bcIndex such that it has the bytecode index of
750
// the compare bytecode.
751
if (branchOffset <= 0)
752
{
753
genAsyncCheck();
754
}
755
756
if (++_bcIndex > lastIndex)
757
lastIndex = _bcIndex;
758
759
return genIfImpl(combinedOpcode);
760
}
761
762
//----------------------------------------------
763
// gen helper routines
764
//----------------------------------------------
765
766
TR::SymbolReference *
767
TR_J9ByteCodeIlGenerator::placeholderWithDummySignature()
768
{
769
// Note: signatures should always be correct. Only call this to pass the
770
// result to something like genNodeAndPopChildren which will expand the
771
// signature properly.
772
if (comp()->getOption(TR_TraceMethodIndex))
773
traceMsg(comp(), "placeholderWithDummySignature using owning symbol M%p _methodSymbol: M%p\n", comp()->getJittedMethodSymbol(), _methodSymbol);
774
775
// Note that we use comp()->getJittedMethodSymbol() instead of _methodSymbol here.
776
// The caller doesn't matter for this special method, and there's no need to make
777
// potentially hundreds of symbols for the same method.
778
//
779
return comp()->getSymRefTab()->methodSymRefFromName(comp()->getJittedMethodSymbol(), JSR292_ILGenMacros, JSR292_placeholder, JSR292_placeholderSig, TR::MethodSymbol::Static);
780
}
781
782
TR::SymbolReference *
783
TR_J9ByteCodeIlGenerator::placeholderWithSignature(char *prefix, int prefixLength, char *middle, int middleLength, char *suffix, int suffixLength)
784
{
785
return symRefWithArtificialSignature(placeholderWithDummySignature(),
786
".#.#.#",
787
prefix, prefixLength,
788
middle, middleLength,
789
suffix, suffixLength);
790
}
791
792
TR::SymbolReference *
793
TR_J9ByteCodeIlGenerator::symRefWithArtificialSignature(TR::SymbolReference *original, char *effectiveSigFormat, ...)
794
{
795
TR::StackMemoryRegion stackMemoryRegion(*comp()->trMemory());
796
797
va_list args;
798
va_start(args, effectiveSigFormat);
799
char *effectiveSig = vartificialSignature(stackAlloc, effectiveSigFormat, args);
800
va_end(args);
801
802
TR::SymbolReference *result = comp()->getSymRefTab()->methodSymRefWithSignature(original, effectiveSig, strlen(effectiveSig));
803
804
return result;
805
}
806
807
static int32_t processArtificialSignature(char *result, char *format, va_list args)
808
{
809
int32_t resultLength = 0;
810
char *cur = result;
811
for (int32_t i = 0; format[i]; i++)
812
{
813
int32_t length=-1;
814
char *startChar=NULL;
815
if (format[i] == '.') // period is the ONLY character (besides null) that can never appear in a method signature
816
{
817
// Formatting code
818
switch (format[++i])
819
{
820
case '@': // insert a single given arg out of a given signature
821
{
822
char *sig = va_arg(args, char*);
823
int n = va_arg(args, int);
824
startChar = nthSignatureArgument(n, sig+1);
825
length = nextSignatureArgument(startChar) - startChar;
826
break;
827
}
828
case '-': // insert a given range of args out of a given signature
829
{
830
char *sig = va_arg(args, char*);
831
int firstN = va_arg(args, int);
832
int lastN = va_arg(args, int);
833
if (lastN >= firstN)
834
{
835
startChar = nthSignatureArgument(firstN, sig+1);
836
length = nthSignatureArgument(lastN+1, sig+1) - startChar;
837
}
838
else
839
{
840
startChar = "";
841
length = 0;
842
}
843
break;
844
}
845
case '*': // insert args from a given one onward, out of a given signature
846
{
847
char *sig = va_arg(args, char*);
848
int firstN = va_arg(args, int);
849
startChar = nthSignatureArgument(firstN, sig+1);
850
length = strchr(startChar, ')') - startChar;
851
break;
852
}
853
case '$': // insert return type from a given signature
854
{
855
char *sig = va_arg(args, char*);
856
startChar = strchr(sig, ')') + 1;
857
length = nextSignatureArgument(startChar) - startChar;
858
break;
859
}
860
case '?': // insert a given null-terminated string
861
{
862
startChar = va_arg(args, char*);
863
length = strlen(startChar);
864
break;
865
}
866
case '#': // insert a given number of characters out of a given string
867
{
868
startChar = va_arg(args, char*);
869
length = va_arg(args, int);
870
break;
871
}
872
default: // literal character
873
TR_ASSERT(0, "Unexpected artificial signature formatting character '%c'", format[i]);
874
875
// If we reach this point, either TR has a bug, or we have actually somehow
876
// encountered a signature that legitimately had a period in it. In the latter
877
// case, proceed on the assumption that the period was a literal character;
878
// if TR has a bug, we will very likely crash soon enough anyway.
879
//
880
startChar = format+i-1; // back up to the period
881
length = 2;
882
break;
883
}
884
}
885
else
886
{
887
// Literal character
888
startChar = format+i;
889
length = 1;
890
}
891
892
TR_ASSERT(length >= 0, "assertion failure");
893
TR_ASSERT(startChar != NULL, "assertion failure");
894
895
resultLength += length;
896
if (result)
897
cur += sprintf(cur, "%.*s", length, startChar);
898
899
}
900
901
return resultLength;
902
}
903
904
char *TR_J9ByteCodeIlGenerator::artificialSignature(TR_AllocationKind allocKind, char *format, ...)
905
{
906
va_list args;
907
va_start(args, format);
908
char *result = vartificialSignature(allocKind, format, args);
909
va_end(args);
910
return result;
911
}
912
913
char *TR_J9ByteCodeIlGenerator::vartificialSignature(TR_AllocationKind allocKind, char *format, va_list args)
914
{
915
// Compute size
916
//
917
va_list argsCopy;
918
va_copy(argsCopy, args);
919
int32_t resultLength = processArtificialSignature(NULL, format, argsCopy);
920
va_copy_end(argsCopy);
921
922
// Produce formatted signature
923
//
924
char *result = (char*)trMemory()->allocateMemory(resultLength+1, allocKind);
925
processArtificialSignature(result, format, args);
926
return result;
927
}
928
929
void
930
TR_J9ByteCodeIlGenerator::genArgPlaceholderCall()
931
{
932
// Create argument load nodes
933
//
934
int32_t numNodesGenerated = 0;
935
ListIterator<TR::ParameterSymbol> i(&_methodSymbol->getParameterList());
936
for (TR::ParameterSymbol *parm = i.getFirst(); parm; parm = i.getNext())
937
{
938
if (parm->getSlot() >= _argPlaceholderSlot)
939
{
940
// What a convoluted way to get a symref from a symbol...
941
TR::SymbolReference *symRef = _methodSymbol->getParmSymRef(parm->getSlot());
942
push(TR::Node::createLoad(symRef));
943
numNodesGenerated++;
944
}
945
}
946
947
// Create placeholder call with the proper signature
948
//
949
char *callerSignature = _methodSymbol->getResolvedMethod()->signatureChars();
950
char *callerExpandedArgsStart = callerSignature + _argPlaceholderSignatureOffset;
951
int32_t lengthOfExpandedArgs = strcspn(callerExpandedArgsStart, ")");
952
TR::SymbolReference *placeholderSymRef = placeholderWithSignature("(", 1, callerExpandedArgsStart, lengthOfExpandedArgs, ")I", 2);
953
push(genNodeAndPopChildren(TR::icall, numNodesGenerated, placeholderSymRef));
954
}
955
956
static bool isPlaceholderCall(TR::Node *node)
957
{
958
if (node->getOpCode().isCall() && node->getSymbol()->getResolvedMethodSymbol())
959
return node->getSymbol()->castToResolvedMethodSymbol()->getMandatoryRecognizedMethod() == TR::java_lang_invoke_ILGenMacros_placeholder;
960
else
961
return false;
962
}
963
964
int32_t
965
TR_J9ByteCodeIlGenerator::expandPlaceholderCall()
966
{
967
TR::Node *placeholder = pop();
968
TR_ASSERT(isPlaceholderCall(placeholder), "expandPlaceholderCall expects placeholder call on top of stack");
969
if (comp()->getOption(TR_TraceILGen))
970
traceMsg(comp(), " Expanding placeholder call %s\n", comp()->getDebug()->getName(placeholder->getSymbolReference()));
971
for (int i = 0; i < placeholder->getNumChildren(); i++)
972
push(placeholder->getAndDecChild(i));
973
return placeholder->getNumChildren()-1; // there was already 1 for the placeholder itself
974
}
975
976
TR::SymbolReference *
977
TR_J9ByteCodeIlGenerator::expandPlaceholderSignature(TR::SymbolReference *symRef, int32_t numArgs)
978
{
979
return expandPlaceholderSignature(symRef, numArgs, numArgs);
980
}
981
982
TR::SymbolReference *
983
TR_J9ByteCodeIlGenerator::expandPlaceholderSignature(TR::SymbolReference *symRef, int32_t numArgs, int32_t firstArgStackDepth)
984
{
985
if (!symRef->getSymbol()->getResolvedMethodSymbol())
986
return symRef;
987
988
TR_ResolvedMethod *originalMethod = symRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod();
989
990
int32_t firstArgStackOffset = _stack->size() - firstArgStackDepth;
991
int32_t currentArgSignatureOffset = 1; // skip parenthesis
992
for (int32_t childIndex = originalMethod->isStatic()? 0 : 1; childIndex < numArgs; childIndex++)
993
{
994
int32_t explicitArgIndex = childIndex - (originalMethod->isStatic()? 0 : 1);
995
TR_ResolvedMethod *symRefMethod = symRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod();
996
char *signatureChars = symRefMethod->signatureChars();
997
int nextArgSignatureOffset = nextSignatureArgument(signatureChars + currentArgSignatureOffset) - signatureChars;
998
999
TR_ASSERT(signatureChars[currentArgSignatureOffset] != ')', "expandPlaceholderSignature must not walk past the end of the argument portion of the signature");
1000
1001
TR::Node *child = _stack->element(firstArgStackOffset + childIndex);
1002
if (isPlaceholderCall(child))
1003
{
1004
// Replace the current argument's signature chars with the chars between the parentheses of the child's signature
1005
int32_t signatureLength = symRefMethod->signatureLength();
1006
char *childSignatureChars = child->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->signatureChars();
1007
int32_t numCharsInserted = strcspn(childSignatureChars+1, ")");
1008
symRef = symRefWithArtificialSignature(symRef,
1009
".#.#.#", // TODO:JSR292: It may be possible to simplify this logic drastically with a more clever format
1010
signatureChars, currentArgSignatureOffset,
1011
childSignatureChars+1, numCharsInserted,
1012
signatureChars+nextArgSignatureOffset, signatureLength - nextArgSignatureOffset);
1013
// This doesn't work...
1014
// "(-**)$",
1015
// symRefMethod->signatureChars(), 0, explicitArgIndex-1, // first n-1 args
1016
// childSignatureChars, 0, // child's args in place of current arg
1017
// symRefMethod->signatureChars(), explicitArgIndex+1, // last m args
1018
// symRefMethod->signatureChars() // return type
1019
// );
1020
currentArgSignatureOffset += numCharsInserted;
1021
}
1022
else
1023
{
1024
currentArgSignatureOffset = nextArgSignatureOffset;
1025
}
1026
}
1027
return symRef;
1028
}
1029
1030
int32_t
1031
TR_J9ByteCodeIlGenerator::numPlaceholderCalls(int32_t depthLimit)
1032
{
1033
int32_t result = 0;
1034
for (int32_t i = 0; i < depthLimit; i++)
1035
if (isPlaceholderCall(_stack->element(_stack->topIndex()-i)))
1036
result++;
1037
return result;
1038
}
1039
1040
int32_t
1041
TR_J9ByteCodeIlGenerator::expandPlaceholderCalls(int32_t depthLimit)
1042
{
1043
if (depthLimit <= 0)
1044
{
1045
return 0;
1046
}
1047
else
1048
{
1049
TR::Node *topNode = pop();
1050
int32_t numAdditionalNodes = expandPlaceholderCalls(depthLimit-1);
1051
push(topNode);
1052
if (isPlaceholderCall(_stack->element(_stack->topIndex())))
1053
numAdditionalNodes += expandPlaceholderCall();
1054
return numAdditionalNodes;
1055
}
1056
}
1057
1058
TR::Node *
1059
TR_J9ByteCodeIlGenerator::genNodeAndPopChildren(TR::ILOpCodes opcode, int32_t numChildren, TR::SymbolReference * symRef, int32_t firstIndex, int32_t lastIndex)
1060
{
1061
if (numPlaceholderCalls(lastIndex-firstIndex+1) > 0) // JSR292
1062
{
1063
symRef = expandPlaceholderSignature(symRef, lastIndex-firstIndex+1);
1064
int32_t numAdditionalNodes = expandPlaceholderCalls(lastIndex-firstIndex+1);
1065
numChildren += numAdditionalNodes;
1066
lastIndex += numAdditionalNodes;
1067
1068
if (comp()->getOption(TR_TraceILGen))
1069
{
1070
traceMsg(comp(), " Expanded placeholder(s) needing %d additional nodes -- resulting symref: %s\n", numAdditionalNodes, comp()->getDebug()->getName(symRef));
1071
1072
TR::StackMemoryRegion stackMemoryRegion(*comp()->trMemory());
1073
1074
TR_BitVector before(comp()->getNodeCount(), trMemory(), stackAlloc, growable);
1075
printStack(comp(), _stack, "stack after expandPlaceholderCalls");
1076
comp()->getDebug()->restoreNodeChecklist(before);
1077
}
1078
}
1079
1080
TR::Node * node = TR::Node::createWithSymRef(opcode, numChildren, symRef);
1081
for (int32_t i = lastIndex; i >= firstIndex; --i)
1082
node->setAndIncChild(i, pop());
1083
return node;
1084
}
1085
1086
TR::Node *
1087
TR_J9ByteCodeIlGenerator::genNodeAndPopChildren(TR::ILOpCodes opcode, int32_t numChildren, TR::SymbolReference * symRef, int32_t firstIndex)
1088
{
1089
return genNodeAndPopChildren(opcode, numChildren, symRef, firstIndex, numChildren-1);
1090
}
1091
1092
void
1093
TR_J9ByteCodeIlGenerator::genUnary(TR::ILOpCodes unaryOp, bool isForArrayAccess)
1094
{
1095
TR::Node *node = TR::Node::create(unaryOp, 1, pop());
1096
if(isForArrayAccess)
1097
{
1098
if (comp()->getOption(TR_TraceILGen))
1099
{
1100
traceMsg(comp(), "setting i2l node %p n%dn non-negative because it's for array access\n");
1101
}
1102
node->setIsNonNegative(true);
1103
}
1104
push(node);
1105
}
1106
1107
bool
1108
TR_J9ByteCodeIlGenerator::swapChildren(TR::ILOpCodes nodeop, TR::Node * firstChild)
1109
{
1110
return TR::ILOpCode(nodeop).getOpCodeForSwapChildren() &&
1111
(firstChild->getOpCode().isLoadConst() ||
1112
(firstChild->getOpCode().isLoadVar() && firstChild->getSymbol()->isConst()));
1113
}
1114
1115
void
1116
TR_J9ByteCodeIlGenerator::genBinary(TR::ILOpCodes nodeop, int32_t numChildren)
1117
{
1118
TR::Node * second = pop();
1119
TR::Node * first = pop();
1120
if (swapChildren(nodeop, first))
1121
push(TR::Node::create(TR::ILOpCode(nodeop).getOpCodeForSwapChildren(), numChildren, second, first));
1122
else
1123
push(TR::Node::create(nodeop, numChildren, first, second));
1124
}
1125
1126
TR::TreeTop *
1127
TR_J9ByteCodeIlGenerator::genTreeTop(TR::Node * n)
1128
{
1129
if (!n->getOpCode().isTreeTop())
1130
n = TR::Node::create(TR::treetop, 1, n);
1131
1132
//In involuntaryOSR, exception points are OSR points but we don't need to
1133
//handle pending pushes for them because the operand stack is always empty at catch.
1134
bool isExceptionOnlyPoint = comp()->getOSRMode() == TR::involuntaryOSR && !n->canGCandReturn() && n->canGCandExcept();
1135
if (comp()->getOption(TR_TraceOSR))
1136
traceMsg(comp(), "skip saving PPS for exceptionOnlyPoints %d node n%dn\n", isExceptionOnlyPoint, n->getGlobalIndex());
1137
1138
// It is not necessary to save the stack under OSR if the bytecode index or caller has been marked as cannotAttemptOSR
1139
bool cannotAttemptOSR = comp()->getOption(TR_EnableOSR) && !comp()->isPeekingMethod() &&
1140
(_methodSymbol->cannotAttemptOSRAt(n->getByteCodeInfo(), NULL, comp()) || _cannotAttemptOSR);
1141
if (comp()->getOption(TR_TraceOSR) && cannotAttemptOSR)
1142
traceMsg(comp(), "skip saving PPS for cannotAttemptOSR at %d:%d node n%dn\n", n->getByteCodeIndex(), n->getByteCodeInfo().getCallerIndex(), n->getGlobalIndex());
1143
1144
if (!comp()->isPeekingMethod() && comp()->isPotentialOSRPoint(n) && !isExceptionOnlyPoint && !cannotAttemptOSR)
1145
{
1146
static const char *OSRPPSThreshold;
1147
static int32_t osrPPSThresh = (OSRPPSThreshold = feGetEnv("TR_OSRPPSThreshold")) ? atoi(OSRPPSThreshold) : 0;
1148
static const char *OSRTotalPPSThreshold;
1149
static int32_t osrTotalPPSThresh = (OSRTotalPPSThreshold = feGetEnv("TR_OSRTotalPPSThreshold")) ? atoi(OSRTotalPPSThreshold) : 0;
1150
1151
static const char *OSRPPSThresholdOutsideLoops;
1152
static int32_t osrPPSThreshOutsideLoops = (OSRPPSThresholdOutsideLoops = feGetEnv("TR_OSRPPSThresholdOutsideLoops")) ? atoi(OSRPPSThresholdOutsideLoops) : 0;
1153
static const char *OSRTotalPPSThresholdOutsideLoops;
1154
static int32_t osrTotalPPSThreshOutsideLoops = (OSRTotalPPSThresholdOutsideLoops = feGetEnv("TR_OSRTotalPPSThresholdOutsideLoops")) ? atoi(OSRTotalPPSThresholdOutsideLoops) : 0;
1155
1156
static const char *OSRLoopNestingThreshold;
1157
static int32_t osrLoopNestingThresh = (OSRLoopNestingThreshold = feGetEnv("TR_OSRLoopNestingThreshold")) ? atoi(OSRLoopNestingThreshold) : 1;
1158
1159
static const char *OSRIndirectCallBCThreshold;
1160
static int32_t osrIndirectCallBCThresh = (OSRIndirectCallBCThreshold = feGetEnv("TR_OSRIndirectCallBCThreshold")) ? atoi(OSRIndirectCallBCThreshold) : 0;
1161
1162
bool OSRTooExpensive = false;
1163
if ((n->getNumChildren() > 0) && !comp()->getOption(TR_EnableOSROnGuardFailure) && comp()->getHCRMode() != TR::osr &&
1164
1165
(((comp()->getNumLoopNestingLevels() == 0) &&
1166
((((int32_t) _stack->size()) > osrPPSThreshOutsideLoops) || true ||
1167
((((int32_t) _stack->size() + (int32_t) comp()->getNumLivePendingPushSlots())) > osrTotalPPSThreshOutsideLoops))) ||
1168
1169
((comp()->getNumLoopNestingLevels() >= osrLoopNestingThresh) &&
1170
((((int32_t) _stack->size()) > osrPPSThresh) ||
1171
((((int32_t) _stack->size() + (int32_t) comp()->getNumLivePendingPushSlots())) > osrTotalPPSThresh))) ||
1172
1173
(n->getFirstChild()->getOpCode().isCallIndirect() &&
1174
(n->getFirstChild()->getSymbolReference()->isUnresolved() || true || // turned OSR off for indirect calls for 727 due to failed guards being seen
1175
n->getFirstChild()->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->virtualMethodIsOverridden() ||
1176
comp()->getPersistentInfo()->isClassLoadingPhase() ||
1177
(comp()->getOption(TR_EnableHCR) &&
1178
(!n->getFirstChild()->getSecondChild()->getOpCode().isLoadVarDirect() || !n->getFirstChild()->getSecondChild()->getSymbol()->isParm())) ||
1179
(n->getFirstChild()->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->maxBytecodeIndex() > osrIndirectCallBCThresh)))
1180
))
1181
{
1182
OSRTooExpensive = true;
1183
if (n->getFirstChild()->getOpCode().isCall() && !comp()->getOption(TR_FullSpeedDebug) && comp()->getOption(TR_EnableOSR))
1184
{
1185
if (comp()->getOption(TR_TraceOSR))
1186
traceMsg(comp(), "Skipping OSR due to cost at bci %d.%d\n", comp()->getCurrentInlinedSiteIndex(), n->getFirstChild()->getByteCodeIndex());
1187
_methodSymbol->setCannotAttemptOSR(n->getFirstChild()->getByteCodeIndex());
1188
}
1189
}
1190
1191
if ((comp()->getOption(TR_MimicInterpreterFrameShape) ||
1192
comp()->getOption(TR_FullSpeedDebug) ||
1193
comp()->getHCRMode() == TR::osr ||
1194
((n->getNumChildren() > 0) && n->getFirstChild()->getOpCode().isCall() && !OSRTooExpensive && comp()->getOption(TR_EnableOSR)))
1195
&& !comp()->isPeekingMethod())
1196
{
1197
if (comp()->isOSRTransitionTarget(TR::postExecutionOSR))
1198
{
1199
// When transitioning to a call bytecode, the VM requires that its
1200
// arguments be provided as children to the induce call
1201
// As the transition will occur at the next bytecode in post
1202
// execution, ensure the arguments for the next bytecode are
1203
// stashed
1204
//
1205
_couldOSRAtNextBC = true;
1206
if ((n->getOpCode().isCheck() || n->getOpCodeValue() == TR::treetop) && n->getFirstChild()->getOpCode().isCall())
1207
{
1208
// Calls are only OSR points for their first evaluation. Other references to the call,
1209
// that are also anchored under checks or treetops, are not OSR points. This can be
1210
// identified based on a node checklist, as the reference count may be unreliable.
1211
//
1212
if (!_processedOSRNodes->contains(n->getFirstChild()))
1213
{
1214
_processedOSRNodes->add(n->getFirstChild());
1215
1216
// The current stack should contain the current method's state prior to the call,
1217
// with the call's arguments popped off. If this call is later inlined, it may
1218
// contain an OSR transition. Therefore, it is necessary to save the current
1219
// method's state now, so that it is available when the transition is made.
1220
handlePendingPushSaveSideEffects(n);
1221
saveStack(-1);
1222
stashPendingPushLivenessForOSR();
1223
}
1224
else if (comp()->getOption(TR_TraceOSR))
1225
{
1226
traceMsg(comp(), "Skipping OSR stack state for repeated call n%dn in treetop n%dn\n", n->getFirstChild()->getGlobalIndex(), n->getGlobalIndex());
1227
}
1228
1229
return _block->append(TR::TreeTop::create(comp(), n));
1230
}
1231
else
1232
{
1233
// Save the stack after the treetop has been created and appended
1234
handlePendingPushSaveSideEffects(n);
1235
TR::TreeTop *toReturn = _block->append(TR::TreeTop::create(comp(), n));
1236
saveStack(-1, !comp()->pendingPushLivenessDuringIlgen());
1237
stashPendingPushLivenessForOSR(comp()->getOSRInductionOffset(n));
1238
1239
return toReturn;
1240
}
1241
}
1242
else
1243
{
1244
handlePendingPushSaveSideEffects(n);
1245
1246
// saveStack(-1) actually stores out the current PPS to the PPS save
1247
// region so that the FSD stackwalker can copy it to the VM frame as
1248
// part of decompilation
1249
//
1250
saveStack(-1);
1251
stashPendingPushLivenessForOSR();
1252
}
1253
}
1254
}
1255
return _block->append(TR::TreeTop::create(comp(), n));
1256
}
1257
1258
void
1259
TR_J9ByteCodeIlGenerator::removeIfNotOnStack(TR::Node *n)
1260
{
1261
startCountingStackRefs();
1262
n->incReferenceCount();
1263
n->recursivelyDecReferenceCount();
1264
stopCountingStackRefs();
1265
}
1266
1267
void
1268
TR_J9ByteCodeIlGenerator::popAndDiscard(int n)
1269
{
1270
TR_ASSERT(n >= 0, "Number of nodes to pop and discard must be non-negative");
1271
startCountingStackRefs();
1272
for (int i = 0; i < n; i++)
1273
pop()->recursivelyDecReferenceCount();
1274
stopCountingStackRefs();
1275
}
1276
1277
void
1278
TR_J9ByteCodeIlGenerator::discardEntireStack()
1279
{
1280
startCountingStackRefs();
1281
while (!_stack->isEmpty())
1282
pop()->recursivelyDecReferenceCount();
1283
// stack is empty, no need to stopCountingStackRefs()
1284
}
1285
1286
void
1287
TR_J9ByteCodeIlGenerator::startCountingStackRefs()
1288
{
1289
for (int i = 0; i < _stack->size(); i++)
1290
_stack->element(i)->incReferenceCount();
1291
}
1292
1293
void
1294
TR_J9ByteCodeIlGenerator::stopCountingStackRefs()
1295
{
1296
for (int i = 0; i < _stack->size(); i++)
1297
_stack->element(i)->decReferenceCount();
1298
}
1299
1300
// saveStack is called to save the operand stack, normally when it might
1301
// be live across BB (as in the call from genTarget). In addition, in
1302
// FSD mode, saveStack is sometimes called with no target block (with
1303
// targetIndex < 0), which means we're saving pending pop slots (PPS) at a
1304
// decompilation point (GC return point?) for FSD.
1305
//
1306
// In any case we store each operand stack/PPS (Pending Pop Stack) slot
1307
// to a region of the frame used exclusively for saving and restoring
1308
// PPS slots.
1309
//
1310
// if there is no PPS (Pending Pop Stack) for the target bytecode
1311
// (Which must be the first in the target bb) we create one which is
1312
// subsequently initialized with the current PPS. This is just a
1313
// lazy initialization.
1314
//
1315
// When a bb is translated _stackTemps initially is a copy of the
1316
// upwardly exposed operand stack to the current bb(?) Then, as slot i
1317
// is saved by this method _stackTemps[i] is set to the node
1318
// representing the value stored. This allows us to trivially avoid
1319
// redundantly saving the same slot over and over. (Presumably this is
1320
// primarily useful at decompilation points in FSD mode though it would
1321
// also avoid saving slots that flow through a block undisturbed.)
1322
//
1323
// The code below appears to save all PPS deeper than _stackTemp but
1324
// only those shallower which are not the same as the corresponding
1325
// slots in _stackTemp. Presumably this is because it is not necessary
1326
// to save a PPS that already must have been saved on entry to the
1327
// current block, ie: when (i <= _stackTemps.topIndex())
1328
//
1329
// Finally, when we are initializing a target block, we add the live
1330
// slots to the target bb's initial stack_. This is okay even if there
1331
// are multiple successors because the JVM spec requires that the
1332
// incoming PPS to each successor bb must be identical.
1333
//
1334
// int parm targetIndex indicates bytecode index of first op in the target bb.
1335
// bool parm anchorLoads will ensure any pending push temps that have not
1336
// been modified since the last call to saveStack will have the corresponding
1337
// pending push slot anchored
1338
//
1339
void
1340
TR_J9ByteCodeIlGenerator::saveStack(int32_t targetIndex)
1341
{
1342
saveStack(targetIndex, false);
1343
}
1344
1345
void
1346
TR_J9ByteCodeIlGenerator::saveStack(int32_t targetIndex, bool anchorLoads)
1347
{
1348
if (_stack->isEmpty())
1349
return;
1350
1351
static const char *disallowOSRPPS2 = feGetEnv("TR_DisallowOSRPPS2");
1352
bool loadPP = !disallowOSRPPS2 && comp()->getOption(TR_EnableOSR) && !comp()->isOSRTransitionTarget(TR::postExecutionOSR);
1353
bool createTargetStack = (targetIndex >= 0 && !_stacks[targetIndex]);
1354
if (createTargetStack)
1355
_stacks[targetIndex] = new (trStackMemory()) ByteCodeStack(trMemory(), std::max<uint32_t>(20, _stack->size()));
1356
1357
int32_t i;
1358
int32_t tempIndex = 0;
1359
for (i = 0; i < _stack->size(); ++i)
1360
{
1361
if (!isPlaceholderCall(_stack->element(i)))
1362
{
1363
if (_stackTemps.topIndex() < tempIndex || _stackTemps[tempIndex] != _stack->element(i))
1364
handlePendingPushSaveSideEffects(_stack->element(i), tempIndex);
1365
tempIndex++;
1366
}
1367
else
1368
{
1369
for (int32_t j = 0; j < _stack->element(i)->getNumChildren(); ++j)
1370
{
1371
TR::Node* child = _stack->element(i)->getChild(j);
1372
if (_stackTemps.topIndex() < tempIndex || _stackTemps[tempIndex] != child)
1373
handlePendingPushSaveSideEffects(child, tempIndex);
1374
tempIndex++;
1375
}
1376
}
1377
}
1378
1379
// There are three different indices here:
1380
// tempIndex: Index into stackTemps, which must take into account the additional children under placeholder calls
1381
// slot: The pending push slot, which must take into account the number of slots required by each node on the stack
1382
// i: Index into _stack
1383
//
1384
int32_t slot = 0;
1385
tempIndex = 0;
1386
for (i = 0; i < _stack->size(); ++i)
1387
{
1388
TR::Node * n = _stack->element(i);
1389
1390
if (!isPlaceholderCall(n))
1391
{
1392
TR::SymbolReference * symRef = symRefTab()->findOrCreatePendingPushTemporary(_methodSymbol, slot, getDataType(n));
1393
if (_stackTemps.topIndex() < tempIndex || _stackTemps[tempIndex] != n)
1394
{
1395
genTreeTop(TR::Node::createStore(symRef, n));
1396
1397
// Under preExecutionOSR, the stack elements are saved to pending push temps and then the corresponding
1398
// slots on the stack are replaced by loads of these temps. This ensures the pending push temp appears live
1399
// across any OSR points, due to the use of the load when it is popped off the stack.
1400
//
1401
if (loadPP)
1402
{
1403
TR::Node *load = TR::Node::createLoad(symRef);
1404
(*_stack)[i] = load;
1405
_stackTemps[tempIndex] = load;
1406
}
1407
else
1408
_stackTemps[tempIndex] = n;
1409
}
1410
1411
// Under postExecutionOSR, the stack elements are saved to pending push slots but the corresponding slots on the stack
1412
// are not modified. Instead, calls to saveStack where anchorLoads is true will achieve the same effect for liveness
1413
// by generating anchored loads of any pending push slots that have not been modified. There will be several superfluous
1414
// loads, but they can be cleaned up in genILOpts once the OSR liveness analysis is complete.
1415
//
1416
else if (anchorLoads
1417
&& comp()->getOption(TR_EnableOSR)
1418
&& comp()->isOSRTransitionTarget(TR::postExecutionOSR)
1419
&& _stackTemps[tempIndex] == n
1420
&& !(n->getOpCode().hasSymbolReference() && n->getSymbolReference() == symRef))
1421
genTreeTop(TR::Node::createLoad(symRef));
1422
1423
// this arranges that PPS i is reloaded on entry to the successor
1424
// basic block, which is the one starting at bytecode index targetIndex
1425
//
1426
if (createTargetStack)
1427
(*_stacks[targetIndex])[i] = TR::Node::createLoad(symRef);
1428
1429
slot += n->getNumberOfSlots();
1430
tempIndex++;
1431
}
1432
else
1433
{
1434
// A placeholder call has several children which represent the true contents of the stack
1435
// For correctness, these children should be stored into pending push slots
1436
//
1437
for (int32_t j = 0; j < n->getNumChildren(); ++j)
1438
{
1439
TR::Node* child = n->getChild(j);
1440
TR::SymbolReference * symRef = symRefTab()->findOrCreatePendingPushTemporary(_methodSymbol, slot, getDataType(child));
1441
if (_stackTemps.topIndex() < tempIndex || _stackTemps[tempIndex] != child)
1442
{
1443
genTreeTop(TR::Node::createStore(symRef, child));
1444
1445
if (loadPP)
1446
{
1447
TR::Node *load = TR::Node::createLoad(symRef);
1448
child->recursivelyDecReferenceCount();
1449
n->setAndIncChild(j, load);
1450
_stackTemps[tempIndex] = load;
1451
}
1452
else
1453
_stackTemps[tempIndex] = child;
1454
}
1455
else if (anchorLoads
1456
&& comp()->getOption(TR_EnableOSR)
1457
&& comp()->isOSRTransitionTarget(TR::postExecutionOSR)
1458
&& _stackTemps[tempIndex] == child
1459
&& !(child->getOpCode().hasSymbolReference() && child->getSymbolReference() == symRef))
1460
genTreeTop(TR::Node::createLoad(symRef));
1461
1462
slot += child->getNumberOfSlots();
1463
tempIndex++;
1464
}
1465
1466
// For this to be supported, pending push loads would always have to replace the placeholder's children in
1467
// all conditions
1468
TR_ASSERT_FATAL(!createTargetStack, "Cannot store and later load placeholder calls in current implementation");
1469
}
1470
}
1471
}
1472
1473
// Bad code results if code following saveStack generated stores
1474
// attempts to load from one of the saved PPS slots. Two obvious
1475
// examples arise. For the first example see the comment before
1476
// TR_J9ByteCodeIlGenerator::genIfImp. Second, consider a treetop preceding a
1477
// decompilation point. Nodes loaded from the PPS save region (i.e that
1478
// were live on entry to the block) may be referred to by treetops on
1479
// both sides of the decompilation point and thus may be killed by the
1480
// stores (soon to be) generated by saveStack.
1481
//
1482
// In both these scenarios the problem is that saveStack assumes the
1483
// execution mode of bytecode rather than the TR IL. The saveStack
1484
// method simply walks the simulated operand stack and generates a
1485
// store treetop for each Node it finds on the simulated stack. This,
1486
// like bytecode, assumes that operations are completed at the time
1487
// values are pushed on the simulated stack.
1488
//
1489
// Meanwhile, TR IL is being generated that refers to Nodes popped off
1490
// the stack. The assumption here is that the order of operations is
1491
// unconstrained other than by the data flow implied by the trees of
1492
// references to nodes and by the control dependencies imposed by the
1493
// order of treetops. The latter are implied by the semantics of each
1494
// bytecode.
1495
//
1496
// The job of handlePendingPushSaveSideEffects is to add additional
1497
// implicit control dependencies to the TR IL caused by the
1498
// decompilation points. All loads of the PPS save region must occur
1499
// before decompilation points except in the specific case when the load
1500
// would redundantly reload a value already in the PPS.
1501
//
1502
// If handlePendingPushSaveSideEffects is being called on the stack
1503
// contents in saveStack, before they are stored in to pending push temps,
1504
// it is possible to eliminate some of the excess anchored pending push
1505
// loads generated by this function using the stackSize parm. As
1506
// the pending pushes are modified in ascending order, it is safe to assume
1507
// any pending push slots equal to the current stack slot or greater have
1508
// not yet been stored to and are, therefore, safe to load from.
1509
//
1510
void
1511
TR_J9ByteCodeIlGenerator::handlePendingPushSaveSideEffects(TR::Node * n, int32_t stackSize)
1512
{
1513
if (_stack->size() == 0)
1514
return;
1515
1516
TR::NodeChecklist checklist(comp());
1517
handlePendingPushSaveSideEffects(n, checklist, stackSize);
1518
}
1519
1520
void
1521
TR_J9ByteCodeIlGenerator::handlePendingPushSaveSideEffects(TR::Node * n, TR::NodeChecklist &checklist, int32_t stackSize)
1522
{
1523
if (checklist.contains(n))
1524
return;
1525
checklist.add(n);
1526
1527
// if any tree on the stack can be modified by the sideEffect then the node
1528
// on the stack must become a treetop before the sideEffect node is evaluated
1529
//
1530
for (int32_t i = n->getNumChildren() - 1; i >= 0; --i)
1531
handlePendingPushSaveSideEffects(n->getChild(i), checklist, stackSize);
1532
1533
// constant pool indices less than 0 indicate loads from saved pending
1534
// pop slot locations. In addition, the value is the negation of the
1535
// PPS slot number the load is to.
1536
//
1537
if (n->getOpCode().isLoadVarDirect() && n->getSymbolReference()->isTemporary(comp()) && n->getSymbolReference()->getCPIndex() < 0)
1538
{
1539
// loadSlot: the pending push slot being loaded from
1540
int32_t loadSlot = -n->getSymbolReference()->getCPIndex() - 1;
1541
// absStackSlot: index into stack elements, taking placeholder children into account
1542
int32_t absStackSlot = 0;
1543
// child: keep track of placeholder children if necessary
1544
int32_t child = -1;
1545
// modifiedSlot: iterate through the slots currently in use
1546
int32_t modifiedSlot = 0;
1547
// i: iterate through the stack elements
1548
int32_t i = 0;
1549
for (i = 0; i < _stack->size(); ++i)
1550
{
1551
if (!isPlaceholderCall(_stack->element(i)))
1552
{
1553
if (modifiedSlot >= loadSlot)
1554
{
1555
child = -1;
1556
break;
1557
}
1558
modifiedSlot += _stack->element(i)->getNumberOfSlots();
1559
absStackSlot++;
1560
}
1561
else
1562
{
1563
for (child = 0; child < _stack->element(i)->getNumChildren(); ++child)
1564
{
1565
if (modifiedSlot >= loadSlot)
1566
break;
1567
modifiedSlot += _stack->element(i)->getChild(child)->getNumberOfSlots();
1568
absStackSlot++;
1569
}
1570
if (child < _stack->element(i)->getNumChildren())
1571
break;
1572
}
1573
}
1574
1575
// If there is a node on the stack that has uses the same slot, it could result in the pending push temp
1576
// being modified when the stack is saved, so it is anchored
1577
//
1578
if (modifiedSlot == loadSlot
1579
&& (stackSize == -1 || stackSize > absStackSlot)
1580
&& i < _stack->size()
1581
&& ((child >= 0 && _stack->element(i)->getChild(child) != n) || (child == -1 && _stack->element(i) != n)))
1582
{
1583
genTreeTop(n);
1584
}
1585
}
1586
}
1587
1588
bool
1589
TR_J9ByteCodeIlGenerator::isAtBBStart(int32_t bcIndex)
1590
{
1591
return blocks(bcIndex) && blocks(bcIndex)->getEntry()->getNode()->getByteCodeIndex() == bcIndex;
1592
}
1593
/*
1594
* Stash the required number of arguments for the provided bytecode.
1595
* The current stack will be walked, determining pending push temps for
1596
* the required arguments. It is assumed that the arguments would have
1597
* already been stored to these symrefs.
1598
*/
1599
void
1600
TR_J9ByteCodeIlGenerator::stashArgumentsForOSR(TR_J9ByteCode byteCode)
1601
{
1602
if (!_couldOSRAtNextBC &&
1603
!isAtBBStart(_bcIndex)) // _couldOSRAtNextBC doesn't work if the curent bc is at bbstart,
1604
// conversatively assume OSR transition can happen at bbstart
1605
return;
1606
_couldOSRAtNextBC = false;
1607
1608
if (comp()->isPeekingMethod()
1609
|| !comp()->getOption(TR_EnableOSR)
1610
|| _cannotAttemptOSR
1611
|| !comp()->isOSRTransitionTarget(TR::postExecutionOSR))
1612
return;
1613
1614
// Determine the symref to extract the number of arguments required by this bytecode
1615
TR::SymbolReference *symRef;
1616
// Check if cp entry is resolved, used by invokedynamic and invokehandle in OpenJDK MethodHandle implementation
1617
bool unresolvedInCP = false;
1618
switch (byteCode)
1619
{
1620
case J9BCinvokevirtual:
1621
symRef = symRefTab()->findOrCreateVirtualMethodSymbol(_methodSymbol, next2Bytes());
1622
break;
1623
case J9BCinvokespecial:
1624
symRef = symRefTab()->findOrCreateSpecialMethodSymbol(_methodSymbol, next2Bytes());
1625
break;
1626
case J9BCinvokestatic:
1627
symRef = symRefTab()->findOrCreateStaticMethodSymbol(_methodSymbol, next2Bytes());
1628
break;
1629
case J9BCinvokeinterface:
1630
symRef = symRefTab()->findOrCreateInterfaceMethodSymbol(_methodSymbol, next2Bytes());
1631
break;
1632
case J9BCinvokeinterface2:
1633
symRef = symRefTab()->findOrCreateInterfaceMethodSymbol(_methodSymbol, next2Bytes(3));
1634
break;
1635
case J9BCinvokedynamic:
1636
symRef = symRefTab()->findOrCreateDynamicMethodSymbol(_methodSymbol, next2Bytes(), &unresolvedInCP);
1637
break;
1638
case J9BCinvokehandle:
1639
case J9BCinvokehandlegeneric:
1640
symRef = symRefTab()->findOrCreateHandleMethodSymbol(_methodSymbol, next2Bytes(), &unresolvedInCP);
1641
break;
1642
case J9BCinvokestaticsplit:
1643
symRef = symRefTab()->findOrCreateStaticMethodSymbol(_methodSymbol, next2Bytes() | J9_STATIC_SPLIT_TABLE_INDEX_FLAG);
1644
break;
1645
case J9BCinvokespecialsplit:
1646
symRef = symRefTab()->findOrCreateSpecialMethodSymbol(_methodSymbol, next2Bytes() | J9_SPECIAL_SPLIT_TABLE_INDEX_FLAG);
1647
break;
1648
default:
1649
return;
1650
}
1651
1652
TR::MethodSymbol *symbol = symRef->getSymbol()->castToMethodSymbol();
1653
int32_t numArgs = symbol->getMethod()->numberOfExplicitParameters() + (symbol->isStatic() ? 0 : 1);
1654
1655
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
1656
// If the transition target is invokehandle/invokedynamic, the arguments to be
1657
// stashed are those already pushed onto the stack before generating the bytecode,
1658
// regardless of the number of arguments needed by the generated call.
1659
//
1660
// The generated call requires one (in resolved case) or two (in unresolved case)
1661
// implicit arguments, so we need to substract them to get the actual number of
1662
// arguments needed.
1663
// The reason why we don't need to stash the implicit arguments is because when we
1664
// transition to the VM, VM will push the implicit argument onto the stack, this is
1665
// part of the behavior of the invokehandle/invokedynamic bytecode.
1666
//
1667
// The method to call is determined by the MemberName object from the side table.
1668
// In the resolved case, one implicit object is passed as the last argument to the
1669
// call, it is the appendixObject from side table.
1670
//
1671
// When the side table entry is unresolved, this object is unknown, thus, the JIT
1672
// doesn't know what method to call at compile time. To represent the unresolved
1673
// case, the JIT uses MethodHandle.linkToStatic to represent the call.
1674
// In addtion to the appendixObject, the MemberName object is also needed, thus
1675
// the call requires two more arguments that what's on the stack.
1676
//
1677
// Resolved case:
1678
// adapter(arg1, arg2, ..., argN, appendixObject)
1679
// Unresolved case:
1680
// MethodHandle.linkToStatic(arg1, arg2, ..., argN, appendixObject, MemberName)
1681
//
1682
// Notice that we always generate a resolved call, thus we use unresolvedInCP to tell
1683
// us whether the side table entry is resolved
1684
//
1685
if (byteCode == J9BCinvokedynamic ||
1686
byteCode == J9BCinvokehandle)
1687
{
1688
numArgs -= 1;
1689
if (unresolvedInCP)
1690
numArgs -= 1;
1691
1692
if (trace())
1693
traceMsg(comp(), "Num args %d for invokedynamic/handle, stack size %d\n", numArgs, _stack->size());
1694
}
1695
#endif
1696
1697
TR_OSRMethodData *osrMethodData =
1698
comp()->getOSRCompilationData()->findOrCreateOSRMethodData(comp()->getCurrentInlinedSiteIndex(), _methodSymbol);
1699
osrMethodData->ensureArgInfoAt(_bcIndex, numArgs);
1700
1701
// Walk the stack, grabbing that last numArgs elements
1702
// It is necessary to walk the whole stack to determine the slot numbers
1703
int32_t slot = 0;
1704
int arg = 0;
1705
for (int32_t i = 0; i < _stack->size(); ++i)
1706
{
1707
TR::Node * n = _stack->element(i);
1708
if (_stack->size() - numArgs <= i)
1709
{
1710
TR::SymbolReference * symRef = symRefTab()->findOrCreatePendingPushTemporary(_methodSymbol, slot, getDataType(n));
1711
osrMethodData->addArgInfo(_bcIndex, arg, symRef->getReferenceNumber());
1712
arg++;
1713
}
1714
slot += n->getNumberOfSlots();
1715
}
1716
}
1717
1718
// Under voluntary OSR, it is preferable to keep only the essential symrefs live
1719
// for the transition. Computing the liveness can be costly however. To reduce
1720
// this compile time overhead, pending push liveness can be solved during IlGen.
1721
//
1722
// This method will solve the liveness for the current bci with the offset applied
1723
// and stash the result against the OSR method data.
1724
void
1725
TR_J9ByteCodeIlGenerator::stashPendingPushLivenessForOSR(int32_t offset)
1726
{
1727
if (!comp()->pendingPushLivenessDuringIlgen())
1728
return;
1729
1730
TR_OSRMethodData *osrData = comp()->getOSRCompilationData()->findOrCreateOSRMethodData(
1731
comp()->getCurrentInlinedSiteIndex(), comp()->getMethodSymbol());
1732
1733
// Reset any existing pending push mapping
1734
// This is due to the overlap with arg stashing
1735
TR_BitVector *livePP = osrData->getPendingPushLivenessInfo(_bcIndex + offset);
1736
if (livePP)
1737
livePP->empty();
1738
1739
int32_t slot = 0;
1740
int arg = 0;
1741
for (int32_t i = 0; i < _stack->size(); ++i)
1742
{
1743
TR::Node *n = _stack->element(i);
1744
TR::SymbolReference *symRef = symRefTab()->findOrCreatePendingPushTemporary(_methodSymbol, slot, getDataType(n));
1745
if (livePP)
1746
livePP->set(symRef->getReferenceNumber());
1747
else
1748
{
1749
livePP = new (trHeapMemory()) TR_BitVector(0, trMemory(), heapAlloc);
1750
livePP->set(symRef->getReferenceNumber());
1751
osrData->addPendingPushLivenessInfo(_bcIndex + offset, livePP);
1752
}
1753
slot += n->getNumberOfSlots();
1754
}
1755
}
1756
1757
void
1758
TR_J9ByteCodeIlGenerator::handleSideEffect(TR::Node * sideEffect)
1759
{
1760
// if any tree on the stack can be modified by the sideEffect then the node
1761
// on the stack must become a treetop before the sideEffect node is evaluated
1762
//
1763
for (int32_t i = 0; i < _stack->size(); ++i)
1764
{
1765
TR::Node * n = _stack->element(i);
1766
if (n->getReferenceCount() == 0 && valueMayBeModified(sideEffect, n))
1767
genTreeTop(n);
1768
}
1769
}
1770
1771
bool
1772
TR_J9ByteCodeIlGenerator::valueMayBeModified(TR::Node * sideEffect, TR::Node * node)
1773
{
1774
if (isPlaceholderCall(node))
1775
return false; // Placeholders have no side-effects
1776
1777
if (node->getOpCode().hasSymbolReference() && sideEffect->mayModifyValue(node->getSymbolReference()))
1778
return true;
1779
1780
int32_t numChilds = node->getNumChildren();
1781
for (int32_t i = 0; i < numChilds; ++i)
1782
if (valueMayBeModified(sideEffect, node->getChild(i)))
1783
return true;
1784
1785
return false;
1786
}
1787
1788
1789
TR::Node *
1790
TR_J9ByteCodeIlGenerator::loadConstantValueIfPossible(TR::Node *topNode, uintptr_t topFieldOffset, TR::DataType type, bool isArrayLength)
1791
{
1792
TR::Node *constNode = NULL;
1793
TR::Node *parent = topNode;
1794
TR::SymbolReference *symRef = NULL;
1795
uintptr_t fieldOffset = 0;
1796
if (topNode->getOpCode().hasSymbolReference())
1797
{
1798
symRef = topNode->getSymbolReference();
1799
if (symRef->getSymbol()->isShadow() &&
1800
symRef->getSymbol()->isFinal() &&
1801
!symRef->isUnresolved())
1802
{
1803
fieldOffset = symRef->getOffset();
1804
TR::Node *child = topNode->getFirstChild();
1805
if (child->getOpCode().hasSymbolReference())
1806
{
1807
topNode = child;
1808
symRef = child->getSymbolReference();
1809
}
1810
}
1811
}
1812
1813
if (symRef && symRef->getSymbol()->isStatic() && !symRef->isUnresolved() && symRef->getSymbol()->isFinal() && !symRef->getSymbol()->isConstObjectRef() && _method->isSameMethod(symRef->getOwningMethod(comp())))
1814
{
1815
TR::StaticSymbol *symbol = symRef->getSymbol()->castToStaticSymbol();
1816
TR_J9VMBase *fej9 = (TR_J9VMBase *)fe();
1817
1818
1819
bool isResolved = !symRef->isUnresolved();
1820
TR_OpaqueClassBlock * classOfStatic = isResolved ? _method->classOfStatic(topNode->getSymbolReference()->getCPIndex()) : 0;
1821
if (classOfStatic == NULL)
1822
{
1823
int len = 0;
1824
char * classNameOfFieldOrStatic = NULL;
1825
classNameOfFieldOrStatic = symRef->getOwningMethod(comp())->classNameOfFieldOrStatic(symRef->getCPIndex(), len);
1826
if (classNameOfFieldOrStatic)
1827
{
1828
classNameOfFieldOrStatic = TR::Compiler->cls.classNameToSignature(classNameOfFieldOrStatic, len, comp());
1829
TR_OpaqueClassBlock * curClass = fej9->getClassFromSignature(classNameOfFieldOrStatic, len, symRef->getOwningMethod(comp()));
1830
TR_OpaqueClassBlock * owningClass = comp()->getJittedMethodSymbol()->getResolvedMethod()->containingClass();
1831
if (owningClass == curClass)
1832
classOfStatic = curClass;
1833
}
1834
}
1835
1836
bool isClassInitialized = false;
1837
TR_PersistentClassInfo * classInfo = _noLookahead ? 0 :
1838
comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(classOfStatic, comp());
1839
if (classInfo && classInfo->isInitialized())
1840
isClassInitialized = true;
1841
1842
bool canOptimizeFinalStatic = false;
1843
if (isResolved && symbol->isFinal() && !symRef->isUnresolved() &&
1844
classOfStatic != comp()->getSystemClassPointer() &&
1845
isClassInitialized)
1846
{
1847
//if (symbol->getDataType() == TR::Address)
1848
{
1849
// todo: figure out why classInfo would be NULL here?
1850
if (!classInfo->getFieldInfo())
1851
performClassLookahead(classInfo);
1852
}
1853
1854
if (classInfo->getFieldInfo() && !classInfo->cannotTrustStaticFinal())
1855
canOptimizeFinalStatic = true;
1856
}
1857
1858
if (canOptimizeFinalStatic)
1859
{
1860
TR::VMAccessCriticalSection loadConstantValueCriticalSection(fej9,
1861
TR::VMAccessCriticalSection::tryToAcquireVMAccess,
1862
comp());
1863
1864
if (loadConstantValueCriticalSection.hasVMAccess())
1865
{
1866
uintptr_t objectPointer = comp()->fej9()->getStaticReferenceFieldAtAddress((uintptr_t)symbol->getStaticAddress());
1867
if (objectPointer)
1868
{
1869
switch (symbol->getDataType())
1870
{
1871
case TR::Address:
1872
{
1873
if (parent != topNode)
1874
objectPointer = fej9->getReferenceFieldAt(objectPointer, fieldOffset);
1875
if ((type == TR::Int32) ||
1876
(type == TR::Int16) ||
1877
(type == TR::Int8))
1878
{
1879
int32_t val;
1880
if (isArrayLength)
1881
val = (int32_t)(fej9->getArrayLengthInElements(objectPointer));
1882
else
1883
val = *(int32_t*)(objectPointer + topFieldOffset);
1884
loadConstant(TR::iconst, val);
1885
constNode = _stack->top();
1886
}
1887
else if (type == TR::Int64)
1888
{
1889
int64_t val;
1890
if (isArrayLength)
1891
val = (int64_t)(fej9->getArrayLengthInElements(objectPointer));
1892
else
1893
val = *(int64_t*)(objectPointer + topFieldOffset);
1894
loadConstant(TR::lconst, val);
1895
constNode = _stack->top();
1896
}
1897
break;
1898
}
1899
default:
1900
break;
1901
}
1902
}
1903
}
1904
1905
} // VM Access Critical Section
1906
1907
}
1908
1909
return constNode;
1910
}
1911
1912
/**
1913
* @brief Abort compilation due to unsupported unresolved value type operation
1914
*
1915
* When dealing with unreslved CP references, certain value type operations cannot
1916
* be handled. This helper provides a convenient way of aborting the compilation
1917
* in such cases.
1918
*
1919
* The abort is triggered by throwing TR::UnsupportedValueTypeOperation with an
1920
* appropriate exception message.
1921
*
1922
* Static debug counters are also used to keep track of how frequently these
1923
* aborts occure. The counters are named using the following formats:
1924
*
1925
* - for outermost methods: ilgen.abort/unresolved/{bytecodeName}/{refType}/({method signature})/bc={bcIndex}
1926
* - for inlining/peeking: ilgen.abort/unresolved/{bytecodeName}/{refType}/({method signature})/bc={bcIndex}/root=({top level method signature})
1927
*
1928
* @param bytecodeName is the name of the unhandled bytecode instruction
1929
* @param refType is the type of unresolved reference (e.g. field, class, etc.)
1930
* @throw TR::UnsupportedValueTypeOperation unconditionally
1931
*/
1932
void
1933
TR_J9ByteCodeIlGenerator::abortForUnresolvedValueTypeOp(const char* bytecodeName, const char* refType)
1934
{
1935
const int32_t bcIndex = currentByteCodeIndex();
1936
if (isOutermostMethod())
1937
{
1938
TR::DebugCounter::incStaticDebugCounter(comp(),
1939
TR::DebugCounter::debugCounterName(comp(),
1940
"ilgen.abort/unresolved/%s/%s/(%s)/bc=%d",
1941
bytecodeName,
1942
refType,
1943
comp()->signature(),
1944
bcIndex));
1945
}
1946
else
1947
{
1948
TR::DebugCounter::incStaticDebugCounter(comp(),
1949
TR::DebugCounter::debugCounterName(comp(),
1950
"ilgen.abort/unresolved/%s/%s/(%s)/bc=%d/root=(%s)",
1951
bytecodeName,
1952
refType,
1953
_method->signature(comp()->trMemory()),
1954
bcIndex,
1955
comp()->signature()));
1956
}
1957
1958
comp()->failCompilation<TR::UnsupportedValueTypeOperation>("Unresolved %s encountered for %s bytecode instruction", refType, bytecodeName);
1959
}
1960
1961
//----------------------------------------------
1962
// gen array
1963
//----------------------------------------------
1964
void
1965
TR_J9ByteCodeIlGenerator::genArrayLength()
1966
{
1967
TR::Node * node = NULL;
1968
TR::Node * topNode = pop();
1969
1970
TR::Node *loadedConst = loadConstantValueIfPossible(topNode, fej9()->getOffsetOfContiguousArraySizeField());
1971
1972
if (!loadedConst)
1973
{
1974
if ( comp()->cg()->getDisableNullCheckOfArrayLength() )
1975
node = TR::Node::create(TR::PassThrough, 1, topNode);
1976
else
1977
node = TR::Node::create(TR::arraylength, 1, topNode);
1978
1979
genTreeTop(genNullCheck(node));
1980
1981
if ( comp()->cg()->getDisableNullCheckOfArrayLength() )
1982
{
1983
node = TR::Node::create(TR::arraylength, 1, topNode);
1984
}
1985
1986
push(node);
1987
}
1988
}
1989
1990
void
1991
TR_J9ByteCodeIlGenerator::genContiguousArrayLength(int32_t width)
1992
{
1993
TR::Node * node = NULL;
1994
TR::Node * topNode = pop();
1995
1996
TR::Node *loadedConst = loadConstantValueIfPossible(topNode, fej9()->getOffsetOfContiguousArraySizeField());
1997
1998
// Discontiguous arrays still require the contiguity check and can't be folded.
1999
//
2000
if (loadedConst)
2001
{
2002
if (TR::Compiler->om.isDiscontiguousArray(loadedConst->getInt(), width))
2003
{
2004
pop();
2005
loadedConst = NULL;
2006
}
2007
}
2008
2009
if (!loadedConst)
2010
{
2011
if ( comp()->cg()->getDisableNullCheckOfArrayLength() )
2012
node = TR::Node::create(TR::PassThrough, 1, topNode);
2013
else
2014
node = TR::Node::create(TR::contigarraylength, 1, topNode);
2015
2016
genTreeTop(genNullCheck(node));
2017
2018
if ( comp()->cg()->getDisableNullCheckOfArrayLength() )
2019
{
2020
node = TR::Node::create(TR::contigarraylength, 1, topNode);
2021
}
2022
2023
push(node);
2024
}
2025
}
2026
2027
void
2028
TR_J9ByteCodeIlGenerator::genArrayBoundsCheck(TR::Node * offset, int32_t width)
2029
{
2030
bool canSkipThisBoundCheck = false;
2031
bool canSkipThisNullCheck = false;
2032
bool canSkipArrayLengthCalc = false;
2033
int32_t firstDimension = -1;
2034
2035
if (_classInfo)
2036
{
2037
if (!_classInfo->getFieldInfo())
2038
performClassLookahead(_classInfo);
2039
2040
// note: findFieldInfo may change baseArray
2041
TR::Node * baseArray = _stack->top();
2042
TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), baseArray, true) : NULL;
2043
if (fieldInfo)
2044
{
2045
int32_t relevantDimension = _stack->top() == baseArray ? 0 : 1;
2046
TR_PersistentArrayFieldInfo *arrayFieldInfo = fieldInfo ? fieldInfo->asPersistentArrayFieldInfo() : 0;
2047
if (arrayFieldInfo && arrayFieldInfo->isDimensionInfoValid() &&
2048
arrayFieldInfo->getDimensionInfo(relevantDimension) >= 0)
2049
{
2050
firstDimension = arrayFieldInfo->getDimensionInfo(relevantDimension);
2051
2052
/*
2053
* When hybrid arraylets are used, simplification based on the arraylength can only
2054
* be done if the arraylength fits within a single region. Otherwise, a spine check
2055
* is still required.
2056
*/
2057
2058
if (!TR::Compiler->om.useHybridArraylets() || !TR::Compiler->om.isDiscontiguousArray(firstDimension, width))
2059
{
2060
if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip array length calculation for array %p based on class file examination\n", baseArray))
2061
canSkipArrayLengthCalc = true;
2062
}
2063
2064
if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip null check for array %p based on class file examination\n", baseArray))
2065
canSkipThisNullCheck = true;
2066
2067
if (offset->getOpCode().isLoadConst() &&
2068
offset->getDataType() == TR::Int32 &&
2069
offset->getInt() < firstDimension &&
2070
offset->getInt() >= 0 &&
2071
(!TR::Compiler->om.useHybridArraylets() || !TR::Compiler->om.isDiscontiguousArray(firstDimension, width)))
2072
{
2073
if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip bound check for access %p using array %p which has length %d based on class file examination\n", offset, baseArray, firstDimension))
2074
canSkipThisBoundCheck = true;
2075
}
2076
}
2077
}
2078
}
2079
2080
if (comp()->requiresSpineChecks() || (!_methodSymbol->skipBoundChecks() && !canSkipThisBoundCheck))
2081
{
2082
TR::Node *arrayLength = 0;
2083
if (!canSkipArrayLengthCalc)
2084
{
2085
if (!comp()->requiresSpineChecks())
2086
genArrayLength();
2087
else
2088
genContiguousArrayLength(width);
2089
2090
arrayLength = pop();
2091
if (arrayLength->getOpCode().isArrayLength())
2092
arrayLength->setArrayStride(width);
2093
}
2094
else
2095
{
2096
TR_J9ByteCodeIteratorWithState::pop();
2097
arrayLength = TR::Node::create(TR::iconst, 0, firstDimension);
2098
}
2099
2100
if (comp()->requiresSpineChecks() && !_suppressSpineChecks)
2101
{
2102
// Create an incomplete check node that will be populated when all the children
2103
// are known. It must be created here to be sure it is anchored in the right spot.
2104
//
2105
TR::Node *checkNode = TR::Node::createWithSymRef(TR::BNDCHKwithSpineCHK, 4, 2, arrayLength, offset,
2106
symRefTab()->findOrCreateArrayBoundsCheckSymbolRef(_methodSymbol));
2107
2108
genTreeTop(checkNode);
2109
push(checkNode);
2110
swap();
2111
}
2112
else
2113
{
2114
genTreeTop(TR::Node::createWithSymRef(TR::BNDCHK, 2, 2, arrayLength, offset,
2115
symRefTab()->findOrCreateArrayBoundsCheckSymbolRef(_methodSymbol)));
2116
}
2117
}
2118
else
2119
{
2120
2121
offset->setIsNonNegative(true);
2122
2123
if (!_methodSymbol->skipNullChecks() && !canSkipThisNullCheck)
2124
{
2125
TR::Node * node = TR::Node::create(TR::PassThrough,1,pop());
2126
genTreeTop(genNullCheck(node));
2127
}
2128
else
2129
{
2130
TR_J9ByteCodeIteratorWithState::pop();
2131
}
2132
2133
// Create an incomplete check node that will be populated when all the children
2134
// are known. It must be created here to be sure it is anchored in the right spot.
2135
//
2136
if (comp()->requiresSpineChecks() && !_suppressSpineChecks)
2137
{
2138
TR::Node *spineChk = TR::Node::create(TR::SpineCHK, 3, offset);
2139
genTreeTop(spineChk);
2140
push(spineChk);
2141
swap();
2142
}
2143
else
2144
{
2145
genTreeTop(TR::Node::create(TR::treetop, 1, offset));
2146
}
2147
}
2148
2149
push(offset);
2150
}
2151
2152
// Helper to calculate the address of the array element in a contiguous array
2153
// Stack: ..., array base address, array element index
2154
// width is the width of each array element in bytes
2155
// headerSize is the number of header bytes at the beginning of the array
2156
void
2157
TR_J9ByteCodeIlGenerator::calculateElementAddressInContiguousArray(int32_t width, int32_t headerSize)
2158
{
2159
const bool isForArrayAccess = true;
2160
int32_t shift = TR::TransformUtil::convertWidthToShift(width);
2161
if (shift)
2162
{
2163
loadConstant(TR::iconst, shift);
2164
// generate a TR::aladd instead if required
2165
if (comp()->target().is64Bit())
2166
{
2167
// stack is now ...index,shift<===
2168
TR::Node *second = pop();
2169
genUnary(TR::i2l, isForArrayAccess);
2170
push(second);
2171
genBinary(TR::lshl);
2172
}
2173
else
2174
genBinary(TR::ishl);
2175
}
2176
if (comp()->target().is64Bit())
2177
{
2178
if (headerSize > 0)
2179
{
2180
loadConstant(TR::lconst, (int64_t)headerSize);
2181
// shift could have been null here (if no scaling is done for the index
2182
// ...so check for that and introduce an i2l if required for the aladd
2183
// stack now is ....index,loadConst<===
2184
if (!shift)
2185
{
2186
TR::Node *second = pop();
2187
genUnary(TR::i2l, isForArrayAccess);
2188
push(second);
2189
}
2190
genBinary(TR::ladd);
2191
}
2192
else if ((headerSize == 0) && (!shift))
2193
{
2194
genUnary(TR::i2l, isForArrayAccess);
2195
}
2196
2197
genBinary(TR::aladd);
2198
}
2199
else
2200
{
2201
if (headerSize > 0)
2202
{
2203
loadConstant(TR::iconst, headerSize);
2204
genBinary(TR::iadd);
2205
}
2206
genBinary(TR::aiadd);
2207
}
2208
}
2209
2210
// Helper to calculate the index of the array element in a contiguous array
2211
// Stack: ..., offset for array element index
2212
// width is the width of each array element in bytes
2213
// headerSize is the number of header bytes at the beginning of the array
2214
void
2215
TR_J9ByteCodeIlGenerator::calculateIndexFromOffsetInContiguousArray(int32_t width, int32_t headerSize)
2216
{
2217
2218
if (comp()->target().is64Bit())
2219
{
2220
if (headerSize > 0)
2221
{
2222
loadConstant(TR::lconst, (int64_t)headerSize);
2223
2224
genBinary(TR::lsub);
2225
}
2226
}
2227
else
2228
{
2229
if (headerSize > 0)
2230
{
2231
loadConstant(TR::iconst, headerSize);
2232
genBinary(TR::isub);
2233
}
2234
}
2235
2236
int32_t shift = TR::TransformUtil::convertWidthToShift(width);
2237
if (shift)
2238
{
2239
loadConstant(TR::iconst, shift);
2240
if (comp()->target().is64Bit())
2241
{
2242
genBinary(TR::lshr);
2243
genUnary(TR::l2i);
2244
}
2245
else
2246
genBinary(TR::ishr);
2247
}
2248
}
2249
2250
2251
// Helper to calculate the address of the element of an array
2252
// RTSJ: if we should be generating arraylets, access the spine
2253
// then the arraylet
2254
void
2255
TR_J9ByteCodeIlGenerator::calculateArrayElementAddress(TR::DataType dataType, bool checks)
2256
{
2257
2258
if (comp()->getOption(TR_EnableSIMDLibrary))
2259
{
2260
if (dataType == TR::VectorInt8)
2261
dataType = TR::Int8;
2262
else if (dataType == TR::VectorInt16)
2263
dataType = TR::Int16;
2264
else if (dataType == TR::VectorInt32)
2265
dataType = TR::Int32;
2266
else if (dataType == TR::VectorInt64)
2267
dataType = TR::Int64;
2268
if (dataType == TR::VectorFloat)
2269
dataType = TR::Float;
2270
else if (dataType == TR::VectorDouble)
2271
dataType = TR::Double;
2272
}
2273
2274
int32_t width = TR::Symbol::convertTypeToSize(dataType);
2275
2276
// since each element of an reference array is a compressed pointer,
2277
// modify the width accordingly, so the stride is 4bytes instead of 8
2278
//
2279
if (comp()->useCompressedPointers() && dataType == TR::Address)
2280
{
2281
width = TR::Compiler->om.sizeofReferenceField();
2282
}
2283
2284
// Stack is now ...,aryRef,index<===
2285
TR::Node * index = pop();
2286
if (checks) dup();
2287
dup();
2288
TR::Node * nodeThatWasNullChecked = pop();
2289
2290
handlePendingPushSaveSideEffects(index);
2291
handlePendingPushSaveSideEffects(nodeThatWasNullChecked);
2292
2293
if (checks)
2294
{
2295
genArrayBoundsCheck(index, width);
2296
}
2297
else
2298
{
2299
push(index);
2300
}
2301
2302
// Stack is now ...,aryRef,index<===
2303
if (comp()->generateArraylets())
2304
{
2305
// shift the index on the current stack to get index into array spine
2306
loadConstant(TR::iconst, fej9()->getArraySpineShift(width));
2307
genBinary(TR::ishr);
2308
2309
// now calculate address of pointer to appropriate arraylet
2310
int32_t arraySpineHeaderSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
2311
calculateElementAddressInContiguousArray(TR::Compiler->om.sizeofReferenceField(), arraySpineHeaderSize);
2312
2313
// fetch the arraylet base address
2314
TR::Node * elementAddress = pop();
2315
TR::SymbolReference * elementSymRef = symRefTab()->findOrCreateArrayletShadowSymbolRef(dataType);
2316
TR::Node * arrayletBaseAddr = TR::Node::createWithSymRef(TR::aloadi, 1, 1, elementAddress, elementSymRef);
2317
if (comp()->useCompressedPointers())
2318
{
2319
TR::Node *newArrayletBaseAddr = genCompressedRefs(arrayletBaseAddr);
2320
if (newArrayletBaseAddr)
2321
arrayletBaseAddr = newArrayletBaseAddr;
2322
}
2323
2324
push(arrayletBaseAddr);
2325
2326
// top of stack is now arraylet base address
2327
2328
// get the original index back, mask it to get index into arraylet
2329
push(index);
2330
loadConstant(TR::iconst, fej9()->getArrayletMask(width));
2331
genBinary(TR::iand);
2332
2333
// figure out the address of the element we want in the arraylet
2334
int32_t arrayletHeaderSize = 0;
2335
calculateElementAddressInContiguousArray(width, arrayletHeaderSize);
2336
}
2337
else
2338
{
2339
int32_t arrayHeaderSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
2340
calculateElementAddressInContiguousArray(width, arrayHeaderSize);
2341
_stack->top()->setIsInternalPointer(true);
2342
}
2343
2344
push(nodeThatWasNullChecked);
2345
}
2346
2347
//----------------------------------------------
2348
// gen check
2349
//----------------------------------------------
2350
2351
void
2352
TR_J9ByteCodeIlGenerator::genAsyncCheck()
2353
{
2354
// Create an asyncCheck tree and insert it at the start of the current block
2355
//
2356
2357
TR::Node *node = TR::Node::createWithSymRef(TR::asynccheck,0,symRefTab()->findOrCreateAsyncCheckSymbolRef(_methodSymbol));
2358
2359
if (comp()->getOption(TR_EnableOSR))
2360
genTreeTop(node);
2361
else
2362
_block->prepend(TR::TreeTop::create(comp(), node));
2363
}
2364
2365
/**
2366
* Pop object and class nodes from the stack, and emit a checkcast tree.
2367
*
2368
* @return The emitted checkcast tree
2369
*/
2370
void
2371
TR_J9ByteCodeIlGenerator::genCheckCast()
2372
{
2373
if (_methodSymbol->safeToSkipCheckCasts())
2374
{
2375
pop();
2376
return;
2377
}
2378
2379
TR::Node *node = genNodeAndPopChildren(TR::checkcast, 2, symRefTab()->findOrCreateCheckCastSymbolRef(_methodSymbol));
2380
genTreeTop(node);
2381
push(node->getFirstChild()); // The object reference
2382
_methodSymbol->setHasCheckCasts(true);
2383
}
2384
2385
/**
2386
* Generate IL for a checkcast bytecode instruction.
2387
*
2388
* If the class specified in the bytecode is unresolved, this leaves out the
2389
* ResolveCHK since it has to be conditional on a non-null object.
2390
* If the class specified in the bytecode is a value type, it has to be resolved
2391
* unconditionally, regardless of whether the value is null.
2392
*
2393
* @param cpIndex The constant pool entry of the class given in the bytecode
2394
*
2395
* @see expandUnresolvedClassTypeTests(List<TR::TreeTop>*)
2396
* @see expandUnresolvedClassCheckcast(TR::TreeTop*)
2397
*/
2398
void
2399
TR_J9ByteCodeIlGenerator::genCheckCast(int32_t cpIndex)
2400
{
2401
if (TR::Compiler->om.areValueTypesEnabled() && TR::Compiler->cls.isClassRefValueType(comp(), method()->classOfMethod(), cpIndex))
2402
{
2403
TR::Node * objNode = _stack->top();
2404
2405
loadClassObject(cpIndex);
2406
2407
TR::Node *passThruNode = TR::Node::create(TR::PassThrough, 1, objNode);
2408
genTreeTop(genNullCheck(passThruNode));
2409
}
2410
else
2411
{
2412
loadClassObjectForTypeTest(cpIndex, TR_DisableAOTCheckCastInlining);
2413
}
2414
genCheckCast();
2415
}
2416
2417
void
2418
TR_J9ByteCodeIlGenerator::genDivCheck()
2419
{
2420
if (!_methodSymbol->skipDivChecks())
2421
{
2422
if (!cg()->getSupportsDivCheck())
2423
_unimplementedOpcode = _code[_bcIndex];
2424
genTreeTop(TR::Node::createWithSymRef(TR::DIVCHK, 1, 1, _stack->top(), symRefTab()->findOrCreateDivCheckSymbolRef(_methodSymbol)));
2425
}
2426
}
2427
2428
// create an integer divide node like:
2429
// div
2430
// load i
2431
// load j
2432
// rem
2433
// ==> load i
2434
// ==> load j
2435
// so that if the remainder can be commoned then on most platforms the rem is free with the div calculation
2436
//
2437
void
2438
TR_J9ByteCodeIlGenerator::genIDiv()
2439
{
2440
if (cg()->getSupportsIDivAndIRemWithThreeChildren())
2441
{
2442
genBinary(TR::idiv, 3);
2443
TR::Node * div = _stack->top();
2444
div->setAndIncChild(2, TR::Node::create(TR::irem, 2, div->getFirstChild(), div->getSecondChild()));
2445
}
2446
else
2447
genBinary(TR::idiv);
2448
2449
genDivCheck();
2450
}
2451
2452
void
2453
TR_J9ByteCodeIlGenerator::genLDiv()
2454
{
2455
if (cg()->getSupportsLDivAndLRemWithThreeChildren())
2456
{
2457
genBinary(TR::ldiv, 3);
2458
TR::Node * div = _stack->top();
2459
div->setAndIncChild(2, TR::Node::create(TR::lrem, 2, div->getFirstChild(), div->getSecondChild()));
2460
}
2461
else
2462
genBinary(TR::ldiv);
2463
2464
genDivCheck();
2465
}
2466
2467
void
2468
TR_J9ByteCodeIlGenerator::genIRem()
2469
{
2470
if (cg()->getSupportsIDivAndIRemWithThreeChildren())
2471
{
2472
genBinary(TR::irem, 3);
2473
TR::Node * rem = _stack->top();
2474
rem->setAndIncChild(2, TR::Node::create(TR::idiv, 2, rem->getFirstChild(), rem->getSecondChild()));
2475
}
2476
else
2477
genBinary(TR::irem);
2478
2479
genDivCheck();
2480
}
2481
2482
void
2483
TR_J9ByteCodeIlGenerator::genLRem()
2484
{
2485
if (cg()->getSupportsLDivAndLRemWithThreeChildren())
2486
{
2487
genBinary(TR::lrem, 3);
2488
TR::Node * rem = _stack->top();
2489
rem->setAndIncChild(2, TR::Node::create(TR::ldiv, 2, rem->getFirstChild(), rem->getSecondChild()));
2490
}
2491
else
2492
genBinary(TR::lrem);
2493
2494
genDivCheck();
2495
}
2496
2497
2498
/**
2499
* Generate IL for an instanceof bytecode instruction.
2500
*
2501
* If the class specified in the bytecode is unresolved, this anchors the
2502
* instanceof node, and it leaves out the ResolveCHK since that has to be
2503
* conditional on a non-null object.
2504
*
2505
* @param cpIndex The constant pool entry of the class given in the bytecode
2506
*
2507
* @see expandUnresolvedClassTypeTests(List<TR::TreeTop>*)
2508
* @see expandUnresolvedClassInstanceof(TR::TreeTop*)
2509
*/
2510
void
2511
TR_J9ByteCodeIlGenerator::genInstanceof(int32_t cpIndex)
2512
{
2513
TR::SymbolReference *classSymRef = loadClassObjectForTypeTest(cpIndex, TR_DisableAOTInstanceOfInlining);
2514
TR::Node *node = genNodeAndPopChildren(TR::instanceof, 2, symRefTab()->findOrCreateInstanceOfSymbolRef(_methodSymbol));
2515
push(node);
2516
if (classSymRef->isUnresolved())
2517
{
2518
// Anchor to ensure sequencing for the implied (conditional) ResolveCHK.
2519
genTreeTop(node);
2520
}
2521
_methodSymbol->setHasInstanceOfs(true);
2522
}
2523
2524
TR::Node *
2525
TR_J9ByteCodeIlGenerator::genCompressedRefs(TR::Node * address, bool genTT, int32_t isLoad)
2526
{
2527
static char *pEnv = feGetEnv("TR_UseTranslateInTrees");
2528
2529
TR::Node *value = address;
2530
if (pEnv && (isLoad < 0)) // store
2531
value = address->getSecondChild();
2532
TR::Node *newAddress = TR::Node::createCompressedRefsAnchor(value);
2533
//traceMsg(comp(), "compressedRefs anchor %p generated\n", newAddress);
2534
2535
if (trace())
2536
traceMsg(comp(), "IlGenerator: Generating compressedRefs anchor [%p] for node [%p]\n", newAddress, address);
2537
2538
if (!pEnv && genTT)
2539
{
2540
genTreeTop(newAddress);
2541
return NULL;
2542
}
2543
else
2544
{
2545
return newAddress;
2546
}
2547
}
2548
2549
2550
TR::Node *
2551
TR_J9ByteCodeIlGenerator::genNullCheck(TR::Node * first)
2552
{
2553
// By default, NULLCHKs will be skipped on String.value fields. A more general mechanism
2554
// is needed for skipping NULL/BNDCHKs on certain recognized fields...
2555
//
2556
static char *c = feGetEnv("TR_disableSkipStringValueNULLCHK");
2557
2558
if (!_methodSymbol->skipNullChecks())
2559
{
2560
TR_ASSERT(first->getNumChildren() >= 1, "no grandchild to nullcheck?");
2561
TR::Node *grandChild = first->getChild(0);
2562
if (!c && grandChild->getOpCode().hasSymbolReference() &&
2563
grandChild->getSymbolReference() &&
2564
grandChild->getSymbolReference()->getSymbol() &&
2565
grandChild->getSymbolReference()->getSymbol()->getRecognizedField() == TR::Symbol::Java_lang_String_value)
2566
{
2567
if (trace())
2568
traceMsg(comp(), "Skipping NULLCHK (node %p) on String.value field : %s -> %s\n", grandChild, comp()->signature(), _methodSymbol->signature(trMemory()));
2569
}
2570
else
2571
{
2572
return TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, first, symRefTab()->findOrCreateNullCheckSymbolRef(_methodSymbol));
2573
}
2574
}
2575
2576
if (first->getOpCode().isTreeTop())
2577
return first;
2578
2579
return TR::Node::create(TR::treetop, 1, first);
2580
}
2581
2582
TR::Node *
2583
TR_J9ByteCodeIlGenerator::genResolveCheck(TR::Node * first)
2584
{
2585
return TR::Node::createWithSymRef(TR::ResolveCHK, 1, 1, first, symRefTab()->findOrCreateResolveCheckSymbolRef(_methodSymbol));
2586
}
2587
2588
TR::Node *
2589
TR_J9ByteCodeIlGenerator::genResolveAndNullCheck(TR::Node * first)
2590
{
2591
TR_ASSERT(first->getNumChildren() >= 1, "no grandchild to nullcheck?");
2592
TR::Node *grandChild = first->getChild(0);
2593
return TR::Node::createWithSymRef(TR::ResolveAndNULLCHK, 1, 1, first, symRefTab()->findOrCreateNullCheckSymbolRef(_methodSymbol));
2594
}
2595
2596
//----------------------------------------------
2597
// genGoto
2598
//----------------------------------------------
2599
2600
int32_t
2601
TR_J9ByteCodeIlGenerator::genGoto(int32_t target)
2602
{
2603
2604
if( _blocksToInline) // partial inlining - only generate goto if its in the list of blocks.
2605
{
2606
bool success=false;
2607
ListIterator<TR_InlineBlock> blocksIt(_blocksToInline->_inlineBlocks);
2608
TR_InlineBlock *aBlock = NULL;
2609
for (aBlock = blocksIt.getCurrent() ; aBlock; aBlock = blocksIt.getNext())
2610
{
2611
if ( aBlock->_BCIndex == target)
2612
{
2613
if (_blocks[target]->getEntry()->getNode()->getByteCodeIndex()<= _block->getEntry()->getNode()->getByteCodeIndex())
2614
genAsyncCheck();
2615
genTreeTop(TR::Node::create(TR::Goto, 0, genTarget(target)));
2616
success=true;
2617
break;
2618
}
2619
}
2620
TR_ASSERT(success, " Walker: genGoto for a partial inline has no target in the list of blocks to be inlined.\n");
2621
}
2622
else
2623
{
2624
2625
if (_blocks[target]->getEntry()->getNode()->getByteCodeIndex()
2626
<= _block->getEntry()->getNode()->getByteCodeIndex())
2627
genAsyncCheck();
2628
2629
genTreeTop(TR::Node::create(TR::Goto, 0, genTarget(target)));
2630
}
2631
return findNextByteCodeToGen();
2632
}
2633
2634
2635
2636
/** \brief
2637
* Generates IL for an conditional branch bytecode that takes one operand.
2638
* Also generates an asynccheck if the bytecode branches backwards.
2639
*
2640
* \param nodeop
2641
* The IL opcode to use.
2642
*
2643
* \return
2644
* The index of the next bytecode to generate.
2645
*/
2646
int32_t
2647
TR_J9ByteCodeIlGenerator::genIfOneOperand(TR::ILOpCodes nodeop)
2648
{
2649
int32_t branchBC = _bcIndex + next2BytesSigned();
2650
2651
if (branchBC <= _bcIndex)
2652
genAsyncCheck();
2653
2654
TR_J9ByteCode currentByteCode = current();
2655
switch (currentByteCode)
2656
{
2657
case J9BCifeq:
2658
case J9BCifne:
2659
case J9BCiflt:
2660
case J9BCifge:
2661
case J9BCifgt:
2662
case J9BCifle:
2663
loadConstant(TR::iconst, 0);
2664
break;
2665
case J9BCifnull:
2666
if (comp()->target().is64Bit())
2667
loadConstant(TR::aconst, (int64_t)0);
2668
else
2669
loadConstant(TR::aconst, (int32_t)0);
2670
break;
2671
case J9BCifnonnull:
2672
if (comp()->target().is64Bit())
2673
loadConstant(TR::aconst, (int64_t)0);
2674
else
2675
loadConstant(TR::aconst, (int32_t)0);
2676
break;
2677
default:
2678
TR_ASSERT(comp(), "Unexpected bytecode at bc index %d\n", _bcIndex);
2679
}
2680
2681
return genIfImpl(nodeop);
2682
}
2683
2684
/** \brief
2685
* Generates IL for an conditional branch bytecode that takes two operands.
2686
* Also generates an asynccheck if the bytecode branches backwards.
2687
*
2688
* \param nodeop
2689
* The IL opcode to use.
2690
*
2691
* \return
2692
* The index of the next bytecode to generate.
2693
*/
2694
int32_t
2695
TR_J9ByteCodeIlGenerator::genIfTwoOperand(TR::ILOpCodes nodeop)
2696
{
2697
int32_t branchBC = _bcIndex + next2BytesSigned();
2698
2699
if (branchBC <= _bcIndex)
2700
genAsyncCheck();
2701
2702
return genIfImpl(nodeop);
2703
}
2704
2705
/** \brief
2706
* Generates IL for a conditional branch bytecode that compares two
2707
* address-typed operands as for bytecode instructions if_acmp{eq,ne}.
2708
* Also generates an asynccheck if the bytecode branches backwards.
2709
*
2710
* If value types are not enabled, then a regulare acmp operation is
2711
* generated instead.
2712
*
2713
* \param nodeop
2714
* The IL opcode that would be used for non-value references. This opcode
2715
* must be either ifacmpeq or ifacmpne.
2716
*
2717
* \return
2718
* The index of the next bytecode to generate.
2719
*/
2720
int32_t
2721
TR_J9ByteCodeIlGenerator::genIfAcmpEqNe(TR::ILOpCodes ifacmpOp)
2722
{
2723
if (!TR::Compiler->om.areValueTypesEnabled())
2724
return genIfTwoOperand(ifacmpOp);
2725
2726
int32_t branchBC = _bcIndex + next2BytesSigned();
2727
2728
if (branchBC <= _bcIndex)
2729
genAsyncCheck();
2730
2731
TR::Node *rhs = pop();
2732
TR::Node *lhs = pop();
2733
2734
TR::SymbolReference *comparisonNonHelper =
2735
comp()->getSymRefTab()->findOrCreateObjectInequalityComparisonSymbolRef();
2736
2737
TR::Node *substitutabilityTest =
2738
TR::Node::createWithSymRef(TR::icall, 2, 2, lhs, rhs, comparisonNonHelper);
2739
2740
substitutabilityTest->getByteCodeInfo().setDoNotProfile(true);
2741
TR::TreeTop* callTree = genTreeTop(substitutabilityTest);
2742
2743
const char *counterName = TR::DebugCounter::debugCounterName(comp(), "vt-helper/generated/acmp/(%s)/bc=%d",
2744
comp()->signature(), currentByteCodeIndex());
2745
TR::DebugCounter::prependDebugCounter(comp(), counterName, callTree);
2746
2747
push(substitutabilityTest);
2748
push(TR::Node::iconst(0));
2749
return genIfImpl(ifacmpOp == TR::ifacmpeq ? TR::ificmpeq : TR::ificmpne);
2750
}
2751
2752
//----------------------------------------------
2753
// genIfImpl
2754
//----------------------------------------------
2755
2756
// The "if" family of bytecodes are composed of two operations: a
2757
// compare and a conditional branch. Like bytecode, the TR IL combines
2758
// them into one operation. The combined operation, obviously, has to
2759
// be the last operation in the basic block.
2760
//
2761
// This complicates our scheme for handling PPS slots that are live
2762
// across blocks. The saveStack method will generate stores of any PPS
2763
// slots live on exit. However, these stores must be generated before
2764
// the combined compare/conditional branch operation. Thus, any loads
2765
// from the PPS save region amongst the inputs of the compare might be
2766
// killed by stores to be generated by saveStack. The method
2767
// handlePendingPushSaveSideEffects is called to promote any such loads
2768
// to treetops preceding the saveStack generated stores.
2769
//
2770
// This API does not generate asynccheck, it's the caller's responsibility
2771
// to ensure one is generated for a backward branch.
2772
//
2773
int32_t
2774
TR_J9ByteCodeIlGenerator::genIfImpl(TR::ILOpCodes nodeop)
2775
{
2776
int32_t branchBC = _bcIndex + next2BytesSigned();
2777
int32_t fallThruBC = _bcIndex + 3;
2778
2779
TR::Node * second = pop();
2780
TR::Node * first = pop();
2781
2782
static char *disableIfFolding = feGetEnv("TR_DisableIfFolding");
2783
bool trace = comp()->getOption(TR_TraceILGen);
2784
2785
TR::DataType type = first->getDataType();
2786
if (!disableIfFolding &&
2787
branchBC > _bcIndex &&
2788
first->getOpCode().isLoadConst() &&
2789
second->getOpCode().isLoadConst() &&
2790
type != TR::Address &&
2791
type != TR::Float &&
2792
type != TR::Double)
2793
{
2794
int64_t v1 = first->getConstValue();
2795
int64_t v2 = second->getConstValue();
2796
bool branchTaken;
2797
TR_ComparisonTypes compareType = TR::ILOpCode::getCompareType(nodeop);
2798
bool isUnsignedCompare = TR::ILOpCode(nodeop).isUnsignedCompare();
2799
switch (compareType)
2800
{
2801
case TR_cmpEQ:
2802
branchTaken = v1 == v2;
2803
break;
2804
case TR_cmpNE:
2805
branchTaken = v1 != v2;
2806
break;
2807
case TR_cmpLT:
2808
branchTaken = isUnsignedCompare ? (uint64_t)v1 < (uint64_t)v2 : v1 < v2;
2809
break;
2810
case TR_cmpLE:
2811
branchTaken = isUnsignedCompare ? (uint64_t)v1 <= (uint64_t)v2 : v1 <= v2;
2812
break;
2813
case TR_cmpGT:
2814
branchTaken = isUnsignedCompare ? (uint64_t)v1 > (uint64_t)v2 : v1 > v2;
2815
break;
2816
case TR_cmpGE:
2817
branchTaken = isUnsignedCompare ? (uint64_t)v1 >= (uint64_t)v2 : v1 >= v2;
2818
break;
2819
}
2820
2821
if (_blocksToInline)
2822
{
2823
if (trace)
2824
traceMsg(comp(), "Not folding the if because of partial inlining\n");
2825
}
2826
else
2827
{
2828
if (trace)
2829
traceMsg(comp(), "%s\n", branchTaken ? "taking the branch" : "fall through");
2830
2831
if (branchTaken)
2832
{
2833
// Folding the if is equivalent to turning it into a goto. We can't just return
2834
// branchBC because there can be arbitrary bytecodes between the `if` and branchBC.
2835
// To get a correct CFG, a goto is required.
2836
//
2837
return genGoto(branchBC);
2838
}
2839
else
2840
{
2841
// In this case, folding the if is equivalent to removing the if bytecode. The fall
2842
// through bytecodes can live in the same block as there is no branch out after the
2843
// folding.
2844
//
2845
return fallThruBC;
2846
}
2847
}
2848
}
2849
2850
_methodSymbol->setHasBranches(true);
2851
handlePendingPushSaveSideEffects(first);
2852
handlePendingPushSaveSideEffects(second);
2853
2854
if( _blocksToInline)
2855
{
2856
bool genFallThru=false, genBranchBC=false;
2857
ListIterator<TR_InlineBlock> blocksIt(_blocksToInline->_inlineBlocks);
2858
TR_InlineBlock *aBlock = NULL;
2859
for (aBlock = blocksIt.getCurrent() ; aBlock; aBlock = blocksIt.getNext())
2860
{
2861
// printf("\tBlock bcIndex = %d owningMethod = %p depth = %d\n",aBlock->_BCIndex,aBlock->_owningMethod,aBlock->_depth);
2862
if(branchBC == aBlock->_BCIndex)
2863
genBranchBC=true;
2864
if(fallThruBC == aBlock->_BCIndex)
2865
genFallThru=true;
2866
}
2867
// printf("genIf: genBranchBC = %d genFallThru = %d\n",genBranchBC,genFallThru);
2868
// fflush(stdout);
2869
2870
TR::TreeTop * branchDestination = NULL;
2871
2872
if(genFallThru && genBranchBC)
2873
{
2874
genTarget(fallThruBC);
2875
// printf("Walker: calling genTarget on branchBC\n");
2876
TR::TreeTop * branchDestination = genTarget(branchBC);
2877
if (swapChildren(nodeop, first))
2878
{
2879
TR::TreeTop *tt = genTreeTop(TR::Node::createif(TR::ILOpCode(nodeop).getOpCodeForSwapChildren(), second, first, branchDestination));
2880
tt->getNode()->setSwappedChildren(true);
2881
}
2882
else
2883
genTreeTop(TR::Node::createif(nodeop, first, second, branchDestination));
2884
2885
return findNextByteCodeToGen();
2886
}
2887
else
2888
{
2889
if(genFallThru)
2890
{
2891
genTarget(fallThruBC);
2892
2893
//need to create a branch destination restart
2894
// printf("Walker: genIf : fallThru : getCallNodeTreeTop = %p, symreftab = %p\n",_blocksToInline->getCallNodeTreeTop(),symRefTab());
2895
// fflush(stdout);
2896
branchDestination = _blocksToInline->hasGeneratedRestartTree() ? _blocksToInline->getGeneratedRestartTree() :
2897
_blocksToInline->setGeneratedRestartTree(genPartialInliningCallBack(branchBC,_blocksToInline->getCallNodeTreeTop())); //not adding it to the queue
2898
if(branchBC > _blocksToInline->getHighestBCIndex())
2899
_blocksToInline->setHighestBCIndex(branchBC);
2900
else if(branchBC < _blocksToInline->getLowestBCIndex())
2901
_blocksToInline->setLowestBCIndex(branchBC);
2902
//printf("Walker: genIf : fallThru : branchDestination = %p\n",branchDestination);
2903
// fflush(stdout);
2904
//_blocksToInline->getCallNodeTreeTop();
2905
}
2906
2907
if(genBranchBC)
2908
{
2909
//printf("Walker: genIf : BranchBC : hasGeneratedRestartTree = %d getGeneratedRestartTree = %p getEnclosingBlock = %p\n",_blocksToInline->hasGeneratedRestartTree(),_blocksToInline->getGeneratedRestartTree(), _blocksToInline->getGeneratedRestartTree() ? _blocksToInline->getGeneratedRestartTree()->getEnclosingBlock() : 0);
2910
// fflush(stdout);
2911
_blocksToInline->hasGeneratedRestartTree() ? genGotoPartialInliningCallBack(fallThruBC,_blocksToInline->getGeneratedRestartTree()) :
2912
_blocksToInline->setGeneratedRestartTree(genPartialInliningCallBack(fallThruBC,_blocksToInline->getCallNodeTreeTop()));
2913
if(fallThruBC > _blocksToInline->getHighestBCIndex())
2914
_blocksToInline->setHighestBCIndex(fallThruBC);
2915
else if(fallThruBC < _blocksToInline->getLowestBCIndex())
2916
_blocksToInline->setLowestBCIndex(fallThruBC);
2917
branchDestination = genTarget(branchBC);
2918
//printf("Walker: genIf : BranchBC : branchDestination = %p\n",branchDestination);
2919
// fflush(stdout);
2920
//genTreeTop(TR::Node::create(TR::Goto, 0, genTarget(target)));
2921
}
2922
//generating the if statement regardless methinks
2923
TR_ASSERT(branchDestination, "Walker: No branchDestination in partial inlining\n");
2924
if (swapChildren(nodeop, first))
2925
{
2926
TR::TreeTop *tt = genTreeTop(TR::Node::createif(TR::ILOpCode(nodeop).getOpCodeForSwapChildren(), second, first, branchDestination));
2927
tt->getNode()->setSwappedChildren(true);
2928
}
2929
else
2930
genTreeTop(TR::Node::createif(nodeop, first, second, branchDestination));
2931
2932
return findNextByteCodeToGen();
2933
}
2934
}
2935
else
2936
{
2937
genTarget(fallThruBC);
2938
// printf("Walker: calling genTarget on branchBC\n");
2939
TR::TreeTop * branchDestination = genTarget(branchBC);
2940
if (swapChildren(nodeop, first))
2941
{
2942
TR::TreeTop *tt = genTreeTop(TR::Node::createif(TR::ILOpCode(nodeop).getOpCodeForSwapChildren(), second, first, branchDestination));
2943
tt->getNode()->setSwappedChildren(true);
2944
}
2945
else
2946
genTreeTop(TR::Node::createif(nodeop, first, second, branchDestination));
2947
2948
return findNextByteCodeToGen();
2949
}
2950
}
2951
2952
//----------------------------------------------
2953
// genInc
2954
//----------------------------------------------
2955
2956
void
2957
TR_J9ByteCodeIlGenerator::genInc()
2958
{
2959
int32_t index = nextByte();
2960
loadAuto(TR::Int32, index);
2961
loadConstant(TR::iconst, nextByteSigned(2));
2962
genBinary(TR::iadd);
2963
storeAuto(TR::Int32, index);
2964
}
2965
2966
void
2967
TR_J9ByteCodeIlGenerator::genIncLong()
2968
{
2969
int32_t index = next2Bytes();
2970
loadAuto(TR::Int32, index);
2971
loadConstant(TR::iconst, next2BytesSigned(3));
2972
genBinary(TR::iadd);
2973
storeAuto(TR::Int32, index);
2974
}
2975
2976
//----------------------------------------------
2977
// genInvoke
2978
//----------------------------------------------
2979
2980
void
2981
TR_J9ByteCodeIlGenerator::genInvokeStatic(int32_t cpIndex)
2982
{
2983
TR::SymbolReference *methodSymRef = symRefTab()->findOrCreateStaticMethodSymbol(_methodSymbol, cpIndex);
2984
2985
if (comp()->getOption(TR_TraceILGen))
2986
traceMsg(comp(), " genInvokeStatic(%d) // %s\n", cpIndex, comp()->getDebug()->getName(methodSymRef));
2987
2988
_staticMethodInvokeEncountered = true;
2989
2990
if (runMacro(methodSymRef))
2991
{
2992
if (comp()->compileRelocatableCode())
2993
{
2994
if (comp()->getOption(TR_TraceILGen))
2995
traceMsg(comp(), " ILGen macro %s not supported in AOT. Aborting compile.\n", comp()->getDebug()->getName(methodSymRef));
2996
comp()->failCompilation<J9::AOTHasInvokeHandle>("An ILGen macro not supported in AOT. Aborting compile.");
2997
}
2998
2999
if (comp()->getOption(TR_FullSpeedDebug) && !isPeekingMethod())
3000
{
3001
if (comp()->getOption(TR_TraceILGen))
3002
traceMsg(comp(), " ILGen macro %s not supported in FSD. Failing ilgen\n", comp()->getDebug()->getName(methodSymRef));
3003
comp()->failCompilation<J9::FSDHasInvokeHandle>("An ILGen macro not supported in FSD. Failing ilgen.");
3004
}
3005
3006
if (comp()->getOption(TR_TraceILGen))
3007
traceMsg(comp(), " Finished macro %s\n", comp()->getDebug()->getName(methodSymRef));
3008
return;
3009
}
3010
3011
TR::MethodSymbol * symbol = methodSymRef->getSymbol()->castToMethodSymbol();
3012
// Note that genInvokeDirect can return nodes that are not calls (for
3013
// recognized methods), so some caution is needed in the handling of callNode.
3014
TR::Node *callNode = genInvokeDirect(methodSymRef);
3015
if (callNode && _methodSymbol->safeToSkipChecksOnArrayCopies())
3016
{
3017
bool isCallToArrayCopy = true;
3018
// Defend against the case where there is no symbol reference
3019
if (callNode->getOpCode().hasSymbolReference() && !callNode->getSymbolReference()->isUnresolved())
3020
{
3021
TR::RecognizedMethod recognizedMethod = callNode->getSymbol()->castToResolvedMethodSymbol()->getRecognizedMethod();
3022
3023
if (recognizedMethod != TR::java_lang_System_arraycopy &&
3024
recognizedMethod != TR::java_lang_String_compressedArrayCopy_BIBII &&
3025
recognizedMethod != TR::java_lang_String_compressedArrayCopy_BICII &&
3026
recognizedMethod != TR::java_lang_String_compressedArrayCopy_CIBII &&
3027
recognizedMethod != TR::java_lang_String_compressedArrayCopy_CICII &&
3028
recognizedMethod != TR::java_lang_String_decompressedArrayCopy_BIBII &&
3029
recognizedMethod != TR::java_lang_String_decompressedArrayCopy_BICII &&
3030
recognizedMethod != TR::java_lang_String_decompressedArrayCopy_CIBII &&
3031
recognizedMethod != TR::java_lang_String_decompressedArrayCopy_CICII)
3032
{
3033
isCallToArrayCopy = false;
3034
}
3035
}
3036
else
3037
isCallToArrayCopy = false;
3038
3039
if (isCallToArrayCopy)
3040
callNode->setNodeIsRecognizedArrayCopyCall(true);
3041
}
3042
}
3043
3044
void
3045
TR_J9ByteCodeIlGenerator::genInvokeSpecial(int32_t cpIndex)
3046
{
3047
TR::SymbolReference *methodSymRef = symRefTab()->findOrCreateSpecialMethodSymbol(_methodSymbol, cpIndex);
3048
3049
genInvokeDirect(methodSymRef);
3050
3051
// In bytecode within an interface, invokespecial instructions calling
3052
// anything other than <init> need to have a run-time type test to ensure
3053
// that the receiver is an instance of the interface. Outside of interfaces
3054
// this is checked during verification, but verification doesn't check
3055
// interface types.
3056
//
3057
// The following collects the bytecode index of each invokespecial
3058
// instruction that requires such a type test. The tests are inserted later
3059
// by expandInvokeSpecialInterface().
3060
3061
const bool trace = comp()->getOption(TR_TraceILGen);
3062
if (skipInvokeSpecialInterfaceTypeChecks())
3063
{
3064
if (trace)
3065
traceMsg(comp(), "invokespecial type tests disabled by env var\n");
3066
return;
3067
}
3068
3069
// Initialize _invokeSpecialInterface if necessary.
3070
if (!_invokeSpecialSeen)
3071
{
3072
_invokeSpecialSeen = true;
3073
3074
// For this purpose, an anonymous class whose host class is an interface
3075
// is expected to behave as though its code is contained within that
3076
// interface. For non-anonymous classes, hostClass is circular.
3077
TR_OpaqueClassBlock * const defClass =
3078
fej9()->getHostClass(_method->containingClass());
3079
if (TR::Compiler->cls.isInterfaceClass(comp(), defClass))
3080
_invokeSpecialInterface = defClass;
3081
3082
if (trace)
3083
{
3084
int32_t len = 6;
3085
const char * name = "(none)";
3086
if (_invokeSpecialInterface != NULL)
3087
name = fej9()->getClassNameChars(_invokeSpecialInterface, len);
3088
traceMsg(comp(),
3089
"within interface %p %.*s for the purpose of invokespecial\n",
3090
_invokeSpecialInterface,
3091
len, name);
3092
}
3093
}
3094
3095
if (_invokeSpecialInterface == NULL)
3096
{
3097
if (trace)
3098
traceMsg(comp(), "no invokespecial type tests in this method\n");
3099
return;
3100
}
3101
3102
TR::Method *callee = methodSymRef->getSymbol()->castToMethodSymbol()->getMethod();
3103
if (callee->isConstructor())
3104
{
3105
if (trace)
3106
traceMsg(comp(), "no invokespecial type test for constructor\n");
3107
return;
3108
}
3109
3110
if (callee->isFinalInObject())
3111
{
3112
if (trace)
3113
traceMsg(comp(), "invokespecial of final Object method is really invokevirtual\n");
3114
return;
3115
}
3116
3117
const int32_t bcIndex = currentByteCodeIndex();
3118
if (comp()->compileRelocatableCode())
3119
{
3120
if (isOutermostMethod())
3121
{
3122
TR::DebugCounter::incStaticDebugCounter(comp(),
3123
TR::DebugCounter::debugCounterName(comp(),
3124
"ilgen.abort/aot-invokespecial-interface/root/(%s)/bc=%d",
3125
comp()->signature(),
3126
bcIndex));
3127
}
3128
else
3129
{
3130
TR::DebugCounter::incStaticDebugCounter(comp(),
3131
TR::DebugCounter::debugCounterName(comp(),
3132
"ilgen.abort/aot-invokespecial-interface/inline/(%s)/bc=%d/root=(%s)",
3133
_method->signature(comp()->trMemory()),
3134
bcIndex,
3135
comp()->signature()));
3136
}
3137
3138
comp()->failCompilation<J9::AOTHasInvokeSpecialInInterface>(
3139
"COMPILATION_AOT_HAS_INVOKESPECIAL_IN_INTERFACE");
3140
}
3141
3142
// Make note of this invokespecial; it needs a run-time type test against
3143
// _invokeSpecialInterface.
3144
if (_invokeSpecialInterfaceCalls == NULL) // lazily allocated
3145
{
3146
_invokeSpecialInterfaceCalls =
3147
new (trHeapMemory()) TR_BitVector(_maxByteCodeIndex + 1, trMemory());
3148
}
3149
3150
_invokeSpecialInterfaceCalls->set(bcIndex);
3151
if (trace)
3152
traceMsg(comp(), "request invokespecial type test at bc index %d\n", bcIndex);
3153
}
3154
3155
void
3156
TR_J9ByteCodeIlGenerator::genInvokeVirtual(int32_t cpIndex)
3157
{
3158
auto owningMethod = (TR_ResolvedJ9Method*)_methodSymbol->getResolvedMethod();
3159
bool unresolvedInCP;
3160
TR_ResolvedMethod *method =
3161
owningMethod->getResolvedPossiblyPrivateVirtualMethod(
3162
comp(),
3163
cpIndex,
3164
/* ignoreRtResolve = */ false,
3165
&unresolvedInCP);
3166
3167
TR::SymbolReference * symRef = NULL;
3168
if (method != NULL && method->isPrivate())
3169
{
3170
_methodSymbol->setMayHaveInlineableCall(true);
3171
symRef = symRefTab()->findOrCreateMethodSymbol(
3172
_methodSymbol->getResolvedMethodIndex(),
3173
cpIndex,
3174
method,
3175
TR::MethodSymbol::Special,
3176
/* isUnresolvedInCP = */ false);
3177
}
3178
else
3179
{
3180
symRef = symRefTab()->findOrCreateVirtualMethodSymbol(_methodSymbol, cpIndex);
3181
3182
// Update method in case getResolvedPossiblyPrivateVirtualMethod()
3183
// returned null originally, but then findOrCreateVirtualMethodSymbol()
3184
// later found the method.
3185
//
3186
// Without doing this, we can fail to set isDirectCall for recognized
3187
// final methods (e.g. Unsafe and JITHelpers methods) where the compiler
3188
// assumes calls are direct.
3189
//
3190
if (!symRef->isUnresolved())
3191
method = symRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod();
3192
}
3193
3194
bool isDirectCall = false;
3195
if (method != NULL)
3196
{
3197
isDirectCall =
3198
symRef->getSymbol()->isFinal() ||
3199
method->isPrivate() ||
3200
(debug("omitVirtualGuard") && !method->virtualMethodIsOverridden());
3201
}
3202
3203
if (isDirectCall)
3204
{
3205
genInvokeDirect(symRef);
3206
}
3207
else
3208
{
3209
genInvokeWithVFTChild(symRef);
3210
_methodSymbol->setMayHaveIndirectCalls(true);
3211
}
3212
}
3213
3214
void
3215
TR_J9ByteCodeIlGenerator::genInvokeInterface(int32_t cpIndex)
3216
{
3217
auto owningMethod = (TR_ResolvedJ9Method*)_methodSymbol->getResolvedMethod();
3218
TR_ResolvedMethod *improperMethod =
3219
owningMethod->getResolvedImproperInterfaceMethod(comp(), cpIndex);
3220
if (improperMethod == NULL)
3221
{
3222
TR::SymbolReference *symRef = symRefTab()->findOrCreateInterfaceMethodSymbol(_methodSymbol, cpIndex);
3223
genInvokeWithVFTChild(symRef);
3224
_methodSymbol->setMayHaveIndirectCalls(true);
3225
}
3226
else
3227
{
3228
_methodSymbol->setMayHaveInlineableCall(true);
3229
TR::TreeTop *prevLastTree = _block->getExit()->getPrevTreeTop();
3230
TR::Node *callNode = NULL;
3231
TR::Node *receiver = topn(improperMethod->numberOfExplicitParameters());
3232
if (improperMethod->isPrivate() || improperMethod->convertToMethod()->isFinalInObject())
3233
{
3234
TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodSymbol(
3235
_methodSymbol->getResolvedMethodIndex(),
3236
cpIndex,
3237
improperMethod,
3238
TR::MethodSymbol::Special,
3239
/* isUnresolvedInCP = */ false);
3240
3241
callNode = genInvokeDirect(symRef);
3242
}
3243
else
3244
{
3245
TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodSymbol(
3246
_methodSymbol->getResolvedMethodIndex(),
3247
cpIndex,
3248
improperMethod,
3249
TR::MethodSymbol::Virtual,
3250
/* isUnresolvedInCP = */ false);
3251
3252
callNode = genInvokeWithVFTChild(symRef);
3253
_methodSymbol->setMayHaveIndirectCalls(true);
3254
}
3255
3256
// Generate the dynamic type test against the interface type, throwing
3257
// IncompatibleClassChangeError in case it fails
3258
TR::TreeTop *bbExit = _block->getExit();
3259
TR::TreeTop *callTree = prevLastTree->getNextTreeTop();
3260
while (callTree != bbExit && callTree->getNode()->getChild(0) != callNode)
3261
callTree = callTree->getNextTreeTop();
3262
3263
TR_ASSERT_FATAL(callTree != bbExit, "invokeinterface call tree not found\n");
3264
3265
TR::TransformUtil::separateNullCheck(comp(), callTree, comp()->getOption(TR_TraceILGen));
3266
3267
uint32_t interfaceCPIndex = owningMethod->classCPIndexOfMethod(cpIndex);
3268
push(receiver);
3269
genInstanceof(interfaceCPIndex);
3270
TR::Node *instanceof = pop();
3271
3272
TR::SymbolReference *icce =
3273
symRefTab()->findOrCreateIncompatibleClassChangeErrorSymbolRef(_methodSymbol);
3274
3275
TR::Node *check =
3276
TR::Node::createWithSymRef(TR::ZEROCHK, 1, 1, instanceof, icce);
3277
3278
callTree->insertBefore(TR::TreeTop::create(comp(), check));
3279
}
3280
}
3281
3282
static char *suffixedName(char *baseName, char typeSuffix, char *buf, int32_t bufSize, TR::Compilation *comp)
3283
{
3284
char *methodName = buf;
3285
int32_t methodNameLength = strlen(baseName) + 2;
3286
if (methodNameLength >= bufSize)
3287
methodName = (char*)comp->trMemory()->allocateStackMemory(methodNameLength+1, TR_MemoryBase::IlGenerator);
3288
sprintf(methodName, "%s%c", baseName, typeSuffix);
3289
return methodName;
3290
}
3291
3292
void
3293
TR_J9ByteCodeIlGenerator::genInvokeDynamic(int32_t callSiteIndex)
3294
{
3295
if (comp()->compileRelocatableCode())
3296
{
3297
comp()->failCompilation<J9::AOTHasInvokeHandle>("COMPILATION_AOT_HAS_INVOKEHANDLE 0");
3298
}
3299
3300
if (comp()->getOption(TR_FullSpeedDebug) && !isPeekingMethod())
3301
comp()->failCompilation<J9::FSDHasInvokeHandle>("FSD_HAS_INVOKEHANDLE 0");
3302
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
3303
3304
// Call generated when call site table entry is resolved:
3305
// -----------------------------------------------------
3306
// call <target method obtained from memberName object>
3307
// arg0
3308
// arg1
3309
// ...
3310
// aloadi <appendix object>
3311
// ------------------------------------------------------
3312
// Call generated when call site table entry is unresolved:
3313
// ------------------------------------------------------
3314
// ResolveCHK
3315
// aload <CallSiteTableEntry @<callSiteIndex>>
3316
// treetop
3317
// aloadi <appendix object> // array-shadow from CallSiteTableEntry
3318
// ...
3319
// treetop
3320
// aloadi <memberName object> // array-shadow from CallSiteTableEntry
3321
// ...
3322
// treetop
3323
// call java/lang/invoke/MethodHandle.linkToStatic(arg0arg1...Ljava/lang/Object;Ljava/lang/Object;)<return type>
3324
// arg0
3325
// arg1
3326
// ...
3327
// aloadi <appendix object>
3328
// aloadi <memberName object>
3329
// ------------------------------------------------------
3330
bool isUnresolved;
3331
TR::SymbolReference * targetMethodSymRef = symRefTab()->findOrCreateDynamicMethodSymbol(_methodSymbol, callSiteIndex, &isUnresolved);
3332
if (isUnresolved)
3333
targetMethodSymRef->getSymbol()->setDummyResolvedMethod(); // linkToStatic is a dummy TR_ResolvedMethod
3334
TR::SymbolReference *callSiteTableEntrySymRef = symRefTab()->findOrCreateCallSiteTableEntrySymbol(_methodSymbol, callSiteIndex);
3335
TR_ResolvedJ9Method* owningMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());
3336
uintptr_t * invokeCacheArray = (uintptr_t *) owningMethod->callSiteTableEntryAddress(callSiteIndex);
3337
loadInvokeCacheArrayElements(callSiteTableEntrySymRef, invokeCacheArray, isUnresolved);
3338
3339
if (comp()->getOption(TR_TraceILGen))
3340
printStack(comp(), _stack, "(Stack after load from callsite table)");
3341
3342
TR::Node* callNode = genInvokeDirect(targetMethodSymRef);
3343
3344
#else
3345
3346
TR::SymbolReference *symRef = symRefTab()->findOrCreateDynamicMethodSymbol(_methodSymbol, callSiteIndex);
3347
3348
// Compute the receiver handle
3349
//
3350
loadFromCallSiteTable(callSiteIndex);
3351
TR::Node *receiver = pop();
3352
3353
if (comp()->getOption(TR_TraceILGen))
3354
printStack(comp(), _stack, "(Stack after load from callsite table)");
3355
3356
// If the receiver handle is resolved, we can use a more specific symref
3357
//
3358
TR_ResolvedMethod * owningMethod = _methodSymbol->getResolvedMethod();
3359
if (!owningMethod->isUnresolvedCallSiteTableEntry(callSiteIndex))
3360
{
3361
TR_ResolvedMethod *specimen = fej9()->createMethodHandleArchetypeSpecimen(trMemory(), (uintptr_t*)owningMethod->callSiteTableEntryAddress(callSiteIndex), owningMethod);
3362
if (specimen)
3363
symRef = symRefTab()->findOrCreateMethodSymbol(_methodSymbol->getResolvedMethodIndex(), -1, specimen, TR::MethodSymbol::ComputedVirtual);
3364
}
3365
3366
// Emit the call
3367
//
3368
TR::Node* callNode = genInvokeHandle(symRef, receiver);
3369
3370
_invokeDynamicCalls->set(_bcIndex);
3371
3372
#endif // J9VM_OPT_OPENJDK_METHODHANDLE
3373
}
3374
3375
TR::Node *
3376
TR_J9ByteCodeIlGenerator::genInvokeHandle(int32_t cpIndex)
3377
{
3378
if (comp()->compileRelocatableCode())
3379
{
3380
comp()->failCompilation<J9::AOTHasInvokeHandle>("COMPILATION_AOT_HAS_INVOKEHANDLE 1");
3381
}
3382
3383
if (comp()->getOption(TR_FullSpeedDebug) && !isPeekingMethod())
3384
comp()->failCompilation<J9::FSDHasInvokeHandle>("FSD_HAS_INVOKEHANDLE 1");
3385
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
3386
// Call generated when methodType table entry is resolved:
3387
// -----------------------------------------------------
3388
// call <target method obtained from memberName object>
3389
// aload <Ljava/lang/invoke/MethodHandle;>
3390
// arg0
3391
// arg1
3392
// ...
3393
// aloadi <appendix object>
3394
// ------------------------------------------------------
3395
// Call generated when methodType table entry is unresolved:
3396
// ------------------------------------------------------
3397
// ResolveCHK
3398
// aload <MethodTypeTableEntry @<cpIndex>>
3399
// treetop
3400
// aloadi <appendix object> // array-shadow from MethodTypeTableEntry
3401
// ...
3402
// treetop
3403
// aloadi <memberName object> // array-shadow from MethodTypeTableEntry
3404
// ...
3405
// treetop
3406
// call java/lang/invoke/MethodHandle.linkToStatic(Ljava/lang/Object;arg0arg1...Ljava/lang/Object;Ljava/lang/Object;)<return type>
3407
// aload <Ljava/lang/invoke/MethodHandle;>
3408
// arg0
3409
// arg1
3410
// ...
3411
// aloadi <appendix object>
3412
// aloadi <memberName object>
3413
// ------------------------------------------------------
3414
bool isUnresolved;
3415
TR::SymbolReference * targetMethodSymRef = symRefTab()->findOrCreateHandleMethodSymbol(_methodSymbol, cpIndex, &isUnresolved);
3416
if (isUnresolved)
3417
targetMethodSymRef->getSymbol()->setDummyResolvedMethod(); // linkToStatic is a dummy TR_ResolvedMethod
3418
TR::SymbolReference *methodTypeTableEntrySymRef = symRefTab()->findOrCreateMethodTypeTableEntrySymbol(_methodSymbol, cpIndex);
3419
TR_ResolvedJ9Method* owningMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());
3420
uintptr_t * invokeCacheArray = (uintptr_t *) owningMethod->methodTypeTableEntryAddress(cpIndex);
3421
loadInvokeCacheArrayElements(methodTypeTableEntrySymRef, invokeCacheArray, isUnresolved);
3422
3423
if (comp()->getOption(TR_TraceILGen))
3424
printStack(comp(), _stack, "(Stack after load from method type table)");
3425
3426
TR::Node* callNode = genInvokeDirect(targetMethodSymRef);
3427
3428
#else
3429
3430
TR::SymbolReference * invokeExactSymRef = symRefTab()->findOrCreateHandleMethodSymbol(_methodSymbol, cpIndex);
3431
3432
// Emit the call
3433
//
3434
TR::Node* callNode = genInvokeHandle(invokeExactSymRef);
3435
3436
_invokeHandleCalls->set(_bcIndex);
3437
#endif // J9VM_OPT_OPENJDK_METHODHANDLE
3438
3439
return callNode;
3440
}
3441
3442
TR::Node *
3443
TR_J9ByteCodeIlGenerator::genInvokeHandle(TR::SymbolReference *invokeExactSymRef, TR::Node *invokedynamicReceiver)
3444
{
3445
if (comp()->getOption(TR_TraceILGen))
3446
printStack(comp(), _stack, "(Stack before genInvokeHandle)");
3447
3448
TR::Node* tmpTargetAddress = TR::Node::lconst(0);
3449
TR::Node *callNode = genInvoke(invokeExactSymRef, tmpTargetAddress, invokedynamicReceiver);
3450
_methodSymbol->setMayHaveIndirectCalls(true);
3451
_methodSymbol->setHasMethodHandleInvokes(true);
3452
3453
if (!isPeekingMethod())
3454
{
3455
if (!comp()->getHasMethodHandleInvoke())
3456
{
3457
comp()->setHasMethodHandleInvoke(); // We only want to print this message once per compilation
3458
if (comp()->getOptions()->getVerboseOption(TR_VerboseMethodHandles))
3459
TR_VerboseLog::writeLineLocked(TR_Vlog_MH, "Jitted method contains MethodHandle invoke: %s", comp()->signature());
3460
}
3461
if (comp()->getOptions()->getVerboseOption(TR_VerboseMethodHandleDetails))
3462
{
3463
TR::Method *callee = callNode->getSymbol()->castToMethodSymbol()->getMethod();
3464
TR_VerboseLog::writeLineLocked(TR_Vlog_MHD, "Call to invokeExact%.*s from %s", callee->signatureLength(), callee->signatureChars(), comp()->signature());
3465
}
3466
}
3467
3468
_methodHandleInvokeCalls->set(_bcIndex);
3469
return callNode;
3470
}
3471
3472
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
3473
void
3474
TR_J9ByteCodeIlGenerator::loadInvokeCacheArrayElements(TR::SymbolReference *tableEntrySymRef, uintptr_t * invokeCacheArray, bool isUnresolved)
3475
{
3476
loadSymbol(TR::aload, tableEntrySymRef);
3477
loadConstant(TR::iconst, JSR292_invokeCacheArrayAppendixIndex);
3478
loadArrayElement(TR::Address, comp()->il.opCodeForIndirectArrayLoad(TR::Address), false, false);
3479
if (isUnresolved)
3480
{
3481
// When the callSite table entry (for invokedynamic) or methodType table entry (for invokehandle)
3482
// is unresolved, instead of calling the target method, we construct a call to VM internal native
3483
// method "linkToStatic", which expects the last arg to be the memberName object which it uses to
3484
// obtain the actual target method and construct the call frame for it
3485
loadSymbol(TR::aload, tableEntrySymRef);
3486
loadConstant(TR::iconst, JSR292_invokeCacheArrayMemberNameIndex);
3487
loadArrayElement(TR::Address, comp()->il.opCodeForIndirectArrayLoad(TR::Address), false, false);
3488
}
3489
else
3490
{
3491
// When the callSite table entry (for invokedynamic) or methodType table entry (for invokehandle)
3492
// is resolved, we can improve the appendix object symRef with known object index as we can get
3493
// the object reference of the appendix object from the invokeCacheArray entry
3494
TR_ResolvedJ9Method* owningMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());
3495
TR::Node * appendixNode = _stack->top();
3496
TR::SymbolReference * appendixSymRef =
3497
fej9()->refineInvokeCacheElementSymRefWithKnownObjectIndex(
3498
comp(),
3499
appendixNode->getSymbolReference(),
3500
invokeCacheArray
3501
);
3502
appendixNode->setSymbolReference(appendixSymRef);
3503
}
3504
}
3505
3506
#endif
3507
3508
TR::Node *
3509
TR_J9ByteCodeIlGenerator::genILGenMacroInvokeExact(TR::SymbolReference *invokeExactSymRef)
3510
{
3511
TR_ASSERT(!comp()->compileRelocatableCode(), "Does not support ILGenMacro under AOT bci %d", _bcIndex);
3512
TR_ASSERT(!comp()->getOption(TR_FullSpeedDebug) || isPeekingMethod(), "Does not support ILGenMacro under FSD bci %d", _bcIndex);
3513
TR::Node* callNode = genInvokeHandle(invokeExactSymRef);
3514
3515
_ilGenMacroInvokeExactCalls->set(_bcIndex);
3516
3517
return callNode;
3518
}
3519
3520
TR::Node*
3521
TR_J9ByteCodeIlGenerator::genHandleTypeCheck(TR::Node* handle, TR::Node* expectedType)
3522
{
3523
uint32_t typeOffset = fej9()->getInstanceFieldOffsetIncludingHeader("Ljava/lang/invoke/MethodHandle;", "type", "Ljava/lang/invoke/MethodType;", method());
3524
TR::SymbolReference *typeSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(_methodSymbol,
3525
TR::Symbol::Java_lang_invoke_MethodHandle_type,
3526
TR::Address,
3527
typeOffset,
3528
false,
3529
false,
3530
true,
3531
"java/lang/invoke/MethodHandle.type Ljava/lang/invoke/MethodType;");
3532
3533
TR::Node *handleType = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(TR::Address), 1, 1, handle, typeSymRef);
3534
3535
if (comp()->getOption(TR_TraceILGen))
3536
{
3537
traceMsg(comp(), "Inserted indirect load of MethodHandle.type n%dn %p\n", handleType->getGlobalIndex(), handleType);
3538
}
3539
3540
// Generate zerochk
3541
TR::Node* zerochkNode = TR::Node::createWithSymRef(TR::ZEROCHK, 1, 1,
3542
TR::Node::create(TR::acmpeq, 2, expectedType, handleType),
3543
symRefTab()->findOrCreateMethodTypeCheckSymbolRef(_methodSymbol));
3544
return zerochkNode;
3545
}
3546
3547
TR::Node *
3548
TR_J9ByteCodeIlGenerator::genInvokeHandleGeneric(int32_t cpIndex)
3549
{
3550
if (comp()->compileRelocatableCode())
3551
{
3552
comp()->failCompilation<J9::AOTHasInvokeHandle>("COMPILATION_AOT_HAS_INVOKEHANDLE 2");
3553
}
3554
3555
if (comp()->getOption(TR_FullSpeedDebug) && !isPeekingMethod())
3556
comp()->failCompilation<J9::FSDHasInvokeHandle>("FSD_HAS_INVOKEHANDLE 2");
3557
3558
TR::SymbolReference * invokeGenericSymRef = symRefTab()->findOrCreateHandleMethodSymbol(_methodSymbol, cpIndex);
3559
TR::Method *invokeGeneric = invokeGenericSymRef->getSymbol()->castToMethodSymbol()->getMethod();
3560
TR::SymbolReference *invokeExactOriginal = symRefTab()->methodSymRefFromName(_methodSymbol,
3561
JSR292_MethodHandle, JSR292_invokeExact, JSR292_invokeExactSig, TR::MethodSymbol::ComputedVirtual, invokeGenericSymRef->getCPIndex());
3562
TR::SymbolReference *invokeExactSymRef = symRefTab()->methodSymRefWithSignature(
3563
invokeExactOriginal, invokeGeneric->signatureChars(), invokeGeneric->signatureLength());
3564
3565
TR::Node* callNode = genInvokeHandle(invokeExactSymRef);
3566
3567
_invokeHandleGenericCalls->set(_bcIndex);
3568
return callNode;
3569
}
3570
3571
TR::Node*
3572
TR_J9ByteCodeIlGenerator::genOrFindAdjunct(TR::Node* node)
3573
{
3574
TR::Node *adjunct;
3575
if (node->getOpCode().isLoadDirect())
3576
{
3577
// need to get adjunct symbol corresponding to this symbol, and create a load for it
3578
TR::SymbolReference* symRef = node->getSymbolReference();
3579
TR::DataType type = symRef->getSymbol()->getDataType();
3580
int32_t slot = symRef->getCPIndex();
3581
loadAuto(type, slot, true);
3582
adjunct = pop();
3583
}
3584
else
3585
{
3586
// expect that adjunct part is third child of node
3587
TR_ASSERT(node->isDualHigh() || node->isSelectHigh(),
3588
"this node should be a dual or select, where the adjunct part of the answer is in the third child");
3589
adjunct = node->getChild(2);
3590
if (node->isSelectHigh())
3591
{
3592
adjunct = adjunct->getFirstChild();
3593
}
3594
}
3595
return adjunct;
3596
}
3597
3598
#define STOPME \
3599
{\
3600
static int stopped = 0; \
3601
if (!stopped) \
3602
{\
3603
genDebugCmd(__FILE__, __LINE__);\
3604
stopped = 1;\
3605
}\
3606
}
3607
3608
// Definition of operation to be executed when converting the non standard lengths
3609
struct OperationDescriptor
3610
{
3611
int32_t shiftDistance; // distance to shift, the direction depends on load or store
3612
int32_t offsetAdjustment; // adjustment of the memory offset
3613
int32_t lengthNew; // new length to be stored or loaded
3614
};
3615
static void printOp(char *tags, struct OperationDescriptor *op)
3616
{
3617
printf("[%s] shift:%d, ajdust:%d, length:%d\n",
3618
tags?tags:"OP",
3619
op->shiftDistance, op->offsetAdjustment,
3620
op->lengthNew);
3621
}
3622
3623
static struct OperationDescriptor opsLength3[] =
3624
{
3625
{0,2,1},{8,0,2}, // big-endian
3626
{0,0,1},{8,1,2} // little-endian
3627
};
3628
static struct OperationDescriptor opsLength5[] =
3629
{
3630
{0,4,1}, {8,0,4}, // big-endian
3631
{0,0,1}, {8,1,4} // little-endian
3632
};
3633
static struct OperationDescriptor opsLength6[] =
3634
{
3635
{0,4,2}, {16,0,4}, // big-endian
3636
{0,0,2}, {16,2,4} // little-endian
3637
};
3638
static struct OperationDescriptor opsLength7[] =
3639
{
3640
{0,6,1}, {8,4,2}, {24,0,4}, // big-endian
3641
{0,0,1}, {8,1,2}, {24,3,4} // little-endian
3642
};
3643
static struct OperationDescriptor *opsNonStandardLengths[] =
3644
{ 0, 0, 0, opsLength3, 0, opsLength5, opsLength6, opsLength7 };
3645
static int32_t numOpsNonStandardLengths[] =
3646
{ 0, 0, 0, 2, 0, 2, 2, 3};
3647
3648
TR::Node *
3649
TR_J9ByteCodeIlGenerator::getReceiverFor(TR::SymbolReference *symRef)
3650
{
3651
TR::Method * method = symRef->getSymbol()->castToMethodSymbol()->getMethod();
3652
int32_t receiverDepth = method->numberOfExplicitParameters(); // look past all the explicit arguments
3653
return _stack->element(_stack->topIndex() - receiverDepth);
3654
}
3655
3656
TR::Node *
3657
TR_J9ByteCodeIlGenerator::genInvokeWithVFTChild(TR::SymbolReference *symRef)
3658
{
3659
TR::Node *receiver = getReceiverFor(symRef);
3660
TR::Node *vftLoad = TR::Node::createWithSymRef(TR::aloadi, 1, 1, receiver, symRefTab()->findOrCreateVftSymbolRef());
3661
return genInvoke(symRef, vftLoad);
3662
}
3663
3664
3665
3666
3667
TR::Node*
3668
TR_J9ByteCodeIlGenerator::genInvoke(TR::SymbolReference * symRef, TR::Node *indirectCallFirstChild, TR::Node *invokedynamicReceiver)
3669
{
3670
TR::MethodSymbol * symbol = symRef->getSymbol()->castToMethodSymbol();
3671
bool isStatic = symbol->isStatic();
3672
bool isDirectCall = indirectCallFirstChild == NULL;
3673
3674
TR::Method * calledMethod = symbol->getMethod();
3675
int32_t numArgs = calledMethod->numberOfExplicitParameters() + (isStatic ? 0 : 1);
3676
3677
TR::ILOpCodes opcode = TR::BadILOp;
3678
switch (symbol->getRecognizedMethod())
3679
{
3680
case TR::java_lang_Integer_valueOf:
3681
// TODO: It's gross that ilgen knows what a dememoization opportunity is. This should be refactored.
3682
_methodSymbol->setHasDememoizationOpportunities(true);
3683
break;
3684
default:
3685
break;
3686
}
3687
3688
if (comp()->cg()->getSupportsBitOpCodes() && !comp()->getOption(TR_DisableBitOpcode))
3689
{
3690
switch (symbol->getRecognizedMethod())
3691
{
3692
case TR::java_lang_Integer_highestOneBit:
3693
opcode = TR::ihbit;
3694
break;
3695
case TR::java_lang_Integer_lowestOneBit:
3696
if(comp()->target().cpu.isX86() || comp()->target().cpu.isARM64())
3697
opcode = TR::ilbit;
3698
else
3699
opcode = TR::BadILOp;
3700
break;
3701
case TR::java_lang_Integer_numberOfLeadingZeros:
3702
opcode = TR::inolz;
3703
break;
3704
case TR::java_lang_Integer_numberOfTrailingZeros:
3705
opcode = TR::inotz;
3706
break;
3707
case TR::java_lang_Integer_bitCount:
3708
if (comp()->target().cpu.hasPopulationCountInstruction())
3709
opcode = TR::ipopcnt;
3710
else
3711
opcode = TR::BadILOp;
3712
break;
3713
case TR::java_lang_Long_highestOneBit:
3714
opcode = TR::lhbit;
3715
break;
3716
case TR::java_lang_Long_lowestOneBit:
3717
if(comp()->target().cpu.isX86() || comp()->target().cpu.isARM64())
3718
opcode = TR::llbit;
3719
else
3720
opcode = TR::BadILOp;
3721
break;
3722
case TR::java_lang_Long_numberOfLeadingZeros:
3723
opcode = TR::lnolz;
3724
break;
3725
case TR::java_lang_Long_numberOfTrailingZeros:
3726
opcode = TR::lnotz;
3727
break;
3728
case TR::java_lang_Long_bitCount:
3729
if (comp()->target().cpu.hasPopulationCountInstruction())
3730
opcode = TR::lpopcnt;
3731
else
3732
opcode = TR::BadILOp;
3733
break;
3734
default:
3735
break;
3736
}
3737
}
3738
3739
if (opcode != TR::BadILOp)
3740
{
3741
performTransformation(comp(), "O^O BIT OPCODE: convert call to method %s to bit opcode\n",calledMethod->signature(trMemory()));
3742
TR::Node * node = TR::Node::create(opcode, 1);
3743
node->setAndIncChild(0, pop());
3744
push(node);
3745
return node;
3746
}
3747
3748
#if !defined(TR_HOST_ARM) && !defined(TR_HOST_ARM64)
3749
3750
if (comp()->supportsQuadOptimization())
3751
{
3752
// Under DLT, the Quad opts don't work because the interpreted Quad
3753
// operations will produce Quad objects, but the jitted ones will assume
3754
// they have been turned into longs.
3755
3756
switch (symbol->getRecognizedMethod())
3757
{
3758
case TR::com_ibm_Compiler_Internal_Quad_enableQuadOptimization:
3759
{
3760
// Quad opts have the potential to make things way worse if we
3761
// don't recognize the methods and special-case them here. However,
3762
// if we recognize enableQuadOptimizations, we should have no trouble
3763
// recognizing the rest.
3764
//
3765
loadConstant(TR::iconst, 1);
3766
return _stack->top();
3767
}
3768
case TR::com_ibm_Compiler_Internal_Quad_mul_ll:
3769
{
3770
// lumulh main operator
3771
// x
3772
// y
3773
// lmul adjunct
3774
// ==> x
3775
// ==> y
3776
TR::Node* y = pop();
3777
TR::Node* x = pop();
3778
TR::Node* lmul = TR::Node::create(TR::lmul, 2, x, y);
3779
TR::Node* lumulh = TR::Node::create(TR::lumulh, 3, x, y, lmul);
3780
push(lumulh);
3781
return lumulh;
3782
break;
3783
}
3784
case TR::com_ibm_Compiler_Internal_Quad_hi:
3785
{
3786
// hi(w)
3787
TR::Node* wh = pop();
3788
push(wh);
3789
return wh;
3790
break;
3791
}
3792
case TR::com_ibm_Compiler_Internal_Quad_lo:
3793
{
3794
// lo(w)
3795
TR::Node* wh = pop();
3796
TR::Node* wl = genOrFindAdjunct(wh);
3797
push(wl);
3798
return wl;
3799
break;
3800
}
3801
case TR::com_ibm_Compiler_Internal_Quad_add_ll:
3802
{
3803
// add two unsigned longs to produce a quad
3804
//
3805
// luaddc main operator
3806
// lconst 0
3807
// lconst 0
3808
// computeCC
3809
// ladd adjunct operator
3810
// x
3811
// y
3812
TR::Node* y = pop();
3813
TR::Node* x = pop();
3814
TR::Node* zero = TR::Node::create(TR::lconst, 0, 0);
3815
TR::Node* ladd = TR::Node::create(TR::ladd, 2, x, y);
3816
TR::Node* carry = TR::Node::create(TR::computeCC, 1, ladd);
3817
TR::Node* luaddc = TR::Node::create(TR::luaddc, 3, zero, zero, carry);
3818
push(luaddc);
3819
return luaddc;
3820
break;
3821
}
3822
case TR::com_ibm_Compiler_Internal_Quad_add_ql:
3823
{
3824
// luaddc main operator
3825
// wh
3826
// lconst 0
3827
// computeCC
3828
// ladd adjunct operator
3829
// wl
3830
// x
3831
TR::Node* x = pop();
3832
TR::Node* wh = pop();
3833
TR::Node* wl = genOrFindAdjunct(wh);
3834
TR::Node* zero = TR::Node::create(TR::lconst, 0, 0);
3835
TR::Node* ladd = TR::Node::create(TR::ladd, 2, wl, x);
3836
TR::Node* carry = TR::Node::create(TR::computeCC, 1, ladd);
3837
TR::Node* luaddc = TR::Node::create(TR::luaddc, 3, wh, zero, carry);
3838
push(luaddc);
3839
return luaddc;
3840
break;
3841
}
3842
case TR::com_ibm_Compiler_Internal_Quad_sub_ll:
3843
{
3844
// sub two unsigned longs to produce a quad
3845
//
3846
// lusubb main operator
3847
// lconst 0
3848
// lconst 0
3849
// computeCC
3850
// lsub adjunct operator
3851
// x
3852
// y
3853
TR::Node* y = pop();
3854
TR::Node* x = pop();
3855
TR::Node* zero = TR::Node::create(TR::lconst, 0, 0);
3856
TR::Node* lsub = TR::Node::create(TR::lsub, 2, x, y);
3857
TR::Node* borrow = TR::Node::create(TR::computeCC, 1, lsub);
3858
TR::Node* lusubb = TR::Node::create(TR::lusubb, 3, zero, zero, borrow);
3859
push(lusubb);
3860
return lusubb;
3861
break;
3862
}
3863
case TR::com_ibm_Compiler_Internal_Quad_sub_ql:
3864
{
3865
// lusubb main operator
3866
// wh
3867
// lconst 0
3868
// computeCC
3869
// lsub adjunct operator
3870
// wl
3871
// x
3872
TR::Node* x = pop();
3873
TR::Node* wh = pop();
3874
TR::Node* wl = genOrFindAdjunct(wh);
3875
TR::Node* zero = TR::Node::create(TR::lconst, 0, 0);
3876
TR::Node* lsub = TR::Node::create(TR::lsub, 2, wl, x);
3877
TR::Node* borrow = TR::Node::create(TR::computeCC, 1, lsub);
3878
TR::Node* lusubb = TR::Node::create(TR::lusubb, 3, wh, zero, borrow);
3879
push(lusubb);
3880
return lusubb;
3881
break;
3882
}
3883
default:
3884
break;
3885
}
3886
}
3887
#endif
3888
3889
if (symbol->getRecognizedMethod() == TR::com_ibm_Compiler_Internal__TR_Prefetch)
3890
{
3891
TR::Node *node = NULL;
3892
3893
if ((comp()->getOptLevel() < hot))
3894
{
3895
int i = 0;
3896
for (i=0; i<numArgs; i++)
3897
genTreeTop(pop());
3898
return node;
3899
}
3900
3901
// Get the type of prefetch
3902
PrefetchType prefetchType = NoPrefetch;
3903
TR::Method *method = symbol->castToMethodSymbol()->getMethod();
3904
if (method->nameLength() == 15 && !strncmp(method->nameChars(), "_TR_Release_All", 15))
3905
{
3906
prefetchType = ReleaseAll;
3907
}
3908
else if (method->nameLength() == 17 && !strncmp(method->nameChars(), "_TR_Prefetch_Load", 17))
3909
{
3910
prefetchType = PrefetchLoad;
3911
}
3912
else if (method->nameLength() == 18 && !strncmp(method->nameChars(), "_TR_Prefetch_Store", 18))
3913
{
3914
prefetchType = PrefetchStore;
3915
}
3916
else if (method->nameLength() == 20)
3917
{
3918
if (!strncmp(method->nameChars(), "_TR_Prefetch_LoadNTA", 20))
3919
prefetchType = PrefetchLoadNonTemporal;
3920
else if (!strncmp(method->nameChars(), "_TR_Prefetch_Load_L1", 20))
3921
prefetchType = PrefetchLoadL1;
3922
else if (!strncmp(method->nameChars(), "_TR_Prefetch_Load_L2", 20))
3923
prefetchType = PrefetchLoadL2;
3924
else if (!strncmp(method->nameChars(), "_TR_Prefetch_Load_L3", 20))
3925
prefetchType = PrefetchLoadL3;
3926
}
3927
else if (method->nameLength() == 21)
3928
{
3929
if (!strncmp(method->nameChars(), "_TR_Prefetch_StoreNTA", 21))
3930
prefetchType = PrefetchStoreNonTemporal;
3931
else if (!strncmp(method->nameChars(), "_TR_Release_StoreOnly", 21))
3932
prefetchType = ReleaseStore;
3933
}
3934
else if (method->nameLength() == 29 && !strncmp(method->nameChars(), "_TR_Prefetch_StoreConditional", 29))
3935
{
3936
prefetchType = PrefetchStoreConditional;
3937
}
3938
3939
TR::Node *n2 = pop();
3940
if (2 == numArgs && n2->getOpCode().isInt())
3941
{
3942
node = TR::Node::createWithSymRef(TR::Prefetch, 4, symRef);
3943
TR::Node *addrNode = pop();
3944
3945
// For constant 2nd arguments, we'll add it to the offset.
3946
if (n2->getOpCode().isLoadConst())
3947
{
3948
// TR::Prefetch 1st child: address
3949
node->setAndIncChild(0, addrNode);
3950
// TR::Prefetch 2nd child: offset
3951
node->setAndIncChild(1, n2);
3952
}
3953
else
3954
{
3955
// TR::Prefetch 1st child: address
3956
// aiadd
3957
// addrNode
3958
// offsetNode
3959
TR::Node * aiaddNode = TR::Node::create(TR::aiadd, 2, addrNode, n2);
3960
node->setAndIncChild(0, aiaddNode);
3961
3962
// TR::Prefetch 2nd child: Set offset to be zero.
3963
TR::Node * offsetNode = TR::Node::create(TR::iconst, 0, 0);
3964
node->setAndIncChild(1, offsetNode);
3965
}
3966
3967
// TR::Prefetch 3rd child : size
3968
TR::Node * size = TR::Node::create(TR::iconst, 0, 1);
3969
node->setAndIncChild(2, size);
3970
3971
// TR::Prefetch 4th child : type
3972
TR::Node * type = TR::Node::create(TR::iconst, 0, (int32_t)prefetchType);
3973
node->setAndIncChild(3, type);
3974
3975
genTreeTop(node);
3976
}
3977
else if (3 == numArgs || 2 == numArgs)
3978
{
3979
TR::Node * n3 = n2; // it's already popped above
3980
TR::Node * n2 = pop();
3981
TR::Node * n1 = (numArgs == 3) ? pop() : NULL;
3982
3983
if (n3->getSymbolReference() &&
3984
n3->getSymbolReference()->getSymbol()->isStatic() &&
3985
n3->getSymbolReference()->getSymbol()->castToStaticSymbol()->isConstString() &&
3986
n2->getSymbolReference() &&
3987
n2->getSymbolReference()->getSymbol()->isStatic() &&
3988
n2->getSymbolReference()->getSymbol()->castToStaticSymbol()->isConstString())
3989
{
3990
uintptr_t offset = fej9()->getFieldOffset(comp(), n2->getSymbolReference(), n3->getSymbolReference() );
3991
if (offset)
3992
{
3993
TR::Node * n ;
3994
if (comp()->target().is32Bit() ||
3995
(int32_t)(((uint32_t)((uint64_t)offset >> 32)) & 0xffffffff) == (uint32_t)0)
3996
{
3997
n = TR::Node::create(TR::iconst, 0, offset);
3998
}
3999
else
4000
{
4001
n = TR::Node::create(TR::lconst, 0, 0);
4002
n->setLongInt(offset);
4003
}
4004
if (numArgs == 3)
4005
{
4006
node = TR::Node::createWithSymRef(TR::Prefetch, 4, symRef);
4007
node->setAndIncChild(1, n);
4008
node->setAndIncChild(0, n1);
4009
}
4010
else
4011
{
4012
node = TR::Node::createWithSymRef(TR::Prefetch, 4, symRef);
4013
node->setAndIncChild(0, n);
4014
TR::Node * offsetNode = TR::Node::create(TR::iconst, 0, 0);
4015
node->setAndIncChild(1, offsetNode);
4016
}
4017
4018
// TR::Prefetch 3rd child : size
4019
TR::Node * size = TR::Node::create(TR::iconst, 0, 1);
4020
node->setAndIncChild(2, size);
4021
4022
// TR::Prefetch 4th child : type
4023
TR::Node * type = TR::Node::create(TR::iconst, 0, (int32_t)prefetchType);
4024
node->setAndIncChild(3, type);
4025
4026
genTreeTop(node);
4027
}
4028
else
4029
{
4030
// Generate treetops to retain proper reference count.
4031
genTreeTop(n2);
4032
genTreeTop(n3);
4033
if (n1)
4034
genTreeTop(n1);
4035
4036
traceMsg(comp(),"Prefetch: Unable to resolve offset.\n");
4037
}
4038
}
4039
}
4040
else
4041
{
4042
TR_ASSERT(0, "TR::Prefetch does not have two or three children");
4043
}
4044
4045
return node;
4046
}
4047
4048
#define DAA_PRINT(a) \
4049
case a: \
4050
if(trace()) \
4051
traceMsg(comp(), "DAA Method found: %s\n", #a); \
4052
break
4053
4054
//print out the method name and ILCode from the
4055
switch (symbol->getRecognizedMethod())
4056
{
4057
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeShort);
4058
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeShortLength);
4059
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeInt);
4060
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeIntLength);
4061
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeLong);
4062
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeLongLength);
4063
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeFloat);
4064
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeDouble);
4065
4066
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readShort);
4067
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readShortLength);
4068
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readInt);
4069
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readIntLength);
4070
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readLong);
4071
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readLongLength);
4072
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readFloat);
4073
DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readDouble);
4074
4075
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_JITIntrinsicsEnabled);
4076
4077
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertIntegerToPackedDecimal);
4078
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertIntegerToPackedDecimal_ByteBuffer);
4079
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToInteger);
4080
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToInteger_ByteBuffer);
4081
4082
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertLongToPackedDecimal);
4083
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertLongToPackedDecimal_ByteBuffer);
4084
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToLong);
4085
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToLong_ByteBuffer);
4086
4087
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertExternalDecimalToPackedDecimal);
4088
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToExternalDecimal);
4089
4090
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertUnicodeDecimalToPackedDecimal);
4091
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToUnicodeDecimal);
4092
4093
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertLongToExternalDecimal);
4094
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertExternalDecimalToLong);
4095
4096
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertIntegerToExternalDecimal);
4097
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertExternalDecimalToInteger);
4098
4099
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertUnicodeDecimalToInteger);
4100
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertIntegerToUnicodeDecimal);
4101
4102
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertUnicodeDecimalToLong);
4103
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertLongToUnicodeDecimal);
4104
4105
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToBigInteger);
4106
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigIntegerToPackedDecimal);
4107
4108
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertExternalDecimalToBigInteger);
4109
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigIntegerToExternalDecimal);
4110
4111
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertUnicodeDecimalToBigInteger);
4112
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigIntegerToUnicodeDecimal);
4113
4114
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigDecimalToPackedDecimal);
4115
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToBigDecimal);
4116
4117
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigDecimalToExternalDecimal);
4118
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertExternalDecimalToBigDecimal);
4119
4120
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigDecimalToUnicodeDecimal);
4121
DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertUnicodeDecimalToBigDecimal);
4122
4123
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_addPackedDecimal);
4124
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_subtractPackedDecimal);
4125
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_multiplyPackedDecimal);
4126
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_dividePackedDecimal);
4127
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_remainderPackedDecimal);
4128
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_greaterThanPackedDecimal);
4129
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_greaterThanOrEqualsPackedDecimal);
4130
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_lessThanPackedDecimal);
4131
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_lessThanOrEqualsPackedDecimal);
4132
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_equalsPackedDecimal);
4133
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_notEqualsPackedDecimal);
4134
4135
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_checkPackedDecimal);
4136
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_checkPackedDecimal_2bInlined2);
4137
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_checkPackedDecimal_2bInlined1);
4138
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_shiftLeftPackedDecimal);
4139
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_shiftRightPackedDecimal);
4140
DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_movePackedDecimal);
4141
4142
default:
4143
break;
4144
}
4145
4146
if(symbol->getRecognizedMethod() == TR::com_ibm_dataaccess_DecimalData_JITIntrinsicsEnabled)
4147
{
4148
bool isZLinux = comp()->target().isLinux() && comp()->target().cpu.isZ();
4149
int32_t constVal = (comp()->target().isZOS() || isZLinux) &&
4150
!comp()->getOption(TR_DisablePackedDecimalIntrinsics) ? 1 : 0;
4151
4152
loadConstant(TR::iconst, constVal);
4153
return NULL;
4154
}
4155
4156
/**
4157
* java/lang/invoke/MethodHandleImpl.profileBoolean() performs some internal profiling
4158
* on the boolean parameter value before returning it. Since the OpenJ9 JIT does not
4159
* consume that profiling information the profiling overhead is not necessary. Eliminate
4160
* the call and simply replace it with a reference to the boolean parameter.
4161
*/
4162
if (symbol->getRecognizedMethod() == TR::java_lang_invoke_MethodHandleImpl_profileBoolean)
4163
{
4164
pop();
4165
TR::Node *resultNode = _stack->top();
4166
genTreeTop(resultNode);
4167
return resultNode;
4168
}
4169
4170
// Can't use recognized methods since it's not enabled on AOT
4171
//if (symbol->getRecognizedMethod() == TR::com_ibm_rmi_io_FastPathForCollocated_isVMDeepCopySupported)
4172
int32_t len = calledMethod->classNameLength();
4173
char * s = TR::Compiler->cls.classNameToSignature(calledMethod->classNameChars(), len, comp());
4174
4175
if (strstr(s, "com/ibm/rmi/io/FastPathForCollocated") &&
4176
!strncmp(calledMethod->nameChars(), "isVMDeepCopySupported", calledMethod->nameLength()))
4177
{
4178
loadConstant(TR::iconst, 1);
4179
return NULL;
4180
}
4181
else if (!strncmp(comp()->getCurrentMethod()->classNameChars(), "com/ibm/jit/JITHelpers", 22))
4182
{
4183
// fast pathing for JITHelpers
4184
//
4185
// do not do this transformation if the current method is com/ibm/jit/JITHelpers.is32Bit
4186
// inlineNativeCall will take care of doing the right thing
4187
//
4188
bool isCall32bit = false;
4189
if (strstr(s, "com/ibm/jit/JITHelpers") &&
4190
!strncmp(calledMethod->nameChars(), "is32Bit", calledMethod->nameLength()))
4191
isCall32bit = true;
4192
#if 0
4193
bool fold = true;
4194
if (!strncmp(comp()->getCurrentMethod()->nameChars(), "is32Bit", 7))
4195
fold = false;
4196
4197
if (fold && indirectCallFirstChild && isCall32bit)
4198
{
4199
// fold away the check if possible
4200
int32_t value = comp()->target().is64Bit() ? 0 : 1;
4201
loadConstant(TR::iconst, value);
4202
// cleanup the receiver because its not going to be used anymore
4203
//
4204
indirectCallFirstChild->incReferenceCount();
4205
indirectCallFirstChild->recursivelyDecReferenceCount();
4206
return NULL;
4207
}
4208
#endif
4209
}
4210
4211
if (comp()->cg()->getSupportsInlineConcurrentLinkedQueue() && (TR::Compiler->om.writeBarrierType() != gc_modron_wrtbar_satb) &&
4212
(symbol->getRecognizedMethod() == TR::java_util_concurrent_ConcurrentLinkedQueue_tmEnabled))
4213
{
4214
loadConstant(TR::iconst, 1);
4215
return NULL;
4216
}
4217
4218
if (symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_supportsIntrinsicCaseConversion)
4219
{
4220
pop(); //pop the receiver since it's not used
4221
loadConstant(TR::iconst, cg()->getSupportsInlineStringCaseConversion() ? 1 : 0);
4222
return NULL;
4223
}
4224
4225
if (!isStatic && _classInfo && !symRef->isUnresolved())
4226
{
4227
if (!_classInfo->getFieldInfo())
4228
performClassLookahead(_classInfo);
4229
4230
int32_t len = calledMethod->classNameLength();
4231
char * s = TR::Compiler->cls.classNameToSignature(calledMethod->classNameChars(), len, comp());
4232
4233
TR::Node * thisObject = invokedynamicReceiver ? invokedynamicReceiver : _stack->element(_stack->topIndex() - (numArgs-1));
4234
TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), thisObject, false) : NULL;
4235
if (fieldInfo && fieldInfo->isTypeInfoValid())
4236
{
4237
if (fieldInfo->getNumChars() == len && !memcmp(s, fieldInfo->getClassPointer(), len))
4238
{
4239
if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Devirtualizing call to method %s on receiver object %p which has type %.*s based on class file examination\n", calledMethod->signature(trMemory()), thisObject, len, s))
4240
isDirectCall = true;
4241
}
4242
}
4243
else if (fieldInfo &&
4244
fieldInfo->isBigDecimalType())
4245
{
4246
if (22 == len && !memcmp(s, "Ljava/math/BigDecimal;", len))
4247
{
4248
if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Devirtualizing call to method %s on receiver object %p which has type %.*s based on class file examination\n", calledMethod->signature(trMemory()), thisObject, len, s))
4249
isDirectCall = true;
4250
}
4251
}
4252
else if (fieldInfo &&
4253
fieldInfo->isBigIntegerType())
4254
{
4255
if (22 == len && !memcmp(s, "Ljava/math/BigInteger;", len))
4256
{
4257
if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Devirtualizing call to method %s on receiver object %p which has type %.*s based on class file examination\n", calledMethod->signature(trMemory()), thisObject, len, s))
4258
isDirectCall = true;
4259
}
4260
}
4261
}
4262
4263
TR::Node * callNode;
4264
TR::Node * receiver = 0;
4265
if (isDirectCall)
4266
{
4267
TR::ILOpCodes callOpCode = calledMethod->directCallOpCode();
4268
TR::ResolvedMethodSymbol *resolvedMethodSymbol = symbol->getResolvedMethodSymbol();
4269
bool needToGenAndPop = false;
4270
if (resolvedMethodSymbol)
4271
{
4272
if (resolvedMethodSymbol->getRecognizedMethod() == TR::java_lang_Class_newInstanceImpl && // the method being called
4273
_methodSymbol->getRecognizedMethod() == TR::java_lang_Class_newInstance && // method we are doing genIl for
4274
comp()->getJittedMethodSymbol()->getRecognizedMethod() != TR::java_lang_Class_newInstance && // method we are compiling
4275
!isPeekingMethod() &&
4276
cg()->getSupportsNewInstanceImplOpt() &&
4277
!comp()->getOption(TR_DisableInliningOfNatives) &&
4278
!comp()->compileRelocatableCode() && // disable when AOTing
4279
!comp()->getOptions()->realTimeGC() &&
4280
!comp()->getOption(TR_DisableNewInstanceImplOpt)) // the caller of Class.newInstance()
4281
{
4282
TR_ASSERT(numArgs == 1, "unexpected numChildren on newInstanceImpl call");
4283
callNode = genNewInstanceImplCall(pop());
4284
calledMethod = callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->getMethod();
4285
}
4286
else
4287
needToGenAndPop = true;
4288
}
4289
else
4290
needToGenAndPop = true;
4291
4292
if (needToGenAndPop)
4293
{
4294
callNode = genNodeAndPopChildren(callOpCode, numArgs, symRef);
4295
}
4296
if (!isStatic)
4297
receiver = callNode->getChild(0);
4298
if (receiver && receiver->isThisPointer())
4299
{
4300
callNode->getByteCodeInfo().setIsSameReceiver(1);
4301
}
4302
}
4303
else
4304
{
4305
TR::ILOpCodes callOpCode = calledMethod->indirectCallOpCode();
4306
if (invokedynamicReceiver)
4307
{
4308
// invokedynamic is an oddball. It's the only way to invoke a method
4309
// such that the receiver is NOT on the operand stack, yet it IS
4310
// included in the numArgs calculation. That's why we pass
4311
// numChildren as numArgs+1 below.
4312
//
4313
callNode = genNodeAndPopChildren(callOpCode, numArgs + 1, symRef, 2);
4314
callNode->setAndIncChild(0, indirectCallFirstChild);
4315
callNode->setAndIncChild(1, invokedynamicReceiver);
4316
}
4317
else
4318
{
4319
callNode = genNodeAndPopChildren(callOpCode, numArgs + 1, symRef, 1);
4320
callNode->setAndIncChild(0, indirectCallFirstChild);
4321
}
4322
4323
if (!isStatic)
4324
receiver = callNode->getChild(1);
4325
4326
if (receiver && receiver->isThisPointer())
4327
{
4328
callNode->getByteCodeInfo().setIsSameReceiver(1);
4329
}
4330
}
4331
4332
if (cg()->getSupportsInlineStringCaseConversion() &&
4333
(symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_toUpperIntrinsicLatin1 ||
4334
symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_toLowerIntrinsicLatin1 ||
4335
symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_toUpperIntrinsicUTF16 ||
4336
symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_toLowerIntrinsicUTF16))
4337
{
4338
isDirectCall = true;
4339
}
4340
4341
if (!comp()->getOption(TR_DisableSIMDDoubleMaxMin))
4342
{
4343
bool platformSupported = comp()->target().cpu.isZ();
4344
bool vecInstrAvailable = cg()->getSupportsVectorRegisters();
4345
4346
if (platformSupported && vecInstrAvailable &&
4347
(symbol->getRecognizedMethod() == TR::java_lang_Math_max_D ||
4348
symbol->getRecognizedMethod() == TR::java_lang_Math_min_D))
4349
{
4350
isDirectCall = true;
4351
}
4352
}
4353
4354
4355
if (comp()->getOptions()->getEnableGPU(TR_EnableGPU) &&
4356
strcmp(symbol->getMethod()->signature(trMemory()),
4357
"java/util/stream/IntStream.forEach(Ljava/util/function/IntConsumer;)V") == 0) // might not be resolved
4358
{
4359
//This prevents recompilation at profiled very hot which also prevents the method from reaching scorching
4360
//If JIT GPU works with profiled very hot or scorching in the future, this can be removed.
4361
TR::Recompilation *recompilationInfo = comp()->getRecompilationInfo();
4362
if (recompilationInfo)
4363
recompilationInfo->getJittedBodyInfo()->setDisableSampling(true);
4364
4365
comp()->setHasIntStreamForEach();
4366
4367
if (comp()->getOptLevel() < scorching &&
4368
!comp()->getOptimizationPlan()->getDontFailOnPurpose())
4369
{
4370
comp()->failCompilation<J9::LambdaEnforceScorching>("Enforcing optLevel=scorching");
4371
}
4372
}
4373
4374
// fast pathing for ORB readObject optimization
4375
//
4376
bool canDoSerializationOpt = true;
4377
if (callNode && callNode->getOpCode().hasSymbolReference() && !callNode->getSymbolReference()->isUnresolved() &&
4378
(_methodSymbol->getResolvedMethod()->nameLength() == ORB_CALLER_METHOD_NAME_LEN) &&
4379
!strncmp(_methodSymbol->getResolvedMethod()->nameChars(), ORB_CALLER_METHOD_NAME, ORB_CALLER_METHOD_NAME_LEN) &&
4380
(_methodSymbol->getResolvedMethod()->signatureLength() == ORB_CALLER_METHOD_SIG_LEN) &&
4381
!strncmp(_methodSymbol->getResolvedMethod()->signatureChars(), ORB_CALLER_METHOD_SIG, ORB_CALLER_METHOD_SIG_LEN))
4382
{
4383
if (comp()->getOption(TR_TraceILGen))
4384
traceMsg(comp(), "handling callNode %p, current method %s\n", callNode, _methodSymbol->getResolvedMethod()->signature(trMemory()));
4385
4386
TR::Node *receiver = callNode->getFirstArgument();
4387
if (receiver && receiver->getOpCode().hasSymbolReference() && receiver->getSymbol()->isParm() && !receiver->isThisPointer() &&
4388
(calledMethod->nameLength() == ORB_CALLEE_METHOD_NAME_LEN) &&
4389
!strncmp(calledMethod->nameChars(), ORB_CALLEE_METHOD_NAME, ORB_CALLEE_METHOD_NAME_LEN) &&
4390
(calledMethod->signatureLength() == ORB_CALLEE_METHOD_SIG_LEN) &&
4391
!strncmp(calledMethod->signatureChars(), ORB_CALLEE_METHOD_SIG, ORB_CALLEE_METHOD_SIG_LEN))
4392
{
4393
TR_OpaqueClassBlock *cl = _methodSymbol->getResolvedMethod()->containingClass();
4394
4395
if (comp()->getOption(TR_TraceILGen))
4396
traceMsg(comp(), "called method %s, containing class %p\n", calledMethod->signature(trMemory()), cl);
4397
4398
bool isClassInitialized = false;
4399
TR_PersistentClassInfo * classInfo = comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(cl, comp());
4400
if (classInfo && classInfo->isInitialized())
4401
isClassInitialized = true;
4402
4403
if (comp()->getOption(TR_TraceILGen))
4404
traceMsg(comp(), "isClassInitialized = %d\n", isClassInitialized);
4405
4406
if (isClassInitialized)
4407
{
4408
TR_OpaqueClassBlock *orbClass = fej9()->getClassFromSignature(ORB_REPLACE_CLASS_NAME, ORB_REPLACE_CLASS_LEN, callNode->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod());
4409
4410
if (comp()->getOption(TR_TraceILGen))
4411
traceMsg(comp(), "orbClass = %p, orbClassLoader %s systemClassLoader\n", orbClass, (!fej9()->isClassLoadedBySystemClassLoader(cl)) ? "!=" : "==");
4412
4413
// PR107804 if the ORB class is loaded we cannot do the serialization opt since the
4414
// ObjectInputStream.redirectedReadObject cannot handle ORB for some reason
4415
if (orbClass)
4416
{
4417
canDoSerializationOpt = false;
4418
}
4419
4420
if (orbClass && !fej9()->isClassLoadedBySystemClassLoader(cl))
4421
{
4422
TR_ScratchList<TR_ResolvedMethod> methods(trMemory());
4423
fej9()->getResolvedMethods(trMemory(), orbClass, &methods);
4424
ListIterator<TR_ResolvedMethod> it(&methods);
4425
TR_ResolvedMethod *replacementMethod;
4426
for (replacementMethod = it.getCurrent(); replacementMethod; replacementMethod = it.getNext())
4427
{
4428
if (replacementMethod->nameLength() == ORB_REPLACE_METHOD_NAME_LEN && !strncmp(replacementMethod->nameChars(), ORB_REPLACE_METHOD_NAME, ORB_REPLACE_METHOD_NAME_LEN))
4429
{
4430
if ((replacementMethod->signatureLength() == ORB_REPLACE_METHOD_SIG_LEN) &&
4431
!strncmp(replacementMethod->signatureChars(), ORB_REPLACE_METHOD_SIG, ORB_REPLACE_METHOD_SIG_LEN))
4432
break; // found it
4433
}
4434
}
4435
4436
if (replacementMethod)
4437
{
4438
if (performTransformation(comp(), "O^O ORB OPTIMIZATION : changing ObjectInputStream.readObject call to ORB redirectedReadObject\n"))
4439
{
4440
TR::Node *clazzLoad = TR::Node::createWithSymRef(TR::loadaddr, 0, symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, cl));
4441
TR::Node *jlClazzLoad = TR::Node::createWithSymRef(TR::aloadi, 1, 1, clazzLoad, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());
4442
4443
push(receiver);
4444
push(jlClazzLoad);
4445
TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodSymbol(_methodSymbol->getResolvedMethodIndex(), -1, replacementMethod, TR::MethodSymbol::Static);
4446
callNode = genNodeAndPopChildren(replacementMethod->directCallOpCode(), 2, symRef);
4447
isStatic = true;
4448
callNode->getChild(0)->recursivelyDecReferenceCount();
4449
}
4450
}
4451
}
4452
}
4453
}
4454
}
4455
4456
if (comp()->getOption(TR_TraceILGen))
4457
traceMsg(comp(), "considering callNode %p for java serialization optimization\n", callNode);
4458
if (canDoSerializationOpt && callNode && callNode->getOpCode().hasSymbolReference() && !callNode->getSymbolReference()->isUnresolved() &&
4459
callNode->getOpCode().isCallDirect())
4460
{
4461
if (comp()->getOption(TR_TraceILGen))
4462
traceMsg(comp(), "looking at receiver sig for callNode %p\n", callNode);
4463
TR::Node *receiver = callNode->getFirstArgument();
4464
if (receiver && receiver->getOpCode().hasSymbolReference())
4465
{
4466
TR::SymbolReference *receiverSymRef = receiver->getSymbolReference();
4467
int32_t receiverLen;
4468
const char *receiverSig = receiverSymRef->getTypeSignature(receiverLen);
4469
if (comp()->getOption(TR_TraceILGen))
4470
traceMsg(comp(), "handling callNode %p, receiver class name %s\n", callNode, receiverSig);
4471
if (receiverSig != NULL && (receiverLen == JAVA_SERIAL_CLASS_NAME_LEN) &&
4472
!strncmp(receiverSig, JAVA_SERIAL_CLASS_NAME, receiverLen))
4473
{
4474
if (comp()->getOption(TR_TraceILGen))
4475
traceMsg(comp(), "handling callNode %p, current method %s\n", callNode, _methodSymbol->getResolvedMethod()->signature(trMemory()));
4476
4477
if ((calledMethod->nameLength() == JAVA_SERIAL_CALLEE_METHOD_NAME_LEN) &&
4478
!strncmp(calledMethod->nameChars(), JAVA_SERIAL_CALLEE_METHOD_NAME, JAVA_SERIAL_CALLEE_METHOD_NAME_LEN) &&
4479
(calledMethod->signatureLength() == JAVA_SERIAL_CALLEE_METHOD_SIG_LEN) &&
4480
!strncmp(calledMethod->signatureChars(), JAVA_SERIAL_CALLEE_METHOD_SIG, JAVA_SERIAL_CALLEE_METHOD_SIG_LEN))
4481
{
4482
TR_OpaqueClassBlock *cl = _methodSymbol->getResolvedMethod()->containingClass();
4483
4484
if (comp()->getOption(TR_TraceILGen))
4485
traceMsg(comp(), "called method %s, containing class %p\n", calledMethod->signature(trMemory()), cl);
4486
bool isClassInitialized = false;
4487
TR_PersistentClassInfo * classInfo = comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(cl, comp());
4488
if (classInfo && classInfo->isInitialized())
4489
isClassInitialized = true;
4490
if (comp()->getOption(TR_TraceILGen))
4491
traceMsg(comp(), "isClassInitialized = %d\n", isClassInitialized);
4492
if (isClassInitialized)
4493
{
4494
TR_OpaqueClassBlock *serialClass = fej9()->getClassFromSignature(JAVA_SERIAL_REPLACE_CLASS_NAME, JAVA_SERIAL_REPLACE_CLASS_LEN, callNode->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod());
4495
if (comp()->getOption(TR_TraceILGen))
4496
traceMsg(comp(), "serialClass = %p, serialClassLoader %s systemClassLoader\n", serialClass, (!fej9()->isClassLoadedBySystemClassLoader(cl)) ? "!=" : "==");
4497
if (serialClass && !fej9()->isClassLoadedBySystemClassLoader(cl))
4498
{
4499
TR_ScratchList<TR_ResolvedMethod> methods(trMemory());
4500
fej9()->getResolvedMethods(trMemory(), serialClass, &methods);
4501
ListIterator<TR_ResolvedMethod> it(&methods);
4502
TR_ResolvedMethod *replacementMethod;
4503
for (replacementMethod = it.getCurrent(); replacementMethod; replacementMethod = it.getNext())
4504
{
4505
if (replacementMethod->nameLength() == JAVA_SERIAL_REPLACE_METHOD_NAME_LEN && !strncmp(replacementMethod->nameChars(), JAVA_SERIAL_REPLACE_METHOD_NAME, JAVA_SERIAL_REPLACE_METHOD_NAME_LEN))
4506
{
4507
if ((replacementMethod->signatureLength() == JAVA_SERIAL_REPLACE_METHOD_SIG_LEN) &&
4508
!strncmp(replacementMethod->signatureChars(), JAVA_SERIAL_REPLACE_METHOD_SIG, JAVA_SERIAL_REPLACE_METHOD_SIG_LEN))
4509
break; // found it
4510
}
4511
}
4512
if (replacementMethod)
4513
{
4514
if (performTransformation(comp(), "O^O JAVA SERIALIZATION OPTIMIZATION : changing ObjectInputStream.readObject call to ObjectInputStream redirectedReadObject\n"))
4515
{
4516
TR::Node *clazzLoad = TR::Node::createWithSymRef(TR::loadaddr, 0, symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, cl));
4517
TR::Node *jlClazzLoad = TR::Node::createWithSymRef(TR::aloadi, 1, clazzLoad, 0, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());
4518
push(receiver);
4519
push(jlClazzLoad);
4520
TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodSymbol(_methodSymbol->getResolvedMethodIndex(), -1, replacementMethod, TR::MethodSymbol::Static);
4521
callNode = genNodeAndPopChildren(replacementMethod->directCallOpCode(), 2, symRef);
4522
isStatic = true;
4523
callNode->getChild(0)->recursivelyDecReferenceCount();
4524
}
4525
}
4526
}
4527
}
4528
}
4529
}
4530
}
4531
}
4532
4533
TR::Node *treeTopNode;
4534
if (isStatic || callNode->getChild(callNode->getFirstArgumentIndex())->isNonNull())
4535
{
4536
if (symRef->isUnresolved())
4537
treeTopNode = genResolveCheck(callNode);
4538
else
4539
treeTopNode = callNode;
4540
}
4541
else
4542
{
4543
if (symRef->isUnresolved())
4544
treeTopNode = genResolveAndNullCheck(callNode);
4545
else
4546
treeTopNode = genNullCheck(callNode);
4547
}
4548
4549
handleSideEffect(treeTopNode);
4550
4551
TR::TreeTop *callNodeTreeTop = NULL;
4552
if (symbol->getMandatoryRecognizedMethod() == TR::java_lang_invoke_ILGenMacros_placeholder)
4553
{
4554
// This call is not a real Java call. We can't put down a treetop for
4555
// it, or else that treetop will linger after the placeholder has been
4556
// expanded, at which point the placeholder call's children will all have
4557
// the wrong refcounts.
4558
}
4559
else
4560
{
4561
if (!_intrinsicErrorHandling)
4562
{
4563
callNodeTreeTop = genTreeTop(treeTopNode);
4564
}
4565
else
4566
{
4567
callNodeTreeTop = TR::TreeTop::create(comp(), treeTopNode);
4568
}
4569
_intrinsicErrorHandling = false;
4570
}
4571
4572
// The call may be transformed into a non-OSR point. Check if bookkeeping is needed
4573
// before the transformation.
4574
bool needOSRBookkeeping = false;
4575
int32_t osrInductionOffset;
4576
4577
// callNodeTreeTop may be null if this call should not be placed in the trees
4578
if (callNodeTreeTop
4579
&& comp()->getOption(TR_EnableOSR)
4580
&& !comp()->isPeekingMethod()
4581
&& comp()->isOSRTransitionTarget(TR::postExecutionOSR)
4582
&& comp()->isPotentialOSRPoint(callNodeTreeTop->getNode())
4583
&& !_methodSymbol->cannotAttemptOSRAt(callNode->getByteCodeInfo(), NULL, comp())
4584
&& !_cannotAttemptOSR)
4585
{
4586
needOSRBookkeeping = true;
4587
// callNode may become a non-OSR point after the transformation, calling getOSRInductionOffset
4588
// on a non-OSR point will trigger the assertion, thus get the induction offset here.
4589
osrInductionOffset = comp()->getOSRInductionOffset(callNode);
4590
}
4591
4592
TR::Node * resultNode = 0;
4593
4594
TR::ResolvedMethodSymbol * resolvedMethodSymbol = symbol->getResolvedMethodSymbol();
4595
4596
4597
// fast pathing for JITHelpers methods
4598
//
4599
if (!strncmp(comp()->getCurrentMethod()->classNameChars(), "com/ibm/jit/JITHelpers", 22))
4600
{
4601
bool isCallGetLength = false;
4602
bool isCallAddressAsPrimitive32 = false;
4603
bool isCallAddressAsPrimitive64 = false;
4604
if (strstr(s, "java/lang/reflect/Array") &&
4605
!strncmp(calledMethod->nameChars(), "getLength", calledMethod->nameLength()))
4606
isCallGetLength = true;
4607
///else if (strstr(s, "com/ibm/jit/JITHelpers") && resolvedMethodSymbol)
4608
else if (resolvedMethodSymbol)
4609
{
4610
/// (!strncmp(calledMethod->nameChars(), "getAddressAsPrimitive32", calledMethod->nameLength()) ||
4611
/// !strncmp(calledMethod->nameChars(), "getAddressAsPrimitive64", calledMethod->nameLength())))
4612
if (resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getAddressAsPrimitive32)
4613
isCallAddressAsPrimitive32 = true;
4614
else if (resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getAddressAsPrimitive64)
4615
isCallAddressAsPrimitive64 = true;
4616
}
4617
}
4618
4619
if (resolvedMethodSymbol &&
4620
!isPeekingMethod() &&
4621
(resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getJ9ClassFromObject32 ||
4622
resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getJ9ClassFromObject64))
4623
{
4624
TR::Node* obj = callNode->getChild(1);
4625
TR::Node* vftLoad = TR::Node::createWithSymRef(callNode, TR::aloadi, 1, obj, symRefTab()->findOrCreateVftSymbolRef());
4626
if (resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getJ9ClassFromObject32)
4627
{
4628
resultNode = TR::Node::create(callNode, TR::a2i, 1, vftLoad);
4629
}
4630
else
4631
{
4632
resultNode = TR::Node::create(callNode, TR::a2l, 1, vftLoad);
4633
}
4634
// Handle NullCHK
4635
if (callNodeTreeTop->getNode()->getOpCode().isNullCheck())
4636
TR::Node::recreate(callNodeTreeTop->getNode(), TR::treetop);
4637
callNodeTreeTop->getNode()->setAndIncChild(0, resultNode);
4638
// Decrement ref count for the call
4639
callNode->recursivelyDecReferenceCount();
4640
callNode = resultNode;
4641
}
4642
else if (resolvedMethodSymbol &&
4643
!isPeekingMethod() &&
4644
resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_isArray)
4645
{
4646
TR::Node* obj = callNode->getChild(1);
4647
TR::Node* vftLoad = TR::Node::createWithSymRef(callNode, TR::aloadi, 1, obj, symRefTab()->findOrCreateVftSymbolRef());
4648
4649
if (comp()->target().is32Bit())
4650
{
4651
resultNode = TR::Node::createWithSymRef(callNode, TR::iloadi, 1, vftLoad, symRefTab()->findOrCreateClassAndDepthFlagsSymbolRef());
4652
}
4653
else
4654
{
4655
resultNode = TR::Node::createWithSymRef(callNode, TR::lloadi, 1, vftLoad, symRefTab()->findOrCreateClassAndDepthFlagsSymbolRef());
4656
resultNode = TR::Node::create(callNode, TR::l2i, 1, resultNode);
4657
}
4658
4659
int32_t andMask = comp()->fej9()->getFlagValueForArrayCheck();
4660
int32_t shiftAmount = trailingZeroes(andMask);
4661
resultNode = TR::Node::create(callNode, TR::iand, 2, resultNode, TR::Node::iconst(callNode, andMask));
4662
resultNode = TR::Node::create(callNode, TR::iushr, 2, resultNode, TR::Node::iconst(callNode, shiftAmount));
4663
// Handle NullCHK
4664
if (callNodeTreeTop->getNode()->getOpCode().isNullCheck())
4665
TR::Node::recreate(callNodeTreeTop->getNode(), TR::treetop);
4666
callNodeTreeTop->getNode()->setAndIncChild(0, resultNode);
4667
// Decrement ref count for the call
4668
callNode->recursivelyDecReferenceCount();
4669
callNode = resultNode;
4670
}
4671
else if (resolvedMethodSymbol &&
4672
resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getClassInitializeStatus &&
4673
!isPeekingMethod())
4674
{
4675
TR::Node* jlClass = callNode->getChild(1);
4676
TR::Node* j9Class = TR::Node::createWithSymRef(callNode, TR::aloadi, 1, jlClass, symRefTab()->findOrCreateClassFromJavaLangClassSymbolRef());
4677
4678
if (comp()->target().is32Bit())
4679
{
4680
resultNode = TR::Node::createWithSymRef(callNode, TR::iloadi, 1, j9Class, symRefTab()->findOrCreateInitializeStatusFromClassSymbolRef());
4681
}
4682
else
4683
{
4684
resultNode = TR::Node::createWithSymRef(callNode, TR::lloadi, 1, j9Class, symRefTab()->findOrCreateInitializeStatusFromClassSymbolRef());
4685
resultNode = TR::Node::create(callNode, TR::l2i, 1, resultNode);
4686
}
4687
4688
// Properly handle the checks
4689
if (callNodeTreeTop->getNode()->getOpCode().isNullCheck())
4690
TR::Node::recreate(callNodeTreeTop->getNode(), TR::treetop);
4691
callNodeTreeTop->getNode()->setAndIncChild(0, resultNode);
4692
// Decrement ref count for the call
4693
callNode->recursivelyDecReferenceCount();
4694
callNode = resultNode;
4695
}
4696
else if (symbol->isNative() && isDirectCall)
4697
{
4698
if (!comp()->getOption(TR_DisableInliningOfNatives) &&
4699
symbol->castToResolvedMethodSymbol()->getRecognizedMethod() != TR::unknownMethod)
4700
{
4701
if (!resultNode)
4702
{
4703
resultNode = fej9()->inlineNativeCall(comp(), callNodeTreeTop, callNode);
4704
}
4705
}
4706
4707
if (!resultNode)
4708
{
4709
if (symbol->isJNI())
4710
resultNode = callNode->processJNICall(callNodeTreeTop, _methodSymbol);
4711
else
4712
resultNode = callNode;
4713
}
4714
}
4715
else
4716
resultNode = callNode;
4717
4718
TR::DataType returnType = calledMethod->returnType();
4719
if (returnType != TR::NoType)
4720
{
4721
push(resultNode);
4722
}
4723
4724
if (needOSRBookkeeping)
4725
{
4726
saveStack(-1, !comp()->pendingPushLivenessDuringIlgen());
4727
stashPendingPushLivenessForOSR(osrInductionOffset);
4728
if (comp()->supportsInduceOSR() && comp()->getOSRMode() == TR::voluntaryOSR)
4729
{
4730
TR::Node* callToPotentialOSRPoint = TR::Node::createPotentialOSRPointHelperCallInILGen(callNodeTreeTop->getNode(), osrInductionOffset);
4731
_block->append(TR::TreeTop::create(comp(), TR::Node::create(TR::treetop, 1, callToPotentialOSRPoint)));
4732
}
4733
}
4734
4735
// We disable this optimization for JITServer because TR_VMField is not supported on JITServer yet. Once we have decided how to build the data structures
4736
// required by this optimization efficiently, we can re-enable this optimization.
4737
if (cg()->getEnforceStoreOrder() && calledMethod->isConstructor())
4738
{
4739
if (resolvedMethodSymbol
4740
#ifdef J9VM_OPT_JITSERVER
4741
&& !cg()->comp()->isOutOfProcessCompilation()
4742
#endif /* defined(J9VM_OPT_JITSERVER) */
4743
)
4744
{
4745
J9Class *methodClass = (J9Class *) resolvedMethodSymbol->getResolvedMethod()->containingClass();
4746
TR_VMFieldsInfo *fieldsInfoByIndex = new (comp()->trStackMemory()) TR_VMFieldsInfo(comp(), methodClass, 1, stackAlloc);
4747
ListIterator<TR_VMField> fieldIter(fieldsInfoByIndex->getFields());
4748
for (TR_VMField *field = fieldIter.getFirst(); field; field = fieldIter.getNext())
4749
{
4750
if ((field->modifiers & J9AccFinal) && methodClass == jitGetDeclaringClassOfROMField(comp()->j9VMThread(), methodClass, field->shape))
4751
{
4752
if (comp()->getOption(TR_TraceILGen))
4753
traceMsg(comp(), "added fence due to field %s \n", field->name);
4754
push(callNode->getFirstChild());
4755
genFlush(0);
4756
pop();
4757
break;
4758
}
4759
}
4760
}
4761
else
4762
{
4763
push(callNode->getFirstChild());
4764
genFlush(0);
4765
pop();
4766
}
4767
}
4768
4769
if (isDirectCall && indirectCallFirstChild)
4770
{
4771
// Not using the supplied node; must clean up its ref counts
4772
indirectCallFirstChild->incReferenceCount();
4773
indirectCallFirstChild->recursivelyDecReferenceCount();
4774
}
4775
4776
_intrinsicErrorHandling = false;
4777
return callNode;
4778
}
4779
4780
void
4781
TR_J9ByteCodeIlGenerator::chopPlaceholder(TR::Node *placeholder, int32_t firstChild, int32_t numChildren)
4782
{
4783
// Dec refcounts on the children we're going to drop. Also, find
4784
// start and end of the portion of the placeholder signature
4785
// describing the arguments we're going to keep.
4786
//
4787
int32_t i;
4788
for (i = 0; i < firstChild; i++)
4789
placeholder->getAndDecChild(i);
4790
for (i = placeholder->getNumChildren()-1; i >= firstChild + numChildren; i--)
4791
placeholder->getAndDecChild(i);
4792
4793
// Move the remaining children to the front.
4794
//
4795
for (i = 0; i < numChildren; i++)
4796
placeholder->setChild(i, placeholder->getChild(i + firstChild));
4797
placeholder->setNumChildren(numChildren);
4798
4799
// Edit signature
4800
//
4801
char *callSignature = placeholder->getSymbol()->castToMethodSymbol()->getMethod()->signatureChars();
4802
placeholder->setSymbolReference(symRefWithArtificialSignature(placeholder->getSymbolReference(),
4803
"(.-).$",
4804
callSignature, firstChild, firstChild + numChildren - 1,
4805
callSignature
4806
));
4807
}
4808
4809
bool
4810
TR_J9ByteCodeIlGenerator::runMacro(TR::SymbolReference * symRef)
4811
{
4812
// Give FE first kick at the can
4813
//
4814
if (runFEMacro(symRef))
4815
return true;
4816
4817
TR::MethodSymbol * symbol = symRef->getSymbol()->castToMethodSymbol();
4818
int32_t archetypeParmCount = symbol->getMethod()->numberOfExplicitParameters() + (symbol->isStatic() ? 0 : 1);
4819
4820
TR_ASSERT(symbol->isStatic(), "Macro methods must be static or else signature processing gets complicated by the implicit receiver");
4821
4822
switch (symRef->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod())
4823
{
4824
case TR::java_lang_invoke_ILGenMacros_numArguments:
4825
{
4826
if (!comp()->compileRelocatableCode())
4827
{
4828
TR::Node *argShepherd = genNodeAndPopChildren(TR::icall, 1, symRef);
4829
loadConstant(TR::iconst, argShepherd->getNumChildren());
4830
argShepherd->removeAllChildren();
4831
}
4832
return true;
4833
}
4834
case TR::java_lang_invoke_ILGenMacros_populateArray:
4835
{
4836
if (!comp()->compileRelocatableCode())
4837
{
4838
TR::Node *argShepherd = genNodeAndPopChildren(TR::icall, 1, symRef);
4839
TR::Node *array = pop();
4840
for (int32_t i = 0; i < argShepherd->getNumChildren(); i++)
4841
{
4842
TR::Node *arg = argShepherd->getChild(i);
4843
push(array);
4844
loadConstant(TR::iconst, i);
4845
push(arg);
4846
storeArrayElement(arg->getDataType()); // TODO:JSR292: use isstore for char arguments
4847
}
4848
argShepherd->removeAllChildren();
4849
push(array);
4850
}
4851
return true;
4852
}
4853
case TR::java_lang_invoke_ILGenMacros_first:
4854
{
4855
if (!comp()->compileRelocatableCode())
4856
{
4857
TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());
4858
chopPlaceholder(placeholder, 0, 1);
4859
push(placeholder);
4860
}
4861
return true;
4862
}
4863
case TR::java_lang_invoke_ILGenMacros_last:
4864
{
4865
if (!comp()->compileRelocatableCode())
4866
{
4867
TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());
4868
chopPlaceholder(placeholder, placeholder->getNumChildren()-1, 1);
4869
push(placeholder);
4870
}
4871
return true;
4872
}
4873
case TR::java_lang_invoke_ILGenMacros_firstN:
4874
{
4875
if (!comp()->compileRelocatableCode())
4876
{
4877
TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());
4878
int32_t n = pop()->getInt();
4879
chopPlaceholder(placeholder, 0, n);
4880
push(placeholder);
4881
}
4882
return true;
4883
}
4884
case TR::java_lang_invoke_ILGenMacros_dropFirstN:
4885
{
4886
if (!comp()->compileRelocatableCode())
4887
{
4888
TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());
4889
int32_t n = pop()->getInt();
4890
chopPlaceholder(placeholder, n, placeholder->getNumChildren()-n);
4891
push(placeholder);
4892
}
4893
return true;
4894
}
4895
case TR::java_lang_invoke_ILGenMacros_lastN:
4896
{
4897
if (!comp()->compileRelocatableCode())
4898
{
4899
TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());
4900
int32_t n = pop()->getInt();
4901
chopPlaceholder(placeholder, placeholder->getNumChildren()-n, n);
4902
push(placeholder);
4903
}
4904
return true;
4905
}
4906
case TR::java_lang_invoke_ILGenMacros_middleN:
4907
{
4908
if (!comp()->compileRelocatableCode())
4909
{
4910
TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());
4911
int32_t n = pop()->getInt();
4912
int32_t startIndex = pop()->getInt();
4913
chopPlaceholder(placeholder, startIndex, n);
4914
push(placeholder);
4915
}
4916
return true;
4917
}
4918
case TR::java_lang_invoke_ILGenMacros_rawNew:
4919
{
4920
if (!comp()->compileRelocatableCode())
4921
{
4922
push(TR::Node::createWithSymRef(TR::aloadi, 1, 1, pop(), symRefTab()->findOrCreateClassFromJavaLangClassSymbolRef()));
4923
genNew(TR::variableNew);
4924
}
4925
return true;
4926
}
4927
case TR::java_lang_invoke_ILGenMacros_push:
4928
{
4929
if (!comp()->compileRelocatableCode())
4930
shiftAndCopy(_stack->size(), 1);
4931
return true;
4932
}
4933
case TR::java_lang_invoke_ILGenMacros_pop:
4934
{
4935
if (!comp()->compileRelocatableCode())
4936
rotate(-1);
4937
return true;
4938
}
4939
case TR::java_lang_invoke_ILGenMacros_invokeExact:
4940
{
4941
if (!comp()->compileRelocatableCode())
4942
{
4943
TR_ResolvedMethod *invokeExactMacro = symRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod();
4944
TR::SymbolReference *invokeExact = comp()->getSymRefTab()->methodSymRefFromName(_methodSymbol, JSR292_MethodHandle, JSR292_invokeExact, JSR292_invokeExactSig, TR::MethodSymbol::ComputedVirtual);
4945
TR::SymbolReference *invokeExactWithSig = symRefWithArtificialSignature(invokeExact,
4946
"(.*).$",
4947
invokeExactMacro->signatureChars(), 1, // skip explicit MethodHandle argument -- invokeExact has it as a receiver
4948
invokeExactMacro->signatureChars());
4949
genILGenMacroInvokeExact(invokeExactWithSig);
4950
}
4951
return true;
4952
}
4953
case TR::java_lang_invoke_ILGenMacros_typeCheck:
4954
{
4955
if (!comp()->compileRelocatableCode())
4956
{
4957
TR::Node* expectedType = pop();
4958
TR::Node* handle = pop();
4959
genTreeTop(genHandleTypeCheck(handle, expectedType));
4960
}
4961
return true;
4962
}
4963
case TR::java_lang_invoke_ILGenMacros_arrayElements:
4964
{
4965
if (!comp()->compileRelocatableCode())
4966
{
4967
TR::Node *argPlaceholder = genNodeAndPopChildren(TR::icall, 3, symRef);
4968
TR::Node *array = argPlaceholder->getAndDecChild(0);
4969
int firstIndex = argPlaceholder->getAndDecChild(1)->getInt();
4970
int numElements = argPlaceholder->getAndDecChild(2)->getInt();
4971
4972
// The hard part here is computing the signature for the resulting placeholder!
4973
char *macroSignature = argPlaceholder->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->signatureChars();
4974
char *arrayElementType = macroSignature+2; // Skip parenthesis and bracket
4975
char *secondArgType = nextSignatureArgument(arrayElementType);
4976
int arrayElementTypeLength = secondArgType - arrayElementType;
4977
4978
char *expandedArgsSignature = (char*)comp()->trMemory()->allocateStackMemory(numElements * arrayElementTypeLength + 1);
4979
4980
TR::DataType arrayElementDataType = TR::NoType;
4981
TR::ILOpCodes convertOp = TR::BadILOp;
4982
switch (arrayElementType[0])
4983
{
4984
case 'Z':
4985
case 'B':
4986
arrayElementDataType = TR::Int8;
4987
convertOp = TR::b2i;
4988
break;
4989
case 'S':
4990
arrayElementDataType = TR::Int16;
4991
convertOp = TR::s2i;
4992
break;
4993
case 'C':
4994
arrayElementDataType = TR::Int16;
4995
convertOp = TR::su2i;
4996
break;
4997
case 'I':
4998
arrayElementDataType = TR::Int32;
4999
break;
5000
case 'J':
5001
arrayElementDataType = TR::Int64;
5002
break;
5003
case 'F':
5004
arrayElementDataType = TR::Float;
5005
break;
5006
case 'D':
5007
arrayElementDataType = TR::Double;
5008
break;
5009
case 'L':
5010
case '[':
5011
case 'Q':
5012
arrayElementDataType = TR::Address;
5013
break;
5014
default:
5015
TR_ASSERT(0, "Unknown array element type '%s'", arrayElementType);
5016
arrayElementDataType = TR::Address;
5017
break;
5018
}
5019
5020
char *cursor = expandedArgsSignature;
5021
cursor[0] = 0; // in case numElements==0
5022
for (int32_t i = firstIndex; i < firstIndex+numElements; i++)
5023
{
5024
push(array);
5025
loadConstant(TR::iconst, i);
5026
loadArrayElement(arrayElementDataType);
5027
if (convertOp != TR::BadILOp)
5028
genUnary(convertOp);
5029
cursor += sprintf(cursor, "%.*s", arrayElementTypeLength, arrayElementType);
5030
}
5031
5032
// Create placeholder with signature that reflects the expansion of arguments.
5033
// Being a placeholder, its return type is still int.
5034
//
5035
TR::Node *placeholder = genNodeAndPopChildren(TR::icall, numElements, symRefWithArtificialSignature(placeholderWithDummySignature(),
5036
"(.?)I", expandedArgsSignature));
5037
5038
push(placeholder);
5039
}
5040
return true;
5041
}
5042
default:
5043
return false;
5044
}
5045
}
5046
5047
//----------------------------------------------
5048
// gen load
5049
//----------------------------------------------
5050
5051
void
5052
TR_J9ByteCodeIlGenerator::loadAuto(TR::DataType type, int32_t slot, bool isAdjunct)
5053
{
5054
if (_argPlaceholderSlot != -1 && _argPlaceholderSlot == slot)
5055
{
5056
genArgPlaceholderCall();
5057
return;
5058
}
5059
5060
TR::Node * load = TR::Node::createLoad(symRefTab()->findOrCreateAutoSymbol(_methodSymbol, slot, type, true, false, true, isAdjunct));
5061
// type may have been coerced
5062
type = load->getDataType();
5063
5064
bool isStatic = _methodSymbol->isStatic();
5065
if (slot == 0 && !isStatic && !_thisChanged)
5066
load->setIsNonNull(true);
5067
5068
push(load);
5069
}
5070
5071
/**
5072
* @brief Returns whether a field ref in the constant pool resolved
5073
*
5074
* Importantly, when this function returns false, a ResolveCHK is guarenteed to be needed.
5075
*
5076
* @param comp is a pointer the current compilation object
5077
* @param owningMethod is the method that owns the constant pool
5078
* @param cpIndex is the index into the constant pool of the field
5079
* @param isStore specifies whether the check is done for a store of the field
5080
* @return true when the constant pool entry for the field is resolved, false otherwise
5081
*/
5082
static bool
5083
isFieldResolved(TR::Compilation *comp, TR_ResolvedJ9Method * owningMethod, int32_t cpIndex, bool isStore)
5084
{
5085
uint32_t offset = 0;
5086
TR::DataType type = TR::NoType;
5087
bool isVolatile = true, isFinal = false, isPrivate = false, isUnresolvedInCP;
5088
return owningMethod->fieldAttributes(comp, cpIndex, &offset, &type, &isVolatile, &isFinal,
5089
&isPrivate, isStore, &isUnresolvedInCP, true /* needsAOTValidation */);
5090
}
5091
5092
void
5093
TR_J9ByteCodeIlGenerator::loadInstance(int32_t cpIndex)
5094
{
5095
if (_generateReadBarriersForFieldWatch && comp()->compileRelocatableCode())
5096
comp()->failCompilation<J9::AOTNoSupportForAOTFailure>("NO support for AOT in field watch");
5097
5098
TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());
5099
if (TR::Compiler->om.areValueTypesEnabled() && owningMethod->isFieldQType(cpIndex))
5100
{
5101
if (!isFieldResolved(comp(), owningMethod, cpIndex, false))
5102
{
5103
abortForUnresolvedValueTypeOp("getfield", "field");
5104
}
5105
else if (owningMethod->isFieldFlattened(comp(), cpIndex, _methodSymbol->isStatic()))
5106
{
5107
return comp()->getOption(TR_UseFlattenedFieldRuntimeHelpers) ?
5108
loadFlattenableInstanceWithHelper(cpIndex) :
5109
loadFlattenableInstance(cpIndex);
5110
}
5111
}
5112
5113
TR::SymbolReference * symRef = symRefTab()->findOrCreateShadowSymbol(_methodSymbol, cpIndex, false);
5114
loadInstance(symRef);
5115
}
5116
5117
void
5118
TR_J9ByteCodeIlGenerator::loadInstance(TR::SymbolReference * symRef)
5119
{
5120
TR::Symbol * symbol = symRef->getSymbol();
5121
TR::DataType type = symbol->getDataType();
5122
5123
TR::Node * address = pop();
5124
5125
if (!symRef->isUnresolved() &&
5126
symRef->getSymbol()->isFinal())
5127
{
5128
TR::Node *constValue = loadConstantValueIfPossible(address, symRef->getOffset(), type, false);
5129
if (constValue)
5130
{
5131
return;
5132
}
5133
}
5134
5135
TR::Node * load, *dummyLoad;
5136
5137
TR::ILOpCodes op = _generateReadBarriersForFieldWatch ? comp()->il.opCodeForIndirectReadBarrier(type): comp()->il.opCodeForIndirectLoad(type);
5138
dummyLoad = load = TR::Node::createWithSymRef(op, 1, 1, address, symRef);
5139
5140
TR::Node * treeTopNode = 0;
5141
5142
if (symRef->isUnresolved())
5143
{
5144
if (!address->isNonNull())
5145
treeTopNode = genResolveAndNullCheck(load);
5146
else
5147
treeTopNode = genResolveCheck(load);
5148
}
5149
else if (!address->isNonNull())
5150
treeTopNode = genNullCheck(load);
5151
else if (symbol->isVolatile() || _generateReadBarriersForFieldWatch)
5152
treeTopNode = load;
5153
5154
if (treeTopNode)
5155
{
5156
handleSideEffect(treeTopNode);
5157
genTreeTop(treeTopNode);
5158
}
5159
5160
if (type == TR::Address)
5161
{
5162
5163
if (comp()->useCompressedPointers())
5164
{
5165
if (!symRefTab()->isFieldClassObject(symRef))
5166
{
5167
TR::Node *loadValue = load;
5168
if (loadValue->getOpCode().isCheck())
5169
loadValue = loadValue->getFirstChild();
5170
// returns non-null if the compressedRefs anchor is going to
5171
// be part of the subtrees (for now, it is a treetop)
5172
//
5173
TR::Node *newLoad = genCompressedRefs(loadValue);
5174
if (newLoad)
5175
load = newLoad;
5176
}
5177
}
5178
}
5179
5180
static char *disableFinalFieldFoldingInILGen = feGetEnv("TR_DisableFinalFieldFoldingInILGen");
5181
static char *disableInstanceFinalFieldFoldingInILGen = feGetEnv("TR_DisableInstanceFinalFieldFoldingInILGen");
5182
if (!disableFinalFieldFoldingInILGen &&
5183
!disableInstanceFinalFieldFoldingInILGen &&
5184
address->getOpCode().hasSymbolReference() &&
5185
address->getSymbolReference()->hasKnownObjectIndex() &&
5186
address->isNonNull())
5187
{
5188
TR::Node* nodeToRemove = NULL;
5189
if (TR::TransformUtil::transformIndirectLoadChain(comp(), dummyLoad, address, address->getSymbolReference()->getKnownObjectIndex(), &nodeToRemove) && nodeToRemove)
5190
{
5191
nodeToRemove->recursivelyDecReferenceCount();
5192
}
5193
}
5194
5195
push(dummyLoad);
5196
}
5197
5198
void
5199
TR_J9ByteCodeIlGenerator::loadFlattenableInstanceWithHelper(int32_t cpIndex)
5200
{
5201
TR::Node * address = pop();
5202
if (!address->isNonNull())
5203
{
5204
auto* nullchk = TR::Node::create(TR::PassThrough, 1, address);
5205
nullchk = genNullCheck(nullchk);
5206
genTreeTop(nullchk);
5207
}
5208
auto* j9ResolvedMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());
5209
auto* ramFieldRef = reinterpret_cast<J9RAMFieldRef*>(j9ResolvedMethod->cp()) + cpIndex;
5210
auto* ramFieldRefNode = TR::Node::aconst(reinterpret_cast<uintptr_t>(ramFieldRef));
5211
auto* receiverNode = address;
5212
auto* helperCallNode = TR::Node::createWithSymRef(TR::acall, 2, 2, receiverNode, ramFieldRefNode, comp()->getSymRefTab()->findOrCreateGetFlattenableFieldSymbolRef());
5213
handleSideEffect(helperCallNode);
5214
genTreeTop(helperCallNode);
5215
push(helperCallNode);
5216
}
5217
5218
static char * getTopLevelPrefixForFlattenedFields(TR_ResolvedJ9Method *owningMethod, int32_t cpIndex, int32_t &prefixLen, TR::Region &region)
5219
{
5220
int32_t len;
5221
const char * fieldNameChars = owningMethod->fieldNameChars(cpIndex, len);
5222
prefixLen = len + 1; // for '.'
5223
5224
char * newName = new (region) char[len+2];
5225
strncpy(newName, fieldNameChars, len);
5226
5227
newName[len] = '.';
5228
newName[len+1] = '\0';
5229
return newName;
5230
}
5231
5232
void
5233
TR_J9ByteCodeIlGenerator::loadFlattenableInstance(int32_t cpIndex)
5234
{
5235
/* An example on what the tree with flattened fields looks like
5236
*
5237
* value NestedA {
5238
* int x;
5239
* int y;
5240
* }
5241
* value NestedB {
5242
* NestedA a;
5243
* NestedA b;
5244
* }
5245
* value ContainerC {
5246
* NestedB c;
5247
* NestedB d;
5248
* }
5249
*
5250
* method="ContainerC.getc()QNestedB;"
5251
*
5252
* /--- trees inserted ------------------------
5253
* n10n ( 0) treetop
5254
* n9n ( 1) newvalue jitNewValue[#100 helper Method] [flags 0x400 0x0 ] (Identityless sharedMemory )
5255
* n4n ( 1) loadaddr NestedB[#367 Static] [flags 0x18307 0x0 ]
5256
* n5n ( 1) iloadi ContainerC.c.a.x I[#368 final ContainerC.c.a.x I +4] [flags 0x20603 0x200 ]
5257
* n3n ( 4) aload <'this' parm LContainerC;>[#366 Parm] [flags 0x40000107 0x0 ] (X!=0 sharedMemory )
5258
* n6n ( 1) iloadi ContainerC.c.a.y I[#369 final ContainerC.c.a.y I +8] [flags 0x20603 0x200 ]
5259
* n3n ( 4) ==>aload (X!=0 sharedMemory )
5260
* n7n ( 1) iloadi ContainerC.c.b.x I[#370 final ContainerC.c.b.x I +12] [flags 0x20603 0x200 ]
5261
* n3n ( 4) ==>aload (X!=0 sharedMemory )
5262
* n8n ( 1) iloadi ContainerC.c.b.y I[#371 final ContainerC.c.b.y I +16] [flags 0x20603 0x200 ]
5263
* n3n ( 4) ==>aload (X!=0 sharedMemory )
5264
* /--- stack after ------------------------
5265
* @0 n9n ( 1) ==>newvalue (Identityless sharedMemory )
5266
* ============================================================
5267
*/
5268
TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());
5269
5270
int len;
5271
const char * fieldClassChars = owningMethod->fieldSignatureChars(cpIndex, len);
5272
TR_OpaqueClassBlock * fieldClass = fej9()->getClassFromSignature(fieldClassChars, len, owningMethod);
5273
5274
int32_t prefixLen = 0;
5275
char * fieldNamePrefix = getTopLevelPrefixForFlattenedFields(owningMethod, cpIndex, prefixLen, comp()->trMemory()->currentStackRegion());
5276
5277
TR_OpaqueClassBlock * containingClass = owningMethod->definingClassFromCPFieldRef(comp(), cpIndex, _methodSymbol->isStatic());
5278
const TR::TypeLayout * containingClassLayout = comp()->typeLayout(containingClass);
5279
size_t fieldCount = containingClassLayout->count();
5280
int flattenedFieldCount = 0;
5281
5282
TR::Node * address = pop();
5283
5284
if (!address->isNonNull())
5285
{
5286
TR::Node * passThruNode = TR::Node::create(TR::PassThrough, 1, address);
5287
genTreeTop(genNullCheck(passThruNode));
5288
}
5289
5290
loadClassObject(fieldClass);
5291
5292
for (size_t idx = 0; idx < fieldCount; idx++)
5293
{
5294
const TR::TypeLayoutEntry &fieldEntry = containingClassLayout->entry(idx);
5295
5296
if (!strncmp(fieldNamePrefix, fieldEntry._fieldname, prefixLen))
5297
{
5298
auto * fieldSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(containingClass,
5299
fieldEntry._datatype,
5300
fieldEntry._offset,
5301
fieldEntry._isVolatile,
5302
fieldEntry._isPrivate,
5303
fieldEntry._isFinal,
5304
fieldEntry._fieldname,
5305
fieldEntry._typeSignature);
5306
5307
if (comp()->getOption(TR_TraceILGen))
5308
{
5309
traceMsg(comp(), "Load flattened field %s\n - field[%d] name %s type %d offset %d\n",
5310
comp()->getDebug()->getName(fieldSymRef), idx, fieldEntry._fieldname,
5311
fieldEntry._datatype.getDataType(), fieldEntry._offset);
5312
}
5313
5314
push(address);
5315
loadInstance(fieldSymRef);
5316
5317
flattenedFieldCount++;
5318
}
5319
}
5320
5321
TR::Node * newValueNode = genNodeAndPopChildren(TR::newvalue, flattenedFieldCount + 1, symRefTab()->findOrCreateNewValueSymbolRef(_methodSymbol));
5322
newValueNode->setIdentityless(true);
5323
genTreeTop(newValueNode);
5324
push(newValueNode);
5325
genFlush(0);
5326
return;
5327
}
5328
5329
void
5330
TR_J9ByteCodeIlGenerator::loadStatic(int32_t cpIndex)
5331
{
5332
if (_generateReadBarriersForFieldWatch && comp()->compileRelocatableCode())
5333
comp()->failCompilation<J9::AOTNoSupportForAOTFailure>("NO support for AOT in field watch");
5334
5335
_staticFieldReferenceEncountered = true;
5336
TR::SymbolReference * symRef = symRefTab()->findOrCreateStaticSymbol(_methodSymbol, cpIndex, false);
5337
if (comp()->getOption(TR_TraceILGen))
5338
traceMsg(comp(), "load static symref %d created with knownObjectIndex %d", symRef->getReferenceNumber(), symRef->getKnownObjectIndex());
5339
TR::StaticSymbol * symbol = symRef->getSymbol()->castToStaticSymbol();
5340
TR_ASSERT(symbol, "Didn't geta static symbol.");
5341
5342
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fej9());
5343
5344
if (!comp()->isDLT())
5345
{
5346
TR::Symbol::RecognizedField recognizedField = symbol->getRecognizedField();
5347
switch (recognizedField)
5348
{
5349
case TR::Symbol::Java_math_BigInteger_useLongRepresentation:
5350
{
5351
// always evaluate to be true
5352
loadConstant(TR::iconst, 1);
5353
return;
5354
}
5355
case TR::Symbol::Com_ibm_jit_JITHelpers_IS_32_BIT:
5356
{
5357
int32_t constValue = comp()->target().is64Bit() ? 0 : 1;
5358
loadConstant(TR::iconst, constValue);
5359
return;
5360
}
5361
case TR::Symbol::Com_ibm_jit_JITHelpers_J9OBJECT_J9CLASS_OFFSET:
5362
{
5363
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9ObjectJ9Class());
5364
return;
5365
}
5366
case TR::Symbol::Com_ibm_jit_JITHelpers_J9OBJECT_FLAGS_MASK32:
5367
{
5368
loadConstant(TR::iconst, (int32_t)fej9->getJ9ObjectFlagsMask32());
5369
return;
5370
}
5371
case TR::Symbol::Com_ibm_jit_JITHelpers_J9OBJECT_FLAGS_MASK64:
5372
{
5373
loadConstant(TR::iconst, (int32_t)fej9->getJ9ObjectFlagsMask64());
5374
return;
5375
}
5376
case TR::Symbol::Com_ibm_jit_JITHelpers_JLTHREAD_J9THREAD_OFFSET:
5377
{
5378
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJLThreadJ9Thread());
5379
return;
5380
}
5381
case TR::Symbol::Com_ibm_jit_JITHelpers_J9THREAD_J9VM_OFFSET:
5382
{
5383
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9ThreadJ9VM());
5384
return;
5385
}
5386
case TR::Symbol::Com_ibm_jit_JITHelpers_J9ROMARRAYCLASS_ARRAYSHAPE_OFFSET:
5387
{
5388
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9ROMArrayClassArrayShape());
5389
return;
5390
}
5391
case TR::Symbol::Com_ibm_jit_JITHelpers_J9CLASS_BACKFILL_OFFSET_OFFSET:
5392
{
5393
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfBackfillOffsetField());
5394
return;
5395
}
5396
case TR::Symbol::Com_ibm_jit_JITHelpers_ARRAYSHAPE_ELEMENTCOUNT_MASK:
5397
{
5398
loadConstant(TR::iconst, 65535);
5399
return;
5400
}
5401
case TR::Symbol::Com_ibm_jit_JITHelpers_J9CONTIGUOUSARRAY_HEADER_SIZE:
5402
{
5403
loadConstant(TR::iconst, (int32_t)TR::Compiler->om.contiguousArrayHeaderSizeInBytes());
5404
return;
5405
}
5406
case TR::Symbol::Com_ibm_jit_JITHelpers_J9DISCONTIGUOUSARRAY_HEADER_SIZE:
5407
{
5408
loadConstant(TR::iconst, (int32_t)TR::Compiler->om.discontiguousArrayHeaderSizeInBytes());
5409
return;
5410
}
5411
case TR::Symbol::Com_ibm_jit_JITHelpers_J9OBJECT_CONTIGUOUS_LENGTH_OFFSET:
5412
{
5413
loadConstant(TR::iconst, (int32_t)fej9->getJ9ObjectContiguousLength());
5414
return;
5415
}
5416
case TR::Symbol::Com_ibm_jit_JITHelpers_J9OBJECT_DISCONTIGUOUS_LENGTH_OFFSET:
5417
{
5418
loadConstant(TR::iconst, (int32_t)fej9->getJ9ObjectDiscontiguousLength());
5419
return;
5420
}
5421
case TR::Symbol::Com_ibm_jit_JITHelpers_JLOBJECT_ARRAY_BASE_OFFSET:
5422
{
5423
loadConstant(TR::iconst, 8);
5424
return;
5425
}
5426
case TR::Symbol::Com_ibm_jit_JITHelpers_J9CLASS_J9ROMCLASS_OFFSET:
5427
{
5428
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfClassRomPtrField());
5429
return;
5430
}
5431
case TR::Symbol::Com_ibm_jit_JITHelpers_J9JAVAVM_IDENTITY_HASH_DATA_OFFSET:
5432
{
5433
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJavaVMIdentityHashData());
5434
return;
5435
}
5436
case TR::Symbol::Com_ibm_jit_JITHelpers_J9IDENTITYHASHDATA_HASH_DATA1_OFFSET:
5437
{
5438
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9IdentityHashData1());
5439
return;
5440
}
5441
case TR::Symbol::Com_ibm_jit_JITHelpers_J9IDENTITYHASHDATA_HASH_DATA2_OFFSET:
5442
{
5443
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9IdentityHashData2());
5444
return;
5445
}
5446
case TR::Symbol::Com_ibm_jit_JITHelpers_J9IDENTITYHASHDATA_HASH_DATA3_OFFSET:
5447
{
5448
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9IdentityHashData3());
5449
return;
5450
}
5451
case TR::Symbol::Com_ibm_jit_JITHelpers_J9IDENTITYHASHDATA_HASH_SALT_TABLE_OFFSET:
5452
{
5453
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9IdentityHashDataHashSaltTable());
5454
return;
5455
}
5456
case TR::Symbol::Com_ibm_jit_JITHelpers_J9_IDENTITY_HASH_SALT_POLICY_STANDARD:
5457
{
5458
loadConstant(TR::iconst, (int32_t)fej9->getJ9IdentityHashSaltPolicyStandard());
5459
return;
5460
}
5461
case TR::Symbol::Com_ibm_jit_JITHelpers_J9_IDENTITY_HASH_SALT_POLICY_REGION:
5462
{
5463
loadConstant(TR::iconst, (int32_t)fej9->getJ9IdentityHashSaltPolicyRegion());
5464
return;
5465
}
5466
case TR::Symbol::Com_ibm_jit_JITHelpers_J9_IDENTITY_HASH_SALT_POLICY_NONE:
5467
{
5468
loadConstant(TR::iconst, (int32_t)fej9->getJ9IdentityHashSaltPolicyNone());
5469
return;
5470
}
5471
case TR::Symbol::Com_ibm_jit_JITHelpers_IDENTITY_HASH_SALT_POLICY:
5472
{
5473
loadConstant(TR::iconst, (int32_t)fej9->getIdentityHashSaltPolicy());
5474
return;
5475
}
5476
case TR::Symbol::Com_ibm_oti_vm_VM_J9CLASS_CLASS_FLAGS_OFFSET:
5477
{
5478
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfClassFlags());
5479
return;
5480
}
5481
case TR::Symbol::Com_ibm_oti_vm_VM_J9CLASS_INITIALIZE_STATUS_OFFSET:
5482
{
5483
5484
loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfClassInitializeStatus());
5485
return;
5486
}
5487
case TR::Symbol::Com_ibm_oti_vm_VM_J9_JAVA_CLASS_RAM_SHAPE_SHIFT:
5488
{
5489
loadConstant(TR::iconst, (int32_t)fej9->getJ9JavaClassRamShapeShift());
5490
return;
5491
}
5492
case TR::Symbol::Com_ibm_oti_vm_VM_OBJECT_HEADER_SHAPE_MASK:
5493
{
5494
loadConstant(TR::iconst, (int32_t)fej9->getObjectHeaderShapeMask());
5495
return;
5496
}
5497
case TR::Symbol::Com_ibm_oti_vm_VM_ADDRESS_SIZE:
5498
{
5499
loadConstant(TR::iconst, (int32_t)sizeof(uintptr_t));
5500
return;
5501
}
5502
default:
5503
break;
5504
}
5505
}
5506
5507
TR::DataType type = symbol->getDataType();
5508
bool isResolved = !symRef->isUnresolved();
5509
TR_OpaqueClassBlock * classOfStatic = isResolved ? _method->classOfStatic(cpIndex) : 0;
5510
if (classOfStatic == NULL)
5511
{
5512
int len = 0;
5513
char * classNameOfFieldOrStatic = NULL;
5514
classNameOfFieldOrStatic = symRef->getOwningMethod(comp())->classNameOfFieldOrStatic(symRef->getCPIndex(), len);
5515
if (classNameOfFieldOrStatic)
5516
{
5517
classNameOfFieldOrStatic = TR::Compiler->cls.classNameToSignature(classNameOfFieldOrStatic, len, comp());
5518
TR_OpaqueClassBlock * curClass = fej9->getClassFromSignature(classNameOfFieldOrStatic, len, symRef->getOwningMethod(comp()));
5519
TR_OpaqueClassBlock * owningClass = comp()->getJittedMethodSymbol()->getResolvedMethod()->containingClass();
5520
if (owningClass == curClass)
5521
classOfStatic = curClass;
5522
}
5523
}
5524
5525
5526
bool isClassInitialized = false;
5527
TR_PersistentClassInfo * classInfo = _noLookahead ? 0 :
5528
comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(classOfStatic, comp());
5529
if (classInfo && classInfo->isInitialized())
5530
isClassInitialized = true;
5531
5532
/*
5533
if (classOfStatic)
5534
{
5535
char *name; int32_t len;
5536
name = comp()->fej9->getClassNameChars(classOfStatic, len);
5537
printf("class name %s class init %d class %p classInfo %p no %d hotness %d\n", name, isClassInitialized, classOfStatic, classInfo, _noLookahead, comp()->getMethodHotness()); fflush(stdout);
5538
}
5539
*/
5540
5541
bool canOptimizeFinalStatic = false;
5542
if (isResolved && symbol->isFinal() && !symRef->isUnresolved() &&
5543
classOfStatic != comp()->getSystemClassPointer() &&
5544
isClassInitialized)
5545
{
5546
//if (type == TR::Address)
5547
{
5548
5549
// todo: figure out why classInfo would be NULL here?
5550
if (!classInfo->getFieldInfo())
5551
performClassLookahead(classInfo);
5552
}
5553
5554
if (classInfo->getFieldInfo() && !classInfo->cannotTrustStaticFinal())
5555
canOptimizeFinalStatic = true;
5556
}
5557
5558
TR::VMAccessCriticalSection loadStaticCriticalSection(fej9,
5559
TR::VMAccessCriticalSection::tryToAcquireVMAccess,
5560
comp());
5561
5562
TR::Node * load = NULL;
5563
5564
if (canOptimizeFinalStatic &&
5565
loadStaticCriticalSection.hasVMAccess())
5566
{
5567
void * p = symbol->getStaticAddress();
5568
5569
switch (type)
5570
{
5571
case TR::Address:
5572
if ((void *)comp()->fej9()->getStaticReferenceFieldAtAddress((uintptr_t)p) == 0)
5573
{
5574
loadConstant(TR::aconst, 0);
5575
break;
5576
}
5577
else
5578
{
5579
// the address isn't constant, because a GC could move it, however is it nonnull
5580
//
5581
load = TR::Node::createLoad(symRef);
5582
load->setIsNonNull(true);
5583
push(load);
5584
break;
5585
}
5586
case TR::Double: loadConstant(TR::dconst, *(double *) p); break;
5587
case TR::Int64: loadConstant(TR::lconst, *(int64_t *)p); break;
5588
case TR::Float: loadConstant(TR::fconst, *(float *) p); break;
5589
case TR::Int32:
5590
default: loadConstant(TR::iconst, *(int32_t *)p); break;
5591
}
5592
}
5593
else if (symbol->isVolatile() && type == TR::Int64 && isResolved && comp()->target().is32Bit() &&
5594
!comp()->cg()->getSupportsInlinedAtomicLongVolatiles() && 0)
5595
{
5596
TR::SymbolReference * volatileLongSymRef =
5597
comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_volatileReadLong, false, false, true);
5598
TR::Node * statics = TR::Node::createWithSymRef(TR::loadaddr, 0, symRef);
5599
TR::Node * call = TR::Node::createWithSymRef(TR::lcall, 1, 1, statics, volatileLongSymRef);
5600
5601
handleSideEffect(call);
5602
5603
genTreeTop(call);
5604
push(call);
5605
}
5606
else
5607
{
5608
if (_generateReadBarriersForFieldWatch)
5609
{
5610
void * staticClass = method()->classOfStatic(cpIndex);
5611
loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, cpIndex, staticClass, true /* cpIndexOfStatic */));
5612
load = TR::Node::createWithSymRef(comp()->il.opCodeForDirectReadBarrier(type), 1, pop(), 0, symRef);
5613
}
5614
else
5615
load = TR::Node::createWithSymRef(comp()->il.opCodeForDirectLoad(type), 0, symRef);
5616
5617
TR::Node * treeTopNode = 0;
5618
if (symRef->isUnresolved())
5619
treeTopNode = genResolveCheck(load);
5620
else if (symbol->isVolatile() || _generateReadBarriersForFieldWatch)
5621
treeTopNode = load;
5622
5623
if (treeTopNode)
5624
{
5625
handleSideEffect(treeTopNode);
5626
genTreeTop(treeTopNode);
5627
}
5628
5629
push(load);
5630
}
5631
5632
static char *disableFinalFieldFoldingInILGen = feGetEnv("TR_DisableFinalFieldFoldingInILGen");
5633
static char *disableStaticFinalFieldFoldingInILGen = feGetEnv("TR_DisableStaticFinalFieldFoldingInILGen");
5634
if (load &&
5635
!disableFinalFieldFoldingInILGen &&
5636
!disableStaticFinalFieldFoldingInILGen &&
5637
symbol->isFinal() &&
5638
TR::TransformUtil::canFoldStaticFinalField(comp(), load) == TR_yes)
5639
{
5640
TR::TransformUtil::foldReliableStaticFinalField(comp(), load);
5641
}
5642
5643
}
5644
5645
TR::Node *
5646
TR_J9ByteCodeIlGenerator::loadSymbol(TR::ILOpCodes loadop, TR::SymbolReference * symRef)
5647
{
5648
TR::Node * node = TR::Node::createWithSymRef(loadop, 0, symRef);
5649
5650
if (symRef->isUnresolved())
5651
{
5652
TR::Node * treeTopNode = genResolveCheck(node);
5653
handleSideEffect(treeTopNode);
5654
genTreeTop(treeTopNode);
5655
}
5656
5657
push(node);
5658
return node;
5659
}
5660
5661
void
5662
TR_J9ByteCodeIlGenerator::loadClassObject(int32_t cpIndex)
5663
{
5664
void * classObject = method()->getClassFromConstantPool(comp(), cpIndex);
5665
loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, cpIndex, classObject));
5666
}
5667
5668
/**
5669
* Push a loadaddr of the class for cpIndex without emitting ResolveCHK.
5670
*
5671
* This is needed for checkcast and instanceof bytecode instructions, which are
5672
* required not to resolve classes when the tested object is null, so they
5673
* can't run ResolveCHK unconditionally.
5674
*
5675
* @param cpIndex The index of the constant pool entry that specifies the class
5676
* @param aotInhibit The JIT option to disallow using the resolved class for AOT
5677
* @return The symbol reference for the class
5678
*
5679
* @see genCheckCast(int32_t)
5680
* @see genInstanceof(int32_t)
5681
*/
5682
TR::SymbolReference *
5683
TR_J9ByteCodeIlGenerator::loadClassObjectForTypeTest(int32_t cpIndex, TR_CompilationOptions aotInhibit)
5684
{
5685
bool aotOK = !comp()->compileRelocatableCode() || !comp()->getOption(aotInhibit);
5686
void *classObject = method()->getClassFromConstantPool(comp(), cpIndex, aotOK);
5687
TR::SymbolReference *symRef = symRefTab()->findOrCreateClassSymbol(_methodSymbol, cpIndex, classObject);
5688
TR::Node *node = TR::Node::createWithSymRef(TR::loadaddr, 0, symRef);
5689
if (symRef->isUnresolved())
5690
{
5691
// We still need to anchor from the stack *as though* we were emitting
5692
// the ResolveCHK, since the type test will expand to include one later.
5693
TR::Node *dummyResolveCheck = genResolveCheck(node);
5694
handleSideEffect(dummyResolveCheck);
5695
node->decReferenceCount();
5696
}
5697
push(node);
5698
return symRef;
5699
}
5700
5701
void
5702
TR_J9ByteCodeIlGenerator::loadClassObject(TR_OpaqueClassBlock *opaqueClass)
5703
{
5704
loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, opaqueClass));
5705
}
5706
5707
void
5708
TR_J9ByteCodeIlGenerator::loadClassObjectAndIndirect(int32_t cpIndex)
5709
{
5710
void * classObject = method()->getClassFromConstantPool(comp(), cpIndex);
5711
loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, cpIndex, classObject));
5712
TR::Node* node = pop();
5713
node = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());
5714
push(node);
5715
}
5716
5717
5718
void
5719
TR_J9ByteCodeIlGenerator::loadConstant(TR::ILOpCodes loadop, int32_t constant)
5720
{
5721
push(TR::Node::create(loadop, 0, constant));
5722
}
5723
5724
void
5725
TR_J9ByteCodeIlGenerator::loadConstant(TR::ILOpCodes loadop, int64_t constant)
5726
{
5727
TR::Node * node = TR::Node::create(loadop, 0);
5728
node->setConstValue(constant);
5729
push(node);
5730
}
5731
5732
void
5733
TR_J9ByteCodeIlGenerator::loadConstant(TR::ILOpCodes loadop, float constant)
5734
{
5735
TR::Node * node = TR::Node::create(loadop, 0);
5736
node->setFloat(constant);
5737
push(node);
5738
}
5739
5740
void
5741
TR_J9ByteCodeIlGenerator::loadConstant(TR::ILOpCodes loadop, double constant)
5742
{
5743
TR::Node * node = TR::Node::create(loadop, 0);
5744
node->setDouble(constant);
5745
push(node);
5746
}
5747
5748
void
5749
TR_J9ByteCodeIlGenerator::loadConstant(TR::ILOpCodes loadop, void * constant)
5750
{
5751
TR::Node * node = TR::Node::create(loadop, 0);
5752
node->setAddress((uintptr_t)constant);
5753
push(node);
5754
}
5755
5756
void
5757
TR_J9ByteCodeIlGenerator::loadFromCP(TR::DataType type, int32_t cpIndex)
5758
{
5759
static char *floatInCP = feGetEnv("TR_FloatInCP");
5760
if (type == TR::NoType)
5761
type = method()->getLDCType(cpIndex);
5762
switch (type)
5763
{
5764
case TR::Int32: loadConstant(TR::iconst, (int32_t)method()->intConstant(cpIndex)); break;
5765
case TR::Int64: loadConstant(TR::lconst, (int64_t)method()->longConstant(cpIndex)); break;
5766
case TR::Float:
5767
if (!floatInCP)
5768
loadConstant(TR::fconst, * method()->floatConstant(cpIndex));
5769
else
5770
loadSymbol(TR::fload, symRefTab()->findOrCreateFloatSymbol(_methodSymbol, cpIndex));
5771
break;
5772
case TR::Double:
5773
if (!floatInCP)
5774
loadConstant(TR::dconst, *(double*)method()->doubleConstant(cpIndex, trMemory()));
5775
else
5776
loadSymbol(TR::dload, symRefTab()->findOrCreateDoubleSymbol(_methodSymbol, cpIndex));
5777
break;
5778
case TR::Address:
5779
if (method()->isConstantDynamic(cpIndex))
5780
{
5781
if (comp()->compileRelocatableCode())
5782
{
5783
if (comp()->getOption(TR_TraceILGen))
5784
traceMsg(comp(), " Constant Dynamic not supported in AOT.\n");
5785
comp()->failCompilation<J9::AOTHasConstantDynamic>("Constant Dynamic not supported in AOT.");
5786
}
5787
5788
bool isCondyUnresolved = _methodSymbol->getResolvedMethod()->isUnresolvedConstantDynamic(cpIndex);
5789
J9UTF8 *returnTypeUtf8 = (J9UTF8 *)_methodSymbol->getResolvedMethod()->getConstantDynamicTypeFromCP(cpIndex);
5790
int returnTypeUtf8Length = J9UTF8_LENGTH(returnTypeUtf8);
5791
char* returnTypeUtf8Data = (char *)J9UTF8_DATA(returnTypeUtf8);
5792
bool isCondyPrimitive = (1 == returnTypeUtf8Length);
5793
5794
// Use aconst for null object
5795
if (!isCondyPrimitive && !isCondyUnresolved)
5796
{
5797
TR::VMAccessCriticalSection condyCriticalSection(comp()->fej9());
5798
uintptr_t obj = 0;
5799
uintptr_t* objLocation = (uintptr_t*)_methodSymbol->getResolvedMethod()->dynamicConstant(cpIndex, &obj);
5800
if (obj == 0)
5801
{
5802
loadConstant(TR::aconst, (void *)0);
5803
return;
5804
}
5805
}
5806
5807
char* symbolTypeSig = NULL;
5808
int32_t symbolTypeSigLength = 0;
5809
// For non-primitive condy, resolved or not, we create a static symbol,
5810
// store the class info in the symbol so it may be retrieved by optimizer later via
5811
// getTypeSignature.
5812
if (!isCondyPrimitive)
5813
{
5814
symbolTypeSig = (char*)comp()->trMemory()->allocateMemory(returnTypeUtf8Length, heapAlloc);
5815
symbolTypeSigLength = returnTypeUtf8Length;
5816
memcpy(symbolTypeSig, returnTypeUtf8Data, symbolTypeSigLength);
5817
}
5818
5819
TR_OpaqueClassBlock * typeClassBlock = NULL;
5820
int32_t valueOffset = 0;
5821
5822
// If condy is primitive type and resolved, load the primitive constant;
5823
// Otherwise, load using a CP symbol (for resolved and unresolved object type),
5824
// and generate subsequent loadi for the unresolved primitive 'value' field if needed (because
5825
// for unresolved primitive the resolve helper only returns an autobox'd object).
5826
if (isCondyPrimitive)
5827
{
5828
char *autoboxClassSig = NULL;
5829
int32_t autoboxClassSigLength = 0;
5830
switch (returnTypeUtf8Data[0])
5831
{
5832
case 'I':
5833
autoboxClassSig = "Ljava/lang/Integer;";
5834
autoboxClassSigLength = 19;
5835
typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());
5836
valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()
5837
+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "I", 1);
5838
break;
5839
case 'J':
5840
autoboxClassSig = "Ljava/lang/Long;";
5841
autoboxClassSigLength = 16;
5842
typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());
5843
valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()
5844
+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "J", 1);
5845
break;
5846
case 'F':
5847
autoboxClassSig = "Ljava/lang/Float;";
5848
autoboxClassSigLength = 17;
5849
typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());
5850
valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()
5851
+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "F", 1);
5852
break;
5853
case 'D':
5854
autoboxClassSig = "Ljava/lang/Double;";
5855
autoboxClassSigLength = 18;
5856
typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());
5857
valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()
5858
+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "D", 1);
5859
break;
5860
case 'B':
5861
autoboxClassSig = "Ljava/lang/Byte;";
5862
autoboxClassSigLength = 16;
5863
typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());
5864
valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()
5865
+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "B", 1);
5866
break;
5867
case 'C':
5868
autoboxClassSig = "Ljava/lang/Character;";
5869
autoboxClassSigLength = 21;
5870
typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());
5871
valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()
5872
+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "C", 1);
5873
break;
5874
case 'S':
5875
autoboxClassSig = "Ljava/lang/Short;";
5876
autoboxClassSigLength = 17;
5877
typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());
5878
valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()
5879
+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "S", 1);
5880
break;
5881
case 'Z':
5882
autoboxClassSig = "Ljava/lang/Boolean;";
5883
autoboxClassSigLength = 19;
5884
typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());
5885
valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()
5886
+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "Z", 1);
5887
break;
5888
default:
5889
TR_ASSERT_FATAL(false, "Unrecognized primitive constant dynamic type signature");
5890
break;
5891
}
5892
// Generate constant for resolved primitive condy.
5893
if(!isCondyUnresolved)
5894
{
5895
TR::VMAccessCriticalSection primitiveCondyCriticalSection(comp()->fej9(),
5896
TR::VMAccessCriticalSection::tryToAcquireVMAccess,
5897
comp());
5898
if (primitiveCondyCriticalSection.hasVMAccess())
5899
{
5900
uintptr_t obj = 0;
5901
uintptr_t* objLocation = (uintptr_t*)_methodSymbol->getResolvedMethod()->dynamicConstant(cpIndex, &obj);
5902
TR_ASSERT(obj, "Resolved primitive Constant Dynamic-type CP entry %d must have autobox object", cpIndex);
5903
switch (returnTypeUtf8Data[0])
5904
{
5905
case 'I':
5906
case 'Z':
5907
case 'C':
5908
case 'S':
5909
case 'B':
5910
loadConstant(TR::iconst, *(int32_t*)(obj+valueOffset));
5911
break;
5912
case 'J':
5913
loadConstant(TR::lconst, *(int64_t*)(obj+valueOffset));
5914
break;
5915
case 'F':
5916
loadConstant(TR::fconst, *(float*)(obj+valueOffset));
5917
break;
5918
case 'D':
5919
loadConstant(TR::dconst, *(double*)(obj+valueOffset));
5920
break;
5921
default:
5922
TR_ASSERT_FATAL(false, "Unrecognized primitive constant dynamic type signature");
5923
break;
5924
}
5925
return;
5926
}
5927
}
5928
// If the primitive condy is unresolved, OR resolved but we fail to acquire VM access,
5929
// proceed to generate the loads. Store the type signature info in the symbol so it may be
5930
// retrieved by optimizer later.
5931
symbolTypeSig = (char*)comp()->trMemory()->allocateMemory(autoboxClassSigLength, heapAlloc);
5932
symbolTypeSigLength = autoboxClassSigLength;
5933
memcpy(symbolTypeSig, autoboxClassSig, symbolTypeSigLength);
5934
}
5935
TR::Node * loadObjNode = loadSymbol(TR::aload, symRefTab()->findOrCreateConstantDynamicSymbol(_methodSymbol, cpIndex,
5936
symbolTypeSig, symbolTypeSigLength, isCondyPrimitive));
5937
// Condy is primitive type, emit indirect load of the value field from the autobox object.
5938
if (isCondyPrimitive)
5939
{
5940
char *recogFieldName = NULL;
5941
TR::Symbol::RecognizedField valueRecogField= TR::Symbol::UnknownField;
5942
TR::DataType dt = TR::NoType;
5943
switch (returnTypeUtf8Data[0])
5944
{
5945
case 'I':
5946
recogFieldName = "java/lang/Integer.value I";
5947
valueRecogField = TR::Symbol::Java_lang_Integer_value;
5948
dt = TR::Int32;
5949
break;
5950
case 'J':
5951
recogFieldName = "java/lang/Long.value J";
5952
valueRecogField = TR::Symbol::Java_lang_Long_value;
5953
dt = TR::Int64;
5954
break;
5955
case 'F':
5956
recogFieldName = "java/lang/Float.value F";
5957
valueRecogField = TR::Symbol::Java_lang_Float_value;
5958
dt = TR::Float;
5959
break;
5960
case 'D':
5961
recogFieldName = "java/lang/Double.value D";
5962
valueRecogField = TR::Symbol::Java_lang_Double_value;
5963
dt = TR::Double;
5964
break;
5965
case 'B':
5966
recogFieldName = "java/lang/Byte.value B";
5967
valueRecogField = TR::Symbol::Java_lang_Byte_value;
5968
dt = TR::Int8;
5969
break;
5970
case 'C':
5971
recogFieldName = "java/lang/Character.value C";
5972
valueRecogField = TR::Symbol::Java_lang_Character_value;
5973
dt = TR::Int16;
5974
break;
5975
case 'S':
5976
recogFieldName = "java/lang/Short.value S";
5977
valueRecogField = TR::Symbol::Java_lang_Short_value;
5978
dt = TR::Int16;
5979
break;
5980
case 'Z':
5981
recogFieldName = "java/lang/Boolean.value Z";
5982
valueRecogField = TR::Symbol::Java_lang_Boolean_value;
5983
dt = TR::Int32;
5984
break;
5985
default:
5986
TR_ASSERT_FATAL(false, "Unrecognized primitive constant dynamic type signature");
5987
break;
5988
}
5989
TR::SymbolReference *valueSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(_methodSymbol,
5990
valueRecogField, dt, valueOffset, false, true, true, recogFieldName);
5991
TR::Node *primitiveValueNode = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(dt),
5992
1, 1, pop(), valueSymRef);
5993
primitiveValueNode->copyByteCodeInfo(loadObjNode);
5994
push(primitiveValueNode);
5995
}
5996
}
5997
else if (method()->isClassConstant(cpIndex))
5998
{
5999
loadClassObjectAndIndirect(cpIndex);
6000
}
6001
else if (method()->isStringConstant(cpIndex))
6002
{
6003
loadSymbol(TR::aload, symRefTab()->findOrCreateStringSymbol(_methodSymbol, cpIndex));
6004
}
6005
else if (method()->isMethodHandleConstant(cpIndex))
6006
{
6007
if (comp()->compileRelocatableCode())
6008
{
6009
if (comp()->getOption(TR_TraceILGen))
6010
traceMsg(comp(), " Method Handle Constant not supported in AOT.\n");
6011
comp()->failCompilation<J9::AOTHasMethodHandleConstant>("Method Handle Constant not supported in AOT.");
6012
}
6013
loadSymbol(TR::aload, symRefTab()->findOrCreateMethodHandleSymbol(_methodSymbol, cpIndex));
6014
}
6015
else
6016
{
6017
TR_ASSERT(method()->isMethodTypeConstant(cpIndex), "Address-type CP entry %d must be class, string, methodHandle, or methodType", cpIndex);
6018
if (comp()->compileRelocatableCode())
6019
{
6020
if (comp()->getOption(TR_TraceILGen))
6021
traceMsg(comp(), " Method Type Constant not supported in AOT.\n");
6022
comp()->failCompilation<J9::AOTHasMethodTypeConstant>("Method Type Constant not supported in AOT.");
6023
}
6024
loadSymbol(TR::aload, symRefTab()->findOrCreateMethodTypeSymbol(_methodSymbol, cpIndex));
6025
}
6026
break;
6027
default:
6028
break;
6029
}
6030
}
6031
6032
void
6033
TR_J9ByteCodeIlGenerator::loadFromCallSiteTable(int32_t callSiteIndex)
6034
{
6035
TR::SymbolReference *symRef = symRefTab()->findOrCreateCallSiteTableEntrySymbol(_methodSymbol, callSiteIndex);
6036
TR::Node *load = loadSymbol(TR::aload, symRef);
6037
if (!symRef->isUnresolved())
6038
{
6039
if (_methodSymbol->getResolvedMethod()->callSiteTableEntryAddress(callSiteIndex))
6040
load->setIsNonNull(true);
6041
else
6042
load->setIsNull(true);
6043
}
6044
}
6045
6046
void
6047
TR_J9ByteCodeIlGenerator::loadArrayElement(TR::DataType dataType, TR::ILOpCodes nodeop, bool checks, bool mayBeValueType)
6048
{
6049
// Value types prototype for flattened array elements does not yet support
6050
// GC policies that allow arraylets. If arraylets are required, assume
6051
// we won't have flattening, so no call to flattenable array element access
6052
// helper is needed.
6053
//
6054
if (mayBeValueType && TR::Compiler->om.areValueTypesEnabled() && !TR::Compiler->om.canGenerateArraylets() && dataType == TR::Address)
6055
{
6056
TR::Node* elementIndex = pop();
6057
TR::Node* arrayBaseAddress = pop();
6058
if (!arrayBaseAddress->isNonNull())
6059
{
6060
auto* nullchk = TR::Node::create(TR::PassThrough, 1, arrayBaseAddress);
6061
nullchk = genNullCheck(nullchk);
6062
genTreeTop(nullchk);
6063
}
6064
auto* helperSymRef = comp()->getSymRefTab()->findOrCreateLoadFlattenableArrayElementSymbolRef();
6065
auto* helperCallNode = TR::Node::createWithSymRef(TR::acall, 2, 2, elementIndex, arrayBaseAddress, helperSymRef);
6066
6067
TR::TreeTop *loadHelperCallTT = genTreeTop(helperCallNode);
6068
6069
const char *counterName = TR::DebugCounter::debugCounterName(comp(), "vt-helper/generated/aaload/(%s)/bc=%d",
6070
comp()->signature(), currentByteCodeIndex());
6071
TR::DebugCounter::prependDebugCounter(comp(), counterName, loadHelperCallTT);
6072
6073
push(helperCallNode);
6074
return;
6075
}
6076
6077
bool genSpineChecks = comp()->requiresSpineChecks();
6078
6079
_suppressSpineChecks = false;
6080
6081
calculateArrayElementAddress(dataType, checks);
6082
6083
TR::Node * arrayBaseAddress = pop();
6084
TR::Node * elementAddress = pop();
6085
6086
TR::Node *element = NULL;
6087
TR::SymbolReference * elementSymRef = symRefTab()->findOrCreateArrayShadowSymbolRef(dataType, arrayBaseAddress);
6088
element = TR::Node::createWithSymRef(nodeop, 1, 1, elementAddress, elementSymRef);
6089
6090
// For hybrid arrays, an incomplete check node may have been pushed on the stack.
6091
// It may not exist if the bound and spine check have been skipped.
6092
//
6093
TR::Node *checkNode = NULL;
6094
6095
if (genSpineChecks && !_stack->isEmpty())
6096
{
6097
if (_stack->top()->getOpCode().isSpineCheck())
6098
{
6099
checkNode = pop();
6100
}
6101
}
6102
6103
if (dataType == TR::Address)
6104
{
6105
6106
if (comp()->useCompressedPointers())
6107
{
6108
// Returns non-null if the compressedRefs anchor is going to
6109
// be part of the subtrees
6110
//
6111
// We don't want this in a separate treetop for hybrid arraylets.
6112
//
6113
TR::Node *newElement = genCompressedRefs(element);
6114
if (newElement)
6115
element = newElement;
6116
}
6117
}
6118
6119
if (checkNode)
6120
{
6121
if (checkNode->getOpCode().isBndCheck())
6122
{
6123
TR_ASSERT(checkNode->getOpCodeValue() == TR::BNDCHKwithSpineCHK, "unexpected check node");
6124
6125
// Re-arrange children now that load and base address
6126
// are known.
6127
//
6128
checkNode->setChild(2, checkNode->getChild(0)); // arraylength
6129
checkNode->setChild(3, checkNode->getChild(1)); // index
6130
}
6131
else
6132
{
6133
TR_ASSERT(checkNode->getOpCodeValue() == TR::SpineCHK, "unexpected check node");
6134
checkNode->setChild(2, checkNode->getChild(0)); // index
6135
}
6136
6137
checkNode->setSpineCheckWithArrayElementChild(true);
6138
checkNode->setAndIncChild(0, element); // array element
6139
checkNode->setAndIncChild(1, arrayBaseAddress); // base array
6140
}
6141
6142
push(element);
6143
}
6144
6145
void
6146
TR_J9ByteCodeIlGenerator::loadMonitorArg()
6147
{
6148
TR_ASSERT(_methodSymbol->isSynchronised(), "loadMonitorArg called for an nonsynchronized method");
6149
6150
// the syncObjectTemp is always initialized with the monitor argument on entry
6151
// to the method (regarless of whether its a static sync method or a sync method)
6152
// we don't want to use the syncObjectTemp always at the monexit because the monent and monexit
6153
// use different symRefs and this can cause problems for redundant monitor elimination.
6154
// we use the syncObjectTemp only when the outermost method is a DLT compile
6155
// for a DLT compile, if the compilation entered directly into a synchronized region, the syncObjectTemp
6156
// will be refreshed with the correct value in the DLT block
6157
//
6158
bool useSyncObjectTemp = comp()->isDLT() && _methodSymbol == comp()->getJittedMethodSymbol();
6159
6160
if (_methodSymbol->isStatic())
6161
loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, method()->containingClass()));
6162
else if (useSyncObjectTemp && _methodSymbol->getSyncObjectTemp())
6163
loadSymbol(TR::aload, _methodSymbol->getSyncObjectTemp());
6164
else
6165
loadAuto(TR::Address, 0); // get this pointer
6166
}
6167
6168
//----------------------------------------------
6169
// gen monitor
6170
//----------------------------------------------
6171
6172
void
6173
TR_J9ByteCodeIlGenerator::genMonitorEnter()
6174
{
6175
TR::SymbolReference * monitorEnterSymbolRef = symRefTab()->findOrCreateMonitorEntrySymbolRef(_methodSymbol);
6176
6177
TR::Node * node = pop();
6178
6179
bool isStatic = (node->getOpCodeValue() == TR::loadaddr && node->getSymbol()->isClassObject());
6180
6181
if (isStatic)
6182
node = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());
6183
6184
TR::Node *loadNode = node;
6185
// We need to keep all synchronized objects on the stack. We'll create meta data that represents each locked object at each
6186
// gc point so that the VM can figure out which objects are locked on the stack at any given gc point
6187
// code moved below, so that the store happens after the monent
6188
/*
6189
if (node->getOpCodeValue() != TR::aload || !comp()->getOption(TR_DisableLiveMonitorMetadata))
6190
{
6191
TR::SymbolReference * tempSymRef = symRefTab()->createTemporary(_methodSymbol, TR::Address);
6192
if (!comp()->getOption(TR_DisableLiveMonitorMetadata))
6193
{
6194
tempSymRef->getSymbol()->setHoldsMonitoredObject();
6195
comp()->addMonitorAuto(tempSymRef->getSymbol()->castToRegisterMappedSymbol(), comp()->getCurrentInlinedSiteIndex());
6196
}
6197
genTreeTop(TR::Node::createStore(tempSymRef, node));
6198
node = TR::Node::createLoad(tempSymRef);
6199
}
6200
*/
6201
6202
node = TR::Node::createWithSymRef(TR::monent, 1, 1, node, monitorEnterSymbolRef);
6203
if (isStatic)
6204
node->setStaticMonitor(true);
6205
6206
genTreeTop(genNullCheck(node));
6207
6208
if (!comp()->getOption(TR_DisableLiveMonitorMetadata))
6209
{
6210
TR::SymbolReference * tempSymRef = symRefTab()->createTemporary(_methodSymbol, TR::Address);
6211
comp()->addAsMonitorAuto(tempSymRef, false);
6212
genTreeTop(TR::Node::createStore(tempSymRef, loadNode));
6213
}
6214
6215
_methodSymbol->setMayContainMonitors(true);
6216
}
6217
6218
void
6219
TR_J9ByteCodeIlGenerator::genMonitorExit(bool isReturn)
6220
{
6221
TR::SymbolReference * monitorExitSymbolRef = isReturn ?
6222
symRefTab()->findOrCreateMethodMonitorExitSymbolRef(_methodSymbol) :
6223
symRefTab()->findOrCreateMonitorExitSymbolRef(_methodSymbol);
6224
6225
TR::Node * node = pop();
6226
6227
bool isStatic = (node->getOpCodeValue() == TR::loadaddr && node->getSymbol()->isClassObject());
6228
///bool isStatic = _methodSymbol->isStatic();
6229
6230
if (isStatic)
6231
node = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());
6232
6233
if (!comp()->getOption(TR_DisableLiveMonitorMetadata))
6234
{
6235
genTreeTop(TR::Node::create(TR::monexitfence,0));
6236
}
6237
node = TR::Node::createWithSymRef(TR::monexit, 1, 1, node, monitorExitSymbolRef);
6238
6239
if (isReturn)
6240
{
6241
if (_methodSymbol->isStatic())
6242
node->setStaticMonitor(true);
6243
6244
node->setSyncMethodMonitor(true);
6245
6246
TR_OpaqueClassBlock * owningClass = _methodSymbol->getResolvedMethod()->containingClass();
6247
if (owningClass != comp()->getObjectClassPointer())
6248
node->setSecond((TR::Node*)owningClass);
6249
6250
_implicitMonitorExits.add(node);
6251
}
6252
6253
node = genNullCheck(node);
6254
6255
// The monitor exit will unlock the class object which will allow other threads to modify the
6256
// fields in this class. To ensure that any fields referenced by the return are evaluated
6257
// before the monitor exit call the shadows symbols on the stack must be anchored before the
6258
// monitor exit call.
6259
//
6260
handleSideEffect(node);
6261
6262
genTreeTop(node);
6263
_methodSymbol->setMayContainMonitors(true);
6264
}
6265
6266
//----------------------------------------------
6267
// gen new
6268
//----------------------------------------------
6269
6270
void
6271
TR_J9ByteCodeIlGenerator::genNew(int32_t cpIndex)
6272
{
6273
loadClassObject(cpIndex);
6274
genNew();
6275
}
6276
6277
void
6278
TR_J9ByteCodeIlGenerator::genNew(TR::ILOpCodes opCode)
6279
{
6280
TR::Node *node = TR::Node::createWithSymRef(opCode, 1, 1, pop(),symRefTab()->findOrCreateNewObjectSymbolRef(_methodSymbol));
6281
_methodSymbol->setHasNews(true);
6282
genTreeTop(node);
6283
push(node);
6284
6285
bool skipFlush = false;
6286
if (!node->getFirstChild()->getSymbolReference()->isUnresolved() && node->getFirstChild()->getSymbol()->isStatic())
6287
{
6288
TR_OpaqueClassBlock *clazz = (TR_OpaqueClassBlock*)node->getFirstChild()->getSymbol()->castToStaticSymbol()->getStaticAddress();
6289
int32_t len;
6290
char *sig;
6291
sig = TR::Compiler->cls.classSignature_DEPRECATED(comp(), clazz, len, comp()->trMemory());
6292
OMR::ResolvedMethodSymbol *resolvedMethodSymbol = node->getSymbol()->getResolvedMethodSymbol();
6293
6294
if (((len == 16) && strncmp(sig, "Ljava/lang/Long;", 16) == 0) ||
6295
((len == 16) && strncmp(sig, "Ljava/lang/Byte;", 16) == 0) ||
6296
((len == 17) && strncmp(sig, "Ljava/lang/Short;", 17) == 0) ||
6297
((len == 18) && strncmp(sig, "Ljava/lang/String;", 18) == 0) ||
6298
((len == 19) && strncmp(sig, "Ljava/lang/Integer;", 19) == 0) ||
6299
((len == 19) && strncmp(sig, "Ljava/util/HashMap;", 19) == 0) ||
6300
((len == 21) && strncmp(sig, "Ljava/lang/Character;", 21) == 0) ||
6301
((len == 21) && strncmp(sig, "Ljava/nio/CharBuffer;", 21) == 0) ||
6302
((len == 21) && strncmp(sig, "Ljava/nio/ByteBuffer;", 21) == 0) ||
6303
((len == 24) && strncmp(sig, "Ljava/util/HashMap$Node;", 24) == 0) ||
6304
((len == 25) && strncmp(sig, "Ljava/util/ArrayList$Itr;", 25) == 0) ||
6305
((len == 25) && strncmp(sig, "Ljava/nio/HeapCharBuffer;", 25) == 0) ||
6306
((len == 25) && strncmp(sig, "Ljava/nio/HeapByteBuffer;", 25) == 0) ||
6307
((len == 25) && strncmp(sig, "Ljava/util/LinkedHashMap;", 25) == 0) ||
6308
((len == 26) && strncmp(sig, "Ljava/util/HashMap$KeySet;", 26) == 0) ||
6309
((len == 27) && strncmp(sig, "Ljava/util/Hashtable$Entry;", 27) == 0) ||
6310
((len == 28) && strncmp(sig, "Ljava/util/AbstractList$Itr;", 28) == 0) ||
6311
((len == 28) && strncmp(sig, "Ljava/util/HashMap$EntrySet;", 28) == 0) ||
6312
((len == 30) && strncmp(sig, "Ljava/util/LinkedList$ListItr;", 30) == 0) ||
6313
((len == 31) && strncmp(sig, "Ljava/util/HashMap$KeyIterator;", 31) == 0) ||
6314
((len == 32) && strncmp(sig, "Ljava/util/HashMap$HashIterator;", 32) == 0) ||
6315
((len == 33) && strncmp(sig, "Ljava/util/HashMap$ValueIterator;", 33) == 0) ||
6316
((len == 33) && strncmp(sig, "Ljava/util/HashMap$EntryIterator;", 33) == 0) ||
6317
((len == 33) && strncmp(sig, "Ljava/nio/charset/CharsetDecoder;", 33) == 0) ||
6318
((len == 35) && strncmp(sig, "Ljavax/servlet/ServletRequestEvent;", 35) == 0) ||
6319
((len == 44) && strncmp(sig, "Ljavax/servlet/ServletRequestAttributeEvent;", 44) == 0) ||
6320
((len == 45) && strncmp(sig, "Ljava/util/concurrent/ConcurrentHashMap$Node;", 45) == 0) ||
6321
((len == 53) && strncmp(sig, "Ljavax/faces/component/_DeltaStateHelper$InternalMap;", 53) == 0) ||
6322
((len == 55) && strncmp(sig, "Ljava/util/concurrent/CopyOnWriteArrayList$COWIterator;", 55) == 0) ||
6323
((len == 68) && strncmp(sig, "Ljava/util/concurrent/locks/ReentrantReadWriteLock$Sync$HoldCounter;", 68) == 0) ||
6324
((len == 25) && strncmp(sig, "Ljava/util/PriorityQueue;", 25) == 0) ||
6325
((len == 42) && strncmp(sig, "Ljava/util/concurrent/locks/ReentrantLock;", 42) == 0) ||
6326
((len == 54) && strncmp(sig, "Ljava/util/concurrent/locks/ReentrantLock$NonfairSync;", 54) == 0)
6327
)
6328
{
6329
skipFlush = true;
6330
}
6331
}
6332
6333
if (!skipFlush)
6334
genFlush(0);
6335
}
6336
6337
void
6338
TR_J9ByteCodeIlGenerator::genWithField(uint16_t fieldCpIndex)
6339
{
6340
const int32_t bcIndex = currentByteCodeIndex();
6341
int32_t classCpIndex = method()->classCPIndexOfFieldOrStatic(fieldCpIndex);
6342
TR_OpaqueClassBlock *valueClass = method()->getClassFromConstantPool(comp(), classCpIndex, true);
6343
if (!valueClass)
6344
{
6345
abortForUnresolvedValueTypeOp("withfield", "class");
6346
}
6347
6348
TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());
6349
if (owningMethod->isFieldQType(fieldCpIndex) && owningMethod->isFieldFlattened(comp(), fieldCpIndex, _methodSymbol->isStatic()))
6350
{
6351
return comp()->getOption(TR_UseFlattenedFieldRuntimeHelpers) ?
6352
genFlattenableWithFieldWithHelper(fieldCpIndex) :
6353
genFlattenableWithField(fieldCpIndex, valueClass);
6354
}
6355
6356
bool isStore = false;
6357
TR::SymbolReference * symRef = symRefTab()->findOrCreateShadowSymbol(_methodSymbol, fieldCpIndex, isStore);
6358
if (symRef->isUnresolved())
6359
{
6360
abortForUnresolvedValueTypeOp("withfield", "field");
6361
}
6362
6363
genWithField(symRef, valueClass);
6364
}
6365
6366
void
6367
TR_J9ByteCodeIlGenerator::genWithField(TR::SymbolReference * symRef, TR_OpaqueClassBlock * valueClass)
6368
{
6369
TR::Node *newFieldValue = pop();
6370
TR::Node *originalObject = pop();
6371
6372
/*
6373
* Insert nullchk for the original object as requested by the JVM spec.
6374
* Especially in case of value type class with a single field, the nullchk is still
6375
* necessary even though the original object is actually not needed.
6376
*/
6377
TR::Node *passThruNode = TR::Node::create(TR::PassThrough, 1, originalObject);
6378
genTreeTop(genNullCheck(passThruNode));
6379
6380
loadClassObject(valueClass);
6381
const TR::TypeLayout *typeLayout = comp()->typeLayout(valueClass);
6382
size_t fieldCount = typeLayout->count();
6383
6384
for (size_t idx = 0; idx < fieldCount; idx++)
6385
{
6386
const TR::TypeLayoutEntry &fieldEntry = typeLayout->entry(idx);
6387
if (fieldEntry._offset == symRef->getOffset())
6388
push(newFieldValue);
6389
else
6390
{
6391
auto* fieldSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(valueClass,
6392
fieldEntry._datatype,
6393
fieldEntry._offset,
6394
fieldEntry._isVolatile,
6395
fieldEntry._isPrivate,
6396
fieldEntry._isFinal,
6397
fieldEntry._fieldname,
6398
fieldEntry._typeSignature
6399
);
6400
push(originalObject);
6401
loadInstance(fieldSymRef);
6402
}
6403
}
6404
6405
TR::Node *newValueNode = genNodeAndPopChildren(TR::newvalue, fieldCount+1, symRefTab()->findOrCreateNewValueSymbolRef(_methodSymbol));
6406
newValueNode->setIdentityless(true);
6407
genTreeTop(newValueNode);
6408
push(newValueNode);
6409
genFlush(0);
6410
}
6411
6412
void
6413
TR_J9ByteCodeIlGenerator::genFlattenableWithFieldWithHelper(uint16_t fieldCpIndex)
6414
{
6415
bool isStore = false;
6416
TR::SymbolReference * symRef = symRefTab()->findOrCreateShadowSymbol(_methodSymbol, fieldCpIndex, isStore);
6417
if (symRef->isUnresolved())
6418
{
6419
abortForUnresolvedValueTypeOp("withfield", "field");
6420
}
6421
6422
TR::Node *newFieldValue = pop();
6423
TR::Node *originalObject = pop();
6424
6425
/*
6426
* Insert nullchk for the original object as requested by the JVM spec.
6427
* Especially in case of value type class with a single field, the nullchk is still
6428
* necessary even though the original object is actually not needed.
6429
*/
6430
TR::Node *passThruNode = TR::Node::create(TR::PassThrough, 1, originalObject);
6431
genTreeTop(genNullCheck(passThruNode));
6432
6433
auto* j9ResolvedMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());
6434
auto* ramFieldRef = reinterpret_cast<J9RAMFieldRef*>(j9ResolvedMethod->cp()) + fieldCpIndex;
6435
auto* ramFieldRefNode = TR::Node::aconst(reinterpret_cast<uintptr_t>(ramFieldRef));
6436
auto* helperCallNode = TR::Node::createWithSymRef(TR::acall, 3, 3, newFieldValue, originalObject, ramFieldRefNode, comp()->getSymRefTab()->findOrCreateWithFlattenableFieldSymbolRef());
6437
handleSideEffect(helperCallNode);
6438
genTreeTop(helperCallNode);
6439
push(helperCallNode);
6440
}
6441
6442
static TR::SymbolReference * createLoadFieldSymRef(TR::Compilation * comp, TR_OpaqueClassBlock * fieldClass, const char * fieldname)
6443
{
6444
const TR::TypeLayout *fieldClassLayout = comp->typeLayout(fieldClass);
6445
size_t fieldClassFieldCount = fieldClassLayout->count();
6446
6447
for (size_t idx = 0; idx < fieldClassFieldCount; idx++)
6448
{
6449
const TR::TypeLayoutEntry &fieldEntry = fieldClassLayout->entry(idx);
6450
if (!strcmp(fieldname, fieldEntry._fieldname))
6451
{
6452
auto * fieldSymRef = comp->getSymRefTab()->findOrFabricateShadowSymbol(fieldClass,
6453
fieldEntry._datatype,
6454
fieldEntry._offset,
6455
fieldEntry._isVolatile,
6456
fieldEntry._isPrivate,
6457
fieldEntry._isFinal,
6458
fieldEntry._fieldname,
6459
fieldEntry._typeSignature
6460
);
6461
return fieldSymRef;
6462
}
6463
}
6464
6465
TR_ASSERT_FATAL(false, "Did not find the matching fieldname %s", fieldname);
6466
return NULL;
6467
}
6468
6469
void
6470
TR_J9ByteCodeIlGenerator::genFlattenableWithField(uint16_t fieldCpIndex, TR_OpaqueClassBlock * valueClass)
6471
{
6472
/* An example on what the tree with flattened fields would look like
6473
*
6474
* value Point2D {
6475
* public final int x;
6476
* public final int y;
6477
* }
6478
*
6479
* value FlattenedLine2D {
6480
* public final Point2D st;
6481
* public final Point2D en;
6482
*
6483
* public static FlattenedLine2D withSt(FlattenedLine2D line, Point2D st) {
6484
* 0: aload_1
6485
* 1: aload_0
6486
* 3: withfield #3 // Field st:QPoint2D;
6487
* 6: astore_2
6488
* 7: aload_2
6489
* 8: areturn
6490
* }
6491
* }
6492
*
6493
* method="FlattenedLine2D.withSt(QFlattenedLine2D;QPoint2D;)QFlattenedLine2D;"
6494
* 3: JBwithfield
6495
* /--- trees inserted ------------------------
6496
* n7n ( 0) NULLCHK on n3n [#32]
6497
* n6n ( 2) iloadi Point2D.x I[#355 final Point2D.x I +4]
6498
* n3n ( 2) aload <parm 1 F>[#353 Parm]
6499
* n9n ( 0) NULLCHK on n3n [#32]
6500
* n8n ( 2) iloadi Point2D.y I[#356 final Point2D.y I +8]
6501
* n3n ( 2) ==>aload
6502
* n11n ( 0) NULLCHK on n4n [#32]
6503
* n10n ( 2) iloadi FlattenedLine2D.en.x I[#357 final FlattenedLine2D.en.x I +12]
6504
* n4n ( 2) aload <parm 0 Q>[#352 Parm]
6505
* n13n ( 0) NULLCHK on n4n [#32]
6506
* n12n ( 2) iloadi FlattenedLine2D.en.y I[#358 final FlattenedLine2D.en.y I +16]
6507
* n4n ( 2) ==>aload
6508
* n15n ( 0) treetop
6509
* n14n ( 1) newvalue jitNewValue[#100 helper Method]
6510
* n5n ( 1) loadaddr FlattenedLine2D[#354 Static]
6511
* n6n ( 2) ==>iloadi
6512
* n8n ( 2) ==>iloadi
6513
* n10n ( 2) ==>iloadi
6514
* n12n ( 2) ==>iloadi
6515
* /--- stack after ------------------------
6516
* @0 n14n ( 1) ==>newvalue (Identityless sharedMemory )
6517
* ============================================================
6518
*/
6519
TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());
6520
6521
if (isFieldResolved(comp(), owningMethod, fieldCpIndex, false))
6522
{
6523
TR::Node *newFieldValue = pop();
6524
TR::Node *originalObject = pop();
6525
6526
int32_t prefixLen = 0;
6527
char * fieldNamePrefix = getTopLevelPrefixForFlattenedFields(owningMethod, fieldCpIndex, prefixLen, comp()->trMemory()->currentStackRegion());
6528
6529
int len;
6530
const char * fieldClassChars = owningMethod->fieldSignatureChars(fieldCpIndex, len);
6531
TR_OpaqueClassBlock * fieldClass = fej9()->getClassFromSignature(fieldClassChars, len, owningMethod);
6532
6533
loadClassObject(valueClass);
6534
6535
const TR::TypeLayout *typeLayout = comp()->typeLayout(valueClass);
6536
size_t fieldCount = typeLayout->count();
6537
6538
TR_OpaqueClassBlock * containingClass = owningMethod->definingClassFromCPFieldRef(comp(), fieldCpIndex, _methodSymbol->isStatic());
6539
6540
for (size_t idx = 0; idx < fieldCount; idx++)
6541
{
6542
const TR::TypeLayoutEntry &fieldEntry = typeLayout->entry(idx);
6543
if (!strncmp(fieldNamePrefix, fieldEntry._fieldname, prefixLen))
6544
{
6545
const char * fieldNameRemovedTopLevelPrefix = fieldEntry._fieldname + prefixLen;
6546
auto * newFieldValueSymRef = createLoadFieldSymRef(comp(), fieldClass, fieldNameRemovedTopLevelPrefix);
6547
6548
if (comp()->getOption(TR_TraceILGen))
6549
{
6550
traceMsg(comp(), "Withfield flattened field %s\n - field[%d] name %s type %d offset %d\n",
6551
comp()->getDebug()->getName(newFieldValueSymRef), idx, fieldEntry._fieldname,
6552
fieldEntry._datatype.getDataType(), fieldEntry._offset);
6553
}
6554
6555
push(newFieldValue);
6556
loadInstance(newFieldValueSymRef);
6557
}
6558
else
6559
{
6560
auto * fieldSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(valueClass,
6561
fieldEntry._datatype,
6562
fieldEntry._offset,
6563
fieldEntry._isVolatile,
6564
fieldEntry._isPrivate,
6565
fieldEntry._isFinal,
6566
fieldEntry._fieldname,
6567
fieldEntry._typeSignature
6568
);
6569
push(originalObject);
6570
loadInstance(fieldSymRef);
6571
}
6572
}
6573
6574
TR::Node *newValueNode = genNodeAndPopChildren(TR::newvalue, fieldCount+1, symRefTab()->findOrCreateNewValueSymbolRef(_methodSymbol));
6575
newValueNode->setIdentityless(true);
6576
genTreeTop(newValueNode);
6577
push(newValueNode);
6578
genFlush(0);
6579
6580
return;
6581
}
6582
else
6583
{
6584
abortForUnresolvedValueTypeOp("withfield", "field");
6585
}
6586
}
6587
6588
void
6589
TR_J9ByteCodeIlGenerator::genAconst_init(uint16_t cpIndex)
6590
{
6591
TR_OpaqueClassBlock *valueTypeClass = method()->getClassFromConstantPool(comp(), cpIndex);
6592
genAconst_init(valueTypeClass);
6593
}
6594
6595
void
6596
TR_J9ByteCodeIlGenerator::genAconst_init(TR_OpaqueClassBlock *valueTypeClass)
6597
{
6598
// valueTypeClass will be NULL if it is unresolved. Abort the compilation and
6599
// track the failure with a static debug counter
6600
if (valueTypeClass == NULL)
6601
{
6602
abortForUnresolvedValueTypeOp("aconst_init", "class");
6603
}
6604
6605
TR::SymbolReference *valueClassSymRef = symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, valueTypeClass);
6606
6607
if (comp()->getOption(TR_TraceILGen))
6608
{
6609
traceMsg(comp(), "Handling aconst_init for valueClass %s\n", comp()->getDebug()->getName(valueClassSymRef));
6610
}
6611
6612
loadSymbol(TR::loadaddr, valueClassSymRef);
6613
6614
TR::Node *newValueNode = NULL;
6615
6616
if (valueClassSymRef->isUnresolved())
6617
{
6618
// IL generation for aconst_init is currently only able to handle value type classes that have been resolved.
6619
// If the class is still unresolved, abort the compilation and track the failure with a static debug counter.
6620
abortForUnresolvedValueTypeOp("aconst_init", "class");
6621
}
6622
else
6623
{
6624
const TR::TypeLayout *typeLayout = comp()->typeLayout(valueTypeClass);
6625
size_t fieldCount = typeLayout->count();
6626
6627
for (size_t idx = 0; idx < fieldCount; idx++)
6628
{
6629
const TR::TypeLayoutEntry &entry = typeLayout->entry(idx);
6630
6631
if (comp()->getOption(TR_TraceILGen))
6632
{
6633
traceMsg(comp(), "Handling aconst_init for valueClass %s\n - field[%d] name %s type %d offset %d\n", comp()->getDebug()->getName(valueClassSymRef), idx, entry._fieldname, entry._datatype.getDataType(), entry._offset);
6634
}
6635
6636
// Supply default value that is appropriate for the type of the corresponding field
6637
// All these are gathered up as operands of a newvalue instruction.
6638
//
6639
// For example, if a value type class "Val" has fields of type int, long, double, LIdent;
6640
// and Qval2;, where value type class "Val2" has a field of type boolean, the following
6641
// IL will be generated:
6642
//
6643
// newvalue jitNewValue // Default value of type Val
6644
// loadaddr Val
6645
// iconst 0 // int default value
6646
// lconst 0 // long default value
6647
// dconst 0.0 // double default value
6648
// aconst 0 // default value (null reference) for class Ident
6649
// newvalue jitNewValue // Default value of type Val2
6650
// loadaddr Val2
6651
// iconst 0 // boolean default value
6652
//
6653
switch (entry._datatype.getDataType())
6654
{
6655
case TR::Int8:
6656
case TR::Int16:
6657
case TR::Int32:
6658
{
6659
loadConstant(TR::iconst, 0);
6660
break;
6661
}
6662
case TR::Int64:
6663
{
6664
loadConstant(TR::lconst, (int64_t) 0ll);
6665
break;
6666
}
6667
case TR::Float:
6668
{
6669
loadConstant(TR::fconst, 0.0f);
6670
break;
6671
}
6672
case TR::Double:
6673
{
6674
loadConstant(TR::dconst, 0.0);
6675
break;
6676
}
6677
case TR::Address:
6678
{
6679
const char *fieldSignature = entry._typeSignature;
6680
6681
// If the field's signature begins with a Q, it is a value type and should be initialized with a default value
6682
// for that value type. That's handled with a recursive call to genAconst_init.
6683
// If the signature does not begin with a Q, the field is an identity type whose default value is a Java null
6684
/// reference.
6685
if (fieldSignature[0] == 'Q')
6686
{
6687
TR_OpaqueClassBlock *fieldClass = fej9()->getClassFromSignature(fieldSignature, (int32_t)strlen(fieldSignature),
6688
comp()->getCurrentMethod());
6689
genAconst_init(fieldClass);
6690
}
6691
else if (comp()->target().is64Bit())
6692
{
6693
loadConstant(TR::aconst, (int64_t)0);
6694
}
6695
else
6696
{
6697
loadConstant(TR::aconst, (int32_t)0);
6698
}
6699
break;
6700
}
6701
default:
6702
{
6703
TR_ASSERT_FATAL(false, "Unexpected type for aconst_init field\n");
6704
}
6705
}
6706
}
6707
6708
newValueNode = genNodeAndPopChildren(TR::newvalue, fieldCount+1, symRefTab()->findOrCreateNewValueSymbolRef(_methodSymbol));
6709
newValueNode->setIdentityless(true);
6710
}
6711
6712
genTreeTop(newValueNode);
6713
push(newValueNode);
6714
genFlush(0);
6715
}
6716
6717
void
6718
TR_J9ByteCodeIlGenerator::genNewArray(int32_t typeIndex)
6719
{
6720
loadConstant(TR::iconst, typeIndex);
6721
6722
TR::Node * secondChild=pop();
6723
TR::Node * firstChild=pop();
6724
TR::Node * node = TR::Node::createWithSymRef(TR::newarray, 2, 2, firstChild, secondChild, symRefTab()->findOrCreateNewArraySymbolRef(_methodSymbol));
6725
6726
if (_methodSymbol->skipZeroInitializationOnNewarrays())
6727
node->setCanSkipZeroInitialization(true);
6728
6729
bool generateArraylets = comp()->generateArraylets();
6730
6731
// special case for handling Arrays.copyOf in the StringEncoder fast paths for Java 9+
6732
if (!comp()->isOutermostMethod() && !comp()->isPeekingMethod()
6733
&& !generateArraylets
6734
&& _methodSymbol->getRecognizedMethod() == TR::java_util_Arrays_copyOf_byte)
6735
{
6736
int32_t callerIndex = comp()->getCurrentInlinedCallSite()->_byteCodeInfo.getCallerIndex();
6737
TR::ResolvedMethodSymbol *caller = callerIndex > -1 ? comp()->getInlinedResolvedMethodSymbol(callerIndex) : comp()->getMethodSymbol();
6738
switch (caller->getRecognizedMethod())
6739
{
6740
case TR::java_lang_StringCoding_encode8859_1:
6741
case TR::java_lang_StringCoding_encodeASCII:
6742
case TR::java_lang_String_encodeASCII:
6743
case TR::java_lang_StringCoding_encodeUTF8:
6744
node->setCanSkipZeroInitialization(true);
6745
break;
6746
6747
default:
6748
break;
6749
}
6750
}
6751
6752
bool separateInitializationFromAllocation;
6753
switch (_methodSymbol->getRecognizedMethod())
6754
{
6755
case TR::java_util_Arrays_copyOf_byte:
6756
case TR::java_util_Arrays_copyOf_short:
6757
case TR::java_util_Arrays_copyOf_char:
6758
case TR::java_util_Arrays_copyOf_int:
6759
case TR::java_util_Arrays_copyOf_long:
6760
case TR::java_util_Arrays_copyOf_float:
6761
case TR::java_util_Arrays_copyOf_double:
6762
case TR::java_util_Arrays_copyOf_boolean:
6763
case TR::java_util_Arrays_copyOfRange_byte:
6764
case TR::java_util_Arrays_copyOfRange_short:
6765
case TR::java_util_Arrays_copyOfRange_char:
6766
case TR::java_util_Arrays_copyOfRange_int:
6767
case TR::java_util_Arrays_copyOfRange_long:
6768
case TR::java_util_Arrays_copyOfRange_float:
6769
case TR::java_util_Arrays_copyOfRange_double:
6770
case TR::java_util_Arrays_copyOfRange_boolean:
6771
separateInitializationFromAllocation = true;
6772
break;
6773
default:
6774
separateInitializationFromAllocation = false;
6775
break;
6776
}
6777
6778
TR::Node *initNode = NULL;
6779
6780
if (!comp()->getOption(TR_DisableSeparateInitFromAlloc) &&
6781
!node->canSkipZeroInitialization() &&
6782
!generateArraylets && separateInitializationFromAllocation &&
6783
comp()->cg()->getSupportsArraySet())
6784
{
6785
node->setCanSkipZeroInitialization(true);
6786
6787
TR::Node *arrayRefNode;
6788
int32_t hdrSize = (int32_t) TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
6789
bool is64BitTarget = comp()->target().is64Bit();
6790
6791
if (is64BitTarget)
6792
{
6793
TR::Node *constantNode = TR::Node::create(node, TR::lconst);
6794
constantNode->setLongInt((int64_t)hdrSize);
6795
arrayRefNode = TR::Node::create(TR::aladd, 2, node, constantNode);
6796
}
6797
else
6798
arrayRefNode = TR::Node::create(TR::aiadd, 2, node, TR::Node::create(node, TR::iconst, 0, hdrSize));
6799
6800
arrayRefNode->setIsInternalPointer(true);
6801
6802
TR::Node *sizeInBytes;
6803
TR::Node *sizeNode = node->getFirstChild();
6804
6805
TR::Node* constValNode = TR::Node::bconst(node, (int8_t)0);
6806
int32_t elementSize = TR::Compiler->om.getSizeOfArrayElement(node);
6807
6808
if (is64BitTarget)
6809
{
6810
TR::Node *stride = TR::Node::create(node, TR::lconst);
6811
stride->setLongInt((int64_t) elementSize);
6812
TR::Node *i2lNode = TR::Node::create(TR::i2l, 1, sizeNode);
6813
sizeInBytes = TR::Node::create(TR::lmul, 2, i2lNode, stride);
6814
}
6815
else
6816
{
6817
TR::Node *stride = TR::Node::create(node, TR::iconst, 0, elementSize);
6818
sizeInBytes = TR::Node::create(TR::imul, 2, sizeNode, stride);
6819
}
6820
6821
TR::Node *arraysetNode = TR::Node::create(TR::arrayset, 3, arrayRefNode, constValNode, sizeInBytes);
6822
TR::SymbolReference *arraySetSymRef = comp()->getSymRefTab()->findOrCreateArraySetSymbol();
6823
arraysetNode->setSymbolReference(arraySetSymRef);
6824
arraysetNode->setArraysetLengthMultipleOfPointerSize(true);
6825
6826
initNode = TR::Node::create(TR::treetop, 1, arraysetNode);
6827
}
6828
6829
_methodSymbol->setHasNews(true);
6830
genTreeTop(node);
6831
if (initNode)
6832
genTreeTop(initNode);
6833
push(node);
6834
genFlush(0);
6835
}
6836
6837
void
6838
TR_J9ByteCodeIlGenerator::genANewArray(int32_t cpIndex)
6839
{
6840
loadClassObject(cpIndex);
6841
genANewArray();
6842
}
6843
6844
void
6845
TR_J9ByteCodeIlGenerator::genANewArray()
6846
{
6847
TR::Node * secondChild=pop();
6848
TR::Node * firstChild=pop();
6849
TR::Node * node = TR::Node::createWithSymRef(TR::anewarray, 2, 2, firstChild, secondChild, symRefTab()->findOrCreateANewArraySymbolRef(_methodSymbol));
6850
_methodSymbol->setHasNews(true);
6851
genTreeTop(node);
6852
push(node);
6853
genFlush(0);
6854
}
6855
6856
void
6857
TR_J9ByteCodeIlGenerator::genMultiANewArray(int32_t cpIndex, int32_t dims)
6858
{
6859
// total number of params is 2+#dims
6860
//
6861
loadClassObject(cpIndex);
6862
genMultiANewArray(dims);
6863
}
6864
6865
void
6866
TR_J9ByteCodeIlGenerator::genMultiANewArray(int32_t dims)
6867
{
6868
// total number of params is 2+#dims
6869
//
6870
TR::Node *node = genNodeAndPopChildren(TR::multianewarray, dims+2, symRefTab()->findOrCreateMultiANewArraySymbolRef(_methodSymbol), 1);
6871
6872
_methodSymbol->setHasNews(true);
6873
// Make number of dimensions the first parameter
6874
//
6875
loadConstant(TR::iconst, dims);
6876
node->setAndIncChild(0, pop());
6877
6878
genTreeTop(node);
6879
push(node);
6880
}
6881
6882
//----------------------------------------------
6883
// genReturn
6884
//----------------------------------------------
6885
6886
int32_t
6887
TR_J9ByteCodeIlGenerator::genReturn(TR::ILOpCodes nodeop, bool monitorExit)
6888
{
6889
if (!comp()->isPeekingMethod() &&
6890
(_methodSymbol->getMandatoryRecognizedMethod() == TR::java_lang_Object_init))
6891
{
6892
TR::Node *receiverArg = NULL;
6893
if (_methodSymbol->getThisTempForObjectCtor())
6894
receiverArg = TR::Node::createLoad(_methodSymbol->getThisTempForObjectCtor());
6895
else
6896
{
6897
loadAuto(TR::Address, 0);
6898
receiverArg = pop();
6899
}
6900
TR::SymbolReference *finalizeSymRef = comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_jitCheckIfFinalizeObject, true, true, true);
6901
TR::Node *vcallNode = TR::Node::createWithSymRef(TR::call, 1, 1, receiverArg, finalizeSymRef);
6902
_finalizeCallsBeforeReturns.add(vcallNode);
6903
genTreeTop(vcallNode);
6904
}
6905
6906
static const char* disableMethodHookForCallees = feGetEnv("TR_DisableMethodHookForCallees");
6907
if ((fej9()->isMethodTracingEnabled(_methodSymbol->getResolvedMethod()->getPersistentIdentifier())
6908
|| (!comp()->getOption(TR_FullSpeedDebug)
6909
&& TR::Compiler->vm.canMethodExitEventBeHooked(comp())))
6910
&& (isOutermostMethod() || !disableMethodHookForCallees))
6911
{
6912
TR::SymbolReference * methodExitSymRef = symRefTab()->findOrCreateReportMethodExitSymbolRef(_methodSymbol);
6913
6914
TR::Node * methodExitNode;
6915
if (nodeop == TR::Return)
6916
{
6917
loadConstant(TR::aconst, (void *)0);
6918
methodExitNode = TR::Node::createWithSymRef(TR::MethodExitHook, 1, 1, pop(), methodExitSymRef);
6919
}
6920
else
6921
{
6922
TR::Node * returnValue = _stack->top();
6923
TR::SymbolReference * tempSymRef = symRefTab()->createTemporary(_methodSymbol, getDataType(returnValue));
6924
genTreeTop(TR::Node::createStore(tempSymRef, returnValue));
6925
methodExitNode = TR::Node::createWithSymRef(TR::MethodExitHook, 1, 1, TR::Node::createWithSymRef(TR::loadaddr, 0, tempSymRef), methodExitSymRef);
6926
}
6927
6928
genTreeTop(methodExitNode);
6929
}
6930
6931
6932
if (comp()->getOption(TR_EnableThisLiveRangeExtension))
6933
{
6934
if (!_methodSymbol->isStatic() &&
6935
(!fej9()->isClassFinal(_methodSymbol->getResolvedMethod()->containingClass()) ||
6936
fej9()->hasFinalizer(_methodSymbol->getResolvedMethod()->containingClass())))
6937
{
6938
loadAuto(TR::Address, 0);
6939
TR::SymbolReference *tempSymRef = symRefTab()->findOrCreateThisRangeExtensionSymRef(comp()->getMethodSymbol());
6940
genTreeTop(TR::Node::createStore(tempSymRef, pop()));
6941
}
6942
}
6943
6944
if (monitorExit && _methodSymbol->isSynchronised())
6945
{
6946
if (!isOutermostMethod())
6947
{
6948
// the monitor exit in an inlined method must be in a separate block so that the generated exception range
6949
// doesn't include it.
6950
//
6951
genTarget(_bcIndex);
6952
setupBBStartContext(_bcIndex);
6953
//printf("create a separate block for %s being inlined into %s\n", _methodSymbol->signature(trMemory()), comp()->signature());
6954
}
6955
6956
loadMonitorArg();
6957
genMonitorExit(true);
6958
}
6959
6960
if (nodeop == TR::Return)
6961
{
6962
genTreeTop(TR::Node::create(nodeop, 0));
6963
}
6964
else
6965
{
6966
TR::Node* returnChild = pop();
6967
6968
switch (current())
6969
{
6970
case J9BCReturnC:
6971
returnChild = TR::Node::create(TR::su2i, 1, TR::Node::create(TR::i2s, 1, returnChild));
6972
break;
6973
6974
case J9BCReturnS:
6975
returnChild = TR::Node::create(TR::s2i, 1, TR::Node::create(TR::i2s, 1, returnChild));
6976
break;
6977
6978
case J9BCReturnB:
6979
returnChild = TR::Node::create(TR::b2i, 1, TR::Node::create(TR::i2b, 1, returnChild));
6980
break;
6981
6982
case J9BCReturnZ:
6983
returnChild = TR::Node::create(TR::iand, 2, returnChild, TR::Node::iconst(1));
6984
break;
6985
6986
default:
6987
break;
6988
}
6989
6990
genTreeTop(TR::Node::create(nodeop, 1, returnChild));
6991
}
6992
6993
discardEntireStack();
6994
6995
return findNextByteCodeToGen();
6996
}
6997
6998
static bool storeCanBeRemovedForUnreadField(TR_PersistentFieldInfo * fieldInfo, TR::Node *node)
6999
{
7000
if (!fieldInfo ||
7001
!fieldInfo->isNotRead())
7002
return false;
7003
7004
// PR 78765: It's generally not safe to remove field stores because we can't
7005
// prove that native methods won't read them. It's also not safe to remove
7006
// address field stores in case the stored object has a finalizer; failing
7007
// to store the reference can cause the finalizer to run prematurely.
7008
//
7009
// However, in certain cases, this is known to be safe, so we can detect
7010
// those and optimize away the stores.
7011
7012
if (node->getOpCode().isCall() &&
7013
!node->getSymbolReference()->isUnresolved())
7014
{
7015
if (fieldInfo->isBigDecimalType())
7016
{
7017
if ((node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigDecimal_add) ||
7018
(node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigDecimal_subtract) ||
7019
(node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigDecimal_multiply))
7020
return true;
7021
}
7022
7023
if (fieldInfo->isBigIntegerType())
7024
{
7025
if ((node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigInteger_add) ||
7026
(node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigInteger_subtract) ||
7027
(node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigInteger_multiply))
7028
return true;
7029
}
7030
}
7031
7032
return false;
7033
}
7034
7035
//----------------------------------------------
7036
// gen store
7037
//----------------------------------------------
7038
void
7039
TR_J9ByteCodeIlGenerator::storeInstance(int32_t cpIndex)
7040
{
7041
if (_generateWriteBarriersForFieldWatch && comp()->compileRelocatableCode())
7042
comp()->failCompilation<J9::AOTNoSupportForAOTFailure>("NO support for AOT in field watch");
7043
7044
TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());
7045
if (TR::Compiler->om.areValueTypesEnabled() && owningMethod->isFieldQType(cpIndex))
7046
{
7047
if (!isFieldResolved(comp(), owningMethod, cpIndex, true))
7048
{
7049
abortForUnresolvedValueTypeOp("putfield", "field");
7050
}
7051
else if (owningMethod->isFieldFlattened(comp(), cpIndex, _methodSymbol->isStatic()))
7052
{
7053
return comp()->getOption(TR_UseFlattenedFieldRuntimeHelpers) ?
7054
storeFlattenableInstanceWithHelper(cpIndex) :
7055
storeFlattenableInstance(cpIndex);
7056
}
7057
}
7058
7059
TR::SymbolReference * symRef = symRefTab()->findOrCreateShadowSymbol(_methodSymbol, cpIndex, true);
7060
storeInstance(symRef);
7061
}
7062
7063
void
7064
TR_J9ByteCodeIlGenerator::storeInstance(TR::SymbolReference * symRef)
7065
{
7066
TR::Symbol * symbol = symRef->getSymbol();
7067
TR::DataType type = symbol->getDataType();
7068
7069
TR::Node * value = pop();
7070
TR::Node * address = pop();
7071
7072
TR::Node * addressNode = address;
7073
TR::Node * parentObject = address;
7074
7075
// code to handle volatiles moved to CodeGenPrep
7076
//
7077
TR::Node * node;
7078
if ((type == TR::Address && _generateWriteBarriersForGC) || _generateWriteBarriersForFieldWatch)
7079
{
7080
node = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectWriteBarrier(type), 3, 3, addressNode, value, parentObject, symRef);
7081
}
7082
else
7083
{
7084
if (type == TR::Int8 && symRefTab()->isFieldTypeBool(symRef))
7085
value = TR::Node::create(TR::iand, 2, value, TR::Node::create(TR::iconst, 0, 1));
7086
node = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectStore(type), 2, 2, addressNode, value, symRef);
7087
}
7088
7089
if (symbol->isPrivate() && _classInfo && comp()->getNeedsClassLookahead())
7090
{
7091
if (!_classInfo->getFieldInfo())
7092
performClassLookahead(_classInfo);
7093
7094
TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), node, true) : NULL;
7095
if (storeCanBeRemovedForUnreadField(fieldInfo, value) &&
7096
performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip store to instance field (that is never read) storing value %p based on class file examination\n", value))
7097
{
7098
//int32_t length;
7099
//char *sig = TR_ClassLookahead::getFieldSignature(comp(), symbol, symRef, length);
7100
//fprintf(stderr, "Skipping store for field %s in %s\n", sig, comp()->signature());
7101
//fflush(stderr);
7102
genTreeTop(value);
7103
genTreeTop(address);
7104
int32_t numChildren = node->getNumChildren();
7105
int32_t i = 0;
7106
while (i < numChildren)
7107
{
7108
node->getChild(i)->decReferenceCount();
7109
i++;
7110
}
7111
7112
if (!address->isNonNull())
7113
{
7114
TR::Node *passThruNode = TR::Node::create(TR::PassThrough, 1, address);
7115
genTreeTop(genNullCheck(passThruNode));
7116
}
7117
7118
return;
7119
}
7120
}
7121
if (symbol->isPrivate() && !comp()->getOptions()->realTimeGC())
7122
{
7123
TR_ResolvedMethod *method;
7124
7125
if (node->getInlinedSiteIndex() != -1)
7126
method = comp()->getInlinedResolvedMethod(node->getInlinedSiteIndex());
7127
else
7128
method = comp()->getCurrentMethod();
7129
7130
if (method && method->getRecognizedMethod() == TR::java_lang_ref_SoftReference_get &&
7131
symbol->getRecognizedField() == TR::Symbol::Java_lang_ref_SoftReference_age)
7132
{
7133
TR::Node *secondChild = node->getChild(1);
7134
if (secondChild && secondChild->getOpCodeValue() == TR::iconst && secondChild->getInt() == 0)
7135
{
7136
handleSideEffect(node);
7137
genTreeTop(node);
7138
genFullFence(node);
7139
return;
7140
}
7141
}
7142
}
7143
bool genTranslateTT = (comp()->useCompressedPointers() && (type == TR::Address));
7144
7145
if (symRef->isUnresolved())
7146
{
7147
if (!address->isNonNull())
7148
node = genResolveAndNullCheck(node);
7149
else
7150
node = genResolveCheck(node);
7151
7152
genTranslateTT = false;
7153
}
7154
else if (!address->isNonNull())
7155
{
7156
TR::Node *nullChkNode = genNullCheck(node);
7157
// in some cases a nullchk may not
7158
// have been generated at all for the store
7159
//
7160
if (nullChkNode != node)
7161
genTranslateTT = false;
7162
node = nullChkNode;
7163
}
7164
7165
handleSideEffect(node);
7166
7167
if (!genTranslateTT)
7168
genTreeTop(node);
7169
7170
if (comp()->useCompressedPointers() &&
7171
(type == TR::Address))
7172
{
7173
// - J9JIT_COMPRESSED_POINTER J9CLASS HACK-
7174
// remove this check when j9class is allocated on the heap
7175
// do not compress fields that contain class pointers
7176
//
7177
TR::Node *storeValue = node;
7178
if (storeValue->getOpCode().isCheck())
7179
storeValue = storeValue->getFirstChild();
7180
7181
if (!symRefTab()->isFieldClassObject(symRef))
7182
{
7183
// returns non-null if the compressedRefs anchor is going to
7184
// be part of the subtrees (for now, it is a treetop)
7185
//
7186
TR::Node *newValue = genCompressedRefs(storeValue, true, -1);
7187
if (newValue)
7188
{
7189
node->getSecondChild()->decReferenceCount();
7190
node->setAndIncChild(1, newValue);
7191
}
7192
}
7193
else
7194
genTreeTop(node);
7195
}
7196
}
7197
7198
void
7199
TR_J9ByteCodeIlGenerator::storeFlattenableInstanceWithHelper(int32_t cpIndex)
7200
{
7201
TR::Node * value = pop();
7202
TR::Node * address = pop();
7203
if (!address->isNonNull())
7204
{
7205
auto* nullchk = TR::Node::create(TR::PassThrough, 1, address);
7206
nullchk = genNullCheck(nullchk);
7207
genTreeTop(nullchk);
7208
}
7209
auto* j9ResolvedMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());
7210
auto* ramFieldRef = reinterpret_cast<J9RAMFieldRef*>(j9ResolvedMethod->cp()) + cpIndex;
7211
auto* ramFieldRefNode = TR::Node::aconst(reinterpret_cast<uintptr_t>(ramFieldRef));
7212
auto* helperCallNode = TR::Node::createWithSymRef(TR::acall, 3, 3, value, address, ramFieldRefNode, comp()->getSymRefTab()->findOrCreatePutFlattenableFieldSymbolRef());
7213
handleSideEffect(helperCallNode);
7214
genTreeTop(helperCallNode);
7215
}
7216
7217
void
7218
TR_J9ByteCodeIlGenerator::storeFlattenableInstance(int32_t cpIndex)
7219
{
7220
/* An example on what the tree with flattened fields would look like
7221
*
7222
* value Point2D {
7223
* public final int x;
7224
* public final int y;
7225
* }
7226
*
7227
* public class Line2D {
7228
* public Point2D st;
7229
* public Point2D en;
7230
* }
7231
*
7232
* public void setSt(Point2D start) {
7233
* 0: aload_0
7234
* 1: aload_1
7235
* 2: putfield #7 // Field st:QPoint2D;
7236
* 5: return
7237
* }
7238
*
7239
* method="Line2D.setSt(QPoint2D;)V"
7240
* 2: JBputfield
7241
* /--- trees inserted ------------------------
7242
* n6n ( 0) NULLCHK on n4n [#32]
7243
* n5n ( 2) iloadi Point2D.x I[#355 final Point2D.x I +4]
7244
* n4n ( 2) aload <parm 1 Q>[#353 Parm]
7245
* n7n ( 0) istorei Line2D.st.x I[#354 final Line2D.st.x I +8]
7246
* n3n ( 2) aload <'this' parm LLine2D;>[#352 Parm]
7247
* n5n ( 2) ==>iloadi
7248
* n9n ( 0) NULLCHK on n4n [#32]
7249
* n8n ( 2) iloadi Point2D.y I[#357 final Point2D.y I +8]
7250
* n4n ( 2) ==>aload
7251
* n10n ( 0) istorei Line2D.st.y I[#356 final Line2D.st.y I +12]
7252
* n3n ( 2) ==>aload (X!=0 sharedMemory )
7253
* n8n ( 2) ==>iloadi
7254
* ---- stack after: empty -----------------
7255
*/
7256
TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());
7257
7258
int32_t prefixLen = 0;
7259
char * fieldNamePrefix = getTopLevelPrefixForFlattenedFields(owningMethod, cpIndex, prefixLen, comp()->trMemory()->currentStackRegion());
7260
7261
TR_OpaqueClassBlock * containingClass = owningMethod->definingClassFromCPFieldRef(comp(), cpIndex, _methodSymbol->isStatic());
7262
const TR::TypeLayout *containingClassLayout = comp()->typeLayout(containingClass);
7263
size_t fieldCount = containingClassLayout->count();
7264
7265
TR::Node * value = pop();
7266
TR::Node * address = pop();
7267
7268
int len;
7269
const char *fieldClassChars = owningMethod->fieldSignatureChars(cpIndex, len);
7270
TR_OpaqueClassBlock * fieldClass = fej9()->getClassFromSignature(fieldClassChars, len, owningMethod);
7271
7272
for (size_t idx = 0; idx < fieldCount; idx++)
7273
{
7274
const TR::TypeLayoutEntry &fieldEntry = containingClassLayout->entry(idx);
7275
if (!strncmp(fieldNamePrefix, fieldEntry._fieldname, prefixLen))
7276
{
7277
auto * fieldSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(containingClass,
7278
fieldEntry._datatype,
7279
fieldEntry._offset,
7280
fieldEntry._isVolatile,
7281
fieldEntry._isPrivate,
7282
fieldEntry._isFinal,
7283
fieldEntry._fieldname,
7284
fieldEntry._typeSignature
7285
);
7286
7287
const char * fieldNameRemovedTopLevelPrefix = fieldEntry._fieldname + prefixLen;
7288
auto * loadFieldSymRef = createLoadFieldSymRef(comp(), fieldClass, fieldNameRemovedTopLevelPrefix);
7289
7290
if (comp()->getOption(TR_TraceILGen))
7291
{
7292
traceMsg(comp(), "Store flattened field %s to %s \n - field[%d] name %s type %d offset %d\n",
7293
comp()->getDebug()->getName(loadFieldSymRef), comp()->getDebug()->getName(fieldSymRef),
7294
idx, fieldEntry._fieldname, fieldEntry._datatype.getDataType(), fieldEntry._offset);
7295
}
7296
7297
push(address);
7298
push(value);
7299
7300
loadInstance(loadFieldSymRef);
7301
storeInstance(fieldSymRef);
7302
}
7303
}
7304
}
7305
7306
void
7307
TR_J9ByteCodeIlGenerator::storeStatic(int32_t cpIndex)
7308
{
7309
if (_generateWriteBarriersForFieldWatch && comp()->compileRelocatableCode())
7310
comp()->failCompilation<J9::AOTNoSupportForAOTFailure>("NO support for AOT in field watch");
7311
7312
_staticFieldReferenceEncountered = true;
7313
TR::Node * value = pop();
7314
7315
TR::SymbolReference * symRef = symRefTab()->findOrCreateStaticSymbol(_methodSymbol, cpIndex, true);
7316
TR::StaticSymbol * symbol = symRef->getSymbol()->castToStaticSymbol();
7317
7318
TR::DataType type = symbol->getDataType();
7319
7320
TR::Node * node;
7321
7322
TR_J9VMBase *fej9 = (TR_J9VMBase *)fe();
7323
if (type == TR::Int8 && symRefTab()->isStaticTypeBool(symRef))
7324
value = TR::Node::create(TR::iand, 2, value, TR::Node::create(TR::iconst, 0, 1));
7325
7326
if ((type == TR::Address && _generateWriteBarriersForGC) || _generateWriteBarriersForFieldWatch)
7327
{
7328
void * staticClass = method()->classOfStatic(cpIndex);
7329
loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, cpIndex, staticClass, true /* cpIndexOfStatic */));
7330
7331
node = pop();
7332
node = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());
7333
push(node);
7334
7335
node = TR::Node::createWithSymRef(comp()->il.opCodeForDirectWriteBarrier(type), 2, 2, value, pop(), symRef);
7336
}
7337
else if (symbol->isVolatile() && type == TR::Int64 && !symRef->isUnresolved() && comp()->target().is32Bit() &&
7338
!comp()->cg()->getSupportsInlinedAtomicLongVolatiles() && 0)
7339
{
7340
TR::SymbolReference *volatileLongSymRef =
7341
comp()->getSymRefTab()->findOrCreateRuntimeHelper (TR_volatileWriteLong, false, false, true);
7342
TR::Node * statics = TR::Node::createWithSymRef(TR::loadaddr, 0, symRef);
7343
7344
node = TR::Node::createWithSymRef(TR::call, 2, 2, value, statics, volatileLongSymRef);
7345
}
7346
else
7347
{
7348
node = TR::Node::createStore(symRef, value);
7349
}
7350
7351
if (symbol->isPrivate() && _classInfo && comp()->getNeedsClassLookahead() && !symbol->isVolatile())
7352
{
7353
if (!_classInfo->getFieldInfo())
7354
performClassLookahead(_classInfo);
7355
7356
// findFieldInfo will update node, if node is array shadow, as it set canBeArrayShadow=true
7357
// For normal static findFieldInfo will not update node, it can't be arrayShadow store
7358
// So set canBeArrayShadow false here
7359
//
7360
TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), node, false) : NULL;
7361
//traceMsg(comp(), "Field %p info %p\n", node, fieldInfo);
7362
if (storeCanBeRemovedForUnreadField(fieldInfo, value) &&
7363
performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip store to static (that is never read) storing value %p based on class file examination\n", value))
7364
{
7365
//int32_t length;
7366
//char *sig = TR_ClassLookahead::getFieldSignature(comp(), symbol, symRef, length);
7367
//fprintf(stderr, "Skipping store for field %s in %s\n", sig, comp()->signature());
7368
//fflush(stderr);
7369
int32_t numChildren = node->getNumChildren();
7370
int32_t i = 0;
7371
while (i < numChildren)
7372
{
7373
genTreeTop(node->getChild(i));
7374
node->getChild(i)->decReferenceCount();
7375
i++;
7376
}
7377
return;
7378
}
7379
}
7380
7381
if (symRef->isUnresolved())
7382
node = genResolveCheck(node);
7383
7384
handleSideEffect(node);
7385
7386
genTreeTop(node);
7387
}
7388
7389
void
7390
TR_J9ByteCodeIlGenerator::storeDualAuto(TR::Node * storeValue, int32_t slot)
7391
{
7392
TR_ASSERT(storeValue->isDualHigh() || storeValue->isSelectHigh(), "Coerced types only happen when a dual or select operator is generated.");
7393
7394
// type may need to be coerced from TR::Address into the type of the value being stored
7395
TR::DataType type = storeValue->getDataType();
7396
7397
// generate the two stores for the storeValue and its adjunct.
7398
TR::Node* adjunctValue = storeValue->getChild(2);
7399
if (storeValue->isSelectHigh())
7400
{
7401
adjunctValue = adjunctValue->getFirstChild();
7402
}
7403
push(storeValue);
7404
storeAuto(type, slot);
7405
push(adjunctValue);
7406
storeAuto(type, slot, true);
7407
return;
7408
}
7409
7410
void
7411
TR_J9ByteCodeIlGenerator::storeAuto(TR::DataType type, int32_t slot, bool isAdjunct)
7412
{
7413
TR::Node* storeValue = pop();
7414
7415
TR::SymbolReference * symRef;
7416
7417
if (storeValue->getDataType() != type && type == TR::Address)
7418
{
7419
// this presently happens only when an operator returning Quad was coerced from
7420
// a TR::Address type into a TR_SInt64 type, and a "dual operator" was created.
7421
// store the dual symbol
7422
storeDualAuto(storeValue, slot);
7423
return;
7424
}
7425
7426
symRef = symRefTab()->findOrCreateAutoSymbol(_methodSymbol, slot, type, true, false, true, isAdjunct);
7427
if (storeValue->isDualHigh() || storeValue->isSelectHigh() || isAdjunct)
7428
symRef->setIsDual();
7429
7430
bool isStatic = _methodSymbol->isStatic();
7431
7432
//Partial Inlining: if we store into a parameter we need to create a temporary for the callback. We need to create the store for the temp in the first block.
7433
7434
int32_t numParmSlots = _methodSymbol->getNumParameterSlots();
7435
7436
if(_blocksToInline)
7437
{
7438
if (slot < numParmSlots)
7439
{
7440
//printf("Walker: (partial)storeAuto: storing into a Parameter. numParmSlots = %d isStatic = %d slot = %d\n",numParmSlots,isStatic,slot);
7441
//Need to create a temporary and use it in the callback
7442
TR::Block *firstBlock = blocks(0);
7443
7444
TR::SymbolReference *tempRef = symRefTab()->createTemporary(_methodSymbol,type);
7445
TR::Node *loadNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectLoad(type),0,symRef);
7446
TR::Node *ttNode = TR::Node::createStore(tempRef, loadNode);
7447
blocks(0)->prepend(TR::TreeTop::create(_compilation, ttNode));
7448
7449
_blocksToInline->hasGeneratedRestartTree() ? patchPartialInliningCallBack(slot,symRef,tempRef,_blocksToInline->getGeneratedRestartTree()) : addTempForPartialInliningCallBack(slot,tempRef,numParmSlots);
7450
}
7451
}
7452
// If there's a store into the receiver of a synchronized method then we
7453
// would need to go to some effort to make sure we unlock the right object
7454
// on exit, and it's just not worth it because nobody actually does this.
7455
//
7456
if (slot == 0 && _methodSymbol->isSynchronised() && !isStatic)
7457
{
7458
comp()->failCompilation<TR::ILGenFailure>("store to this in sync method");
7459
}
7460
7461
TR::Node * node = TR::Node::createStore(symRef, storeValue);
7462
7463
handleSideEffect(node);
7464
7465
genTreeTop(node);
7466
7467
// If there's a store into the receiver of a synchronized method then we have to save the receive into a
7468
// temp and use the temporary on the monitorexit
7469
//
7470
if (slot == 0 && _methodSymbol->isSynchronised() && !isStatic && !_methodSymbol->getSyncObjectTemp()) // RTSJ support
7471
{
7472
_methodSymbol->setSyncObjectTemp(symRefTab()->createTemporary(_methodSymbol, TR::Address));
7473
ListIterator<TR::Node> i(&_implicitMonitorExits);
7474
for (TR::Node * monexit = i.getFirst(); monexit; monexit = i.getNext())
7475
{
7476
TR::Node *newLoad = TR::Node::createLoad(_methodSymbol->getSyncObjectTemp());
7477
monexit->setChild(0, newLoad);
7478
}
7479
}
7480
7481
// If there's a store into the receiver of Object.<init> then save the receiver into a temporary and use
7482
// the temporary as the parameter of the call to jitCheckIfFinalize
7483
//
7484
if (slot == 0 &&
7485
_methodSymbol->getResolvedMethod()->isObjectConstructor() &&
7486
!_methodSymbol->getThisTempForObjectCtor())
7487
{
7488
TR::SymbolReference *tempSymRef = symRefTab()->createTemporary(_methodSymbol, TR::Address);
7489
///traceMsg(comp(), "created tempSymRef = %d\n", tempSymRef->getReferenceNumber());
7490
_methodSymbol->setThisTempForObjectCtor(tempSymRef);
7491
// iterate through other returns in this method to make sure all the calls to jitCheckIfFinalizeObject
7492
// use this particular symref
7493
//
7494
ListIterator<TR::Node> i(&_finalizeCallsBeforeReturns);
7495
for (TR::Node *finalize = i.getFirst(); finalize; finalize = i.getNext())
7496
{
7497
TR::Node *receiverArg = finalize->getFirstChild();
7498
if (receiverArg->getOpCode().hasSymbolReference() &&
7499
receiverArg->getSymbolReference() != tempSymRef)
7500
{
7501
receiverArg->decReferenceCount();
7502
receiverArg = TR::Node::createLoad(tempSymRef);
7503
finalize->setAndIncChild(0, receiverArg);
7504
}
7505
}
7506
}
7507
}
7508
7509
void
7510
TR_J9ByteCodeIlGenerator::storeArrayElement(TR::DataType dataType, TR::ILOpCodes nodeop, bool checks)
7511
{
7512
TR::Node * value = pop();
7513
7514
handlePendingPushSaveSideEffects(value);
7515
7516
// Value types prototype for flattened array elements does not yet support
7517
// GC policies that allow arraylets. If arraylets are required, assume
7518
// we won't have flattening, so no call to flattenable array element access
7519
// helper is needed.
7520
//
7521
if (TR::Compiler->om.areValueTypesEnabled() && !TR::Compiler->om.canGenerateArraylets() && dataType == TR::Address)
7522
{
7523
TR::Node* elementIndex = pop();
7524
TR::Node* arrayBaseAddress = pop();
7525
if (!arrayBaseAddress->isNonNull())
7526
{
7527
auto* nullchk = TR::Node::create(TR::PassThrough, 1, arrayBaseAddress);
7528
nullchk = genNullCheck(nullchk);
7529
genTreeTop(nullchk);
7530
}
7531
auto* helperSymRef = comp()->getSymRefTab()->findOrCreateStoreFlattenableArrayElementSymbolRef();
7532
TR::TreeTop *storeHelperCallTT = genTreeTop(TR::Node::createWithSymRef(TR::call, 3, 3, value, elementIndex, arrayBaseAddress, helperSymRef));
7533
7534
const char *counterName = TR::DebugCounter::debugCounterName(comp(), "vt-helper/generated/aastore/(%s)/bc=%d",
7535
comp()->signature(), currentByteCodeIndex());
7536
TR::DebugCounter::prependDebugCounter(comp(), counterName, storeHelperCallTT);
7537
7538
return;
7539
}
7540
7541
bool genSpineChecks = comp()->requiresSpineChecks();
7542
7543
_suppressSpineChecks = false;
7544
7545
calculateArrayElementAddress(dataType, true);
7546
7547
TR::Node * arrayBaseAddress = pop();
7548
bool usedArrayBaseAddress = false;
7549
TR::Node * elementAddress = pop();
7550
7551
TR::SymbolReference * symRef = symRefTab()->findOrCreateArrayShadowSymbolRef(dataType, NULL);
7552
bool generateWriteBarrier = (dataType == TR::Address);
7553
7554
TR::Node * storeNode, * resultNode;
7555
if (generateWriteBarrier)
7556
{
7557
storeNode = resultNode = TR::Node::createWithSymRef(TR::awrtbari, 3, 3, elementAddress, value, arrayBaseAddress, symRef);
7558
usedArrayBaseAddress = true;
7559
}
7560
else
7561
{
7562
storeNode = resultNode = TR::Node::createWithSymRef(nodeop, 2, 2, elementAddress, value, symRef);
7563
}
7564
7565
// For hybrid arrays, an incomplete check node may have been pushed on the stack.
7566
// It may not exist if the bound and spine check have been skipped.
7567
//
7568
TR::Node *checkNode = NULL;
7569
7570
if (genSpineChecks && !_stack->isEmpty())
7571
{
7572
if (_stack->top()->getOpCode().isSpineCheck())
7573
{
7574
checkNode = pop();
7575
usedArrayBaseAddress = true;
7576
}
7577
}
7578
7579
if (dataType == TR::Address)
7580
{
7581
bool canSkipThisArrayStoreCheck = _methodSymbol->skipArrayStoreChecks() && checks; // transformed java/lang/unsafe calls don't require checks;
7582
if (!canSkipThisArrayStoreCheck && _classInfo && value->getOpCodeValue() == TR::New)
7583
{
7584
if (!_classInfo->getFieldInfo())
7585
performClassLookahead(_classInfo);
7586
7587
TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), arrayBaseAddress, false) : NULL;
7588
TR_PersistentFieldInfo * arrayFieldInfo = fieldInfo ? fieldInfo->asPersistentArrayFieldInfo() : 0;
7589
if (arrayFieldInfo && arrayFieldInfo->isTypeInfoValid())
7590
{
7591
int32_t len;
7592
const char * s = value->getFirstChild()->getSymbolReference()->getTypeSignature(len);
7593
if (arrayFieldInfo->getNumChars() == len && !memcmp(s, arrayFieldInfo->getClassPointer(), len))
7594
{
7595
if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip array store check for value %p using array object %p which has type %s based on class file examination\n", value, arrayBaseAddress, s))
7596
canSkipThisArrayStoreCheck = true;
7597
}
7598
}
7599
}
7600
7601
if (!canSkipThisArrayStoreCheck)
7602
{
7603
symRef = symRefTab()->findOrCreateTypeCheckArrayStoreSymbolRef(_methodSymbol);
7604
TR_ASSERT(generateWriteBarrier,"TR::ArrayStoreCHK needs write barrier support.");
7605
if (generateWriteBarrier)
7606
resultNode = TR::Node::createWithRoomForThree(TR::ArrayStoreCHK, storeNode, 0, symRef);
7607
}
7608
}
7609
7610
if (!usedArrayBaseAddress)
7611
removeIfNotOnStack(arrayBaseAddress);
7612
7613
handleSideEffect(storeNode);
7614
7615
// if a compressedRefs anchor has to be
7616
// generated, dont do anything for if
7617
// the result is just the store
7618
//
7619
bool genTranslateTT = (comp()->useCompressedPointers() && (dataType == TR::Address));
7620
7621
// If the store is hung off the bound or spine check then do not anchor it
7622
// under its own treetop.
7623
//
7624
if (checkNode)
7625
{
7626
if (resultNode->getOpCodeValue() == TR::ArrayStoreCHK || (storeNode->getOpCode().isWrtBar() && !genTranslateTT))
7627
{
7628
// Anchor the array store check or the write barrier under its own treetop.
7629
//
7630
genTreeTop(resultNode);
7631
}
7632
}
7633
else
7634
{
7635
if (!((genTranslateTT) && resultNode->getOpCode().isStore()))
7636
genTreeTop(resultNode);
7637
}
7638
7639
if (genTranslateTT)
7640
{
7641
TR::Node *newValue = genCompressedRefs(storeNode, true, -1);
7642
if (newValue)
7643
{
7644
storeNode->getSecondChild()->decReferenceCount();
7645
storeNode->setAndIncChild(1, newValue);
7646
}
7647
}
7648
7649
if (checkNode)
7650
{
7651
if (checkNode->getOpCode().isBndCheck())
7652
{
7653
TR_ASSERT(checkNode->getOpCodeValue() == TR::BNDCHKwithSpineCHK, "unexpected check node");
7654
7655
// Re-arrange children now that element address and base address
7656
// are known.
7657
//
7658
checkNode->setChild(2, checkNode->getChild(0)); // arraylength
7659
checkNode->setChild(3, checkNode->getChild(1)); // index
7660
}
7661
else
7662
{
7663
TR_ASSERT(checkNode->getOpCodeValue() == TR::SpineCHK, "unexpected check node");
7664
checkNode->setChild(2, checkNode->getChild(0)); // index
7665
}
7666
7667
// The store node cannot, in general, be hung from the check node
7668
// because the resulting tree may have multiple side effects. For example,
7669
// a BNDCHKwithSpineCHK node with an ArrayStoreCHK beneath it. So,
7670
// the tree is created with the array element address instead. This
7671
// is sub-optimal in the sense that the destination address is always
7672
// evaluated into a register first, thereby bypassing any direct memory
7673
// opportunities.
7674
//
7675
7676
if (storeNode->getOpCode().isWrtBar())
7677
checkNode->setAndIncChild(0, elementAddress); // iwrtbar
7678
else
7679
{
7680
checkNode->setSpineCheckWithArrayElementChild(true);
7681
checkNode->setAndIncChild(0, storeNode); // primitive store
7682
}
7683
checkNode->setAndIncChild(1, arrayBaseAddress); // base array
7684
}
7685
7686
}
7687
7688
//----------------------------------------------
7689
// gen switch
7690
//----------------------------------------------
7691
7692
int32_t
7693
TR_J9ByteCodeIlGenerator::genLookupSwitch()
7694
{
7695
int32_t i = 1;
7696
while ((intptr_t)&_code[_bcIndex+i] & 3) ++i; // 4 byte align
7697
7698
int32_t bcIndex = _bcIndex + i;
7699
int32_t defaultTarget = nextSwitchValue(bcIndex) + _bcIndex;
7700
int32_t tableSize = nextSwitchValue(bcIndex);
7701
7702
TR::Node * first = pop();
7703
7704
if (tableSize == 0)
7705
{
7706
first->incReferenceCount();
7707
first->recursivelyDecReferenceCount();
7708
return genGoto(defaultTarget);
7709
}
7710
7711
handlePendingPushSaveSideEffects(first);
7712
7713
bool needAsyncCheck = defaultTarget <= _bcIndex ? true : false;
7714
TR::Node * caseNode = TR::Node::createCase( 0, genTarget(defaultTarget));
7715
TR::Node * node = TR::Node::create(TR::lookup, tableSize + 2, first, caseNode);
7716
7717
for (i = 0; i < tableSize; ++i)
7718
{
7719
int32_t intMatch = nextSwitchValue(bcIndex);
7720
int32_t target = nextSwitchValue(bcIndex) + _bcIndex;
7721
if (target <= _bcIndex)
7722
needAsyncCheck = true;
7723
node->setAndIncChild(i + 2, TR::Node::createCase( 0, genTarget(target), intMatch));
7724
}
7725
7726
if (needAsyncCheck)
7727
genAsyncCheck();
7728
genTreeTop(node);
7729
return findNextByteCodeToGen();
7730
}
7731
7732
int32_t
7733
TR_J9ByteCodeIlGenerator::genTableSwitch()
7734
{
7735
int32_t i = 1;
7736
while ((intptr_t)&_code[_bcIndex+i] & 3) ++i; // 4 byte align
7737
7738
int32_t bcIndex = _bcIndex + i;
7739
int32_t defaultTarget = nextSwitchValue(bcIndex) + _bcIndex;
7740
int32_t low = nextSwitchValue(bcIndex);
7741
int32_t high = nextSwitchValue(bcIndex);
7742
if (low != 0)
7743
{
7744
loadConstant(TR::iconst, low);
7745
genBinary(TR::isub);
7746
high = high - low;
7747
}
7748
7749
TR::Node * first = pop();
7750
7751
handlePendingPushSaveSideEffects(first);
7752
7753
bool needAsyncCheck = defaultTarget <= _bcIndex ? true : false;
7754
TR::Node * caseNode = TR::Node::createCase(0, genTarget(defaultTarget));
7755
TR::Node * node = TR::Node::create(TR::table, high + 3, first, caseNode);
7756
7757
TR_Array<TR::Node *> caseTargets(trMemory(), _maxByteCodeIndex + 1, true, stackAlloc);
7758
for (i = 0; i < high + 1; ++i)
7759
{
7760
int32_t targetIndex = nextSwitchValue(bcIndex) + _bcIndex;
7761
if (targetIndex <= _bcIndex)
7762
needAsyncCheck = true;
7763
if (!caseTargets[targetIndex])
7764
caseTargets[targetIndex] = TR::Node::createCase(0, genTarget(targetIndex));
7765
node->setAndIncChild(i + 2, caseTargets[targetIndex]);
7766
}
7767
7768
if (needAsyncCheck)
7769
genAsyncCheck();
7770
genTreeTop(node);
7771
return findNextByteCodeToGen();
7772
}
7773
7774
//----------------------------------------------
7775
// gen throw
7776
//----------------------------------------------
7777
7778
int32_t
7779
TR_J9ByteCodeIlGenerator::genAThrow()
7780
{
7781
TR::Node * node = TR::Node::createWithSymRef(TR::athrow, 1, 1, pop(), symRefTab()->findOrCreateAThrowSymbolRef(_methodSymbol));
7782
7783
bool canSkipNullCheck = node->getFirstChild()->isNonNull();
7784
if (!canSkipNullCheck && _classInfo)
7785
{
7786
if (!_classInfo->getFieldInfo())
7787
performClassLookahead(_classInfo);
7788
TR::Node * thisObject = node->getFirstChild();
7789
TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), thisObject, false) : NULL;
7790
if (fieldInfo && fieldInfo->isTypeInfoValid())
7791
{
7792
if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip null check at exception throw %p based on class file examination\n", thisObject))
7793
canSkipNullCheck = true;
7794
}
7795
}
7796
7797
if (comp()->getOption(TR_EnableThisLiveRangeExtension))
7798
{
7799
if (!_methodSymbol->isStatic() &&
7800
(!fej9()->isClassFinal(_methodSymbol->getResolvedMethod()->containingClass()) ||
7801
fej9()->hasFinalizer(_methodSymbol->getResolvedMethod()->containingClass())))
7802
{
7803
loadAuto(TR::Address, 0);
7804
TR::SymbolReference *tempSymRef = symRefTab()->findOrCreateThisRangeExtensionSymRef(comp()->getMethodSymbol());
7805
genTreeTop(TR::Node::createStore(tempSymRef, pop()));
7806
}
7807
}
7808
7809
if (!canSkipNullCheck)
7810
node = genNullCheck(node);
7811
7812
genTreeTop(node);
7813
7814
discardEntireStack();
7815
7816
return findNextByteCodeToGen();
7817
}
7818
7819
// genFlush: provide a store barrier for weakly consistent memory system//
7820
//
7821
void TR_J9ByteCodeIlGenerator::genFlush(int32_t nargs)
7822
{
7823
if (cg()->getEnforceStoreOrder())
7824
{
7825
TR::Node *newNode = node(_stack->topIndex() - nargs);
7826
TR::Node *flushNode = TR::Node::createAllocationFence(NULL, newNode);
7827
7828
genTreeTop(flushNode);
7829
}
7830
}
7831
7832
void TR_J9ByteCodeIlGenerator::genFullFence(TR::Node *node)
7833
{
7834
TR::Node *fullFenceNode = TR::Node::createWithSymRef(node, TR::fullFence, 0, node->getSymbolReference());
7835
fullFenceNode->setOmitSync(true);
7836
genTreeTop(fullFenceNode);
7837
}
7838
7839
7840
void TR_J9ByteCodeIlGenerator::performClassLookahead(TR_PersistentClassInfo *classInfo)
7841
{
7842
#if defined(J9VM_OPT_JITSERVER)
7843
// Do not perform class lookahead in server mode
7844
if (comp()->isOutOfProcessCompilation())
7845
return;
7846
#endif
7847
// Do not perform class lookahead when peeking (including recursive class lookahead)
7848
//
7849
if (comp()->isPeekingMethod())
7850
return;
7851
// Do not perform class lookahead if classes can be redefined
7852
if (comp()->getOption(TR_EnableHCR))
7853
return;
7854
7855
if (comp()->compileRelocatableCode() && !comp()->getOption(TR_UseSymbolValidationManager))
7856
return;
7857
7858
_classLookaheadSymRefTab = new (trStackMemory())TR::SymbolReferenceTable(method()->maxBytecodeIndex(), comp());
7859
7860
TR::SymbolReferenceTable *callerCurrentSymRefTab = comp()->getCurrentSymRefTab();
7861
comp()->setCurrentSymRefTab(_classLookaheadSymRefTab);
7862
TR_ClassLookahead classLookahead(classInfo, fej9(), comp(), _classLookaheadSymRefTab);
7863
classLookahead.perform();
7864
comp()->setCurrentSymRefTab(callerCurrentSymRefTab);
7865
}
7866
7867