Path: blob/master/runtime/bcutil/ROMClassBuilder.cpp
5985 views
/*******************************************************************************1* Copyright (c) 2001, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* 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-exception20*******************************************************************************/21/*22* ROMClassBuilder.cpp23*/2425#include "ut_j9bcu.h"26#include "bcutil_api.h"27#include "stackmap_api.h"28#include "SCQueryFunctions.h"2930#include "ROMClassBuilder.hpp"3132#include "AllocationStrategy.hpp"33#include "BufferManager.hpp"34#include "ClassFileOracle.hpp"35#include "ClassFileParser.hpp"36#include "ClassFileWriter.hpp"37#include "ConstantPoolMap.hpp"38#include "ComparingCursor.hpp"39#include "Cursor.hpp"40#include "J9PortAllocationStrategy.hpp"41#include "ROMClassCreationContext.hpp"42#include "ROMClassStringInternManager.hpp"43#include "ROMClassSegmentAllocationStrategy.hpp"44#include "ROMClassVerbosePhase.hpp"45#include "ROMClassWriter.hpp"46#include "SCStoreTransaction.hpp"47#include "SCStringTransaction.hpp"48#include "SRPKeyProducer.hpp"49#include "SuppliedBufferAllocationStrategy.hpp"50#include "WritingCursor.hpp"51#include "j9protos.h"52#include "ut_j9bcu.h"5354static const UDATA INITIAL_CLASS_FILE_BUFFER_SIZE = 4096;55static const UDATA INITIAL_BUFFER_MANAGER_SIZE = 32768 * 10;5657ROMClassBuilder::ROMClassBuilder(J9JavaVM *javaVM, J9PortLibrary *portLibrary, UDATA maxStringInternTableSize, U_8 * verifyExcludeAttribute, VerifyClassFunction verifyClassFunction) :58_javaVM(javaVM),59_portLibrary(portLibrary),60_verifyExcludeAttribute(verifyExcludeAttribute),61_verifyClassFunction(verifyClassFunction),62_classFileParserBufferSize(INITIAL_CLASS_FILE_BUFFER_SIZE),63_bufferManagerSize(INITIAL_BUFFER_MANAGER_SIZE),64_classFileBuffer(NULL),65_bufferManagerBuffer(NULL),66_anonClassNameBuffer(NULL),67_anonClassNameBufferSize(0),68_stringInternTable(javaVM, portLibrary, maxStringInternTableSize)69{70}7172ROMClassBuilder::~ROMClassBuilder()73{74PORT_ACCESS_FROM_PORT(_portLibrary);75if (_javaVM != NULL && _javaVM->dynamicLoadBuffers != NULL) {76if (_javaVM->dynamicLoadBuffers->classFileError == _classFileBuffer) {77/* Set dynamicLoadBuffers->classFileError to NULL to prevent a78* crash in j9bcutil_freeAllTranslationBuffers() on JVM shutdown79*/80_javaVM->dynamicLoadBuffers->classFileError = NULL;81}82}83j9mem_free_memory(_classFileBuffer);84j9mem_free_memory(_bufferManagerBuffer);85j9mem_free_memory(_anonClassNameBuffer);86}8788ROMClassBuilder *89ROMClassBuilder::getROMClassBuilder(J9PortLibrary *portLibrary, J9JavaVM *vm)90{91PORT_ACCESS_FROM_PORT(portLibrary);92ROMClassBuilder *romClassBuilder = (ROMClassBuilder *)vm->dynamicLoadBuffers->romClassBuilder;93if ( NULL == romClassBuilder ) {94romClassBuilder = (ROMClassBuilder *)j9mem_allocate_memory(sizeof(ROMClassBuilder), J9MEM_CATEGORY_CLASSES);95if ( NULL != romClassBuilder ) {96J9BytecodeVerificationData * verifyBuffers = vm->bytecodeVerificationData;97new(romClassBuilder) ROMClassBuilder(vm, portLibrary,98vm->maxInvariantLocalTableNodeCount,99(NULL == verifyBuffers ? NULL : verifyBuffers->excludeAttribute),100(NULL == verifyBuffers ? NULL : j9bcv_verifyClassStructure));101if (romClassBuilder->isOK()) {102ROMClassBuilder **romClassBuilderPtr = (ROMClassBuilder **)&(vm->dynamicLoadBuffers->romClassBuilder);103*romClassBuilderPtr = romClassBuilder;104} else {105romClassBuilder->~ROMClassBuilder();106j9mem_free_memory(romClassBuilder);107romClassBuilder = NULL;108}109}110}111return romClassBuilder;112}113114extern "C" void115shutdownROMClassBuilder(J9JavaVM *vm)116{117PORT_ACCESS_FROM_JAVAVM(vm);118ROMClassBuilder *romClassBuilder = (ROMClassBuilder *)vm->dynamicLoadBuffers->romClassBuilder;119if ( NULL != romClassBuilder ) {120vm->dynamicLoadBuffers->romClassBuilder = NULL;121romClassBuilder->~ROMClassBuilder();122j9mem_free_memory(romClassBuilder);123}124}125126#if defined(J9DYN_TEST)127extern "C" IDATA128j9bcutil_compareRomClass(129U_8 * classFileBytes,130U_32 classFileSize,131J9PortLibrary * portLib,132struct J9BytecodeVerificationData * verifyBuffers,133UDATA bctFlags,134UDATA bcuFlags,135J9ROMClass *romClass)136{137ROMClassBuilder romClassBuilder(NULL, portLib, 0, NULL == verifyBuffers ? NULL : verifyBuffers->excludeAttribute, NULL == verifyBuffers ? NULL : j9bcv_verifyClassStructure);138ROMClassCreationContext context(portLib, classFileBytes, classFileSize, bctFlags, bcuFlags, romClass);139return (IDATA)romClassBuilder.buildROMClass(&context);140}141#endif142143extern "C" IDATA144j9bcutil_buildRomClassIntoBuffer(145U_8 * classFileBytes,146UDATA classFileSize,147J9PortLibrary * portLib,148J9BytecodeVerificationData * verifyBuffers,149UDATA bctFlags,150UDATA bcuFlags,151UDATA findClassFlags,152U_8 * romSegment,153UDATA romSegmentSize,154U_8 * lineNumberBuffer,155UDATA lineNumberBufferSize,156U_8 * varInfoBuffer,157UDATA varInfoBufferSize,158U_8 ** classFileBufferPtr159)160{161SuppliedBufferAllocationStrategy suppliedBufferAllocationStrategy(romSegment, romSegmentSize, lineNumberBuffer, lineNumberBufferSize, varInfoBuffer, varInfoBufferSize);162ROMClassBuilder romClassBuilder(NULL, portLib, 0, NULL == verifyBuffers ? NULL : verifyBuffers->excludeAttribute, NULL == verifyBuffers ? NULL : j9bcv_verifyClassStructure);163ROMClassCreationContext context(portLib, classFileBytes, classFileSize, bctFlags, bcuFlags, findClassFlags, &suppliedBufferAllocationStrategy);164IDATA result = IDATA(romClassBuilder.buildROMClass(&context));165if (NULL != classFileBufferPtr) {166*classFileBufferPtr = romClassBuilder.releaseClassFileBuffer();167}168return result;169}170171extern "C" IDATA172j9bcutil_buildRomClass(J9LoadROMClassData *loadData, U_8 * intermediateData, UDATA intermediateDataLength, J9JavaVM *javaVM, UDATA bctFlags, UDATA classFileBytesReplaced, UDATA isIntermediateROMClass, J9TranslationLocalBuffer *localBuffer)173{174PORT_ACCESS_FROM_JAVAVM(javaVM);175UDATA bcuFlags = javaVM->dynamicLoadBuffers->flags;176UDATA findClassFlags = loadData->options;177178ROMClassSegmentAllocationStrategy romClassSegmentAllocationStrategy(javaVM, loadData->classLoader);179ROMClassBuilder *romClassBuilder = ROMClassBuilder::getROMClassBuilder(PORTLIB, javaVM);180if (NULL == romClassBuilder) {181return BCT_ERR_OUT_OF_MEMORY;182}183184ROMClassCreationContext context(185PORTLIB, javaVM, loadData->classData, loadData->classDataLength, bctFlags, bcuFlags, findClassFlags, &romClassSegmentAllocationStrategy,186loadData->className, loadData->classNameLength, loadData->hostPackageName, loadData->hostPackageLength, intermediateData, (U_32) intermediateDataLength, loadData->romClass, loadData->classBeingRedefined,187loadData->classLoader, (0 != classFileBytesReplaced), (TRUE == isIntermediateROMClass), localBuffer);188189BuildResult result = romClassBuilder->buildROMClass(&context);190loadData->romClass = context.romClass();191context.reportStatistics(localBuffer);192193return IDATA(result);194}195196extern "C" IDATA197j9bcutil_transformROMClass(J9JavaVM *javaVM, J9PortLibrary *portLibrary, J9ROMClass *romClass, U_8 **classData, U_32 *size)198{199ClassFileWriter classFileWriter(javaVM, portLibrary, romClass);200if (classFileWriter.isOK()) {201*size = (U_32) classFileWriter.classFileSize();202*classData = classFileWriter.classFileData();203}204205return IDATA(classFileWriter.getResult());206}207208BuildResult209ROMClassBuilder::buildROMClass(ROMClassCreationContext *context)210{211BuildResult result = OK;212ROMClassVerbosePhase v0(context, ROMClassCreation, &result);213214context->recordLoadStart();215216context->recordParseClassFileStart();217ClassFileParser classFileParser(_portLibrary, _verifyClassFunction);218result = classFileParser.parseClassFile(context, &_classFileParserBufferSize, &_classFileBuffer);219context->recordParseClassFileEnd();220221if ( OK == result ) {222ROMClassVerbosePhase v1(context, ROMClassTranslation, &result);223context->recordTranslationStart();224result = OutOfMemory;225while( OutOfMemory == result ) {226BufferManager bufferManager = BufferManager(_portLibrary, _bufferManagerSize, &_bufferManagerBuffer);227if (!bufferManager.isOK()) {228/*229* not enough native memory to complete this ROMClass load230*/231break;232}233result = prepareAndLaydown( &bufferManager, &classFileParser, context );234if (OutOfMemory == result) {235context->recordOutOfMemory(_bufferManagerSize);236/* Restore the original method bytecodes, as we may have transformed them. */237classFileParser.restoreOriginalMethodBytecodes();238/* set up new bufferSize for top of loop */239_bufferManagerSize = _bufferManagerSize * 2;240}241}242}243if ( OK == result ) {244context->recordTranslationEnd();245}246247context->recordLoadEnd(result);248return result;249}250251#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)252BuildResult253ROMClassBuilder::injectInterfaces(ClassFileOracle *classFileOracle)254{255U_32 numOfInterfaces = 0;256if (classFileOracle->needsIdentityInterface()) {257J9_DECLARE_CONSTANT_UTF8(identityInterface, IDENTITY_OBJECT_NAME);258_interfaceInjectionInfo.interfaces[numOfInterfaces++] = (J9UTF8 *) &identityInterface;259}260_interfaceInjectionInfo.numOfInterfaces = numOfInterfaces;261return OK;262}263#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */264BuildResult265ROMClassBuilder::handleAnonClassName(J9CfrClassFile *classfile, bool *isLambda, ROMClassCreationContext *context)266{267J9CfrConstantPoolInfo* constantPool = classfile->constantPool;268U_32 cpThisClassUTF8Slot = constantPool[classfile->thisClass].slot1;269U_32 originalStringLength = constantPool[cpThisClassUTF8Slot].slot1;270const char* originalStringBytes = (const char*)constantPool[cpThisClassUTF8Slot].bytes;271U_16 newUtfCPEntry = classfile->constantPoolCount - 1; /* last cpEntry is reserved for anonClassName utf */272U_32 i = 0;273BOOLEAN stringOrNASReferenceToClassName = FALSE;274BOOLEAN newCPEntry = TRUE;275BuildResult result = OK;276char buf[ROM_ADDRESS_LENGTH + 1] = {0};277U_8 *hostPackageName = context->hostPackageName();278UDATA hostPackageLength = context->hostPackageLength();279PORT_ACCESS_FROM_PORT(_portLibrary);280281#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)282/* InjectedInvoker is a hidden class without the strong attribute set. It283* is created by MethodHandleImpl.makeInjectedInvoker on the OpenJDK side.284* So, OpenJ9 does not have control over the implementation of InjectedInvoker.285* ROM class name for InjectedInvoker is set using the hidden class name, which286* contains the correct host class name. The below filter is used to reduce287* the number of memcmps when identifying if a hidden class is named288* InjectedInvoker. Class name for InjectedInvoker:289* - in class file bytecodes: "InjectedInvoker"; and290* - during hidden class creation: "<HOST_CLASS>$$InjectedInvoker".291*/292if (context->isClassHidden()293&& !context->isHiddenClassOptStrongSet()294/* In JDK17, InjectedInvoker does not have the nestmate attribute. In JDK18,295* InjectedInvoker has the nestmate attribute due to change in implementation.296* This filter checks for the nestmate attribute based upon the Java version297* in order to identify a InjectedInvoker class.298*/299#if JAVA_SPEC_VERSION <= 17300&& !context->isHiddenClassOptNestmateSet()301#else /* JAVA_SPEC_VERSION <= 17 */302&& context->isHiddenClassOptNestmateSet()303#endif /* JAVA_SPEC_VERSION <= 17 */304) {305#define J9_INJECTED_INVOKER_CLASSNAME "$$InjectedInvoker"306U_8 *nameData = context->className();307if (NULL != nameData) {308UDATA nameLength = context->classNameLength();309IDATA startIndex = nameLength - LITERAL_STRLEN(J9_INJECTED_INVOKER_CLASSNAME);310if (startIndex >= 0) {311/* start points to a location in class name for checking if it contains312* "$$InjectedInvoker".313*/314U_8 *start = nameData + startIndex;315if (0 == memcmp(316start, J9_INJECTED_INVOKER_CLASSNAME,317LITERAL_STRLEN(J9_INJECTED_INVOKER_CLASSNAME))318) {319originalStringBytes = (char *)nameData;320originalStringLength = (U_32)nameLength;321}322}323}324#undef J9_INJECTED_INVOKER_CLASSNAME325}326#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */327328/* check if adding host package name to anonymous class is needed */329UDATA newHostPackageLength = 0;330if (memcmp(originalStringBytes, hostPackageName, hostPackageLength) != 0) {331newHostPackageLength = hostPackageLength + 1;332}333UDATA newAnonClassNameLength = originalStringLength + 1 + ROM_ADDRESS_LENGTH + 1 + newHostPackageLength;334335/* check if the class is a lambda class */336if (NULL != getLastDollarSignOfLambdaClassName(originalStringBytes, originalStringLength)) {337*isLambda = true;338}339340/* Find if there are any Constant_String or CFR_CONSTANT_NameAndType references to the className.341* If there are none we don't need to make a new cpEntry, we can overwrite the existing342* one since the only reference to it is the classRef343* Note: The check only applies to the existing cpEntries of the constant pool rather than344* the last cpEntry (not yet initialized) for the anonClassName.345*/346for (i = 0; i < newUtfCPEntry; i++) {347if ((CFR_CONSTANT_String == constantPool[i].tag)348|| (CFR_CONSTANT_NameAndType == constantPool[i].tag)349) {350if (cpThisClassUTF8Slot == constantPool[i].slot1) {351stringOrNASReferenceToClassName = TRUE;352}353}354}355356if (!stringOrNASReferenceToClassName) {357/* do not need the new cpEntry so fix up classfile->constantPoolCount */358newCPEntry = FALSE;359newUtfCPEntry = cpThisClassUTF8Slot;360classfile->constantPoolCount -= 1;361}362363J9CfrConstantPoolInfo *anonClassName = &classfile->constantPool[newUtfCPEntry];364/*365* alloc an array for the new name with the following format:366* [className]/[ROMClassAddress]\0367*/368369if ((0 == _anonClassNameBufferSize) || (newAnonClassNameLength > _anonClassNameBufferSize)) {370j9mem_free_memory(_anonClassNameBuffer);371_anonClassNameBuffer = (U_8 *)j9mem_allocate_memory(newAnonClassNameLength, J9MEM_CATEGORY_CLASSES);372if (NULL == _anonClassNameBuffer) {373result = OutOfMemory;374goto done;375}376_anonClassNameBufferSize = newAnonClassNameLength;377}378constantPool[newUtfCPEntry].bytes = _anonClassNameBuffer;379380if (newCPEntry) {381constantPool[classfile->lastUTF8CPIndex].nextCPIndex = newUtfCPEntry;382}383384/* calculate the size of the new string and create new cpEntry*/385anonClassName->slot1 = (U_32)newAnonClassNameLength - 1;386if (newCPEntry) {387anonClassName->slot2 = 0;388anonClassName->tag = CFR_CONSTANT_Utf8;389#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)390/**391* The following line should be put inside if (classfile->majorVersion > 61) according to the SPEC. However, the current392* OpenJDK Valhalla implementation is not updated on this yet. There are cases that the new VT form is used in old classes393* from OpenJDK Valhalla JCL.394*/395anonClassName->flags1 |= CFR_CLASS_FILE_VERSION_SUPPORT_VALUE_TYPE;396#else /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */397anonClassName->flags1 = 0;398#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */399anonClassName->nextCPIndex = 0;400anonClassName->romAddress = 0;401}402403constantPool[classfile->thisClass].slot1 = newUtfCPEntry;404405/* copy the name into the new location and add the special character, fill the rest with zeroes */406if (newHostPackageLength > 0 ) {407memcpy(constantPool[newUtfCPEntry].bytes, hostPackageName, newHostPackageLength - 1);408*(U_8*)((UDATA) constantPool[newUtfCPEntry].bytes + newHostPackageLength - 1) = ANON_CLASSNAME_CHARACTER_SEPARATOR;409}410memcpy (constantPool[newUtfCPEntry].bytes + newHostPackageLength, originalStringBytes, originalStringLength);411*(U_8*)((UDATA) constantPool[newUtfCPEntry].bytes + newHostPackageLength + originalStringLength) = ANON_CLASSNAME_CHARACTER_SEPARATOR;412/*413* 0x<romAddress> will be appended to anon/hidden class name.414* Initialize the 0x<romAddress> part to 0x00000000 or 0x0000000000000000 (depending on the platforms).415*/416j9str_printf(PORTLIB, buf, ROM_ADDRESS_LENGTH + 1, ROM_ADDRESS_FORMAT, 0);417memcpy(constantPool[newUtfCPEntry].bytes + newHostPackageLength + originalStringLength + 1, buf, ROM_ADDRESS_LENGTH + 1);418419/* search constantpool for all other identical classRefs. We have not actually420* tested this scenario as javac will not output more than one classRef or utfRef of the421* same kind.422*/423for (i = 0; i < classfile->constantPoolCount; i++) {424if (CFR_CONSTANT_Class == constantPool[i].tag) {425U_32 classNameSlot = constantPool[i].slot1;426if (classNameSlot != newUtfCPEntry) {427U_32 classNameLength = constantPool[classNameSlot].slot1;428if (J9UTF8_DATA_EQUALS(originalStringBytes, originalStringLength,429constantPool[classNameSlot].bytes, classNameLength))430{431/* if it is the same class, point to original class name slot */432constantPool[i].slot1 = newUtfCPEntry;433}434}435}436}437438done:439return result;440}441442U_8 *443ROMClassBuilder::releaseClassFileBuffer()444{445U_8 *result = _classFileBuffer;446_classFileBuffer = NULL;447return result;448}449450void451ROMClassBuilder::getSizeInfo(ROMClassCreationContext *context, ROMClassWriter *romClassWriter, SRPOffsetTable *srpOffsetTable, bool *countDebugDataOutOfLine, SizeInformation *sizeInformation)452{453/* create a new scope to allow the ROMClassVerbosePhase to properly record the amount of time spent in454* preparation */455ROMClassVerbosePhase v(context, PrepareROMClass);456Cursor mainAreaCursor(RC_TAG, srpOffsetTable, context);457Cursor lineNumberCursor(LINE_NUMBER_TAG, srpOffsetTable, context);458Cursor variableInfoCursor(VARIABLE_INFO_TAG, srpOffsetTable, context);459Cursor utf8Cursor(UTF8_TAG, srpOffsetTable, context);460Cursor classDataCursor(INTERMEDIATE_TAG, srpOffsetTable, context);461/*462* The need to have separate lineNumber and variableInfo Cursors from mainAreaCursor only exists463* if it is possible to place debug information out of line. That is currently only done when464* shared classes is enabled and it is possible to share the class OR when the allocation strategy465* permits it.466*/467if (context->canPossiblyStoreDebugInfoOutOfLine()) {468/* It's possible that debug information can be stored out of line.469* Calculate sizes and offsets with out of line debug information.*/470*countDebugDataOutOfLine = true;471romClassWriter472->writeROMClass(&mainAreaCursor,473&lineNumberCursor,474&variableInfoCursor,475&utf8Cursor,476(context->isIntermediateDataAClassfile()) ? &classDataCursor : NULL,4770, 0, 0, 0,478ROMClassWriter::MARK_AND_COUNT_ONLY);479} else {480context->forceDebugDataInLine();481romClassWriter482->writeROMClass(&mainAreaCursor,483&mainAreaCursor,484&mainAreaCursor,485&utf8Cursor,486(context->isIntermediateDataAClassfile()) ? &classDataCursor : NULL,4870, 0, 0, 0,488ROMClassWriter::MARK_AND_COUNT_ONLY);489}490/* NOTE: the size of the VarHandle MethodType lookup table is already included in491* rcWithOutUTF8sSize; see ROMClassWriter::writeVarHandleMethodTypeLookupTable().492* VarHandleMethodTypeLookupTable is disabled for OpenJDK MethodHandles because493* it is not used.494*/495sizeInformation->rcWithOutUTF8sSize = mainAreaCursor.getCount();496sizeInformation->lineNumberSize = lineNumberCursor.getCount();497sizeInformation->variableInfoSize = variableInfoCursor.getCount();498sizeInformation->utf8sSize = utf8Cursor.getCount();499/* In case of intermediateData being stored as ROMClass, rawClassDataSize will be 0. */500sizeInformation->rawClassDataSize = classDataCursor.getCount();501}502503BuildResult504ROMClassBuilder::prepareAndLaydown( BufferManager *bufferManager, ClassFileParser *classFileParser, ROMClassCreationContext *context )505{506bool countDebugDataOutOfLine = false;507BuildResult result = OK;508ROMClassVerbosePhase v0(context, ROMClassPrepareAndLayDown, &result);509PORT_ACCESS_FROM_PORT(_portLibrary);510/*511* If retransforming is enabled, intermediate class data is laid down after the first corresponding ROMClass.512* When a ROMClass is retransformed, the intermediateClassData of the new ROMClass points to the data laid down513* after the old ROMClass. Hence we only lay down intermediate class data if retransforming is enabled, but we514* are not currently retransforming.515*516* With -Xshareclasses:enableBCI sub-option, intermediateClassData is laid down for every ROMClass which is not517* modified by the BCI agent.518*/519Trc_BCU_Assert_False(context->isRetransforming() && !context->isRetransformAllowed());520521bool isLambda = false;522if (context->isClassAnon() || context->isClassHidden()) {523BuildResult res = handleAnonClassName(classFileParser->getParsedClassFile(), &isLambda, context);524if (OK != res) {525return res;526}527}528529ConstantPoolMap constantPoolMap(bufferManager, context);530ClassFileOracle classFileOracle(bufferManager, classFileParser->getParsedClassFile(), &constantPoolMap, _verifyExcludeAttribute, _classFileBuffer, context);531if ( !classFileOracle.isOK() ) {532return classFileOracle.getBuildResult();533}534535#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)536result = injectInterfaces(&classFileOracle);537if (OK != result) {538return result;539}540SRPKeyProducer srpKeyProducer(&classFileOracle, &_interfaceInjectionInfo);541#else /* J9VM_OPT_VALHALLA_VALUE_TYPES */542SRPKeyProducer srpKeyProducer(&classFileOracle);543#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */544545/*546* The ROMClassWriter must be constructed before the SRPOffsetTable because it generates additional SRP keys.547* There must be no SRP keys generated after the SRPOffsetTable is initialized.548*/549#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)550ROMClassWriter romClassWriter(bufferManager, &classFileOracle, &srpKeyProducer, &constantPoolMap, context, &_interfaceInjectionInfo);551#else /* J9VM_OPT_VALHALLA_VALUE_TYPES */552ROMClassWriter romClassWriter(bufferManager, &classFileOracle, &srpKeyProducer, &constantPoolMap, context);553#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */554if ( !romClassWriter.isOK() ) {555return romClassWriter.getBuildResult();556}557SRPOffsetTable srpOffsetTable(&srpKeyProducer, bufferManager, MAX_TAG, context);558if ( !srpOffsetTable.isOK() ) {559return srpOffsetTable.getBuildResult();560}561562/* Pass the SRPOffsetTable to the ROMClassWriter to complete its initialization. */563romClassWriter.setSRPOffsetTable(&srpOffsetTable);564565U_32 modifiers = classFileOracle.getAccessFlags();566U_32 extraModifiers = computeExtraModifiers(&classFileOracle, context);567U_32 optionalFlags = computeOptionalFlags(&classFileOracle, context);568569/*570* calculate the amount of space required to write out this ROMClass without UTF8s571* and calculate the maximum amount of space required for UTF8s572* also prepare the SRP offset information573*/574SizeInformation sizeInformation;575getSizeInfo(context, &romClassWriter, &srpOffsetTable, &countDebugDataOutOfLine, &sizeInformation);576577U_32 romSize = 0;578U_32 sizeToCompareForLambda = 0;579if (isLambda) {580/*581* romSize calculated from getSizeInfo() does not involve StringInternManager. It is only accurate for string intern disabled classes.582* Lambda classes in java 15 and up are strong hidden classes (defined with Option.STONG), which has the same lifecycle as its583* defining class loader. It is string intern enabled. So pass classFileSize instead of romSize to sizeToCompareForLambda.584*/585sizeToCompareForLambda = classFileOracle.getClassFileSize();586}587588if ( context->shouldCompareROMClassForEquality() ) {589ROMClassVerbosePhase v(context, CompareHashtableROMClass);590591/*592* Check if the supplied ROMClass is identical to the one being created. If it is, simply return OK.593*594* This is done either when there is an orphan ROM class (without a RAM class) that has been created595* previously, or for ROMClass comparison on behalf of dyntest.596*/597J9ROMClass *romClass = context->romClass();598bool romClassIsShared = (j9shr_Query_IsAddressInCache(_javaVM, romClass, romClass->romSize) ? true : false);599600if (compareROMClassForEquality((U_8*)romClass, romClassIsShared, &romClassWriter,601&srpOffsetTable, &srpKeyProducer, &classFileOracle, modifiers, extraModifiers, optionalFlags, context, sizeToCompareForLambda, isLambda)602) {603return OK;604} else {605/* ROM classes not equal so remove from creation context */606context->recordROMClass(NULL);607/* need to recalculate size info and srp offsets, as comparing may have added bogus debug info */608srpOffsetTable.clear();609getSizeInfo(context, &romClassWriter, &srpOffsetTable, &countDebugDataOutOfLine, &sizeInformation);610}611612#if defined(J9DYN_TEST)613if (NULL == context->allocationStrategy()) {614/*615* No allocationStrategy is a dyntest request to compare to the existing ROMClass supplied in romClassPtr.616*/617return GenericError;618}619#endif620}621622UDATA maxRequiredSize = sizeInformation.rcWithOutUTF8sSize +623sizeInformation.lineNumberSize +624sizeInformation.variableInfoSize +625sizeInformation.utf8sSize +626sizeInformation.rawClassDataSize;627628#if defined(J9VM_OPT_SHARED_CLASSES)629if (context->isROMClassShareable()) {630UDATA loadType = J9SHR_LOADTYPE_NORMAL;631if (context->isRedefining()) {632loadType = J9SHR_LOADTYPE_REDEFINED;633} else if (context->isRetransforming()) {634loadType = J9SHR_LOADTYPE_RETRANSFORMED;635} else if (context->isClassUnsafe()636|| context->isClassHidden()637|| (LOAD_LOCATION_UNKNOWN == context->loadLocation())638) {639/* For redefining/transforming, we still want loadType to be J9SHR_LOADTYPE_REDEFINED/J9SHR_LOADTYPE_RETRANSFORMED,640* so put these checks after the redefining/transforming checks.641*/642loadType = J9SHR_LOADTYPE_NOT_FROM_PATH;643}644645SCStoreTransaction sharedStoreClassTransaction =646SCStoreTransaction(context->currentVMThread(),647context->classLoader(),648context->cpIndex(),649loadType,650classFileOracle.getUTF8Length(classFileOracle.getClassNameIndex()), classFileOracle.getUTF8Data(classFileOracle.getClassNameIndex()),651context->classFileBytesReplaced(),652context->isCreatingIntermediateROMClass());653654if ( sharedStoreClassTransaction.isOK() ) {655/*656* Shared Classes is enabled, there may be an existing ROMClass657* that can be used in place of the one being created.658*659* Attempt to find it.660*661* Note: When comparing classes it is expected that the context contains the662* rom class being compared to. 'prevROMClass' is used to backup the romClass663* currently in the context, so the compare loop can set the romClass in the664* context accordingly.665*/666J9ROMClass * prevROMClass = context->romClass();667for (668J9ROMClass *existingROMClass = sharedStoreClassTransaction.nextSharedClassForCompare();669NULL != existingROMClass;670existingROMClass = sharedStoreClassTransaction.nextSharedClassForCompare()671) {672ROMClassVerbosePhase v(context, CompareSharedROMClass);673if (!context->isIntermediateDataAClassfile()674&& ((U_8 *)existingROMClass == context->intermediateClassData())675) {676/* 'existingROMClass' is same as the ROMClass corresponding to intermediate class data.677* Based on the assumption that an agent is actually modifying the class file678* instead of just returning a copy of the classbytes it receives,679* this comparison can be avoided.680*/681continue;682}683context->recordROMClass(existingROMClass);684if (compareROMClassForEquality((U_8*)existingROMClass, /* romClassIsShared = */ true, &romClassWriter,685&srpOffsetTable, &srpKeyProducer, &classFileOracle, modifiers, extraModifiers, optionalFlags, context, sizeToCompareForLambda, isLambda)686) {687/*688* Found an existing ROMClass in the shared cache that is equivalent689* to the ROMClass that was about to be created.690* Make the found ROMClass available to our caller and leave the routine.691*/692/* no need to checkDebugInfoCompression when class comes from sharedClassCache since the romClass693* was validated when in was placed in the sharedClassCache */694return OK;695}696}697context->recordROMClass(prevROMClass);698699/*700* A shared ROMClass equivalent to the one being created was NOT found.701*702* Attempt to obtain space in the shared cache to laydown (i.e., share)703* the ROMClass being created.704*/705ROMClassVerbosePhase v(context, CreateSharedClass);706J9RomClassRequirements sizeRequirements;707708sizeRequirements.romClassMinimalSize =709U_32(sizeInformation.rcWithOutUTF8sSize710+ sizeInformation.utf8sSize + sizeInformation.rawClassDataSize);711sizeRequirements.romClassMinimalSize = ROUND_UP_TO_POWEROF2(sizeRequirements.romClassMinimalSize, sizeof(U_64));712713sizeRequirements.romClassSizeFullSize =714U_32(sizeRequirements.romClassMinimalSize715+ sizeInformation.lineNumberSize716+ sizeInformation.variableInfoSize);717sizeRequirements.romClassSizeFullSize = ROUND_UP_TO_POWEROF2(sizeRequirements.romClassSizeFullSize, sizeof(U_64));718719sizeRequirements.lineNumberTableSize = U_32(sizeInformation.lineNumberSize);720sizeRequirements.localVariableTableSize = U_32(sizeInformation.variableInfoSize);721722/*723* 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.724* Without this check, j9shr_classStoreTransaction_createSharedClass() does not guarantee returning on checking J9SHR_RUNTIMEFLAG_AVAILABLE_SPACE_FULL in runtimeFlags,725* as another thread that has write mutex may unset this flag, leading to unexpected write operation to the cache without the write mutex.726*/727if (!sharedStoreClassTransaction.isCacheFull()) {728if ( sharedStoreClassTransaction.allocateSharedClass(&sizeRequirements) ){729U_8 *romClassBuffer = (U_8*)sharedStoreClassTransaction.getRomClass();730/*731* Make note that the laydown is occurring in SharedClasses732*/733romSize = finishPrepareAndLaydown(734(U_8*)sharedStoreClassTransaction.getRomClass(),735(U_8*)sharedStoreClassTransaction.getLineNumberTable(),736(U_8*)sharedStoreClassTransaction.getLocalVariableTable(),737&sizeInformation, modifiers, extraModifiers, optionalFlags,738true, sharedStoreClassTransaction.hasSharedStringTableLock(),739&classFileOracle, &srpOffsetTable, &srpKeyProducer, &romClassWriter,740context, &constantPoolMap741);742743fixReturnBytecodes(_portLibrary, (J9ROMClass *)romClassBuffer);744745/*746* inform the shared class transaction what the final ROMSize is747*/748sharedStoreClassTransaction.updateSharedClassSize(romSize);749context->recordROMClass((J9ROMClass *)romClassBuffer);750if ((NULL != _javaVM) && (_javaVM->extendedRuntimeFlags & J9_EXTENDED_RUNTIME_CHECK_DEBUG_INFO_COMPRESSION)) {751checkDebugInfoCompression((J9ROMClass *)romClassBuffer, classFileOracle, &srpKeyProducer, &constantPoolMap, &srpOffsetTable);752}753return OK;754}755/* If sharedStoreClassTransaction.allocateSharedClass() returned false due to the shared cache softmx, unstored bytes is increased inside756* SH_CompositeCacheImpl::allocate(). No need to call sharedStoreClassTransaction.updateUnstoredBytes() here.757*/758} else {759sharedStoreClassTransaction.updateUnstoredBytes(sizeRequirements.romClassSizeFullSize);760}761}762763/*764* There is insufficient space available in the shared cache765* to accommodate the ROMClass that is being built.766*767* Terminate the attempted Store Class Transaction.768*769* Simply exit the scope. This will invoke the destructor for770* sharedStoreClassTransaction and terminate the transaction.771*/772}773774if (context->isIntermediateDataAClassfile()) {775/* For some reason we are not storing ROMClass in the cache.776* In case we earlier decided to store Intermediate Class File bytes along with ROMClass,777* need to check if we still need them. If not, modify sizeRequirements accordingly.778*779* We don't need to store Intermediate Class File if we fail to store ROMClass in the cache780* when running with -Xshareclasses:enableBCI and class file bytes are not modified and re-transformation is not enabled.781*/782if (context->shouldStripIntermediateClassData()) {783maxRequiredSize -= sizeInformation.rawClassDataSize;784sizeInformation.rawClassDataSize = 0;785}786787/* In case ROMClass is not stored in cache, and we are re-transforming,788* try to re-use intermediateClassData from existing ROMClass.789*/790if (false == context->isReusingIntermediateClassData()) {791romClassWriter.reuseIntermediateClassData();792/* Modify size requirements if we are able to reuse intermediate class data now */793if (true == context->isReusingIntermediateClassData()) {794maxRequiredSize -= sizeInformation.rawClassDataSize;795sizeInformation.rawClassDataSize = 0;796}797}798}799#endif /* J9VM_OPT_SHARED_CLASSES */800/*801* Shared Classes is disabled, unavailable, or failed; use the regular allocation strategy.802*/803804/*805* request the maximum amount of space to laydown this ROMClass806*/807U_8 *romClassBuffer = NULL;808U_8 *lineNumberBuffer = NULL;809U_8 *variableInfoBuffer = NULL;810AllocationStrategy::AllocatedBuffers allocatedBuffers;811812if ( context->allocationStrategy()->allocateWithOutOfLineData( &allocatedBuffers,813sizeInformation.rcWithOutUTF8sSize + sizeInformation.utf8sSize + sizeInformation.rawClassDataSize,814sizeInformation.lineNumberSize, sizeInformation.variableInfoSize)815) {816romClassBuffer = allocatedBuffers.romClassBuffer;817lineNumberBuffer = allocatedBuffers.lineNumberBuffer;818variableInfoBuffer = allocatedBuffers.variableInfoBuffer;819} else {820/* Pad maxRequiredSize to the size to sizeof(U_64) in order to prevent memory corruption.821* This mirrors ROM class padding in finishPrepareAndLaydown when the final ROM class size822* is calculated.823*/824maxRequiredSize = ROUND_UP_TO_POWEROF2(maxRequiredSize, sizeof(U_64));825romClassBuffer = context->allocationStrategy()->allocate(maxRequiredSize);826}827if ( romClassBuffer == NULL ) {828return OutOfROM;829}830831/*832* Use an if statement here and call finishPrepareAndLaydown() in both cases to allow the scope of SCStringTransaction() to survive the life of the call to833* finishPrepareAndLaydown(). Otherwise, the scope of SCStringTransaction() would end early and it would not be safe to us interned strings.834*/835if (J9_ARE_ANY_BITS_SET(context->findClassFlags(), J9_FINDCLASS_FLAG_ANON | J9_FINDCLASS_FLAG_HIDDEN)) {836U_16 classNameIndex = classFileOracle.getClassNameIndex();837U_8* classNameBytes = classFileOracle.getUTF8Data(classNameIndex);838U_16 classNameFullLength = classFileOracle.getUTF8Length(classNameIndex);839U_16 classNameRealLenghth = classNameFullLength - ROM_ADDRESS_LENGTH;840char* nameString = NULL;841char message[ROM_ADDRESS_LENGTH + 1];842if (J9_ARE_ALL_BITS_SET(context->findClassFlags(), J9_FINDCLASS_FLAG_REDEFINING)843|| J9_ARE_ALL_BITS_SET(context->findClassFlags(), J9_FINDCLASS_FLAG_RETRANSFORMING)844) {845/* When redefining we need to use the original class name */846nameString = ((char*) context->className() + classNameRealLenghth);847} else {848/* fix up the ROM className with segment Address849* write the name into a buffer first because j9str_printf automatically adds a NULL terminator850* at the end, and J9UTF8 are not NULL terminated851*/852j9str_printf(PORTLIB, message, ROM_ADDRESS_LENGTH + 1, ROM_ADDRESS_FORMAT, (UDATA)romClassBuffer);853nameString = (char*) message;854}855memcpy((char*) (classNameBytes + classNameRealLenghth), nameString, ROM_ADDRESS_LENGTH);856}857858#if defined(J9VM_OPT_SHARED_CLASSES)859if (NULL != context->javaVM()) {860SCStringTransaction scStringTransaction = SCStringTransaction(context->currentVMThread());861romSize = finishPrepareAndLaydown(romClassBuffer, lineNumberBuffer, variableInfoBuffer, &sizeInformation, modifiers, extraModifiers, optionalFlags,862false, scStringTransaction.isOK(), &classFileOracle, &srpOffsetTable, &srpKeyProducer, &romClassWriter, context, &constantPoolMap);863} else864#endif865{866romSize = finishPrepareAndLaydown(romClassBuffer, lineNumberBuffer, variableInfoBuffer, &sizeInformation, modifiers, extraModifiers, optionalFlags,867false, false, &classFileOracle, &srpOffsetTable, &srpKeyProducer, &romClassWriter, context, &constantPoolMap);868}869870/* This assert will detect memory corruption when a new segment871* for the ROM class was allocated using maxRequiredSize.872*/873Trc_BCU_Assert_True_Level1(romSize <= maxRequiredSize);874875/*876* inform the allocator what the final ROMSize is877*/878if (J9_ARE_ALL_BITS_SET(context->findClassFlags(), J9_FINDCLASS_FLAG_ANON)) {879/* for anonClasses lie about the size report that it is full so no one else can use the segment */880romSize = (U_32) ((ROMClassSegmentAllocationStrategy*) context->allocationStrategy())->getSegmentSize();881}882context->allocationStrategy()->updateFinalROMSize(romSize);883884context->recordROMClass((J9ROMClass *)romClassBuffer);885886if ((NULL != _javaVM) && (_javaVM->extendedRuntimeFlags & J9_EXTENDED_RUNTIME_CHECK_DEBUG_INFO_COMPRESSION)) {887checkDebugInfoCompression((J9ROMClass *)romClassBuffer, classFileOracle, &srpKeyProducer, &constantPoolMap, &srpOffsetTable);888}889890return OK;891}892893/*894* Test the compression of the ROMclass'debug information when running the command895* Tests the line number compression and the local variable table compression896* -Xcheck:vm:debuginfo897*/898void899ROMClassBuilder::checkDebugInfoCompression(J9ROMClass *romClass, ClassFileOracle classFileOracle, SRPKeyProducer *srpKeyProducer, ConstantPoolMap *constantPoolMap, SRPOffsetTable *srpOffsetTable)900{901PORT_ACCESS_FROM_PORT(_portLibrary);902J9ROMMethod *currentMethod;903currentMethod = (J9ROMMethod*)(J9ROMCLASS_ROMMETHODS(romClass));904for (ClassFileOracle::MethodIterator methodIterator = classFileOracle.getMethodIterator();905methodIterator.isNotDone();906methodIterator.next()) {907908/* 1) Test the line number compression */909UDATA lineNumbersInfoSize = methodIterator.getLineNumbersCount() * sizeof (J9CfrLineNumberTableEntry);910if (0 != lineNumbersInfoSize) {911J9CfrLineNumberTableEntry *lineNumbersInfo = (J9CfrLineNumberTableEntry*)j9mem_allocate_memory(lineNumbersInfoSize, J9MEM_CATEGORY_CLASSES);912if (NULL != lineNumbersInfo) {913classFileOracle.sortLineNumberTable(methodIterator.getIndex(), lineNumbersInfo);914J9LineNumber lineNumber;915lineNumber.lineNumber = 0;916lineNumber.location = 0;917918J9MethodDebugInfo *methodInfo = getMethodDebugInfoFromROMMethod(currentMethod);919if (NULL != methodInfo) {920U_8 *currentLineNumber = getLineNumberTable(methodInfo);921U_32 lineNumbersCount = getLineNumberCount(methodInfo);922UDATA index;923Trc_BCU_Assert_CorrectLineNumbersCount(lineNumbersCount, methodIterator.getLineNumbersCount());924925if (0 != lineNumbersCount) {926for (index = 0; index < lineNumbersCount; index++) {927/* From the original class */928U_32 pcOriginal = lineNumbersInfo[index].startPC;929U_32 lineNumberOriginal = lineNumbersInfo[index].lineNumber;930931/* From the compressed class */932getNextLineNumberFromTable(¤tLineNumber, &lineNumber);933if ((lineNumber.lineNumber != lineNumberOriginal) || (lineNumber.location != pcOriginal)) {934J9UTF8* name = J9ROMCLASS_CLASSNAME(romClass);935PORT_ACCESS_FROM_PORT(_portLibrary);936j9tty_printf(PORTLIB, "Error while uncompressing the debug information for the class %.*s\n", (UDATA)J9UTF8_LENGTH(name), J9UTF8_DATA(name));937j9tty_printf(PORTLIB, "lineNumber.lineNumber(%d) / lineNumberOriginal(%d)\n", lineNumber.lineNumber,lineNumberOriginal);938j9tty_printf(PORTLIB, "lineNumber.location(%d) / pcOriginal(%d)\n", lineNumber.location, pcOriginal);939Trc_BCU_Assert_ShouldNeverHappen_CompressionMissmatch();940}941}942}943}944j9mem_free_memory(lineNumbersInfo);945} else {946Trc_BCU_Assert_Compression_OutOfMemory();947}948}949/* 2) Test local variable table compression */950U_32 localVariablesCount = methodIterator.getLocalVariablesCount();951if (0 != localVariablesCount) {952J9MethodDebugInfo *methodDebugInfo = getMethodDebugInfoFromROMMethod(currentMethod);953if (NULL != methodDebugInfo) {954J9VariableInfoWalkState state;955J9VariableInfoValues *values = NULL;956957Trc_BCU_Assert_Equals_Level1(methodDebugInfo->varInfoCount, localVariablesCount);958959values = variableInfoStartDo(methodDebugInfo, &state);960if (NULL != values) {961for (ClassFileOracle::LocalVariablesIterator localVariablesIterator = methodIterator.getLocalVariablesIterator();962localVariablesIterator.isNotDone();963localVariablesIterator.next()) {964if (NULL == values) {965/* The number of compressed variableTableInfo is less than the original number */966Trc_BCU_Assert_ShouldNeverHappen_CompressionMissmatch();967}968Trc_BCU_Assert_Equals_Level1(values->startVisibility, localVariablesIterator.getStartPC());969Trc_BCU_Assert_Equals_Level1(values->visibilityLength, localVariablesIterator.getLength());970Trc_BCU_Assert_Equals_Level1(values->slotNumber, localVariablesIterator.getIndex());971972Trc_BCU_Assert_Equals_Level1(973(J9UTF8*)(values->name),974(J9UTF8*)(srpOffsetTable->computeWSRP(srpKeyProducer->mapCfrConstantPoolIndexToKey(localVariablesIterator.getNameIndex()), 0))975);976Trc_BCU_Assert_Equals_Level1(977(J9UTF8*)(values->signature),978(J9UTF8*)(srpOffsetTable->computeWSRP(srpKeyProducer->mapCfrConstantPoolIndexToKey(localVariablesIterator.getDescriptorIndex()), 0))979);980if (localVariablesIterator.hasGenericSignature()) {981Trc_BCU_Assert_Equals_Level1(982(J9UTF8*)(values->genericSignature),983(J9UTF8*)(srpOffsetTable->computeWSRP(srpKeyProducer->mapCfrConstantPoolIndexToKey(localVariablesIterator.getGenericSignatureIndex()), 0))984);985} else {986Trc_BCU_Assert_Equals_Level1((J9UTF8*)(values->genericSignature), NULL);987}988989values = variableInfoNextDo(&state);990}991}992}993}994995/* 3) next method */996currentMethod = nextROMMethod(currentMethod);997}998}9991000U_321001ROMClassBuilder::finishPrepareAndLaydown(1002U_8 *romClassBuffer,1003U_8 *lineNumberBuffer,1004U_8 *variableInfoBuffer,1005SizeInformation *sizeInformation,1006U_32 modifiers,1007U_32 extraModifiers,1008U_32 optionalFlags,1009bool sharingROMClass,1010bool hasStringTableLock,1011ClassFileOracle *classFileOracle,1012SRPOffsetTable *srpOffsetTable,1013SRPKeyProducer *srpKeyProducer,1014ROMClassWriter *romClassWriter,1015ROMClassCreationContext *context,1016ConstantPoolMap *constantPoolMap)1017{1018U_8 * romClassBufferEndAddress = romClassBuffer + sizeInformation->rcWithOutUTF8sSize + sizeInformation->utf8sSize + sizeInformation->rawClassDataSize;1019ROMClassStringInternManager internManager(1020context,1021&_stringInternTable,1022srpOffsetTable,1023srpKeyProducer,1024romClassBuffer,1025romClassBufferEndAddress,1026sharingROMClass,1027hasStringTableLock);10281029/*1030* Identify interned strings.1031*/1032if (internManager.isInterningEnabled()) {1033ROMClassVerbosePhase v(context, WalkUTF8sAndMarkInterns);1034/**1035* It is not common that part of shared cache is in the SRP range of ROM class, and other part is not.1036* But it is possible.1037* For instance, on AIX platforms, shared cache is always not in SRP range of local ROM classes.1038* On the other hand, for linux machines, shared cache is in SRP range of local ROM class very mostly.1039* Therefore;1040* 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.1041* if shared cache is totally in the SRP range of local ROM classes, then local ROM classes can use UTF8s in shared cache safely.1042* if part of shared cache is in the SRP range, and part of it is not,1043* then for each UTF8 in the local ROM class, SRP range check is required in order to use shared UTFs in the shared cache.1044*1045* Values of sharedCacheSRPRangeInfo:1046* 1: (SC_COMPLETELY_OUT_OF_THE_SRP_RANGE) Shared cache is out of the SRP range1047* 2: (SC_COMPLETELY_IN_THE_SRP_RANGE) Shared cache is in the SRP range1048* 3: (SC_PARTIALLY_IN_THE_SRP_RANGE) Part of shared cache is in the SRP range, part of it is not.1049*1050* Shared cache is always in the SRP range of any address in shared cache.1051*/1052SharedCacheRangeInfo sharedCacheSRPRangeInfo = SC_COMPLETELY_IN_THE_SRP_RANGE;1053#if defined(J9VM_OPT_SHARED_CLASSES)1054#if defined(J9VM_ENV_DATA64)1055sharedCacheSRPRangeInfo = SC_PARTIALLY_IN_THE_SRP_RANGE;1056if (!internManager.isSharedROMClass()) {1057UDATA romClassStartRangeCheck = getSharedCacheSRPRangeInfo(romClassBuffer);1058UDATA romClassEndRangeCheck = getSharedCacheSRPRangeInfo(romClassBufferEndAddress);10591060if (SC_COMPLETELY_OUT_OF_THE_SRP_RANGE == romClassStartRangeCheck) {1061if (SC_COMPLETELY_OUT_OF_THE_SRP_RANGE == romClassEndRangeCheck) {1062sharedCacheSRPRangeInfo = SC_COMPLETELY_OUT_OF_THE_SRP_RANGE;1063}1064} else if (SC_COMPLETELY_IN_THE_SRP_RANGE == romClassStartRangeCheck ) {1065if (SC_COMPLETELY_IN_THE_SRP_RANGE == romClassEndRangeCheck) {1066sharedCacheSRPRangeInfo = SC_COMPLETELY_IN_THE_SRP_RANGE;1067}1068}1069} else {1070/* Shared cache is always in the range of shared rom classes in it */1071sharedCacheSRPRangeInfo = SC_COMPLETELY_IN_THE_SRP_RANGE;1072}1073#endif1074#endif1075{1076ROMClassVerbosePhase v(context, VisitUTF8Block);1077for (ClassFileOracle::UTF8Iterator iterator = classFileOracle->getUTF8Iterator();1078iterator.isNotDone();1079iterator.next()) {1080U_16 cpIndex = iterator.getCPIndex();10811082if (constantPoolMap->isUTF8ConstantReferenced(cpIndex)) {1083internManager.visitUTF8(cpIndex, iterator.getUTF8Length(), iterator.getUTF8Data(), sharedCacheSRPRangeInfo);1084}1085}1086}1087}10881089/*1090* Determine what kind of recount needs to be performed, either only the UTF8 section or the entire ROMClass.1091*1092* The UTF8 section always needs to be when string interning is on.1093*1094* The entire ROMClass needs to be when calculating debug information out of line and then NOT sharing the class1095* in an out of line fashion.1096*/1097if ( (sizeInformation->lineNumberSize > 0) && (NULL == lineNumberBuffer) ) {1098/*1099* Debug Information has been calculated out of line1100* --and--1101* there is no room for out of line debug information1102*1103* Need to recalculate the entire ROMClass.1104*/1105Cursor mainAreaCursor(RC_TAG, srpOffsetTable, context);1106Cursor utf8Cursor(UTF8_TAG, srpOffsetTable, context);1107Cursor classDataCursor(INTERMEDIATE_TAG, srpOffsetTable, context);11081109context->forceDebugDataInLine();1110romClassWriter->writeROMClass(&mainAreaCursor,1111&mainAreaCursor,1112&mainAreaCursor,1113&utf8Cursor,1114(context->isIntermediateDataAClassfile()) ? &classDataCursor : NULL,11150, 0, 0, 0,1116ROMClassWriter::MARK_AND_COUNT_ONLY);11171118/* NOTE: the size of the VarHandle MethodType lookup table is already included in1119* rcWithOutUTF8sSize; see ROMClassWriter::writeVarHandleMethodTypeLookupTable().1120* VarHandleMethodTypeLookupTable is disabled for OpenJDK MethodHandles because1121* it is not used.1122*/1123sizeInformation->rcWithOutUTF8sSize = mainAreaCursor.getCount();1124sizeInformation->lineNumberSize = 0;1125sizeInformation->variableInfoSize = 0;1126sizeInformation->utf8sSize = utf8Cursor.getCount();1127sizeInformation->rawClassDataSize = classDataCursor.getCount();1128} else if (internManager.isInterningEnabled()) {1129/*1130* With the interned strings known, do a second pass on the UTF8 block to update SRP offset information1131* and determine the final size for UTF8s1132*/1133ROMClassVerbosePhase v(context, PrepareUTF8sAfterInternsMarked);1134Cursor utf8Cursor(UTF8_TAG, srpOffsetTable, context);1135romClassWriter->writeUTF8s(&utf8Cursor);1136sizeInformation->utf8sSize = utf8Cursor.getCount();1137}11381139/*1140* Record the romSize as the final size of the ROMClass with interned strings space removed.1141*/1142U_32 romSize = U_32(sizeInformation->rcWithOutUTF8sSize + sizeInformation->utf8sSize + sizeInformation->rawClassDataSize);1143romSize = ROUND_UP_TO_POWEROF2(romSize, sizeof(U_64));11441145/*1146* update the SRP Offset Table with the base addresses for main ROMClass section (RC_TAG),1147* the UTF8 Block (UTF8_TAG) and the Intermediate Class Data Block (INTERMEDIATE_TAG)1148*/1149srpOffsetTable->setBaseAddressForTag(RC_TAG, romClassBuffer);1150srpOffsetTable->setBaseAddressForTag(UTF8_TAG, romClassBuffer+sizeInformation->rcWithOutUTF8sSize);1151if (context->isIntermediateDataAClassfile()) {1152/* Raw class data is always written inline and the calculation1153* of where to start writing must be done after string interning is done.1154*/1155srpOffsetTable->setBaseAddressForTag(INTERMEDIATE_TAG, romClassBuffer + sizeInformation->rcWithOutUTF8sSize + sizeInformation->utf8sSize);1156}1157srpOffsetTable->setBaseAddressForTag(LINE_NUMBER_TAG, lineNumberBuffer);1158srpOffsetTable->setBaseAddressForTag(VARIABLE_INFO_TAG, variableInfoBuffer);11591160/*1161* write ROMClass to memory1162*/1163layDownROMClass(romClassWriter, srpOffsetTable, romSize, modifiers, extraModifiers, optionalFlags, &internManager, context, sizeInformation);1164return romSize;1165}11661167/*1168* ROMClass->extraModifiers what does each bit represent?1169*1170* 0000 0000 0000 0000 0000 0000 0000 00001171* + UNUSED1172* + UNUSED1173* + UNUSED1174* + UNUSED1175*1176* + UNUSED1177* + J9AccClassHasIdentity1178* + J9AccClassIsValueBased1179* + J9AccClassHiddenOptionNestmate1180*1181* + J9AccClassHiddenOptionStrong1182* + AccSealed1183* + AccRecord1184* + AccClassAnonClass1185*1186* + AccSynthetic (matches Oracle modifier position)1187* + AccClassUseBisectionSearch1188* + AccClassInnerClass1189* + J9AccClassHidden1190*1191* + AccClassNeedsStaticConstantInit1192* + AccClassIntermediateDataIsClassfile1193* + AccClassUnsafe1194* + AccClassAnnnotionRefersDoubleSlotEntry1195*1196* + AccClassBytecodesModified1197* + AccClassHasEmptyFinalize1198* + AccClassIsUnmodifiable1199* + AccClassHasVerifyData1200*1201* + AccClassIsContended1202* + AccClassHasFinalFields1203* + AccClassHasClinit1204* + AccClassHasNonStaticNonAbstractMethods1205*1206* + (shape)1207* + (shape)1208* + AccClassFinalizeNeeded1209* + AccClassCloneable1210*/12111212U_321213ROMClassBuilder::computeExtraModifiers(ClassFileOracle *classFileOracle, ROMClassCreationContext *context)1214{1215ROMClassVerbosePhase v(context, ComputeExtraModifiers);12161217U_32 modifiers = 0;12181219if ( context->isClassUnsafe() ) {1220modifiers |= J9AccClassUnsafe;1221}12221223if ( context->isClassAnon() ) {1224modifiers |= J9AccClassAnonClass;1225}12261227if (context->isClassHidden()) {1228modifiers |= J9AccClassHidden;1229if (context->isHiddenClassOptNestmateSet()) {1230modifiers |= J9AccClassHiddenOptionNestmate;1231}1232if (context->isHiddenClassOptStrongSet()) {1233modifiers |= J9AccClassHiddenOptionStrong;1234}1235}12361237if ( context->classFileBytesReplaced() ) {1238modifiers |= J9AccClassBytecodesModified;1239}12401241if ( classFileOracle->hasFinalFields() ) {1242modifiers |= J9AccClassHasFinalFields;1243}12441245if ( classFileOracle->hasNonStaticNonAbstractMethods() ) {1246modifiers |= J9AccClassHasNonStaticNonAbstractMethods;1247}12481249if ( classFileOracle->isCloneable() ) {1250modifiers |= J9AccClassCloneable;1251}12521253if ( classFileOracle->isClassContended() ) {1254modifiers |= J9AccClassIsContended;1255}12561257if ( classFileOracle->isClassUnmodifiable() ) {1258modifiers |= J9AccClassIsUnmodifiable;1259}12601261if (classFileOracle->isValueBased()) {1262modifiers |= J9AccClassIsValueBased;1263}12641265#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)1266if (classFileOracle->hasIdentityInterface()1267|| classFileOracle->needsIdentityInterface()1268) {1269modifiers |= J9AccClassHasIdentity;1270}1271#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */12721273U_32 classNameindex = classFileOracle->getClassNameIndex();12741275#define WEAK_NAME "java/lang/ref/WeakReference"1276#define SOFT_NAME "java/lang/ref/SoftReference"1277#define PHANTOM_NAME "java/lang/ref/PhantomReference"1278if ( classFileOracle->isUTF8AtIndexEqualToString(classNameindex, WEAK_NAME, sizeof(WEAK_NAME)) ) {1279modifiers |= J9AccClassReferenceWeak;1280} else if( classFileOracle->isUTF8AtIndexEqualToString(classNameindex, SOFT_NAME, sizeof(SOFT_NAME)) ) {1281modifiers |= J9AccClassReferenceSoft;1282} else if( classFileOracle->isUTF8AtIndexEqualToString(classNameindex, PHANTOM_NAME, sizeof(PHANTOM_NAME)) ) {1283modifiers |= J9AccClassReferencePhantom;1284}1285#undef WEAK_NAME1286#undef SOFT_NAME1287#undef PHANTOM_NAME12881289if ( classFileOracle->hasFinalizeMethod() ) {1290if ( classFileOracle->hasEmptyFinalizeMethod() ) {1291/* If finalize() is empty, mark this class so it does not inherit CFR_ACC_FINALIZE_NEEDED from its superclass */1292modifiers |= J9AccClassHasEmptyFinalize;1293} else {1294modifiers |= J9AccClassFinalizeNeeded;1295}1296}12971298if (classFileOracle->getMajorVersion() >= (BCT_JavaMajorVersionShifted(6) >> BCT_MajorClassFileVersionMaskShift)) {1299/* Expect verify data for Java 6 and later versions */1300modifiers |= J9AccClassHasVerifyData;1301} else {1302/* Detect if there is verify data for at least one method for versions less than Java 6 */1303for (ClassFileOracle::MethodIterator methodIterator = classFileOracle->getMethodIterator();1304methodIterator.isNotDone();1305methodIterator.next()) {1306if ( methodIterator.hasStackMap() ) {1307modifiers |= J9AccClassHasVerifyData;1308break;1309}1310}1311}13121313if ( classFileOracle->isSynthetic() ) {1314/* handle the synthetic attribute. In java 1.5 synthetic may be specified in the access flags as well so do not unset bit here */1315// Trc_BCU_createRomClassEndian_Synthetic(romClass);1316modifiers |= J9AccSynthetic;1317}13181319if (classFileOracle->hasClinit()) {1320modifiers |= J9AccClassHasClinit;1321}13221323if (classFileOracle->annotationRefersDoubleSlotEntry()) {1324modifiers |= J9AccClassAnnnotionRefersDoubleSlotEntry;1325}13261327if (context->isIntermediateDataAClassfile()) {1328modifiers |= J9AccClassIntermediateDataIsClassfile;1329}13301331if (context->canRomMethodsBeSorted(classFileOracle->getMethodsCount())) {1332modifiers |= J9AccClassUseBisectionSearch;1333}13341335if (classFileOracle->isInnerClass()) {1336modifiers |= J9AccClassInnerClass;1337}13381339if (classFileOracle->needsStaticConstantInit()) {1340modifiers |= J9AccClassNeedsStaticConstantInit;1341}13421343if (classFileOracle->isRecord()) {1344modifiers |= J9AccRecord;1345}13461347if (classFileOracle->isSealed()) {1348modifiers |= J9AccSealed;1349}13501351return modifiers;1352}13531354U_321355ROMClassBuilder::computeOptionalFlags(ClassFileOracle *classFileOracle, ROMClassCreationContext *context)1356{1357ROMClassVerbosePhase v(context, ComputeOptionalFlags);13581359U_32 optionalFlags = 0;13601361if (classFileOracle->hasSourceFile() && context->shouldPreserveSourceFileName()){1362optionalFlags |= J9_ROMCLASS_OPTINFO_SOURCE_FILE_NAME;1363}1364if (classFileOracle->hasGenericSignature()){1365optionalFlags |= J9_ROMCLASS_OPTINFO_GENERIC_SIGNATURE;1366}1367if (classFileOracle->hasSourceDebugExtension() && context->shouldPreserveSourceDebugExtension()){1368optionalFlags |= J9_ROMCLASS_OPTINFO_SOURCE_DEBUG_EXTENSION;1369}1370if (classFileOracle->hasClassAnnotations()) {1371optionalFlags |= J9_ROMCLASS_OPTINFO_CLASS_ANNOTATION_INFO;1372}1373if (classFileOracle->hasTypeAnnotations()) {1374optionalFlags |= J9_ROMCLASS_OPTINFO_TYPE_ANNOTATION_INFO;1375}1376if (classFileOracle->hasEnclosingMethod()){1377optionalFlags |= J9_ROMCLASS_OPTINFO_ENCLOSING_METHOD;1378}1379if (classFileOracle->hasSimpleName()){1380optionalFlags |= J9_ROMCLASS_OPTINFO_SIMPLE_NAME;1381}1382if (classFileOracle->hasVerifyExcludeAttribute()) {1383optionalFlags |= J9_ROMCLASS_OPTINFO_VERIFY_EXCLUDE;1384}1385if (classFileOracle->isRecord()) {1386optionalFlags |= J9_ROMCLASS_OPTINFO_RECORD_ATTRIBUTE;1387}1388if (classFileOracle->isSealed()) {1389optionalFlags |= J9_ROMCLASS_OPTINFO_PERMITTEDSUBCLASSES_ATTRIBUTE;1390}1391#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)1392if (_interfaceInjectionInfo.numOfInterfaces > 0) {1393optionalFlags |= J9_ROMCLASS_OPTINFO_INJECTED_INTERFACE_INFO;1394}1395#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */1396return optionalFlags;1397}13981399void1400ROMClassBuilder::layDownROMClass(1401ROMClassWriter *romClassWriter, SRPOffsetTable *srpOffsetTable, U_32 romSize, U_32 modifiers, U_32 extraModifiers, U_32 optionalFlags,1402ROMClassStringInternManager *internManager, ROMClassCreationContext *context, SizeInformation *sizeInformation)1403{1404ROMClassVerbosePhase v(context, LayDownROMClass);1405WritingCursor writingCursor(RC_TAG, srpOffsetTable, internManager, context);1406WritingCursor lineNumberCursor(LINE_NUMBER_TAG, srpOffsetTable, internManager, context);1407WritingCursor variableInfoCursor(VARIABLE_INFO_TAG, srpOffsetTable, internManager, context);1408WritingCursor utf8Cursor(UTF8_TAG, srpOffsetTable, internManager, context);1409WritingCursor classDataCursor(INTERMEDIATE_TAG, srpOffsetTable, internManager, context);1410WritingCursor *lineNumberCursorPtr = &writingCursor;1411WritingCursor *variableInfoCursorPtr = &writingCursor;14121413if ( sizeInformation->lineNumberSize > 0 ) {1414lineNumberCursorPtr = &lineNumberCursor;1415variableInfoCursorPtr = &variableInfoCursor;1416} else {1417context->forceDebugDataInLine();1418}14191420romClassWriter->writeROMClass(&writingCursor,1421lineNumberCursorPtr,1422variableInfoCursorPtr,1423&utf8Cursor,1424(context->isIntermediateDataAClassfile()) ? &classDataCursor : NULL,1425romSize, modifiers, extraModifiers, optionalFlags,1426ROMClassWriter::WRITE);1427}14281429bool1430ROMClassBuilder::compareROMClassForEquality(U_8 *romClass,bool romClassIsShared,1431ROMClassWriter *romClassWriter, SRPOffsetTable *srpOffsetTable, SRPKeyProducer *srpKeyProducer,1432ClassFileOracle *classFileOracle, U_32 modifiers, U_32 extraModifiers, U_32 optionalFlags,1433ROMClassCreationContext * context, U_32 sizeToCompareForLambda, bool isLambda)1434{1435bool ret = false;14361437if (isLambda) {1438int maxVariance = 9;1439if (abs((int)(sizeToCompareForLambda - ((J9ROMClass *)romClass)->classFileSize)) > maxVariance) {1440/*1441* Lambda class names are in the format of HostClassName$$Lambda$<IndexNumber>/0x0000000000000000.1442* When we reach this check, the host class names will be the same for both the classes because1443* of the hash key check earlier so the only difference in the size will be the difference1444* between the number of digits of the index number. The same lambda class might have a1445* different index number from run to run and when the number of digits of the index number1446* increases by 1, classFileSize also increases by 1. The indexNumber is counter for the number of lambda classes1447* 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).1448* This check is different than the romSize check because when the number of digits of the index1449* number increases by 1, classFileSize also increases by 1 but romSize increases by 2.1450*/1451ret = false;1452} else {1453ComparingCursor compareCursor(_javaVM, srpOffsetTable, srpKeyProducer, classFileOracle, romClass, romClassIsShared, context, isLambda);1454romClassWriter->writeROMClass(&compareCursor,1455&compareCursor,1456&compareCursor,1457NULL,1458NULL,14590, modifiers, extraModifiers, optionalFlags,1460ROMClassWriter::WRITE);14611462ret = compareCursor.isEqual();1463}1464} else {1465ComparingCursor compareCursor(_javaVM, srpOffsetTable, srpKeyProducer, classFileOracle, romClass, romClassIsShared, context, isLambda);1466romClassWriter->writeROMClass(&compareCursor,1467&compareCursor,1468&compareCursor,1469NULL,1470NULL,14710, modifiers, extraModifiers, optionalFlags,1472ROMClassWriter::WRITE);14731474ret = compareCursor.isEqual();1475}1476J9UTF8* name = J9ROMCLASS_CLASSNAME((J9ROMClass *)romClass);1477Trc_BCU_compareROMClassForEquality_event(ret, J9UTF8_LENGTH(name), J9UTF8_DATA(name));1478return ret;1479}14801481#if defined(J9VM_OPT_SHARED_CLASSES)1482#if defined(J9VM_ENV_DATA64)1483/**1484* This function checks how much of shared cache is in SRP range of the given address.1485* This check is done only for 64 bit environments.1486* @param address Given address whose SRP range will be checked against shared cache.1487* @return 1 (SC_COMPLETELY_OUT_OF_THE_SRP_RANGE) if shared cache is totally out of the SRP range.1488* @return 2 (SC_COMPLETELY_IN_THE_SRP_RANGE) if shared cache is totally in the SRP range.1489* @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.1490*/1491SharedCacheRangeInfo1492ROMClassBuilder::getSharedCacheSRPRangeInfo(void *address)1493{1494if ((NULL != _javaVM) && (NULL != _javaVM->sharedClassConfig)) {1495J9SharedClassCacheDescriptor *cache = _javaVM->sharedClassConfig->cacheDescriptorList;1496if (NULL == cache) {1497/*1498* If there is no shared cache,1499* just return 1:out of range to avoid trying to find utf8 in shared cache in the future1500*/1501return SC_COMPLETELY_OUT_OF_THE_SRP_RANGE;1502}1503/*This is initial value to set the bits to zero*/1504SharedCacheRangeInfo sharedCacheRangeInfo = SC_NO_RANGE_INFO;15051506/**1507* It checks whether shared cache(s) in the SRP range completely, not at all or partially against the specific address passed to this function.1508* 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.1509* 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.1510* In all other cases, shared cache(s) are SC_PARTIALLY_IN_THE_SRP_RANGE.1511*/1512while (NULL != cache) {1513void * cacheStart = (void *)cache->cacheStartAddress;1514void * cacheEnd = (void *)(((U_8 *)cacheStart) + cache->cacheSizeBytes - 1);15151516if (StringInternTable::areAddressesInSRPRange(cacheStart, address)) {1517/* Check whether the end of cache is in the SRP range of the address */1518if (StringInternTable::areAddressesInSRPRange(cacheEnd, address)) {1519/**1520* Current cache is in SRP range. Check whether previous cache(s) were in range or not if there is any.1521* If current cache is the first cache in the list, then sharedCacheRangeInfo is set to SC_NO_RANGE_INFO.1522* 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.1523* If they are all SC_COMPLETELY_IN_THE_SRP_RANGE, then set sharedCacheRangeInfo to SC_COMPLETELY_IN_THE_SRP_RANGE1524*1525*/1526if (sharedCacheRangeInfo == SC_COMPLETELY_OUT_OF_THE_SRP_RANGE) {1527return SC_PARTIALLY_IN_THE_SRP_RANGE;1528} else {1529sharedCacheRangeInfo = SC_COMPLETELY_IN_THE_SRP_RANGE;1530}1531} else {1532return SC_PARTIALLY_IN_THE_SRP_RANGE;1533}1534} else {1535if (StringInternTable::areAddressesInSRPRange(cacheEnd, address)) {1536return SC_PARTIALLY_IN_THE_SRP_RANGE;1537} else {1538/**1539* Current cache is out of SRP range. Check whether previous cache(s) were in range or not if there is any.1540* If current cache is the first cache in the list, then sharedCacheRangeInfo is set to SC_NO_RANGE_INFO.1541* 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.1542* If they are all SC_COMPLETELY_OUT_OF_THE_SRP_RANGE, then set sharedCacheRangeInfo to SC_COMPLETELY_OUT_OF_THE_SRP_RANGE1543*1544*/1545if (sharedCacheRangeInfo == SC_PARTIALLY_IN_THE_SRP_RANGE) {1546return SC_PARTIALLY_IN_THE_SRP_RANGE;1547} else {1548sharedCacheRangeInfo = SC_COMPLETELY_OUT_OF_THE_SRP_RANGE;1549}1550}1551}15521553if (cache->next == _javaVM->sharedClassConfig->cacheDescriptorList) {1554/* Break out of the circular descriptor list. */1555break;1556}1557cache = cache->next;1558}15591560return sharedCacheRangeInfo;1561}1562/* Either _javaVM or _JavaVM->sharedClassConfig is null.1563* Try doing range check for each UTF8.1564* In normal circumstances, we should never be here.1565*/1566return SC_PARTIALLY_IN_THE_SRP_RANGE;1567}1568#endif1569#endif157015711572