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

Handle monitor enter/exit on value based instances (X86) #11358

Merged
merged 2 commits into from
Dec 17, 2020
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: 24 additions & 2 deletions runtime/compiler/codegen/J9CodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5426,10 +5426,11 @@ J9::CodeGenerator::getMonClass(TR::Node* monNode)
TR_YesNoMaybe
J9::CodeGenerator::isMonitorValueType(TR::Node* monNode)
{
if (_monitorMapping.find(monNode->getGlobalIndex()) == _monitorMapping.end())
TR_OpaqueClassBlock *clazz = self()->getMonClass(monNode);

if (!clazz)
return TR_maybe;

TR_OpaqueClassBlock *clazz = _monitorMapping[monNode->getGlobalIndex()];
//java.lang.Object class is only set when monitor is java.lang.Object but not its subclass
if (clazz == self()->comp()->getObjectClassPointer())
return TR_no;
Expand All @@ -5442,3 +5443,24 @@ J9::CodeGenerator::isMonitorValueType(TR::Node* monNode)

return TR_no;
}

TR_YesNoMaybe
J9::CodeGenerator::isMonitorValueBasedOrValueType(TR::Node* monNode)
{
TR_OpaqueClassBlock *clazz = self()->getMonClass(monNode);

if (!clazz)
return TR_maybe;

//java.lang.Object class is only set when monitor is java.lang.Object but not its subclass
if (clazz == self()->comp()->getObjectClassPointer())
return TR_no;

a7ehuo marked this conversation as resolved.
Show resolved Hide resolved
if (!TR::Compiler->cls.isConcreteClass(self()->comp(), clazz))
return TR_maybe;

if (TR::Compiler->cls.isValueBasedOrValueTypeClass(clazz))
return TR_yes;

return TR_no;
}
10 changes: 10 additions & 0 deletions runtime/compiler/codegen/J9CodeGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,16 @@ class OMR_EXTENSIBLE CodeGenerator : public OMR::CodeGeneratorConnector
* TR_maybe It is unknown whether the monitor object is identity type or value type
*/
TR_YesNoMaybe isMonitorValueType(TR::Node* monNode);
/*
* \brief
* Whether a monitor object is of value based class type or value type
*
* \return
* TR_yes The monitor object is definitely value based class type or value type
* TR_no The monitor object is definitely not value based class type or value type
* TR_maybe It is unknown whether the monitor object is value based class type or value type
*/
TR_YesNoMaybe isMonitorValueBasedOrValueType(TR::Node* monNode);

protected:

Expand Down
23 changes: 23 additions & 0 deletions runtime/compiler/env/J9ClassEnv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,29 @@ J9::ClassEnv::isValueTypeClassFlattened(TR_OpaqueClassBlock *clazz)
return (clazz && J9_IS_J9CLASS_FLATTENED(reinterpret_cast<J9Class*>(clazz)));
}

bool
J9::ClassEnv::isValueBasedOrValueTypeClass(TR_OpaqueClassBlock *clazz)
{
#if defined(J9VM_OPT_JITSERVER)
if (auto stream = TR::CompilationInfo::getStream())
{
uintptr_t classFlags = 0;
JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazz, TR::compInfoPT->getClientData(), stream, JITServerHelpers::CLASSINFO_CLASS_FLAGS, (void *)&classFlags);
#ifdef DEBUG
stream->write(JITServer::MessageType::ClassEnv_classFlagsValue, clazz);
uintptr_t classFlagsRemote = std::get<0>(stream->read<uintptr_t>());
// Check that class flags from remote call is equal to the cached ones
classFlags = classFlags & J9_CLASS_DISALLOWS_LOCKING_FLAGS;
classFlagsRemote = classFlagsRemote & J9_CLASS_DISALLOWS_LOCKING_FLAGS;
TR_ASSERT_FATAL(classFlags == classFlagsRemote, "remote call class flags is not equal to cached class flags");
#endif
return J9_ARE_ANY_BITS_SET(classFlags, J9_CLASS_DISALLOWS_LOCKING_FLAGS);
}
#endif /* defined(J9VM_OPT_JITSERVER) */
J9Class *j9class = reinterpret_cast<J9Class*>(clazz);
return J9_ARE_ANY_BITS_SET(j9class->classFlags, J9_CLASS_DISALLOWS_LOCKING_FLAGS);
}

bool
J9::ClassEnv::isZeroInitializable(TR_OpaqueClassBlock *clazz)
{
Expand Down
1 change: 1 addition & 0 deletions runtime/compiler/env/J9ClassEnv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class OMR_EXTENSIBLE ClassEnv : public OMR::ClassEnvConnector
bool isConcreteClass(TR::Compilation *comp, TR_OpaqueClassBlock * clazzPointer);
bool isValueTypeClass(TR_OpaqueClassBlock *);
bool isValueTypeClassFlattened(TR_OpaqueClassBlock *clazz);
bool isValueBasedOrValueTypeClass(TR_OpaqueClassBlock *);

/**
* \brief
Expand Down
16 changes: 16 additions & 0 deletions runtime/compiler/env/J9ObjectModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,22 @@ J9::ObjectModel::areValueTypesEnabled()
}


bool
J9::ObjectModel::areValueBasedMonitorChecksEnabled()
{
#if defined(J9VM_OPT_JITSERVER)
if (auto stream = TR::CompilationInfo::getStream())
{
auto *vmInfo = TR::compInfoPT->getClientData()->getOrCacheVMInfo(stream);
return J9_ARE_ANY_BITS_SET(vmInfo->_extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_VALUE_BASED_EXCEPTION | J9_EXTENDED_RUNTIME2_VALUE_BASED_WARNING);
}
#endif /* defined(J9VM_OPT_JITSERVER) */

J9JavaVM * javaVM = TR::Compiler->javaVM;
return javaVM->internalVMFunctions->areValueBasedMonitorChecksEnabled(javaVM);
}


int32_t
J9::ObjectModel::sizeofReferenceField()
{
Expand Down
4 changes: 4 additions & 0 deletions runtime/compiler/env/J9ObjectModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ class ObjectModel : public OMR::ObjectModelConnector
bool mayRequireSpineChecks();

bool areValueTypesEnabled();
/**
* @brief Whether the check is enabled on monitor object being value based class type
*/
bool areValueBasedMonitorChecksEnabled();
a7ehuo marked this conversation as resolved.
Show resolved Hide resolved

int32_t sizeofReferenceField();
bool isHotReferenceFieldRequired();
Expand Down
40 changes: 27 additions & 13 deletions runtime/compiler/x/codegen/J9TreeEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ inline void generateLoadJ9Class(TR::Node* node, TR::Register* j9class, TR::Regis
{
case TR::monent:
case TR::monexit:
TR_ASSERT_FATAL(TR::Compiler->om.areValueTypesEnabled(), "monent and monexit are expected for generateLoadJ9Class only when value type is enabled");
TR_ASSERT_FATAL(TR::Compiler->om.areValueTypesEnabled() || TR::Compiler->om.areValueBasedMonitorChecksEnabled(),
"monent and monexit are expected for generateLoadJ9Class only when value type or when value based monitor check is enabled");
case TR::checkcastAndNULLCHK:
needsNULLCHK = true;
break;
Expand Down Expand Up @@ -4482,21 +4483,26 @@ void J9::X86::TreeEvaluator::transactionalMemoryJITMonitorEntry(TR::Node
}

void
J9::X86::TreeEvaluator::generateCheckForValueTypeMonitorEnterOrExit(
J9::X86::TreeEvaluator::generateCheckForValueMonitorEnterOrExit(
TR::Node *node,
int32_t classFlag,
TR::LabelSymbol *snippetLabel,
TR::CodeGenerator *cg)
{
if (cg->isMonitorValueType(node) != TR_maybe)
return;
TR::Register *objectReg = cg->evaluate(node->getFirstChild());
TR::Register *j9classReg = cg->allocateRegister();
generateLoadJ9Class(node, j9classReg, objectReg, cg);
auto fej9 = (TR_J9VMBase *)(cg->fe());
TR::MemoryReference *classFlagsMR = generateX86MemoryReference(j9classReg, (uintptr_t)(fej9->getOffsetOfClassFlags()), cg);
static_assert((uint32_t) J9ClassIsValueType < USHRT_MAX, "Expecting J9ClassIsValueType to be less than 16 bits for use in test instruction");
//test [j9classReg.classFlags], J9ClassIsValueType
generateMemImmInstruction(TEST2MemImm2, node, classFlagsMR, J9ClassIsValueType, cg);

//test [j9classReg.classFlags], J9ClassIsValueType or J9ClassIsValueBased
TR_X86OpCodes testOpCode;
if ((uint32_t)classFlag <= USHRT_MAX)
testOpCode = TEST2MemImm2;
else
testOpCode = TEST4MemImm4;

generateMemImmInstruction(testOpCode, node, classFlagsMR, classFlag, cg);
generateLabelInstruction(JNE4, node, snippetLabel, cg);
}

Expand Down Expand Up @@ -4525,7 +4531,8 @@ J9::X86::TreeEvaluator::VMmonentEvaluator(
if (comp->getOption(TR_MimicInterpreterFrameShape) ||
(comp->getOption(TR_FullSpeedDebug) && node->isSyncMethodMonitor()) ||
noInline ||
TR::Compiler->om.areValueTypesEnabled() && cg->isMonitorValueType(node) == TR_yes ||
((TR::Compiler->om.areValueTypesEnabled() || TR::Compiler->om.areValueBasedMonitorChecksEnabled()) &&
(cg->isMonitorValueBasedOrValueType(node) == TR_yes)) ||
comp->getOption(TR_DisableInlineMonEnt) ||
(firstMonEnt && (*firstMonEnt-'0') > monEntCount++))
{
Expand Down Expand Up @@ -4590,8 +4597,11 @@ J9::X86::TreeEvaluator::VMmonentEvaluator(
TR::SymbolReference *originalNodeSymRef = NULL;

TR::Node *helperCallNode = node;
if (TR::Compiler->om.areValueTypesEnabled())
TR::TreeEvaluator::generateCheckForValueTypeMonitorEnterOrExit(node, snippetLabel, cg);

if ((TR::Compiler->om.areValueTypesEnabled() || TR::Compiler->om.areValueBasedMonitorChecksEnabled())
&& (cg->isMonitorValueBasedOrValueType(node) == TR_maybe))
TR::TreeEvaluator::generateCheckForValueMonitorEnterOrExit(node, J9_CLASS_DISALLOWS_LOCKING_FLAGS, snippetLabel, cg);

if (comp->getOption(TR_ReservingLocks))
{
// About to change the node's symref... store the original.
Expand Down Expand Up @@ -5143,7 +5153,8 @@ TR::Register

if ((comp->getOption(TR_MimicInterpreterFrameShape) /*&& !comp->getOption(TR_EnableLiveMonitorMetadata)*/) ||
noInline ||
TR::Compiler->om.areValueTypesEnabled() && cg->isMonitorValueType(node) == TR_yes ||
((TR::Compiler->om.areValueTypesEnabled() || TR::Compiler->om.areValueBasedMonitorChecksEnabled()) &&
(cg->isMonitorValueBasedOrValueType(node) == TR_yes)) ||
comp->getOption(TR_DisableInlineMonExit) ||
(firstMonExit && (*firstMonExit-'0') > monExitCount++))
{
Expand Down Expand Up @@ -5193,8 +5204,11 @@ TR::Register
TR::LabelSymbol *fallThru = generateLabelSymbol(cg);
// Create the monitor exit snippet
TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg);
if (TR::Compiler->om.areValueTypesEnabled())
TR::TreeEvaluator::generateCheckForValueTypeMonitorEnterOrExit(node, snippetLabel, cg);

if ((TR::Compiler->om.areValueTypesEnabled() || TR::Compiler->om.areValueBasedMonitorChecksEnabled())
&& (cg->isMonitorValueBasedOrValueType(node) == TR_maybe))
TR::TreeEvaluator::generateCheckForValueMonitorEnterOrExit(node, J9_CLASS_DISALLOWS_LOCKING_FLAGS, 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
13 changes: 8 additions & 5 deletions runtime/compiler/x/codegen/J9TreeEvaluator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ class OMR_EXTENSIBLE TreeEvaluator: public J9::TreeEvaluator

/*
* \brief
* Generates the sequence to handle cases where the monitor object is value type
* Generates the sequence to handle cases where the monitor object
* is value type or value based class type
*
* \param node
* the monitor enter/exit node
Expand All @@ -102,14 +103,16 @@ class OMR_EXTENSIBLE TreeEvaluator: public J9::TreeEvaluator
* 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.
* Call the VM helper if it's detected at runtime that the monitor object
* is value type or value based class type.
* The VM helper throws appropriate IllegalMonitorStateException for value type
* and VirtualMachineError for value based class type.
*
* \note
* This method only handles the cases where, at compile time, it's unknown whether the
* object is reference type or value type.
* object is reference type or value type or value based class type.
*/
static void generateCheckForValueTypeMonitorEnterOrExit(TR::Node *node, TR::LabelSymbol *snippetLabel, TR::CodeGenerator *cg);
static void generateCheckForValueMonitorEnterOrExit(TR::Node *node, int32_t classFlag, 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);
Expand Down