Path: blob/master/runtime/bcutil/ConstantPoolMap.hpp
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*******************************************************************************/2122/*23* ConstantPoolMap.hpp24*/2526#ifndef CONSTANTPOOLMAP_HPP_27#define CONSTANTPOOLMAP_HPP_2829/* @ddr_namespace: default */30#include "j9comp.h"31#include "j9.h"32#include "cfr.h"3334#include "BuildResult.hpp"35#include "ClassFileOracle.hpp"36#include "ROMClassCreationContext.hpp"3738class BufferManager;3940/*41* The ConstantPoolMap class handles mapping from class file constant pool indices42* to ROM class constant pool indices.43*44* The resulting ROM constant pool looks like this.45*46* +------------+-------------------+------------------+--------------------+47* | CP entry 0 | HEADER CP entries | split CP entries | FOOTER CP entries |48* +------------+-------------------+------------------+--------------------+49*50* The CP entry at index 0 is reserved - as it has a special meaning (e.g. null).51*52* The HEADER CP entries are those that must be at the beginning of the constant pool.53* These are required to be at the beginning because they are indexed by U_8 (and must54* thus be within the first 256 values). These entries are referred by 'ldc' bytecode,55* and since only these entries can have objects, storing them together improves56* the locality of objects in the heap.57*58* The FOOTER CP entries are the ones that must be at the end of the constant pool.59* The FOOTER entries are constants that do not need runtime-resolution, and thus60* do not get included in the RAM constant pool.61*62* All other CP entries are in the middle. A single CP entry in the class file may be split63* into multiple ROM (and consequently RAM) CP entries. This is done because a single constant64* pool entry may be used for different purposes, and thus requires a different value when it65* is resolved in the RAM constant pool. The ROM and RAM constant pools are parallel except66* for the FOOTER CP entries, which do not get included in the RAM constant pool.67*68* For example, suppose that during the marking phase a MethodRef constant pool entry has been69* marked that it is used by both invoke virtual and invoke special. Since the RAM constant pool70* contents for a MethodRef entry will be different based on how it's used - it is necessary that71* the original constant pool entry be split into (in this case) two constant pool entries and72* that the constant pool indices in the byte code be mapped to the reflect this.73*74* Each SPLIT* type (see EntryFlags) indicates a different SPLIT 'slot'. Concrete uses of these75* are specified by EntryUseFlags. All uses for a single SPLIT type must be mutually exclusive.76*77* A split constant pool entry will occupy consecutive constant pool slots for its different78* splits. For example, if class file constant pool entry 12 was marked with SPLIT1, SPLIT2 and79* SPLIT4 flags, then it will map to the following indices in the ROM constant pool:80*81* _constantPoolEntries[12].romCPBaseIndex for SPLIT182* _constantPoolEntries[12].romCPBaseIndex + 1 for SPLIT283* _constantPoolEntries[12].romCPBaseIndex + 2 for SPLIT484*85* The above can be queried by using the getROMClassCPIndex() function after all marking is done.86*/87class ConstantPoolMap88{89public:9091class ConstantPoolVisitor92{93public:94virtual void visitClass(U_16 cfrCPIndex) = 0;95virtual void visitString(U_16 cfrCPIndex) = 0;96virtual void visitMethodType(U_16 cfrCPIndex, U_16 forMethodHandleInvocation) = 0;97virtual void visitMethodHandle(U_16 kind, U_16 cfrCPIndex) = 0;98virtual void visitConstantDynamic(U_16 bsmIndex, U_16 cfrCPIndex, U_32 primitiveFlag) = 0;99virtual void visitSingleSlotConstant(U_32 slot1) = 0;100virtual void visitDoubleSlotConstant(U_32 slot1, U_32 slot2) = 0;101virtual void visitFieldOrMethod(U_16 classRefCPIndex, U_16 nameAndSignatureCfrCPIndex) = 0;102};103104class ConstantPoolEntryTypeVisitor105{106public:107virtual void visitEntryType(U_32 entryType) = 0;108};109110struct CallSiteVisitor111{112virtual void visitCallSite(U_16 nameAndSignatureCfrCPIndex, U_16 bootstrapMethodIndex) = 0;113};114115struct SplitEntryVisitor116{117virtual void visitSplitEntry(U_16 cpIndex) = 0;118};119120ConstantPoolMap(BufferManager *bufferManager, ROMClassCreationContext *context);121~ConstantPoolMap();122123void setClassFileOracleAndInitialize(ClassFileOracle *classFileOracle);124125void computeConstantPoolMapAndSizes();126127#if defined(J9VM_OPT_METHOD_HANDLE)128void findVarHandleMethodRefs();129#endif /* defined(J9VM_OPT_METHOD_HANDLE) */130131bool isOK() const { return OK == _buildResult; }132BuildResult getBuildResult() const { return _buildResult; }133134void constantPoolDo(ConstantPoolVisitor *visitor);135void constantPoolEntryTypesDo(ConstantPoolEntryTypeVisitor *visitor)136{137for (UDATA i = 1; i < _romConstantPoolCount; i++) {138visitor->visitEntryType(_romConstantPoolTypes[i]);139}140}141142void callSitesDo(CallSiteVisitor *visitor)143{144U_16 constantPoolCount = _classFileOracle->getConstantPoolCount();145for (U_16 i = 0; i < constantPoolCount; ++i) {146U_32 callSiteReferenceCount = _constantPoolEntries[i].callSiteReferenceCount;147for (U_32 j = 0; j < callSiteReferenceCount; ++j) {148visitor->visitCallSite(U_16(getCPSlot2(i)), U_16(getCPSlot1(i)));149}150}151}152153void staticSplitEntriesDo(SplitEntryVisitor *visitor)154{155for (U_16 i = 0; i < _staticSplitEntryCount; i++) {156visitor->visitSplitEntry(_staticSplitEntries[i]);157}158}159160void specialSplitEntriesDo(SplitEntryVisitor *visitor)161{162for (U_16 i = 0; i < _specialSplitEntryCount; i++) {163visitor->visitSplitEntry(_specialSplitEntries[i]);164}165}166167#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)168U_32 getInvokeCacheCount() const { return _invokeCacheCount; }169#else /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */170U_32 getMethodTypeCount() const { return _methodTypeCount; }171U_32 getVarHandleMethodTypeCount() const { return _varHandleMethodTypeCount; }172U_32 getVarHandleMethodTypePaddedCount() const { return _varHandleMethodTypeCount + (_varHandleMethodTypeCount & 0x1); /* Rounding up to an even number */ }173U_16 *getVarHandleMethodTypeLookupTable() const { return _varHandleMethodTypeLookupTable; }174#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */175U_32 getCallSiteCount() const { return _callSiteCount; }176U_16 getRAMConstantPoolCount() const { return _ramConstantPoolCount; }177U_16 getROMConstantPoolCount() const { return _romConstantPoolCount; }178U_16 getStaticSplitEntryCount() const { return _staticSplitEntryCount; }179U_16 getSpecialSplitEntryCount() const { return _specialSplitEntryCount; }180181U_16 getROMClassCPIndex(U_16 cfrCPIndex, UDATA splitType) const182{183return _constantPoolEntries[cfrCPIndex].romCPIndex;184}185U_16 getROMClassCPIndex(U_16 cfrCPIndex) const { return getROMClassCPIndex(cfrCPIndex, 0); }186187/*188* Note: InvokeDynamicInfo CP entries are not marked in the same way as other CP entries. In particular,189* isMarked(cfrCPIndex, INVOKE_DYNAMIC) is always false. The correct check is190* computeConstantPoolMapAndSizes, is (0 != _constantPoolEntries[cfrCPIndex].callSiteReferenceCount).191*/192U_16 getCallSiteIndex(U_16 cfrCPIndex)193{194U_16 romClassCPIndex = getROMClassCPIndex(cfrCPIndex);195U_16 index = _constantPoolEntries[cfrCPIndex].currentCallSiteIndex++;196Trc_BCU_Assert_True(index < _constantPoolEntries[cfrCPIndex].callSiteReferenceCount);197return romClassCPIndex + index;198}199200U_16 getStaticSplitTableIndex(U_16 cfrCPIndex) { return _constantPoolEntries[cfrCPIndex].staticSplitTableIndex; }201U_16 getSpecialSplitTableIndex(U_16 cfrCPIndex) { return _constantPoolEntries[cfrCPIndex].specialSplitTableIndex; }202203void mark(U_16 cfrCPIndex) { _constantPoolEntries[cfrCPIndex].isReferenced = true; }204void mark(U_16 cfrCPIndex, UDATA useType)205{206mark(cfrCPIndex);207_constantPoolEntries[cfrCPIndex].isUsedBy[useType] = true;208}209210bool isMarked(U_16 cfrCPIndex) const { return _constantPoolEntries[cfrCPIndex].isReferenced; }211bool isMarked(U_16 cfrCPIndex, UDATA useType) const { return _constantPoolEntries[cfrCPIndex].isUsedBy[useType]; }212213U_8 getCPTag(U_16 cfrCPIndex) const { return _classFileOracle->getCPTag(cfrCPIndex); }214U_32 getCPSlot1(U_16 cfrCPIndex) const { return _classFileOracle->getCPSlot1(cfrCPIndex); }215U_32 getCPSlot2(U_16 cfrCPIndex) const { return _classFileOracle->getCPSlot2(cfrCPIndex); }216217U_16 getROMClassCPIndexForReference(U_16 cfrCPIndex) const { return getROMClassCPIndex(cfrCPIndex); }218U_16 getROMClassCPIndexForAnnotation(U_16 cfrCPIndex) const { return getROMClassCPIndex(cfrCPIndex); }219220bool isUTF8ConstantReferenced(U_16 cfrCPIndex) const { return isMarked(cfrCPIndex); }221bool isNATConstantReferenced(U_16 cfrCPIndex) const { return isMarked(cfrCPIndex); }222223bool isStaticSplit(U_16 cfrCPIndex) const224{225/* A CP index needs to be added to static split side table if any of the following is true:226* 1. it is shared between 'invokestatic' and 'invokeinterface' bytecodes,227* 2. it is shared between 'invokestatic' and 'invokespecial' bytecodes228*229* First condition is required to support 'default' methods introduced as part of JSR 335.230* Sharing of CP index between 'invokestatic' and 'invokespecial' can also be handled using the side table mechanism231* instead of marking it as J9CPTYPE_SHARED_METHOD, and hence the second condition.232* See Jazz103 Design 40047.233*/234return (isMarked(cfrCPIndex, INVOKE_STATIC)235&& (_context->alwaysSplitBytecodes()236|| isMarked(cfrCPIndex, INVOKE_INTERFACE)237|| isMarked(cfrCPIndex, INVOKE_SPECIAL)238#if JAVA_SPEC_VERSION >= 11239|| isMarked(cfrCPIndex, INVOKE_VIRTUAL)240#endif /* JAVA_SPEC_VERSION >= 11 */241));242}243244bool isSpecialSplit(U_16 cfrCPIndex) const245{246/* A constant pool index needs to be added to special split table if247* it is referred by 'invokespecial' and 'invokeinterface' bytecodes.248* This is required to support 'default' methods introduced as part of JSR 335.249* See Jazz103 Design 40047.250*/251return (isMarked(cfrCPIndex, INVOKE_SPECIAL)252&& (_context->alwaysSplitBytecodes()253|| isMarked(cfrCPIndex, INVOKE_INTERFACE)254#if JAVA_SPEC_VERSION >= 11255|| isMarked(cfrCPIndex, INVOKE_VIRTUAL)256#endif /* JAVA_SPEC_VERSION >= 11 */257));258}259260bool hasStaticSplitTable() const { return _staticSplitEntryCount != 0; }261bool hasSpecialSplitTable() const { return _specialSplitEntryCount != 0; }262263bool hasCallSites() const { return 0 != _callSiteCount; }264#if defined(J9VM_OPT_METHOD_HANDLE)265bool hasVarHandleMethodRefs() const { return 0 != _varHandleMethodTypeCount; }266#endif /* defined(J9VM_OPT_METHOD_HANDLE) */267268void markConstantAsReferencedDoubleSlot(U_16 cfrCPIndex) { mark(cfrCPIndex); }269void markConstantAsUsedByLDC(U_8 cfrCPIndex) { _constantPoolEntries[cfrCPIndex].isUsedByLDC = true; }270271void markConstantAsReferenced(U_16 cfrCPIndex) { mark(cfrCPIndex, REFERENCED); }272273void markConstantUTF8AsReferenced(U_16 cfrCPIndex) { mark(cfrCPIndex); }274void markConstantNameAndTypeAsReferenced(U_16 cfrCPIndex) { mark(cfrCPIndex); }275276void markConstantAsUsedByAnnotationUTF8(U_16 cfrCPIndex) { mark(cfrCPIndex, ANNOTATION); }277278void markClassAsUsedByInstanceOf(U_16 classCfrCPIndex) { mark(classCfrCPIndex, INSTANCE_OF); }279void markClassAsUsedByCheckCast(U_16 classCfrCPIndex) { mark(classCfrCPIndex, CHECK_CAST); }280void markClassAsUsedByMultiANewArray(U_16 classCfrCPIndex) { mark(classCfrCPIndex, MULTI_ANEW_ARRAY); }281void markClassAsUsedByANewArray(U_16 classCfrCPIndex) { mark(classCfrCPIndex, ANEW_ARRAY); }282void markClassAsUsedByNew(U_16 classCfrCPIndex) { mark(classCfrCPIndex, NEW); }283#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)284void markClassAsUsedByAconst_init(U_16 classCfrCPIndex) { mark(classCfrCPIndex, ACONST_INIT); }285void markFieldRefAsUsedByWithField(U_16 fieldRefCfrCPIndex) { mark(fieldRefCfrCPIndex, WITH_FIELD); }286#endif287288void markFieldRefAsUsedByGetStatic(U_16 fieldRefCfrCPIndex) { mark(fieldRefCfrCPIndex, GET_STATIC); }289void markFieldRefAsUsedByPutStatic(U_16 fieldRefCfrCPIndex) { mark(fieldRefCfrCPIndex, PUT_STATIC); }290void markFieldRefAsUsedByGetField(U_16 fieldRefCfrCPIndex) { mark(fieldRefCfrCPIndex, GET_FIELD); }291void markFieldRefAsUsedByPutField(U_16 fieldRefCfrCPIndex) { mark(fieldRefCfrCPIndex, PUT_FIELD); }292293void markMethodRefAsUsedByInvokeVirtual(U_16 methodRefCfrCPIndex) { mark(methodRefCfrCPIndex, INVOKE_VIRTUAL); }294void markMethodRefAsUsedByInvokeSpecial(U_16 methodRefCfrCPIndex) { mark(methodRefCfrCPIndex, INVOKE_SPECIAL); }295void markMethodRefAsUsedByInvokeStatic(U_16 methodRefCfrCPIndex) { mark(methodRefCfrCPIndex, INVOKE_STATIC); }296void markMethodRefAsUsedByInvokeInterface(U_16 methodRefCfrCPIndex) { mark(methodRefCfrCPIndex, INVOKE_INTERFACE); }297298void markMethodRefAsUsedByInvokeHandle(U_16 methodRefCfrCPIndex) {299mark(methodRefCfrCPIndex, INVOKE_HANDLEEXACT);300#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)301_invokeCacheCount++;302#else /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */303_methodTypeCount++;304#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */305}306307void markMethodRefAsUsedByInvokeHandleGeneric(U_16 methodRefCfrCPIndex) {308mark(methodRefCfrCPIndex, INVOKE_HANDLEGENERIC);309#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)310_invokeCacheCount++;311#else /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */312_methodTypeCount++;313#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */314}315316317void markInvokeDynamicInfoAsUsedByInvokeDynamic(U_16 cfrCPIndex)318{319/*320* Note: Unlike the other markFooAsUsedByBar(U_16 cfrCPIndex) methods above, uses of InvokeDynamicInfo CP entries are not marked321* with mark(cfrCPIndex, INVOKE_DYNAMIC) because the romCPBaseIndex for these entries is an index into the callSites table322* instead of the ROM Constant Pool. Also see computeConstantPoolMapAndSizes.323*/324mark(cfrCPIndex);325_constantPoolEntries[cfrCPIndex].callSiteReferenceCount++;326++_callSiteCount;327}328329private:330/* TODO turn EntryFlags into static const UDATAs instead of an enum type that is never used */331332/* Indices into the ConstantPoolEntry.flags bool array. See comment at the top of the file for more info. */333enum EntryFlags334{335SPLIT1 = 0,336SPLIT2 = 1,337SPLIT3 = 2,338SPLIT4 = 3,339SPLIT5 = 4,340/* SPLIT_FLAG_COUNT is the number of possible split types. */341SPLIT_FLAG_COUNT = 5342};343344struct ConstantPoolEntry345{346/* If callSiteReferenceCount > 0 then romCPIndexes[0] is the Call Site base index for this entry. */347U_32 callSiteReferenceCount;348U_16 currentCallSiteIndex;349U_16 staticSplitTableIndex; /* maps this cpIndex to J9ROMClass.staticSplitMethodRefIndexes */350U_16 specialSplitTableIndex; /* maps this cpIndex to J9ROMClass.specialSplitMethodRefIndexes */351U_16 romCPIndex;352bool isUsedBy[SPLIT_FLAG_COUNT];353bool isReferenced;354bool isUsedByLDC;355};356357ROMClassCreationContext *_context;358ClassFileOracle *_classFileOracle;359BufferManager *_bufferManager;360361ConstantPoolEntry *_constantPoolEntries;362U_16 *_romConstantPoolEntries;363U_8 *_romConstantPoolTypes;364U_16 *_staticSplitEntries;365U_16 *_specialSplitEntries;366#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)367U_32 _invokeCacheCount;368#else /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */369U_32 _methodTypeCount;370U_16 _varHandleMethodTypeCount;371U_16 *_varHandleMethodTypeLookupTable;372#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */373U_32 _callSiteCount;374U_16 _ramConstantPoolCount;375U_16 _romConstantPoolCount;376U_16 _staticSplitEntryCount;377U_16 _specialSplitEntryCount;378BuildResult _buildResult;379380public:381382/* Specific flags that are aliases for EntryFlags constants. See comment at the top of the file for more info. */383enum EntryUseFlags384{385REFERENCED = SPLIT1,386LDC2W = SPLIT1,387PUT_STATIC = SPLIT1,388GET_STATIC = SPLIT1,389PUT_FIELD = SPLIT1,390GET_FIELD = SPLIT1,391#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)392ACONST_INIT = SPLIT1,393WITH_FIELD = SPLIT1,394#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */395NEW = SPLIT1,396INVOKE_HANDLEGENERIC = SPLIT5,397INVOKE_HANDLEEXACT = SPLIT5,398INVOKE_STATIC = SPLIT4,399INVOKE_SPECIAL = SPLIT3,400INVOKE_VIRTUAL = SPLIT2,401INVOKE_INTERFACE = SPLIT1,402ANEW_ARRAY = SPLIT1,403CHECK_CAST = SPLIT1,404INSTANCE_OF = SPLIT1,405MULTI_ANEW_ARRAY = SPLIT1,406ANNOTATION = SPLIT1,407/* INVOKE_DYNAMIC does not use a constant pool entry. It is used only for ClassFileOracle::BytecodeFixupEntry.type. */408INVOKE_DYNAMIC = SPLIT_FLAG_COUNT,409/* LDC does not use a constant pool entry. It is used only for ClassFileOracle::BytecodeFixupEntry.type. */410LDC = SPLIT_FLAG_COUNT + 1411};412413};414415#endif /* CONSTANTPOOLMAP_HPP_ */416417418