Path: blob/master/runtime/compiler/env/J9ClassEnv.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 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#include "compile/Compilation.hpp"23#if defined(J9VM_OPT_JITSERVER)24#include "control/CompilationRuntime.hpp"25#include "control/CompilationThread.hpp"26#include "control/JITServerHelpers.hpp"27#include "runtime/JITClientSession.hpp"28#endif /* defined(J9VM_OPT_JITSERVER) */29#include "env/ClassEnv.hpp"30#include "env/CompilerEnv.hpp"31#include "env/jittypes.h"32#include "env/TypeLayout.hpp"33#include "env/VMJ9.h"34#include "j9.h"35#include "j9cfg.h"36#include "j9cp.h"37#include "j9fieldsInfo.h"38#include "j9nonbuilder.h"39#include "j9protos.h"40#include "rommeth.h"41#include "runtime/RuntimeAssumptions.hpp"4243class TR_PersistentClassInfo;44template <typename ListKind> class List;4546/* REQUIRES STATE (_vmThread). MOVE vmThread to COMPILATION4748TR_OpaqueClassBlock *49J9::ClassEnv::getClassFromJavaLangClass(uintptr_t objectPointer)50{51return (TR_OpaqueClassBlock*)J9VM_J9CLASS_FROM_HEAPCLASS(_vmThread, objectPointer);52}53*/5455TR::ClassEnv *56J9::ClassEnv::self()57{58return static_cast<TR::ClassEnv *>(this);59}6061J9Class *62J9::ClassEnv::convertClassOffsetToClassPtr(TR_OpaqueClassBlock *clazzOffset)63{64// NOTE : We could pass down vmThread() in the call below if the conversion65// required the VM thread. Currently it does not. If we did change that66// such that the VM thread was reqd, we would need to handle AOT where the67// TR_FrontEnd is created with a NULL J9VMThread object.68//69return (J9Class*)((TR_OpaqueClassBlock *)clazzOffset);70}7172TR_OpaqueClassBlock *73J9::ClassEnv::convertClassPtrToClassOffset(J9Class *clazzPtr)74{75// NOTE : We could pass down vmThread() in the call below if the conversion76// required the VM thread. Currently it does not. If we did change that77// such that the VM thread was reqd, we would need to handle AOT where the78// TR_FrontEnd is created with a NULL J9VMThread object.79//80return (TR_OpaqueClassBlock*)(clazzPtr);81}8283bool84J9::ClassEnv::isClassSpecialForStackAllocation(TR_OpaqueClassBlock * clazz)85{86const UDATA mask = (J9AccClassReferenceWeak |87J9AccClassReferenceSoft |88J9AccClassFinalizeNeeded |89J9AccClassOwnableSynchronizer);9091#if defined(J9VM_OPT_JITSERVER)92if (auto stream = TR::CompilationInfo::getStream())93{94uintptr_t classDepthAndFlags = 0;95JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazz, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_CLASS_DEPTH_AND_FLAGS, (void *)&classDepthAndFlags);96return ((classDepthAndFlags & mask)?true:false);97}98else99#endif /* defined(J9VM_OPT_JITSERVER) */100{101if (((J9Class *)clazz)->classDepthAndFlags & mask)102{103return true;104}105}106107return false;108}109110uintptr_t111J9::ClassEnv::classFlagsValue(TR_OpaqueClassBlock * classPointer)112{113#if defined(J9VM_OPT_JITSERVER)114if (auto stream = TR::CompilationInfo::getStream())115{116stream->write(JITServer::MessageType::ClassEnv_classFlagsValue, classPointer);117return std::get<0>(stream->read<uintptr_t>());118}119#endif /* defined(J9VM_OPT_JITSERVER) */120return (TR::Compiler->cls.convertClassOffsetToClassPtr(classPointer)->classFlags);121}122123uintptr_t124J9::ClassEnv::classFlagReservableWordInitValue(TR_OpaqueClassBlock * classPointer)125{126#if defined(J9VM_OPT_JITSERVER)127if (auto stream = TR::CompilationInfo::getStream())128{129uintptr_t classFlags = 0;130JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)classPointer, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_CLASS_FLAGS, (void *)&classFlags);131#ifdef DEBUG132stream->write(JITServer::MessageType::ClassEnv_classFlagsValue, classPointer);133uintptr_t classFlagsRemote = std::get<0>(stream->read<uintptr_t>());134// Check that class flags from remote call is equal to the cached ones135classFlags = classFlags & J9ClassReservableLockWordInit;136classFlagsRemote = classFlagsRemote & J9ClassReservableLockWordInit;137TR_ASSERT(classFlags == classFlagsRemote, "remote call class flags is not equal to cached class flags");138#endif139return classFlags & J9ClassReservableLockWordInit;140}141#endif /* defined(J9VM_OPT_JITSERVER) */142return (TR::Compiler->cls.convertClassOffsetToClassPtr(classPointer)->classFlags) & J9ClassReservableLockWordInit;143}144145uintptr_t146J9::ClassEnv::classDepthOf(TR_OpaqueClassBlock * clazzPointer)147{148#if defined(J9VM_OPT_JITSERVER)149if (auto stream = TR::CompilationInfo::getStream())150{151uintptr_t classDepthAndFlags = 0;152JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazzPointer, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_CLASS_DEPTH_AND_FLAGS, (void *)&classDepthAndFlags);153return (classDepthAndFlags & J9AccClassDepthMask);154}155#endif /* defined(J9VM_OPT_JITSERVER) */156return J9CLASS_DEPTH(TR::Compiler->cls.convertClassOffsetToClassPtr(clazzPointer));157}158159160uintptr_t161J9::ClassEnv::classInstanceSize(TR_OpaqueClassBlock * clazzPointer)162{163#if defined(J9VM_OPT_JITSERVER)164if (auto stream = TR::CompilationInfo::getStream())165{166uintptr_t totalInstanceSize = 0;167JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazzPointer, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_TOTAL_INSTANCE_SIZE, (void *)&totalInstanceSize);168return totalInstanceSize;169}170#endif /* defined(J9VM_OPT_JITSERVER) */171return TR::Compiler->cls.convertClassOffsetToClassPtr(clazzPointer)->totalInstanceSize;172}173174175J9ROMClass *176J9::ClassEnv::romClassOf(TR_OpaqueClassBlock * clazz)177{178J9Class *j9clazz = TR::Compiler->cls.convertClassOffsetToClassPtr(clazz);179#if defined(J9VM_OPT_JITSERVER)180if (TR::compInfoPT && TR::compInfoPT->getStream())181{182return TR::compInfoPT->getAndCacheRemoteROMClass(j9clazz);183}184#endif /* defined(J9VM_OPT_JITSERVER) */185return j9clazz->romClass;186}187188J9Class **189J9::ClassEnv::superClassesOf(TR_OpaqueClassBlock * clazz)190{191#if defined(J9VM_OPT_JITSERVER)192if (auto stream = TR::CompilationInfo::getStream())193{194stream->write(JITServer::MessageType::ClassEnv_superClassesOf, clazz);195return std::get<0>(stream->read<J9Class **>());196}197#endif /* defined(J9VM_OPT_JITSERVER) */198return TR::Compiler->cls.convertClassOffsetToClassPtr(clazz)->superclasses;199}200201J9ROMClass *202J9::ClassEnv::romClassOfSuperClass(TR_OpaqueClassBlock * clazz, size_t index)203{204#if defined(J9VM_OPT_JITSERVER)205if (auto stream = TR::CompilationInfo::getStream())206{207stream->write(JITServer::MessageType::ClassEnv_indexedSuperClassOf, clazz, index);208J9Class *j9clazz = std::get<0>(stream->read<J9Class *>());209return TR::compInfoPT->getAndCacheRemoteROMClass(j9clazz);210}211#endif /* defined(J9VM_OPT_JITSERVER) */212return self()->superClassesOf(clazz)[index]->romClass;213}214215J9ITable *216J9::ClassEnv::iTableOf(TR_OpaqueClassBlock * clazz)217{218#if defined(J9VM_OPT_JITSERVER)219if (auto stream = TR::CompilationInfo::getStream())220{221stream->write(JITServer::MessageType::ClassEnv_iTableOf, clazz);222return std::get<0>(stream->read<J9ITable*>());223}224#endif /* defined(J9VM_OPT_JITSERVER) */225return (J9ITable*) self()->convertClassOffsetToClassPtr(clazz)->iTable;226}227228J9ITable *229J9::ClassEnv::iTableNext(J9ITable *current)230{231#if defined(J9VM_OPT_JITSERVER)232if (auto stream = TR::CompilationInfo::getStream())233{234stream->write(JITServer::MessageType::ClassEnv_iTableNext, current);235return std::get<0>(stream->read<J9ITable*>());236}237#endif /* defined(J9VM_OPT_JITSERVER) */238return current->next;239}240241J9ROMClass *242J9::ClassEnv::iTableRomClass(J9ITable *current)243{244#if defined(J9VM_OPT_JITSERVER)245if (auto stream = TR::CompilationInfo::getStream())246{247stream->write(JITServer::MessageType::ClassEnv_iTableRomClass, current);248return std::get<0>(stream->read<J9ROMClass*>());249}250#endif /* defined(J9VM_OPT_JITSERVER) */251return current->interfaceClass->romClass;252}253254#if defined(J9VM_OPT_JITSERVER)255std::vector<TR_OpaqueClassBlock *>256J9::ClassEnv::getITable(TR_OpaqueClassBlock *clazz)257{258if (auto stream = TR::CompilationInfo::getStream())259{260// This normally shouldn't be called from the server,261// because it will have a cached table262stream->write(JITServer::MessageType::ClassEnv_getITable, clazz);263return std::get<0>(stream->read<std::vector<TR_OpaqueClassBlock *>>());264}265std::vector<TR_OpaqueClassBlock *> iTableSerialization;266iTableSerialization.reserve((TR::Compiler->cls.romClassOf(clazz)->interfaceCount));267for (J9ITable *iTableCur = TR::Compiler->cls.iTableOf(clazz); iTableCur; iTableCur = iTableCur->next)268iTableSerialization.push_back((TR_OpaqueClassBlock *) iTableCur->interfaceClass);269return iTableSerialization;270}271#endif /* defined(J9VM_OPT_JITSERVER) */272273bool274J9::ClassEnv::isStringClass(TR_OpaqueClassBlock *clazz)275{276//return (J9Class*)clazz == J9VMJAVALANGSTRING(jitConfig->javaVM);277return false;278}279280bool281J9::ClassEnv::isAbstractClass(TR::Compilation *comp, TR_OpaqueClassBlock *clazzPointer)282{283return comp->fej9()->isAbstractClass(clazzPointer);284}285286bool287J9::ClassEnv::isInterfaceClass(TR::Compilation *comp, TR_OpaqueClassBlock *clazzPointer)288{289return comp->fej9()->isInterfaceClass(clazzPointer);290}291292bool293J9::ClassEnv::isConcreteClass(TR::Compilation *comp, TR_OpaqueClassBlock * clazzPointer)294{295return comp->fej9()->isConcreteClass(clazzPointer);296}297298bool299J9::ClassEnv::isEnumClass(TR::Compilation *comp, TR_OpaqueClassBlock *clazzPointer, TR_ResolvedMethod *method)300{301return comp->fej9()->isEnumClass(clazzPointer, method);302}303304bool305J9::ClassEnv::isPrimitiveClass(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)306{307return comp->fej9()->isPrimitiveClass(clazz);308}309310bool311J9::ClassEnv::isPrimitiveArray(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)312{313return comp->fej9()->isPrimitiveArray(clazz);314}315316bool317J9::ClassEnv::isReferenceArray(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)318{319return comp->fej9()->isReferenceArray(clazz);320}321322bool323J9::ClassEnv::isClassArray(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)324{325return comp->fej9()->isClassArray(clazz);326}327328bool329J9::ClassEnv::isClassFinal(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)330{331return comp->fej9()->isClassFinal(clazz);332}333334bool335J9::ClassEnv::hasFinalizer(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)336{337return comp->fej9()->hasFinalizer(clazz);338}339340bool341J9::ClassEnv::isClassInitialized(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)342{343return comp->fej9()->isClassInitialized(clazz);344}345346bool347J9::ClassEnv::classHasIllegalStaticFinalFieldModification(TR_OpaqueClassBlock * clazzPointer)348{349J9Class* j9clazz = TR::Compiler->cls.convertClassOffsetToClassPtr(clazzPointer);350#if defined(J9VM_OPT_JITSERVER)351if (auto stream = TR::CompilationInfo::getStream())352{353// J9ClassHasIllegalFinalFieldModifications bit is cached by ClientSessionData::processIllegalFinalFieldModificationList()354// before the compilation takes place.355uintptr_t classFlags = 0;356JITServerHelpers::getAndCacheRAMClassInfo(j9clazz, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_CLASS_FLAGS, (void *)&classFlags);357return J9_ARE_ANY_BITS_SET(classFlags, J9ClassHasIllegalFinalFieldModifications);358}359#endif /* defined(J9VM_OPT_JITSERVER) */360return J9_ARE_ANY_BITS_SET(j9clazz->classFlags, J9ClassHasIllegalFinalFieldModifications);361}362363bool364J9::ClassEnv::hasFinalFieldsInClass(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)365{366return comp->fej9()->hasFinalFieldsInClass(clazz);367}368369bool370J9::ClassEnv::sameClassLoaders(TR::Compilation *comp, TR_OpaqueClassBlock *class1, TR_OpaqueClassBlock *class2)371{372return comp->fej9()->sameClassLoaders(class1, class2);373}374375bool376J9::ClassEnv::isString(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)377{378return comp->fej9()->isString(clazz);379}380381bool382J9::ClassEnv::jitStaticsAreSame(383TR::Compilation *comp,384TR_ResolvedMethod * method1,385int32_t cpIndex1,386TR_ResolvedMethod * method2,387int32_t cpIndex2)388{389return comp->fej9()->jitStaticsAreSame(method1, cpIndex1, method2, cpIndex2);390}391392bool393J9::ClassEnv::jitFieldsAreSame(394TR::Compilation *comp,395TR_ResolvedMethod * method1,396int32_t cpIndex1,397TR_ResolvedMethod * method2,398int32_t cpIndex2,399int32_t isStatic)400{401return comp->fej9()->jitFieldsAreSame(method1, cpIndex1, method2, cpIndex2, isStatic);402}403404bool405J9::ClassEnv::isAnonymousClass(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)406{407return comp->fej9()->isAnonymousClass(clazz);408}409410/*411* Merges the prefix with the field name to a new string.412*413* \param prefix414* prefix could be NULL.415* \param prefixLength416* The length of the prefix string.417* \param mergedLength418* The merged length of the concatenated field name that is returned to the caller.419*/420static char * mergeFieldNames(char *prefix, uint32_t prefixLength, J9ROMFieldShape *field,421TR::Region ®ion, uint32_t &mergedLength)422{423J9UTF8 *fieldNameUTF = J9ROMFIELDSHAPE_NAME(field);424char *fieldName = reinterpret_cast<char *>(J9UTF8_DATA(fieldNameUTF));425uint32_t nameLength = J9UTF8_LENGTH(fieldNameUTF);426427mergedLength = nameLength + prefixLength;428mergedLength++; // for adding '\0' at the end429430char *newName = new (region) char[mergedLength];431432if (prefixLength > 0)433strncpy(newName, prefix, prefixLength);434strncpy(newName + prefixLength, fieldName, nameLength);435436newName[mergedLength-1] = '\0';437438return newName;439}440441/*442* Builds a new string with the prefix and the field name and appends the string with "." to be used443* as a part of the flattened field chain name.444*445* \param prefix446* prefix could be ended with `.` or NULL.447* \param prefixLength448* The length of the prefix string.449* \param mergedLength450* The merged length of the concatenated field name that is returned to the caller.451*/452static char * buildTransitiveFieldNames(char *prefix, uint32_t prefixLength, J9ROMFieldShape *field,453TR::Region ®ion, uint32_t &mergedLength)454{455J9UTF8 *fieldNameUTF = J9ROMFIELDSHAPE_NAME(field);456char *fieldName = reinterpret_cast<char *>(J9UTF8_DATA(fieldNameUTF));457uint32_t nameLength = J9UTF8_LENGTH(fieldNameUTF);458459mergedLength = nameLength + prefixLength;460mergedLength++; // for appending '.'461mergedLength++; // for adding '\0' at the end462463char *newName = new (region) char[mergedLength];464465if (prefixLength > 0)466strncpy(newName, prefix, prefixLength);467strncpy(newName + prefixLength, fieldName, nameLength);468469newName[mergedLength-2] = '.';470newName[mergedLength-1] = '\0';471472return newName;473}474475static void addEntryForFieldImpl(TR_VMField *field, TR::TypeLayoutBuilder &tlb, TR::Region ®ion, J9Class *definingClass,476char *prefix, uint32_t prefixLength, IDATA offsetBase, TR::Compilation *comp)477{478J9JavaVM *vm = comp->fej9()->getJ9JITConfig()->javaVM;479bool trace = comp->getOption(TR_TraceILGen);480uint32_t mergedLength = 0;481J9UTF8 *signature = J9ROMFIELDSHAPE_SIGNATURE(field->shape);482483if (TR::Compiler->om.areValueTypesEnabled() &&484vm->internalVMFunctions->isNameOrSignatureQtype(signature) &&485vm->internalVMFunctions->isFlattenableFieldFlattened(definingClass, field->shape))486{487char *prefixForChild = buildTransitiveFieldNames(prefix, prefixLength, field->shape, comp->trMemory()->currentStackRegion(), mergedLength);488uint32_t prefixLengthForChild = mergedLength-1;489IDATA offsetBaseForChild = field->offset + offsetBase;490491if (trace)492traceMsg(comp, "field %s:%s is flattened. offset from TR_VMField %d, offset from fcc %d\n",493field->name, field->signature, field->offset,494vm->internalVMFunctions->getFlattenableFieldOffset(definingClass, field->shape));495496J9Class *fieldClass = vm->internalVMFunctions->getFlattenableFieldType(definingClass, field->shape);497TR_VMFieldsInfo fieldsInfo(comp, fieldClass, 1, stackAlloc);498ListIterator<TR_VMField> iter(fieldsInfo.getFields());499for (TR_VMField *childField = iter.getFirst(); childField; childField = iter.getNext())500{501IDATA offsetBaseForChild = field->offset + offsetBase;502/* Types with fields (flat or non-flat) that require double (64bit) alignment are pre-padded if there isn't503* a smaller type that can be used as pre-padding. Pre-padding is eliminated when a type is flattened within504* its container. As a result pre-padding must be subtracted from the base offset of the flattened field.505*/506offsetBaseForChild -= J9CLASS_PREPADDING_SIZE(fieldClass);507508addEntryForFieldImpl(childField, tlb, region, fieldClass, prefixForChild, prefixLengthForChild, offsetBaseForChild, comp);509}510}511else512{513char *signature = field->signature;514char charSignature = *signature;515TR::DataType dataType;516switch(charSignature)517{518case 'Z':519case 'B':520case 'C':521case 'S':522case 'I':523{524dataType = TR::Int32;525break;526}527case 'J':528{529dataType = TR::Int64;530break;531}532case 'F':533{534dataType = TR::Float;535break;536}537case 'D':538{539dataType = TR::Double;540break;541}542case 'L':543case 'Q':544case '[':545{546dataType = TR::Address;547break;548}549}550551char *fieldName = mergeFieldNames(prefix, prefixLength, field->shape, region, mergedLength);552int32_t offset = offsetBase + field->offset + TR::Compiler->om.objectHeaderSizeInBytes();553bool isVolatile = (field->modifiers & J9AccVolatile) ? true : false;554bool isPrivate = (field->modifiers & J9AccPrivate) ? true : false;555bool isFinal = (field->modifiers & J9AccFinal) ? true : false;556557int sigLen = strlen(signature);558char *fieldSignature = new (region) char[sigLen+1];559memcpy(fieldSignature, signature, sigLen);560fieldSignature[sigLen] = '\0';561562if (trace)563traceMsg(comp, "type layout definingClass %p field: %s signature: %s field offset: %d offsetBase %d\n", definingClass, fieldName, fieldSignature, field->offset, offsetBase);564tlb.add(TR::TypeLayoutEntry(dataType, offset, fieldName, isVolatile, isPrivate, isFinal, fieldSignature));565}566}567568static void addEntryForField(TR_VMField *field, TR::TypeLayoutBuilder &tlb, TR::Region ®ion, TR_OpaqueClassBlock *opaqueClazz, TR::Compilation *comp)569{570char *prefix = NULL;571uint32_t prefixLength = 0;572IDATA offsetBase = 0;573J9Class *definingClass = reinterpret_cast<J9Class*>(opaqueClazz);574575addEntryForFieldImpl(field, tlb, region, definingClass, prefix, prefixLength, offsetBase, comp);576}577578const TR::TypeLayout*579J9::ClassEnv::enumerateFields(TR::Region ®ion, TR_OpaqueClassBlock *opaqueClazz, TR::Compilation *comp)580{581TR::TypeLayoutBuilder tlb(region);582#if defined(J9VM_OPT_JITSERVER)583if (comp->isOutOfProcessCompilation())584{585auto stream = TR::CompilationInfo::getStream();586stream->write(JITServer::MessageType::ClassEnv_enumerateFields, opaqueClazz);587auto recv = stream->read<std::vector<TR::TypeLayoutEntry>, std::vector<std::string>, std::vector<std::string>>();588auto entries = std::get<0>(recv);589auto fieldNames = std::get<1>(recv);590auto typeSignatures = std::get<2>(recv);591for (int32_t idx = 0; idx < entries.size(); ++idx)592{593TR::TypeLayoutEntry entry = entries[idx];594char *fieldname = new (region) char[fieldNames[idx].length() + 1];595memcpy(fieldname, fieldNames[idx].c_str(), fieldNames[idx].length() + 1);596entry._fieldname = fieldname;597char *typeSignature = new (region) char[typeSignatures[idx].length() + 1];598memcpy(typeSignature, typeSignatures[idx].c_str(), typeSignatures[idx].length() + 1);599entry._typeSignature = typeSignature;600tlb.add(entry);601}602603}604else605#endif606{607TR_VMFieldsInfo fieldsInfo(comp, reinterpret_cast<J9Class*>(opaqueClazz), 1, stackAlloc);608ListIterator<TR_VMField> iter(fieldsInfo.getFields());609for (TR_VMField *field = iter.getFirst(); field; field = iter.getNext())610{611addEntryForField(field, tlb, region, opaqueClazz, comp);612}613}614615return tlb.build();616}617618int32_t619J9::ClassEnv::vTableSlot(TR::Compilation *comp, TR_OpaqueMethodBlock *method, TR_OpaqueClassBlock *clazz)620{621return comp->fej9()->getVTableSlot(method, clazz);622}623624625int32_t626J9::ClassEnv::flagValueForPrimitiveTypeCheck(TR::Compilation *comp)627{628return comp->fej9()->getFlagValueForPrimitiveTypeCheck();629}630631632int32_t633J9::ClassEnv::flagValueForArrayCheck(TR::Compilation *comp)634{635return comp->fej9()->getFlagValueForArrayCheck();636}637638639int32_t640J9::ClassEnv::flagValueForFinalizerCheck(TR::Compilation *comp)641{642return comp->fej9()->getFlagValueForFinalizerCheck();643}644645646// this should be a method of TR_SymbolReference647char *648J9::ClassEnv::classNameChars(TR::Compilation *comp, TR::SymbolReference * symRef, int32_t & length)649{650return comp->fej9()->classNameChars(comp, symRef, length);651}652653654char *655J9::ClassEnv::classNameChars(TR::Compilation *comp, TR_OpaqueClassBlock *clazz, int32_t & length)656{657return comp->fej9()->getClassNameChars(clazz, length);658}659660661char *662J9::ClassEnv::classSignature_DEPRECATED(TR::Compilation *comp, TR_OpaqueClassBlock * clazz, int32_t & length, TR_Memory *m)663{664return comp->fej9()->getClassSignature_DEPRECATED(clazz, length, m);665}666667668char *669J9::ClassEnv::classSignature(TR::Compilation *comp, TR_OpaqueClassBlock * clazz, TR_Memory *m)670{671return comp->fej9()->getClassSignature(clazz, m);672}673674uintptr_t675J9::ClassEnv::persistentClassPointerFromClassPointer(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)676{677return comp->fej9()->getPersistentClassPointerFromClassPointer(clazz);678}679680TR_OpaqueClassBlock *681J9::ClassEnv::objectClass(TR::Compilation *comp, uintptr_t objectPointer)682{683return comp->fej9()->getObjectClass(objectPointer);684}685686TR_OpaqueClassBlock *687J9::ClassEnv::classFromJavaLangClass(TR::Compilation *comp, uintptr_t objectPointer)688{689return comp->fej9()->getClassFromJavaLangClass(objectPointer);690}691692693uint16_t694J9::ClassEnv::getStringCharacter(TR::Compilation *comp, uintptr_t objectPointer, int32_t index)695{696return comp->fej9()->getStringCharacter(objectPointer, index);697}698699700bool701J9::ClassEnv::getStringFieldByName(TR::Compilation *comp, TR::SymbolReference *stringRef, TR::SymbolReference *fieldRef, void* &pResult)702{703return comp->fej9()->getStringFieldByName(comp, stringRef, fieldRef, pResult);704}705706uintptr_t707J9::ClassEnv::getArrayElementWidthInBytes(TR::Compilation *comp, TR_OpaqueClassBlock* arrayClass)708{709TR_ASSERT(TR::Compiler->cls.isClassArray(comp, arrayClass), "Class must be array");710int32_t logElementSize = ((J9ROMArrayClass*)((J9Class*)arrayClass)->romClass)->arrayShape & 0x0000FFFF;711return 1 << logElementSize;712}713714intptr_t715J9::ClassEnv::getVFTEntry(TR::Compilation *comp, TR_OpaqueClassBlock* clazz, int32_t offset)716{717return comp->fej9()->getVFTEntry(clazz, offset);718}719720uint8_t *721J9::ClassEnv::getROMClassRefName(TR::Compilation *comp, TR_OpaqueClassBlock *clazz, uint32_t cpIndex, int &classRefLen)722{723J9ROMConstantPoolItem *romCP = self()->getROMConstantPool(comp, clazz);724J9ROMFieldRef *romFieldRef = (J9ROMFieldRef *)&romCP[cpIndex];725J9ROMClassRef *romClassRef = (J9ROMClassRef *)&romCP[romFieldRef->classRefCPIndex];726J9UTF8 *classRefNameUtf8 = J9ROMCLASSREF_NAME(romClassRef);727classRefLen = J9UTF8_LENGTH(classRefNameUtf8);728uint8_t *classRefName = J9UTF8_DATA(classRefNameUtf8);729return classRefName;730}731732J9ROMConstantPoolItem *733J9::ClassEnv::getROMConstantPool(TR::Compilation *comp, TR_OpaqueClassBlock *clazz)734{735#if defined(J9VM_OPT_JITSERVER)736if (comp->isOutOfProcessCompilation())737{738J9ROMClass *romClass = TR::compInfoPT->getAndCacheRemoteROMClass(reinterpret_cast<J9Class *>(clazz));739return (J9ROMConstantPoolItem *) ((UDATA) romClass + sizeof(J9ROMClass));740}741#endif /* defined(J9VM_OPT_JITSERVER) */742J9ConstantPool *ramCP = reinterpret_cast<J9ConstantPool *>(comp->fej9()->getConstantPoolFromClass(clazz));743return ramCP->romConstantPool;744}745746bool747J9::ClassEnv::isValueTypeClass(TR_OpaqueClassBlock *clazz)748{749#if defined(J9VM_OPT_JITSERVER)750if (auto stream = TR::CompilationInfo::getStream())751{752uintptr_t classFlags = 0;753JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazz, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_CLASS_FLAGS, (void *)&classFlags);754#ifdef DEBUG755stream->write(JITServer::MessageType::ClassEnv_classFlagsValue, clazz);756uintptr_t classFlagsRemote = std::get<0>(stream->read<uintptr_t>());757// Check that class flags from remote call is equal to the cached ones758classFlags = classFlags & J9ClassIsValueType;759classFlagsRemote = classFlagsRemote & J9ClassIsValueType;760TR_ASSERT(classFlags == classFlagsRemote, "remote call class flags is not equal to cached class flags");761#endif762return classFlags & J9ClassIsValueType;763}764#endif /* defined(J9VM_OPT_JITSERVER) */765J9Class *j9class = reinterpret_cast<J9Class*>(clazz);766return J9_IS_J9CLASS_VALUETYPE(j9class);767}768769bool770J9::ClassEnv::isValueTypeClassFlattened(TR_OpaqueClassBlock *clazz)771{772#if defined(J9VM_OPT_JITSERVER)773if (auto stream = TR::CompilationInfo::getStream())774{775uintptr_t classFlags = 0;776JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazz, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_CLASS_FLAGS, (void *)&classFlags);777#ifdef DEBUG778stream->write(JITServer::MessageType::ClassEnv_classFlagsValue, clazz);779uintptr_t classFlagsRemote = std::get<0>(stream->read<uintptr_t>());780// Check that class flags from remote call is equal to the cached ones781classFlags = classFlags & J9ClassIsFlattened;782classFlagsRemote = classFlagsRemote & J9ClassIsFlattened;783TR_ASSERT(classFlags == classFlagsRemote, "remote call class flags is not equal to cached class flags");784#endif785return classFlags & J9ClassIsFlattened;786}787#endif /* defined(J9VM_OPT_JITSERVER) */788789return (clazz && J9_IS_J9CLASS_FLATTENED(reinterpret_cast<J9Class*>(clazz)));790}791792bool793J9::ClassEnv::isValueBasedOrValueTypeClass(TR_OpaqueClassBlock *clazz)794{795#if defined(J9VM_OPT_JITSERVER)796if (auto stream = TR::CompilationInfo::getStream())797{798uintptr_t classFlags = 0;799JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazz, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_CLASS_FLAGS, (void *)&classFlags);800#ifdef DEBUG801stream->write(JITServer::MessageType::ClassEnv_classFlagsValue, clazz);802uintptr_t classFlagsRemote = std::get<0>(stream->read<uintptr_t>());803// Check that class flags from remote call is equal to the cached ones804classFlags = classFlags & J9_CLASS_DISALLOWS_LOCKING_FLAGS;805classFlagsRemote = classFlagsRemote & J9_CLASS_DISALLOWS_LOCKING_FLAGS;806TR_ASSERT_FATAL(classFlags == classFlagsRemote, "remote call class flags is not equal to cached class flags");807#endif808return J9_ARE_ANY_BITS_SET(classFlags, J9_CLASS_DISALLOWS_LOCKING_FLAGS);809}810#endif /* defined(J9VM_OPT_JITSERVER) */811J9Class *j9class = reinterpret_cast<J9Class*>(clazz);812return J9_ARE_ANY_BITS_SET(j9class->classFlags, J9_CLASS_DISALLOWS_LOCKING_FLAGS);813}814815bool816J9::ClassEnv::classHasIdentity(TR_OpaqueClassBlock *clazz)817{818#if defined(J9VM_OPT_JITSERVER)819if (auto stream = TR::CompilationInfo::getStream())820{821uintptr_t classFlags = 0;822JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazz, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_CLASS_FLAGS, (void *)&classFlags);823#ifdef DEBUG824stream->write(JITServer::MessageType::ClassEnv_classFlagsValue, clazz);825uintptr_t classFlagsRemote = std::get<0>(stream->read<uintptr_t>());826// Check that class flags from remote call is equal to the cached ones827classFlags = classFlags & J9ClassHasIdentity;828classFlagsRemote = classFlagsRemote & J9ClassHasIdentity;829TR_ASSERT_FATAL(classFlags == classFlagsRemote, "remote call class flags is not equal to cached class flags");830#endif831return J9_ARE_ANY_BITS_SET(classFlags, J9ClassHasIdentity);832}833#endif /* defined(J9VM_OPT_JITSERVER) */834J9Class *j9class = reinterpret_cast<J9Class*>(clazz);835return J9_ARE_ANY_BITS_SET(j9class->classFlags, J9ClassHasIdentity);836}837838bool839J9::ClassEnv::isZeroInitializable(TR_OpaqueClassBlock *clazz)840{841#if defined(J9VM_OPT_JITSERVER)842if (auto stream = TR::CompilationInfo::getStream())843{844uintptr_t classFlags = 0;845JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazz, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_CLASS_FLAGS, (void *)&classFlags);846#ifdef DEBUG847stream->write(JITServer::MessageType::ClassEnv_classFlagsValue, clazz);848uintptr_t classFlagsRemote = std::get<0>(stream->read<uintptr_t>());849// Check that class flags from remote call is equal to the cached ones850classFlags = classFlags & J9ClassContainsUnflattenedFlattenables;851classFlagsRemote = classFlagsRemote & J9ClassContainsUnflattenedFlattenables;852TR_ASSERT(classFlags == classFlagsRemote, "remote call class flags is not equal to cached class flags");853#endif854return classFlags & J9ClassContainsUnflattenedFlattenables;855}856#endif857return (self()->classFlagsValue(clazz) & J9ClassContainsUnflattenedFlattenables) == 0;858}859860bool861J9::ClassEnv::containsZeroOrOneConcreteClass(TR::Compilation *comp, List<TR_PersistentClassInfo>* subClasses)862{863int count = 0;864#if defined(J9VM_OPT_JITSERVER)865if (comp->isOutOfProcessCompilation())866{867ListIterator<TR_PersistentClassInfo> j(subClasses);868TR_ScratchList<TR_PersistentClassInfo> subClassesNotCached(comp->trMemory());869870// Process classes cached at the server first871ClientSessionData * clientData = TR::compInfoPT->getClientData();872for (TR_PersistentClassInfo *ptClassInfo = j.getFirst(); ptClassInfo; ptClassInfo = j.getNext())873{874TR_OpaqueClassBlock *clazz = ptClassInfo->getClassId();875J9Class *j9clazz = TR::Compiler->cls.convertClassOffsetToClassPtr(clazz);876auto romClass = JITServerHelpers::getRemoteROMClassIfCached(clientData, j9clazz);877if (romClass == NULL)878{879subClassesNotCached.add(ptClassInfo);880}881else882{883if (TR::Compiler->cls.isConcreteClass(comp, clazz))884{885if (++count > 1)886return false;887}888}889}890// Traverse through classes that are not cached on server891ListIterator<TR_PersistentClassInfo> i(&subClassesNotCached);892for (TR_PersistentClassInfo *ptClassInfo = i.getFirst(); ptClassInfo; ptClassInfo = i.getNext())893{894TR_OpaqueClassBlock *clazz = ptClassInfo->getClassId();895if (TR::Compiler->cls.isConcreteClass(comp, clazz))896{897if (++count > 1)898return false;899}900}901}902else // non-jitserver903#endif /* defined(J9VM_OPT_JITSERVER) */904{905ListIterator<TR_PersistentClassInfo> i(subClasses);906for (TR_PersistentClassInfo *ptClassInfo = i.getFirst(); ptClassInfo; ptClassInfo = i.getNext())907{908TR_OpaqueClassBlock *clazz = ptClassInfo->getClassId();909if (TR::Compiler->cls.isConcreteClass(comp, clazz))910{911if (++count > 1)912return false;913}914}915}916return true;917}918919bool920J9::ClassEnv::isClassRefValueType(TR::Compilation *comp, TR_OpaqueClassBlock *cpContextClass, int32_t cpIndex)921{922#if defined(J9VM_OPT_JITSERVER)923if (auto stream = TR::CompilationInfo::getStream())924{925stream->write(JITServer::MessageType::ClassEnv_isClassRefValueType, cpContextClass, cpIndex);926return std::get<0>(stream->read<bool>());927}928else // non-jitserver929#endif /* defined(J9VM_OPT_JITSERVER) */930{931J9Class * j9class = reinterpret_cast<J9Class *>(cpContextClass);932J9JavaVM *vm = comp->fej9()->getJ9JITConfig()->javaVM;933return vm->internalVMFunctions->isClassRefQtype(j9class, cpIndex);934}935}936937char *938J9::ClassEnv::classNameToSignature(const char *name, int32_t &len, TR::Compilation *comp, TR_AllocationKind allocKind, TR_OpaqueClassBlock *clazz)939{940char *sig;941942if (name[0] == '[')943{944sig = (char *)comp->trMemory()->allocateMemory(len+1, allocKind);945memcpy(sig,name,len);946}947else948{949len += 2;950sig = (char *)comp->trMemory()->allocateMemory(len+1, allocKind);951if (clazz && TR::Compiler->om.areValueTypesEnabled() && self()->isValueTypeClass(clazz))952sig[0] = 'Q';953else954sig[0] = 'L';955memcpy(sig+1,name,len-2);956sig[len-1]=';';957}958959sig[len] = '\0';960return sig;961}962963int32_t964J9::ClassEnv::flattenedArrayElementSize(TR::Compilation *comp, TR_OpaqueClassBlock *arrayClass)965{966#if defined(J9VM_OPT_JITSERVER)967if (auto stream = TR::CompilationInfo::getStream())968{969int32_t arrayElementSize = 0;970JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)arrayClass, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_ARRAY_ELEMENT_SIZE, (void *)&arrayElementSize);971return arrayElementSize;972}973else974#endif /* defined(J9VM_OPT_JITSERVER) */975{976J9JavaVM *vm = comp->fej9()->getJ9JITConfig()->javaVM;977return vm->internalVMFunctions->arrayElementSize((J9ArrayClass*)self()->convertClassOffsetToClassPtr(arrayClass));978}979}980981982