diff --git a/runtime/compiler/control/JITClientCompilationThread.cpp b/runtime/compiler/control/JITClientCompilationThread.cpp index 7e9eb1ce332..5f0ae628a19 100644 --- a/runtime/compiler/control/JITClientCompilationThread.cpp +++ b/runtime/compiler/control/JITClientCompilationThread.cpp @@ -2958,6 +2958,52 @@ handleServerMessage(JITServer::ClientStream *client, TR_J9VM *fe, JITServer::Mes client->write(response, vectorBitSize); } break; + case MessageType::KnownObjectTable_addFieldAddressFromBaseIndex: + { + auto recv = client->getRecvData(); + TR::KnownObjectTable::Index baseObjectIndex = std::get<0>(recv); + intptr_t fieldOffset = std::get<1>(recv); + bool isArrayWithConstantElements = std::get<2>(recv); + + TR::KnownObjectTable::Index resultIndex = TR::KnownObjectTable::UNKNOWN; + + { + TR::VMAccessCriticalSection addFieldAddressFromBaseIndex(fe); + uintptr_t baseObjectAddress = knot->getPointer(baseObjectIndex); + uintptr_t fieldAddress = baseObjectAddress + fieldOffset; + + uintptr_t objectPointer = fe->getReferenceFieldAtAddress(fieldAddress); + + if (objectPointer) + resultIndex = knot->getOrCreateIndexAt(&objectPointer, isArrayWithConstantElements); + } + + uintptr_t *resultPointer = (resultIndex == TR::KnownObjectTable::UNKNOWN) ? + NULL : knot->getPointerLocation(resultIndex); + + client->write(response, resultIndex, resultPointer); + } + break; + case MessageType::KnownObjectTable_getFieldAddressData: + { + auto recv = client->getRecvData(); + TR::KnownObjectTable::Index baseObjectIndex = std::get<0>(recv); + intptr_t fieldOffset = std::get<1>(recv); + + J9::TransformUtil::value data; + + { + TR::VMAccessCriticalSection addFieldAddressFromBaseIndex(fe); + uintptr_t baseObjectAddress = knot->getPointer(baseObjectIndex); + + uintptr_t fieldAddress = baseObjectAddress + fieldOffset; + + data = *(J9::TransformUtil::value *) fieldAddress; + } + + client->write(response, data); + } + break; case MessageType::AOTCache_getROMClassBatch: { auto recv = client->getRecvData>(); diff --git a/runtime/compiler/env/J9KnownObjectTable.cpp b/runtime/compiler/env/J9KnownObjectTable.cpp index 204dce6484b..4a123bd9c86 100644 --- a/runtime/compiler/env/J9KnownObjectTable.cpp +++ b/runtime/compiler/env/J9KnownObjectTable.cpp @@ -230,7 +230,7 @@ J9::KnownObjectTable::getPointerLocation(Index index) #if defined(J9VM_OPT_JITSERVER) void -J9::KnownObjectTable::updateKnownObjectTableAtServer(Index index, uintptr_t *objectReferenceLocationClient) +J9::KnownObjectTable::updateKnownObjectTableAtServer(Index index, uintptr_t *objectReferenceLocationClient, bool isArrayWithConstantElements) { TR_ASSERT_FATAL(self()->comp()->isOutOfProcessCompilation(), "updateKnownObjectTableAtServer should only be called at the server"); if (index == TR::KnownObjectTable::UNKNOWN) @@ -256,6 +256,9 @@ J9::KnownObjectTable::updateKnownObjectTableAtServer(Index index, uintptr_t *obj { TR_ASSERT_FATAL(false, "index %d from the client is greater than the KOT nextIndex %d at the server", index, nextIndex); } + + if (isArrayWithConstantElements) + addArrayWithConstantElements(index); } #endif /* defined(J9VM_OPT_JITSERVER) */ diff --git a/runtime/compiler/env/J9KnownObjectTable.hpp b/runtime/compiler/env/J9KnownObjectTable.hpp index 5ab5149c705..cf73f25907b 100644 --- a/runtime/compiler/env/J9KnownObjectTable.hpp +++ b/runtime/compiler/env/J9KnownObjectTable.hpp @@ -107,7 +107,7 @@ class OMR_EXTENSIBLE KnownObjectTable : public OMR::KnownObjectTableConnector uintptr_t getPointer(Index index); #if defined(J9VM_OPT_JITSERVER) - void updateKnownObjectTableAtServer(Index index, uintptr_t *objectReferenceLocationClient); + void updateKnownObjectTableAtServer(Index index, uintptr_t *objectReferenceLocationClient, bool isArrayWithConstantElements = false); void getKnownObjectTableDumpInfo(std::vector &knotDumpInfoList); #endif /* defined(J9VM_OPT_JITSERVER) */ diff --git a/runtime/compiler/env/VMJ9Server.hpp b/runtime/compiler/env/VMJ9Server.hpp index 966d91e0193..544a9c704b2 100644 --- a/runtime/compiler/env/VMJ9Server.hpp +++ b/runtime/compiler/env/VMJ9Server.hpp @@ -210,7 +210,8 @@ class TR_J9ServerVM: public TR_J9VM virtual intptr_t getVFTEntry(TR_OpaqueClassBlock *clazz, int32_t offset) override; virtual bool isClassArray(TR_OpaqueClassBlock *klass) override; virtual uintptr_t getFieldOffset(TR::Compilation * comp, TR::SymbolReference* classRef, TR::SymbolReference* fieldRef) override { return 0; } // safe answer - virtual bool canDereferenceAtCompileTime(TR::SymbolReference *fieldRef, TR::Compilation *comp) override { return false; } // safe answer, might change in the future +// The base version should be safe, no need to override. +// virtual bool canDereferenceAtCompileTime(TR::SymbolReference *fieldRef, TR::Compilation *comp) override; // safe answer, might change in the future virtual bool instanceOfOrCheckCast(J9Class *instanceClass, J9Class* castClass) override; virtual bool instanceOfOrCheckCastNoCacheUpdate(J9Class *instanceClass, J9Class* castClass) override; virtual bool transformJlrMethodInvoke(J9Method *callerMethod, J9Class *callerClass) override; diff --git a/runtime/compiler/net/CommunicationStream.hpp b/runtime/compiler/net/CommunicationStream.hpp index b637e190665..eca531df600 100644 --- a/runtime/compiler/net/CommunicationStream.hpp +++ b/runtime/compiler/net/CommunicationStream.hpp @@ -129,7 +129,7 @@ class CommunicationStream // likely to lose an increment when merging/rebasing/etc. // static const uint8_t MAJOR_NUMBER = 1; - static const uint16_t MINOR_NUMBER = 75; // ID: kzkyjklaOnYjEzzJyIl7 + static const uint16_t MINOR_NUMBER = 76; // ID: BpR0Syhau116Bh0vAoVr static const uint8_t PATCH_NUMBER = 0; static uint32_t CONFIGURATION_FLAGS; diff --git a/runtime/compiler/net/MessageTypes.cpp b/runtime/compiler/net/MessageTypes.cpp index 36cb325a2ef..4715a258704 100644 --- a/runtime/compiler/net/MessageTypes.cpp +++ b/runtime/compiler/net/MessageTypes.cpp @@ -263,6 +263,8 @@ const char *messageNames[] = "KnownObjectTable_getKnownObjectTableDumpInfo", "KnownObjectTable_getOpaqueClass", "KnownObjectTable_getVectorBitSize", + "KnownObjectTable_addFieldAddressFromBaseIndex", + "KnownObjectTable_getFieldAddressData", "AOTCache_getROMClassBatch", "AOTCacheMap_request", "AOTCacheMap_reply" diff --git a/runtime/compiler/net/MessageTypes.hpp b/runtime/compiler/net/MessageTypes.hpp index 8cdceb317b1..f90e791aa93 100644 --- a/runtime/compiler/net/MessageTypes.hpp +++ b/runtime/compiler/net/MessageTypes.hpp @@ -290,6 +290,9 @@ enum MessageType : uint16_t KnownObjectTable_getOpaqueClass, // for getting a vectorBitSize from KnownObjectTable KnownObjectTable_getVectorBitSize, + // used with J9TransformUtil + KnownObjectTable_addFieldAddressFromBaseIndex, + KnownObjectTable_getFieldAddressData, AOTCache_getROMClassBatch, diff --git a/runtime/compiler/optimizer/J9TransformUtil.cpp b/runtime/compiler/optimizer/J9TransformUtil.cpp index 80c07d0e656..0469173fabd 100644 --- a/runtime/compiler/optimizer/J9TransformUtil.cpp +++ b/runtime/compiler/optimizer/J9TransformUtil.cpp @@ -660,6 +660,140 @@ static void *dereferenceStructPointerChain(void *baseStruct, TR::Node *baseNode, return NULL; } +#if defined(J9VM_OPT_JITSERVER) +/** + * Mimics dereferenceStructPointerChain to dereference an indirect load, but only for the first + * level of the chain; executed from the JITServer only + */ +static void *dereferenceStructPointer(TR::KnownObjectTable::Index baseKnownObject, + TR::Node *node, + TR::Node *baseExpression, + bool isBaseStableArray, + TR::Compilation *comp, + J9::TransformUtil::value *valuePtr) + { + TR_ASSERT(comp->isOutOfProcessCompilation(), "must be executed from the jitserver"); + + if (node == baseExpression) + { + TR_ASSERT(false, "dereferenceStructPointerChain has no idea what to dereference"); + traceMsg(comp, "Caller has already dereferenced node %p, returning NULL as dereferenceStructPointerChain has no idea what to dereference\n", node); + return NULL; + } + TR_ASSERT(node != NULL, "Field node is NULL"); + TR_ASSERT(node->getOpCode().hasSymbolReference(), "Node must have a symref"); + + TR_J9VMBase *fej9 = comp->fej9(); + TR::SymbolReference *symRef = node->getSymbolReference(); + TR::Symbol *field = symRef->getSymbol(); + + TR::Node *addressChildNode = field->isArrayShadowSymbol() ? + node->getFirstChild()->getFirstChild() : + node->getFirstChild(); + // Abort if the indirection is more than a single level. + if (!addressChildNode->getOpCode().hasSymbolReference() + || addressChildNode != baseExpression) + return NULL; + + // We only consider the case where isJavaField is true for verifyFieldAccess + if (isJavaField(symRef, comp)) + { + TR_OpaqueClassBlock *fieldClass = NULL; + + if (symRef->getCPIndex() < 0 && + field->getRecognizedField() != TR::Symbol::UnknownField) + { + const char* className; + int32_t length; + className = field->owningClassNameCharsForRecognizedField(length); + fieldClass = fej9->getClassFromSignature(className, length, symRef->getOwningMethod(comp)); + } + else + fieldClass = symRef->getOwningMethod(comp)->getDeclaringClassFromFieldOrStatic(comp, + symRef->getCPIndex()); + + if (fieldClass == NULL) + return NULL; + + TR_OpaqueClassBlock *objectClass = + fej9->getObjectClassFromKnownObjectIndex(comp, baseKnownObject); + + // field access verified + if (fej9->isInstanceOf(objectClass, fieldClass, true) == TR_yes) + { + // Mimic avoidFoldingInstanceField by exiting in all cases where the method returns true: + // We should avoid folding instance field if: + // 1. the content of the fieldAddress is null; this is checked when we load the values + // 2. the field is of one of the two types below + if (field->getRecognizedField() == TR::Symbol::Java_lang_invoke_CallSite_target || + field->getRecognizedField() == TR::Symbol::Java_lang_invoke_MethodHandle_form) + return NULL; + + TR::DataType loadType = node->getDataType(); + + switch (loadType) + { + case TR::Int32: + case TR::Int64: + case TR::Float: + case TR::Double: + { + // not address + auto stream = comp->getStream(); + stream->write(JITServer::MessageType::KnownObjectTable_getFieldAddressData, + baseKnownObject, symRef->getOffset()); + J9::TransformUtil::value value = std::get<0>(stream->read()); + *valuePtr = value; + + // Do the null check part of avoidFoldingConstantField + // We do not have to worry about the case of address; the returned knot index will + // be UNKNOWN in that case + if (isNullValueAtAddress(comp, loadType, (uintptr_t) valuePtr, field)) + return NULL; + + return valuePtr; + } + break; + case TR::Address: + { + if (isFinalFieldPointingAtRepresentableNativeStruct(symRef, comp) || + isFinalFieldPointingAtNativeStruct(symRef, comp)) + { + return NULL; + } + else if (field->isCollectedReference()) + { + bool isArray = isArrayWithConstantElements(symRef, comp); + auto stream = comp->getStream(); + stream->write( + JITServer::MessageType::KnownObjectTable_addFieldAddressFromBaseIndex, + baseKnownObject, + symRef->getOffset(), + isArray + ); + auto recv = stream->read(); + TR::KnownObjectTable::Index value = std::get<0>(recv); + uintptr_t *objectReferenceLocationClient = std::get<1>(recv); + comp->getKnownObjectTable()->updateKnownObjectTableAtServer( + value, + objectReferenceLocationClient, + isArray + ); + valuePtr->idx = value; + return valuePtr; + } + } + break; + default: + return NULL; + } + } + } + return NULL; + } +#endif /* defined(J9VM_OPT_JITSERVER) */ + + bool J9::TransformUtil::foldFinalFieldsIn(TR_OpaqueClassBlock *clazz, const char *className, int32_t classNameLength, bool isStatic, TR::Compilation *comp) { TR::SimpleRegex *classRegex = comp->getOptions()->getClassesWithFoldableFinalFields(); @@ -1701,7 +1835,10 @@ J9::TransformUtil::transformIndirectLoadChainAt(TR::Compilation *comp, TR::Node { baseAddress = *baseReferenceLocation; } - bool result = TR::TransformUtil::transformIndirectLoadChainImpl(comp, node, baseExpression, (void*)baseAddress, 0, removedNode); + bool result = TR::TransformUtil::transformIndirectLoadChainImpl(comp, node, baseExpression, + TR::KnownObjectTable::UNKNOWN, + (void *)baseAddress, + 0, removedNode); return result; } @@ -1716,20 +1853,27 @@ J9::TransformUtil::transformIndirectLoadChainAt(TR::Compilation *comp, TR::Node bool J9::TransformUtil::transformIndirectLoadChain(TR::Compilation *comp, TR::Node *node, TR::Node *baseExpression, TR::KnownObjectTable::Index baseKnownObject, TR::Node **removedNode) { + int32_t stableArrayRank = comp->getKnownObjectTable()->getArrayWithStableElementsRank(baseKnownObject); + bool result = false; + #if defined(J9VM_OPT_JITSERVER) - // JITServer KOT: Bypass this method at the JITServer. - // transformIndirectLoadChainImpl requires access to the VM. - // It is already bypassed by transformIndirectLoadChainAt(). if (comp->isOutOfProcessCompilation()) { - return false; + // In the JITServer, pass in the Knot Index rather than the address + result = TR::TransformUtil::transformIndirectLoadChainImpl(comp, node, baseExpression, + baseKnownObject, NULL, stableArrayRank, removedNode); } + else #endif /* defined(J9VM_OPT_JITSERVER) */ + { + TR::VMAccessCriticalSection transformIndirectLoadChain(comp->fej9()); + result = TR::TransformUtil::transformIndirectLoadChainImpl( + comp, node, baseExpression, TR::KnownObjectTable::UNKNOWN, + (void*)comp->getKnownObjectTable()->getPointer(baseKnownObject), + stableArrayRank, removedNode + ); + } - TR::VMAccessCriticalSection transformIndirectLoadChain(comp->fej9()); - int32_t stableArrayRank = comp->getKnownObjectTable()->getArrayWithStableElementsRank(baseKnownObject); - - bool result = TR::TransformUtil::transformIndirectLoadChainImpl(comp, node, baseExpression, (void*)comp->getKnownObjectTable()->getPointer(baseKnownObject), stableArrayRank, removedNode); return result; } @@ -1738,7 +1882,8 @@ J9::TransformUtil::transformIndirectLoadChain(TR::Compilation *comp, TR::Node *n * @parm comp The compilation object * @parm node The node to be folded * @parm baseExpression The start of the indirect load chain - * @parm baseAddress Value of baseExpression + * @parm baseKnownObject KnownObjectTable index containing the value of the base expression + * @parm baseAddress The value of the base expression * @parm removedNode Pointer to the removed node if removal happens * * @return true if the load chain has been folded, false otherwise @@ -1797,17 +1942,37 @@ J9::TransformUtil::transformIndirectLoadChain(TR::Compilation *comp, TR::Node *n * */ bool -J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, TR::Node *node, TR::Node *baseExpression, void *baseAddress, int32_t baseStableArrayRank, TR::Node **removedNode) +J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, + TR::Node *node, TR::Node *baseExpression, + TR::KnownObjectTable::Index baseKnownObject, + void *baseAddress, + int32_t baseStableArrayRank, + TR::Node **removedNode) { - bool isBaseStableArray = baseStableArrayRank > 0; +#if defined(J9VM_OPT_JITSERVER) + bool isServer = comp->isOutOfProcessCompilation(); + + // baseKnownObject is used only for jitserver, otherwise we use baseAddress + if (isServer) + TR_ASSERT(baseKnownObject != TR::KnownObjectTable::UNKNOWN, + "invalid baseKnownObject in jitserver"); + else +#endif /* defined(J9VM_OPT_JITSERVER) */ + { + TR_ASSERT(TR::Compiler->vm.hasAccess(comp), + "transformIndirectLoadChain requires VM access for non-JITServer mode"); + TR_ASSERT(baseAddress, "invalid base address"); + } + + bool isBaseStableArray = baseStableArrayRank > 0; TR_J9VMBase *fej9 = comp->fej9(); -#if defined(J9VM_OPT_JITSERVER) - TR_ASSERT_FATAL(!comp->isOutOfProcessCompilation(), "It's not safe to call transformIndirectLoadChainImpl() in JITServer mode"); -#endif - TR_ASSERT(TR::Compiler->vm.hasAccess(comp), "transformIndirectLoadChain requires VM access"); - TR_ASSERT(node->getOpCode().isLoadIndirect(), "Expecting indirect load; found %s %p", node->getOpCode().getName(), node); - TR_ASSERT(node->getNumChildren() == 1, "Expecting indirect load %s %p to have one child; actually has %d", node->getOpCode().getName(), node, node->getNumChildren()); + + TR_ASSERT(node->getOpCode().isLoadIndirect(), "Expecting indirect load; found %s %p", + node->getOpCode().getName(), node); + TR_ASSERT(node->getNumChildren() == 1, + "Expecting indirect load %s %p to have one child; actually has %d", + node->getOpCode().getName(), node, node->getNumChildren()); if (comp->compileRelocatableCode()) { @@ -1823,31 +1988,44 @@ J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, TR::Nod return false; // Fold initializeStatus field in J9Class whose finality is conditional on the value it is holding - if (!symRef->isUnresolved() && symRef == comp->getSymRefTab()->findInitializeStatusFromClassSymbolRef()) + if (!symRef->isUnresolved() + && symRef == comp->getSymRefTab()->findInitializeStatusFromClassSymbolRef()) { - J9Class* clazz = (J9Class*)baseAddress; - traceMsg(comp, "Looking at node %p with initializeStatusFromClassSymbol, class %p initialize status is %d\n", node, clazz, clazz->initializeStatus); - // Only fold the load if the class has been initialized - if (fej9->isClassInitialized((TR_OpaqueClassBlock *) clazz) == J9ClassInitSucceeded) +#if defined(J9VM_OPT_JITSERVER) + if (isServer) { - if (node->getDataType() == TR::Int32) + return false; + } + else +#endif /* defined(J9VM_OPT_JITSERVER) */ + { + J9Class* clazz = (J9Class*) baseAddress; + traceMsg(comp, + "Looking at node %p with initializeStatusFromClassSymbol," + " class %p initialize status is %d\n", + node, clazz, clazz->initializeStatus); + // Only fold the load if the class has been initialized + if (fej9->isClassInitialized((TR_OpaqueClassBlock *) clazz) == J9ClassInitSucceeded) { - if (changeIndirectLoadIntoConst(node, TR::iconst, removedNode, comp)) - node->setInt(J9ClassInitSucceeded); + if (node->getDataType() == TR::Int32) + { + if (changeIndirectLoadIntoConst(node, TR::iconst, removedNode, comp)) + node->setInt(J9ClassInitSucceeded); + else + return false; + } else - return false; + { + if (changeIndirectLoadIntoConst(node, TR::lconst, removedNode, comp)) + node->setLongInt(J9ClassInitSucceeded); + else + return false; + } + return true; } else - { - if (changeIndirectLoadIntoConst(node, TR::lconst, removedNode, comp)) - node->setLongInt(J9ClassInitSucceeded); - else - return false; - } - return true; + return false; } - else - return false; } if (!isBaseStableArray && !fej9->canDereferenceAtCompileTime(symRef, comp)) @@ -1859,15 +2037,34 @@ J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, TR::Nod return false; } - // Dereference the chain starting from baseAddress and get the field address - void *fieldAddress = dereferenceStructPointerChain(baseAddress, baseExpression, isBaseStableArray, node, comp); - if (!fieldAddress) + void *valuePtr; + J9::TransformUtil::value value; +#if defined(J9VM_OPT_JITSERVER) + if (isServer) + { + // Instead of the recursive dereferenceStructPointerChain, we only consider a single level + // of indirection + void *result = dereferenceStructPointer(baseKnownObject, node, baseExpression, + isBaseStableArray, comp, &value); + valuePtr = &value; + if (result != valuePtr) + return false; + } + else // not jitserver +#endif /* defined(J9VM_OPT_JITSERVER) */ { - if (comp->getOption(TR_TraceOptDetails)) + // Dereference the chain starting from baseAddress and get the field address + void *fieldAddress = dereferenceStructPointerChain(baseAddress, baseExpression, + isBaseStableArray, node, comp); + if (!fieldAddress) { - traceMsg(comp, "Abort transformIndirectLoadChain - cannot verify/dereference field access to %s in %p!\n", symRef->getName(comp->getDebug()), baseAddress); + if (comp->getOption(TR_TraceOptDetails)) + { + traceMsg(comp, "Abort transformIndirectLoadChain - cannot verify/dereference field access to %s in %p!\n", symRef->getName(comp->getDebug()), baseAddress); + } + return false; } - return false; + valuePtr = fieldAddress; } // The last step in the dereference chain is not necessarily an address. @@ -1881,7 +2078,7 @@ J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, TR::Nod { case TR::Int32: { - int32_t value = *(int32_t*)fieldAddress; + int32_t value = *(int32_t*)valuePtr; if (changeIndirectLoadIntoConst(node, TR::iconst, removedNode, comp)) node->setInt(value); else @@ -1890,7 +2087,7 @@ J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, TR::Nod break; case TR::Int64: { - int64_t value = *(int64_t*)fieldAddress; + int64_t value = *(int64_t*)valuePtr; if (changeIndirectLoadIntoConst(node, TR::lconst, removedNode, comp)) node->setLongInt(value); else @@ -1899,7 +2096,7 @@ J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, TR::Nod break; case TR::Float: { - float value = *(float*)fieldAddress; + float value = *(float*)valuePtr; if (changeIndirectLoadIntoConst(node, TR::fconst, removedNode, comp)) node->setFloat(value); else @@ -1908,7 +2105,7 @@ J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, TR::Nod break; case TR::Double: { - double value = *(double*)fieldAddress; + double value = *(double*)valuePtr; if (changeIndirectLoadIntoConst(node, TR::dconst, removedNode, comp)) node->setDouble(value); else @@ -1919,11 +2116,15 @@ J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, TR::Nod { if (isFinalFieldPointingAtRepresentableNativeStruct(symRef, comp)) { +#if defined(J9VM_OPT_JITSERVER) + if (isServer) + return false; +#endif /* defined(J9VM_OPT_JITSERVER) */ if (fej9->isFinalFieldPointingAtJ9Class(symRef, comp)) { if (changeIndirectLoadIntoConst(node, TR::loadaddr, removedNode, comp)) { - TR_OpaqueClassBlock *value = *(TR_OpaqueClassBlock**)fieldAddress; + TR_OpaqueClassBlock *value = *(TR_OpaqueClassBlock**)valuePtr; node->setSymbolReference(comp->getSymRefTab()->findOrCreateClassSymbol(comp->getMethodSymbol(), -1, value)); } else @@ -1940,9 +2141,13 @@ J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, TR::Nod } else if (isFinalFieldPointingAtNativeStruct(symRef, comp)) { +#if defined(J9VM_OPT_JITSERVER) + if (isServer) + return false; +#endif /* defined(J9VM_OPT_JITSERVER) */ if (symRef->getReferenceNumber() - comp->getSymRefTab()->getNumHelperSymbols() == TR::SymbolReferenceTable::ramStaticsFromClassSymbol) { - uintptr_t value = *(uintptr_t*)fieldAddress; + uintptr_t value = *(uintptr_t*)valuePtr; if (changeIndirectLoadIntoConst(node, TR::aconst, removedNode, comp)) { node->setAddress(value); @@ -1957,10 +2162,24 @@ J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, TR::Nod } else if (symRef->getSymbol()->isCollectedReference()) { - uintptr_t value = fej9->getReferenceFieldAtAddress((uintptr_t)fieldAddress); - if (value) + TR::KnownObjectTable::Index knotIndex = TR::KnownObjectTable::UNKNOWN; +#if defined(J9VM_OPT_JITSERVER) + if (isServer) + { + knotIndex = ((J9::TransformUtil::value *)valuePtr)->idx; + } + else +#endif /* defined(J9VM_OPT_JITSERVER) */ + { + uintptr_t value = fej9->getReferenceFieldAtAddress((uintptr_t)valuePtr); + knotIndex = comp->getKnownObjectTable()->getOrCreateIndexAt(&value, + isArrayWithConstantElements(symRef, comp)); + } + + if (knotIndex != TR::KnownObjectTable::UNKNOWN) { - TR::SymbolReference *improvedSymRef = comp->getSymRefTab()->findOrCreateSymRefWithKnownObject(symRef, &value, isArrayWithConstantElements(symRef, comp)); + TR::SymbolReference *improvedSymRef = + comp->getSymRefTab()->findOrCreateSymRefWithKnownObject(symRef, knotIndex); if (improvedSymRef->hasKnownObjectIndex() && performTransformation(comp, "O^O transformIndirectLoadChain: %s [%p] with fieldOffset %d is obj%d referenceAddr is %p\n", node->getOpCode().getName(), node, improvedSymRef->getKnownObjectIndex(), symRef->getOffset(), value)) @@ -1970,8 +2189,8 @@ J9::TransformUtil::transformIndirectLoadChainImpl(TR::Compilation *comp, TR::Nod node->setIsNonNull(true); int32_t stableArrayRank = isArrayWithStableElements(symRef->getCPIndex(), - symRef->getOwningMethod(comp), - comp); + symRef->getOwningMethod(comp), + comp); if (isBaseStableArray) stableArrayRank = baseStableArrayRank - 1; diff --git a/runtime/compiler/optimizer/J9TransformUtil.hpp b/runtime/compiler/optimizer/J9TransformUtil.hpp index f3ac986ba94..ecd039960ff 100644 --- a/runtime/compiler/optimizer/J9TransformUtil.hpp +++ b/runtime/compiler/optimizer/J9TransformUtil.hpp @@ -220,9 +220,18 @@ class OMR_EXTENSIBLE TransformUtil : public OMR::TransformUtilConnector TR_ResolvedMethod *owningMethod, int32_t cpIndex); + union value{ + int32_t i; + int64_t l; + float f; + double d; + void *p; + TR::KnownObjectTable::Index idx; + }; + static bool transformIndirectLoadChain(TR::Compilation *, TR::Node *node, TR::Node *baseExpression, TR::KnownObjectTable::Index baseKnownObject, TR::Node **removedNode); static bool transformIndirectLoadChainAt(TR::Compilation *, TR::Node *node, TR::Node *baseExpression, uintptr_t *baseReferenceLocation, TR::Node **removedNode); - static bool transformIndirectLoadChainImpl( TR::Compilation *, TR::Node *node, TR::Node *baseExpression, void *baseAddress, int32_t baseStableArrayRank, TR::Node **removedNode); + static bool transformIndirectLoadChainImpl( TR::Compilation *, TR::Node *node, TR::Node *baseExpression, TR::KnownObjectTable::Index baseKnownObject, void *baseAddress, int32_t baseStableArrayRank, TR::Node **removedNode); static bool fieldShouldBeCompressed(TR::Node *node, TR::Compilation *comp);