Skip to content

Commit

Permalink
Merge pull request #16453 from klangman/prevent-invalid-compiletime-f…
Browse files Browse the repository at this point in the history
…ield-access

Disable ClassLookahead by default
  • Loading branch information
vijaysun-omr authored Dec 12, 2022
2 parents 7cafd4b + 2cf11bc commit 60a4172
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 211 deletions.
44 changes: 31 additions & 13 deletions runtime/compiler/ilgen/ClassLookahead.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2021 IBM Corp. and others
* Copyright (c) 2000, 2022 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
Expand Down Expand Up @@ -55,8 +55,16 @@ TR_ClassLookahead::TR_ClassLookahead(
int32_t
TR_ClassLookahead::perform()
{
static bool allowClassLookahead = feGetEnv("TR_AllowClassLookahead") ? true : false;
TR_J9VMBase *fej9 = (TR_J9VMBase *)fe();

// Static analysis of static final fields is not possible because there are ways for
// such fields to change after initialization. The staticFinalFieldFolding opt is the
// safe way since it uses OSR to invalidate code after some operation changes a static
// final field. Therefore we are disabling this code by default!
if (!allowClassLookahead)
return 0;

if ((fej9->getNumInnerClasses(_classPointer) > 0) ||
_classInfo->cannotTrustStaticFinal())
return 0;
Expand Down Expand Up @@ -593,26 +601,36 @@ TR_ClassLookahead::examineNode(TR::TreeTop *nextTree, TR::Node *grandParent, TR:
isConstantLengthArrayAllocation &&
(numberOfDimensions <= 2))
{
int32_t oldNumDimensions = arrayFieldInfo->getNumDimensions();
if (oldNumDimensions > -1)
if (_inFirstBlock &&
_inInitializerMethod)
{
if (arrayFieldInfo->isDimensionInfoValid())
int32_t oldNumDimensions = arrayFieldInfo->getNumDimensions();
if (oldNumDimensions > -1)
{
if (oldNumDimensions != numberOfDimensions)
if (arrayFieldInfo->isDimensionInfoValid())
{
// Same field is assigned different dimension arrays
// at different program points within this class.
//
if (_traceIt)
traceMsg(comp(), "0Invalidating dimension info for symbol %x at node %x\n", sym, node);
arrayFieldInfo->setIsDimensionInfoValid(INVALID);
if (oldNumDimensions != numberOfDimensions)
{
// Same field is assigned different dimension arrays
// at different program points within this class.
//
if (_traceIt)
traceMsg(comp(), "0Invalidating dimension info for symbol %x at node %x\n", sym, node);
arrayFieldInfo->setIsDimensionInfoValid(INVALID);
}
}
}
else
{
isInitialized = true;
arrayFieldInfo->prepareArrayFieldInfo(numberOfDimensions, comp());
}
}
else
{
isInitialized = true;
arrayFieldInfo->prepareArrayFieldInfo(numberOfDimensions, comp());
if (_traceIt)
traceMsg(comp(), "00Invalidating dimension info for symbol %x at node %x\n", sym, node);
arrayFieldInfo->setIsDimensionInfoValid(INVALID);
}

if (arrayFieldInfo->isDimensionInfoValid())
Expand Down
5 changes: 1 addition & 4 deletions runtime/compiler/ilgen/J9ByteCodeIlGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,7 @@ class TR_J9ByteCodeIlGenerator : public TR_IlGenerator, public TR_J9ByteCodeIter
//
TR::TreeTop * genTreeTop(TR::Node *);

TR::Node * loadConstantValueIfPossible(TR::Node *, uintptr_t, TR::DataType type = TR::Int32, bool isArrayLength = true);

void genArrayLength();
void genContiguousArrayLength(int32_t width);
void genArrayLength(bool contiguous = false);
void genArrayBoundsCheck(TR::Node *, int32_t);
void genDivCheck();
void genIDiv();
Expand Down
205 changes: 11 additions & 194 deletions runtime/compiler/ilgen/Walker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1802,130 +1802,6 @@ TR_J9ByteCodeIlGenerator::valueMayBeModified(TR::Node * sideEffect, TR::Node * n
return false;
}


TR::Node *
TR_J9ByteCodeIlGenerator::loadConstantValueIfPossible(TR::Node *topNode, uintptr_t topFieldOffset, TR::DataType type, bool isArrayLength)
{
TR::Node *constNode = NULL;
TR::Node *parent = topNode;
TR::SymbolReference *symRef = NULL;
uintptr_t fieldOffset = 0;
if (topNode->getOpCode().hasSymbolReference())
{
symRef = topNode->getSymbolReference();
if (symRef->getSymbol()->isShadow() &&
symRef->getSymbol()->isFinal() &&
!symRef->isUnresolved())
{
fieldOffset = symRef->getOffset();
TR::Node *child = topNode->getFirstChild();
if (child->getOpCode().hasSymbolReference())
{
topNode = child;
symRef = child->getSymbolReference();
}
}
}

if (symRef && symRef->getSymbol()->isStatic() && !symRef->isUnresolved() && symRef->getSymbol()->isFinal() && !symRef->getSymbol()->isConstObjectRef() && _method->isSameMethod(symRef->getOwningMethod(comp())))
{
TR::StaticSymbol *symbol = symRef->getSymbol()->castToStaticSymbol();
TR_J9VMBase *fej9 = (TR_J9VMBase *)fe();


bool isResolved = !symRef->isUnresolved();
TR_OpaqueClassBlock * classOfStatic = isResolved ? _method->classOfStatic(topNode->getSymbolReference()->getCPIndex()) : 0;
if (classOfStatic == NULL)
{
int len = 0;
char * classNameOfFieldOrStatic = NULL;
classNameOfFieldOrStatic = symRef->getOwningMethod(comp())->classNameOfFieldOrStatic(symRef->getCPIndex(), len);
if (classNameOfFieldOrStatic)
{
classNameOfFieldOrStatic = TR::Compiler->cls.classNameToSignature(classNameOfFieldOrStatic, len, comp());
TR_OpaqueClassBlock * curClass = fej9->getClassFromSignature(classNameOfFieldOrStatic, len, symRef->getOwningMethod(comp()));
TR_OpaqueClassBlock * owningClass = comp()->getJittedMethodSymbol()->getResolvedMethod()->containingClass();
if (owningClass == curClass)
classOfStatic = curClass;
}
}

bool isClassInitialized = false;
TR_PersistentClassInfo * classInfo = _noLookahead ? 0 :
comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(classOfStatic, comp());
if (classInfo && classInfo->isInitialized())
isClassInitialized = true;

bool canOptimizeFinalStatic = false;
if (isResolved && symbol->isFinal() && !symRef->isUnresolved() &&
classOfStatic != comp()->getSystemClassPointer() &&
isClassInitialized)
{
//if (symbol->getDataType() == TR::Address)
{
// todo: figure out why classInfo would be NULL here?
if (!classInfo->getFieldInfo())
performClassLookahead(classInfo);
}

if (classInfo->getFieldInfo() && !classInfo->cannotTrustStaticFinal())
canOptimizeFinalStatic = true;
}

if (canOptimizeFinalStatic)
{
TR::VMAccessCriticalSection loadConstantValueCriticalSection(fej9,
TR::VMAccessCriticalSection::tryToAcquireVMAccess,
comp());

if (loadConstantValueCriticalSection.hasVMAccess())
{
uintptr_t objectPointer = comp()->fej9()->getStaticReferenceFieldAtAddress((uintptr_t)symbol->getStaticAddress());
if (objectPointer)
{
switch (symbol->getDataType())
{
case TR::Address:
{
if (parent != topNode)
objectPointer = fej9->getReferenceFieldAt(objectPointer, fieldOffset);
if ((type == TR::Int32) ||
(type == TR::Int16) ||
(type == TR::Int8))
{
int32_t val;
if (isArrayLength)
val = (int32_t)(fej9->getArrayLengthInElements(objectPointer));
else
val = *(int32_t*)(objectPointer + topFieldOffset);
loadConstant(TR::iconst, val);
constNode = _stack->top();
}
else if (type == TR::Int64)
{
int64_t val;
if (isArrayLength)
val = (int64_t)(fej9->getArrayLengthInElements(objectPointer));
else
val = *(int64_t*)(objectPointer + topFieldOffset);
loadConstant(TR::lconst, val);
constNode = _stack->top();
}
break;
}
default:
break;
}
}
}

} // VM Access Critical Section

}

return constNode;
}

/**
* @brief Abort compilation due to unsupported unresolved value type operation
*
Expand Down Expand Up @@ -1979,66 +1855,24 @@ TR_J9ByteCodeIlGenerator::loadConstantValueIfPossible(TR::Node *topNode, uintptr
// gen array
//----------------------------------------------
void
TR_J9ByteCodeIlGenerator::genArrayLength()
TR_J9ByteCodeIlGenerator::genArrayLength(bool contiguous)
{
TR::Node * node = NULL;
TR::Node * topNode = pop();

TR::Node *loadedConst = loadConstantValueIfPossible(topNode, fej9()->getOffsetOfContiguousArraySizeField());

if (!loadedConst)
{
if ( comp()->cg()->getDisableNullCheckOfArrayLength() )
node = TR::Node::create(TR::PassThrough, 1, topNode);
else
node = TR::Node::create(TR::arraylength, 1, topNode);

genTreeTop(genNullCheck(node));

if ( comp()->cg()->getDisableNullCheckOfArrayLength() )
{
node = TR::Node::create(TR::arraylength, 1, topNode);
}

push(node);
}
}

void
TR_J9ByteCodeIlGenerator::genContiguousArrayLength(int32_t width)
{
TR::Node * node = NULL;
TR::Node * topNode = pop();
if ( comp()->cg()->getDisableNullCheckOfArrayLength() )
node = TR::Node::create(TR::PassThrough, 1, topNode);
else
node = TR::Node::create((contiguous) ? TR::contigarraylength : TR::arraylength, 1, topNode);

TR::Node *loadedConst = loadConstantValueIfPossible(topNode, fej9()->getOffsetOfContiguousArraySizeField());
genTreeTop(genNullCheck(node));

// Discontiguous arrays still require the contiguity check and can't be folded.
//
if (loadedConst)
if ( comp()->cg()->getDisableNullCheckOfArrayLength() )
{
if (TR::Compiler->om.isDiscontiguousArray(loadedConst->getInt(), width))
{
pop();
loadedConst = NULL;
}
node = TR::Node::create((contiguous) ? TR::contigarraylength : TR::arraylength, 1, topNode);
}

if (!loadedConst)
{
if ( comp()->cg()->getDisableNullCheckOfArrayLength() )
node = TR::Node::create(TR::PassThrough, 1, topNode);
else
node = TR::Node::create(TR::contigarraylength, 1, topNode);

genTreeTop(genNullCheck(node));

if ( comp()->cg()->getDisableNullCheckOfArrayLength() )
{
node = TR::Node::create(TR::contigarraylength, 1, topNode);
}

push(node);
}
push(node);
}

void
Expand Down Expand Up @@ -2099,10 +1933,7 @@ TR_J9ByteCodeIlGenerator::genArrayBoundsCheck(TR::Node * offset, int32_t width)
TR::Node *arrayLength = 0;
if (!canSkipArrayLengthCalc)
{
if (!comp()->requiresSpineChecks())
genArrayLength();
else
genContiguousArrayLength(width);
genArrayLength(comp()->requiresSpineChecks());

arrayLength = pop();
if (arrayLength->getOpCode().isArrayLength())
Expand Down Expand Up @@ -5154,26 +4985,12 @@ TR_J9ByteCodeIlGenerator::loadInstance(TR::SymbolReference * symRef)
{
TR::Symbol * symbol = symRef->getSymbol();
TR::DataType type = symbol->getDataType();

TR::Node * address = pop();

if (!symRef->isUnresolved() &&
symRef->getSymbol()->isFinal())
{
TR::Node *constValue = loadConstantValueIfPossible(address, symRef->getOffset(), type, false);
if (constValue)
{
return;
}
}

TR::Node * load, *dummyLoad;

TR::Node * treeTopNode = 0;
TR::ILOpCodes op = _generateReadBarriersForFieldWatch ? comp()->il.opCodeForIndirectReadBarrier(type): comp()->il.opCodeForIndirectLoad(type);
dummyLoad = load = TR::Node::createWithSymRef(op, 1, 1, address, symRef);

TR::Node * treeTopNode = 0;

if (symRef->isUnresolved())
{
if (!address->isNonNull())
Expand Down

0 comments on commit 60a4172

Please sign in to comment.