Skip to content

Commit

Permalink
Merge pull request #4777 from aviansie-ben/power-aot-svm-support
Browse files Browse the repository at this point in the history
Add support for generating SVM relocations on Power
  • Loading branch information
gita-omr authored Feb 22, 2019
2 parents eead1c5 + 715b9d3 commit 394debd
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 33 deletions.
36 changes: 28 additions & 8 deletions runtime/compiler/p/codegen/CallSnippet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,13 @@ TR_RuntimeHelper TR::PPCCallSnippet::getInterpretedDispatchHelper(
isJitInduceOSRCall = true;
}

if (methodSymRef->isUnresolved() || comp->compileRelocatableCode()) // KEN
bool forceUnresolvedDispatch = fej9->forceUnresolvedDispatch();
if (comp->getOption(TR_UseSymbolValidationManager))
forceUnresolvedDispatch = false;

if (methodSymRef->isUnresolved() || forceUnresolvedDispatch)
{
TR_ASSERT(!isJitInduceOSRCall || !comp->compileRelocatableCode(), "calling jitInduceOSR is not supported yet under AOT\n");
TR_ASSERT(!isJitInduceOSRCall || !forceUnresolvedDispatch, "calling jitInduceOSR is not supported yet under AOT\n");

if (methodSymbol->isSpecial())
return TR_PPCinterpreterUnresolvedSpecialGlue;
Expand Down Expand Up @@ -397,8 +401,12 @@ uint8_t *TR::PPCCallSnippet::emitSnippetBody()
//continue execution in interpreted mode. Therefore, it doesn't need the method pointer.
if (!glueRef->isOSRInductionHelper())
{
bool forceUnresolvedDispatch = fej9->forceUnresolvedDispatch();
if (comp->getOption(TR_UseSymbolValidationManager))
forceUnresolvedDispatch = false;

// Store the method pointer: it is NULL for unresolved
if (methodSymRef->isUnresolved() || comp->compileRelocatableCode())
if (methodSymRef->isUnresolved() || forceUnresolvedDispatch)
{
*(intptrj_t *)cursor = 0;
if (comp->getOption(TR_EnableHCR))
Expand All @@ -415,10 +423,18 @@ uint8_t *TR::PPCCallSnippet::emitSnippetBody()
if (comp->getOption(TR_EnableHCR))
cg()->jitAddPicToPatchOnClassRedefinition((void *)methodSymbol->getMethodAddress(), (void *)cursor);

cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, (uint8_t *)methodSymRef,
getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,
TR_MethodObject, cg()),
__FILE__, __LINE__, callNode);
if (comp->compileRelocatableCode())
{
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,
(uint8_t *)methodSymbol->getMethodAddress(),
(uint8_t *)TR::SymbolType::typeMethod,
TR_SymbolFromManager,
cg()), __FILE__, __LINE__, getNode());
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,
(uint8_t *)methodSymbol->getMethodAddress(),
TR_ResolvedTrampolines,
cg()), __FILE__, __LINE__, getNode());
}
}
}
cursor += TR::Compiler->om.sizeofReferenceAddress();
Expand Down Expand Up @@ -1277,13 +1293,17 @@ TR_Debug::print(TR::FILE *pOutFile, TR::PPCCallSnippet * snippet)
const char *labelString = NULL;
bool isNativeStatic = false;

bool forceUnresolvedDispatch = fej9->forceUnresolvedDispatch();
if (comp->getOption(TR_UseSymbolValidationManager))
forceUnresolvedDispatch = false;

if (methodSymbol->isHelper() &&
methodSymRef->isOSRInductionHelper())
{
labelString = "Induce OSR Call Snippet";
glueRef = methodSymRef;
}
else if (methodSymRef->isUnresolved() || comp->compileRelocatableCode())
else if (methodSymRef->isUnresolved() || forceUnresolvedDispatch)
{
labelString = "Unresolved Direct Call Snippet";
if (methodSymbol->isSpecial())
Expand Down
4 changes: 2 additions & 2 deletions runtime/compiler/p/codegen/CallSnippet.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corp. and others
* Copyright (c) 2000, 2019 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 @@ -43,7 +43,7 @@ class PPCCallSnippet : public TR::Snippet
bool needsGCMap(TR::CodeGenerator *cg, TR::SymbolReference *methodSymRef)
{
TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());
if (OMR_UNLIKELY(cg->comp()->compileRelocatableCode()))
if (OMR_UNLIKELY(cg->comp()->compileRelocatableCode() && !cg->comp()->getOption(TR_UseSymbolValidationManager)))
return false;
TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
return !methodSymRef->isUnresolved() &&
Expand Down
136 changes: 116 additions & 20 deletions runtime/compiler/p/codegen/J9TreeEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,21 @@ static void genInlineTest(TR::Node * node, TR_OpaqueClassBlock* castClassAddr, T
// Load the cached value in scratch1Reg
// HCR in genInlineTest for checkcast and instanceof
if (cg->wantToPatchClassPointer(guessClassArray[i], node))
{
iCursor = loadAddressConstantInSnippet(cg, node, (intptrj_t) (guessClassArray[i]), scratch1Reg, scratch2Reg,TR::InstOpCode::Op_load, true, iCursor);
}
else if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager))
{
TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);
sym->setStaticAddress(guessClassArray[i]);
sym->setClassObject();

iCursor = loadAddressConstant(cg, node, (intptrj_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), scratch1Reg, iCursor, false, TR_ClassAddress);
}
else
{
iCursor = loadAddressConstant(cg, node, (intptrj_t) (guessClassArray[i]), scratch1Reg, iCursor);
}
result_bool = instanceOfOrCheckCast((J9Class*) guessClassArray[i], (J9Class*) castClassAddr);
int32_t result_value = result_bool ? 1 : 0;
result_label = (falseLabel != trueLabel) ? (result_bool ? trueLabel : falseLabel) : doneLabel;
Expand All @@ -193,9 +205,21 @@ static void genInlineTest(TR::Node * node, TR_OpaqueClassBlock* castClassAddr, T

// Load the cached value in scratch1Reg
if (cg->wantToPatchClassPointer(guessClassArray[num_PICS - 1], node))
{
iCursor = loadAddressConstantInSnippet(cg, node, (intptrj_t) (guessClassArray[num_PICS - 1]), scratch1Reg, scratch2Reg,TR::InstOpCode::Op_load, true, iCursor);
}
else if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager))
{
TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);
sym->setStaticAddress(guessClassArray[num_PICS - 1]);
sym->setClassObject();

iCursor = loadAddressConstant(cg, node, (intptrj_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), scratch1Reg, iCursor, false, TR_ClassAddress);
}
else
{
iCursor = loadAddressConstant(cg, node, (intptrj_t) (guessClassArray[num_PICS - 1]), scratch1Reg, iCursor);
}
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, objClassReg, scratch1Reg, iCursor);
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg, iCursor);
result_bool = instanceOfOrCheckCast((J9Class*) guessClassArray[num_PICS - 1], (J9Class*) castClassAddr);
Expand Down Expand Up @@ -3006,31 +3030,42 @@ static void VMarrayStoreCHKEvaluator(TR::Node *node, TR::Register *src, TR::Regi
new (cg->trHeapMemory()) TR::MemoryReference(dst, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4, cg));
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, t2Reg,
new (cg->trHeapMemory()) TR::MemoryReference(src, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4, cg));
TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, t1Reg);
TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, t2Reg);
// here we may need to convert from class offset contained in t1Reg to
// J9Class pointer
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t1Reg,
new (cg->trHeapMemory()) TR::MemoryReference(t1Reg, (int32_t)offsetof(J9ArrayClass, componentType), TR::Compiler->om.sizeofReferenceAddress(), cg));
// here we may need to convert from J9Class pointer contained in t1Reg
// into class offset (so that we can compare two classes)
#else
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t1Reg,
new (cg->trHeapMemory()) TR::MemoryReference(dst, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), TR::Compiler->om.sizeofReferenceAddress(), cg));
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t2Reg,
new (cg->trHeapMemory()) TR::MemoryReference(src, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), TR::Compiler->om.sizeofReferenceAddress(), cg));
#endif
TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, t1Reg);
TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, t2Reg);

generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t1Reg,
new (cg->trHeapMemory()) TR::MemoryReference(t1Reg, (int32_t) offsetof(J9ArrayClass, componentType), TR::Compiler->om.sizeofReferenceAddress(), cg));
#endif
new (cg->trHeapMemory()) TR::MemoryReference(t1Reg, (int32_t)offsetof(J9ArrayClass, componentType), TR::Compiler->om.sizeofReferenceAddress(), cg));

TR_OpaqueClassBlock *rootClass = fej9->getSystemClassFromClassName("java/lang/Object", 16);
if (!comp->compileRelocatableCode() || comp->getOption(TR_UseSymbolValidationManager))
{
TR_OpaqueClassBlock *rootClass = fej9->getSystemClassFromClassName("java/lang/Object", 16);

if (cg->wantToPatchClassPointer(rootClass, node))
loadAddressConstantInSnippet(cg, node, (intptrj_t) rootClass, t3Reg, t4Reg,TR::InstOpCode::Op_load, false, NULL);
else
loadAddressConstant(cg, node, (intptrj_t) rootClass, t3Reg);
if (cg->wantToPatchClassPointer(rootClass, node))
{
loadAddressConstantInSnippet(cg, node, (intptrj_t) rootClass, t3Reg, t4Reg, TR::InstOpCode::Op_load, false, NULL);
}
else if (comp->compileRelocatableCode())
{
TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);
sym->setStaticAddress(rootClass);
sym->setClassObject();

loadAddressConstant(cg, node, (intptrj_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), t3Reg, NULL, false, TR_ClassAddress);
}
else
{
loadAddressConstant(cg, node, (intptrj_t) rootClass, t3Reg);
}

generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t3Reg);
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg);
}

generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t4Reg,
new (cg->trHeapMemory()) TR::MemoryReference(t2Reg, (int32_t) offsetof(J9Class, castClassCache), TR::Compiler->om.sizeofReferenceAddress(), cg));
Expand Down Expand Up @@ -3672,7 +3707,18 @@ static
void genInstanceOfOrCheckCastArbitraryClassTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR_OpaqueClassBlock *arbitraryClass, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg)
{
TR::Register *arbitraryClassReg = srm->findOrCreateScratchRegister();
loadAddressConstant(cg, node, (intptr_t)arbitraryClass, arbitraryClassReg);
if (cg->comp()->compileRelocatableCode() && cg->comp()->getOption(TR_UseSymbolValidationManager))
{
TR::StaticSymbol *sym = TR::StaticSymbol::create(cg->comp()->trHeapMemory(), TR::Address);
sym->setStaticAddress(arbitraryClass);
sym->setClassObject();

loadAddressConstant(cg, node, (intptr_t) new (cg->comp()->trHeapMemory()) TR::SymbolReference(cg->comp()->getSymRefTab(), sym), arbitraryClassReg, NULL, false, TR_ClassAddress);
}
else
{
loadAddressConstant(cg, node, (intptr_t)arbitraryClass, arbitraryClassReg);
}
genInstanceOfOrCheckCastClassEqualityTest(node, condReg, instanceClassReg, arbitraryClassReg, cg);
srm->reclaimScratchRegister(arbitraryClassReg);

Expand Down Expand Up @@ -4163,6 +4209,9 @@ TR::Register *J9::Power::TreeEvaluator::VMcheckcastEvaluator(TR::Node *node, TR:
if (newCheckCast)
return VMcheckcastEvaluator2(node, cg);

TR_ASSERT_FATAL(!cg->comp()->compileRelocatableCode() || !cg->comp()->getOption(TR_UseSymbolValidationManager),
"Old checkcast and instanceof evaluators are not supported under AOT");

TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
TR::Register *objReg, *castClassReg, *objClassReg, *scratch1Reg, *scratch2Reg, *cndReg;
TR::LabelSymbol *doneLabel, *callLabel, *callForInlineLabel, *nextTestLabel;
Expand Down Expand Up @@ -4568,6 +4617,9 @@ TR::Register *J9::Power::TreeEvaluator::VMinstanceOfEvaluator(TR::Node *node, TR
if (newInstanceOf)
return VMinstanceOfEvaluator2(node, cg);

TR_ASSERT_FATAL(!cg->comp()->compileRelocatableCode() || !cg->comp()->getOption(TR_UseSymbolValidationManager),
"Old checkcast and instanceof evaluators are not supported under AOT");

TR::Compilation *comp = cg->comp();
TR::Node *depNode;
int32_t depIndex;
Expand Down Expand Up @@ -4846,7 +4898,7 @@ TR::Register * J9::Power::TreeEvaluator::VMgenCoreInstanceofEvaluator(TR::Node *
if (castClassIsReferenceArray)
{
TR_OpaqueClassBlock * jlobjectclassBlock = fej9->getSystemClassFromClassName("java/lang/Object", 16);
J9Class* jlobjectarrayclassBlock = jlobjectclassBlock ? ((J9Class*) jlobjectclassBlock)->arrayClass : NULL;
J9Class* jlobjectarrayclassBlock = jlobjectclassBlock ? (J9Class*)fej9->getArrayClassFromComponentClass((TR_OpaqueClassBlock*)jlobjectclassBlock) : NULL;
if (jlobjectarrayclassBlock != NULL)
{
iCursor = loadAddressConstant(cg, node, (intptrj_t) (jlobjectarrayclassBlock), scratch1Reg, iCursor);
Expand Down Expand Up @@ -6329,7 +6381,7 @@ static void genInitObjectHeader(TR::Node *node, TR::Instruction *&iCursor, TR_Op

TR::Register * clzReg = classReg;

if (comp->compileRelocatableCode())
if (comp->compileRelocatableCode() && !comp->getOption(TR_UseSymbolValidationManager))
{
if (node->getOpCodeValue() == TR::newarray)
{
Expand Down Expand Up @@ -6929,6 +6981,17 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG
allocateSize = (allocateSize + fej9->getObjectAlignmentInBytes() - 1) & (-fej9->getObjectAlignmentInBytes());
}

if (comp->compileRelocatableCode())
{
switch (opCode)
{
case TR::New: break;
case TR::anewarray: break;
case TR::newarray: break;
default: doInline = false; break;
}
}

static int count = 0;
doInline = doInline && performTransformation(comp, "O^O <%3d> Inlining Allocation of %s [0x%p].\n", count++, node->getOpCode().getName(), node);

Expand Down Expand Up @@ -6980,7 +7043,26 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG

insertType = (opCode == TR::newarray && secondChild->getDataType() == TR::Int32 && secondChild->getReferenceCount() == 1 && secondChild->getOpCode().isLoadConst());

if (insertType)
if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager))
{
// IMPORTANT: secondChild actually references the J9Class of the array *elements* rather
// than the J9Class of the array itself; the new AOT infrastructure requires that
// classReg contain the J9Class of the array, so we have to actually construct a new
// loadaddr for that and then evaluate it instead of evaluating secondChild directly.
// Note that the original secondChild *must still be evaluated* as it will be used in
// the out-of-line code section.
TR::StaticSymbol *classSymbol = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);
classSymbol->setStaticAddress(clazz);
classSymbol->setClassObject();

cg->evaluate(secondChild);
secondChild = TR::Node::createWithSymRef(TR::loadaddr, 0,
new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), classSymbol));
secondChild->incReferenceCount();

classReg = cg->evaluate(secondChild);
}
else if (insertType)
{
classReg = cg->allocateRegister();
}
Expand Down Expand Up @@ -7061,7 +7143,7 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG
// Align the array if necessary.
if (doublewordAlign && !comp->getOptions()->realTimeGC())
genAlignArray(node, iCursor, isVariableLen, resReg, objectSize, dataBegin, dataSizeReg, condReg, tmp5Reg, tmp4Reg, cg);
if (cg->comp()->compileRelocatableCode() && opCode == TR::anewarray)
if (cg->comp()->compileRelocatableCode() && (opCode == TR::anewarray || comp->getOption(TR_UseSymbolValidationManager)))
genInitArrayHeader(node, iCursor, isVariableLen, clazz, classReg, resReg, zeroReg, condReg, enumReg, dataSizeReg, tmp5Reg, tmp4Reg, conditions, needZeroInit, cg);
else
genInitArrayHeader(node, iCursor, isVariableLen, clazz, NULL, resReg, zeroReg, condReg, enumReg, dataSizeReg,
Expand Down Expand Up @@ -7374,11 +7456,14 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG
if (cg->comp()->compileRelocatableCode() && (opCode == TR::New || opCode == TR::anewarray))
{
firstInstruction = firstInstruction->getNext();
TR_OpaqueClassBlock *classToValidate = clazz;

TR_RelocationRecordInformation *recordInfo = (TR_RelocationRecordInformation *) comp->trMemory()->allocateMemory(sizeof(TR_RelocationRecordInformation), heapAlloc);
recordInfo->data1 = allocateSize;
recordInfo->data2 = node->getInlinedSiteIndex();
recordInfo->data3 = (uintptr_t) callLabel;
recordInfo->data4 = (uintptr_t) firstInstruction;

TR::SymbolReference * classSymRef;
TR_ExternalRelocationTargetKind reloKind;

Expand All @@ -7391,6 +7476,15 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG
{
classSymRef = node->getSecondChild()->getSymbolReference();
reloKind = TR_VerifyRefArrayForAlloc;

if (comp->getOption(TR_UseSymbolValidationManager))
classToValidate = comp->fej9()->getComponentClassFromArrayClass(classToValidate);
}

if (comp->getOption(TR_UseSymbolValidationManager))
{
TR_ASSERT_FATAL(classToValidate, "classToValidate should not be NULL, clazz=%p\n", clazz);
recordInfo->data5 = (uintptr_t)classToValidate;
}

cg->addExternalRelocation(new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(firstInstruction, (uint8_t *) classSymRef, (uint8_t *) recordInfo, reloKind, cg),
Expand Down Expand Up @@ -7429,6 +7523,8 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG
else
{
cg->decReferenceCount(secondChild);
if (node->getSecondChild() != secondChild)
cg->decReferenceCount(node->getSecondChild());
if (classReg != secondChild->getRegister())
cg->stopUsingRegister(classReg);
}
Expand Down
Loading

0 comments on commit 394debd

Please sign in to comment.