diff --git a/runtime/compiler/codegen/J9CodeGenerator.cpp b/runtime/compiler/codegen/J9CodeGenerator.cpp index 80ec0fcbc6e..96d6bb29c3e 100644 --- a/runtime/compiler/codegen/J9CodeGenerator.cpp +++ b/runtime/compiler/codegen/J9CodeGenerator.cpp @@ -78,7 +78,7 @@ J9::CodeGenerator::CodeGenerator() : _liveMonitors(NULL), _nodesSpineCheckedList(getTypedAllocator(TR::comp()->allocator())), _jniCallSites(getTypedAllocator *>(TR::comp()->allocator())), - _monitorMapping(self()->comp()->trMemory(), 256), + _monitorMapping(MonitorTypeMap(std::less(), MonitorMapAllocator(self()->comp()->trMemory()->heapMemoryRegion()))), _dummyTempStorageRefNode(NULL) { } @@ -1089,10 +1089,9 @@ J9::CodeGenerator::lowerTreeIfNeeded( TR_OpaqueClassBlock * monClass = node->getMonitorClass(self()->comp()->getCurrentMethod()); if (monClass) self()->addMonClass(node, monClass); - - // Clear the hidden second child that may be used by code generation - // - node->setMonitorInfo(0); + else if (node->isMonitorIdentityType()) + self()->addMonClass(node, (TR_OpaqueClassBlock* )IDENTITY_CLASS_PLACEHOLDER); + node->setMonitorInfoInNode(NULL); } @@ -4999,15 +4998,25 @@ J9::CodeGenerator::generatePoisonNode(TR::Block *currentBlock, TR::SymbolReferen void J9::CodeGenerator::addMonClass(TR::Node* monNode, TR_OpaqueClassBlock* clazz) { - _monitorMapping.add(monNode); - _monitorMapping.add(clazz); + _monitorMapping[monNode->getGlobalIndex()] = clazz; } TR_OpaqueClassBlock * J9::CodeGenerator::getMonClass(TR::Node* monNode) { - for (int i = 0; i < _monitorMapping.size(); i += 2) - if (_monitorMapping[i] == monNode) - return (TR_OpaqueClassBlock *) _monitorMapping[i+1]; - return 0; + if (_monitorMapping.find(monNode->getGlobalIndex()) == _monitorMapping.end()) + return NULL; + TR_OpaqueClassBlock * clazz = (TR_OpaqueClassBlock *) _monitorMapping[monNode->getGlobalIndex()]; + return clazz != (TR_OpaqueClassBlock*) IDENTITY_CLASS_PLACEHOLDER? clazz: NULL; + } + +TR_YesNoMaybe +J9::CodeGenerator::isMonitorValueType(TR::Node* monNode) + { + if (_monitorMapping.find(monNode->getGlobalIndex()) == _monitorMapping.end()) + return TR_maybe; + TR_OpaqueClassBlock *clazz = _monitorMapping[monNode->getGlobalIndex()]; + if (clazz != (TR_OpaqueClassBlock *) IDENTITY_CLASS_PLACEHOLDER && TR::Compiler->cls.isValueTypeClass(clazz)) + return TR_yes; + return TR_no; } diff --git a/runtime/compiler/codegen/J9CodeGenerator.hpp b/runtime/compiler/codegen/J9CodeGenerator.hpp index a86a773fc37..77ca5c85282 100644 --- a/runtime/compiler/codegen/J9CodeGenerator.hpp +++ b/runtime/compiler/codegen/J9CodeGenerator.hpp @@ -300,21 +300,41 @@ class OMR_EXTENSIBLE CodeGenerator : public OMR::CodeGeneratorConnector TR_BitVector *setLiveMonitors(TR_BitVector *v) {return (_liveMonitors = v);} public: + /* + * \brief + * Get the class or the superclass of the monitor object. + * + * \note + * java.lang.Object is only returned when the monitor object is of type java.lang.Object but not any subclasses + */ + TR_OpaqueClassBlock* getMonClass(TR::Node* monNode); -TR_OpaqueClassBlock* getMonClass(TR::Node* monNode); + /* + * \brief + * whether a monitor object is of value type + * + * \return + * TR_yes The monitor object is definitely value type + * TR_no The monitor object is definitely identity type + * TR_maybe It is unknown whether the monitor object is identity type or value type + */ + TR_YesNoMaybe isMonitorValueType(TR::Node* monNode); protected: -TR_Array _monitorMapping; +typedef TR::typed_allocator, TR::Region &> MonitorMapAllocator; +typedef std::map, MonitorMapAllocator> MonitorTypeMap; + +MonitorTypeMap _monitorMapping; // map global node index to monitor object class void addMonClass(TR::Node* monNode, TR_OpaqueClassBlock* clazz); private: TR_HashTabInt _uncommonedNodes; // uncommoned nodes keyed by the original nodes - + TR::list _nodesSpineCheckedList; - + TR::list *> _jniCallSites; // list of instrutions representing direct jni call sites uint16_t changeParmLoadsToRegLoads(TR::Node*node, TR::Node **regLoads, TR_BitVector *globalRegsWithRegLoad, TR_BitVector &killedParms, vcount_t visitCount); // returns number of RegLoad nodes created @@ -393,11 +413,11 @@ void addMonClass(TR::Node* monNode, TR_OpaqueClassBlock* clazz); void setSupportsBigDecimalLongLookasideVersioning() { _flags3.set(SupportsBigDecimalLongLookasideVersioning);} bool constLoadNeedsLiteralFromPool(TR::Node *node) { return false; } - + // Java, likely Z bool supportsTrapsInTMRegion() { return true; } - // J9 + // J9 int32_t getInternalPtrMapBit() { return 31;} // -------------------------------------------------------------------------- @@ -536,7 +556,7 @@ void addMonClass(TR::Node* monNode, TR_OpaqueClassBlock* clazz); TR::Node *generatePoisonNode( TR::Block *currentBlock, TR::SymbolReference *liveAutoSymRef); - + /** * \brief Determines whether VM Internal Natives is supported or not @@ -553,7 +573,7 @@ void addMonClass(TR::Node* monNode, TR_OpaqueClassBlock* clazz); SupportsInlineStringIndexOf = 0x00000008, /*! codegen inlining of Java string index of */ SupportsInlineStringHashCode = 0x00000010, /*! codegen inlining of Java string hash code */ SupportsInlineConcurrentLinkedQueue = 0x00000020, - SupportsBigDecimalLongLookasideVersioning = 0x00000040, + SupportsBigDecimalLongLookasideVersioning = 0x00000040, }; flags32_t _j9Flags; diff --git a/runtime/compiler/x/codegen/J9TreeEvaluator.cpp b/runtime/compiler/x/codegen/J9TreeEvaluator.cpp index 95c275ff1d7..84d4d6c21af 100644 --- a/runtime/compiler/x/codegen/J9TreeEvaluator.cpp +++ b/runtime/compiler/x/codegen/J9TreeEvaluator.cpp @@ -132,14 +132,17 @@ inline void generateLoadJ9Class(TR::Node* node, TR::Register* j9class, TR::Regis switch (opValue) { case TR::checkcastAndNULLCHK: + case TR::monent: + case TR::monexit: needsNULLCHK = true; break; case TR::icall: // TR_checkAssignable return; // j9class register already holds j9class + case TR::checkcast: + case TR::instanceof: + break; default: - TR_ASSERT(opValue == TR::checkcast || - opValue == TR::instanceof, - "Unexpected opCode for generateLoadJ9Class %s.", node->getOpCode().getName()); + TR_ASSERT(false, "Unexpected opCode for generateLoadJ9Class %s.", node->getOpCode().getName()); break; } } @@ -1868,7 +1871,7 @@ TR::Register *J9::X86::TreeEvaluator::evaluateNULLCHKWithPossibleResolve( { needExplicitCheck = false; TR::MemoryReference *memRef = NULL; - if (TR::Compiler->om.compressedReferenceShift() > 0 + if (TR::Compiler->om.compressedReferenceShift() > 0 && firstChild->getType() == TR::Address && firstChild->getOpCode().hasSymbolReference() && firstChild->getSymbol()->isCollectedReference()) @@ -4508,6 +4511,25 @@ void J9::X86::TreeEvaluator::transactionalMemoryJITMonitorEntry(TR::Node cg->stopUsingRegister(counterReg); } +void +J9::X86::TreeEvaluator::monitorEnterOrExitForValueTypeClass( + TR::Node *node, + TR::LabelSymbol *snippetLabel, + TR::CodeGenerator *cg) + { + if (cg->isMonitorValueType(node) != TR_maybe) + return; + TR::Register *objectReg = cg->evaluate(node->getFirstChild()); + auto j9classReg = cg->allocateRegister(); + generateLoadJ9Class(node, j9classReg, objectReg, cg); + TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe()); + auto classFlagsMR = generateX86MemoryReference(j9classReg, (uintptr_t)(fej9->getOffsetOfClassFlags()), cg); + static_assert((uint32_t) J9ClassIsValueType < USHRT_MAX); + //test [j9classReg.classFlags], J9ClassIsValueType + generateMemImmInstruction(TEST2MemImm2, node, classFlagsMR, J9ClassIsValueType, cg); + generateLabelInstruction(JNE4, node, snippetLabel, cg); + } + TR::Register * J9::X86::TreeEvaluator::VMmonentEvaluator( TR::Node *node, @@ -4518,20 +4540,22 @@ J9::X86::TreeEvaluator::VMmonentEvaluator( // appropriate excepting instruction we must make sure to reset the // excepting instruction since our children may have set it. // + TR::Compilation *comp = cg->comp(); + TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe()); static const char *noInline = feGetEnv("TR_NoInlineMonitor"); - static int32_t monEntCount = 0; static const char *firstMonEnt = feGetEnv("TR_FirstMonEnt"); - static const char *doCmpFirst = feGetEnv("TR_AddCMPBeforeCMPXCHG"); + static int32_t monEntCount = 0; bool reservingLock = false; bool normalLockPreservingReservation = false; bool dummyMethodMonitor = false; - TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe()); - TR::Compilation *comp = cg->comp(); + + static const char *doCmpFirst = feGetEnv("TR_AddCMPBeforeCMPXCHG"); int lwOffset = fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node)); if (comp->getOption(TR_MimicInterpreterFrameShape) || (comp->getOption(TR_FullSpeedDebug) && node->isSyncMethodMonitor()) || noInline || + TR::Compiler->om.areValueTypesEnabled() && cg->isMonitorValueType(node) == TR_yes || comp->getOption(TR_DisableInlineMonEnt) || (firstMonEnt && (*firstMonEnt-'0') > monEntCount++)) { @@ -4596,6 +4620,8 @@ J9::X86::TreeEvaluator::VMmonentEvaluator( TR::SymbolReference *originalNodeSymRef = NULL; TR::Node *helperCallNode = node; + if (TR::Compiler->om.areValueTypesEnabled()) + monitorEnterOrExitForValueTypeClass(node, snippetLabel, cg); if (comp->getOption(TR_ReservingLocks)) { // About to change the node's symref... store the original. @@ -5124,8 +5150,10 @@ void J9::X86::TreeEvaluator::generateValueTracingCode( generateMemRegInstruction(SMemReg(), node, generateX86MemoryReference(vmThreadReg, vmThreadCursor, cg), scratchReg, cg); } -TR::Register *J9::X86::TreeEvaluator::VMmonexitEvaluator(TR::Node *node, - TR::CodeGenerator *cg) +TR::Register +*J9::X86::TreeEvaluator::VMmonexitEvaluator( + TR::Node *node, + TR::CodeGenerator *cg) { // If there is a NULLCHK above this node it will be expecting us to set // up the excepting instruction. If we are not going to inline an @@ -5135,16 +5163,17 @@ TR::Register *J9::X86::TreeEvaluator::VMmonexitEvaluator(TR::Node *node TR::Compilation *comp = cg->comp(); TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe()); static const char *noInline = feGetEnv("TR_NoInlineMonitor"); - static int32_t monExitCount = 0; static const char *firstMonExit = feGetEnv("TR_FirstMonExit"); + static int32_t monExitCount = 0; bool reservingLock = false; bool normalLockPreservingReservation = false; bool dummyMethodMonitor = false; bool gen64BitInstr = cg->comp()->target().is64Bit() && !fej9->generateCompressedLockWord(); - int lwOffset = fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node)); + if ((comp->getOption(TR_MimicInterpreterFrameShape) /*&& !comp->getOption(TR_EnableLiveMonitorMetadata)*/) || noInline || + TR::Compiler->om.areValueTypesEnabled() && cg->isMonitorValueType(node) == TR_yes || comp->getOption(TR_DisableInlineMonExit) || (firstMonExit && (*firstMonExit-'0') > monExitCount++)) { @@ -5192,7 +5221,10 @@ TR::Register *J9::X86::TreeEvaluator::VMmonexitEvaluator(TR::Node *node TR::LabelSymbol *startLabel = generateLabelSymbol(cg); TR::LabelSymbol *fallThru = generateLabelSymbol(cg); - + // Create the monitor exit snippet + TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg); + if (TR::Compiler->om.areValueTypesEnabled()) + monitorEnterOrExitForValueTypeClass(node, snippetLabel, cg); #if !defined(J9VM_OPT_REAL_TIME_LOCKING_SUPPORT) // Now that the object reference has been generated, see if this is the end // of a small synchronized block. @@ -5245,7 +5277,6 @@ TR::Register *J9::X86::TreeEvaluator::VMmonexitEvaluator(TR::Node *node TR::LabelSymbol *fallThruFromMonitorLookupCacheLabel = generateLabelSymbol(cg); #if defined(J9VM_OPT_REAL_TIME_LOCKING_SUPPORT) - TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg); TR::LabelSymbol *decCountLabel = generateLabelSymbol(cg); unlockedReg = cg->allocateRegister(); @@ -5343,10 +5374,6 @@ TR::Register *J9::X86::TreeEvaluator::VMmonexitEvaluator(TR::Node *node #else - // Create the monitor exit snippet - // - TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg); - if (lwOffset <= 0) { generateRegImmInstruction(CMP4RegImm4, node, objectClassReg, 0, cg); @@ -12663,7 +12690,7 @@ TR::Register * J9::X86::TreeEvaluator::generateConcurrentScavengeSequence(TR::Node *node, TR::CodeGenerator *cg) { TR::Register* object = TR::TreeEvaluator::performHeapLoadWithReadBarrier(node, cg); - + if (!node->getSymbolReference()->isUnresolved() && (node->getSymbolReference()->getSymbol()->getKind() == TR::Symbol::IsShadow) && (node->getSymbolReference()->getCPIndex() >= 0) && @@ -12712,7 +12739,7 @@ J9::X86::TreeEvaluator::irdbariEvaluator(TR::Node *node, TR::CodeGenerator *cg) } } - // Note: For indirect rdbar nodes, the first child (sideEffectNode) is also used by the + // Note: For indirect rdbar nodes, the first child (sideEffectNode) is also used by the // load evaluator. The load evaluator will also evaluate+decrement it. In order to avoid double // decrementing the node we skip doing it here and let the load evaluator do it. return resultReg; @@ -12780,7 +12807,7 @@ J9::X86::TreeEvaluator::ardbariEvaluator(TR::Node *node, TR::CodeGenerator *cg) node->setRegister(resultReg); } - // Note: For indirect rdbar nodes, the first child (sideEffectNode) is also used by the + // Note: For indirect rdbar nodes, the first child (sideEffectNode) is also used by the // load evaluator. The load evaluator will also evaluate+decrement it. In order to avoid double // decrementing the node we skip doing it here and let the load evaluator do it. return resultReg; @@ -12800,7 +12827,7 @@ TR::Register *J9::X86::TreeEvaluator::fwrtbarEvaluator(TR::Node *node, TR::CodeG TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg); } - // Note: The reference count for valueReg's node is not decremented here because the + // Note: The reference count for valueReg's node is not decremented here because the // store evaluator also uses it and so it will evaluate+decrement it. Thus we must skip decrementing here // to avoid double decrementing. cg->decReferenceCount(sideEffectNode); @@ -12821,7 +12848,7 @@ TR::Register *J9::X86::TreeEvaluator::fwrtbariEvaluator(TR::Node *node, TR::Code TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg); } - // Note: The reference count for valueReg's node is not decremented here because the + // Note: The reference count for valueReg's node is not decremented here because the // store evaluator also uses it and so it will evaluate+decrement it. Thus we must skip decrementing here // to avoid double decrementing. cg->decReferenceCount(sideEffectNode); @@ -12843,7 +12870,7 @@ TR::Register *J9::X86::i386::TreeEvaluator::dwrtbarEvaluator(TR::Node *node, TR: TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg); } - // Note: The reference count for valueReg's node is not decremented here because the + // Note: The reference count for valueReg's node is not decremented here because the // store evaluator also uses it and so it will evaluate+decrement it. Thus we must skip decrementing here // to avoid double decrementing. cg->decReferenceCount(sideEffectNode); @@ -12864,7 +12891,7 @@ TR::Register *J9::X86::i386::TreeEvaluator::dwrtbariEvaluator(TR::Node *node, TR TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg); } - // Note: The reference count for valueReg's node is not decremented here because the + // Note: The reference count for valueReg's node is not decremented here because the // store evaluator also uses it and so it will evaluate+decrement it. Thus we must skip decrementing here // to avoid double decrementing. cg->decReferenceCount(sideEffectNode); @@ -12887,7 +12914,7 @@ TR::Register *J9::X86::AMD64::TreeEvaluator::dwrtbarEvaluator(TR::Node *node, TR TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg); } - // Note: The reference count for valueReg's node is not decremented here because the + // Note: The reference count for valueReg's node is not decremented here because the // store evaluator also uses it and so it will evaluate+decrement it. Thus we must skip decrementing here // to avoid double decrementing. cg->decReferenceCount(sideEffectNode); @@ -12908,7 +12935,7 @@ TR::Register *J9::X86::AMD64::TreeEvaluator::dwrtbariEvaluator(TR::Node *node, T TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg); } - // Note: The reference count for valueReg's node is not decremented here because the + // Note: The reference count for valueReg's node is not decremented here because the // store evaluator also uses it and so it will evaluate+decrement it. Thus we must skip decrementing here // to avoid double decrementing. cg->decReferenceCount(sideEffectNode); diff --git a/runtime/compiler/x/codegen/J9TreeEvaluator.hpp b/runtime/compiler/x/codegen/J9TreeEvaluator.hpp index d175298a341..f66311c7f0c 100644 --- a/runtime/compiler/x/codegen/J9TreeEvaluator.hpp +++ b/runtime/compiler/x/codegen/J9TreeEvaluator.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corp. and others + * Copyright (c) 2000, 2020 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -90,6 +90,26 @@ class OMR_EXTENSIBLE TreeEvaluator: public J9::TreeEvaluator static TR::Register *checkcastinstanceofEvaluator(TR::Node *node, TR::CodeGenerator *cg); static void asyncGCMapCheckPatching(TR::Node *node, TR::CodeGenerator *cg, TR::LabelSymbol *snippetLabel); static void inlineRecursiveMonitor(TR::Node *node, TR::CodeGenerator *cg, TR::LabelSymbol *startLabel, TR::LabelSymbol *snippetLabel, TR::LabelSymbol *JITMonitorEnterSnippetLabel, TR::Register *objectReg, int lwoffset, TR::LabelSymbol *snippetRestartLabel, bool reservingLock); + + /* + * \brief + * Generates the sequence to handle cases where the monitor object is value type + * + * \param node + * the monitor enter/exit node + * + * \param snippetLabel + * the label for OOL code calling VM monitor enter/exit helpers + * + * \details + * Call the VM helper if it's detected at runtime that the monitor object is value type. + * The VM helper throws appropriate IllegalMonitorStateException. + * + * \note + * This method only handles the cases where, at compile time, it's unknown whether the + * object is reference type or value type. + */ + static void monitorEnterOrExitForValueTypeClass(TR::Node *node, TR::LabelSymbol *snippetLabel, TR::CodeGenerator *cg); static void transactionalMemoryJITMonitorEntry(TR::Node *node, TR::CodeGenerator *cg, TR::LabelSymbol *startLabel, TR::LabelSymbol *snippetLabel, TR::LabelSymbol *JITMonitorEnterSnippetLabel, TR::Register *objectReg, int lwoffset); static void generateValueTracingCode(TR::Node *node, TR::Register *vmThreadReg, TR::Register *scratchReg, TR::Register *valueRegHigh, TR::Register *valueRegLow, TR::CodeGenerator *cg); static void generateValueTracingCode(TR::Node *node, TR::Register *vmThreadReg, TR::Register *scratchReg, TR::Register *valueReg, TR::CodeGenerator *cg); @@ -101,14 +121,14 @@ class OMR_EXTENSIBLE TreeEvaluator: public J9::TreeEvaluator /* * Generate instructions for static/instance field access report. - * @param dataSnippetRegister: Optional, can be used to pass the address of the snippet inside the register. - */ + * @param dataSnippetRegister: Optional, can be used to pass the address of the snippet inside the register. + */ static void generateTestAndReportFieldWatchInstructions(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *valueReg, TR::Register *dataSnippetRegister); /* * Generates instructions to fill in the J9JITWatchedStaticFieldData.fieldAddress, J9JITWatchedStaticFieldData.fieldClass for static fields, * and J9JITWatchedInstanceFieldData.offset for instance fields at runtime. Used for fieldwatch support. - * @param dataSnippetRegister: Optional, can be used to pass the address of the snippet inside the register. + * @param dataSnippetRegister: Optional, can be used to pass the address of the snippet inside the register. */ static void generateFillInDataBlockSequenceForUnresolvedField (TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *dataSnippetRegister); static TR::Register *directCallEvaluator(TR::Node *node, TR::CodeGenerator *cg);