Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/bcutil/ROMClassBuilder.cpp
5985 views
1
/*******************************************************************************
2
* Copyright (c) 2001, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
/*
23
* ROMClassBuilder.cpp
24
*/
25
26
#include "ut_j9bcu.h"
27
#include "bcutil_api.h"
28
#include "stackmap_api.h"
29
#include "SCQueryFunctions.h"
30
31
#include "ROMClassBuilder.hpp"
32
33
#include "AllocationStrategy.hpp"
34
#include "BufferManager.hpp"
35
#include "ClassFileOracle.hpp"
36
#include "ClassFileParser.hpp"
37
#include "ClassFileWriter.hpp"
38
#include "ConstantPoolMap.hpp"
39
#include "ComparingCursor.hpp"
40
#include "Cursor.hpp"
41
#include "J9PortAllocationStrategy.hpp"
42
#include "ROMClassCreationContext.hpp"
43
#include "ROMClassStringInternManager.hpp"
44
#include "ROMClassSegmentAllocationStrategy.hpp"
45
#include "ROMClassVerbosePhase.hpp"
46
#include "ROMClassWriter.hpp"
47
#include "SCStoreTransaction.hpp"
48
#include "SCStringTransaction.hpp"
49
#include "SRPKeyProducer.hpp"
50
#include "SuppliedBufferAllocationStrategy.hpp"
51
#include "WritingCursor.hpp"
52
#include "j9protos.h"
53
#include "ut_j9bcu.h"
54
55
static const UDATA INITIAL_CLASS_FILE_BUFFER_SIZE = 4096;
56
static const UDATA INITIAL_BUFFER_MANAGER_SIZE = 32768 * 10;
57
58
ROMClassBuilder::ROMClassBuilder(J9JavaVM *javaVM, J9PortLibrary *portLibrary, UDATA maxStringInternTableSize, U_8 * verifyExcludeAttribute, VerifyClassFunction verifyClassFunction) :
59
_javaVM(javaVM),
60
_portLibrary(portLibrary),
61
_verifyExcludeAttribute(verifyExcludeAttribute),
62
_verifyClassFunction(verifyClassFunction),
63
_classFileParserBufferSize(INITIAL_CLASS_FILE_BUFFER_SIZE),
64
_bufferManagerSize(INITIAL_BUFFER_MANAGER_SIZE),
65
_classFileBuffer(NULL),
66
_bufferManagerBuffer(NULL),
67
_anonClassNameBuffer(NULL),
68
_anonClassNameBufferSize(0),
69
_stringInternTable(javaVM, portLibrary, maxStringInternTableSize)
70
{
71
}
72
73
ROMClassBuilder::~ROMClassBuilder()
74
{
75
PORT_ACCESS_FROM_PORT(_portLibrary);
76
if (_javaVM != NULL && _javaVM->dynamicLoadBuffers != NULL) {
77
if (_javaVM->dynamicLoadBuffers->classFileError == _classFileBuffer) {
78
/* Set dynamicLoadBuffers->classFileError to NULL to prevent a
79
* crash in j9bcutil_freeAllTranslationBuffers() on JVM shutdown
80
*/
81
_javaVM->dynamicLoadBuffers->classFileError = NULL;
82
}
83
}
84
j9mem_free_memory(_classFileBuffer);
85
j9mem_free_memory(_bufferManagerBuffer);
86
j9mem_free_memory(_anonClassNameBuffer);
87
}
88
89
ROMClassBuilder *
90
ROMClassBuilder::getROMClassBuilder(J9PortLibrary *portLibrary, J9JavaVM *vm)
91
{
92
PORT_ACCESS_FROM_PORT(portLibrary);
93
ROMClassBuilder *romClassBuilder = (ROMClassBuilder *)vm->dynamicLoadBuffers->romClassBuilder;
94
if ( NULL == romClassBuilder ) {
95
romClassBuilder = (ROMClassBuilder *)j9mem_allocate_memory(sizeof(ROMClassBuilder), J9MEM_CATEGORY_CLASSES);
96
if ( NULL != romClassBuilder ) {
97
J9BytecodeVerificationData * verifyBuffers = vm->bytecodeVerificationData;
98
new(romClassBuilder) ROMClassBuilder(vm, portLibrary,
99
vm->maxInvariantLocalTableNodeCount,
100
(NULL == verifyBuffers ? NULL : verifyBuffers->excludeAttribute),
101
(NULL == verifyBuffers ? NULL : j9bcv_verifyClassStructure));
102
if (romClassBuilder->isOK()) {
103
ROMClassBuilder **romClassBuilderPtr = (ROMClassBuilder **)&(vm->dynamicLoadBuffers->romClassBuilder);
104
*romClassBuilderPtr = romClassBuilder;
105
} else {
106
romClassBuilder->~ROMClassBuilder();
107
j9mem_free_memory(romClassBuilder);
108
romClassBuilder = NULL;
109
}
110
}
111
}
112
return romClassBuilder;
113
}
114
115
extern "C" void
116
shutdownROMClassBuilder(J9JavaVM *vm)
117
{
118
PORT_ACCESS_FROM_JAVAVM(vm);
119
ROMClassBuilder *romClassBuilder = (ROMClassBuilder *)vm->dynamicLoadBuffers->romClassBuilder;
120
if ( NULL != romClassBuilder ) {
121
vm->dynamicLoadBuffers->romClassBuilder = NULL;
122
romClassBuilder->~ROMClassBuilder();
123
j9mem_free_memory(romClassBuilder);
124
}
125
}
126
127
#if defined(J9DYN_TEST)
128
extern "C" IDATA
129
j9bcutil_compareRomClass(
130
U_8 * classFileBytes,
131
U_32 classFileSize,
132
J9PortLibrary * portLib,
133
struct J9BytecodeVerificationData * verifyBuffers,
134
UDATA bctFlags,
135
UDATA bcuFlags,
136
J9ROMClass *romClass)
137
{
138
ROMClassBuilder romClassBuilder(NULL, portLib, 0, NULL == verifyBuffers ? NULL : verifyBuffers->excludeAttribute, NULL == verifyBuffers ? NULL : j9bcv_verifyClassStructure);
139
ROMClassCreationContext context(portLib, classFileBytes, classFileSize, bctFlags, bcuFlags, romClass);
140
return (IDATA)romClassBuilder.buildROMClass(&context);
141
}
142
#endif
143
144
extern "C" IDATA
145
j9bcutil_buildRomClassIntoBuffer(
146
U_8 * classFileBytes,
147
UDATA classFileSize,
148
J9PortLibrary * portLib,
149
J9BytecodeVerificationData * verifyBuffers,
150
UDATA bctFlags,
151
UDATA bcuFlags,
152
UDATA findClassFlags,
153
U_8 * romSegment,
154
UDATA romSegmentSize,
155
U_8 * lineNumberBuffer,
156
UDATA lineNumberBufferSize,
157
U_8 * varInfoBuffer,
158
UDATA varInfoBufferSize,
159
U_8 ** classFileBufferPtr
160
)
161
{
162
SuppliedBufferAllocationStrategy suppliedBufferAllocationStrategy(romSegment, romSegmentSize, lineNumberBuffer, lineNumberBufferSize, varInfoBuffer, varInfoBufferSize);
163
ROMClassBuilder romClassBuilder(NULL, portLib, 0, NULL == verifyBuffers ? NULL : verifyBuffers->excludeAttribute, NULL == verifyBuffers ? NULL : j9bcv_verifyClassStructure);
164
ROMClassCreationContext context(portLib, classFileBytes, classFileSize, bctFlags, bcuFlags, findClassFlags, &suppliedBufferAllocationStrategy);
165
IDATA result = IDATA(romClassBuilder.buildROMClass(&context));
166
if (NULL != classFileBufferPtr) {
167
*classFileBufferPtr = romClassBuilder.releaseClassFileBuffer();
168
}
169
return result;
170
}
171
172
extern "C" IDATA
173
j9bcutil_buildRomClass(J9LoadROMClassData *loadData, U_8 * intermediateData, UDATA intermediateDataLength, J9JavaVM *javaVM, UDATA bctFlags, UDATA classFileBytesReplaced, UDATA isIntermediateROMClass, J9TranslationLocalBuffer *localBuffer)
174
{
175
PORT_ACCESS_FROM_JAVAVM(javaVM);
176
UDATA bcuFlags = javaVM->dynamicLoadBuffers->flags;
177
UDATA findClassFlags = loadData->options;
178
179
ROMClassSegmentAllocationStrategy romClassSegmentAllocationStrategy(javaVM, loadData->classLoader);
180
ROMClassBuilder *romClassBuilder = ROMClassBuilder::getROMClassBuilder(PORTLIB, javaVM);
181
if (NULL == romClassBuilder) {
182
return BCT_ERR_OUT_OF_MEMORY;
183
}
184
185
ROMClassCreationContext context(
186
PORTLIB, javaVM, loadData->classData, loadData->classDataLength, bctFlags, bcuFlags, findClassFlags, &romClassSegmentAllocationStrategy,
187
loadData->className, loadData->classNameLength, loadData->hostPackageName, loadData->hostPackageLength, intermediateData, (U_32) intermediateDataLength, loadData->romClass, loadData->classBeingRedefined,
188
loadData->classLoader, (0 != classFileBytesReplaced), (TRUE == isIntermediateROMClass), localBuffer);
189
190
BuildResult result = romClassBuilder->buildROMClass(&context);
191
loadData->romClass = context.romClass();
192
context.reportStatistics(localBuffer);
193
194
return IDATA(result);
195
}
196
197
extern "C" IDATA
198
j9bcutil_transformROMClass(J9JavaVM *javaVM, J9PortLibrary *portLibrary, J9ROMClass *romClass, U_8 **classData, U_32 *size)
199
{
200
ClassFileWriter classFileWriter(javaVM, portLibrary, romClass);
201
if (classFileWriter.isOK()) {
202
*size = (U_32) classFileWriter.classFileSize();
203
*classData = classFileWriter.classFileData();
204
}
205
206
return IDATA(classFileWriter.getResult());
207
}
208
209
BuildResult
210
ROMClassBuilder::buildROMClass(ROMClassCreationContext *context)
211
{
212
BuildResult result = OK;
213
ROMClassVerbosePhase v0(context, ROMClassCreation, &result);
214
215
context->recordLoadStart();
216
217
context->recordParseClassFileStart();
218
ClassFileParser classFileParser(_portLibrary, _verifyClassFunction);
219
result = classFileParser.parseClassFile(context, &_classFileParserBufferSize, &_classFileBuffer);
220
context->recordParseClassFileEnd();
221
222
if ( OK == result ) {
223
ROMClassVerbosePhase v1(context, ROMClassTranslation, &result);
224
context->recordTranslationStart();
225
result = OutOfMemory;
226
while( OutOfMemory == result ) {
227
BufferManager bufferManager = BufferManager(_portLibrary, _bufferManagerSize, &_bufferManagerBuffer);
228
if (!bufferManager.isOK()) {
229
/*
230
* not enough native memory to complete this ROMClass load
231
*/
232
break;
233
}
234
result = prepareAndLaydown( &bufferManager, &classFileParser, context );
235
if (OutOfMemory == result) {
236
context->recordOutOfMemory(_bufferManagerSize);
237
/* Restore the original method bytecodes, as we may have transformed them. */
238
classFileParser.restoreOriginalMethodBytecodes();
239
/* set up new bufferSize for top of loop */
240
_bufferManagerSize = _bufferManagerSize * 2;
241
}
242
}
243
}
244
if ( OK == result ) {
245
context->recordTranslationEnd();
246
}
247
248
context->recordLoadEnd(result);
249
return result;
250
}
251
252
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
253
BuildResult
254
ROMClassBuilder::injectInterfaces(ClassFileOracle *classFileOracle)
255
{
256
U_32 numOfInterfaces = 0;
257
if (classFileOracle->needsIdentityInterface()) {
258
J9_DECLARE_CONSTANT_UTF8(identityInterface, IDENTITY_OBJECT_NAME);
259
_interfaceInjectionInfo.interfaces[numOfInterfaces++] = (J9UTF8 *) &identityInterface;
260
}
261
_interfaceInjectionInfo.numOfInterfaces = numOfInterfaces;
262
return OK;
263
}
264
#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */
265
BuildResult
266
ROMClassBuilder::handleAnonClassName(J9CfrClassFile *classfile, bool *isLambda, ROMClassCreationContext *context)
267
{
268
J9CfrConstantPoolInfo* constantPool = classfile->constantPool;
269
U_32 cpThisClassUTF8Slot = constantPool[classfile->thisClass].slot1;
270
U_32 originalStringLength = constantPool[cpThisClassUTF8Slot].slot1;
271
const char* originalStringBytes = (const char*)constantPool[cpThisClassUTF8Slot].bytes;
272
U_16 newUtfCPEntry = classfile->constantPoolCount - 1; /* last cpEntry is reserved for anonClassName utf */
273
U_32 i = 0;
274
BOOLEAN stringOrNASReferenceToClassName = FALSE;
275
BOOLEAN newCPEntry = TRUE;
276
BuildResult result = OK;
277
char buf[ROM_ADDRESS_LENGTH + 1] = {0};
278
U_8 *hostPackageName = context->hostPackageName();
279
UDATA hostPackageLength = context->hostPackageLength();
280
PORT_ACCESS_FROM_PORT(_portLibrary);
281
282
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
283
/* InjectedInvoker is a hidden class without the strong attribute set. It
284
* is created by MethodHandleImpl.makeInjectedInvoker on the OpenJDK side.
285
* So, OpenJ9 does not have control over the implementation of InjectedInvoker.
286
* ROM class name for InjectedInvoker is set using the hidden class name, which
287
* contains the correct host class name. The below filter is used to reduce
288
* the number of memcmps when identifying if a hidden class is named
289
* InjectedInvoker. Class name for InjectedInvoker:
290
* - in class file bytecodes: "InjectedInvoker"; and
291
* - during hidden class creation: "<HOST_CLASS>$$InjectedInvoker".
292
*/
293
if (context->isClassHidden()
294
&& !context->isHiddenClassOptStrongSet()
295
/* In JDK17, InjectedInvoker does not have the nestmate attribute. In JDK18,
296
* InjectedInvoker has the nestmate attribute due to change in implementation.
297
* This filter checks for the nestmate attribute based upon the Java version
298
* in order to identify a InjectedInvoker class.
299
*/
300
#if JAVA_SPEC_VERSION <= 17
301
&& !context->isHiddenClassOptNestmateSet()
302
#else /* JAVA_SPEC_VERSION <= 17 */
303
&& context->isHiddenClassOptNestmateSet()
304
#endif /* JAVA_SPEC_VERSION <= 17 */
305
) {
306
#define J9_INJECTED_INVOKER_CLASSNAME "$$InjectedInvoker"
307
U_8 *nameData = context->className();
308
if (NULL != nameData) {
309
UDATA nameLength = context->classNameLength();
310
IDATA startIndex = nameLength - LITERAL_STRLEN(J9_INJECTED_INVOKER_CLASSNAME);
311
if (startIndex >= 0) {
312
/* start points to a location in class name for checking if it contains
313
* "$$InjectedInvoker".
314
*/
315
U_8 *start = nameData + startIndex;
316
if (0 == memcmp(
317
start, J9_INJECTED_INVOKER_CLASSNAME,
318
LITERAL_STRLEN(J9_INJECTED_INVOKER_CLASSNAME))
319
) {
320
originalStringBytes = (char *)nameData;
321
originalStringLength = (U_32)nameLength;
322
}
323
}
324
}
325
#undef J9_INJECTED_INVOKER_CLASSNAME
326
}
327
#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
328
329
/* check if adding host package name to anonymous class is needed */
330
UDATA newHostPackageLength = 0;
331
if (memcmp(originalStringBytes, hostPackageName, hostPackageLength) != 0) {
332
newHostPackageLength = hostPackageLength + 1;
333
}
334
UDATA newAnonClassNameLength = originalStringLength + 1 + ROM_ADDRESS_LENGTH + 1 + newHostPackageLength;
335
336
/* check if the class is a lambda class */
337
if (NULL != getLastDollarSignOfLambdaClassName(originalStringBytes, originalStringLength)) {
338
*isLambda = true;
339
}
340
341
/* Find if there are any Constant_String or CFR_CONSTANT_NameAndType references to the className.
342
* If there are none we don't need to make a new cpEntry, we can overwrite the existing
343
* one since the only reference to it is the classRef
344
* Note: The check only applies to the existing cpEntries of the constant pool rather than
345
* the last cpEntry (not yet initialized) for the anonClassName.
346
*/
347
for (i = 0; i < newUtfCPEntry; i++) {
348
if ((CFR_CONSTANT_String == constantPool[i].tag)
349
|| (CFR_CONSTANT_NameAndType == constantPool[i].tag)
350
) {
351
if (cpThisClassUTF8Slot == constantPool[i].slot1) {
352
stringOrNASReferenceToClassName = TRUE;
353
}
354
}
355
}
356
357
if (!stringOrNASReferenceToClassName) {
358
/* do not need the new cpEntry so fix up classfile->constantPoolCount */
359
newCPEntry = FALSE;
360
newUtfCPEntry = cpThisClassUTF8Slot;
361
classfile->constantPoolCount -= 1;
362
}
363
364
J9CfrConstantPoolInfo *anonClassName = &classfile->constantPool[newUtfCPEntry];
365
/*
366
* alloc an array for the new name with the following format:
367
* [className]/[ROMClassAddress]\0
368
*/
369
370
if ((0 == _anonClassNameBufferSize) || (newAnonClassNameLength > _anonClassNameBufferSize)) {
371
j9mem_free_memory(_anonClassNameBuffer);
372
_anonClassNameBuffer = (U_8 *)j9mem_allocate_memory(newAnonClassNameLength, J9MEM_CATEGORY_CLASSES);
373
if (NULL == _anonClassNameBuffer) {
374
result = OutOfMemory;
375
goto done;
376
}
377
_anonClassNameBufferSize = newAnonClassNameLength;
378
}
379
constantPool[newUtfCPEntry].bytes = _anonClassNameBuffer;
380
381
if (newCPEntry) {
382
constantPool[classfile->lastUTF8CPIndex].nextCPIndex = newUtfCPEntry;
383
}
384
385
/* calculate the size of the new string and create new cpEntry*/
386
anonClassName->slot1 = (U_32)newAnonClassNameLength - 1;
387
if (newCPEntry) {
388
anonClassName->slot2 = 0;
389
anonClassName->tag = CFR_CONSTANT_Utf8;
390
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
391
/**
392
* The following line should be put inside if (classfile->majorVersion > 61) according to the SPEC. However, the current
393
* OpenJDK Valhalla implementation is not updated on this yet. There are cases that the new VT form is used in old classes
394
* from OpenJDK Valhalla JCL.
395
*/
396
anonClassName->flags1 |= CFR_CLASS_FILE_VERSION_SUPPORT_VALUE_TYPE;
397
#else /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */
398
anonClassName->flags1 = 0;
399
#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */
400
anonClassName->nextCPIndex = 0;
401
anonClassName->romAddress = 0;
402
}
403
404
constantPool[classfile->thisClass].slot1 = newUtfCPEntry;
405
406
/* copy the name into the new location and add the special character, fill the rest with zeroes */
407
if (newHostPackageLength > 0 ) {
408
memcpy(constantPool[newUtfCPEntry].bytes, hostPackageName, newHostPackageLength - 1);
409
*(U_8*)((UDATA) constantPool[newUtfCPEntry].bytes + newHostPackageLength - 1) = ANON_CLASSNAME_CHARACTER_SEPARATOR;
410
}
411
memcpy (constantPool[newUtfCPEntry].bytes + newHostPackageLength, originalStringBytes, originalStringLength);
412
*(U_8*)((UDATA) constantPool[newUtfCPEntry].bytes + newHostPackageLength + originalStringLength) = ANON_CLASSNAME_CHARACTER_SEPARATOR;
413
/*
414
* 0x<romAddress> will be appended to anon/hidden class name.
415
* Initialize the 0x<romAddress> part to 0x00000000 or 0x0000000000000000 (depending on the platforms).
416
*/
417
j9str_printf(PORTLIB, buf, ROM_ADDRESS_LENGTH + 1, ROM_ADDRESS_FORMAT, 0);
418
memcpy(constantPool[newUtfCPEntry].bytes + newHostPackageLength + originalStringLength + 1, buf, ROM_ADDRESS_LENGTH + 1);
419
420
/* search constantpool for all other identical classRefs. We have not actually
421
* tested this scenario as javac will not output more than one classRef or utfRef of the
422
* same kind.
423
*/
424
for (i = 0; i < classfile->constantPoolCount; i++) {
425
if (CFR_CONSTANT_Class == constantPool[i].tag) {
426
U_32 classNameSlot = constantPool[i].slot1;
427
if (classNameSlot != newUtfCPEntry) {
428
U_32 classNameLength = constantPool[classNameSlot].slot1;
429
if (J9UTF8_DATA_EQUALS(originalStringBytes, originalStringLength,
430
constantPool[classNameSlot].bytes, classNameLength))
431
{
432
/* if it is the same class, point to original class name slot */
433
constantPool[i].slot1 = newUtfCPEntry;
434
}
435
}
436
}
437
}
438
439
done:
440
return result;
441
}
442
443
U_8 *
444
ROMClassBuilder::releaseClassFileBuffer()
445
{
446
U_8 *result = _classFileBuffer;
447
_classFileBuffer = NULL;
448
return result;
449
}
450
451
void
452
ROMClassBuilder::getSizeInfo(ROMClassCreationContext *context, ROMClassWriter *romClassWriter, SRPOffsetTable *srpOffsetTable, bool *countDebugDataOutOfLine, SizeInformation *sizeInformation)
453
{
454
/* create a new scope to allow the ROMClassVerbosePhase to properly record the amount of time spent in
455
* preparation */
456
ROMClassVerbosePhase v(context, PrepareROMClass);
457
Cursor mainAreaCursor(RC_TAG, srpOffsetTable, context);
458
Cursor lineNumberCursor(LINE_NUMBER_TAG, srpOffsetTable, context);
459
Cursor variableInfoCursor(VARIABLE_INFO_TAG, srpOffsetTable, context);
460
Cursor utf8Cursor(UTF8_TAG, srpOffsetTable, context);
461
Cursor classDataCursor(INTERMEDIATE_TAG, srpOffsetTable, context);
462
/*
463
* The need to have separate lineNumber and variableInfo Cursors from mainAreaCursor only exists
464
* if it is possible to place debug information out of line. That is currently only done when
465
* shared classes is enabled and it is possible to share the class OR when the allocation strategy
466
* permits it.
467
*/
468
if (context->canPossiblyStoreDebugInfoOutOfLine()) {
469
/* It's possible that debug information can be stored out of line.
470
* Calculate sizes and offsets with out of line debug information.*/
471
*countDebugDataOutOfLine = true;
472
romClassWriter
473
->writeROMClass(&mainAreaCursor,
474
&lineNumberCursor,
475
&variableInfoCursor,
476
&utf8Cursor,
477
(context->isIntermediateDataAClassfile()) ? &classDataCursor : NULL,
478
0, 0, 0, 0,
479
ROMClassWriter::MARK_AND_COUNT_ONLY);
480
} else {
481
context->forceDebugDataInLine();
482
romClassWriter
483
->writeROMClass(&mainAreaCursor,
484
&mainAreaCursor,
485
&mainAreaCursor,
486
&utf8Cursor,
487
(context->isIntermediateDataAClassfile()) ? &classDataCursor : NULL,
488
0, 0, 0, 0,
489
ROMClassWriter::MARK_AND_COUNT_ONLY);
490
}
491
/* NOTE: the size of the VarHandle MethodType lookup table is already included in
492
* rcWithOutUTF8sSize; see ROMClassWriter::writeVarHandleMethodTypeLookupTable().
493
* VarHandleMethodTypeLookupTable is disabled for OpenJDK MethodHandles because
494
* it is not used.
495
*/
496
sizeInformation->rcWithOutUTF8sSize = mainAreaCursor.getCount();
497
sizeInformation->lineNumberSize = lineNumberCursor.getCount();
498
sizeInformation->variableInfoSize = variableInfoCursor.getCount();
499
sizeInformation->utf8sSize = utf8Cursor.getCount();
500
/* In case of intermediateData being stored as ROMClass, rawClassDataSize will be 0. */
501
sizeInformation->rawClassDataSize = classDataCursor.getCount();
502
}
503
504
BuildResult
505
ROMClassBuilder::prepareAndLaydown( BufferManager *bufferManager, ClassFileParser *classFileParser, ROMClassCreationContext *context )
506
{
507
bool countDebugDataOutOfLine = false;
508
BuildResult result = OK;
509
ROMClassVerbosePhase v0(context, ROMClassPrepareAndLayDown, &result);
510
PORT_ACCESS_FROM_PORT(_portLibrary);
511
/*
512
* If retransforming is enabled, intermediate class data is laid down after the first corresponding ROMClass.
513
* When a ROMClass is retransformed, the intermediateClassData of the new ROMClass points to the data laid down
514
* after the old ROMClass. Hence we only lay down intermediate class data if retransforming is enabled, but we
515
* are not currently retransforming.
516
*
517
* With -Xshareclasses:enableBCI sub-option, intermediateClassData is laid down for every ROMClass which is not
518
* modified by the BCI agent.
519
*/
520
Trc_BCU_Assert_False(context->isRetransforming() && !context->isRetransformAllowed());
521
522
bool isLambda = false;
523
if (context->isClassAnon() || context->isClassHidden()) {
524
BuildResult res = handleAnonClassName(classFileParser->getParsedClassFile(), &isLambda, context);
525
if (OK != res) {
526
return res;
527
}
528
}
529
530
ConstantPoolMap constantPoolMap(bufferManager, context);
531
ClassFileOracle classFileOracle(bufferManager, classFileParser->getParsedClassFile(), &constantPoolMap, _verifyExcludeAttribute, _classFileBuffer, context);
532
if ( !classFileOracle.isOK() ) {
533
return classFileOracle.getBuildResult();
534
}
535
536
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
537
result = injectInterfaces(&classFileOracle);
538
if (OK != result) {
539
return result;
540
}
541
SRPKeyProducer srpKeyProducer(&classFileOracle, &_interfaceInjectionInfo);
542
#else /* J9VM_OPT_VALHALLA_VALUE_TYPES */
543
SRPKeyProducer srpKeyProducer(&classFileOracle);
544
#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */
545
546
/*
547
* The ROMClassWriter must be constructed before the SRPOffsetTable because it generates additional SRP keys.
548
* There must be no SRP keys generated after the SRPOffsetTable is initialized.
549
*/
550
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
551
ROMClassWriter romClassWriter(bufferManager, &classFileOracle, &srpKeyProducer, &constantPoolMap, context, &_interfaceInjectionInfo);
552
#else /* J9VM_OPT_VALHALLA_VALUE_TYPES */
553
ROMClassWriter romClassWriter(bufferManager, &classFileOracle, &srpKeyProducer, &constantPoolMap, context);
554
#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */
555
if ( !romClassWriter.isOK() ) {
556
return romClassWriter.getBuildResult();
557
}
558
SRPOffsetTable srpOffsetTable(&srpKeyProducer, bufferManager, MAX_TAG, context);
559
if ( !srpOffsetTable.isOK() ) {
560
return srpOffsetTable.getBuildResult();
561
}
562
563
/* Pass the SRPOffsetTable to the ROMClassWriter to complete its initialization. */
564
romClassWriter.setSRPOffsetTable(&srpOffsetTable);
565
566
U_32 modifiers = classFileOracle.getAccessFlags();
567
U_32 extraModifiers = computeExtraModifiers(&classFileOracle, context);
568
U_32 optionalFlags = computeOptionalFlags(&classFileOracle, context);
569
570
/*
571
* calculate the amount of space required to write out this ROMClass without UTF8s
572
* and calculate the maximum amount of space required for UTF8s
573
* also prepare the SRP offset information
574
*/
575
SizeInformation sizeInformation;
576
getSizeInfo(context, &romClassWriter, &srpOffsetTable, &countDebugDataOutOfLine, &sizeInformation);
577
578
U_32 romSize = 0;
579
U_32 sizeToCompareForLambda = 0;
580
if (isLambda) {
581
/*
582
* romSize calculated from getSizeInfo() does not involve StringInternManager. It is only accurate for string intern disabled classes.
583
* Lambda classes in java 15 and up are strong hidden classes (defined with Option.STONG), which has the same lifecycle as its
584
* defining class loader. It is string intern enabled. So pass classFileSize instead of romSize to sizeToCompareForLambda.
585
*/
586
sizeToCompareForLambda = classFileOracle.getClassFileSize();
587
}
588
589
if ( context->shouldCompareROMClassForEquality() ) {
590
ROMClassVerbosePhase v(context, CompareHashtableROMClass);
591
592
/*
593
* Check if the supplied ROMClass is identical to the one being created. If it is, simply return OK.
594
*
595
* This is done either when there is an orphan ROM class (without a RAM class) that has been created
596
* previously, or for ROMClass comparison on behalf of dyntest.
597
*/
598
J9ROMClass *romClass = context->romClass();
599
bool romClassIsShared = (j9shr_Query_IsAddressInCache(_javaVM, romClass, romClass->romSize) ? true : false);
600
601
if (compareROMClassForEquality((U_8*)romClass, romClassIsShared, &romClassWriter,
602
&srpOffsetTable, &srpKeyProducer, &classFileOracle, modifiers, extraModifiers, optionalFlags, context, sizeToCompareForLambda, isLambda)
603
) {
604
return OK;
605
} else {
606
/* ROM classes not equal so remove from creation context */
607
context->recordROMClass(NULL);
608
/* need to recalculate size info and srp offsets, as comparing may have added bogus debug info */
609
srpOffsetTable.clear();
610
getSizeInfo(context, &romClassWriter, &srpOffsetTable, &countDebugDataOutOfLine, &sizeInformation);
611
}
612
613
#if defined(J9DYN_TEST)
614
if (NULL == context->allocationStrategy()) {
615
/*
616
* No allocationStrategy is a dyntest request to compare to the existing ROMClass supplied in romClassPtr.
617
*/
618
return GenericError;
619
}
620
#endif
621
}
622
623
UDATA maxRequiredSize = sizeInformation.rcWithOutUTF8sSize +
624
sizeInformation.lineNumberSize +
625
sizeInformation.variableInfoSize +
626
sizeInformation.utf8sSize +
627
sizeInformation.rawClassDataSize;
628
629
#if defined(J9VM_OPT_SHARED_CLASSES)
630
if (context->isROMClassShareable()) {
631
UDATA loadType = J9SHR_LOADTYPE_NORMAL;
632
if (context->isRedefining()) {
633
loadType = J9SHR_LOADTYPE_REDEFINED;
634
} else if (context->isRetransforming()) {
635
loadType = J9SHR_LOADTYPE_RETRANSFORMED;
636
} else if (context->isClassUnsafe()
637
|| context->isClassHidden()
638
|| (LOAD_LOCATION_UNKNOWN == context->loadLocation())
639
) {
640
/* For redefining/transforming, we still want loadType to be J9SHR_LOADTYPE_REDEFINED/J9SHR_LOADTYPE_RETRANSFORMED,
641
* so put these checks after the redefining/transforming checks.
642
*/
643
loadType = J9SHR_LOADTYPE_NOT_FROM_PATH;
644
}
645
646
SCStoreTransaction sharedStoreClassTransaction =
647
SCStoreTransaction(context->currentVMThread(),
648
context->classLoader(),
649
context->cpIndex(),
650
loadType,
651
classFileOracle.getUTF8Length(classFileOracle.getClassNameIndex()), classFileOracle.getUTF8Data(classFileOracle.getClassNameIndex()),
652
context->classFileBytesReplaced(),
653
context->isCreatingIntermediateROMClass());
654
655
if ( sharedStoreClassTransaction.isOK() ) {
656
/*
657
* Shared Classes is enabled, there may be an existing ROMClass
658
* that can be used in place of the one being created.
659
*
660
* Attempt to find it.
661
*
662
* Note: When comparing classes it is expected that the context contains the
663
* rom class being compared to. 'prevROMClass' is used to backup the romClass
664
* currently in the context, so the compare loop can set the romClass in the
665
* context accordingly.
666
*/
667
J9ROMClass * prevROMClass = context->romClass();
668
for (
669
J9ROMClass *existingROMClass = sharedStoreClassTransaction.nextSharedClassForCompare();
670
NULL != existingROMClass;
671
existingROMClass = sharedStoreClassTransaction.nextSharedClassForCompare()
672
) {
673
ROMClassVerbosePhase v(context, CompareSharedROMClass);
674
if (!context->isIntermediateDataAClassfile()
675
&& ((U_8 *)existingROMClass == context->intermediateClassData())
676
) {
677
/* 'existingROMClass' is same as the ROMClass corresponding to intermediate class data.
678
* Based on the assumption that an agent is actually modifying the class file
679
* instead of just returning a copy of the classbytes it receives,
680
* this comparison can be avoided.
681
*/
682
continue;
683
}
684
context->recordROMClass(existingROMClass);
685
if (compareROMClassForEquality((U_8*)existingROMClass, /* romClassIsShared = */ true, &romClassWriter,
686
&srpOffsetTable, &srpKeyProducer, &classFileOracle, modifiers, extraModifiers, optionalFlags, context, sizeToCompareForLambda, isLambda)
687
) {
688
/*
689
* Found an existing ROMClass in the shared cache that is equivalent
690
* to the ROMClass that was about to be created.
691
* Make the found ROMClass available to our caller and leave the routine.
692
*/
693
/* no need to checkDebugInfoCompression when class comes from sharedClassCache since the romClass
694
* was validated when in was placed in the sharedClassCache */
695
return OK;
696
}
697
}
698
context->recordROMClass(prevROMClass);
699
700
/*
701
* A shared ROMClass equivalent to the one being created was NOT found.
702
*
703
* Attempt to obtain space in the shared cache to laydown (i.e., share)
704
* the ROMClass being created.
705
*/
706
ROMClassVerbosePhase v(context, CreateSharedClass);
707
J9RomClassRequirements sizeRequirements;
708
709
sizeRequirements.romClassMinimalSize =
710
U_32(sizeInformation.rcWithOutUTF8sSize
711
+ sizeInformation.utf8sSize + sizeInformation.rawClassDataSize);
712
sizeRequirements.romClassMinimalSize = ROUND_UP_TO_POWEROF2(sizeRequirements.romClassMinimalSize, sizeof(U_64));
713
714
sizeRequirements.romClassSizeFullSize =
715
U_32(sizeRequirements.romClassMinimalSize
716
+ sizeInformation.lineNumberSize
717
+ sizeInformation.variableInfoSize);
718
sizeRequirements.romClassSizeFullSize = ROUND_UP_TO_POWEROF2(sizeRequirements.romClassSizeFullSize, sizeof(U_64));
719
720
sizeRequirements.lineNumberTableSize = U_32(sizeInformation.lineNumberSize);
721
sizeRequirements.localVariableTableSize = U_32(sizeInformation.variableInfoSize);
722
723
/*
724
* Check sharedStoreClassTransaction.isCacheFull() here because for performance concerns on a full cache, we don't have write mutex if the cache is full/soft full.
725
* Without this check, j9shr_classStoreTransaction_createSharedClass() does not guarantee returning on checking J9SHR_RUNTIMEFLAG_AVAILABLE_SPACE_FULL in runtimeFlags,
726
* as another thread that has write mutex may unset this flag, leading to unexpected write operation to the cache without the write mutex.
727
*/
728
if (!sharedStoreClassTransaction.isCacheFull()) {
729
if ( sharedStoreClassTransaction.allocateSharedClass(&sizeRequirements) ){
730
U_8 *romClassBuffer = (U_8*)sharedStoreClassTransaction.getRomClass();
731
/*
732
* Make note that the laydown is occurring in SharedClasses
733
*/
734
romSize = finishPrepareAndLaydown(
735
(U_8*)sharedStoreClassTransaction.getRomClass(),
736
(U_8*)sharedStoreClassTransaction.getLineNumberTable(),
737
(U_8*)sharedStoreClassTransaction.getLocalVariableTable(),
738
&sizeInformation, modifiers, extraModifiers, optionalFlags,
739
true, sharedStoreClassTransaction.hasSharedStringTableLock(),
740
&classFileOracle, &srpOffsetTable, &srpKeyProducer, &romClassWriter,
741
context, &constantPoolMap
742
);
743
744
fixReturnBytecodes(_portLibrary, (J9ROMClass *)romClassBuffer);
745
746
/*
747
* inform the shared class transaction what the final ROMSize is
748
*/
749
sharedStoreClassTransaction.updateSharedClassSize(romSize);
750
context->recordROMClass((J9ROMClass *)romClassBuffer);
751
if ((NULL != _javaVM) && (_javaVM->extendedRuntimeFlags & J9_EXTENDED_RUNTIME_CHECK_DEBUG_INFO_COMPRESSION)) {
752
checkDebugInfoCompression((J9ROMClass *)romClassBuffer, classFileOracle, &srpKeyProducer, &constantPoolMap, &srpOffsetTable);
753
}
754
return OK;
755
}
756
/* If sharedStoreClassTransaction.allocateSharedClass() returned false due to the shared cache softmx, unstored bytes is increased inside
757
* SH_CompositeCacheImpl::allocate(). No need to call sharedStoreClassTransaction.updateUnstoredBytes() here.
758
*/
759
} else {
760
sharedStoreClassTransaction.updateUnstoredBytes(sizeRequirements.romClassSizeFullSize);
761
}
762
}
763
764
/*
765
* There is insufficient space available in the shared cache
766
* to accommodate the ROMClass that is being built.
767
*
768
* Terminate the attempted Store Class Transaction.
769
*
770
* Simply exit the scope. This will invoke the destructor for
771
* sharedStoreClassTransaction and terminate the transaction.
772
*/
773
}
774
775
if (context->isIntermediateDataAClassfile()) {
776
/* For some reason we are not storing ROMClass in the cache.
777
* In case we earlier decided to store Intermediate Class File bytes along with ROMClass,
778
* need to check if we still need them. If not, modify sizeRequirements accordingly.
779
*
780
* We don't need to store Intermediate Class File if we fail to store ROMClass in the cache
781
* when running with -Xshareclasses:enableBCI and class file bytes are not modified and re-transformation is not enabled.
782
*/
783
if (context->shouldStripIntermediateClassData()) {
784
maxRequiredSize -= sizeInformation.rawClassDataSize;
785
sizeInformation.rawClassDataSize = 0;
786
}
787
788
/* In case ROMClass is not stored in cache, and we are re-transforming,
789
* try to re-use intermediateClassData from existing ROMClass.
790
*/
791
if (false == context->isReusingIntermediateClassData()) {
792
romClassWriter.reuseIntermediateClassData();
793
/* Modify size requirements if we are able to reuse intermediate class data now */
794
if (true == context->isReusingIntermediateClassData()) {
795
maxRequiredSize -= sizeInformation.rawClassDataSize;
796
sizeInformation.rawClassDataSize = 0;
797
}
798
}
799
}
800
#endif /* J9VM_OPT_SHARED_CLASSES */
801
/*
802
* Shared Classes is disabled, unavailable, or failed; use the regular allocation strategy.
803
*/
804
805
/*
806
* request the maximum amount of space to laydown this ROMClass
807
*/
808
U_8 *romClassBuffer = NULL;
809
U_8 *lineNumberBuffer = NULL;
810
U_8 *variableInfoBuffer = NULL;
811
AllocationStrategy::AllocatedBuffers allocatedBuffers;
812
813
if ( context->allocationStrategy()->allocateWithOutOfLineData( &allocatedBuffers,
814
sizeInformation.rcWithOutUTF8sSize + sizeInformation.utf8sSize + sizeInformation.rawClassDataSize,
815
sizeInformation.lineNumberSize, sizeInformation.variableInfoSize)
816
) {
817
romClassBuffer = allocatedBuffers.romClassBuffer;
818
lineNumberBuffer = allocatedBuffers.lineNumberBuffer;
819
variableInfoBuffer = allocatedBuffers.variableInfoBuffer;
820
} else {
821
/* Pad maxRequiredSize to the size to sizeof(U_64) in order to prevent memory corruption.
822
* This mirrors ROM class padding in finishPrepareAndLaydown when the final ROM class size
823
* is calculated.
824
*/
825
maxRequiredSize = ROUND_UP_TO_POWEROF2(maxRequiredSize, sizeof(U_64));
826
romClassBuffer = context->allocationStrategy()->allocate(maxRequiredSize);
827
}
828
if ( romClassBuffer == NULL ) {
829
return OutOfROM;
830
}
831
832
/*
833
* Use an if statement here and call finishPrepareAndLaydown() in both cases to allow the scope of SCStringTransaction() to survive the life of the call to
834
* finishPrepareAndLaydown(). Otherwise, the scope of SCStringTransaction() would end early and it would not be safe to us interned strings.
835
*/
836
if (J9_ARE_ANY_BITS_SET(context->findClassFlags(), J9_FINDCLASS_FLAG_ANON | J9_FINDCLASS_FLAG_HIDDEN)) {
837
U_16 classNameIndex = classFileOracle.getClassNameIndex();
838
U_8* classNameBytes = classFileOracle.getUTF8Data(classNameIndex);
839
U_16 classNameFullLength = classFileOracle.getUTF8Length(classNameIndex);
840
U_16 classNameRealLenghth = classNameFullLength - ROM_ADDRESS_LENGTH;
841
char* nameString = NULL;
842
char message[ROM_ADDRESS_LENGTH + 1];
843
if (J9_ARE_ALL_BITS_SET(context->findClassFlags(), J9_FINDCLASS_FLAG_REDEFINING)
844
|| J9_ARE_ALL_BITS_SET(context->findClassFlags(), J9_FINDCLASS_FLAG_RETRANSFORMING)
845
) {
846
/* When redefining we need to use the original class name */
847
nameString = ((char*) context->className() + classNameRealLenghth);
848
} else {
849
/* fix up the ROM className with segment Address
850
* write the name into a buffer first because j9str_printf automatically adds a NULL terminator
851
* at the end, and J9UTF8 are not NULL terminated
852
*/
853
j9str_printf(PORTLIB, message, ROM_ADDRESS_LENGTH + 1, ROM_ADDRESS_FORMAT, (UDATA)romClassBuffer);
854
nameString = (char*) message;
855
}
856
memcpy((char*) (classNameBytes + classNameRealLenghth), nameString, ROM_ADDRESS_LENGTH);
857
}
858
859
#if defined(J9VM_OPT_SHARED_CLASSES)
860
if (NULL != context->javaVM()) {
861
SCStringTransaction scStringTransaction = SCStringTransaction(context->currentVMThread());
862
romSize = finishPrepareAndLaydown(romClassBuffer, lineNumberBuffer, variableInfoBuffer, &sizeInformation, modifiers, extraModifiers, optionalFlags,
863
false, scStringTransaction.isOK(), &classFileOracle, &srpOffsetTable, &srpKeyProducer, &romClassWriter, context, &constantPoolMap);
864
} else
865
#endif
866
{
867
romSize = finishPrepareAndLaydown(romClassBuffer, lineNumberBuffer, variableInfoBuffer, &sizeInformation, modifiers, extraModifiers, optionalFlags,
868
false, false, &classFileOracle, &srpOffsetTable, &srpKeyProducer, &romClassWriter, context, &constantPoolMap);
869
}
870
871
/* This assert will detect memory corruption when a new segment
872
* for the ROM class was allocated using maxRequiredSize.
873
*/
874
Trc_BCU_Assert_True_Level1(romSize <= maxRequiredSize);
875
876
/*
877
* inform the allocator what the final ROMSize is
878
*/
879
if (J9_ARE_ALL_BITS_SET(context->findClassFlags(), J9_FINDCLASS_FLAG_ANON)) {
880
/* for anonClasses lie about the size report that it is full so no one else can use the segment */
881
romSize = (U_32) ((ROMClassSegmentAllocationStrategy*) context->allocationStrategy())->getSegmentSize();
882
}
883
context->allocationStrategy()->updateFinalROMSize(romSize);
884
885
context->recordROMClass((J9ROMClass *)romClassBuffer);
886
887
if ((NULL != _javaVM) && (_javaVM->extendedRuntimeFlags & J9_EXTENDED_RUNTIME_CHECK_DEBUG_INFO_COMPRESSION)) {
888
checkDebugInfoCompression((J9ROMClass *)romClassBuffer, classFileOracle, &srpKeyProducer, &constantPoolMap, &srpOffsetTable);
889
}
890
891
return OK;
892
}
893
894
/*
895
* Test the compression of the ROMclass'debug information when running the command
896
* Tests the line number compression and the local variable table compression
897
* -Xcheck:vm:debuginfo
898
*/
899
void
900
ROMClassBuilder::checkDebugInfoCompression(J9ROMClass *romClass, ClassFileOracle classFileOracle, SRPKeyProducer *srpKeyProducer, ConstantPoolMap *constantPoolMap, SRPOffsetTable *srpOffsetTable)
901
{
902
PORT_ACCESS_FROM_PORT(_portLibrary);
903
J9ROMMethod *currentMethod;
904
currentMethod = (J9ROMMethod*)(J9ROMCLASS_ROMMETHODS(romClass));
905
for (ClassFileOracle::MethodIterator methodIterator = classFileOracle.getMethodIterator();
906
methodIterator.isNotDone();
907
methodIterator.next()) {
908
909
/* 1) Test the line number compression */
910
UDATA lineNumbersInfoSize = methodIterator.getLineNumbersCount() * sizeof (J9CfrLineNumberTableEntry);
911
if (0 != lineNumbersInfoSize) {
912
J9CfrLineNumberTableEntry *lineNumbersInfo = (J9CfrLineNumberTableEntry*)j9mem_allocate_memory(lineNumbersInfoSize, J9MEM_CATEGORY_CLASSES);
913
if (NULL != lineNumbersInfo) {
914
classFileOracle.sortLineNumberTable(methodIterator.getIndex(), lineNumbersInfo);
915
J9LineNumber lineNumber;
916
lineNumber.lineNumber = 0;
917
lineNumber.location = 0;
918
919
J9MethodDebugInfo *methodInfo = getMethodDebugInfoFromROMMethod(currentMethod);
920
if (NULL != methodInfo) {
921
U_8 *currentLineNumber = getLineNumberTable(methodInfo);
922
U_32 lineNumbersCount = getLineNumberCount(methodInfo);
923
UDATA index;
924
Trc_BCU_Assert_CorrectLineNumbersCount(lineNumbersCount, methodIterator.getLineNumbersCount());
925
926
if (0 != lineNumbersCount) {
927
for (index = 0; index < lineNumbersCount; index++) {
928
/* From the original class */
929
U_32 pcOriginal = lineNumbersInfo[index].startPC;
930
U_32 lineNumberOriginal = lineNumbersInfo[index].lineNumber;
931
932
/* From the compressed class */
933
getNextLineNumberFromTable(&currentLineNumber, &lineNumber);
934
if ((lineNumber.lineNumber != lineNumberOriginal) || (lineNumber.location != pcOriginal)) {
935
J9UTF8* name = J9ROMCLASS_CLASSNAME(romClass);
936
PORT_ACCESS_FROM_PORT(_portLibrary);
937
j9tty_printf(PORTLIB, "Error while uncompressing the debug information for the class %.*s\n", (UDATA)J9UTF8_LENGTH(name), J9UTF8_DATA(name));
938
j9tty_printf(PORTLIB, "lineNumber.lineNumber(%d) / lineNumberOriginal(%d)\n", lineNumber.lineNumber,lineNumberOriginal);
939
j9tty_printf(PORTLIB, "lineNumber.location(%d) / pcOriginal(%d)\n", lineNumber.location, pcOriginal);
940
Trc_BCU_Assert_ShouldNeverHappen_CompressionMissmatch();
941
}
942
}
943
}
944
}
945
j9mem_free_memory(lineNumbersInfo);
946
} else {
947
Trc_BCU_Assert_Compression_OutOfMemory();
948
}
949
}
950
/* 2) Test local variable table compression */
951
U_32 localVariablesCount = methodIterator.getLocalVariablesCount();
952
if (0 != localVariablesCount) {
953
J9MethodDebugInfo *methodDebugInfo = getMethodDebugInfoFromROMMethod(currentMethod);
954
if (NULL != methodDebugInfo) {
955
J9VariableInfoWalkState state;
956
J9VariableInfoValues *values = NULL;
957
958
Trc_BCU_Assert_Equals_Level1(methodDebugInfo->varInfoCount, localVariablesCount);
959
960
values = variableInfoStartDo(methodDebugInfo, &state);
961
if (NULL != values) {
962
for (ClassFileOracle::LocalVariablesIterator localVariablesIterator = methodIterator.getLocalVariablesIterator();
963
localVariablesIterator.isNotDone();
964
localVariablesIterator.next()) {
965
if (NULL == values) {
966
/* The number of compressed variableTableInfo is less than the original number */
967
Trc_BCU_Assert_ShouldNeverHappen_CompressionMissmatch();
968
}
969
Trc_BCU_Assert_Equals_Level1(values->startVisibility, localVariablesIterator.getStartPC());
970
Trc_BCU_Assert_Equals_Level1(values->visibilityLength, localVariablesIterator.getLength());
971
Trc_BCU_Assert_Equals_Level1(values->slotNumber, localVariablesIterator.getIndex());
972
973
Trc_BCU_Assert_Equals_Level1(
974
(J9UTF8*)(values->name),
975
(J9UTF8*)(srpOffsetTable->computeWSRP(srpKeyProducer->mapCfrConstantPoolIndexToKey(localVariablesIterator.getNameIndex()), 0))
976
);
977
Trc_BCU_Assert_Equals_Level1(
978
(J9UTF8*)(values->signature),
979
(J9UTF8*)(srpOffsetTable->computeWSRP(srpKeyProducer->mapCfrConstantPoolIndexToKey(localVariablesIterator.getDescriptorIndex()), 0))
980
);
981
if (localVariablesIterator.hasGenericSignature()) {
982
Trc_BCU_Assert_Equals_Level1(
983
(J9UTF8*)(values->genericSignature),
984
(J9UTF8*)(srpOffsetTable->computeWSRP(srpKeyProducer->mapCfrConstantPoolIndexToKey(localVariablesIterator.getGenericSignatureIndex()), 0))
985
);
986
} else {
987
Trc_BCU_Assert_Equals_Level1((J9UTF8*)(values->genericSignature), NULL);
988
}
989
990
values = variableInfoNextDo(&state);
991
}
992
}
993
}
994
}
995
996
/* 3) next method */
997
currentMethod = nextROMMethod(currentMethod);
998
}
999
}
1000
1001
U_32
1002
ROMClassBuilder::finishPrepareAndLaydown(
1003
U_8 *romClassBuffer,
1004
U_8 *lineNumberBuffer,
1005
U_8 *variableInfoBuffer,
1006
SizeInformation *sizeInformation,
1007
U_32 modifiers,
1008
U_32 extraModifiers,
1009
U_32 optionalFlags,
1010
bool sharingROMClass,
1011
bool hasStringTableLock,
1012
ClassFileOracle *classFileOracle,
1013
SRPOffsetTable *srpOffsetTable,
1014
SRPKeyProducer *srpKeyProducer,
1015
ROMClassWriter *romClassWriter,
1016
ROMClassCreationContext *context,
1017
ConstantPoolMap *constantPoolMap)
1018
{
1019
U_8 * romClassBufferEndAddress = romClassBuffer + sizeInformation->rcWithOutUTF8sSize + sizeInformation->utf8sSize + sizeInformation->rawClassDataSize;
1020
ROMClassStringInternManager internManager(
1021
context,
1022
&_stringInternTable,
1023
srpOffsetTable,
1024
srpKeyProducer,
1025
romClassBuffer,
1026
romClassBufferEndAddress,
1027
sharingROMClass,
1028
hasStringTableLock);
1029
1030
/*
1031
* Identify interned strings.
1032
*/
1033
if (internManager.isInterningEnabled()) {
1034
ROMClassVerbosePhase v(context, WalkUTF8sAndMarkInterns);
1035
/**
1036
* It is not common that part of shared cache is in the SRP range of ROM class, and other part is not.
1037
* But it is possible.
1038
* For instance, on AIX platforms, shared cache is always not in SRP range of local ROM classes.
1039
* On the other hand, for linux machines, shared cache is in SRP range of local ROM class very mostly.
1040
* Therefore;
1041
* if shared cache is totally out of the SRP range of local ROM classes, then local ROM classes can not use UTF8s in shared cache.
1042
* if shared cache is totally in the SRP range of local ROM classes, then local ROM classes can use UTF8s in shared cache safely.
1043
* if part of shared cache is in the SRP range, and part of it is not,
1044
* then for each UTF8 in the local ROM class, SRP range check is required in order to use shared UTFs in the shared cache.
1045
*
1046
* Values of sharedCacheSRPRangeInfo:
1047
* 1: (SC_COMPLETELY_OUT_OF_THE_SRP_RANGE) Shared cache is out of the SRP range
1048
* 2: (SC_COMPLETELY_IN_THE_SRP_RANGE) Shared cache is in the SRP range
1049
* 3: (SC_PARTIALLY_IN_THE_SRP_RANGE) Part of shared cache is in the SRP range, part of it is not.
1050
*
1051
* Shared cache is always in the SRP range of any address in shared cache.
1052
*/
1053
SharedCacheRangeInfo sharedCacheSRPRangeInfo = SC_COMPLETELY_IN_THE_SRP_RANGE;
1054
#if defined(J9VM_OPT_SHARED_CLASSES)
1055
#if defined(J9VM_ENV_DATA64)
1056
sharedCacheSRPRangeInfo = SC_PARTIALLY_IN_THE_SRP_RANGE;
1057
if (!internManager.isSharedROMClass()) {
1058
UDATA romClassStartRangeCheck = getSharedCacheSRPRangeInfo(romClassBuffer);
1059
UDATA romClassEndRangeCheck = getSharedCacheSRPRangeInfo(romClassBufferEndAddress);
1060
1061
if (SC_COMPLETELY_OUT_OF_THE_SRP_RANGE == romClassStartRangeCheck) {
1062
if (SC_COMPLETELY_OUT_OF_THE_SRP_RANGE == romClassEndRangeCheck) {
1063
sharedCacheSRPRangeInfo = SC_COMPLETELY_OUT_OF_THE_SRP_RANGE;
1064
}
1065
} else if (SC_COMPLETELY_IN_THE_SRP_RANGE == romClassStartRangeCheck ) {
1066
if (SC_COMPLETELY_IN_THE_SRP_RANGE == romClassEndRangeCheck) {
1067
sharedCacheSRPRangeInfo = SC_COMPLETELY_IN_THE_SRP_RANGE;
1068
}
1069
}
1070
} else {
1071
/* Shared cache is always in the range of shared rom classes in it */
1072
sharedCacheSRPRangeInfo = SC_COMPLETELY_IN_THE_SRP_RANGE;
1073
}
1074
#endif
1075
#endif
1076
{
1077
ROMClassVerbosePhase v(context, VisitUTF8Block);
1078
for (ClassFileOracle::UTF8Iterator iterator = classFileOracle->getUTF8Iterator();
1079
iterator.isNotDone();
1080
iterator.next()) {
1081
U_16 cpIndex = iterator.getCPIndex();
1082
1083
if (constantPoolMap->isUTF8ConstantReferenced(cpIndex)) {
1084
internManager.visitUTF8(cpIndex, iterator.getUTF8Length(), iterator.getUTF8Data(), sharedCacheSRPRangeInfo);
1085
}
1086
}
1087
}
1088
}
1089
1090
/*
1091
* Determine what kind of recount needs to be performed, either only the UTF8 section or the entire ROMClass.
1092
*
1093
* The UTF8 section always needs to be when string interning is on.
1094
*
1095
* The entire ROMClass needs to be when calculating debug information out of line and then NOT sharing the class
1096
* in an out of line fashion.
1097
*/
1098
if ( (sizeInformation->lineNumberSize > 0) && (NULL == lineNumberBuffer) ) {
1099
/*
1100
* Debug Information has been calculated out of line
1101
* --and--
1102
* there is no room for out of line debug information
1103
*
1104
* Need to recalculate the entire ROMClass.
1105
*/
1106
Cursor mainAreaCursor(RC_TAG, srpOffsetTable, context);
1107
Cursor utf8Cursor(UTF8_TAG, srpOffsetTable, context);
1108
Cursor classDataCursor(INTERMEDIATE_TAG, srpOffsetTable, context);
1109
1110
context->forceDebugDataInLine();
1111
romClassWriter->writeROMClass(&mainAreaCursor,
1112
&mainAreaCursor,
1113
&mainAreaCursor,
1114
&utf8Cursor,
1115
(context->isIntermediateDataAClassfile()) ? &classDataCursor : NULL,
1116
0, 0, 0, 0,
1117
ROMClassWriter::MARK_AND_COUNT_ONLY);
1118
1119
/* NOTE: the size of the VarHandle MethodType lookup table is already included in
1120
* rcWithOutUTF8sSize; see ROMClassWriter::writeVarHandleMethodTypeLookupTable().
1121
* VarHandleMethodTypeLookupTable is disabled for OpenJDK MethodHandles because
1122
* it is not used.
1123
*/
1124
sizeInformation->rcWithOutUTF8sSize = mainAreaCursor.getCount();
1125
sizeInformation->lineNumberSize = 0;
1126
sizeInformation->variableInfoSize = 0;
1127
sizeInformation->utf8sSize = utf8Cursor.getCount();
1128
sizeInformation->rawClassDataSize = classDataCursor.getCount();
1129
} else if (internManager.isInterningEnabled()) {
1130
/*
1131
* With the interned strings known, do a second pass on the UTF8 block to update SRP offset information
1132
* and determine the final size for UTF8s
1133
*/
1134
ROMClassVerbosePhase v(context, PrepareUTF8sAfterInternsMarked);
1135
Cursor utf8Cursor(UTF8_TAG, srpOffsetTable, context);
1136
romClassWriter->writeUTF8s(&utf8Cursor);
1137
sizeInformation->utf8sSize = utf8Cursor.getCount();
1138
}
1139
1140
/*
1141
* Record the romSize as the final size of the ROMClass with interned strings space removed.
1142
*/
1143
U_32 romSize = U_32(sizeInformation->rcWithOutUTF8sSize + sizeInformation->utf8sSize + sizeInformation->rawClassDataSize);
1144
romSize = ROUND_UP_TO_POWEROF2(romSize, sizeof(U_64));
1145
1146
/*
1147
* update the SRP Offset Table with the base addresses for main ROMClass section (RC_TAG),
1148
* the UTF8 Block (UTF8_TAG) and the Intermediate Class Data Block (INTERMEDIATE_TAG)
1149
*/
1150
srpOffsetTable->setBaseAddressForTag(RC_TAG, romClassBuffer);
1151
srpOffsetTable->setBaseAddressForTag(UTF8_TAG, romClassBuffer+sizeInformation->rcWithOutUTF8sSize);
1152
if (context->isIntermediateDataAClassfile()) {
1153
/* Raw class data is always written inline and the calculation
1154
* of where to start writing must be done after string interning is done.
1155
*/
1156
srpOffsetTable->setBaseAddressForTag(INTERMEDIATE_TAG, romClassBuffer + sizeInformation->rcWithOutUTF8sSize + sizeInformation->utf8sSize);
1157
}
1158
srpOffsetTable->setBaseAddressForTag(LINE_NUMBER_TAG, lineNumberBuffer);
1159
srpOffsetTable->setBaseAddressForTag(VARIABLE_INFO_TAG, variableInfoBuffer);
1160
1161
/*
1162
* write ROMClass to memory
1163
*/
1164
layDownROMClass(romClassWriter, srpOffsetTable, romSize, modifiers, extraModifiers, optionalFlags, &internManager, context, sizeInformation);
1165
return romSize;
1166
}
1167
1168
/*
1169
* ROMClass->extraModifiers what does each bit represent?
1170
*
1171
* 0000 0000 0000 0000 0000 0000 0000 0000
1172
* + UNUSED
1173
* + UNUSED
1174
* + UNUSED
1175
* + UNUSED
1176
*
1177
* + UNUSED
1178
* + J9AccClassHasIdentity
1179
* + J9AccClassIsValueBased
1180
* + J9AccClassHiddenOptionNestmate
1181
*
1182
* + J9AccClassHiddenOptionStrong
1183
* + AccSealed
1184
* + AccRecord
1185
* + AccClassAnonClass
1186
*
1187
* + AccSynthetic (matches Oracle modifier position)
1188
* + AccClassUseBisectionSearch
1189
* + AccClassInnerClass
1190
* + J9AccClassHidden
1191
*
1192
* + AccClassNeedsStaticConstantInit
1193
* + AccClassIntermediateDataIsClassfile
1194
* + AccClassUnsafe
1195
* + AccClassAnnnotionRefersDoubleSlotEntry
1196
*
1197
* + AccClassBytecodesModified
1198
* + AccClassHasEmptyFinalize
1199
* + AccClassIsUnmodifiable
1200
* + AccClassHasVerifyData
1201
*
1202
* + AccClassIsContended
1203
* + AccClassHasFinalFields
1204
* + AccClassHasClinit
1205
* + AccClassHasNonStaticNonAbstractMethods
1206
*
1207
* + (shape)
1208
* + (shape)
1209
* + AccClassFinalizeNeeded
1210
* + AccClassCloneable
1211
*/
1212
1213
U_32
1214
ROMClassBuilder::computeExtraModifiers(ClassFileOracle *classFileOracle, ROMClassCreationContext *context)
1215
{
1216
ROMClassVerbosePhase v(context, ComputeExtraModifiers);
1217
1218
U_32 modifiers = 0;
1219
1220
if ( context->isClassUnsafe() ) {
1221
modifiers |= J9AccClassUnsafe;
1222
}
1223
1224
if ( context->isClassAnon() ) {
1225
modifiers |= J9AccClassAnonClass;
1226
}
1227
1228
if (context->isClassHidden()) {
1229
modifiers |= J9AccClassHidden;
1230
if (context->isHiddenClassOptNestmateSet()) {
1231
modifiers |= J9AccClassHiddenOptionNestmate;
1232
}
1233
if (context->isHiddenClassOptStrongSet()) {
1234
modifiers |= J9AccClassHiddenOptionStrong;
1235
}
1236
}
1237
1238
if ( context->classFileBytesReplaced() ) {
1239
modifiers |= J9AccClassBytecodesModified;
1240
}
1241
1242
if ( classFileOracle->hasFinalFields() ) {
1243
modifiers |= J9AccClassHasFinalFields;
1244
}
1245
1246
if ( classFileOracle->hasNonStaticNonAbstractMethods() ) {
1247
modifiers |= J9AccClassHasNonStaticNonAbstractMethods;
1248
}
1249
1250
if ( classFileOracle->isCloneable() ) {
1251
modifiers |= J9AccClassCloneable;
1252
}
1253
1254
if ( classFileOracle->isClassContended() ) {
1255
modifiers |= J9AccClassIsContended;
1256
}
1257
1258
if ( classFileOracle->isClassUnmodifiable() ) {
1259
modifiers |= J9AccClassIsUnmodifiable;
1260
}
1261
1262
if (classFileOracle->isValueBased()) {
1263
modifiers |= J9AccClassIsValueBased;
1264
}
1265
1266
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
1267
if (classFileOracle->hasIdentityInterface()
1268
|| classFileOracle->needsIdentityInterface()
1269
) {
1270
modifiers |= J9AccClassHasIdentity;
1271
}
1272
#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */
1273
1274
U_32 classNameindex = classFileOracle->getClassNameIndex();
1275
1276
#define WEAK_NAME "java/lang/ref/WeakReference"
1277
#define SOFT_NAME "java/lang/ref/SoftReference"
1278
#define PHANTOM_NAME "java/lang/ref/PhantomReference"
1279
if ( classFileOracle->isUTF8AtIndexEqualToString(classNameindex, WEAK_NAME, sizeof(WEAK_NAME)) ) {
1280
modifiers |= J9AccClassReferenceWeak;
1281
} else if( classFileOracle->isUTF8AtIndexEqualToString(classNameindex, SOFT_NAME, sizeof(SOFT_NAME)) ) {
1282
modifiers |= J9AccClassReferenceSoft;
1283
} else if( classFileOracle->isUTF8AtIndexEqualToString(classNameindex, PHANTOM_NAME, sizeof(PHANTOM_NAME)) ) {
1284
modifiers |= J9AccClassReferencePhantom;
1285
}
1286
#undef WEAK_NAME
1287
#undef SOFT_NAME
1288
#undef PHANTOM_NAME
1289
1290
if ( classFileOracle->hasFinalizeMethod() ) {
1291
if ( classFileOracle->hasEmptyFinalizeMethod() ) {
1292
/* If finalize() is empty, mark this class so it does not inherit CFR_ACC_FINALIZE_NEEDED from its superclass */
1293
modifiers |= J9AccClassHasEmptyFinalize;
1294
} else {
1295
modifiers |= J9AccClassFinalizeNeeded;
1296
}
1297
}
1298
1299
if (classFileOracle->getMajorVersion() >= (BCT_JavaMajorVersionShifted(6) >> BCT_MajorClassFileVersionMaskShift)) {
1300
/* Expect verify data for Java 6 and later versions */
1301
modifiers |= J9AccClassHasVerifyData;
1302
} else {
1303
/* Detect if there is verify data for at least one method for versions less than Java 6 */
1304
for (ClassFileOracle::MethodIterator methodIterator = classFileOracle->getMethodIterator();
1305
methodIterator.isNotDone();
1306
methodIterator.next()) {
1307
if ( methodIterator.hasStackMap() ) {
1308
modifiers |= J9AccClassHasVerifyData;
1309
break;
1310
}
1311
}
1312
}
1313
1314
if ( classFileOracle->isSynthetic() ) {
1315
/* handle the synthetic attribute. In java 1.5 synthetic may be specified in the access flags as well so do not unset bit here */
1316
// Trc_BCU_createRomClassEndian_Synthetic(romClass);
1317
modifiers |= J9AccSynthetic;
1318
}
1319
1320
if (classFileOracle->hasClinit()) {
1321
modifiers |= J9AccClassHasClinit;
1322
}
1323
1324
if (classFileOracle->annotationRefersDoubleSlotEntry()) {
1325
modifiers |= J9AccClassAnnnotionRefersDoubleSlotEntry;
1326
}
1327
1328
if (context->isIntermediateDataAClassfile()) {
1329
modifiers |= J9AccClassIntermediateDataIsClassfile;
1330
}
1331
1332
if (context->canRomMethodsBeSorted(classFileOracle->getMethodsCount())) {
1333
modifiers |= J9AccClassUseBisectionSearch;
1334
}
1335
1336
if (classFileOracle->isInnerClass()) {
1337
modifiers |= J9AccClassInnerClass;
1338
}
1339
1340
if (classFileOracle->needsStaticConstantInit()) {
1341
modifiers |= J9AccClassNeedsStaticConstantInit;
1342
}
1343
1344
if (classFileOracle->isRecord()) {
1345
modifiers |= J9AccRecord;
1346
}
1347
1348
if (classFileOracle->isSealed()) {
1349
modifiers |= J9AccSealed;
1350
}
1351
1352
return modifiers;
1353
}
1354
1355
U_32
1356
ROMClassBuilder::computeOptionalFlags(ClassFileOracle *classFileOracle, ROMClassCreationContext *context)
1357
{
1358
ROMClassVerbosePhase v(context, ComputeOptionalFlags);
1359
1360
U_32 optionalFlags = 0;
1361
1362
if (classFileOracle->hasSourceFile() && context->shouldPreserveSourceFileName()){
1363
optionalFlags |= J9_ROMCLASS_OPTINFO_SOURCE_FILE_NAME;
1364
}
1365
if (classFileOracle->hasGenericSignature()){
1366
optionalFlags |= J9_ROMCLASS_OPTINFO_GENERIC_SIGNATURE;
1367
}
1368
if (classFileOracle->hasSourceDebugExtension() && context->shouldPreserveSourceDebugExtension()){
1369
optionalFlags |= J9_ROMCLASS_OPTINFO_SOURCE_DEBUG_EXTENSION;
1370
}
1371
if (classFileOracle->hasClassAnnotations()) {
1372
optionalFlags |= J9_ROMCLASS_OPTINFO_CLASS_ANNOTATION_INFO;
1373
}
1374
if (classFileOracle->hasTypeAnnotations()) {
1375
optionalFlags |= J9_ROMCLASS_OPTINFO_TYPE_ANNOTATION_INFO;
1376
}
1377
if (classFileOracle->hasEnclosingMethod()){
1378
optionalFlags |= J9_ROMCLASS_OPTINFO_ENCLOSING_METHOD;
1379
}
1380
if (classFileOracle->hasSimpleName()){
1381
optionalFlags |= J9_ROMCLASS_OPTINFO_SIMPLE_NAME;
1382
}
1383
if (classFileOracle->hasVerifyExcludeAttribute()) {
1384
optionalFlags |= J9_ROMCLASS_OPTINFO_VERIFY_EXCLUDE;
1385
}
1386
if (classFileOracle->isRecord()) {
1387
optionalFlags |= J9_ROMCLASS_OPTINFO_RECORD_ATTRIBUTE;
1388
}
1389
if (classFileOracle->isSealed()) {
1390
optionalFlags |= J9_ROMCLASS_OPTINFO_PERMITTEDSUBCLASSES_ATTRIBUTE;
1391
}
1392
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
1393
if (_interfaceInjectionInfo.numOfInterfaces > 0) {
1394
optionalFlags |= J9_ROMCLASS_OPTINFO_INJECTED_INTERFACE_INFO;
1395
}
1396
#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */
1397
return optionalFlags;
1398
}
1399
1400
void
1401
ROMClassBuilder::layDownROMClass(
1402
ROMClassWriter *romClassWriter, SRPOffsetTable *srpOffsetTable, U_32 romSize, U_32 modifiers, U_32 extraModifiers, U_32 optionalFlags,
1403
ROMClassStringInternManager *internManager, ROMClassCreationContext *context, SizeInformation *sizeInformation)
1404
{
1405
ROMClassVerbosePhase v(context, LayDownROMClass);
1406
WritingCursor writingCursor(RC_TAG, srpOffsetTable, internManager, context);
1407
WritingCursor lineNumberCursor(LINE_NUMBER_TAG, srpOffsetTable, internManager, context);
1408
WritingCursor variableInfoCursor(VARIABLE_INFO_TAG, srpOffsetTable, internManager, context);
1409
WritingCursor utf8Cursor(UTF8_TAG, srpOffsetTable, internManager, context);
1410
WritingCursor classDataCursor(INTERMEDIATE_TAG, srpOffsetTable, internManager, context);
1411
WritingCursor *lineNumberCursorPtr = &writingCursor;
1412
WritingCursor *variableInfoCursorPtr = &writingCursor;
1413
1414
if ( sizeInformation->lineNumberSize > 0 ) {
1415
lineNumberCursorPtr = &lineNumberCursor;
1416
variableInfoCursorPtr = &variableInfoCursor;
1417
} else {
1418
context->forceDebugDataInLine();
1419
}
1420
1421
romClassWriter->writeROMClass(&writingCursor,
1422
lineNumberCursorPtr,
1423
variableInfoCursorPtr,
1424
&utf8Cursor,
1425
(context->isIntermediateDataAClassfile()) ? &classDataCursor : NULL,
1426
romSize, modifiers, extraModifiers, optionalFlags,
1427
ROMClassWriter::WRITE);
1428
}
1429
1430
bool
1431
ROMClassBuilder::compareROMClassForEquality(U_8 *romClass,bool romClassIsShared,
1432
ROMClassWriter *romClassWriter, SRPOffsetTable *srpOffsetTable, SRPKeyProducer *srpKeyProducer,
1433
ClassFileOracle *classFileOracle, U_32 modifiers, U_32 extraModifiers, U_32 optionalFlags,
1434
ROMClassCreationContext * context, U_32 sizeToCompareForLambda, bool isLambda)
1435
{
1436
bool ret = false;
1437
1438
if (isLambda) {
1439
int maxVariance = 9;
1440
if (abs((int)(sizeToCompareForLambda - ((J9ROMClass *)romClass)->classFileSize)) > maxVariance) {
1441
/*
1442
* Lambda class names are in the format of HostClassName$$Lambda$<IndexNumber>/0x0000000000000000.
1443
* When we reach this check, the host class names will be the same for both the classes because
1444
* of the hash key check earlier so the only difference in the size will be the difference
1445
* between the number of digits of the index number. The same lambda class might have a
1446
* different index number from run to run and when the number of digits of the index number
1447
* increases by 1, classFileSize also increases by 1. The indexNumber is counter for the number of lambda classes
1448
* defined so far. It is an int in the JCL side, so the it cannot vary more than max integer vs 0, which is maxVariance (9 bytes).
1449
* This check is different than the romSize check because when the number of digits of the index
1450
* number increases by 1, classFileSize also increases by 1 but romSize increases by 2.
1451
*/
1452
ret = false;
1453
} else {
1454
ComparingCursor compareCursor(_javaVM, srpOffsetTable, srpKeyProducer, classFileOracle, romClass, romClassIsShared, context, isLambda);
1455
romClassWriter->writeROMClass(&compareCursor,
1456
&compareCursor,
1457
&compareCursor,
1458
NULL,
1459
NULL,
1460
0, modifiers, extraModifiers, optionalFlags,
1461
ROMClassWriter::WRITE);
1462
1463
ret = compareCursor.isEqual();
1464
}
1465
} else {
1466
ComparingCursor compareCursor(_javaVM, srpOffsetTable, srpKeyProducer, classFileOracle, romClass, romClassIsShared, context, isLambda);
1467
romClassWriter->writeROMClass(&compareCursor,
1468
&compareCursor,
1469
&compareCursor,
1470
NULL,
1471
NULL,
1472
0, modifiers, extraModifiers, optionalFlags,
1473
ROMClassWriter::WRITE);
1474
1475
ret = compareCursor.isEqual();
1476
}
1477
J9UTF8* name = J9ROMCLASS_CLASSNAME((J9ROMClass *)romClass);
1478
Trc_BCU_compareROMClassForEquality_event(ret, J9UTF8_LENGTH(name), J9UTF8_DATA(name));
1479
return ret;
1480
}
1481
1482
#if defined(J9VM_OPT_SHARED_CLASSES)
1483
#if defined(J9VM_ENV_DATA64)
1484
/**
1485
* This function checks how much of shared cache is in SRP range of the given address.
1486
* This check is done only for 64 bit environments.
1487
* @param address Given address whose SRP range will be checked against shared cache.
1488
* @return 1 (SC_COMPLETELY_OUT_OF_THE_SRP_RANGE) if shared cache is totally out of the SRP range.
1489
* @return 2 (SC_COMPLETELY_IN_THE_SRP_RANGE) if shared cache is totally in the SRP range.
1490
* @return 3 (SC_PARTIALLY_IN_THE_SRP_RANGE) if part of the shared cache is in the SRP range, and part of it is not.
1491
*/
1492
SharedCacheRangeInfo
1493
ROMClassBuilder::getSharedCacheSRPRangeInfo(void *address)
1494
{
1495
if ((NULL != _javaVM) && (NULL != _javaVM->sharedClassConfig)) {
1496
J9SharedClassCacheDescriptor *cache = _javaVM->sharedClassConfig->cacheDescriptorList;
1497
if (NULL == cache) {
1498
/*
1499
* If there is no shared cache,
1500
* just return 1:out of range to avoid trying to find utf8 in shared cache in the future
1501
*/
1502
return SC_COMPLETELY_OUT_OF_THE_SRP_RANGE;
1503
}
1504
/*This is initial value to set the bits to zero*/
1505
SharedCacheRangeInfo sharedCacheRangeInfo = SC_NO_RANGE_INFO;
1506
1507
/**
1508
* It checks whether shared cache(s) in the SRP range completely, not at all or partially against the specific address passed to this function.
1509
* Shared cache(s) are SC_COMPLETELY_IN_THE_SRP_RANGE if and only if all the start and end addresses of shared cache(s) are in the srp range.
1510
* Shared cache(s) are SC_COMPLETELY_OUT_OF_THE_SRP_RANGE if and only if all the start and end addresses of shared cache(s) are out of the srp range.
1511
* In all other cases, shared cache(s) are SC_PARTIALLY_IN_THE_SRP_RANGE.
1512
*/
1513
while (NULL != cache) {
1514
void * cacheStart = (void *)cache->cacheStartAddress;
1515
void * cacheEnd = (void *)(((U_8 *)cacheStart) + cache->cacheSizeBytes - 1);
1516
1517
if (StringInternTable::areAddressesInSRPRange(cacheStart, address)) {
1518
/* Check whether the end of cache is in the SRP range of the address */
1519
if (StringInternTable::areAddressesInSRPRange(cacheEnd, address)) {
1520
/**
1521
* Current cache is in SRP range. Check whether previous cache(s) were in range or not if there is any.
1522
* If current cache is the first cache in the list, then sharedCacheRangeInfo is set to SC_NO_RANGE_INFO.
1523
* If all the previous caches are SC_COMPLETELY_OUT_OF_THE_SRP_RANGE, then return SC_PARTIALLY_IN_THE_SRP_RANGE since current cache is in range.
1524
* If they are all SC_COMPLETELY_IN_THE_SRP_RANGE, then set sharedCacheRangeInfo to SC_COMPLETELY_IN_THE_SRP_RANGE
1525
*
1526
*/
1527
if (sharedCacheRangeInfo == SC_COMPLETELY_OUT_OF_THE_SRP_RANGE) {
1528
return SC_PARTIALLY_IN_THE_SRP_RANGE;
1529
} else {
1530
sharedCacheRangeInfo = SC_COMPLETELY_IN_THE_SRP_RANGE;
1531
}
1532
} else {
1533
return SC_PARTIALLY_IN_THE_SRP_RANGE;
1534
}
1535
} else {
1536
if (StringInternTable::areAddressesInSRPRange(cacheEnd, address)) {
1537
return SC_PARTIALLY_IN_THE_SRP_RANGE;
1538
} else {
1539
/**
1540
* Current cache is out of SRP range. Check whether previous cache(s) were in range or not if there is any.
1541
* If current cache is the first cache in the list, then sharedCacheRangeInfo is set to SC_NO_RANGE_INFO.
1542
* If all the previous caches are SC_PARTIALLY_IN_THE_SRP_RANGE, then return SC_PARTIALLY_IN_THE_SRP_RANGE since current cache is out of range.
1543
* If they are all SC_COMPLETELY_OUT_OF_THE_SRP_RANGE, then set sharedCacheRangeInfo to SC_COMPLETELY_OUT_OF_THE_SRP_RANGE
1544
*
1545
*/
1546
if (sharedCacheRangeInfo == SC_PARTIALLY_IN_THE_SRP_RANGE) {
1547
return SC_PARTIALLY_IN_THE_SRP_RANGE;
1548
} else {
1549
sharedCacheRangeInfo = SC_COMPLETELY_OUT_OF_THE_SRP_RANGE;
1550
}
1551
}
1552
}
1553
1554
if (cache->next == _javaVM->sharedClassConfig->cacheDescriptorList) {
1555
/* Break out of the circular descriptor list. */
1556
break;
1557
}
1558
cache = cache->next;
1559
}
1560
1561
return sharedCacheRangeInfo;
1562
}
1563
/* Either _javaVM or _JavaVM->sharedClassConfig is null.
1564
* Try doing range check for each UTF8.
1565
* In normal circumstances, we should never be here.
1566
*/
1567
return SC_PARTIALLY_IN_THE_SRP_RANGE;
1568
}
1569
#endif
1570
#endif
1571
1572