Path: blob/master/runtime/bcutil/ConstantPoolMap.cpp
5985 views
/*******************************************************************************1* Copyright (c) 2001, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/21/*22* ConstantPoolMap.cpp23*24* NOTE: See ConstantPoolMap.hpp for an explanation of why and how constant pool mapping is done.25*/2627#include "ConstantPoolMap.hpp"2829#include "BufferManager.hpp"30#include "ClassFileOracle.hpp"31#include "ROMClassCreationContext.hpp"32#include "ROMClassVerbosePhase.hpp"33#include "VMHelpers.hpp"3435#include "ut_j9bcu.h"3637#define MAX_CALL_SITE_COUNT (1 << 16)38#define MAX_LDC_COUNT (1 << 8)39#define VARHANDLE_CLASS_NAME "java/lang/invoke/VarHandle"4041ConstantPoolMap::ConstantPoolMap(BufferManager *bufferManager, ROMClassCreationContext *context) :42_context(context),43_classFileOracle(NULL),44_bufferManager(bufferManager),45_constantPoolEntries(NULL),46_romConstantPoolEntries(NULL),47_romConstantPoolTypes(NULL),48_staticSplitEntries(NULL),49_specialSplitEntries(NULL),50#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)51_invokeCacheCount(0),52#else /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */53_methodTypeCount(0),54_varHandleMethodTypeCount(0),55_varHandleMethodTypeLookupTable(NULL),56#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */57_callSiteCount(0),58_ramConstantPoolCount(0),59_romConstantPoolCount(0),60_staticSplitEntryCount(0),61_specialSplitEntryCount(0),62_buildResult(OutOfMemory)63{64}6566ConstantPoolMap::~ConstantPoolMap()67{68PORT_ACCESS_FROM_PORT(_context->portLibrary());69_bufferManager->free(_constantPoolEntries);70_bufferManager->free(_romConstantPoolEntries);71_bufferManager->free(_romConstantPoolTypes);72#if defined(J9VM_OPT_METHOD_HANDLE)73j9mem_free_memory(_varHandleMethodTypeLookupTable);74#endif /* defined(J9VM_OPT_METHOD_HANDLE) */75}7677void78ConstantPoolMap::setClassFileOracleAndInitialize(ClassFileOracle *classFileOracle)79{80ROMClassVerbosePhase v(_context, ConstantPoolMapping, &_buildResult);8182_classFileOracle = classFileOracle;8384UDATA cpCount = classFileOracle->getConstantPoolCount();85_constantPoolEntries = (ConstantPoolEntry *) _bufferManager->alloc(cpCount * sizeof(ConstantPoolEntry));86if (NULL != _constantPoolEntries) {87memset(_constantPoolEntries, 0, cpCount * sizeof(ConstantPoolEntry));88_buildResult = OK;89}90}9192void93ConstantPoolMap::computeConstantPoolMapAndSizes()94{95/* CFR_CONSTANT_* to J9CPTYPE_* map. The remainder of the array maps to 0 (== J9CPTYPE_UNUSED). */96static const U_8 cpTypeMap[256] = {97J9CPTYPE_UNUSED, /* CFR_CONSTANT_Null */98J9CPTYPE_ANNOTATION_UTF8, /* CFR_CONSTANT_Utf8 */99J9CPTYPE_UNUSED, /* 2 */100J9CPTYPE_INT, /* CFR_CONSTANT_Integer */101J9CPTYPE_FLOAT, /* CFR_CONSTANT_Float */102J9CPTYPE_LONG, /* CFR_CONSTANT_Long */103J9CPTYPE_DOUBLE, /* CFR_CONSTANT_Double */104J9CPTYPE_CLASS, /* CFR_CONSTANT_Class */105J9CPTYPE_STRING, /* CFR_CONSTANT_String */106J9CPTYPE_FIELD, /* CFR_CONSTANT_Fieldref */107J9CPTYPE_UNUSED, /* CFR_CONSTANT_Methodref */108J9CPTYPE_INTERFACE_METHOD, /* CFR_CONSTANT_InterfaceMethodref */109J9CPTYPE_UNUSED, /* CFR_CONSTANT_NameAndType */110J9CPTYPE_UNUSED, /* 13 */111J9CPTYPE_UNUSED, /* 14 */112J9CPTYPE_METHODHANDLE, /* CFR_CONSTANT_MethodHandle */113J9CPTYPE_METHOD_TYPE, /* CFR_CONSTANT_MethodType */114J9CPTYPE_CONSTANT_DYNAMIC, /* CFR_CONSTANT_Dynamic */115J9CPTYPE_UNUSED, /* CFR_CONSTANT_InvokeDynamic */116};117118ROMClassVerbosePhase v(_context, ConstantPoolMapping, &_buildResult);119120/* Count entries */121UDATA ldcSlotCount = 0;122UDATA singleSlotCount = 0;123UDATA doubleSlotCount = 0;124UDATA cfrCPCount = _classFileOracle->getConstantPoolCount();125126for (U_16 cfrCPIndex = 0; cfrCPIndex < cfrCPCount; cfrCPIndex++) {127if (_constantPoolEntries[cfrCPIndex].isUsedByLDC) {128ldcSlotCount += 1;129} else if (_constantPoolEntries[cfrCPIndex].isReferenced) {130switch (getCPTag(cfrCPIndex)) {131case CFR_CONSTANT_Double: /* fall through */132case CFR_CONSTANT_Long:133doubleSlotCount += 1;134break;135case CFR_CONSTANT_InterfaceMethodref: /* fall through */136case CFR_CONSTANT_Methodref:137if (isStaticSplit(cfrCPIndex)) {138_staticSplitEntryCount += 1;139}140if (isSpecialSplit(cfrCPIndex)) {141_specialSplitEntryCount += 1;142}143/* fall through */144case CFR_CONSTANT_Fieldref: /* fall through */145case CFR_CONSTANT_Class:146case CFR_CONSTANT_String: /* fall through */147case CFR_CONSTANT_Integer: /* fall through */148case CFR_CONSTANT_Float: /* fall through */149case CFR_CONSTANT_MethodHandle: /* fall through */150case CFR_CONSTANT_MethodType:151singleSlotCount += 1;152break;153case CFR_CONSTANT_Dynamic:154if (isMarked(cfrCPIndex)) {155/*156* All Constant Dynamic entries [ldc, ldc_w, ldc2w] are treated as single slot157* to always have a RAM constantpool entry created158*/159singleSlotCount += 1;160}161break;162case CFR_CONSTANT_Utf8:163if (isMarked(cfrCPIndex, ANNOTATION)) {164singleSlotCount += 1;165}166break;167case CFR_CONSTANT_InvokeDynamic: /* fall through */168case CFR_CONSTANT_NameAndType:169/* Ignore */170break;171default:172Trc_BCU_Assert_ShouldNeverHappen();173break;174}175}176}177178if (_callSiteCount > MAX_CALL_SITE_COUNT) {179_buildResult = GenericError;180return;181}182183if (ldcSlotCount > MAX_LDC_COUNT) {184_buildResult = GenericError;185return;186}187188_ramConstantPoolCount = U_16(singleSlotCount + ldcSlotCount + 1);189_romConstantPoolCount = U_16(_ramConstantPoolCount + doubleSlotCount);190191_romConstantPoolEntries = (U_16 *) _bufferManager->alloc(_romConstantPoolCount * sizeof(U_16));192_romConstantPoolTypes = (U_8 *) _bufferManager->alloc(_romConstantPoolCount * sizeof(U_8));193_staticSplitEntries = (U_16 *) _bufferManager->alloc(_staticSplitEntryCount * sizeof(U_16));194_specialSplitEntries = (U_16 *) _bufferManager->alloc(_specialSplitEntryCount * sizeof(U_16));195196if ((NULL == _romConstantPoolEntries)197|| (NULL == _romConstantPoolTypes)198|| (NULL == _staticSplitEntries)199|| (NULL == _specialSplitEntries)200) {201_buildResult = OutOfMemory;202return;203}204205/* Skip the zeroth entry. */206U_16 ldcCPIndex = 1;207U_16 romCPIndex = U_16(ldcCPIndex + ldcSlotCount);208U_16 doubleSlotIndex = _ramConstantPoolCount;209U_16 currentCallSiteIndex = 0;210U_16 staticSplitTableIndex = 0;211U_16 specialSplitTableIndex = 0;212213/*214* Fill in entries, ignoring InvokeDynamic, Utf8 and NameAndType entries.215* These entries take no space in ROMConstant Pool.216*/217for (U_16 cfrCPIndex = 0; cfrCPIndex < cfrCPCount; cfrCPIndex++) {218#define SET_ROM_CP_INDEX(cfrCPIdx, splitIdx, romCPIdx) _constantPoolEntries[(cfrCPIdx)].romCPIndex = (romCPIdx)219if (_constantPoolEntries[cfrCPIndex].isUsedByLDC) {220U_8 cpTag = getCPTag(cfrCPIndex);221U_8 cpType = cpTypeMap[cpTag];222223Trc_BCU_Assert_NotEquals(cpType, J9CPTYPE_UNUSED);224225_romConstantPoolEntries[ldcCPIndex] = cfrCPIndex;226_romConstantPoolTypes[ldcCPIndex] = cpType;227SET_ROM_CP_INDEX(cfrCPIndex, 0, ldcCPIndex++);228} else if (_constantPoolEntries[cfrCPIndex].isReferenced) {229U_8 cpTag = getCPTag(cfrCPIndex);230switch (cpTag) {231case CFR_CONSTANT_Double: /* fall through */232case CFR_CONSTANT_Long:233_romConstantPoolEntries[doubleSlotIndex] = cfrCPIndex;234_romConstantPoolTypes[doubleSlotIndex] = cpTypeMap[cpTag];235SET_ROM_CP_INDEX(cfrCPIndex, 0, doubleSlotIndex++);236break;237case CFR_CONSTANT_InterfaceMethodref: /* fall through */238case CFR_CONSTANT_Methodref: {239if (isStaticSplit(cfrCPIndex)) {240_staticSplitEntries[staticSplitTableIndex] = romCPIndex;241_constantPoolEntries[cfrCPIndex].staticSplitTableIndex = staticSplitTableIndex;242staticSplitTableIndex += 1;243}244if (isSpecialSplit(cfrCPIndex)) {245_specialSplitEntries[specialSplitTableIndex] = romCPIndex;246_constantPoolEntries[cfrCPIndex].specialSplitTableIndex = specialSplitTableIndex;247specialSplitTableIndex += 1;248}249_romConstantPoolEntries[romCPIndex] = cfrCPIndex;250if (isMarked(cfrCPIndex, INVOKE_INTERFACE)) {251_romConstantPoolTypes[romCPIndex] = J9CPTYPE_INTERFACE_METHOD;252} else if (isMarked(cfrCPIndex, INVOKE_SPECIAL)) {253if (CFR_CONSTANT_InterfaceMethodref == cpTag) {254_romConstantPoolTypes[romCPIndex] = J9CPTYPE_INTERFACE_INSTANCE_METHOD;255} else {256_romConstantPoolTypes[romCPIndex] = J9CPTYPE_INSTANCE_METHOD;257}258} else if (isMarked(cfrCPIndex, INVOKE_HANDLEEXACT) || isMarked(cfrCPIndex, INVOKE_HANDLEGENERIC)) {259_romConstantPoolTypes[romCPIndex] = J9CPTYPE_HANDLE_METHOD;260} else if (isMarked(cfrCPIndex, INVOKE_STATIC)) {261if (CFR_CONSTANT_InterfaceMethodref == cpTag) {262_romConstantPoolTypes[romCPIndex] = J9CPTYPE_INTERFACE_STATIC_METHOD;263} else {264_romConstantPoolTypes[romCPIndex] = J9CPTYPE_STATIC_METHOD;265}266267} else if (isMarked(cfrCPIndex, INVOKE_VIRTUAL)) {268_romConstantPoolTypes[romCPIndex] = J9CPTYPE_INSTANCE_METHOD;269} else {270Trc_BCU_Assert_ShouldNeverHappen();271}272SET_ROM_CP_INDEX(cfrCPIndex, 0, romCPIndex++);273break;274}275case CFR_CONSTANT_Fieldref: /* fall through */276case CFR_CONSTANT_Class: /* fall through */277case CFR_CONSTANT_String: /* fall through */278case CFR_CONSTANT_Integer: /* fall through */279case CFR_CONSTANT_Float: /* fall through */280case CFR_CONSTANT_MethodHandle: /* fall through */281case CFR_CONSTANT_MethodType: /* fall through */282case CFR_CONSTANT_Dynamic:283_romConstantPoolEntries[romCPIndex] = cfrCPIndex;284_romConstantPoolTypes[romCPIndex] = cpTypeMap[cpTag];285SET_ROM_CP_INDEX(cfrCPIndex, 0, romCPIndex++);286break;287case CFR_CONSTANT_InvokeDynamic:288/*289* Update the starting indexing for this InvokeDynamic constant. Index will be used by290* the BytecodeFixups in the writeBytecodes when dealing with invokedynamic291*/292SET_ROM_CP_INDEX(cfrCPIndex, 0, currentCallSiteIndex);293currentCallSiteIndex += _constantPoolEntries[cfrCPIndex].callSiteReferenceCount;294break;295case CFR_CONSTANT_NameAndType:296/* Ignore */297break;298case CFR_CONSTANT_Utf8:299if (isMarked(cfrCPIndex, ANNOTATION)) {300_romConstantPoolEntries[romCPIndex] = cfrCPIndex;301_romConstantPoolTypes[romCPIndex] = cpTypeMap[cpTag];302SET_ROM_CP_INDEX(cfrCPIndex, 0, romCPIndex++);303}304break;305default:306Trc_BCU_Assert_ShouldNeverHappen();307break;308}309}310}311312J9ClassPatchMap *map = _context->patchMap();313314/**315* If a valid patchMap structure is passed, this class requires ConstantPool patching.316* Record the index mapping from Classfile to J9Class constantpool to allow patching317* the RAM CP after it is created by VM.318*/319if (map != NULL) {320Trc_BCU_Assert_Equals(map->size, cfrCPCount);321for (U_16 cfrCPIndex = 0; cfrCPIndex < cfrCPCount; cfrCPIndex++) {322map->indexMap[cfrCPIndex] = _constantPoolEntries[cfrCPIndex].romCPIndex;323}324}325}326327#if defined(J9VM_OPT_METHOD_HANDLE)328void329ConstantPoolMap::findVarHandleMethodRefs()330{331PORT_ACCESS_FROM_PORT(_context->portLibrary());332U_16 *varHandleMethodTable = NULL;333334for (U_16 i = 1; i < _romConstantPoolCount; i++) {335if ((J9CPTYPE_INSTANCE_METHOD == _romConstantPoolTypes[i])336|| (J9CPTYPE_INTERFACE_INSTANCE_METHOD == _romConstantPoolTypes[i])337) {338U_16 cfrCPIndex = _romConstantPoolEntries[i];339U_32 classIndex = getCPSlot1(cfrCPIndex);340U_32 classNameIndex = getCPSlot1(classIndex);341U_16 classNameLength = _classFileOracle->getUTF8Length(classNameIndex);342343if ((sizeof(VARHANDLE_CLASS_NAME) - 1) == classNameLength) {344const U_8 *classNameData = _classFileOracle->getUTF8Data(classNameIndex);345if (0 == memcmp(classNameData, VARHANDLE_CLASS_NAME, classNameLength)) {346U_32 nasIndex = getCPSlot2(cfrCPIndex);347U_32 methodNameIndex = getCPSlot1(nasIndex);348U_16 methodNameLength = _classFileOracle->getUTF8Length(methodNameIndex);349const U_8 *methodNameData = _classFileOracle->getUTF8Data(methodNameIndex);350351if (VM_VMHelpers::isPolymorphicVarHandleMethod(methodNameData, methodNameLength)) {352if (NULL == varHandleMethodTable) {353/* Allocate a temporary array for storing indices of VarHandle methodrefs. */354varHandleMethodTable = (U_16*) j9mem_allocate_memory(_romConstantPoolCount * sizeof(U_16), OMRMEM_CATEGORY_VM);355if (NULL == varHandleMethodTable) {356_buildResult = OutOfMemory;357break;358}359}360varHandleMethodTable[_varHandleMethodTypeCount] = i;361_varHandleMethodTypeCount++;362}363}364}365}366}367368/* Store trimmed varHandleMethodTable into _varHandleMethodTypeLookupTable. */369if (NULL != varHandleMethodTable) {370_varHandleMethodTypeLookupTable = (U_16*) j9mem_allocate_memory(_varHandleMethodTypeCount * sizeof(U_16), OMRMEM_CATEGORY_VM);371if (NULL == _varHandleMethodTypeLookupTable) {372_buildResult = OutOfMemory;373} else {374memcpy(_varHandleMethodTypeLookupTable, varHandleMethodTable, _varHandleMethodTypeCount * sizeof(U_16));375}376j9mem_free_memory(varHandleMethodTable);377}378}379#endif /* defined(J9VM_OPT_METHOD_HANDLE) */380381void382ConstantPoolMap::constantPoolDo(ConstantPoolVisitor *visitor)383{384for (UDATA i = 1; i < _romConstantPoolCount; i++) {385U_16 cfrCPIndex = _romConstantPoolEntries[i];386U_32 slot1 = getCPSlot1(cfrCPIndex);387U_32 slot2 = getCPSlot2(cfrCPIndex);388389switch (_romConstantPoolTypes[i]) {390case J9CPTYPE_INT: /* fall through */391case J9CPTYPE_FLOAT:392visitor->visitSingleSlotConstant(slot1);393break;394case J9CPTYPE_LONG: /* fall through */395case J9CPTYPE_DOUBLE:396visitor->visitDoubleSlotConstant(slot1, slot2);397break;398case J9CPTYPE_CLASS:399visitor->visitClass(slot1);400break;401case J9CPTYPE_STRING:402if (CFR_CONSTANT_Utf8 == getCPTag(cfrCPIndex)) {403visitor->visitString(cfrCPIndex);404} else {405visitor->visitString(slot1);406}407break;408case J9CPTYPE_ANNOTATION_UTF8:409visitor->visitString(cfrCPIndex);410break;411case J9CPTYPE_FIELD: /* fall through */412case J9CPTYPE_INSTANCE_METHOD: /* fall through */413case J9CPTYPE_HANDLE_METHOD: /* fall through */414case J9CPTYPE_STATIC_METHOD: /* fall through */415case J9CPTYPE_INTERFACE_METHOD: /* fall through */416case J9CPTYPE_INTERFACE_INSTANCE_METHOD: /* fall through */417case J9CPTYPE_INTERFACE_STATIC_METHOD:418visitor->visitFieldOrMethod(getROMClassCPIndexForReference(slot1), U_16(slot2));419break;420case J9CPTYPE_METHOD_TYPE:421if (CFR_CONSTANT_Methodref == getCPTag(cfrCPIndex)) {422/* Will be a MethodRef { class, nas } - dig out nas->slot2 */423U_32 methodTypeOriginFlags = 0;424if (_classFileOracle->getUTF8Length(getCPSlot1(slot2)) == (sizeof("invokeExact") - 1)) {425methodTypeOriginFlags = J9_METHOD_TYPE_ORIGIN_INVOKE_EXACT;426} else {427methodTypeOriginFlags = J9_METHOD_TYPE_ORIGIN_INVOKE;428}429visitor->visitMethodType(getCPSlot2(slot2), methodTypeOriginFlags);430} else {431visitor->visitMethodType(slot1, J9_METHOD_TYPE_ORIGIN_LDC);432}433break;434case J9CPTYPE_METHODHANDLE:435visitor->visitMethodHandle(slot1, slot2);436break;437case J9CPTYPE_CONSTANT_DYNAMIC:438/* Check if the return type of constant dynamic entry is a primitive type439* Set the J9DescriptionCpPrimitiveType flag so interpreter know to unbox440* the resolved object before returning it.441*/442{443char fieldDescriptor = (char)*_classFileOracle->getUTF8Data(getCPSlot2(slot2));444switch (fieldDescriptor) {445case 'B':446visitor->visitConstantDynamic(slot1, slot2, (J9DescriptionReturnTypeByte << J9DescriptionReturnTypeShift));447break;448case 'C':449visitor->visitConstantDynamic(slot1, slot2, (J9DescriptionReturnTypeChar << J9DescriptionReturnTypeShift));450break;451case 'D':452visitor->visitConstantDynamic(slot1, slot2, (J9DescriptionReturnTypeDouble << J9DescriptionReturnTypeShift));453break;454case 'F':455visitor->visitConstantDynamic(slot1, slot2, (J9DescriptionReturnTypeFloat << J9DescriptionReturnTypeShift));456break;457case 'I':458visitor->visitConstantDynamic(slot1, slot2, (J9DescriptionReturnTypeInt << J9DescriptionReturnTypeShift));459break;460case 'J':461visitor->visitConstantDynamic(slot1, slot2, (J9DescriptionReturnTypeLong << J9DescriptionReturnTypeShift));462break;463case 'S':464visitor->visitConstantDynamic(slot1, slot2, (J9DescriptionReturnTypeShort << J9DescriptionReturnTypeShift));465break;466case 'Z':467visitor->visitConstantDynamic(slot1, slot2, (J9DescriptionReturnTypeBoolean << J9DescriptionReturnTypeShift));468break;469default:470visitor->visitConstantDynamic(slot1, slot2, 0);471break;472}473}474break;475default:476Trc_BCU_Assert_ShouldNeverHappen();477break;478}479}480}481482483