Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for class lookup by name in CP for JITServer/AOT #20686

Merged
merged 2 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 3 additions & 23 deletions runtime/compiler/compile/J9SymbolReferenceTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,30 +826,10 @@ J9::SymbolReferenceTable::findOrFabricateShadowSymbol(
qualifiedFieldName,
TR::Symbol::UnknownField);

// As yet JITServer does not support getClassFromSignature() based directly
// on J9ConstantPool*, but it does support it using TR_OpaqueMethodBlock*.
// Find an arbitrary method (if there is one) defined by the same class that
// declares the field, and use that method to getClassFromSignature(), since
// it will have the desired constant pool.
//
// The class containing the field is highly likely to declare at least a
// constructor, and if it doesn't, then it seems that it's not possible to
// instantiate it in the usual way (new, dup, invokespecial <init>), so the
// performance of accesses to its instance fields is especially unlikely to
// matter.
//
TR_J9VM *fej9 = reinterpret_cast<TR_J9VM *>(fe());
if (fej9->getNumMethods(containingClass) > 0)
{
auto *firstMethod =
static_cast<TR_OpaqueMethodBlock*>(fej9->getMethods(containingClass));

TR_OpaqueClassBlock *declaredClass = fej9->getClassFromSignature(
signature, (int32_t)strlen(signature), firstMethod);

if (declaredClass != NULL)
sym->setDeclaredClass(declaredClass);
}
TR_OpaqueClassBlock *declaredClass = fej9->getClassFromSignature(signature, (int32_t)strlen(signature), containingClass);
jdmpapin marked this conversation as resolved.
Show resolved Hide resolved
if (declaredClass != NULL)
sym->setDeclaredClass(declaredClass);

mcount_t methodIndex = mcount_t::valueOf(0);
int32_t cpIndex = -1;
Expand Down
14 changes: 6 additions & 8 deletions runtime/compiler/control/JITClientCompilationThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,15 +308,13 @@ handleServerMessage(JITServer::ClientStream *client, TR_J9VM *fe, JITServer::Mes
{
// Need to get a non-AOT frontend because the AOT frontend also
// performs some class validation which we want to do at the server
TR_J9VMBase *fej9 = TR_J9VMBase::get(vmThread->javaVM->jitConfig, vmThread);
auto recv = client->getRecvData<std::string, TR_OpaqueMethodBlock *, bool>();
auto fej9 = (TR_J9VM *)TR_J9VMBase::get(vmThread->javaVM->jitConfig, vmThread);
auto recv = client->getRecvData<std::string, J9ConstantPool *>();
auto &sig = std::get<0>(recv);
auto method = std::get<1>(recv);
bool isVettedForAOT = std::get<2>(recv);
auto clazz = fej9->getClassFromSignature(sig.data(), sig.length(), method, isVettedForAOT);
J9ClassLoader *cl = clazz ? reinterpret_cast<J9ClassLoader *>(fej9->getClassLoader(clazz)) : NULL;
J9ClassLoader *methodCL = reinterpret_cast<J9ClassLoader *>(fej9->getClassLoader(fej9->getClassOfMethod(method)));
client->write(response, clazz, cl, methodCL);
auto constantPool = std::get<1>(recv);
auto clazz = fej9->getClassFromSignature(sig.data(), sig.length(), constantPool, true);
J9ClassLoader *cl = clazz ? reinterpret_cast<J9ClassLoader *>(fej9->getClassLoader((TR_OpaqueClassBlock *)clazz)) : NULL;
client->write(response, clazz, cl);
}
break;
case MessageType::VM_jitFieldsOrStaticsAreSame:
Expand Down
40 changes: 16 additions & 24 deletions runtime/compiler/env/VMJ9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7422,12 +7422,20 @@ TR_J9VM::getClassFromSignature(const char * sig, int32_t sigLength, TR_ResolvedM
TR_OpaqueClassBlock *
TR_J9VM::getClassFromSignature(const char * sig, int32_t sigLength, TR_OpaqueMethodBlock * method, bool isVettedForAOT)
{
J9ConstantPool * constantPool = (J9ConstantPool *) (J9_CP_FROM_METHOD((J9Method*)method));
return getClassFromSignature(sig, sigLength, constantPool);
auto constantPool = (J9ConstantPool *)getConstantPoolFromMethod(method);
return getClassFromSignature(sig, sigLength, constantPool, isVettedForAOT);
}


TR_OpaqueClassBlock *
TR_J9VM::getClassFromSignature(const char * sig, int32_t sigLength, TR_OpaqueClassBlock *clazz, bool isVettedForAOT)
{
auto constantPool = (J9ConstantPool *)getConstantPoolFromClass(clazz);
return getClassFromSignature(sig, sigLength, constantPool, isVettedForAOT);
}

TR_OpaqueClassBlock *
TR_J9VM::getClassFromSignature(const char * sig, int32_t sigLength, J9ConstantPool * constantPool)
TR_J9VM::getClassFromSignature(const char * sig, int32_t sigLength, J9ConstantPool * constantPool, bool isVettedForAOT)
{
// Primitive types don't have a class associated with them
if (isSignatureForPrimitiveType(sig, sigLength))
Expand Down Expand Up @@ -9056,34 +9064,18 @@ TR_J9SharedCacheVM::isInstanceOf(TR_OpaqueClassBlock * a, TR_OpaqueClassBlock *b
}

TR_OpaqueClassBlock *
TR_J9SharedCacheVM::getClassFromSignature(const char * sig, int32_t sigLength, TR_ResolvedMethod * method, bool isVettedForAOT)
TR_J9SharedCacheVM::getClassFromSignature(const char * sig, int32_t sigLength, J9ConstantPool *constantPool, bool isVettedForAOT)
{
return getClassFromSignature(sig, sigLength, (TR_OpaqueMethodBlock *)method->getPersistentIdentifier(), isVettedForAOT);
}

TR_OpaqueClassBlock *
TR_J9SharedCacheVM::getClassFromSignature(const char * sig, int32_t sigLength, TR_OpaqueMethodBlock * method, bool isVettedForAOT)
{
TR_OpaqueClassBlock* j9class = TR_J9VM::getClassFromSignature(sig, sigLength, method, true);
TR_OpaqueClassBlock* j9class = TR_J9VM::getClassFromSignature(sig, sigLength, constantPool, isVettedForAOT);
bool validated = false;
TR::Compilation* comp = TR::comp();

if (j9class)
{
if (comp->getOption(TR_UseSymbolValidationManager))
{
TR::SymbolValidationManager *svm = comp->getSymbolValidationManager();
SVM_ASSERT_ALREADY_VALIDATED(svm, method);
validated = svm->addClassByNameRecord(j9class, getClassFromMethodBlock(method));
}
else
{
if (isVettedForAOT)
{
if (((TR_ResolvedRelocatableJ9Method *) comp->getCurrentMethod())->validateArbitraryClass(comp, (J9Class *) j9class))
validated = true;
}
}
validated = comp->getSymbolValidationManager()->addClassByNameRecord(j9class, getClassFromCP(constantPool));
else if (isVettedForAOT)
validated = ((TR_ResolvedRelocatableJ9Method *) comp->getCurrentMethod())->validateArbitraryClass(comp, (J9Class *) j9class);
}

if (validated)
Expand Down
11 changes: 5 additions & 6 deletions runtime/compiler/env/VMJ9.h
Original file line number Diff line number Diff line change
Expand Up @@ -1573,8 +1573,10 @@ class TR_J9VM : public TR_J9VMBase
virtual TR_OpaqueClassBlock * getNullRestrictedArrayClassFromComponentClass(TR_OpaqueClassBlock *componentClass);
virtual TR_OpaqueClassBlock * getLeafComponentClassFromArrayClass(TR_OpaqueClassBlock * arrayClass);
virtual int32_t getNewArrayTypeFromClass(TR_OpaqueClassBlock *clazz);
virtual TR_OpaqueClassBlock * getClassFromSignature(const char * sig, int32_t length, TR_ResolvedMethod *method, bool isVettedForAOT=false);
virtual TR_OpaqueClassBlock * getClassFromSignature(const char * sig, int32_t length, TR_OpaqueMethodBlock *method, bool isVettedForAOT=false);
virtual TR_OpaqueClassBlock *getClassFromSignature(const char * sig, int32_t sigLength, TR_ResolvedMethod *method, bool isVettedForAOT=false);
virtual TR_OpaqueClassBlock *getClassFromSignature(const char * sig, int32_t sigLength, TR_OpaqueMethodBlock *method, bool isVettedForAOT=false);
virtual TR_OpaqueClassBlock *getClassFromSignature(const char * sig, int32_t sigLength, TR_OpaqueClassBlock *clazz, bool isVettedForAOT=false);
virtual TR_OpaqueClassBlock *getClassFromSignature(const char * sig, int32_t sigLength, J9ConstantPool * constantPool, bool isVettedForAOT=false);

virtual TR_OpaqueClassBlock *getBaseComponentClass(TR_OpaqueClassBlock *clazz, int32_t &numDims)
{
Expand Down Expand Up @@ -1615,8 +1617,6 @@ class TR_J9VM : public TR_J9VMBase

virtual TR_StaticFinalData dereferenceStaticFinalAddress(void *staticAddress, TR::DataType addressType);

TR_OpaqueClassBlock * getClassFromSignature(const char * sig, int32_t sigLength, J9ConstantPool * constantPool);

private:
void transformJavaLangClassIsArrayOrIsPrimitive( TR::Compilation *, TR::Node * callNode, TR::TreeTop * treeTop, int32_t andMask);
void transformJavaLangClassIsArray( TR::Compilation *, TR::Node * callNode, TR::TreeTop * treeTop);
Expand Down Expand Up @@ -1715,8 +1715,7 @@ class TR_J9SharedCacheVM : public TR_J9VM
virtual bool isClassVisible(TR_OpaqueClassBlock * sourceClass, TR_OpaqueClassBlock * destClass);
virtual bool isPrimitiveArray(TR_OpaqueClassBlock *);
virtual bool isReferenceArray(TR_OpaqueClassBlock *);
virtual TR_OpaqueClassBlock * getClassFromSignature(const char * sig, int32_t length, TR_ResolvedMethod *method, bool isVettedForAOT=false);
virtual TR_OpaqueClassBlock * getClassFromSignature(const char * sig, int32_t length, TR_OpaqueMethodBlock *method, bool isVettedForAOT=false);
virtual TR_OpaqueClassBlock * getClassFromSignature(const char * sig, int32_t length, J9ConstantPool *constantPool, bool isVettedForAOT=false);
virtual TR_OpaqueClassBlock * getSystemClassFromClassName(const char * name, int32_t length, bool isVettedForAOT=false);

virtual intptr_t methodTrampolineLookup( TR::Compilation *, TR::SymbolReference *symRef, void *callSite);
Expand Down
160 changes: 42 additions & 118 deletions runtime/compiler/env/VMJ9Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,26 +348,49 @@ TR_J9ServerVM::getLeafComponentClassFromArrayClass(TR_OpaqueClassBlock * arrayCl
}

TR_OpaqueClassBlock *
TR_J9ServerVM::getClassFromSignature(const char *sig, int32_t length, TR_ResolvedMethod *method, bool isVettedForAOT)
TR_J9ServerVM::getClassFromSignature(const char *sig, int32_t sigLength, J9ConstantPool *constantPool, bool isVettedForAOT)
{
// Primitive types don't have a class associated with them
if (isSignatureForPrimitiveType(sig, length))
if (isSignatureForPrimitiveType(sig, sigLength))
return NULL;

TR_OpaqueClassBlock * clazz = NULL;
J9ClassLoader * cl = ((TR_ResolvedJ9Method *)method)->getClassLoader();
ClassLoaderStringPair key = {cl, std::string(sig, length)};
PersistentUnorderedMap<ClassLoaderStringPair, TR_OpaqueClassBlock*> & classBySignatureMap = _compInfoPT->getClientData()->getClassBySignatureMap();
auto cpClass = getClassFromCP(constantPool);
auto cpClassLoader = (J9ClassLoader *)getClassLoader(cpClass);

ClassLoaderStringPair key = {cpClassLoader, std::string(sig, sigLength)};
PersistentUnorderedMap<ClassLoaderStringPair, TR_OpaqueClassBlock *> & classBySignatureMap = _compInfoPT->getClientData()->getClassBySignatureMap();
{
OMR::CriticalSection classFromSigCS(_compInfoPT->getClientData()->getClassMapMonitor());
auto it = classBySignatureMap.find(key);
if (it != classBySignatureMap.end())
return it->second;
}

// classname not found; ask the client and cache the answer
clazz = getClassFromSignature(sig, length, (TR_OpaqueMethodBlock *)method->getPersistentIdentifier(), isVettedForAOT);
JITServer::ServerStream *stream = _compInfoPT->getMethodBeingCompiled()->_stream;
std::string str(sig, sigLength);
stream->write(JITServer::MessageType::VM_getClassFromSignature, str, constantPool);
auto recv = stream->read<TR_OpaqueClassBlock *, J9ClassLoader *>();
TR_OpaqueClassBlock *clazz = std::get<0>(recv);
J9ClassLoader *cl = std::get<1>(recv);
if (clazz)
{
if (cl != cpClassLoader)
{
// make sure that the class is cached
J9ROMClass *romClass = TR::Compiler->cls.romClassOf((TR_OpaqueClassBlock *)clazz);
TR_ASSERT_FATAL(romClass, "class %p could not be cached", clazz);
OMR::CriticalSection getRemoteROMClass(_compInfoPT->getClientData()->getROMMapMonitor());
auto it = _compInfoPT->getClientData()->getROMClassMap().find(reinterpret_cast<J9Class *>(clazz));
if (it != _compInfoPT->getClientData()->getROMClassMap().end())
{
// remember that we cached this class by cp class loader
// so that the cache entry is removed if the cached class gets unloaded
// if the class loaders are not identical
it->second._referencingClassLoaders.insert(cpClassLoader);
}
}

OMR::CriticalSection classFromSigCS(_compInfoPT->getClientData()->getClassMapMonitor());
classBySignatureMap[key] = clazz;
}
Expand All @@ -383,39 +406,6 @@ TR_J9ServerVM::getClassFromSignature(const char *sig, int32_t length, TR_Resolve
return clazz;
}


TR_OpaqueClassBlock *
TR_J9ServerVM::getClassFromSignature(const char *sig, int32_t length, TR_OpaqueMethodBlock *method, bool isVettedForAOT)
{
// Primitive types don't have a class associated with them
if (isSignatureForPrimitiveType(sig, length))
return NULL;

JITServer::ServerStream *stream = _compInfoPT->getMethodBeingCompiled()->_stream;
std::string str(sig, length);
stream->write(JITServer::MessageType::VM_getClassFromSignature, str, method, isVettedForAOT);
auto recv = stream->read<TR_OpaqueClassBlock *, J9ClassLoader *, J9ClassLoader *>();
TR_OpaqueClassBlock *clazz = std::get<0>(recv);
J9ClassLoader *cl = std::get<1>(recv);
J9ClassLoader *methodClassLoader = std::get<2>(recv);
if (clazz && cl != methodClassLoader)
{
// make sure that the class is cached
J9ROMClass *romClass = TR::Compiler->cls.romClassOf(clazz);
TR_ASSERT_FATAL(romClass, "class %p could not be cached", clazz);
OMR::CriticalSection getRemoteROMClass(_compInfoPT->getClientData()->getROMMapMonitor());
auto it = _compInfoPT->getClientData()->getROMClassMap().find(reinterpret_cast<J9Class *>(clazz));
if (it != _compInfoPT->getClientData()->getROMClassMap().end())
{
// remember that we cached this class by method class loader
// so that the cache entry is removed if the cached class gets unloaded
// if the class loaders are not identical
it->second._referencingClassLoaders.insert(methodClassLoader);
}
}
return clazz;
}

void *
TR_J9ServerVM::getSystemClassLoader()
{
Expand Down Expand Up @@ -2817,91 +2807,25 @@ TR_J9SharedCacheServerVM::supportAllocationInlining(TR::Compilation *comp, TR::N
}

TR_OpaqueClassBlock *
TR_J9SharedCacheServerVM::getClassFromSignature(const char * sig, int32_t sigLength, TR_ResolvedMethod * method, bool isVettedForAOT)
TR_J9SharedCacheServerVM::getClassFromSignature(const char *sig, int32_t sigLength, J9ConstantPool *constantPool, bool isVettedForAOT)
{
// Primitive types don't have a class associated with them
if (isSignatureForPrimitiveType(sig, sigLength))
return NULL;

TR_ResolvedRelocatableJ9JITServerMethod* resolvedJITServerMethod = (TR_ResolvedRelocatableJ9JITServerMethod *)method;
TR_OpaqueClassBlock* clazz = NULL;
J9ClassLoader * cl = ((TR_ResolvedJ9Method *)method)->getClassLoader();
ClassLoaderStringPair key = {cl, std::string(sig, sigLength)};
PersistentUnorderedMap<ClassLoaderStringPair, TR_OpaqueClassBlock*> & classBySignatureMap = _compInfoPT->getClientData()->getClassBySignatureMap();
{
OMR::CriticalSection classFromSigCS(_compInfoPT->getClientData()->getClassMapMonitor());
auto it = classBySignatureMap.find(key);
if (it != classBySignatureMap.end())
clazz = it->second;
}
if (!clazz)
{
// classname not found; ask the client and cache the answer
clazz = TR_J9ServerVM::getClassFromSignature(sig, sigLength, (TR_OpaqueMethodBlock *)resolvedJITServerMethod->getPersistentIdentifier(), isVettedForAOT);
if (clazz)
{
{
OMR::CriticalSection classFromSigCS(_compInfoPT->getClientData()->getClassMapMonitor());
classBySignatureMap[key] = clazz;
}
if (!validateClass((TR_OpaqueMethodBlock *)resolvedJITServerMethod->getPersistentIdentifier(), clazz, isVettedForAOT))
{
clazz = NULL;
}
}
else
{
// Class with given name does not exist yet, but it could be
// loaded in the future, thus we should not cache NULL pointers.
// Note: many times we get in here due to Ljava/lang/String$StringCompressionFlag;
// In theory we could consider this a special case and watch the CHTable updates
// for a class load event for Ljava/lang/String$StringCompressionFlag, but it may not
// be worth the trouble.
//printf("ErrorSystem %lu for cl=%p\tclassName=%.*s\n", ++errorsSystem, cl, length, sig);
}
}
else
{
if (!validateClass((TR_OpaqueMethodBlock *)resolvedJITServerMethod->getPersistentIdentifier(), clazz, isVettedForAOT))
clazz = NULL;
}
return clazz;
}
auto comp = _compInfoPT->getCompilation();
auto j9class = TR_J9ServerVM::getClassFromSignature(sig, sigLength, constantPool, isVettedForAOT);
bool validated = false;

TR_OpaqueClassBlock *
TR_J9SharedCacheServerVM::getClassFromSignature(const char * sig, int32_t sigLength, TR_OpaqueMethodBlock * method, bool isVettedForAOT)
{
TR_OpaqueClassBlock* j9class = TR_J9ServerVM::getClassFromSignature(sig, sigLength, method, true);
if (j9class)
{
if (!validateClass(method, j9class, isVettedForAOT))
j9class = NULL;
if (comp->getOption(TR_UseSymbolValidationManager))
validated = comp->getSymbolValidationManager()->addClassByNameRecord(j9class, getClassFromCP(constantPool));
else if (isVettedForAOT)
validated = ((TR_ResolvedRelocatableJ9JITServerMethod *) comp->getCurrentMethod())->validateArbitraryClass(comp, (J9Class *) j9class);
}

return j9class;
}

bool
TR_J9SharedCacheServerVM::validateClass(TR_OpaqueMethodBlock * method, TR_OpaqueClassBlock* j9class, bool isVettedForAOT)
{
TR::Compilation* comp = _compInfoPT->getCompilation();
bool validated = false;

if (comp->getOption(TR_UseSymbolValidationManager))
{
TR::SymbolValidationManager *svm = comp->getSymbolValidationManager();
SVM_ASSERT_ALREADY_VALIDATED(svm, method);
validated = svm->addClassByNameRecord(j9class, getClassFromMethodBlock(method));
}
if (validated)
return j9class;
else
{
if (isVettedForAOT)
{
if (((TR_ResolvedRelocatableJ9JITServerMethod *) comp->getCurrentMethod())->validateArbitraryClass(comp, (J9Class *) j9class))
validated = true;
}
}
return validated;
return NULL;

}

bool
Expand Down
Loading