Path: blob/master/runtime/bcutil/ClassFileOracle.cpp
5985 views
/*******************************************************************************1* Copyright (c) 2001, 2022 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* ClassFileOracle.cpp23*/2425#include "ClassFileOracle.hpp"26#include "BufferManager.hpp"27#include "ConstantPoolMap.hpp"28#include "ROMClassCreationContext.hpp"29#include "ROMClassVerbosePhase.hpp"303132#include "j9port.h"33#include "jbcmap.h"34#include "ut_j9bcu.h"35#include "util_api.h"36#include "j9protos.h"3738#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)39#define VALUE_TYPES_MAJOR_VERSION 5540#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */4142/* The array entries must be in same order as the enums in ClassFileOracle.hpp */43ClassFileOracle::KnownAnnotation ClassFileOracle::_knownAnnotations[] = {44#define FRAMEITERATORSKIP_SIGNATURE "Ljava/lang/invoke/MethodHandle$FrameIteratorSkip;"45{FRAMEITERATORSKIP_SIGNATURE, sizeof(FRAMEITERATORSKIP_SIGNATURE)},46#undef FRAMEITERATORSKIP_SIGNATURE47#define SUN_REFLECT_CALLERSENSITIVE_SIGNATURE "Lsun/reflect/CallerSensitive;"48{SUN_REFLECT_CALLERSENSITIVE_SIGNATURE, sizeof(SUN_REFLECT_CALLERSENSITIVE_SIGNATURE)},49#undef SUN_REFLECT_CALLERSENSITIVE_SIGNATURE50#define JDK_INTERNAL_REFLECT_CALLERSENSITIVE_SIGNATURE "Ljdk/internal/reflect/CallerSensitive;"51{JDK_INTERNAL_REFLECT_CALLERSENSITIVE_SIGNATURE, sizeof(JDK_INTERNAL_REFLECT_CALLERSENSITIVE_SIGNATURE)},52#undef JDK_INTERNAL_REFLECT_CALLERSENSITIVE_SIGNATURE53#if JAVA_SPEC_VERSION >= 1854#define JDK_INTERNAL_REFLECT_CALLERSENSITIVEADAPTER_SIGNATURE "Ljdk/internal/reflect/CallerSensitiveAdapter;"55{JDK_INTERNAL_REFLECT_CALLERSENSITIVEADAPTER_SIGNATURE, sizeof(JDK_INTERNAL_REFLECT_CALLERSENSITIVEADAPTER_SIGNATURE)},56#undef JDK_INTERNAL_REFLECT_CALLERSENSITIVEADAPTER_SIGNATURE57#endif /* JAVA_SPEC_VERSION >= 18 */58#define JAVA8_CONTENDED_SIGNATURE "Lsun/misc/Contended;" /* TODO remove this if VM does not support Java 8 */59{JAVA8_CONTENDED_SIGNATURE, sizeof(JAVA8_CONTENDED_SIGNATURE)},60#undef JAVA8_CONTENDED_SIGNATURE61#define CONTENDED_SIGNATURE "Ljdk/internal/vm/annotation/Contended;"62{CONTENDED_SIGNATURE, sizeof(CONTENDED_SIGNATURE)},63#undef CONTENDED_SIGNATURE64{J9_UNMODIFIABLE_CLASS_ANNOTATION, sizeof(J9_UNMODIFIABLE_CLASS_ANNOTATION)},65#define VALUEBASED_SIGNATURE "Ljdk/internal/ValueBased;"66{VALUEBASED_SIGNATURE, sizeof(VALUEBASED_SIGNATURE)},67#undef VALUEBASED_SIGNATURE68#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)69#if JAVA_SPEC_VERSION >= 1670#define HIDDEN_SIGNATURE "Ljdk/internal/vm/annotation/Hidden;"71#else /* JAVA_SPEC_VERSION >= 16 */72#define HIDDEN_SIGNATURE "Ljava/lang/invoke/LambdaForm$Hidden;"73#endif /* JAVA_SPEC_VERSION >= 16 */74{HIDDEN_SIGNATURE, sizeof(HIDDEN_SIGNATURE)},75#undef HIDDEN_SIGNATURE76#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */77#if JAVA_SPEC_VERSION >= 1678#define SCOPED_SIGNATURE "Ljdk/internal/misc/ScopedMemoryAccess$Scoped;"79{SCOPED_SIGNATURE, sizeof(SCOPED_SIGNATURE)},80#undef SCOPED_SIGNATURE81#endif /* JAVA_SPEC_VERSION >= 16 */82{0, 0}83};8485bool86ClassFileOracle::containsKnownAnnotation(UDATA knownAnnotationSet, UDATA knownAnnotation)87{88UDATA knownAnnotationBit = (UDATA) 1 << knownAnnotation;89return (knownAnnotationSet & knownAnnotationBit) == knownAnnotationBit;90}9192UDATA93ClassFileOracle::addAnnotationBit(UDATA annotationBits, UDATA knownAnnotation)94{95UDATA knownAnnotationBit = (UDATA) 1 << knownAnnotation;96return annotationBits |= knownAnnotationBit;97}9899U_16100ClassFileOracle::LocalVariablesIterator::getGenericSignatureIndex()101{102Trc_BCU_Assert_NotEquals(NULL, _localVariableTable);103Trc_BCU_Assert_NotEquals(NULL, _localVariablesInfo[_index].localVariableTypeTableAttribute);104105/* If the localVariableTable and localVariableTypeTable are in the same order, return the signatureIndex */106J9CfrLocalVariableTypeTableEntry* localVariableTypeTable = _localVariablesInfo[_index].localVariableTypeTableAttribute->localVariableTypeTable;107if ((_localVariableTableIndex < _localVariablesInfo[_index].localVariableTypeTableAttribute->localVariableTypeTableLength)108&& (_localVariableTable[_localVariableTableIndex].index == localVariableTypeTable[_localVariableTableIndex].index)109&& (_localVariableTable[_localVariableTableIndex].startPC == localVariableTypeTable[_localVariableTableIndex].startPC)110&& (_localVariableTable[_localVariableTableIndex].length == localVariableTypeTable[_localVariableTableIndex].length)) {111return localVariableTypeTable[_localVariableTableIndex].signatureIndex;112}113114/* Scan for matching localVariableTypeTable entry */115for (U_16 localVariableTypeTableIndex = 0;116localVariableTypeTableIndex < _localVariablesInfo[_index].localVariableTypeTableAttribute->localVariableTypeTableLength;117++localVariableTypeTableIndex) {118if ((_localVariableTable[_localVariableTableIndex].index == localVariableTypeTable[localVariableTypeTableIndex].index)119&& (_localVariableTable[_localVariableTableIndex].startPC == localVariableTypeTable[localVariableTypeTableIndex].startPC)120&& (_localVariableTable[_localVariableTableIndex].length == localVariableTypeTable[localVariableTypeTableIndex].length)) {121return localVariableTypeTable[localVariableTypeTableIndex].signatureIndex;122}123}124125Trc_BCU_Assert_ShouldNeverHappen();126return 0;127}128129bool130ClassFileOracle::LocalVariablesIterator::hasGenericSignature()131{132Trc_BCU_Assert_NotEquals(NULL, _localVariableTable);133134/* Check if the current local variable isn't generic */135if (NULL == _localVariablesInfo[_index].localVariableTypeTableAttribute) {136return false;137}138139/* Check if the localVariableTable and localVariableTypeTable are in the same order */140J9CfrLocalVariableTypeTableEntry* localVariableTypeTable = _localVariablesInfo[_index].localVariableTypeTableAttribute->localVariableTypeTable;141if ((_localVariableTableIndex < _localVariablesInfo[_index].localVariableTypeTableAttribute->localVariableTypeTableLength)142&& (_localVariableTable[_localVariableTableIndex].index == localVariableTypeTable[_localVariableTableIndex].index)143&& (_localVariableTable[_localVariableTableIndex].startPC == localVariableTypeTable[_localVariableTableIndex].startPC)144&& (_localVariableTable[_localVariableTableIndex].length == localVariableTypeTable[_localVariableTableIndex].length)) {145return true;146}147148/* Scan for matching localVariableTypeTable entry */149for (U_16 localVariableTypeTableIndex = 0;150localVariableTypeTableIndex < _localVariablesInfo[_index].localVariableTypeTableAttribute->localVariableTypeTableLength;151++localVariableTypeTableIndex) {152if ((_localVariableTable[_localVariableTableIndex].index == localVariableTypeTable[localVariableTypeTableIndex].index)153&& (_localVariableTable[_localVariableTableIndex].startPC == localVariableTypeTable[localVariableTypeTableIndex].startPC)154&& (_localVariableTable[_localVariableTableIndex].length == localVariableTypeTable[localVariableTypeTableIndex].length)) {155return true;156}157}158return false;159}160161ClassFileOracle::ClassFileOracle(BufferManager *bufferManager, J9CfrClassFile *classFile, ConstantPoolMap *constantPoolMap,162U_8 * verifyExcludeAttribute, U_8 * romBuilderClassFileBuffer, ROMClassCreationContext *context) :163_buildResult(OK),164_bufferManager(bufferManager),165_classFile(classFile),166_constantPoolMap(constantPoolMap),167_verifyExcludeAttribute(verifyExcludeAttribute),168_romBuilderClassFileBuffer(romBuilderClassFileBuffer),169_context(context),170_singleScalarStaticCount(0),171_objectStaticCount(0),172_doubleScalarStaticCount(0),173_memberAccessFlags(0),174_innerClassCount(0),175_enclosedInnerClassCount(0),176#if JAVA_SPEC_VERSION >= 11177_nestMembersCount(0),178_nestHost(0),179#endif /* JAVA_SPEC_VERSION >= 11 */180_maxBranchCount(1), /* This is required to support buffer size calculations for stackmap support code */181_outerClassNameIndex(0),182_simpleNameIndex(0),183_hasEmptyFinalizeMethod(false),184_hasFinalFields(false),185_hasNonStaticNonAbstractMethods(false),186_hasFinalizeMethod(false),187_isCloneable(false),188_isSerializable(false),189_isSynthetic(false),190_hasVerifyExcludeAttribute(false),191_hasFrameIteratorSkipAnnotation(false),192_hasClinit(false),193_annotationRefersDoubleSlotEntry(false),194_fieldsInfo(NULL),195_methodsInfo(NULL),196_recordComponentsInfo(NULL),197_genericSignature(NULL),198_enclosingMethod(NULL),199_sourceFile(NULL),200_sourceDebugExtension(NULL),201_annotationsAttribute(NULL),202_typeAnnotationsAttribute(NULL),203_innerClasses(NULL),204_bootstrapMethodsAttribute(NULL),205#if JAVA_SPEC_VERSION >= 11206_nestMembers(NULL),207#endif /* JAVA_SPEC_VERSION >= 11 */208_isClassContended(false),209_isClassUnmodifiable(context->isClassUnmodifiable()),210_isInnerClass(false),211_needsStaticConstantInit(false),212_isRecord(false),213#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)214_hasIdentityInterface(false),215_isIdentityInterfaceNeeded(false),216_isValueType(false),217_hasNonStaticSynchronizedMethod(false),218_hasNonStaticFields(false),219_hasNonEmptyConstructor(false),220#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */221_recordComponentCount(0),222_permittedSubclassesAttribute(NULL),223_isSealed(false),224_isClassValueBased(false)225{226Trc_BCU_Assert_NotEquals( classFile, NULL );227228ROMClassVerbosePhase v(_context, ClassFileAnalysis, &_buildResult);229230231/* Quick check against expected class name */232_buildResult = _context->checkClassName(getUTF8Data(getClassNameIndex()), getUTF8Length(getClassNameIndex()));233if (OK != _buildResult) {234return;235}236237_fieldsInfo = (FieldInfo *) _bufferManager->alloc(getFieldsCount() * sizeof(FieldInfo));238_methodsInfo = (MethodInfo *) _bufferManager->alloc(getMethodsCount() * sizeof(MethodInfo));239if ( (NULL == _fieldsInfo) || (NULL == _methodsInfo) ) {240Trc_BCU_ClassFileOracle_OutOfMemory((U_32)getUTF8Length(getClassNameIndex()), getUTF8Data(getClassNameIndex()));241_buildResult = OutOfMemory;242return;243}244memset(_fieldsInfo, 0, getFieldsCount() * sizeof(FieldInfo));245memset(_methodsInfo, 0, getMethodsCount() * sizeof(MethodInfo));246247_constantPoolMap->setClassFileOracleAndInitialize(this);248if ( !constantPoolMap->isOK() ) {249_buildResult = _constantPoolMap->getBuildResult();250return;251}252#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)253if (J9_ARE_ALL_BITS_SET(_classFile->accessFlags, CFR_ACC_VALUE_TYPE)254|| J9_ARE_NO_BITS_SET(_classFile->accessFlags, CFR_ACC_ABSTRACT | CFR_ACC_INTERFACE)255) {256/**257* We care about whether there is a non-empty constructor only for non-value type abstract classes.258* Simply set _hasNonEmptyConstructor to true for value types, or concrete classes.259*/260_hasNonEmptyConstructor = true;261}262#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */263264/* analyze class file */265266if (OK == _buildResult) {267walkHeader();268}269if (OK == _buildResult) {270walkAttributes();271}272273if (_context->isClassHidden()) {274checkHiddenClass();275}276277if (OK == _buildResult) {278walkInterfaces();279}280281282if (OK == _buildResult) {283walkMethods();284}285286if (OK == _buildResult) {287walkFields();288}289290#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)291if (OK == _buildResult) {292checkAndRecordIsIdentityInterfaceNeeded();293}294#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */295if (OK == _buildResult) {296_constantPoolMap->computeConstantPoolMapAndSizes();297if (!constantPoolMap->isOK()) {298_buildResult = _constantPoolMap->getBuildResult();299} else {300#if defined(J9VM_OPT_METHOD_HANDLE)301/* computeConstantPoolMapAndSizes must complete successfully before calling findVarHandleMethodRefs */302_constantPoolMap->findVarHandleMethodRefs();303if (!constantPoolMap->isOK()) {304_buildResult = _constantPoolMap->getBuildResult();305}306#endif /* defined(J9VM_OPT_METHOD_HANDLE) */307}308}309310}311312ClassFileOracle::~ClassFileOracle()313{314if (NULL != _methodsInfo && OutOfMemory != _buildResult) {315for (U_16 methodIndex = 0; methodIndex < _classFile->methodsCount; ++methodIndex) {316_bufferManager->free(_methodsInfo[methodIndex].stackMapFramesInfo);317_bufferManager->free(_methodsInfo[methodIndex].localVariablesInfo);318_bufferManager->free(_methodsInfo[methodIndex].lineNumbersInfoCompressed);319}320}321_bufferManager->free(_methodsInfo);322_bufferManager->free(_fieldsInfo);323324}325326void327ClassFileOracle::walkHeader()328{329ROMClassVerbosePhase v(_context, ClassFileHeaderAnalysis);330331markConstantUTF8AsReferenced(getClassNameIndex());332U_16 superClassNameIndex = getSuperClassNameIndex();333if (0 != superClassNameIndex) { /* java/lang/Object has no super class */334markConstantUTF8AsReferenced(superClassNameIndex);335}336}337338void339ClassFileOracle::walkFields()340{341ROMClassVerbosePhase v(_context, ClassFileFieldsAnalysis);342343344U_16 fieldsCount = getFieldsCount();345346/* CMVC 197718 : After the first compliance offense is detected, if we do not stop, annotations on subsequent fields347* will not be parsed, resulting in all subsequent valid fields to be noted as not having proper @Length annotation, hence overwriting348* the good error message. Checking (OK == _buildResult) in for-loop condition achieves the desired error handling behavior.349*/350for (U_16 fieldIndex = 0; (OK == _buildResult) && (fieldIndex < fieldsCount); fieldIndex++) {351J9CfrField *field = &_classFile->fields[fieldIndex];352U_8 fieldChar = _classFile->constantPool[field->descriptorIndex].bytes[0];353bool isStatic = (0 != (field->accessFlags & CFR_ACC_STATIC));354355356markConstantUTF8AsReferenced(field->nameIndex);357markConstantUTF8AsReferenced(field->descriptorIndex);358359if (isStatic) {360if (NULL != field->constantValueAttribute) {361_needsStaticConstantInit = true;362U_16 constantValueIndex = field->constantValueAttribute->constantValueIndex;363if (CFR_CONSTANT_String == _classFile->constantPool[constantValueIndex].tag) {364markStringAsReferenced(constantValueIndex);365}366}367if ((IS_REF_OR_VAL_SIGNATURE(fieldChar))368|| ('[' == fieldChar)369) {370_objectStaticCount++;371} else if (('D' == fieldChar) || ('J' == fieldChar)) {372_doubleScalarStaticCount++;373} else {374_singleScalarStaticCount++;375}376} else {377if (0 != (field->accessFlags & CFR_ACC_FINAL)) {378/* if the class has any final instance fields, mark it so that we can generate379* the appropriate memory barriers when its constructors run. See380* JBreturnFromConstructor381*/382_hasFinalFields = true;383}384#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)385_hasNonStaticFields = true;386#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */387}388389for (U_16 attributeIndex = 0; (OK == _buildResult) && (attributeIndex < field->attributesCount); ++attributeIndex) {390J9CfrAttribute * attrib = field->attributes[attributeIndex];391switch (attrib->tag) {392case CFR_ATTRIBUTE_Signature: {393J9CfrAttributeSignature *signature = (J9CfrAttributeSignature *) attrib;394markConstantUTF8AsReferenced(signature->signatureIndex);395_fieldsInfo[fieldIndex].hasGenericSignature = true;396_fieldsInfo[fieldIndex].genericSignatureIndex = signature->signatureIndex;397break;398}399case CFR_ATTRIBUTE_Synthetic:400_fieldsInfo[fieldIndex].isSynthetic = true;401break;402case CFR_ATTRIBUTE_RuntimeVisibleAnnotations: {403J9CfrAttributeRuntimeVisibleAnnotations *attribAnnotations = (J9CfrAttributeRuntimeVisibleAnnotations *)attrib;404UDATA knownAnnotations = 0;405if ((NULL != _context->javaVM()) && (J9_ARE_ALL_BITS_SET(_context->javaVM()->extendedRuntimeFlags, J9_EXTENDED_RUNTIME_ALLOW_CONTENDED_FIELDS)) &&406(_context->isBootstrapLoader() || (J9_ARE_ALL_BITS_SET(_context->javaVM()->extendedRuntimeFlags, J9_EXTENDED_RUNTIME_ALLOW_APPLICATION_CONTENDED_FIELDS)))) {407knownAnnotations = addAnnotationBit(knownAnnotations, CONTENDED_ANNOTATION);408knownAnnotations = addAnnotationBit(knownAnnotations, JAVA8_CONTENDED_ANNOTATION);409}410if (0 == attribAnnotations->rawDataLength) {411UDATA foundAnnotations = walkAnnotations(attribAnnotations->numberOfAnnotations, attribAnnotations->annotations, knownAnnotations);412413414if (containsKnownAnnotation(foundAnnotations, CONTENDED_ANNOTATION) || containsKnownAnnotation(foundAnnotations, JAVA8_CONTENDED_ANNOTATION)) {415_fieldsInfo[fieldIndex].isFieldContended = true;416}417}418_fieldsInfo[fieldIndex].annotationsAttribute = attribAnnotations;419break;420}421case CFR_ATTRIBUTE_RuntimeVisibleTypeAnnotations: {422J9CfrAttributeRuntimeVisibleTypeAnnotations *typeAnnotations = (J9CfrAttributeRuntimeVisibleTypeAnnotations *)attrib;423if (0 == typeAnnotations->rawDataLength) { /* rawDataLength non-zero in case of error in the attribute */424walkTypeAnnotations(typeAnnotations->numberOfAnnotations, typeAnnotations->typeAnnotations);425}426_fieldsInfo[fieldIndex].typeAnnotationsAttribute = typeAnnotations;427break;428}429case CFR_ATTRIBUTE_ConstantValue:430/* Fall through */431case CFR_ATTRIBUTE_Deprecated:432/* Do nothing */433break;434default:435Trc_BCU_ClassFileOracle_walkFields_UnknownAttribute((U_32)attrib->tag, (U_32)getUTF8Length(attrib->nameIndex), getUTF8Data(attrib->nameIndex), attrib->length);436break;437}438}439440}441442}443444void445ClassFileOracle::walkAttributes()446{447ROMClassVerbosePhase v(_context, ClassFileAttributesAnalysis);448449for (U_16 attributeIndex = 0; attributeIndex < _classFile->attributesCount; attributeIndex++) {450J9CfrAttribute *attrib = _classFile->attributes[attributeIndex];451switch (attrib->tag) {452case CFR_ATTRIBUTE_InnerClasses: {453J9CfrAttributeInnerClasses *classes = (J9CfrAttributeInnerClasses*)attrib;454U_16 thisClassUTF8 = UTF8_INDEX_FROM_CLASS_INDEX(_classFile->constantPool, _classFile->thisClass);455for (U_16 classIndex = 0; classIndex < classes->numberOfClasses; classIndex++) {456J9CfrClassesEntry *entry = &(classes->classes[classIndex]);457U_16 outerClassUTF8 = UTF8_INDEX_FROM_CLASS_INDEX(_classFile->constantPool, entry->outerClassInfoIndex);458U_16 innerClassUTF8 = UTF8_INDEX_FROM_CLASS_INDEX(_classFile->constantPool, entry->innerClassInfoIndex);459460/* In some cases, there might be two entries for the same class.461* But the UTF8 classname entry will be only one.462* Therefore comparing the UTF8 will find the matches, while comparing the class entries will not463*/464if (outerClassUTF8 == thisClassUTF8) {465/* Member class - mark the class' name. */466markClassNameAsReferenced(entry->innerClassInfoIndex);467_innerClassCount += 1;468} else if (innerClassUTF8 == thisClassUTF8) {469_isInnerClass = true;470_memberAccessFlags = entry->innerClassAccessFlags;471/* We are an inner class - a member? */472if (entry->outerClassInfoIndex != 0) {473/* We are a member class - mark the outer class name. */474markClassNameAsReferenced(entry->outerClassInfoIndex);475_outerClassNameIndex = outerClassUTF8;476}477if (entry->innerNameIndex != 0) {478/* mark the simple class name of member, local, and anonymous classes */479markConstantUTF8AsReferenced(entry->innerNameIndex);480_simpleNameIndex = entry->innerNameIndex;481}482} else {483/* Count all entries in the InnerClass attribute (except the inner class itself) so as484* to check the InnerClass attribute between the inner classes and the enclosing class.485* See getDeclaringClass() for details.486*/487markClassNameAsReferenced(entry->innerClassInfoIndex);488_enclosedInnerClassCount += 1;489}490}491Trc_BCU_Assert_Equals(NULL, _innerClasses);492_innerClasses = classes;493break;494}495case CFR_ATTRIBUTE_Signature:496_genericSignature = (J9CfrAttributeSignature *)attrib;497markConstantUTF8AsReferenced(_genericSignature->signatureIndex);498break;499case CFR_ATTRIBUTE_EnclosingMethod:500_enclosingMethod = (J9CfrAttributeEnclosingMethod *)attrib;501markClassAsReferenced(_enclosingMethod->classIndex);502if (0 != _enclosingMethod->methodIndex) {503markNameAndDescriptorAsReferenced(_enclosingMethod->methodIndex);504}505break;506case CFR_ATTRIBUTE_Synthetic:507_isSynthetic = true;508break;509case CFR_ATTRIBUTE_SourceFile:510if (!hasSourceFile() && _context->shouldPreserveSourceFileName()) {511_sourceFile = (J9CfrAttributeSourceFile *)attrib;512markConstantUTF8AsReferenced(_sourceFile->sourceFileIndex);513}514break;515case CFR_ATTRIBUTE_SourceDebugExtension:516if (!hasSourceDebugExtension()) {517_sourceDebugExtension = (J9CfrAttributeUnknown *)attrib;518}519break;520case CFR_ATTRIBUTE_RuntimeVisibleAnnotations: {521UDATA knownAnnotations = 0;522if ((NULL != _context->javaVM()) && J9_ARE_ALL_BITS_SET(_context->javaVM()->extendedRuntimeFlags, J9_EXTENDED_RUNTIME_ALLOW_CONTENDED_FIELDS) &&523(_context->isBootstrapLoader() || (J9_ARE_ALL_BITS_SET(_context->javaVM()->extendedRuntimeFlags, J9_EXTENDED_RUNTIME_ALLOW_APPLICATION_CONTENDED_FIELDS)))) {524knownAnnotations = addAnnotationBit(knownAnnotations, CONTENDED_ANNOTATION);525knownAnnotations = addAnnotationBit(knownAnnotations, JAVA8_CONTENDED_ANNOTATION);526}527knownAnnotations = addAnnotationBit(knownAnnotations, UNMODIFIABLE_ANNOTATION);528knownAnnotations = addAnnotationBit(knownAnnotations, VALUEBASED_ANNOTATION);529_annotationsAttribute = (J9CfrAttributeRuntimeVisibleAnnotations *)attrib;530if (0 == _annotationsAttribute->rawDataLength) {531UDATA foundAnnotations = walkAnnotations(_annotationsAttribute->numberOfAnnotations, _annotationsAttribute->annotations, knownAnnotations);532if (containsKnownAnnotation(foundAnnotations, CONTENDED_ANNOTATION) || containsKnownAnnotation(foundAnnotations, JAVA8_CONTENDED_ANNOTATION)) {533_isClassContended = true;534}535if (containsKnownAnnotation(foundAnnotations, UNMODIFIABLE_ANNOTATION)) {536_isClassUnmodifiable = true;537}538if (containsKnownAnnotation(foundAnnotations, VALUEBASED_ANNOTATION)) {539_isClassValueBased = true;540}541}542break;543}544case CFR_ATTRIBUTE_RuntimeVisibleTypeAnnotations: {545J9CfrAttributeRuntimeVisibleTypeAnnotations *typeAnnotations = (J9CfrAttributeRuntimeVisibleTypeAnnotations *)attrib;546if (0 == typeAnnotations->rawDataLength) { /* rawDataLength non-zero in case of error in the attribute */547walkTypeAnnotations(typeAnnotations->numberOfAnnotations, typeAnnotations->typeAnnotations);548}549_typeAnnotationsAttribute = typeAnnotations;550break;551}552case CFR_ATTRIBUTE_BootstrapMethods: {553_bootstrapMethodsAttribute = (J9CfrAttributeBootstrapMethods *)attrib;554for (U_16 methodIndex = 0; methodIndex < _bootstrapMethodsAttribute->numberOfBootstrapMethods; methodIndex++) {555J9CfrBootstrapMethod *bootstrapMethod = _bootstrapMethodsAttribute->bootstrapMethods + methodIndex;556markMethodHandleAsReferenced(bootstrapMethod->bootstrapMethodIndex);557for (U_16 argumentIndex = 0; argumentIndex < bootstrapMethod->numberOfBootstrapArguments; argumentIndex++) {558U_16 argCpIndex = bootstrapMethod->bootstrapArguments[argumentIndex];559markConstantBasedOnCpType(argCpIndex, false);560}561}562break;563}564case CFR_ATTRIBUTE_Record: {565_isRecord = true;566walkRecordComponents((J9CfrAttributeRecord *)attrib);567break;568}569case CFR_ATTRIBUTE_PermittedSubclasses: {570/* PermittedSubclasses verification is for Java version >= 15 */571if ((_classFile->majorVersion > 59)572|| ((59 == _classFile->majorVersion) && (65535 == _classFile->minorVersion))573) {574_isSealed = true;575_permittedSubclassesAttribute = (J9CfrAttributePermittedSubclasses *)attrib;576for (U_16 numberOfClasses = 0; numberOfClasses < _permittedSubclassesAttribute->numberOfClasses; numberOfClasses++) {577U_16 classCpIndex = _permittedSubclassesAttribute->classes[numberOfClasses];578markClassAsReferenced(classCpIndex);579}580}581break;582}583#if JAVA_SPEC_VERSION >= 11584case CFR_ATTRIBUTE_NestMembers:585/* ignore CFR_ATTRIBUTE_NestMembers for hidden classes, as the nest members never know the name of hidden classes */586if (!_context->isClassHidden()) {587_nestMembers = (J9CfrAttributeNestMembers *)attrib;588_nestMembersCount = _nestMembers->numberOfClasses;589/* The classRefs are never resolved & therefore do not need to590* be kept in the constant pool.591*/592for (U_16 i = 0; i < _nestMembersCount; i++) {593U_16 classNameIndex = UTF8_INDEX_FROM_CLASS_INDEX(_classFile->constantPool, _nestMembers->classes[i]);594markConstantUTF8AsReferenced(classNameIndex);595}596}597break;598599case CFR_ATTRIBUTE_NestHost: {600/* Ignore CFR_ATTRIBUTE_NestHost for hidden classes, as the nest host of a hidden class is not decided by CFR_ATTRIBUTE_NestHost.601* The nesthost of a hidden class is its host class if ClassOption.NESTMATE is used or itself if ClassOption.NESTMATE is not used. */602if (!_context->isClassHidden()) {603U_16 hostClassIndex = ((J9CfrAttributeNestHost *)attrib)->hostClassIndex;604_nestHost = UTF8_INDEX_FROM_CLASS_INDEX(_classFile->constantPool, hostClassIndex);605markConstantUTF8AsReferenced(_nestHost);606}607break;608}609#endif /* JAVA_SPEC_VERSION >= 11 */610default:611Trc_BCU_ClassFileOracle_walkAttributes_UnknownAttribute((U_32)attrib->tag, (U_32)getUTF8Length(attrib->nameIndex), getUTF8Data(attrib->nameIndex), attrib->length);612break;613}614if (!_hasVerifyExcludeAttribute && (NULL != _verifyExcludeAttribute)) {615U_8 *found = (U_8 *) strstr((const char *)_verifyExcludeAttribute, (const char *)getUTF8Data(attrib->nameIndex));616if ((NULL != found)617&& ((found == _verifyExcludeAttribute) || (';' == (*(found - 1))))618&& (('\0' == found[getUTF8Length(attrib->nameIndex)]) || (';' == found[getUTF8Length(attrib->nameIndex)]))) {619_hasVerifyExcludeAttribute = true;620}621}622}623}624625void626ClassFileOracle::checkHiddenClass()627{628ROMClassVerbosePhase v(_context, ClassFileAttributesAnalysis);629/* Hidden Class cannot be a record or enum. */630U_16 superClassNameIndex = getSuperClassNameIndex();631bool isEnum = false;632633/**634* See test case jdk/java/lang/invoke/defineHiddenClass/BasicTest.emptyHiddenClass().635* A normal Enum cannot be defined as a hidden class. But an empty enum class that does not636* define constants of its type can still be defined as a hidden class.637* So when setting isEnum, add a check for field count.638*/639if (0 != superClassNameIndex) {640isEnum = J9_ARE_ALL_BITS_SET(_classFile->accessFlags, CFR_ACC_ENUM) &&641J9UTF8_DATA_EQUALS(getUTF8Data(superClassNameIndex), getUTF8Length(superClassNameIndex), "java/lang/Enum", LITERAL_STRLEN("java/lang/Enum")) &&642(getFieldsCount() > 0);643}644if (_isRecord || isEnum) {645PORT_ACCESS_FROM_PORT(_context->portLibrary());646char msg[] = "Hidden Class cannot be a record or enum";647UDATA len = sizeof(msg);648char *error = (char *) j9mem_allocate_memory(len, J9MEM_CATEGORY_CLASSES);649if (NULL != error) {650strcpy(error, msg);651_context->recordCFRError((U_8*)error);652}653_buildResult = InvalidClassType;654}655}656657void658ClassFileOracle::walkRecordComponents(J9CfrAttributeRecord *attrib)659{660ROMClassVerbosePhase v(_context, ClassFileAttributesRecordAnalysis);661662if (0 == attrib->numberOfRecordComponents) {663return;664}665666_recordComponentCount = attrib->numberOfRecordComponents;667668_recordComponentsInfo = (RecordComponentInfo *) _bufferManager->alloc(_recordComponentCount * sizeof(RecordComponentInfo));669if (NULL == _recordComponentsInfo) {670Trc_BCU_ClassFileOracle_OutOfMemory((U_32)getUTF8Length(getClassNameIndex()), getUTF8Data(getClassNameIndex()));671_buildResult = OutOfMemory;672return;673}674memset(_recordComponentsInfo, 0, _recordComponentCount * sizeof(RecordComponentInfo));675676for (U_16 i = 0; i < _recordComponentCount; i++) {677J9CfrRecordComponent* recordComponent = &attrib->recordComponents[i];678679markConstantUTF8AsReferenced(recordComponent->nameIndex);680_recordComponentsInfo[i].nameIndex = recordComponent->nameIndex;681markConstantUTF8AsReferenced(recordComponent->descriptorIndex);682_recordComponentsInfo[i].descriptorIndex = recordComponent->descriptorIndex;683684/* track record component attributes */685for (U_16 j = 0; j < recordComponent->attributesCount; j++) {686J9CfrAttribute* recordComponentAttr = recordComponent->attributes[j];687switch(recordComponentAttr->tag) {688case CFR_ATTRIBUTE_Signature: {689J9CfrAttributeSignature *signature = (J9CfrAttributeSignature *) recordComponentAttr;690markConstantUTF8AsReferenced(signature->signatureIndex);691_recordComponentsInfo[i].hasGenericSignature = true;692_recordComponentsInfo[i].genericSignatureIndex = signature->signatureIndex;693break;694}695case CFR_ATTRIBUTE_RuntimeVisibleAnnotations: {696J9CfrAttributeRuntimeVisibleAnnotations *recordComponentAnnotations = (J9CfrAttributeRuntimeVisibleAnnotations *)recordComponentAttr;697if (0 == recordComponentAnnotations->rawDataLength) {698walkAnnotations(recordComponentAnnotations->numberOfAnnotations, recordComponentAnnotations->annotations, 0);699}700_recordComponentsInfo[i].annotationsAttribute = recordComponentAnnotations;701break;702}703case CFR_ATTRIBUTE_RuntimeVisibleTypeAnnotations: {704J9CfrAttributeRuntimeVisibleTypeAnnotations *recordComponentTypeAnnotations = (J9CfrAttributeRuntimeVisibleTypeAnnotations *)recordComponentAttr;705if (0 == recordComponentTypeAnnotations->rawDataLength) {706walkTypeAnnotations(recordComponentTypeAnnotations->numberOfAnnotations, recordComponentTypeAnnotations->typeAnnotations);707}708_recordComponentsInfo[i].typeAnnotationsAttribute = recordComponentTypeAnnotations;709break;710}711default:712Trc_BCU_ClassFileOracle_walkRecordComponents_UnknownAttribute((U_32)attrib->tag, (U_32)getUTF8Length(attrib->nameIndex), getUTF8Data(attrib->nameIndex), attrib->length);713break;714}715}716}717}718719class ClassFileOracle::InterfaceVisitor : public ClassFileOracle::ConstantPoolIndexVisitor720{721public:722InterfaceVisitor(ClassFileOracle *classFileOracle, ConstantPoolMap *constantPoolMap) :723_classFileOracle(classFileOracle),724_constantPoolMap(constantPoolMap),725#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)726_wasIdentityInterfaceSeen(false),727#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */728_wasCloneableSeen(false),729_wasSerializableSeen(false)730{731}732733void visitConstantPoolIndex(U_16 cpIndex)734{735_constantPoolMap->markConstantUTF8AsReferenced(cpIndex);736#define CLONEABLE_NAME "java/lang/Cloneable"737if( _classFileOracle->isUTF8AtIndexEqualToString(cpIndex, CLONEABLE_NAME, sizeof(CLONEABLE_NAME)) ) {738_wasCloneableSeen = true;739}740#undef CLONEABLE_NAME741742#define SERIALIZABLE_NAME "java/io/Serializable"743if( _classFileOracle->isUTF8AtIndexEqualToString(cpIndex, SERIALIZABLE_NAME, sizeof(SERIALIZABLE_NAME)) ) {744_wasSerializableSeen = true;745}746#undef SERIALIZABLE_NAME747748#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)749if( _classFileOracle->isUTF8AtIndexEqualToString(cpIndex, IDENTITY_OBJECT_NAME, sizeof(IDENTITY_OBJECT_NAME)) ) {750_wasIdentityInterfaceSeen = true;751}752#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */753}754755bool wasCloneableSeen() const { return _wasCloneableSeen; }756bool wasSerializableSeen() const { return _wasSerializableSeen; }757#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)758bool wasIdentityInterfaceSeen() const { return _wasIdentityInterfaceSeen; }759#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */760761private:762ClassFileOracle *_classFileOracle;763ConstantPoolMap *_constantPoolMap;764bool _wasCloneableSeen;765bool _wasSerializableSeen;766#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)767bool _wasIdentityInterfaceSeen;768#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */769};770771void772ClassFileOracle::walkInterfaces()773{774ROMClassVerbosePhase v(_context, ClassFileInterfacesAnalysis);775776InterfaceVisitor interfaceVisitor(this, _constantPoolMap);777#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)778interfacesDo(&interfaceVisitor, 0);779#else780interfacesDo(&interfaceVisitor);781#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */782_isCloneable = interfaceVisitor.wasCloneableSeen();783_isSerializable = interfaceVisitor.wasSerializableSeen();784#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)785if (J9_ARE_ALL_BITS_SET(_classFile->accessFlags, CFR_ACC_VALUE_TYPE)) {786_isValueType = true;787}788_hasIdentityInterface = interfaceVisitor.wasIdentityInterfaceSeen();789#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */790}791792#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)793void794ClassFileOracle::checkAndRecordIsIdentityInterfaceNeeded()795{796if (isValueType()) {797if (_hasIdentityInterface798|| J9_ARE_ANY_BITS_SET(_classFile->accessFlags, CFR_ACC_ABSTRACT | CFR_ACC_INTERFACE)799|| _hasNonStaticSynchronizedMethod800) {801_buildResult = InvalidValueType;802}803} else {804if (!_hasIdentityInterface805&& (getSuperClassNameIndex() != 0) /* j.l.Object has no superClass */806) {807if (J9_ARE_NO_BITS_SET(_classFile->accessFlags, CFR_ACC_ABSTRACT | CFR_ACC_INTERFACE)) {808/* For concrete classes, IdentityInterface is needed. */809_isIdentityInterfaceNeeded = true;810} else {811/**812* For abstract classes, IdentityInterface is needed only when it has non-static fields,813* non-static synchronized method or non-empty constructor.814*/815if ((_hasNonStaticFields)816|| (_hasNonStaticSynchronizedMethod)817|| (_hasNonEmptyConstructor)818) {819_isIdentityInterfaceNeeded = true;820}821}822}823}824}825#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */826827void828ClassFileOracle::walkMethods()829{830ROMClassVerbosePhase v(_context, ClassFileMethodsAnalysis);831832U_16 methodsCount = getMethodsCount();833/* We check (OK == _buildResult) because walkMethodCodeAttribute() may fail to alloc the bytecode fixup table. */834for (U_16 methodIndex = 0; (methodIndex < methodsCount) && (OK == _buildResult); ++methodIndex) {835U_16 nameIndex = _classFile->methods[methodIndex].nameIndex;836U_16 descIndex = _classFile->methods[methodIndex].descriptorIndex;837markConstantUTF8AsReferenced(nameIndex);838markConstantUTF8AsReferenced(descIndex);839840841walkMethodAttributes(methodIndex);842843_methodsInfo[methodIndex].modifiers |= _classFile->methods[methodIndex].accessFlags;844845/* Is this an empty method, a getter, a forwarder or <clinit>?846* Note that <clinit> is checked after empty, so we will consider847* classes with an empty <clinit> to not have one.848*/849if (methodIsEmpty(methodIndex)) {850_methodsInfo[methodIndex].modifiers |= J9AccEmptyMethod;851} else if (methodIsForwarder(methodIndex)) {852_methodsInfo[methodIndex].modifiers |= J9AccForwarderMethod;853} else if (methodIsGetter(methodIndex)) {854_methodsInfo[methodIndex].modifiers |= J9AccGetterMethod;855} else if (methodIsClinit(methodIndex)) {856_hasClinit = true;857}858859if (methodIsObjectConstructor(methodIndex)) {860_methodsInfo[methodIndex].modifiers |= J9AccMethodObjectConstructor;861}862863#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)864if (!_hasNonEmptyConstructor) {865if (methodIsConstructor(methodIndex)) {866/* Do not record constructor forwarded to its superclass. */867if (J9_ARE_NO_BITS_SET(_methodsInfo[methodIndex].modifiers, J9AccForwarderMethod)) {868_hasNonEmptyConstructor = true;869}870}871}872#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */873874/* does the method belong in vtables? */875if (methodIsVirtual(methodIndex)) {876_methodsInfo[methodIndex].modifiers |= J9AccMethodVTable;877}878879/* Does this class contain non-static, non-abstract methods? */880if (!_hasNonStaticNonAbstractMethods) {881_hasNonStaticNonAbstractMethods = methodIsNonStaticNonAbstract(methodIndex);882}883884/* Look for an instance selector whose name is finalize()V */885if (methodIsFinalize(methodIndex, 0 != (_methodsInfo[methodIndex].modifiers & J9AccForwarderMethod))) {886_hasFinalizeMethod = true;887/* If finalize() is empty, mark this class so it does not inherit CFR_ACC_FINALIZE_NEEDED from its superclass */888if (0 != (_methodsInfo[methodIndex].modifiers & J9AccEmptyMethod)) {889_hasEmptyFinalizeMethod = true;890}891}892#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)893if (!_hasNonStaticSynchronizedMethod) {894_hasNonStaticSynchronizedMethod = methodIsNonStaticSynchronized(methodIndex);895}896#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */897898computeSendSlotCount(methodIndex);899900walkMethodThrownExceptions(methodIndex);901walkMethodCodeAttribute(methodIndex);902walkMethodMethodParametersAttribute(methodIndex);903}904905}906907void908ClassFileOracle::walkMethodAttributes(U_16 methodIndex)909{910ROMCLASS_VERBOSE_PHASE_HOT(_context, ClassFileMethodAttributesAnalysis);911912for (U_16 methodAttrIndex = 0; (methodAttrIndex < _classFile->methods[methodIndex].attributesCount) && (OK == _buildResult); ++methodAttrIndex){913J9CfrAttribute *attrib = _classFile->methods[methodIndex].attributes[methodAttrIndex];914switch (attrib->tag) {915case CFR_ATTRIBUTE_Synthetic:916_methodsInfo[methodIndex].modifiers |= J9AccSynthetic;917break;918case CFR_ATTRIBUTE_Signature: {919J9CfrAttributeSignature *signature = (J9CfrAttributeSignature *) attrib;920markConstantUTF8AsReferenced(signature->signatureIndex);921_methodsInfo[methodIndex].modifiers |= J9AccMethodHasGenericSignature;922_methodsInfo[methodIndex].genericSignatureIndex = signature->signatureIndex;923break;924}925case CFR_ATTRIBUTE_RuntimeVisibleAnnotations: {926UDATA knownAnnotations = 0;927knownAnnotations = addAnnotationBit(knownAnnotations, FRAMEITERATORSKIP_ANNOTATION);928knownAnnotations = addAnnotationBit(knownAnnotations, SUN_REFLECT_CALLERSENSITIVE_ANNOTATION);929knownAnnotations = addAnnotationBit(knownAnnotations, JDK_INTERNAL_REFLECT_CALLERSENSITIVE_ANNOTATION);930#if JAVA_SPEC_VERSION >= 18931knownAnnotations = addAnnotationBit(knownAnnotations, JDK_INTERNAL_REFLECT_CALLERSENSITIVEADAPTER_ANNOTATION);932#endif /* JAVA_SPEC_VERSION >= 18*/933#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)934knownAnnotations = addAnnotationBit(knownAnnotations, HIDDEN_ANNOTATION);935#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */936#if JAVA_SPEC_VERSION >= 16937knownAnnotations = addAnnotationBit(knownAnnotations, SCOPED_ANNOTATION);938#endif /* JAVA_SPEC_VERSION >= 16*/939940J9CfrAttributeRuntimeVisibleAnnotations *attribAnnotations = (J9CfrAttributeRuntimeVisibleAnnotations *)attrib;941if (0 == attribAnnotations->rawDataLength) { /* rawDataLength non-zero in case of error in the attribute */942UDATA foundAnnotations = walkAnnotations(attribAnnotations->numberOfAnnotations, attribAnnotations->annotations, knownAnnotations);943if (containsKnownAnnotation(foundAnnotations, SUN_REFLECT_CALLERSENSITIVE_ANNOTATION)944|| containsKnownAnnotation(foundAnnotations, JDK_INTERNAL_REFLECT_CALLERSENSITIVE_ANNOTATION)945#if JAVA_SPEC_VERSION >= 18946|| containsKnownAnnotation(foundAnnotations, JDK_INTERNAL_REFLECT_CALLERSENSITIVEADAPTER_ANNOTATION)947#endif /* JAVA_SPEC_VERSION >= 18*/948) {949_methodsInfo[methodIndex].modifiers |= J9AccMethodCallerSensitive;950}951if (_context->isBootstrapLoader()) {952/* Only check for FrameIteratorSkip annotation on bootstrap classes */953if (containsKnownAnnotation(foundAnnotations, FRAMEITERATORSKIP_ANNOTATION)) {954_methodsInfo[methodIndex].modifiers |= J9AccMethodFrameIteratorSkip;955}956}957#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)958if (containsKnownAnnotation(foundAnnotations, HIDDEN_ANNOTATION)) {959/* J9AccMethodFrameIteratorSkip is reused for Hidden Annotation when OpenJDK MH is enabled960* Hidden annotation is used by OpenJDK to tag LambdaForm generated methods which is similar961* to the thunkArchetype methods as they both need to be skipped during stackwalk when962* verifying the caller963*/964_methodsInfo[methodIndex].modifiers |= J9AccMethodFrameIteratorSkip;965}966#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */967#if JAVA_SPEC_VERSION >= 16968if (containsKnownAnnotation(foundAnnotations, SCOPED_ANNOTATION)) {969/* J9AccMethodHasExtendedModifiers in the modifiers is set when the ROM class is written */970_methodsInfo[methodIndex].extendedModifiers |= CFR_METHOD_EXT_HAS_SCOPED_ANNOTATION;971}972#endif /* JAVA_SPEC_VERSION >= 16*/973}974_methodsInfo[methodIndex].annotationsAttribute = attribAnnotations;975_methodsInfo[methodIndex].modifiers |= J9AccMethodHasMethodAnnotations;976break;977}978case CFR_ATTRIBUTE_RuntimeVisibleParameterAnnotations: {979J9CfrAttributeRuntimeVisibleParameterAnnotations *attribParameterAnnotations = (J9CfrAttributeRuntimeVisibleParameterAnnotations *)attrib;980for (U_8 parameterAnnotationIndex = 0;981(parameterAnnotationIndex < attribParameterAnnotations->numberOfParameters) && (OK == _buildResult);982++parameterAnnotationIndex) {983walkAnnotations(984attribParameterAnnotations->parameterAnnotations[parameterAnnotationIndex].numberOfAnnotations,985attribParameterAnnotations->parameterAnnotations[parameterAnnotationIndex].annotations,9860);987}988_methodsInfo[methodIndex].parameterAnnotationsAttribute = attribParameterAnnotations;989_methodsInfo[methodIndex].modifiers |= J9AccMethodHasParameterAnnotations;990break;991}992case CFR_ATTRIBUTE_RuntimeVisibleTypeAnnotations: {993J9CfrAttributeRuntimeVisibleTypeAnnotations *typeAnnotations = (J9CfrAttributeRuntimeVisibleTypeAnnotations *)attrib;994if (0 == typeAnnotations->rawDataLength) { /* rawDataLength non-zero in case of error in the attribute */995walkTypeAnnotations(typeAnnotations->numberOfAnnotations, typeAnnotations->typeAnnotations);996}997_methodsInfo[methodIndex].methodTypeAnnotationsAttribute = typeAnnotations;998/* J9AccMethodHasExtendedModifiers in the modifiers is set when the ROM class is written */999_methodsInfo[methodIndex].extendedModifiers |= CFR_METHOD_EXT_HAS_METHOD_TYPE_ANNOTATIONS;1000break;1001}1002case CFR_ATTRIBUTE_AnnotationDefault:1003walkAnnotationElement(((J9CfrAttributeAnnotationDefault *)attrib)->defaultValue);1004_methodsInfo[methodIndex].defaultAnnotationAttribute = (J9CfrAttributeAnnotationDefault *)attrib;1005_methodsInfo[methodIndex].modifiers |= J9AccMethodHasDefaultAnnotation;1006break;1007case CFR_ATTRIBUTE_MethodParameters:1008/* Fall through */1009case CFR_ATTRIBUTE_Code:1010/* Fall through */1011case CFR_ATTRIBUTE_Exceptions:1012/* Fall through */1013case CFR_ATTRIBUTE_Deprecated:1014/* Do nothing */1015break;1016default:1017Trc_BCU_ClassFileOracle_walkMethods_UnknownAttribute((U_32)attrib->tag, (U_32)getUTF8Length(attrib->nameIndex), getUTF8Data(attrib->nameIndex), attrib->length);1018break;1019}1020}1021}10221023UDATA1024ClassFileOracle::walkAnnotations(U_16 annotationsCount, J9CfrAnnotation *annotations, UDATA knownAnnotations)1025{1026ROMClassVerbosePhase v(_context, ClassFileAnnotationsAnalysis);1027UDATA foundAnnotations = 0;10281029if (0 == knownAnnotations) {1030for (U_16 annotationsIndex = 0; (annotationsIndex < annotationsCount) &&(OK == _buildResult); ++annotationsIndex) {1031markConstantAsUsedByAnnotation(annotations[annotationsIndex].typeIndex);1032const U_16 elementValuePairsCount = annotations[annotationsIndex].numberOfElementValuePairs;1033for (U_16 elementValuePairsIndex = 0; (elementValuePairsIndex < elementValuePairsCount) && (OK == _buildResult); ++elementValuePairsIndex) {1034markConstantAsUsedByAnnotation(annotations[annotationsIndex].elementValuePairs[elementValuePairsIndex].elementNameIndex);1035walkAnnotationElement(annotations[annotationsIndex].elementValuePairs[elementValuePairsIndex].value);1036}1037}1038} else {1039for (U_16 annotationsIndex = 0; (annotationsIndex < annotationsCount) && (OK == _buildResult); ++annotationsIndex) {1040markConstantAsUsedByAnnotation(annotations[annotationsIndex].typeIndex);1041for (UDATA knownAnnotationIndex = 0; knownAnnotationIndex < KNOWN_ANNOTATION_COUNT; ++knownAnnotationIndex) {1042if (containsKnownAnnotation(knownAnnotations, knownAnnotationIndex) && isUTF8AtIndexEqualToString(annotations[annotationsIndex].typeIndex, _knownAnnotations[knownAnnotationIndex].name, _knownAnnotations[knownAnnotationIndex].size)) {1043foundAnnotations = addAnnotationBit(foundAnnotations, knownAnnotationIndex);1044}1045}1046const U_16 elementValuePairsCount = annotations[annotationsIndex].numberOfElementValuePairs;1047for (U_16 elementValuePairsIndex = 0; (elementValuePairsIndex < elementValuePairsCount) && (OK == _buildResult); ++elementValuePairsIndex) {1048markConstantAsUsedByAnnotation(annotations[annotationsIndex].elementValuePairs[elementValuePairsIndex].elementNameIndex);1049walkAnnotationElement(annotations[annotationsIndex].elementValuePairs[elementValuePairsIndex].value);1050}1051}1052}1053return foundAnnotations;1054}10551056void1057ClassFileOracle::walkTypeAnnotations(U_16 annotationsCount, J9CfrTypeAnnotation *typeAnnotations) {1058for (U_16 typeAnnotationIndex = 0; typeAnnotationIndex < annotationsCount; ++ typeAnnotationIndex) {1059J9CfrAnnotation *annotation = &(typeAnnotations[typeAnnotationIndex].annotation);1060/* type_index in an annotation must refer to a CONSTANT_UTF8_info structure. */1061if (getCPTag(annotation->typeIndex) == CFR_CONSTANT_Utf8) {1062markConstantAsUsedByAnnotation(annotation->typeIndex);1063const U_16 elementValuePairsCount = annotation->numberOfElementValuePairs;1064for (U_16 elementValuePairsIndex = 0;1065(elementValuePairsIndex < elementValuePairsCount) && (OK == _buildResult); ++elementValuePairsIndex) {1066markConstantAsUsedByAnnotation(annotation->elementValuePairs[elementValuePairsIndex].elementNameIndex);1067walkAnnotationElement(annotation->elementValuePairs[elementValuePairsIndex].value);1068}1069} else {1070/*1071* UTF-8 entries and method entries use the same set of marking labels when1072* preparing to build the ROM class, but1073* the label value meanings differ depending on the type of the entry.1074* Thus we cannot mark a non-UTF-8 entry with a label used for UTF-8 as that label1075* value will be (mis)interpreted according to the type of the entry.1076*1077* In this case, force the typeIndex to a null value.1078* This will cause the parser to throw1079* an error if the VM or application tries to retrieve the annotation.1080*/1081annotation->typeIndex = 0;1082}1083}1084}10851086void1087ClassFileOracle::walkAnnotationElement(J9CfrAnnotationElement * annotationElement)1088{1089ROMClassVerbosePhase v(_context, ClassFileAnnotationElementAnalysis);10901091switch (annotationElement->tag) {1092case 'e':1093markConstantAsUsedByAnnotation(((J9CfrAnnotationElementEnum *)annotationElement)->typeNameIndex);1094markConstantAsUsedByAnnotation(((J9CfrAnnotationElementEnum *)annotationElement)->constNameIndex);1095break;1096case 'c':1097markConstantAsUsedByAnnotation(((J9CfrAnnotationElementClass *)annotationElement)->classInfoIndex);1098break;1099case '@':1100walkAnnotations(1, &(((J9CfrAnnotationElementAnnotation *)annotationElement)->annotationValue), 0);1101break;1102case '[': {1103J9CfrAnnotationElementArray *array = (J9CfrAnnotationElementArray *)annotationElement;1104for (U_16 valuesIndex = 0; (valuesIndex < array->numberOfValues) && (OK == _buildResult); ++valuesIndex) {1105walkAnnotationElement(array->values[valuesIndex]);1106}1107break;1108}11091110case 'D': /* fall thru */1111case 'J':1112_annotationRefersDoubleSlotEntry = true;1113/* fall thru */1114case 'B': /* fall thru */1115case 'C': /* fall thru */1116case 'F': /* fall thru */1117case 'I': /* fall thru */1118case 'S': /* fall thru */1119case 'Z': /* fall thru */1120/* Fall through - in Java 7, the annotation data is preserved in class file format, including referenced constant pool entries */1121case 's':1122markConstantAsUsedByAnnotation(((J9CfrAnnotationElementPrimitive *)annotationElement)->constValueIndex);1123break;1124default:1125Trc_BCU_ClassFileOracle_walkAnnotationElement_UnknownTag((U_32)annotationElement->tag);1126_buildResult = UnknownAnnotation;1127break;1128}1129}11301131void1132ClassFileOracle::computeSendSlotCount(U_16 methodIndex)1133{1134ROMCLASS_VERBOSE_PHASE_HOT(_context, ComputeSendSlotCount);11351136U_16 descriptorIndex = _classFile->methods[methodIndex].descriptorIndex;1137U_16 count = getUTF8Length(descriptorIndex);1138U_8 * bytes = getUTF8Data(descriptorIndex);1139U_8 sendSlotCount = 0;11401141for (U_16 index = 1; index < count; ++index) { /* 1 to skip the opening '(' */1142switch (bytes[index]) {1143case ')':1144_methodsInfo[methodIndex].sendSlotCount = sendSlotCount;1145return;1146case '[':1147/* skip all '['s */1148while ((index < count) && ('[' == bytes[index])) {1149++index;1150}1151if ((index >= count)1152#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)1153|| (('L' != bytes[index]) && ('Q' != bytes[index]))1154#else1155|| ('L' != bytes[index])1156#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */1157) {1158break;1159}1160/* fall through */1161case 'L':1162#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)1163case 'Q':1164#endif /* J9VM_OPT_VALHALLA_VALUE_TYPES */1165++index;1166while ((index < count) && (';' != bytes[index])) {1167++index;1168}1169break;1170case 'D':1171++sendSlotCount; /* double requires an extra send slot */1172break;1173case 'J':1174++sendSlotCount; /* long requires an extra send slot */1175break;1176default:1177/* any other primitive type */1178break;1179}1180++sendSlotCount;1181}1182}11831184void1185ClassFileOracle::walkMethodThrownExceptions(U_16 methodIndex)1186{1187ROMCLASS_VERBOSE_PHASE_HOT(_context, ClassFileMethodThrownExceptionsAnalysis);11881189J9CfrAttributeExceptions *exceptions = _classFile->methods[methodIndex].exceptionsAttribute;1190if (NULL != exceptions) {1191U_16 exceptionsThrownCount = 0;1192U_16 exceptionsCount = exceptions->numberOfExceptions;11931194for (U_16 exceptionIndex = 0; exceptionIndex < exceptionsCount; ++exceptionIndex) {1195U_16 cpIndex = exceptions->exceptionIndexTable[exceptionIndex];1196if (0 != cpIndex) {1197markClassNameAsReferenced(cpIndex);1198++exceptionsThrownCount;11991200}1201}12021203if (exceptionsThrownCount > 0) {1204_methodsInfo[methodIndex].exceptionsThrownCount = exceptionsThrownCount;1205_methodsInfo[methodIndex].modifiers |= J9AccMethodHasExceptionInfo;1206}1207}1208}12091210void1211ClassFileOracle::walkMethodCodeAttribute(U_16 methodIndex)1212{1213ROMCLASS_VERBOSE_PHASE_HOT(_context, ClassFileMethodCodeAttributeAnalysis);12141215J9CfrAttributeCode *codeAttribute = _classFile->methods[methodIndex].codeAttribute;1216if (NULL != codeAttribute) {1217walkMethodCodeAttributeAttributes(methodIndex);1218walkMethodCodeAttributeCaughtExceptions(methodIndex);1219walkMethodCodeAttributeCode(methodIndex);12201221if (0 != codeAttribute->exceptionTableLength) {1222_methodsInfo[methodIndex].modifiers |= J9AccMethodHasExceptionInfo;1223}1224}1225}12261227void1228ClassFileOracle::walkMethodMethodParametersAttribute(U_16 methodIndex)1229{1230ROMCLASS_VERBOSE_PHASE_HOT(_context, ClassFileMethodMethodParametersAttributeAnalysis);12311232J9CfrAttributeMethodParameters *methodParametersAttribute = _classFile->methods[methodIndex].methodParametersAttribute;12331234if (NULL != methodParametersAttribute) {1235for (U_8 methodParamsIndex = 0;1236(methodParamsIndex < methodParametersAttribute->numberOfMethodParameters) && (OK == _buildResult);1237++methodParamsIndex)1238{1239U_16 utfIndex = methodParametersAttribute->methodParametersIndexTable[methodParamsIndex];1240if (J9_ARE_ANY_BITS_SET(methodParametersAttribute->flags[methodParamsIndex], ~CFR_ATTRIBUTE_METHOD_PARAMETERS_MASK)) {1241/* only CFR_ACC_FINAL | CFR_ACC_SYNTHETIC | CFR_ACC_MANDATED should be set */1242_methodsInfo[methodIndex].extendedModifiers |= CFR_METHOD_EXT_INVALID_CP_ENTRY;1243}1244if (0 != utfIndex) {1245bool cpEntryOkay = false;1246if (utfIndex <= _classFile->constantPoolCount) {1247UDATA cpTag = getCPTag(utfIndex);1248if (CFR_CONSTANT_Utf8 == cpTag) {1249markConstantUTF8AsReferenced(utfIndex);1250cpEntryOkay = true;1251}1252}1253if (!cpEntryOkay) {1254/* Mark the method as having bad methodParameters */1255methodParametersAttribute->methodParametersIndexTable[methodParamsIndex] = 0;1256_methodsInfo[methodIndex].extendedModifiers |= CFR_METHOD_EXT_INVALID_CP_ENTRY;1257Trc_BCU_MalformedMethodParameterAttribute(methodIndex);1258}1259}1260}1261/* PR 97987 keep parameters object to detect mismatch between parameters attribute and actual argument count */1262_methodsInfo[methodIndex].methodParametersAttribute = methodParametersAttribute;1263_methodsInfo[methodIndex].modifiers |= J9AccMethodHasMethodParameters;1264}12651266}12671268void1269ClassFileOracle::throwGenericErrorWithCustomMsg(UDATA code, UDATA offset)1270{1271_buildResult = OutOfMemory;1272PORT_ACCESS_FROM_PORT(_context->portLibrary());1273U_8* errorMsg = (U_8 *)j9mem_allocate_memory(sizeof(J9CfrError), J9MEM_CATEGORY_CLASSES);1274if (NULL != errorMsg) {1275_buildResult = GenericErrorCustomMsg;1276buildError((J9CfrError*)errorMsg, code, GenericErrorCustomMsg, offset);1277J9TranslationBufferSet* dlb = _context->javaVM()->dynamicLoadBuffers;1278/* avoid leaking memory if classFileError was not previously null. Do not free1279* memory if _classFileBuffer from ROMClassBuilder is using the same address. */1280if ((NULL != dlb->classFileError) && (_romBuilderClassFileBuffer != dlb->classFileError)) {1281j9mem_free_memory(dlb->classFileError);1282}1283dlb->classFileError = errorMsg;1284}1285}12861287void1288ClassFileOracle::walkMethodCodeAttributeAttributes(U_16 methodIndex)1289{1290ROMCLASS_VERBOSE_PHASE_HOT(_context, ClassFileMethodCodeAttributeAttributesAnalysis);12911292J9CfrAttributeCode *codeAttribute = _classFile->methods[methodIndex].codeAttribute;1293U_32 lineNumbersCount = 0;12941295Trc_BCU_Assert_NotEquals(NULL, codeAttribute);12961297U_16 attributesCount = codeAttribute->attributesCount;1298for (U_16 attributeIndex = 0; (attributeIndex < attributesCount) && (OK == _buildResult); ++attributeIndex) {1299J9CfrAttribute *attribute = codeAttribute->attributes[attributeIndex];13001301switch (attribute->tag) {1302case CFR_ATTRIBUTE_StackMapTable: {1303/*1304* Stack map table frames are variable sized and look like:1305* StackMapTableFrame {1306* U_8 frameType1307* ... rest1308* };1309*1310* frameType is a tag distinguishing 256 different types of frame that fall into 8 categories:1311* SAME1312* SAME_LOCALS_1_STACK1313* Reserved1314* SAME_LOCALS_1_STACK_EXTENDED1315* CHOP1316* SAME_EXTENDED1317* APPEND1318* FULL1319*1320* Each of these types is described in more detail below.1321*1322* Some frame types contain 1 or more TypeInfo entries. TypeInfo is a variable-length data type TODO add doc?1323*1324* stackMap->numberOfEntries is the number of StackMapFrames in stackMap->entries.1325* stackMap->entries is a byte buffer containing the variable length StackMapFrames.1326*1327* framePointer is used to step through stackMap->entries.1328* entryIndex is used to determine when we've read all the StackMapFrames.1329*/13301331J9CfrAttributeStackMap * stackMap = (J9CfrAttributeStackMap *) attribute;1332_methodsInfo[methodIndex].modifiers |= J9AccMethodHasStackMap;13331334Trc_BCU_Assert_Equals(NULL, _methodsInfo[methodIndex].stackMapFramesInfo);1335_methodsInfo[methodIndex].stackMapFramesInfo = (StackMapFrameInfo *) _bufferManager->alloc(stackMap->numberOfEntries * sizeof(StackMapFrameInfo));1336if (NULL == _methodsInfo[methodIndex].stackMapFramesInfo) {1337Trc_BCU_ClassFileOracle_walkMethodCodeAttributeAttributes_OutOfMemory(stackMap->numberOfEntries * sizeof(StackMapFrameInfo));1338_buildResult = OutOfMemory;1339break;1340}1341memset(_methodsInfo[methodIndex].stackMapFramesInfo, 0, stackMap->numberOfEntries * sizeof(StackMapFrameInfo));1342_methodsInfo[methodIndex].stackMapFramesCount = U_16(stackMap->numberOfEntries);13431344StackMapFrameInfo *stackMapFramesInfo = _methodsInfo[methodIndex].stackMapFramesInfo;1345U_8 *framePointer = stackMap->entries;1346U_16 entryCount = U_16(stackMap->numberOfEntries);1347for(U_16 entryIndex = 0; entryIndex < entryCount; ++entryIndex) {1348NEXT_U8(stackMapFramesInfo[entryIndex].frameType, framePointer);13491350if (CFR_STACKMAP_SAME_LOCALS_1_STACK > stackMapFramesInfo[entryIndex].frameType) { /* 0..63 */1351/* SAME frame - no extra data */1352} else if (CFR_STACKMAP_SAME_LOCALS_1_STACK_END > stackMapFramesInfo[entryIndex].frameType) { /* 64..127 */1353/*1354* SAME_LOCALS_1_STACK {1355* TypeInfo stackItems[1]1356* };1357*/1358stackMapFramesInfo[entryIndex].stackItemsCount = 1;1359stackMapFramesInfo[entryIndex].stackItemsTypeInfo = framePointer;1360framePointer = walkStackMapSlots(framePointer, stackMapFramesInfo[entryIndex].stackItemsCount);1361} else if (CFR_STACKMAP_SAME_LOCALS_1_STACK_EXTENDED > stackMapFramesInfo[entryIndex].frameType) { /* 128..246 */1362/* Reserved frame types - no extra data */1363Trc_BCU_Assert_ShouldNeverHappen();1364} else if (CFR_STACKMAP_SAME_LOCALS_1_STACK_EXTENDED == stackMapFramesInfo[entryIndex].frameType) { /* 247 */1365/*1366* SAME_LOCALS_1_STACK_EXTENDED {1367* U_16 offsetDelta1368* TypeInfo stackItems[1]1369* };1370*/1371NEXT_U16(stackMapFramesInfo[entryIndex].offsetDelta, framePointer); /* Extract offsetDelta */1372stackMapFramesInfo[entryIndex].stackItemsCount = 1;1373stackMapFramesInfo[entryIndex].stackItemsTypeInfo = framePointer;1374framePointer = walkStackMapSlots(framePointer, stackMapFramesInfo[entryIndex].stackItemsCount);1375} else if (CFR_STACKMAP_SAME_EXTENDED > stackMapFramesInfo[entryIndex].frameType) { /* 248..250 */1376/*1377* CHOP {1378* U_16 offsetDelta1379* };1380*/1381NEXT_U16(stackMapFramesInfo[entryIndex].offsetDelta, framePointer); /* Extract offsetDelta */1382} else if (CFR_STACKMAP_SAME_EXTENDED == stackMapFramesInfo[entryIndex].frameType) { /* 251 */1383/*1384* SAME_EXTENDED {1385* U_16 offsetDelta1386* };1387*/1388NEXT_U16(stackMapFramesInfo[entryIndex].offsetDelta, framePointer); /* Extract offsetDelta */1389} else if (CFR_STACKMAP_FULL > stackMapFramesInfo[entryIndex].frameType) { /* 252..254 */1390/*1391* APPEND {1392* U_16 offsetDelta1393* TypeInfo locals[frameType - CFR_STACKMAP_APPEND_BASE]1394* };1395*/1396NEXT_U16(stackMapFramesInfo[entryIndex].offsetDelta, framePointer); /* Extract offsetDelta */1397stackMapFramesInfo[entryIndex].localsCount = stackMapFramesInfo[entryIndex].frameType - CFR_STACKMAP_APPEND_BASE;1398stackMapFramesInfo[entryIndex].localsTypeInfo = framePointer;1399framePointer = walkStackMapSlots(framePointer, stackMapFramesInfo[entryIndex].localsCount);1400} else if (CFR_STACKMAP_FULL == stackMapFramesInfo[entryIndex].frameType) { /* 255 */1401/*1402* FULL {1403* U_16 offsetDelta1404* U_16 localsCount1405* TypeInfo locals[localsCount]1406* U_16 stackItemsCount1407* TypeInfo stackItems[stackItemsCount]1408* };1409*/1410NEXT_U16(stackMapFramesInfo[entryIndex].offsetDelta, framePointer); /* Extract offsetDelta */1411NEXT_U16(stackMapFramesInfo[entryIndex].localsCount, framePointer); /* Extract localsCount */1412stackMapFramesInfo[entryIndex].localsTypeInfo = framePointer;1413framePointer = walkStackMapSlots(framePointer, stackMapFramesInfo[entryIndex].localsCount);1414NEXT_U16(stackMapFramesInfo[entryIndex].stackItemsCount, framePointer); /* Extract stackItemsCount */1415stackMapFramesInfo[entryIndex].stackItemsTypeInfo = framePointer;1416framePointer = walkStackMapSlots(framePointer, stackMapFramesInfo[entryIndex].stackItemsCount);1417}1418}1419break;1420}1421case CFR_ATTRIBUTE_LineNumberTable:1422if (_context->shouldPreserveLineNumbers()) {1423J9CfrAttributeLineNumberTable *lineNumberTable = (J9CfrAttributeLineNumberTable *) attribute;1424lineNumbersCount += lineNumberTable->lineNumberTableLength;1425}1426break;1427case CFR_ATTRIBUTE_LocalVariableTable:1428if (_context->shouldPreserveLocalVariablesInfo()) {1429/* There can be at most one entry per local variable, so we allocate the full table up-front and index by local variable index */1430if (NULL == _methodsInfo[methodIndex].localVariablesInfo) {1431_methodsInfo[methodIndex].localVariablesInfo = (LocalVariableInfo *) _bufferManager->alloc(codeAttribute->maxLocals * sizeof(LocalVariableInfo));1432if (NULL == _methodsInfo[methodIndex].localVariablesInfo) {1433Trc_BCU_ClassFileOracle_walkMethodCodeAttributeAttributes_OutOfMemory(codeAttribute->maxLocals * sizeof(LocalVariableInfo));1434_buildResult = OutOfMemory;1435break;1436}1437memset(_methodsInfo[methodIndex].localVariablesInfo, 0, codeAttribute->maxLocals * sizeof(LocalVariableInfo));1438}14391440J9CfrAttributeLocalVariableTable *localVariableTableAttribute = (J9CfrAttributeLocalVariableTable *) attribute;1441_methodsInfo[methodIndex].localVariablesCount += localVariableTableAttribute->localVariableTableLength;1442if (0 != localVariableTableAttribute->localVariableTableLength) {1443for (U_16 localVariableTableIndex = 0; localVariableTableIndex < localVariableTableAttribute->localVariableTableLength; ++localVariableTableIndex) {1444U_16 index = localVariableTableAttribute->localVariableTable[localVariableTableIndex].index;1445if (codeAttribute->maxLocals <= index) {1446Trc_BCU_ClassFileOracle_walkMethodCodeAttributeAttributes_LocalVariableTableIndexOutOfBounds(1447index, codeAttribute->maxLocals, (U_32)getUTF8Length(_classFile->methods[methodIndex].nameIndex), getUTF8Data(_classFile->methods[methodIndex].nameIndex));14481449throwGenericErrorWithCustomMsg(J9NLS_CFR_LVT_INDEX_OUTOFRANGE__ID, index);1450break;1451} else if (NULL == _methodsInfo[methodIndex].localVariablesInfo[index].localVariableTableAttribute) {1452_methodsInfo[methodIndex].localVariablesInfo[index].localVariableTableAttribute = localVariableTableAttribute;1453} else if (localVariableTableAttribute != _methodsInfo[methodIndex].localVariablesInfo[index].localVariableTableAttribute) {1454Trc_BCU_ClassFileOracle_walkMethodCodeAttributeAttributes_DuplicateLocalVariableTable(1455(U_32)getUTF8Length(_classFile->methods[methodIndex].nameIndex), getUTF8Data(_classFile->methods[methodIndex].nameIndex),1456localVariableTableAttribute, _methodsInfo[methodIndex].localVariablesInfo[index].localVariableTableAttribute);1457_buildResult = GenericError;1458break;1459}1460markConstantUTF8AsReferenced(localVariableTableAttribute->localVariableTable[localVariableTableIndex].nameIndex);1461markConstantUTF8AsReferenced(localVariableTableAttribute->localVariableTable[localVariableTableIndex].descriptorIndex);1462}1463}1464}1465break;1466case CFR_ATTRIBUTE_LocalVariableTypeTable:1467if (_context->shouldPreserveLocalVariablesInfo()) {1468/* There can be at most one entry per local variable, so we allocate the full table up-front and index by local variable index */1469if (NULL == _methodsInfo[methodIndex].localVariablesInfo) {1470_methodsInfo[methodIndex].localVariablesInfo = (LocalVariableInfo *) _bufferManager->alloc(codeAttribute->maxLocals * sizeof(LocalVariableInfo));1471if (NULL == _methodsInfo[methodIndex].localVariablesInfo) {1472Trc_BCU_ClassFileOracle_walkMethodCodeAttributeAttributes_OutOfMemory(codeAttribute->maxLocals * sizeof(LocalVariableInfo));1473_buildResult = OutOfMemory;1474break;1475}1476memset(_methodsInfo[methodIndex].localVariablesInfo, 0, codeAttribute->maxLocals * sizeof(LocalVariableInfo));1477}14781479J9CfrAttributeLocalVariableTypeTable *localVariableTypeTableAttribute = (J9CfrAttributeLocalVariableTypeTable *) attribute;1480if (0 != localVariableTypeTableAttribute->localVariableTypeTableLength) {1481for (U_16 localVariableTypeTableIndex = 0; localVariableTypeTableIndex < localVariableTypeTableAttribute->localVariableTypeTableLength; ++localVariableTypeTableIndex) {1482J9CfrLocalVariableTypeTableEntry *lvttEntry = &(localVariableTypeTableAttribute->localVariableTypeTable[localVariableTypeTableIndex]);1483const U_16 index = lvttEntry->index;1484if (codeAttribute->maxLocals <= index) {1485Trc_BCU_ClassFileOracle_walkMethodCodeAttributeAttributes_LocalVariableTypeTableIndexOutOfBounds(1486index, codeAttribute->maxLocals, (U_32)getUTF8Length(_classFile->methods[methodIndex].nameIndex), getUTF8Data(_classFile->methods[methodIndex].nameIndex));1487throwGenericErrorWithCustomMsg(J9NLS_CFR_LVTT_INDEX_OUTOFRANGE__ID, index);1488break;1489} else if (NULL == _methodsInfo[methodIndex].localVariablesInfo[index].localVariableTypeTableAttribute) {1490_methodsInfo[methodIndex].localVariablesInfo[index].localVariableTypeTableAttribute = localVariableTypeTableAttribute;1491} else if (localVariableTypeTableAttribute != _methodsInfo[methodIndex].localVariablesInfo[index].localVariableTypeTableAttribute) {1492Trc_BCU_ClassFileOracle_walkMethodCodeAttributeAttributes_DuplicateLocalVariableTypeTable(1493(U_32)getUTF8Length(_classFile->methods[methodIndex].nameIndex), getUTF8Data(_classFile->methods[methodIndex].nameIndex),1494localVariableTypeTableAttribute, _methodsInfo[methodIndex].localVariablesInfo[index].localVariableTypeTableAttribute);1495_buildResult = GenericError;1496break;1497}14981499/* 4.7.14: There may be no more than one LocalVariableTypeTable attribute per local variable in the attributes table of a Code attribute.1500* The entry is unique with its startPC, length, and index. */1501for (U_16 localVariableTypeTableCompareIndex = 0; localVariableTypeTableCompareIndex < localVariableTypeTableIndex; ++localVariableTypeTableCompareIndex) {1502J9CfrLocalVariableTypeTableEntry *lvttCompareEntry = &(localVariableTypeTableAttribute->localVariableTypeTable[localVariableTypeTableCompareIndex]);1503if ((lvttEntry->startPC == lvttCompareEntry->startPC)1504&& (lvttEntry->length == lvttCompareEntry->length)1505&& (lvttEntry->nameIndex == lvttCompareEntry->nameIndex)1506&& (lvttEntry->signatureIndex == lvttCompareEntry->signatureIndex)1507&& (index == lvttCompareEntry->index)1508) {1509throwGenericErrorWithCustomMsg(J9NLS_CFR_LVTT_DUPLICATE__ID, index);1510break;1511}1512}1513markConstantUTF8AsReferenced(localVariableTypeTableAttribute->localVariableTypeTable[localVariableTypeTableIndex].signatureIndex);1514}1515}1516}1517break;1518case CFR_ATTRIBUTE_RuntimeVisibleTypeAnnotations: {1519J9CfrAttributeRuntimeVisibleTypeAnnotations *typeAnnotations = (J9CfrAttributeRuntimeVisibleTypeAnnotations *)attribute;1520if (0 == typeAnnotations->rawDataLength) { /* rawDataLength non-zero in case of error in the attribute */1521walkTypeAnnotations(typeAnnotations->numberOfAnnotations, typeAnnotations->typeAnnotations);1522}1523_methodsInfo[methodIndex].codeTypeAnnotationsAttribute = typeAnnotations;1524/* J9AccMethodHasExtendedModifiers in the modifiers is set when the ROM class is written */1525_methodsInfo[methodIndex].extendedModifiers |= CFR_METHOD_EXT_HAS_CODE_TYPE_ANNOTATIONS;1526break;1527}1528default:1529Trc_BCU_ClassFileOracle_walkMethodCodeAttributeAttributes_UnknownAttribute((U_32)attribute->tag, (U_32)getUTF8Length(attribute->nameIndex), getUTF8Data(attribute->nameIndex), attribute->length);1530break;1531}1532}15331534/* Verify that each LVTT entry has a matching local variable. Since there is no guaranteed order1535* for code attributes, this check must be performed after all attributes are processed.1536*1537* According to the JVM spec: "Each entry in the local_variable_type_table array ...1538* indicates the index into the local variable array of the current frame at which1539* that local variable can be found."1540*1541* While multiple LocalVariableTypeTable attributes may exist according to the spec, upon observation1542* it is the common case for 'javac' to generate only one attribute per method. To take advantage of this1543* I tracked the last LVTT attribute that has been verified so the second loop search is not repeated.1544* Because of this for most cases the second loop will only be executed once.1545*1546* It is also common to see LVT and LVTT entries in the same order though the spec makes no ordering guaruntees.1547* To take advantage of this each search for an LVT match starts from the index where the previous match was1548* found saving iterations.1549*1550* With these two optimizations the common runtime for this verification step should be:1551* maxLocals + localVariableTypeTableLength + localVariableTableLength1552*/1553if (_context->shouldPreserveLocalVariablesInfo() && (NULL != _methodsInfo[methodIndex].localVariablesInfo)) {1554J9CfrAttributeLocalVariableTypeTable *lastLVTTAttribute = NULL; /* track last processed LVTT attribute */15551556for (UDATA varIndex = 0; varIndex < codeAttribute->maxLocals; varIndex++) {1557J9CfrAttributeLocalVariableTable *localVariableTableAttribute = _methodsInfo[methodIndex].localVariablesInfo[varIndex].localVariableTableAttribute;1558J9CfrAttributeLocalVariableTypeTable *localVariableTypeTableAttribute = _methodsInfo[methodIndex].localVariablesInfo[varIndex].localVariableTypeTableAttribute;15591560/* This may occur if the variable type does not require signature information, or if there is no entry for this variable. */1561if ((NULL == localVariableTypeTableAttribute) || (NULL == localVariableTableAttribute)) {1562continue;1563}15641565/* if LVTT has been processed previously, skip to the next variable */1566if (NULL == lastLVTTAttribute) {1567lastLVTTAttribute = localVariableTypeTableAttribute;1568} else if (localVariableTypeTableAttribute == lastLVTTAttribute) {1569continue;1570}15711572/* Verify that each entry in the LocalVariableTypeTable has a match */1573U_16 lvtIndex = 0; /* start at the index of the last LVT match since LVT and LVTTs are likely in the same order. */1574for (U_16 lvttIndex = 0; lvttIndex < localVariableTypeTableAttribute->localVariableTypeTableLength; lvttIndex++) {1575J9CfrLocalVariableTypeTableEntry *lvttEntry = &(localVariableTypeTableAttribute->localVariableTypeTable[lvttIndex]);1576UDATA foundMatch = FALSE;15771578/* Search for match in LVT attribute with matching index. */1579for (U_16 lvtCount = 0; lvtCount < localVariableTableAttribute->localVariableTableLength; lvtCount++) {1580J9CfrLocalVariableTableEntry *lvtEntry = &(localVariableTableAttribute->localVariableTable[lvtIndex]);15811582/* Update index for next iteration, rolling over to 0 if necessary. */1583lvtIndex = (lvtIndex + 1) % localVariableTableAttribute->localVariableTableLength;15841585if ((lvttEntry->startPC == lvtEntry->startPC)1586&& (lvttEntry->length == lvtEntry->length)1587&& (lvttEntry->nameIndex == lvtEntry->nameIndex)1588&& (lvttEntry->index == lvtEntry->index)1589) {1590foundMatch = TRUE;1591break;1592}1593}15941595/* throw error if there is no variable match. */1596if (!foundMatch) {1597throwGenericErrorWithCustomMsg(J9NLS_CFR_LVTT_DOES_NOT_MATCH_LVT__ID, lvttIndex);1598}1599}1600}1601}16021603if ((OK == _buildResult) && (0 != lineNumbersCount)) {1604ROMCLASS_VERBOSE_PHASE_HOT(_context, CompressLineNumbers);1605compressLineNumberTable(methodIndex, lineNumbersCount);1606}1607}16081609int1610ClassFileOracle::compareLineNumbers(const void *left, const void *right)1611{1612J9CfrLineNumberTableEntry *leftNumber = (J9CfrLineNumberTableEntry *)left;1613J9CfrLineNumberTableEntry *rightNumber = (J9CfrLineNumberTableEntry *)right;16141615return int(leftNumber->startPC - rightNumber->startPC);1616}16171618void1619ClassFileOracle::compressLineNumberTable(U_16 methodIndex, U_32 lineNumbersCount)1620{1621J9CfrAttributeCode *codeAttribute = _classFile->methods[methodIndex].codeAttribute;1622U_16 attributesCount = codeAttribute->attributesCount;1623MethodInfo *method = &(_methodsInfo[methodIndex]);16241625/* maximum possible size of compressed data, compressLineNumbers may use a maximum1626* of 5 bytes for compressed data, the maximum memory needed will be of 5 bytes per line number.1627*/1628U_8 *lineNumbersInfoCompressed = (U_8*)(_bufferManager->alloc(lineNumbersCount * 5));1629U_8 *lineNumbersInfoCompressedInitial = lineNumbersInfoCompressed;1630if (NULL == lineNumbersInfoCompressed) {1631Trc_BCU_ClassFileOracle_walkMethodCodeAttributeAttributes_OutOfMemory(lineNumbersCount * 5);1632_buildResult = OutOfMemory;1633} else {1634J9CfrLineNumberTableEntry * lastLineNumberTableEntry = NULL;16351636for (U_16 attributeIndex = 0; attributeIndex < attributesCount; ++attributeIndex) {1637J9CfrAttribute *attribute = codeAttribute->attributes[attributeIndex];1638if (CFR_ATTRIBUTE_LineNumberTable == attribute->tag) {1639J9CfrAttributeLineNumberTable *lineNumberTable = (J9CfrAttributeLineNumberTable *) attribute;1640if (!compressLineNumbers(lineNumberTable->lineNumberTable, lineNumberTable->lineNumberTableLength, lastLineNumberTableEntry, &lineNumbersInfoCompressed)) {1641/* the line numbers are not sorted, sort them */1642sortAndCompressLineNumberTable(methodIndex, lineNumbersCount, lineNumbersInfoCompressedInitial);1643return;1644}1645lastLineNumberTableEntry = &lineNumberTable->lineNumberTable[lineNumberTable->lineNumberTableLength - 1];1646}1647}1648method->lineNumbersInfoCompressed = lineNumbersInfoCompressedInitial;1649method->lineNumbersCount = lineNumbersCount;1650method->lineNumbersInfoCompressedSize = (U_32)(lineNumbersInfoCompressed - lineNumbersInfoCompressedInitial);16511652/* Reclaim the rest of the buffer lineNumbersInfoCompressed */1653_bufferManager->reclaim(lineNumbersInfoCompressedInitial, method->lineNumbersInfoCompressedSize);1654}1655}16561657void1658ClassFileOracle::sortAndCompressLineNumberTable(U_16 methodIndex, U_32 lineNumbersCount, U_8 *lineNumbersInfoCompressedInitial)1659{1660J9CfrAttributeCode *codeAttribute = _classFile->methods[methodIndex].codeAttribute;1661U_16 attributesCount = codeAttribute->attributesCount;1662MethodInfo *method = &(_methodsInfo[methodIndex]);16631664U_8 *lineNumbersInfoCompressed;1665UDATA lineNumbersInfoSize = lineNumbersCount * sizeof (J9CfrLineNumberTableEntry);1666J9CfrLineNumberTableEntry *lineNumbersInfo = (J9CfrLineNumberTableEntry*)(_bufferManager->alloc(lineNumbersInfoSize));1667lineNumbersInfoCompressed = lineNumbersInfoCompressedInitial;1668if (NULL == lineNumbersInfo) {1669Trc_BCU_ClassFileOracle_walkMethodCodeAttributeAttributes_OutOfMemory(lineNumbersInfoSize);1670_buildResult = OutOfMemory;1671} else {1672sortLineNumberTable(methodIndex, lineNumbersInfo);16731674/* Compress the line numbers */1675if (!compressLineNumbers(lineNumbersInfo, lineNumbersCount, NULL, &lineNumbersInfoCompressed)) {1676/* The pcOffset should be sorted by now */1677Trc_BCU_Assert_ShouldNeverHappen();1678}16791680method->lineNumbersInfoCompressed = lineNumbersInfoCompressedInitial;1681method->lineNumbersCount = lineNumbersCount;1682method->lineNumbersInfoCompressedSize = (U_32)(lineNumbersInfoCompressed - lineNumbersInfoCompressedInitial);1683_bufferManager->reclaim(lineNumbersInfo, lineNumbersInfoSize);1684}1685}1686void1687ClassFileOracle::sortLineNumberTable(U_16 methodIndex, J9CfrLineNumberTableEntry *lineNumbersInfo) {1688J9CfrAttributeCode *codeAttribute = _classFile->methods[methodIndex].codeAttribute;1689U_16 attributesCount = codeAttribute->attributesCount;16901691U_32 lineNumbersIndex = 0;1692U_32 lastPC = 0;1693/* Used by ROMClassBuilder to not sort the line if they were already sorted */1694BOOLEAN sorted = TRUE;1695for (U_16 attributeIndex = 0; attributeIndex < attributesCount; ++attributeIndex) {1696J9CfrAttribute *attribute = codeAttribute->attributes[attributeIndex];16971698if (CFR_ATTRIBUTE_LineNumberTable == attribute->tag) {1699J9CfrAttributeLineNumberTable *lineNumberTable = (J9CfrAttributeLineNumberTable *) attribute;1700for (U_16 lineNumberTableIndex = 0; lineNumberTableIndex < lineNumberTable->lineNumberTableLength; ++lineNumberTableIndex) {1701if (lineNumberTable->lineNumberTable[lineNumberTableIndex].startPC < lastPC) {1702sorted = FALSE;1703}1704lastPC = lineNumbersInfo[lineNumbersIndex].startPC = lineNumberTable->lineNumberTable[lineNumberTableIndex].startPC;1705lineNumbersInfo[lineNumbersIndex].lineNumber = lineNumberTable->lineNumberTable[lineNumberTableIndex].lineNumber;1706++lineNumbersIndex;1707}1708}1709}17101711if (!sorted) {1712/* Sort the line numbers */1713J9_SORT(lineNumbersInfo, lineNumbersIndex, sizeof(J9CfrLineNumberTableEntry), &ClassFileOracle::compareLineNumbers);1714}1715}17161717void1718ClassFileOracle::walkMethodCodeAttributeCaughtExceptions(U_16 methodIndex)1719{1720ROMCLASS_VERBOSE_PHASE_HOT(_context, ClassFileMethodCodeAttributeCaughtExceptionsAnalysis);1721J9CfrAttributeCode *codeAttribute = _classFile->methods[methodIndex].codeAttribute;17221723Trc_BCU_Assert_NotEquals(NULL, codeAttribute);17241725for (U_16 exceptionTableIndex = 0; exceptionTableIndex < codeAttribute->exceptionTableLength; ++exceptionTableIndex) {1726U_16 cpIndex = codeAttribute->exceptionTable[exceptionTableIndex].catchType;1727if (0 != cpIndex) {1728markClassAsReferenced(cpIndex);1729}1730}1731}17321733void1734ClassFileOracle::addBytecodeFixupEntry(BytecodeFixupEntry *entry, U_32 codeIndex, U_16 cpIndex, U_8 type)1735{1736entry->codeIndex = codeIndex;1737entry->cpIndex = cpIndex;1738entry->type = type;1739}17401741const U_8 PARAM_VOID = 0;1742const U_8 PARAM_BOOLEAN = 1;1743const U_8 PARAM_BYTE = 2;1744const U_8 PARAM_CHAR = 3;1745const U_8 PARAM_SHORT = 4;1746const U_8 PARAM_FLOAT = 5;1747const U_8 PARAM_INT = 6;1748const U_8 PARAM_DOUBLE = 7;1749const U_8 PARAM_LONG = 8;1750const U_8 PARAM_OBJECT = 9;17511752#define PARAM_U8() code[codeIndex + 1]1753#define PARAM_U16() (U_16(code[codeIndex + 1]) << 8) | U_16(code[codeIndex + 2])1754#define PARAM_I16() I_16(PARAM_U16())17551756#if defined(J9VM_ENV_LITTLE_ENDIAN)17571758/*1759* Swaps the I_32 in-place, returning it.1760*/1761static VMINLINE I_321762swapI32(U_8 *code, U_32 codeIndex)1763{1764I_32 *dest = (I_32 *)&code[codeIndex];1765I_32 value = I_32(U_32(code[codeIndex] << 24) | U_32(code[codeIndex + 1] << 16) | U_32(code[codeIndex + 2] << 8) | U_32(code[codeIndex + 3]));1766*dest = value;1767return value;1768}17691770#define SWAP_I32_GET(index) swapI32(code, index)1771#define SWAP_I32(index) SWAP_I32_GET(index)1772#else1773/*1774* We use separate macros here because the compiler is not guaranteed to optimize out the pointer1775* dereference (as doing so may result in a change of program behaviour in the compiler's view -1776* for example a GPF may not happen).1777*/1778#define SWAP_I32_GET(index) *(I_32*)&code[index]1779#define SWAP_I32(index)1780#endif17811782void1783ClassFileOracle::walkMethodCodeAttributeCode(U_16 methodIndex)1784{1785ROMCLASS_VERBOSE_PHASE_HOT(_context, ClassFileMethodCodeAttributeCodeAnalysis);1786J9CfrAttributeCode *codeAttribute = _classFile->methods[methodIndex].codeAttribute;17871788static const U_8 returnArgCharConversion[] = {17890, PARAM_INT, PARAM_INT, PARAM_DOUBLE,17900, PARAM_FLOAT, 0, 0,1791PARAM_INT, PARAM_LONG, 0, PARAM_OBJECT,17920, 0, 0, 0,17930, 0, PARAM_INT, 0,17940, PARAM_VOID, 0, 0,17950, PARAM_INT1796};17971798static const U_8 returnBytecodeConversion[] = {1799PARAM_INT, /* ireturn */1800PARAM_LONG, /* lreturn */1801PARAM_FLOAT, /* freturn */1802PARAM_DOUBLE, /* dreturn */1803PARAM_OBJECT, /* areturn */1804PARAM_VOID /* return */1805};18061807Trc_BCU_Assert_NotEquals(NULL, codeAttribute);18081809U_32 step = 0;1810U_16 cpIndex = 0;1811U_32 branchCount = 1;18121813U_16 methodDescriptorIndex = _classFile->methods[methodIndex].descriptorIndex;1814U_8 *methodDescriptorData = getUTF8Data(methodDescriptorIndex);1815U_16 methodDescriptorLength = getUTF8Length(methodDescriptorIndex);1816U_8 returnType = methodDescriptorData[methodDescriptorLength - 1];1817if (( returnType == ';') || (methodDescriptorData[methodDescriptorLength - 2] == '[')) {1818returnType = PARAM_OBJECT;1819} else {1820returnType = returnArgCharConversion[returnType - 'A'];1821}18221823/* In the worst case scenario, all bytecodes are LDCs and thus half the bytes will need fixup entries. */1824UDATA maxFixupTableSize = (codeAttribute->codeLength / 2) * sizeof(BytecodeFixupEntry);1825BytecodeFixupEntry *fixupTable = (BytecodeFixupEntry *) _bufferManager->alloc(maxFixupTableSize);1826if (NULL == fixupTable) {1827_buildResult = OutOfMemory;1828return;1829}1830BytecodeFixupEntry *entry = fixupTable;18311832U_8 *code = codeAttribute->code;1833for (U_32 codeIndex = 0; codeIndex < codeAttribute->codeLength; codeIndex += step) { /* NOTE codeIndex is modified below for CFR_BC_tableswitch and CFR_BC_lookupswitch */18341835U_8 sunInstruction = code[codeIndex];18361837step = sunJavaInstructionSizeTable[sunInstruction];18381839/* Unknown bytecodes should have been detected by the static verifier. */1840Trc_BCU_Assert_SupportedByteCode(sunInstruction);18411842/* TODO: A lot of cases in this switch are very similar, can we use a lookup table to match them faster? */1843switch (sunInstruction) {1844case CFR_BC_ireturn:1845case CFR_BC_freturn:1846case CFR_BC_areturn:1847case CFR_BC_lreturn:1848case CFR_BC_dreturn:1849case CFR_BC_return:1850if (returnType == returnBytecodeConversion[sunInstruction - CFR_BC_ireturn]) {1851code[codeIndex] = JBgenericReturn;1852} else if (returnType == PARAM_VOID) {1853code[codeIndex] = JBreturn1;1854} else {1855code[codeIndex] = JBreturn0;1856}1857break;18581859case CFR_BC_aload_0:1860if (CFR_BC_getfield == code[codeIndex + 1]) {1861code[codeIndex] = JBaload0getfield;1862}1863break;18641865case CFR_BC_ldc:1866cpIndex = PARAM_U8();1867if (isConstantInteger0(cpIndex)) {1868/* Don't allow constant int of 0, use iconst_0 - for string/class resolution later */1869code[codeIndex] = JBnop;1870code[codeIndex + 1] = JBiconst0;1871} else if (isConstantFloat0(cpIndex)) {1872/* Don't allow constant float of 0, use fconst_0 - for string/class resolution later */1873code[codeIndex] = JBnop;1874code[codeIndex + 1] = JBfconst0;1875} else {1876markConstantAsUsedByLDC(U_8(cpIndex));1877addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::LDC);1878markConstantBasedOnCpType(cpIndex, true);1879}1880break;18811882case CFR_BC_wide: {1883U_8 nextInstruction = code[codeIndex + 1];1884/* byteswap and move up the U_16 local variable index */1885#if !defined(J9VM_ENV_LITTLE_ENDIAN)1886code[codeIndex + 1] = code[codeIndex + 2];1887code[codeIndex + 2] = code[codeIndex + 3];1888#else1889code[codeIndex + 1] = code[codeIndex + 3];1890/* Don't need to do: code[codeIndex + 2] = code[codeIndex + 2]; */1891#endif1892if (CFR_BC_iinc == nextInstruction) {1893code[codeIndex + 0] = JBiincw;1894/* byteswap and move up the U_16 increment */1895#if !defined(J9VM_ENV_LITTLE_ENDIAN)1896code[codeIndex + 3] = code[codeIndex + 4];1897code[codeIndex + 4] = code[codeIndex + 5];1898#else1899code[codeIndex + 3] = code[codeIndex + 5];1900/* Don't need to do: code[codeIndex + 4] = code[codeIndex + 4]; */1901#endif1902code[codeIndex + 5] = JBnop;1903} else {1904if (CFR_BC_istore <= nextInstruction) {1905/* Stores - assumes JB?storew in same order as CFR_BC_?store */1906code[codeIndex + 0] = (nextInstruction - CFR_BC_istore) + JBistorew;1907} else {1908/* Loads - assumes JB?loadw in same order as CFR_BC_?load */1909code[codeIndex + 0] = (nextInstruction - CFR_BC_iload) + JBiloadw;1910}1911code[codeIndex + 3] = JBnop;1912}1913/* Wide instruction are twice as wide as the original instructions */1914step = sunJavaInstructionSizeTable[nextInstruction] * 2;1915break;1916}19171918case CFR_BC_ldc_w:1919cpIndex = PARAM_U16();1920if (isConstantInteger0(cpIndex)) {1921/* Don't allow constant int of 0, use iconst_0 - for string/class resolution later */1922code[codeIndex + 0] = JBnop;1923code[codeIndex + 1] = JBiconst0;1924code[codeIndex + 2] = JBnop;1925} else if (isConstantFloat0(cpIndex)) {1926/* Don't allow constant float of 0, use fconst_0 - for string/class resolution later */1927code[codeIndex + 0] = JBnop;1928code[codeIndex + 1] = JBfconst0;1929code[codeIndex + 2] = JBnop;1930} else {1931addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::REFERENCED);1932markConstantBasedOnCpType(cpIndex, true);1933}1934break;19351936case CFR_BC_ldc2_w:1937cpIndex = PARAM_U16();1938addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::LDC2W);19391940if (isConstantLong(cpIndex)) {1941code[codeIndex + 0] = JBldc2lw;1942markConstantAsUsedByLDC2W(cpIndex);1943} else if (isConstantDouble(cpIndex)) {1944code[codeIndex + 0] = JBldc2dw;1945markConstantAsUsedByLDC2W(cpIndex);1946} else if (isConstantDynamic(cpIndex)) {1947code[codeIndex + 0] = constantDynamicType(cpIndex);1948markConstantDynamicAsReferenced(cpIndex);1949} else {1950Trc_BCU_Assert_ShouldNeverHappen();1951}1952break;19531954case CFR_BC_tableswitch: {1955codeIndex += 4 - (codeIndex & 3); /* step past instruction + pad */1956SWAP_I32(codeIndex);1957codeIndex += sizeof(I_32); /* default offset */1958I_32 low = SWAP_I32_GET(codeIndex);1959codeIndex += sizeof(I_32);1960I_32 high = SWAP_I32_GET(codeIndex);1961codeIndex += sizeof(I_32);1962I_32 noffsets = high - low + 1;1963#if defined(J9VM_ENV_LITTLE_ENDIAN)1964for (U_32 offsetsCount = high - low + 1; 0 != offsetsCount; --offsetsCount) {1965SWAP_I32(codeIndex);1966codeIndex += sizeof(I_32);1967}1968#else1969codeIndex += noffsets * sizeof(I_32);1970#endif1971step = 0; /* codeIndex increment has been handled already */1972branchCount += noffsets + 1;1973break;1974}19751976case CFR_BC_lookupswitch: {1977codeIndex += 4 - (codeIndex & 3); /* step past instruction + pad */1978SWAP_I32(codeIndex);1979codeIndex += sizeof(I_32); /* default offset */1980I_32 npairs = SWAP_I32_GET(codeIndex);1981codeIndex += sizeof(I_32);1982#if defined(J9VM_ENV_LITTLE_ENDIAN)1983for (I_32 count = npairs; 0 != count; --count) {1984SWAP_I32(codeIndex);1985codeIndex += sizeof(I_32);1986SWAP_I32(codeIndex);1987codeIndex += sizeof(I_32);1988}1989#else1990codeIndex += npairs * 2 * sizeof(I_32);1991#endif1992step = 0; /* codeIndex increment has been handled already */1993branchCount += npairs + 1;1994break;1995}19961997case CFR_BC_invokevirtual:1998UDATA methodHandleInvocation;1999cpIndex = PARAM_U16();20002001methodHandleInvocation = shouldConvertInvokeVirtualToMethodHandleBytecodeForMethodRef(cpIndex);2002if (methodHandleInvocation == CFR_BC_invokehandlegeneric) {2003code[codeIndex + 0] = CFR_BC_invokehandlegeneric;2004addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::INVOKE_HANDLEGENERIC);2005markMethodRefAsUsedByInvokeHandleGeneric(cpIndex);2006_methodsInfo[methodIndex].modifiers |= J9AccMethodHasMethodHandleInvokes;2007} else if (methodHandleInvocation == CFR_BC_invokehandle) {2008code[codeIndex + 0] = CFR_BC_invokehandle;2009addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::INVOKE_HANDLEEXACT);2010markMethodRefAsUsedByInvokeHandle(cpIndex);2011_methodsInfo[methodIndex].modifiers |= J9AccMethodHasMethodHandleInvokes;2012} else if (shouldConvertInvokeVirtualToInvokeSpecialForMethodRef(cpIndex)) {2013code[codeIndex + 0] = CFR_BC_invokespecial;2014addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::INVOKE_SPECIAL);2015markMethodRefAsUsedByInvokeSpecial(cpIndex);2016} else {2017addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::INVOKE_VIRTUAL);2018markMethodRefAsUsedByInvokeVirtual(cpIndex);2019}2020break;20212022case CFR_BC_invokeinterface:2023cpIndex = PARAM_U16();2024markMethodRefAsUsedByInvokeInterface(cpIndex);2025addBytecodeFixupEntry(entry++, codeIndex + 3, cpIndex, ConstantPoolMap::INVOKE_INTERFACE);2026code[codeIndex + 0] = JBinvokeinterface2;2027code[codeIndex + 1] = JBnop;2028code[codeIndex + 2] = JBinvokeinterface;2029break;20302031case CFR_BC_invokedynamic:2032cpIndex = PARAM_U16();2033markInvokeDynamicInfoAsUsedByInvokeDynamic(cpIndex);2034addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::INVOKE_DYNAMIC);2035// TODO slam in JBnop2 to code[codeIndex + 3]?2036_methodsInfo[methodIndex].modifiers |= J9AccMethodHasMethodHandleInvokes;2037break;20382039case CFR_BC_putfield:2040cpIndex = PARAM_U16();2041addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::PUT_FIELD);2042markFieldRefAsUsedByPutField(cpIndex);2043break;2044case CFR_BC_invokespecial:2045cpIndex = PARAM_U16();2046addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::INVOKE_SPECIAL);2047markMethodRefAsUsedByInvokeSpecial(cpIndex);2048break;2049case CFR_BC_putstatic:2050cpIndex = PARAM_U16();2051addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::PUT_STATIC);2052markFieldRefAsUsedByPutStatic(cpIndex);2053break;2054case CFR_BC_getfield:2055cpIndex = PARAM_U16();2056addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::GET_FIELD);2057markFieldRefAsUsedByGetField(cpIndex);2058break;2059case CFR_BC_invokestatic:2060cpIndex = PARAM_U16();2061addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::INVOKE_STATIC);2062markMethodRefAsUsedByInvokeStatic(cpIndex);2063break;2064case CFR_BC_getstatic:2065cpIndex = PARAM_U16();2066addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::GET_STATIC);2067markFieldRefAsUsedByGetStatic(cpIndex);2068break;2069case CFR_BC_new:2070cpIndex = PARAM_U16();2071addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::NEW);2072markClassAsUsedByNew(cpIndex);2073if (CFR_BC_dup == code[codeIndex + 3]) {2074code[codeIndex] = JBnewdup;2075}2076break;2077case CFR_BC_anewarray:2078cpIndex = PARAM_U16();2079addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::ANEW_ARRAY);2080markClassAsUsedByANewArray(cpIndex);2081break;2082case CFR_BC_multianewarray:2083cpIndex = PARAM_U16();2084addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::MULTI_ANEW_ARRAY);2085markClassAsUsedByMultiANewArray(cpIndex);2086break;2087case CFR_BC_checkcast:2088cpIndex = PARAM_U16();2089addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::CHECK_CAST);2090markClassAsUsedByCheckCast(cpIndex);2091break;2092case CFR_BC_instanceof:2093cpIndex = PARAM_U16();2094addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::INSTANCE_OF);2095markClassAsUsedByInstanceOf(cpIndex);2096break;20972098#if defined(J9VM_ENV_LITTLE_ENDIAN)2099case CFR_BC_sipush: {2100/* byteswap U_16 */2101U_8 temp = code[codeIndex + 1];2102code[codeIndex + 1] = code[codeIndex + 2];2103code[codeIndex + 2] = temp;2104break;2105}2106#endif21072108case CFR_BC_ifeq:2109/* Fall through */2110case CFR_BC_ifne:2111/* Fall through */2112case CFR_BC_iflt:2113/* Fall through */2114case CFR_BC_ifge:2115/* Fall through */2116case CFR_BC_ifgt:2117/* Fall through */2118case CFR_BC_ifle:2119/* Fall through */2120case CFR_BC_if_icmplt:2121/* Fall through */2122case CFR_BC_if_icmpge:2123/* Fall through */2124case CFR_BC_if_icmpgt:2125/* Fall through */2126case CFR_BC_if_icmple:2127/* Fall through */2128case CFR_BC_if_icmpeq:2129/* Fall through */2130case CFR_BC_if_icmpne:2131/* Fall through */2132case CFR_BC_if_acmpeq:2133/* Fall through */2134case CFR_BC_if_acmpne:2135/* Fall through */2136case CFR_BC_ifnull:2137/* Fall through */2138case CFR_BC_ifnonnull:2139++branchCount;2140/* Fall through */21412142case CFR_BC_goto: {2143#if defined(J9VM_ENV_LITTLE_ENDIAN)2144U_8 temp = code[codeIndex + 1];2145code[codeIndex + 1] = code[codeIndex + 2];2146code[codeIndex + 2] = temp;2147#endif2148if (0 == (_methodsInfo[methodIndex].modifiers & J9AccMethodHasBackwardBranches)) {2149I_32 offset = I_32(*(I_16*)&code[codeIndex + 1]);2150if (offset <= 0) {2151/* The branch wasn't positive, so mark the method as containing backward branches. */2152_methodsInfo[methodIndex].modifiers |= J9AccMethodHasBackwardBranches;2153}2154}2155break;2156}21572158case CFR_BC_goto_w: {2159SWAP_I32(codeIndex + 1);2160if (0 == (_methodsInfo[methodIndex].modifiers & J9AccMethodHasBackwardBranches)) {2161I_32 offset = *(I_32*)&code[codeIndex + 1];2162if (offset <= 0) {2163/* The branch wasn't positive, so mark the method as containing backward branches. */2164_methodsInfo[methodIndex].modifiers |= J9AccMethodHasBackwardBranches;2165}2166}2167break;2168}21692170#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)2171case CFR_BC_aconst_init:2172if (_classFile->majorVersion >= VALUE_TYPES_MAJOR_VERSION) {2173cpIndex = PARAM_U16();2174addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::ACONST_INIT);2175markClassAsUsedByAconst_init(cpIndex);2176}2177break;2178case CFR_BC_withfield:2179if (_classFile->majorVersion >= VALUE_TYPES_MAJOR_VERSION) {2180cpIndex = PARAM_U16();2181addBytecodeFixupEntry(entry++, codeIndex + 1, cpIndex, ConstantPoolMap::WITH_FIELD);2182markFieldRefAsUsedByWithField(cpIndex);2183}2184break;2185#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */21862187default:2188/* Do nothing */2189break;2190}2191}21922193branchCount += _classFile->methods[methodIndex].codeAttribute->exceptionTableLength;2194if (_maxBranchCount < branchCount) {2195_maxBranchCount = branchCount;2196}21972198/* Let the buffer manager reclaim the unused part of the fixup table. */2199UDATA actualFixupTableSize = UDATA(entry) - UDATA(fixupTable);2200_bufferManager->reclaim(fixupTable, actualFixupTableSize);2201_methodsInfo[methodIndex].byteCodeFixupTable = fixupTable;2202_methodsInfo[methodIndex].byteCodeFixupCount = U_32(actualFixupTableSize / sizeof(BytecodeFixupEntry));2203_methodsInfo[methodIndex].isByteCodeFixupDone = false;2204}2205#undef SWAP_I322206#undef SWAP_I32_GET2207#undef PARAM_I162208#undef PARAM_U162209#undef PARAM_U822102211U_8 *2212ClassFileOracle::walkStackMapSlots(U_8 *framePointer, U_16 typeInfoCount)2213{2214ROMCLASS_VERBOSE_PHASE_HOT(_context, ClassFileStackMapSlotsAnalysis);2215U_8 typeInfoType;2216U_16 cpIndex;2217U_16 offset;22182219/*2220* Type info entries are variable sized and distinguished by a 8-bit type tag.2221* Most entry types contain only the tag. The exceptions are described below.2222*/2223for(U_16 typeInfoIndex = 0; typeInfoIndex < typeInfoCount; ++typeInfoIndex) {2224NEXT_U8(typeInfoType, framePointer); /* Extract typeInfoType */2225switch (typeInfoType) {2226case CFR_STACKMAP_TYPE_OBJECT:2227/*2228* OBJECT {2229* U_8 type2230* U_16 cpIndex2231* };2232*/2233NEXT_U16(cpIndex, framePointer); /* Extract cpIndex */2234markClassAsReferenced(cpIndex);2235break;2236case CFR_STACKMAP_TYPE_NEW_OBJECT:2237/*2238* NEW_OBJECT {2239* U_8 type2240* U_16 offset2241* };2242*/2243NEXT_U16(offset, framePointer); /* Extract offset */2244break;2245default:2246/* do nothing */2247break;2248}2249}22502251return framePointer;2252}22532254bool2255ClassFileOracle::methodIsFinalize(U_16 methodIndex, bool isForwarder)2256{2257ROMCLASS_VERBOSE_PHASE_HOT(_context, MethodIsFinalize);22582259#define FINALIZE_NAME "finalize"2260#define FINALIZE_SIG "()V"2261if (2262(0 == (_classFile->methods[methodIndex].accessFlags & CFR_ACC_STATIC))2263&& isUTF8AtIndexEqualToString(_classFile->methods[methodIndex].descriptorIndex, FINALIZE_SIG, sizeof(FINALIZE_SIG))2264&& isUTF8AtIndexEqualToString(_classFile->methods[methodIndex].nameIndex, FINALIZE_NAME, sizeof(FINALIZE_NAME))2265) {2266return true;2267}2268#undef FINALIZE_NAME2269#undef FINALIZE_SIG22702271return false;2272}2273227422752276bool2277ClassFileOracle::methodIsEmpty(U_16 methodIndex)2278{2279ROMCLASS_VERBOSE_PHASE_HOT(_context, MethodIsEmpty);2280if (0 == (_classFile->methods[methodIndex].accessFlags & (CFR_ACC_ABSTRACT | CFR_ACC_NATIVE | CFR_ACC_SYNCHRONIZED))) {2281U_8 instruction = _classFile->methods[methodIndex].codeAttribute->code[0];2282if ((CFR_BC_ireturn <= instruction) && (instruction <= CFR_BC_return)) {2283return true;2284}2285}2286return false;2287}22882289bool2290ClassFileOracle::methodIsObjectConstructor(U_16 methodIndex)2291{2292ROMCLASS_VERBOSE_PHASE_HOT(_context, MethodIsObjectConstructor);22932294if ((0 == _classFile->superClass) &&2295(0 == (_classFile->methods[methodIndex].accessFlags & (CFR_ACC_ABSTRACT | CFR_ACC_STATIC | CFR_ACC_PRIVATE | CFR_ACC_SYNCHRONIZED))) &&2296('<' == getUTF8Data(_classFile->methods[methodIndex].nameIndex)[0]))2297{2298return true;2299}23002301return false;2302}23032304#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)2305/**2306* Determine if a method is constructor of a non-Value Type (Value Type constructors are static).2307*2308* @param methodIndex[in] the method index2309*2310* @returns true if the method is a constructor of a non-Value Type, false if not.2311*/2312bool2313ClassFileOracle::methodIsConstructor(U_16 methodIndex)2314{2315ROMCLASS_VERBOSE_PHASE_HOT(_context, MethodIsConstructor);23162317if (J9_ARE_NO_BITS_SET(_classFile->methods[methodIndex].accessFlags, (CFR_ACC_ABSTRACT | CFR_ACC_STATIC | CFR_ACC_SYNCHRONIZED))2318&& ('<' == getUTF8Data(_classFile->methods[methodIndex].nameIndex)[0])2319) {2320return true;2321}23222323return false;2324}2325#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */23262327/**2328* Determine if a method is <clinit>.2329*2330* @param methodIndex[in] the method index2331*2332* @returns true if the method is <clinit>, false if not2333*/2334bool2335ClassFileOracle::methodIsClinit(U_16 methodIndex)2336{2337ROMCLASS_VERBOSE_PHASE_HOT(_context, MethodIsClinit);23382339/* Use a quick check - assume any static method starting with < is <clinit>.2340* This can not be harmful, as the worst thing that happens is we would lose2341* the performance optimization on questionable class files.2342*/2343if ((_classFile->methods[methodIndex].accessFlags & CFR_ACC_STATIC) &&2344('<' == getUTF8Data(_classFile->methods[methodIndex].nameIndex)[0]))2345{2346return true;2347}23482349return false;2350}23512352/* answers non-zero if this method simply forwards to its superclass.2353A forwarder method is not synchronized.2354Forwarder methods must have return type void (because right now we only care if it forwards to an empty method)2355*/23562357bool2358ClassFileOracle::methodIsForwarder(U_16 methodIndex)2359{2360ROMCLASS_VERBOSE_PHASE_HOT(_context, MethodIsForwarder);2361if (_classFile->methods[methodIndex].accessFlags & (CFR_ACC_ABSTRACT | CFR_ACC_NATIVE | CFR_ACC_SYNCHRONIZED | CFR_ACC_STATIC)) {2362return false;2363}23642365/* Must return void */2366U_16 signatureIndex = _classFile->methods[methodIndex].descriptorIndex;2367U_8 *signatureData = getUTF8Data(signatureIndex);2368U_16 signatureLength = getUTF8Length(signatureIndex);2369if ((signatureData[signatureLength - 1]) != 'V') {2370return false;2371}23722373J9CfrAttributeCode *codeAttribute = _classFile->methods[methodIndex].codeAttribute;23742375/* ensure that there are no exception handlers */2376if (codeAttribute->exceptionTableLength > 0) {2377return false;2378}23792380/* check that there are no temps */2381U_8 argCount = _methodsInfo[methodIndex].sendSlotCount;2382++argCount; /* not static */2383U_16 tempCount = codeAttribute->maxLocals;2384if (tempCount >= argCount) {2385tempCount -= argCount;2386} else {2387Trc_BCU_Assert_Equals(0, tempCount);2388}23892390if (0 != tempCount) {2391return false;2392}23932394IDATA thisArg = 0;2395U_8 *code = codeAttribute->code;2396for (U_32 codeIndex = 0; ;codeIndex++) {2397switch (code[codeIndex]) {2398case CFR_BC_aload_0:2399if (thisArg++ != 0) {2400return false;2401}2402break;2403case CFR_BC_iload_1:2404case CFR_BC_fload_1:2405case CFR_BC_aload_1:2406if (thisArg++ != 1) {2407return false;2408}2409break;2410case CFR_BC_dload_1:2411case CFR_BC_lload_1:2412if (thisArg != 1) {2413return false;2414}2415thisArg += 2;2416break;2417case CFR_BC_iload_2:2418case CFR_BC_fload_2:2419case CFR_BC_aload_2:2420if (thisArg++ != 2) {2421return false;2422}2423break;2424case CFR_BC_dload_2:2425case CFR_BC_lload_2:2426if (thisArg != 2) {2427return false;2428}2429thisArg += 2;2430break;2431case CFR_BC_iload_3:2432case CFR_BC_fload_3:2433case CFR_BC_aload_3:2434if (thisArg++ != 3) {2435return false;2436}2437break;2438case CFR_BC_dload_3:2439case CFR_BC_lload_3:2440if (thisArg != 3) {2441return false;2442}2443thisArg += 2;2444break;2445case CFR_BC_iload:2446case CFR_BC_fload:2447case CFR_BC_aload:2448if (thisArg++ != code[++codeIndex]) {2449return false;2450}2451break;2452case CFR_BC_dload:2453case CFR_BC_lload:2454if (thisArg != code[++codeIndex]) {2455return false;2456}2457thisArg += 2;2458break;2459case CFR_BC_invokespecial: {2460if (thisArg++ != argCount) {2461/* we haven't pushed all of our arguments */2462return false;2463}2464#define PARAM_U16() (U_16(code[codeIndex + 1]) << 8) | U_16(code[codeIndex + 2])2465J9CfrConstantPoolInfo *methodRef = (J9CfrConstantPoolInfo *) &_classFile->constantPool[PARAM_U16()];2466#undef PARAM_U1624672468/* use identity comparisons for name and sig for simplicity. Since they came from the same2469class file they're almost certainly identical,and if not we just run a bit slower */24702471/* check that this is a super send */2472if ( methodRef->slot1 != _classFile->superClass ) {2473return false;2474}2475J9CfrConstantPoolInfo *nas = (J9CfrConstantPoolInfo *) &_classFile->constantPool[methodRef->slot2];2476if ( !isUTF8AtIndexEqualToString(nas->slot1, (const char *)getUTF8Data(_classFile->methods[methodIndex].nameIndex), getUTF8Length(_classFile->methods[methodIndex].nameIndex)+1)) {2477return false;2478}2479if ( !isUTF8AtIndexEqualToString(nas->slot2, (const char *)getUTF8Data(_classFile->methods[methodIndex].descriptorIndex), getUTF8Length(_classFile->methods[methodIndex].descriptorIndex)+1)) {2480return false;2481}24822483/* check that the next instruction is a void return */2484if (CFR_BC_return == code[codeIndex+3]) {2485return true;2486}24872488/* fall through */2489}2490default:2491return false;2492}2493}24942495/* can't get here, but add a return false just in case */2496return false;2497}2498249925002501bool2502ClassFileOracle::methodIsGetter (U_16 methodIndex)2503{2504ROMCLASS_VERBOSE_PHASE_HOT(_context, MethodIsGetter);250525062507if (0 != (_classFile->methods[methodIndex].accessFlags & (CFR_ACC_ABSTRACT | CFR_ACC_NATIVE | CFR_ACC_SYNCHRONIZED | CFR_ACC_STATIC))) {2508return false;2509}25102511/* ensure that there are no exception handlers */2512if (0 != _classFile->methods[methodIndex].codeAttribute->exceptionTableLength) {2513return false;2514}25152516/* ensure that there's exactly one argument (the receiver) */2517if (')' != getUTF8Data(_classFile->methods[methodIndex].descriptorIndex)[1]) {2518return false;2519}25202521/* this exact bytecode sequence */2522/* JBaload0getfield means JBgetfield follows2523* NOTEs:2524* - JBaload0getfield is actually CFR_BC_aload_0 followed by CFR_BC_getfield in Sun bytecodes2525* - JBgenericReturn is any one of the return bytecodes CFR_BC_*return */2526U_8* sunBytecodes = _classFile->methods[methodIndex].codeAttribute->code;2527if ((CFR_BC_aload_0 == sunBytecodes[0]) && (CFR_BC_getfield == sunBytecodes[1]) && (CFR_BC_ireturn <= sunBytecodes[4]) && (sunBytecodes[4] <= CFR_BC_return)) {2528return true;2529}25302531return false;2532}25332534bool2535ClassFileOracle::methodIsVirtual(U_16 methodIndex)2536{2537ROMCLASS_VERBOSE_PHASE_HOT(_context, MethodIsVirtual);25382539/* static and private methods are never virtual */2540if (0 != (_classFile->methods[methodIndex].accessFlags & (CFR_ACC_STATIC | CFR_ACC_PRIVATE))) {2541return false;2542}25432544/* <init> (and <clinit>) are not virtual */2545if ('<' == getUTF8Data(_classFile->methods[methodIndex].nameIndex)[0]) {2546return false;2547}25482549if (0 == _classFile->superClass) { // TODO is this the same as J9ROMCLASS_SUPERCLASSNAME(romClass) == NULL???2550/* check for the final methods in object */2551if (methodIsFinalInObject (2552getUTF8Length(_classFile->methods[methodIndex].nameIndex),2553getUTF8Data(_classFile->methods[methodIndex].nameIndex),2554getUTF8Length(_classFile->methods[methodIndex].descriptorIndex),2555getUTF8Data(_classFile->methods[methodIndex].descriptorIndex)2556)) {2557return false;2558}2559}2560return true;2561}25622563bool2564ClassFileOracle::methodIsNonStaticNonAbstract(U_16 methodIndex)2565{2566ROMCLASS_VERBOSE_PHASE_HOT(_context, IsMethodNonStaticNonAbstract);25672568return J9_ARE_NO_BITS_SET(_classFile->methods[methodIndex].accessFlags, (CFR_ACC_STATIC | CFR_ACC_ABSTRACT));2569}25702571#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)2572bool2573ClassFileOracle::methodIsNonStaticSynchronized(U_16 methodIndex)2574{2575ROMCLASS_VERBOSE_PHASE_HOT(_context, MethodIsNonStaticSynchronized);2576if (J9_ARE_NO_BITS_SET(_classFile->methods[methodIndex].accessFlags, CFR_ACC_STATIC)2577&& J9_ARE_ALL_BITS_SET(_classFile->methods[methodIndex].accessFlags, CFR_ACC_SYNCHRONIZED)2578) {2579return true;2580}2581return false;2582}2583#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */25842585/**2586* Method to determine if an invokevirtual instruction should be re-written to be an2587* invokehandle or invokehandlegeneric bytecode. Modifications as follows:2588* invokevirtual MethodHandle.invokeExact(any signature) --> invokehandle2589* invokevirtual MethodHandle.invoke(any signature) --> invokehandlegeneric2590*2591* @param methodRefCPIndex - the constantpool index used in the invokevirtual bytecode2592* @return the invoke* bytecode to be used if it needs to be rewritten or 02593* ie: One of: CFR_BC_invokehandlegeneric, CFR_BC_invokehandle, 02594*/2595UDATA2596ClassFileOracle::shouldConvertInvokeVirtualToMethodHandleBytecodeForMethodRef(U_16 methodRefCPIndex)2597{2598J9CfrConstantPoolInfo *methodInfo = &_classFile->constantPool[methodRefCPIndex];2599J9CfrConstantPoolInfo *targetClassName = &_classFile->constantPool[ _classFile->constantPool[methodInfo->slot1].slot1 ];2600J9CfrConstantPoolInfo *nas = &_classFile->constantPool[methodInfo->slot2];2601J9CfrConstantPoolInfo *name = &_classFile->constantPool[nas->slot1];2602UDATA result = 0;26032604/* Invoking against java.lang.invoke.MethodHandle. */2605if (J9UTF8_LITERAL_EQUALS(targetClassName->bytes, targetClassName->slot1, "java/lang/invoke/MethodHandle")) {2606if (J9UTF8_LITERAL_EQUALS(name->bytes, name->slot1, "invokeExact")) {2607/* MethodHandle.invokeExact */2608result = CFR_BC_invokehandle;2609} else if (J9UTF8_LITERAL_EQUALS(name->bytes, name->slot1, "invoke")) {2610/* MethodHandle.invoke */2611#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)2612result = CFR_BC_invokehandle;2613#else /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */2614result = CFR_BC_invokehandlegeneric;2615#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */2616}2617}26182619#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)2620/* Invoking against java.lang.invoke.VarHandle. */2621if (J9UTF8_LITERAL_EQUALS(targetClassName->bytes, targetClassName->slot1, "java/lang/invoke/VarHandle")2622&& VM_VMHelpers::isPolymorphicVarHandleMethod((const U_8 *)name->bytes, name->slot1)2623) {2624result = CFR_BC_invokehandle;2625}2626#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */26272628return result;2629}26302631bool2632ClassFileOracle::shouldConvertInvokeVirtualToInvokeSpecialForMethodRef(U_16 methodRefCPIndex)2633{2634ROMCLASS_VERBOSE_PHASE_HOT(_context, ShouldConvertInvokeVirtualToInvokeSpecial);26352636J9CfrConstantPoolInfo *methodInfo = &_classFile->constantPool[methodRefCPIndex];2637J9CfrConstantPoolInfo *className = &_classFile->constantPool[ _classFile->constantPool[_classFile->thisClass].slot1 ];2638J9CfrConstantPoolInfo *targetClassName = &_classFile->constantPool[ _classFile->constantPool[methodInfo->slot1].slot1 ];2639J9CfrConstantPoolInfo *nas = &_classFile->constantPool[methodInfo->slot2];2640J9CfrConstantPoolInfo *name = &_classFile->constantPool[nas->slot1];2641J9CfrConstantPoolInfo *sig = &_classFile->constantPool[nas->slot2];26422643/* check for wait, notify, notifyAll and getClass first */2644if (methodIsFinalInObject(name->slot1, name->bytes, sig->slot1, sig->bytes)) {2645return true;2646}26472648/* Interfaces are allowed to call methods in java.lang.Object but other invokevirtual must fail */2649if (J9_ARE_ANY_BITS_SET(_classFile->accessFlags, CFR_ACC_INTERFACE)) {2650return false;2651}26522653/* check for private methods (this is unlikely to be generated by a working compiler,2654* but it is legal, so check for the case and force it to be an invokespecial)2655*/2656// TODO this hurts performance significantly - can we get away with not doing this? E.g. does it inflate vtables? Does the JIT do "the right thing"?2657if (J9UTF8_DATA_EQUALS(className->bytes, className->slot1, targetClassName->bytes, targetClassName->slot1)) {2658for (UDATA methodIndex = 0; methodIndex < _classFile->methodsCount; methodIndex++) {2659J9CfrMethod* method = &_classFile->methods[methodIndex];2660J9CfrConstantPoolInfo *aName = &_classFile->constantPool[method->nameIndex];2661J9CfrConstantPoolInfo *aSig = &_classFile->constantPool[method->descriptorIndex];2662if ((aName->slot1 == name->slot1)2663&& (aSig->slot1 == sig->slot1)2664&& (0 == memcmp(aName->bytes, name->bytes, name->slot1))2665&& (0 == memcmp(aSig->bytes, sig->bytes, sig->slot1))2666) {2667/* we found the method -- is it private or final? */2668return (method->accessFlags & (CFR_ACC_PRIVATE | CFR_ACC_FINAL)) != 0;2669}2670}2671}2672return false;2673}26742675void2676ClassFileOracle::markClassAsReferenced(U_16 classCPIndex)2677{2678Trc_BCU_Assert_Equals(CFR_CONSTANT_Class, _classFile->constantPool[classCPIndex].tag);26792680markConstantAsReferenced(classCPIndex); /* Mark class */2681markClassNameAsReferenced(classCPIndex);2682}26832684void2685ClassFileOracle::markClassNameAsReferenced(U_16 classCPIndex)2686{2687Trc_BCU_Assert_Equals(CFR_CONSTANT_Class, _classFile->constantPool[classCPIndex].tag);26882689markConstantUTF8AsReferenced(_classFile->constantPool[classCPIndex].slot1); /* Mark class name UTF8 */2690}26912692void2693ClassFileOracle::markStringAsReferenced(U_16 cpIndex)2694{2695Trc_BCU_Assert_Equals(CFR_CONSTANT_String, _classFile->constantPool[cpIndex].tag);26962697markConstantAsReferenced(cpIndex); /* Mark string */2698markConstantUTF8AsReferenced(_classFile->constantPool[cpIndex].slot1); /* Mark UTF8 */2699}27002701void2702ClassFileOracle::markMethodTypeAsReferenced(U_16 cpIndex)2703{2704Trc_BCU_Assert_Equals(CFR_CONSTANT_MethodType, _classFile->constantPool[cpIndex].tag);27052706markConstantAsReferenced(cpIndex); /* Mark MethodType */2707markConstantUTF8AsReferenced(_classFile->constantPool[cpIndex].slot1); /* Mark UTF8 */2708}27092710void2711ClassFileOracle::markMethodHandleAsReferenced(U_16 cpIndex)2712{27132714Trc_BCU_Assert_Equals(CFR_CONSTANT_MethodHandle, _classFile->constantPool[cpIndex].tag);27152716markConstantAsReferenced(cpIndex); /* Mark MethodHandle */27172718switch(_classFile->constantPool[cpIndex].slot1) {2719case MH_REF_GETFIELD:2720markFieldRefAsUsedByGetField(_classFile->constantPool[cpIndex].slot2);2721break;2722case MH_REF_GETSTATIC:2723markFieldRefAsUsedByGetStatic(_classFile->constantPool[cpIndex].slot2);2724break;2725case MH_REF_PUTFIELD:2726markFieldRefAsUsedByPutField(_classFile->constantPool[cpIndex].slot2);2727break;2728case MH_REF_PUTSTATIC:2729markFieldRefAsUsedByPutStatic(_classFile->constantPool[cpIndex].slot2);2730break;2731case MH_REF_INVOKEVIRTUAL:2732markMethodRefAsUsedByInvokeVirtual(_classFile->constantPool[cpIndex].slot2);2733break;2734case MH_REF_INVOKESTATIC:2735markMethodRefAsUsedByInvokeStatic(_classFile->constantPool[cpIndex].slot2);2736break;2737case MH_REF_INVOKESPECIAL:2738case MH_REF_NEWINVOKESPECIAL:2739markMethodRefAsUsedByInvokeSpecial(_classFile->constantPool[cpIndex].slot2);2740break;2741case MH_REF_INVOKEINTERFACE:2742markMethodRefAsUsedByInvokeInterface(_classFile->constantPool[cpIndex].slot2);2743break;2744}2745}27462747void2748ClassFileOracle::markNameAndDescriptorAsReferenced(U_16 nasCPIndex)2749{2750Trc_BCU_Assert_Equals(CFR_CONSTANT_NameAndType, _classFile->constantPool[nasCPIndex].tag);27512752markConstantNameAndTypeAsReferenced(nasCPIndex); /* Mark name-and-signature */2753markConstantUTF8AsReferenced(_classFile->constantPool[nasCPIndex].slot1); /* Mark name UTF8 */2754markConstantUTF8AsReferenced(_classFile->constantPool[nasCPIndex].slot2); /* Mark descriptor UTF8 */2755}27562757void2758ClassFileOracle::markFieldRefAsReferenced(U_16 cpIndex)2759{2760Trc_BCU_Assert_Equals(CFR_CONSTANT_Fieldref, _classFile->constantPool[cpIndex].tag);27612762// TODO markConstantAsReferenced(cpIndex); -- this breaks the iteration strategy in ROMClassBuilder2763markClassAsReferenced(_classFile->constantPool[cpIndex].slot1);2764markNameAndDescriptorAsReferenced(_classFile->constantPool[cpIndex].slot2);2765}27662767void2768ClassFileOracle::markMethodRefAsReferenced(U_16 cpIndex)2769{2770Trc_BCU_Assert_True((CFR_CONSTANT_Methodref == _classFile->constantPool[cpIndex].tag) || (CFR_CONSTANT_InterfaceMethodref == _classFile->constantPool[cpIndex].tag));27712772// TODO markConstantAsReferenced(cpIndex); -- this breaks the iteration strategy in ROMClassBuilder2773markClassAsReferenced(_classFile->constantPool[cpIndex].slot1);2774markNameAndDescriptorAsReferenced(_classFile->constantPool[cpIndex].slot2);2775}27762777/* Mark the parts of a MethodRef used for a MethodTypeRef - just the signature of the methodref's nas.2778* The invokehandle/invokehandlegeneric instruction will only ever preserve the signature.2779*/2780void2781ClassFileOracle::markMethodRefForMHInvocationAsReferenced(U_16 cpIndex)2782{2783markMethodRefAsReferenced(cpIndex);2784}27852786void2787ClassFileOracle::markConstantAsReferenced(U_16 cpIndex)2788{2789if (0 != cpIndex) { /* Never, never, never mark constantPool[0] referenced */2790_constantPoolMap->markConstantAsReferenced(cpIndex);2791}2792}27932794void2795ClassFileOracle::markConstantUTF8AsReferenced(U_16 cpIndex)2796{2797if (0 != cpIndex) { /* Never, never, never mark constantPool[0] referenced */2798_constantPoolMap->markConstantUTF8AsReferenced(cpIndex);2799}2800}28012802void2803ClassFileOracle::markConstantNameAndTypeAsReferenced(U_16 cpIndex)2804{2805if (0 != cpIndex) { /* Never, never, never mark constantPool[0] referenced */2806_constantPoolMap->markConstantNameAndTypeAsReferenced(cpIndex);2807}2808}28092810void2811ClassFileOracle::markConstantDynamicAsReferenced(U_16 cpIndex)2812{2813markNameAndDescriptorAsReferenced(_classFile->constantPool[cpIndex].slot2);2814if (0 != cpIndex) { /* Never, never, never mark constantPool[0] referenced */2815_constantPoolMap->markConstantAsReferenced(cpIndex);2816}2817}28182819void2820ClassFileOracle::markConstantAsUsedByAnnotation(U_16 cpIndex)2821{2822UDATA cpTag = getCPTag(cpIndex);28232824if ((CFR_CONSTANT_Double == cpTag) || (CFR_CONSTANT_Long == cpTag)) {2825_constantPoolMap->markConstantAsReferencedDoubleSlot(cpIndex);2826} else if (CFR_CONSTANT_Utf8 == cpTag) {2827markConstantUTF8AsReferenced(cpIndex); /* Mark descriptor UTF8 */2828/* Is not equivalent to markConstantAsReferenced(), as that does something else for UTF8s. */2829_constantPoolMap->markConstantAsUsedByAnnotationUTF8(cpIndex);2830} else {2831markConstantAsReferenced(cpIndex);2832}2833}28342835void2836ClassFileOracle::markConstantAsUsedByLDC(U_8 cpIndex)2837{2838_constantPoolMap->markConstantAsUsedByLDC(cpIndex);2839}28402841void2842ClassFileOracle::markConstantAsUsedByLDC2W(U_16 cpIndex)2843{2844_constantPoolMap->markConstantAsReferencedDoubleSlot(cpIndex);2845}28462847void2848ClassFileOracle::markClassAsUsedByInstanceOf(U_16 classCPIndex)2849{2850markClassAsReferenced(classCPIndex);2851_constantPoolMap->markClassAsUsedByInstanceOf(classCPIndex);2852}28532854void2855ClassFileOracle::markClassAsUsedByCheckCast(U_16 classCPIndex)2856{2857markClassAsReferenced(classCPIndex);2858_constantPoolMap->markClassAsUsedByCheckCast(classCPIndex);2859}28602861void2862ClassFileOracle::markClassAsUsedByMultiANewArray(U_16 classCPIndex)2863{2864markClassAsReferenced(classCPIndex);2865_constantPoolMap->markClassAsUsedByMultiANewArray(classCPIndex);2866}28672868void2869ClassFileOracle::markClassAsUsedByANewArray(U_16 classCPIndex)2870{2871markClassAsReferenced(classCPIndex);2872_constantPoolMap->markClassAsUsedByANewArray(classCPIndex);2873}28742875void2876ClassFileOracle::markClassAsUsedByNew(U_16 classCPIndex)2877{2878markClassAsReferenced(classCPIndex);2879_constantPoolMap->markClassAsUsedByNew(classCPIndex);2880}28812882#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)2883void2884ClassFileOracle::markClassAsUsedByAconst_init(U_16 classCPIndex)2885{2886markClassAsReferenced(classCPIndex);2887_constantPoolMap->markClassAsUsedByAconst_init(classCPIndex);2888}28892890void2891ClassFileOracle::markFieldRefAsUsedByWithField(U_16 fieldRefCPIndex)2892{2893markFieldRefAsReferenced(fieldRefCPIndex);2894_constantPoolMap->markFieldRefAsUsedByWithField(fieldRefCPIndex);2895}2896#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */28972898void2899ClassFileOracle::markFieldRefAsUsedByGetStatic(U_16 fieldRefCPIndex)2900{2901markFieldRefAsReferenced(fieldRefCPIndex);2902_constantPoolMap->markFieldRefAsUsedByGetStatic(fieldRefCPIndex);2903}29042905void2906ClassFileOracle::markFieldRefAsUsedByPutStatic(U_16 fieldRefCPIndex)2907{2908markFieldRefAsReferenced(fieldRefCPIndex);2909_constantPoolMap->markFieldRefAsUsedByPutStatic(fieldRefCPIndex);2910}29112912void2913ClassFileOracle::markFieldRefAsUsedByGetField(U_16 fieldRefCPIndex)2914{2915markFieldRefAsReferenced(fieldRefCPIndex);2916_constantPoolMap->markFieldRefAsUsedByGetField(fieldRefCPIndex);2917}29182919void2920ClassFileOracle::markFieldRefAsUsedByPutField(U_16 fieldRefCPIndex)2921{2922markFieldRefAsReferenced(fieldRefCPIndex);2923_constantPoolMap->markFieldRefAsUsedByPutField(fieldRefCPIndex);2924}29252926void2927ClassFileOracle::markMethodRefAsUsedByInvokeVirtual(U_16 methodRefCPIndex)2928{2929markMethodRefAsReferenced(methodRefCPIndex);2930_constantPoolMap->markMethodRefAsUsedByInvokeVirtual(methodRefCPIndex);2931}29322933void2934ClassFileOracle::markMethodRefAsUsedByInvokeSpecial(U_16 methodRefCPIndex)2935{2936markMethodRefAsReferenced(methodRefCPIndex);2937_constantPoolMap->markMethodRefAsUsedByInvokeSpecial(methodRefCPIndex);2938}29392940void2941ClassFileOracle::markMethodRefAsUsedByInvokeStatic(U_16 methodRefCPIndex)2942{2943markMethodRefAsReferenced(methodRefCPIndex);2944_constantPoolMap->markMethodRefAsUsedByInvokeStatic(methodRefCPIndex);2945}29462947void2948ClassFileOracle::markMethodRefAsUsedByInvokeInterface(U_16 methodRefCPIndex)2949{2950markMethodRefAsReferenced(methodRefCPIndex);2951_constantPoolMap->markMethodRefAsUsedByInvokeInterface(methodRefCPIndex);2952}29532954void2955ClassFileOracle::markMethodRefAsUsedByInvokeHandle(U_16 methodRefCPIndex)2956{2957markMethodRefForMHInvocationAsReferenced(methodRefCPIndex);2958_constantPoolMap->markMethodRefAsUsedByInvokeHandle(methodRefCPIndex);2959}29602961void2962ClassFileOracle::markMethodRefAsUsedByInvokeHandleGeneric(U_16 methodRefCPIndex)2963{2964markMethodRefForMHInvocationAsReferenced(methodRefCPIndex);2965_constantPoolMap->markMethodRefAsUsedByInvokeHandleGeneric(methodRefCPIndex);2966}29672968void2969ClassFileOracle::markInvokeDynamicInfoAsUsedByInvokeDynamic(U_16 cpIndex)2970{2971Trc_BCU_Assert_Equals(CFR_CONSTANT_InvokeDynamic, _classFile->constantPool[cpIndex].tag);29722973U_16 bsmIndex = _classFile->constantPool[cpIndex].slot1;2974if ((NULL == _bootstrapMethodsAttribute) || (bsmIndex >= _bootstrapMethodsAttribute->numberOfBootstrapMethods)) {2975_buildResult = GenericError;2976return;2977}29782979markNameAndDescriptorAsReferenced(_classFile->constantPool[cpIndex].slot2);2980_constantPoolMap->markInvokeDynamicInfoAsUsedByInvokeDynamic(cpIndex);2981}29822983void2984ClassFileOracle::markConstantBasedOnCpType(U_16 cpIndex, bool assertNotDoubleOrLong)2985{2986switch(getCPTag(cpIndex)) {2987case CFR_CONSTANT_String:2988markStringAsReferenced(cpIndex);2989break;2990case CFR_CONSTANT_Class:2991markClassAsReferenced(cpIndex);2992break;2993case CFR_CONSTANT_Integer:2994case CFR_CONSTANT_Float:2995markConstantAsReferenced(cpIndex);2996break;2997case CFR_CONSTANT_MethodHandle:2998markMethodHandleAsReferenced(cpIndex);2999break;3000case CFR_CONSTANT_MethodType:3001markMethodTypeAsReferenced(cpIndex);3002break;3003case CFR_CONSTANT_Double:3004case CFR_CONSTANT_Long:3005if (assertNotDoubleOrLong) {3006Trc_BCU_Assert_ShouldNeverHappen();3007break;3008}3009_constantPoolMap->markConstantAsReferencedDoubleSlot(cpIndex);3010break;3011case CFR_CONSTANT_Dynamic:3012markConstantDynamicAsReferenced(cpIndex);3013break;3014default:3015Trc_BCU_Assert_ShouldNeverHappen();3016}3017}301830193020