Skip to content
Open
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
17 changes: 2 additions & 15 deletions runtime/compiler/compile/J9Compilation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -851,22 +851,9 @@ J9::Compilation::freeKnownObjectTable()
{
if (_knownObjectTable)
{
#if defined(J9VM_OPT_JITSERVER)
if (!isOutOfProcessCompilation())
#endif /* defined(J9VM_OPT_JITSERVER) */
{
TR::VMAccessCriticalSection freeKnownObjectTable(self()->fej9());

J9VMThread *thread = self()->fej9()->vmThread();
TR_ASSERT(thread, "assertion failure");

TR_ArrayIterator<uintptr_t> i(&_knownObjectTable->_references);
for (uintptr_t *ref = i.getFirst(); !i.pastEnd(); ref = i.getNext())
thread->javaVM->internalVMFunctions->j9jni_deleteLocalRef((JNIEnv*)thread, (jobject)ref);
}
_knownObjectTable->freeKnownObjectTable();
_knownObjectTable = NULL;
}

_knownObjectTable = NULL;
}


Expand Down
36 changes: 8 additions & 28 deletions runtime/compiler/control/JITClientCompilationThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,14 @@ handleServerMessage(JITServer::ClientStream *client, TR_J9VM *fe, JITServer::Mes
knot->getPointerLocation(ci.knownObjectIndex));
}
break;
case MessageType::VM_getObjectClassInfoFromKnotIndex:
{
auto recv = client->getRecvData<TR::KnownObjectTable::Index>();
TR::KnownObjectTable::Index knotIndex = std::get<0>(recv);
TR::KnownObjectTable::ObjectInfo objInfo = fe->getObjClassInfoFromKnotIndex(comp, knotIndex);
client->write(response, objInfo);
}
break;
case MessageType::VM_stackWalkerMaySkipFrames:
{
client->getRecvData<JITServer::Void>();
Expand Down Expand Up @@ -2781,41 +2789,13 @@ handleServerMessage(JITServer::ClientStream *client, TR_J9VM *fe, JITServer::Mes
std::string((char*) bodyInfo->getMethodInfo(), sizeof(TR_PersistentMethodInfo)));
}
break;
case MessageType::KnownObjectTable_getOrCreateIndex:
{
uintptr_t objectPointer = std::get<0>(client->getRecvData<uintptr_t>());
TR::KnownObjectTable::Index index = TR::KnownObjectTable::UNKNOWN;
uintptr_t *objectPointerReference = NULL;

{
TR::VMAccessCriticalSection knownObjectTableGetIndex(fe);
index = knot->getOrCreateIndex(objectPointer);
objectPointerReference = knot->getPointerLocation(index);
}

client->write(response, index, objectPointerReference);
}
break;
case MessageType::KnownObjectTable_getOrCreateIndexAt:
{
uintptr_t *objectPointerReferenceServerQuery = std::get<0>(client->getRecvData<uintptr_t*>());
TR::KnownObjectTable::Index index = knot->getOrCreateIndexAt(objectPointerReferenceServerQuery);
client->write(response, index, knot->getPointerLocation(index));
}
break;
case MessageType::KnownObjectTable_getPointer:
{
TR::KnownObjectTable::Index knotIndex = std::get<0>(client->getRecvData<TR::KnownObjectTable::Index>());
uintptr_t objectPointer = 0;

{
TR::VMAccessCriticalSection knownObjectTableGetPointer(fe);
objectPointer = knot->getPointer(knotIndex);
}

client->write(response, objectPointer);
}
break;
case MessageType::KnownObjectTable_getExistingIndexAt:
{
uintptr_t *objectPointerReference = std::get<0>(client->getRecvData<uintptr_t*>());
Expand Down
121 changes: 58 additions & 63 deletions runtime/compiler/env/J9KnownObjectTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@

J9::KnownObjectTable::KnownObjectTable(TR::Compilation *comp) :
OMR::KnownObjectTableConnector(comp),
_references(comp->trMemory()),
_objectInfos(comp->trMemory()),
_stableArrayRanks(comp->trMemory())
{
_references.add(NULL); // Reserve index zero for NULL
_objectInfos.add(ObjectInfo()); // Reserve index zero for NULL
}


Expand All @@ -54,7 +54,7 @@ J9::KnownObjectTable::self()
TR::KnownObjectTable::Index
J9::KnownObjectTable::getEndIndex()
{
return _references.size();
return _objectInfos.size();
}


Expand All @@ -73,45 +73,23 @@ J9::KnownObjectTable::getOrCreateIndex(uintptr_t objectPointer)

uint32_t nextIndex = self()->getEndIndex();
#if defined(J9VM_OPT_JITSERVER)
if (self()->comp()->isOutOfProcessCompilation())
{
TR_ASSERT_FATAL(false, "It is not safe to call getOrCreateIndex() at the server. The object pointer could have become stale at the client.");
auto stream = TR::CompilationInfo::getStream();
stream->write(JITServer::MessageType::KnownObjectTable_getOrCreateIndex, objectPointer);
auto recv = stream->read<TR::KnownObjectTable::Index, uintptr_t *>();

TR::KnownObjectTable::Index index = std::get<0>(recv);
uintptr_t *objectReferenceLocation = std::get<1>(recv);
TR_ASSERT_FATAL(index <= nextIndex, "The KOT index %d at the client is greater than the KOT index %d at the server", index, nextIndex);

if (index < nextIndex)
{
return index;
}
else
{
updateKnownObjectTableAtServer(index, objectReferenceLocation);
}
}
else
TR_ASSERT_FATAL(!self()->comp()->isOutOfProcessCompilation(), "It is not safe to call getOrCreateIndex() at the server. The object pointer could have become stale at the client.");
#endif /* defined(J9VM_OPT_JITSERVER) */
{
TR_J9VMBase *fej9 = (TR_J9VMBase *)(self()->fe());
TR_ASSERT(fej9->haveAccess(), "Must haveAccess in J9::KnownObjectTable::getOrCreateIndex");

// Search for existing matching entry
//
for (uint32_t i = 1; i < nextIndex; i++)
if (*_references.element(i) == objectPointer)
return i;

// No luck -- allocate a new one
//
J9VMThread *thread = getJ9VMThreadFromTR_VM(self()->fe());
TR_ASSERT(thread, "assertion failure");
_references.setSize(nextIndex+1);
_references[nextIndex] = (uintptr_t*)thread->javaVM->internalVMFunctions->j9jni_createLocalRef((JNIEnv*)thread, (j9object_t)objectPointer);
}
TR_J9VMBase *fej9 = (TR_J9VMBase *)(self()->fe());
TR_ASSERT(fej9->haveAccess(), "Must haveAccess in J9::KnownObjectTable::getOrCreateIndex");

// Search for existing matching entry
//
for (uint32_t i = 1; i < nextIndex; i++)
if (*(_objectInfos.element(i)._jniReference) == objectPointer)
return i;

// No luck -- allocate a new one
//
J9VMThread *thread = getJ9VMThreadFromTR_VM(self()->fe());
TR_ASSERT(thread, "assertion failure");
_objectInfos.setSize(nextIndex+1);
_objectInfos[nextIndex]._jniReference = (uintptr_t*)thread->javaVM->internalVMFunctions->j9jni_createLocalRef((JNIEnv*)thread, (j9object_t)objectPointer);

return nextIndex;
}
Expand All @@ -135,7 +113,7 @@ J9::KnownObjectTable::getOrCreateIndexAt(uintptr_t *objectReferenceLocation)
#if defined(J9VM_OPT_JITSERVER)
if (self()->comp()->isOutOfProcessCompilation())
{
auto stream = TR::CompilationInfo::getStream();
auto stream = self()->comp()->getStream();
stream->write(JITServer::MessageType::KnownObjectTable_getOrCreateIndexAt, objectReferenceLocation);
auto recv = stream->read<TR::KnownObjectTable::Index, uintptr_t *>();

Expand Down Expand Up @@ -204,31 +182,49 @@ J9::KnownObjectTable::getPointer(Index index)
else
{
#if defined(J9VM_OPT_JITSERVER)
if (self()->comp()->isOutOfProcessCompilation())
{
TR_ASSERT_FATAL(false, "It is not safe to call getPointer() at the server. The object pointer could have become stale at the client.");
auto stream = TR::CompilationInfo::getStream();
stream->write(JITServer::MessageType::KnownObjectTable_getPointer, index);
return std::get<0>(stream->read<uintptr_t>());
}
else
TR_ASSERT_FATAL(!self()->comp()->isOutOfProcessCompilation(), "It is not safe to call getPointer() at the server. The object pointer could have become stale at the client.");
#endif /* defined(J9VM_OPT_JITSERVER) */
{
TR_J9VMBase *fej9 = (TR_J9VMBase *)(self()->fe());
TR_ASSERT(fej9->haveAccess(), "Must haveAccess in J9::KnownObjectTable::getPointer");
return *self()->getPointerLocation(index);
}
TR_J9VMBase *fej9 = (TR_J9VMBase *)(self()->fe());
TR_ASSERT(fej9->haveAccess(), "Must haveAccess in J9::KnownObjectTable::getPointer");
return *self()->getPointerLocation(index);
}
}


uintptr_t *
J9::KnownObjectTable::getPointerLocation(Index index)
{
TR_ASSERT(index != UNKNOWN && 0 <= index && index < _references.size(), "getPointerLocation(%d): index must be in range 0..%d", (int)index, _references.size());
return _references[index];
TR_ASSERT(index != UNKNOWN && 0 <= index && index < _objectInfos.size(), "getPointerLocation(%d): index must be in range 0..%d", (int)index, _objectInfos.size());
return _objectInfos[index]._jniReference;
}

void
J9::KnownObjectTable::setObjectInfoFields(Index index, const ObjectInfo& objInfoSource)
{
ObjectInfo &objInfo = _objectInfos[index];
TR_ASSERT_FATAL(objInfo._jniReference, "Index %d from known object table must have a valid jniReference", index);
TR_ASSERT_FATAL(objInfo._jniReference == objInfoSource._jniReference, "The _jniReference for source and destination do not match. Index=%d %p != %p", index, objInfo._jniReference, objInfoSource._jniReference);
objInfo = objInfoSource;
}

// Delete all the JNI references to the known objects tracked by the table
void
J9::KnownObjectTable::freeKnownObjectTable()
{
#if defined(J9VM_OPT_JITSERVER)
if (comp()->isOutOfProcessCompilation())
return;
#endif /* defined(J9VM_OPT_JITSERVER) */

TR_J9VMBase *fej9 = (TR_J9VMBase *)(self()->fe());
J9VMThread *thread = fej9->vmThread();
TR_ASSERT(thread, "assertion failure");

TR::VMAccessCriticalSection freeKnownObjectTable(fej9);
uint32_t nextIndex = self()->getEndIndex();
for (uint32_t i = 1; i < nextIndex; i++)
thread->javaVM->internalVMFunctions->j9jni_deleteLocalRef((JNIEnv*)thread, (jobject)_objectInfos.element(i)._jniReference);
}

#if defined(J9VM_OPT_JITSERVER)
void
Expand All @@ -244,15 +240,14 @@ J9::KnownObjectTable::updateKnownObjectTableAtServer(Index index, uintptr_t *obj

if (index == nextIndex)
{
_references.setSize(nextIndex+1);
_references[nextIndex] = objectReferenceLocationClient;
_objectInfos.setSize(nextIndex+1);
_objectInfos[nextIndex]._jniReference = objectReferenceLocationClient;
}
else if (index < nextIndex)
{
TR_ASSERT((objectReferenceLocationClient == _references[index]),
TR_ASSERT_FATAL((objectReferenceLocationClient == _objectInfos[index]._jniReference),
"comp %p: server _references[%d]=%p is not the same as the client _references[%d]=%p (total size = %u)",
self()->comp(), index, _references[index], index, objectReferenceLocationClient, nextIndex);
_references[index] = objectReferenceLocationClient;
self()->comp(), index, _objectInfos[index]._jniReference, index, objectReferenceLocationClient, nextIndex);
}
else
{
Expand Down Expand Up @@ -403,7 +398,7 @@ J9::KnownObjectTable::dumpTo(OMR::Logger *log, TR::Compilation *comp)
#if defined(J9VM_OPT_JITSERVER)
if (comp->isOutOfProcessCompilation())
{
auto stream = TR::CompilationInfo::getStream();
auto stream = comp->getStream();
stream->write(JITServer::MessageType::KnownObjectTable_getKnownObjectTableDumpInfo, JITServer::Void());

auto recv = stream->read<std::vector<TR_KnownObjectTableDumpInfo>>();
Expand Down
22 changes: 20 additions & 2 deletions runtime/compiler/env/J9KnownObjectTable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,25 @@ namespace J9

class OMR_EXTENSIBLE KnownObjectTable : public OMR::KnownObjectTableConnector
{
public:
// Note: the _jniReference field is always populated for a valid known object index.
// The other fields will be populated on demand. If _clazz is populated (non NULL),
// we expect the other fields to be populated too.
struct ObjectInfo
{
uintptr_t *_jniReference;
TR_OpaqueClassBlock *_clazz;
TR_OpaqueClassBlock *_jlClass;
bool _isFixedJavaLangClass;
bool _isString;
ObjectInfo() : _jniReference(NULL), _clazz(NULL), _jlClass(NULL), _isFixedJavaLangClass(false), _isString(false) {}
};
friend class ::TR_J9VMBase;
friend class Compilation;
TR_Array<uintptr_t*> _references;
private:
TR_Array<ObjectInfo> _objectInfos;
TR_Array<int32_t> _stableArrayRanks;


public:
TR_ALLOC(TR_Memory::FrontEnd);

Expand All @@ -106,6 +119,11 @@ class OMR_EXTENSIBLE KnownObjectTable : public OMR::KnownObjectTableConnector
Index getExistingIndexAt(uintptr_t *objectReferenceLocation);

uintptr_t getPointer(Index index);
struct ObjectInfo getObjectInfo(Index index) const { return _objectInfos[index]; }

void setObjectInfoFields(Index index, const ObjectInfo& objInfo);

void freeKnownObjectTable();

#if defined(J9VM_OPT_JITSERVER)
void updateKnownObjectTableAtServer(Index index, uintptr_t *objectReferenceLocationClient, bool isArrayWithConstantElements = false);
Expand Down
67 changes: 67 additions & 0 deletions runtime/compiler/env/VMJ9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,73 @@ TR_J9VMBase::getObjectClassInfoFromObjectReferenceLocation(TR::Compilation *comp
return ci;
}

TR::KnownObjectTable::ObjectInfo
TR_J9VMBase::getObjClassInfoFromKnotIndexNoCaching(TR::Compilation *comp, TR::KnownObjectTable::Index knotIndex)
{
TR::KnownObjectTable::ObjectInfo retrievedObjInfo;
TR::KnownObjectTable *knot = comp->getKnownObjectTable();
TR::KnownObjectTable::ObjectInfo existingObjInfo = knot->getObjectInfo(knotIndex);

// Retrieve the data from the VM
TR::VMAccessCriticalSection vmAccess(comp);

uintptr_t objectReference = knot->getPointer(knotIndex);
retrievedObjInfo._jniReference = existingObjInfo._jniReference;
retrievedObjInfo._clazz = getObjectClass(objectReference);
retrievedObjInfo._isString = isString(retrievedObjInfo._clazz);
retrievedObjInfo._jlClass = getClassClassPointer(retrievedObjInfo._clazz);
retrievedObjInfo._isFixedJavaLangClass = (retrievedObjInfo._jlClass == retrievedObjInfo._clazz);
if (retrievedObjInfo._isFixedJavaLangClass)
{
// A FixedClass constraint means something different
// when the class happens to be java/lang/Class.
// Must add constraints pertaining to the class that
// the java/lang/Class object represents.
retrievedObjInfo._clazz = getClassFromJavaLangClass(objectReference);
}
return retrievedObjInfo;
}

TR::KnownObjectTable::ObjectInfo
TR_J9VMBase::getObjClassInfoFromKnotIndex(TR::Compilation *comp, TR::KnownObjectTable::Index knotIndex)
{
TR::KnownObjectTable *knot = comp->getKnownObjectTable();
// Check to see whether the known object entry already holds the desired info.
// If so, return the cached version. Otherwise, fetch the info and cache it.
TR::KnownObjectTable::ObjectInfo existingObjInfo = knot->getObjectInfo(knotIndex);
TR::KnownObjectTable::ObjectInfo answerObjInfo;
TR_ASSERT_FATAL(existingObjInfo._jniReference, "The jniReference is missing for knotIndex %d", knotIndex);
if (comp->getOption(TR_DisableKnownObjectTableCaching))
{
answerObjInfo = getObjClassInfoFromKnotIndexNoCaching(comp, knotIndex);
}
else // Caching is enabled
{
if (existingObjInfo._clazz == NULL) // Not yet cached
{
answerObjInfo = getObjClassInfoFromKnotIndexNoCaching(comp, knotIndex);
knot->setObjectInfoFields(knotIndex, answerObjInfo); // populate cache
}
else // Reply with information from the cache
{
if (comp->getOption(TR_EnableKnownObjectTableCachingVerification))
{
TR::KnownObjectTable::ObjectInfo retrievedObjInfo = getObjClassInfoFromKnotIndexNoCaching(comp, knotIndex);
TR_ASSERT_FATAL(existingObjInfo._clazz == retrievedObjInfo._clazz, "_clazz discrepancy");
TR_ASSERT_FATAL(existingObjInfo._jlClass == retrievedObjInfo._jlClass, "_jlClazz discrepancy");
TR_ASSERT_FATAL(existingObjInfo._isString == retrievedObjInfo._isString, "_isString discrepancy");
TR_ASSERT_FATAL(existingObjInfo._isFixedJavaLangClass == retrievedObjInfo._isFixedJavaLangClass, "_isFixedJavaLangClass discrepancy");
TR_ASSERT_FATAL(existingObjInfo._jniReference == retrievedObjInfo._jniReference, "_jniReference discrepancy");
}
answerObjInfo = existingObjInfo;
}
}

J9::ConstProvenanceGraph *cpg = comp->constProvenanceGraph();
cpg->addEdge(cpg->knownObject(knotIndex), answerObjInfo._clazz);
return answerObjInfo;
}

uintptr_t
TR_J9VMBase::getReferenceFieldAtAddress(uintptr_t fieldAddress)
{
Expand Down
Loading