Skip to content

Commit

Permalink
Merge pull request eclipse-openj9#16 from cathyzhyi/monitor-valhalla-…
Browse files Browse the repository at this point in the history
…sandbox

Implment monitor enter/exit for valuetype
  • Loading branch information
Charlmzz authored Mar 26, 2020
2 parents 619b5ea + e7be341 commit 7d321a9
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 50 deletions.
31 changes: 20 additions & 11 deletions runtime/compiler/codegen/J9CodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ J9::CodeGenerator::CodeGenerator() :
_liveMonitors(NULL),
_nodesSpineCheckedList(getTypedAllocator<TR::Node*>(TR::comp()->allocator())),
_jniCallSites(getTypedAllocator<TR_Pair<TR_ResolvedMethod,TR::Instruction> *>(TR::comp()->allocator())),
_monitorMapping(self()->comp()->trMemory(), 256),
_monitorMapping(MonitorTypeMap(std::less<ncount_t>(), MonitorMapAllocator(self()->comp()->trMemory()->heapMemoryRegion()))),
_dummyTempStorageRefNode(NULL)
{
}
Expand Down Expand Up @@ -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);
}


Expand Down Expand Up @@ -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;
}
36 changes: 28 additions & 8 deletions runtime/compiler/codegen/J9CodeGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<void *> _monitorMapping;
typedef TR::typed_allocator<std::pair<const ncount_t , TR_OpaqueClassBlock*>, TR::Region &> MonitorMapAllocator;
typedef std::map<ncount_t , TR_OpaqueClassBlock *, std::less<ncount_t>, 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<TR::Node*> _nodesSpineCheckedList;

TR::list<TR_Pair<TR_ResolvedMethod, TR::Instruction> *> _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
Expand Down Expand Up @@ -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;}

// --------------------------------------------------------------------------
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down
81 changes: 54 additions & 27 deletions runtime/compiler/x/codegen/J9TreeEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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,
Expand All @@ -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++))
{
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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++))
{
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) &&
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down
Loading

0 comments on commit 7d321a9

Please sign in to comment.