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

Add full support for calls on z/OS and enable corresponding tests #4907

Merged
merged 17 commits into from
Apr 2, 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
2 changes: 1 addition & 1 deletion buildenv/jenkins/jobs/builds/Build-zos_390-64
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pipeline {
timestamps {
dir('build') {
echo 'Configure...'
sh '''cmake -Wdev -C../cmake/caches/Travis.cmake -DCMAKE_C_COMPILER=/bin/c89 -DCMAKE_CXX_COMPILER=/bin/xlc -DOMR_DDR=OFF -DOMR_THR_FORK_SUPPORT=0 ..'''
sh '''cmake -Wdev -C../cmake/caches/Travis.cmake -DCMAKE_C_COMPILER=/bin/c89 -DCMAKE_CXX_COMPILER=/bin/xlc -DOMR_DDR=OFF -DOMR_THR_FORK_SUPPORT=0 -DOMR_JITBUILDER_TEST_EXTENDED=1 ..'''
echo 'Compile...'
sh '''make -j4'''
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pipeline {
timestamps {
dir('build') {
echo 'Configure...'
sh '''cmake -Wdev -C../cmake/caches/Travis.cmake -DCMAKE_C_COMPILER=/bin/c89 -DCMAKE_CXX_COMPILER=/bin/xlc -DOMR_DDR=OFF -DOMR_THR_FORK_SUPPORT=0 ..'''
sh '''cmake -Wdev -C../cmake/caches/Travis.cmake -DCMAKE_C_COMPILER=/bin/c89 -DCMAKE_CXX_COMPILER=/bin/xlc -DOMR_DDR=OFF -DOMR_THR_FORK_SUPPORT=0 -DOMR_JITBUILDER_TEST_EXTENDED=1 ..'''
echo 'Compile...'
sh '''make -j4'''
}
Expand Down
75 changes: 37 additions & 38 deletions compiler/codegen/OMRCodeGenPhase.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -180,48 +180,44 @@ OMR::CodeGenPhase::performProcessRelocationsPhase(TR::CodeGenerator * cg, TR::Co
}

if (cg->getAheadOfTimeCompile() && (comp->getOption(TR_TraceRelocatableDataCG) || comp->getOption(TR_TraceRelocatableDataDetailsCG) || comp->getOption(TR_TraceReloCG)))
{
traceMsg(comp, "\n<relocatableDataCG>\n");
if (comp->getOption(TR_TraceRelocatableDataDetailsCG)) // verbose output
{
uint8_t * relocatableMethodCodeStart = (uint8_t *)comp->getRelocatableMethodCodeStart();
traceMsg(comp, "Code start = %8x, Method start pc = %x, Method start pc offset = 0x%x\n", relocatableMethodCodeStart, cg->getCodeStart(), cg->getCodeStart() - relocatableMethodCodeStart);
}
cg->getAheadOfTimeCompile()->dumpRelocationData();
traceMsg(comp, "</relocatableDataCG>\n");
}
{
traceMsg(comp, "\n<relocatableDataCG>\n");
if (comp->getOption(TR_TraceRelocatableDataDetailsCG)) // verbose output
{
uint8_t * relocatableMethodCodeStart = (uint8_t *)comp->getRelocatableMethodCodeStart();
traceMsg(comp, "Code start = %8x, Method start pc = %x, Method start pc offset = 0x%x\n", relocatableMethodCodeStart, cg->getCodeStart(), cg->getCodeStart() - relocatableMethodCodeStart);
}
cg->getAheadOfTimeCompile()->dumpRelocationData();
traceMsg(comp, "</relocatableDataCG>\n");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any chance you could split these changes into a separate commit? they interfere with appreciating the setup you've made here for a much better solution to the FD issue.

Copy link
Contributor Author

@fjeremic fjeremic Mar 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason this formatting change was made is because the indentation in it's current state is very confusing [1], and at first sight one may think the:

     if (comp->getCurrentMethod() == NULL)
        {
        comp->getMethodSymbol()->setMethodAddress(cg->getBinaryBufferStart());
        }

piece of code is guarded by the if (cg->getAheadOfTimeCompile() && check, which is what I first thought, but upon a more careful inspection the indentation was hiding this is not the case.

If you wish to view that commit without whitespace changes GitHub can help here:
ab6d6a4?w=1

[1] https://github.com/eclipse/omr/blob/31db81f3d84a431736ac7a9ff1b3980158fae258/compiler/codegen/OMRCodeGenPhase.cpp#L182-L202

Copy link
Contributor Author

@fjeremic fjeremic Mar 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, I think I agree. For history of commits it would be beneficial to split up formatting from actual changes.

I've split up the actual change into 6e902d5, where it belongs, and the formatting change into 27349e8. Hope that helps!


if (debug("dumpCodeSizes"))
{
diagnostic("%08d %s\n", cg->getCodeLength(), comp->signature());
}
if (debug("dumpCodeSizes"))
{
diagnostic("%08d %s\n", cg->getCodeLength(), comp->signature());
}

if (comp->getCurrentMethod() == NULL)
{
comp->getMethodSymbol()->setMethodAddress(cg->getBinaryBufferStart());
}
Comment on lines -199 to -202
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This piece of code was alarming to me. Does anyone know why this exists? And why is it guarded by a getCurrentMethod null check? When would this value ever be NULL?

TR_ASSERT(cg->getCodeLength() <= cg->getEstimatedCodeLength(),
"Method length estimate must be conservatively large\n"
" codeLength = %d, estimatedCodeLength = %d \n",
cg->getCodeLength(), cg->getEstimatedCodeLength()
);

TR_ASSERT(cg->getCodeLength() <= cg->getEstimatedCodeLength(),
"Method length estimate must be conservatively large\n"
" codeLength = %d, estimatedCodeLength = %d \n",
cg->getCodeLength(), cg->getEstimatedCodeLength()
);
// also trace the interal stack atlas
cg->getStackAtlas()->close(cg);

// also trace the interal stack atlas
cg->getStackAtlas()->close(cg);
TR::SimpleRegex * regex = comp->getOptions()->getSlipTrap();
if (regex && TR::SimpleRegex::match(regex, comp->getCurrentMethod()))
{
if (cg->comp()->target().is64Bit())
{
setDllSlip((char*)cg->getCodeStart(), (char*)cg->getCodeStart() + cg->getCodeLength(), "SLIPDLL64", comp);
}
else
{
setDllSlip((char*)cg->getCodeStart(), (char*)cg->getCodeStart() + cg->getCodeLength(), "SLIPDLL31", comp);
}
}

TR::SimpleRegex * regex = comp->getOptions()->getSlipTrap();
if (regex && TR::SimpleRegex::match(regex, comp->getCurrentMethod()))
{
if (cg->comp()->target().is64Bit())
{
setDllSlip((char*)cg->getCodeStart(),(char*)cg->getCodeStart()+cg->getCodeLength(),"SLIPDLL64", comp);
}
else
{
setDllSlip((char*)cg->getCodeStart(),(char*)cg->getCodeStart()+cg->getCodeLength(),"SLIPDLL31", comp);
}
}
if (comp->getOption(TR_TraceCG) || comp->getOptions()->getTraceCGOption(TR_TraceCGPostBinaryEncoding))
{
const char * title = "Post Relocation Instructions";
Expand Down Expand Up @@ -304,6 +300,9 @@ OMR::CodeGenPhase::performBinaryEncodingPhase(TR::CodeGenerator * cg, TR::CodeGe

cg->doBinaryEncoding();

// Instructions have been emitted, and now we know what the entry point is, so update the compilation method symbol
comp->getMethodSymbol()->setMethodAddress(cg->getCodeStart());

if (debug("verifyFinalNodeReferenceCounts"))
{
if (cg->getDebug())
Expand Down
4 changes: 2 additions & 2 deletions compiler/control/CompileMethod.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -379,7 +379,7 @@ compileMethodFromDetails(
// not ready yet...
//OMR::MethodMetaDataPOD *metaData = fe.createMethodMetaData(&compiler);

startPC = compiler.cg()->getCodeStart();
startPC = (uint8_t*)compiler.getMethodSymbol()->getMethodAddress();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the main change in thinking here. See the commit body (ab6d6a4) for a full description of why we made this change.

Copy link
Contributor Author

@fjeremic fjeremic Mar 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be explicit this is a design decision which I'd like @mstoodle and @aviansie-ben to comment on, and perhaps @Leonardo2718 as well. It is unfortunate we don't have a public API, because in that case getCodeStart would likely be a private API internal to the compiler, and we would only provide one public API to extract the "pointer to a function" we compiled with OMR.

Do we agree with this approach? If not, any suggestions on an alternative?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach seems fine to me.

I agree that having a single public API to extract the function pointer would be ideal. But I don't think that's a problem that needs to be solved here. The approach you've taken is reasonable given what we currently have, IMHO.

uint64_t translationTime = TR::Compiler->vm.getUSecClock() - translationStartTime;

if (TR::Options::isAnyVerboseOptionSet(TR_VerboseCompileEnd, TR_VerbosePerformance))
Expand Down
39 changes: 5 additions & 34 deletions compiler/z/codegen/OMRLinkage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2035,32 +2035,7 @@ OMR::Z::Linkage::buildArgs(TR::Node * callNode, TR::RegisterDependencyConditions
argSize += gprSize;
}

bool isXPLinkToPureOSLinkageCall = false;
if (!self()->isFirstParmAtFixedOffset())
{
stackOffset = argSize;
}
else
{
stackOffset = self()->getOffsetToFirstParm();

if (isXPLinkToPureOSLinkageCall)
{
// Load argument list (GPR1) pointer here in XPLink to OS linkage call
// The OS linkage argument list is embedded in the XPLink outbound argument area
// at offset 8 instead of 0 (to bypass collision with long displacement slot)
TR::Register *r1Reg = self()->cg()->allocateRegister();
if (stackOffset == self()->getOffsetToLongDispSlot())
{
stackOffset += 8; // avoid first parm at long displacement slot
}
TR::RealRegister * stackPtr = self()->getNormalStackPointerRealRegister();
generateRXInstruction(self()->cg(), TR::InstOpCode::LA, callNode, r1Reg,
generateS390MemoryReference(stackPtr, stackOffset, self()->cg()));
dependencies->addPreCondition(r1Reg, TR::RealRegister::GPR1);
self()->cg()->stopUsingRegister(r1Reg);
}
}
stackOffset = self()->isFirstParmAtFixedOffset() ? self()->getOffsetToFirstParm() : argSize;

//store env register
stackOffset = self()->storeExtraEnvRegForBuildArgs(callNode, self(), dependencies, isFastJNI, stackOffset, gprSize, numIntegerArgs);
Expand Down Expand Up @@ -2114,28 +2089,24 @@ OMR::Z::Linkage::buildArgs(TR::Node * callNode, TR::RegisterDependencyConditions

if (self()->isSkipGPRsForFloatParms())
{
if (numIntegerArgs < self()->getNumIntegerArgumentRegisters())
{
numIntegerArgs++;
}
numIntegerArgs++;
}
break;
}
case TR::Double:
#ifdef J9_PROJECT_SPECIFIC
case TR::DecimalDouble:
#endif
argRegister = self()->pushArg(callNode, child, numIntegerArgs, numFloatArgs, &stackOffset, dependencies);

numFloatArgs++;

if (self()->isSkipGPRsForFloatParms())
{
if (numIntegerArgs < self()->getNumIntegerArgumentRegisters())
{
numIntegerArgs += (self()->cg()->comp()->target().is64Bit()) ? 1 : 2;
}
numIntegerArgs += (self()->cg()->comp()->target().is64Bit()) ? 1 : 2;
}
break;
#ifdef J9_PROJECT_SPECIFIC
case TR::DecimalLongDouble:
if (numFloatArgs%2 == 1)
{ // need to skip fp arg 'hole' for long double arg
Expand Down
110 changes: 91 additions & 19 deletions compiler/z/codegen/SystemLinkagezOS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,11 @@ void TR::S390zOSSystemLinkage::createPrologue(TR::Instruction* cursor)

TR::CodeGenerator* cg = self()->cg();

_xplinkFunctionDescriptorSnippet = new (self()->trHeapMemory()) XPLINKFunctionDescriptorSnippet(cg);
_ppa1Snippet = new (self()->trHeapMemory()) TR::PPA1Snippet(cg, this);
_ppa2Snippet = new (self()->trHeapMemory()) TR::PPA2Snippet(cg, this);

cg->addSnippet(_xplinkFunctionDescriptorSnippet);
cg->addSnippet(_ppa1Snippet);
cg->addSnippet(_ppa2Snippet);

Expand Down Expand Up @@ -527,8 +529,6 @@ TR::S390zOSSystemLinkage::generateInstructionsForCall(TR::Node * callNode, TR::R
TR::Register * methodAddressReg, TR::Register * javaLitOffsetReg, TR::LabelSymbol * returnFromJNICallLabel,
TR::S390JNICallDataSnippet * jniCallDataSnippet, bool isJNIGCPoint)
{
TR::CodeGenerator * codeGen = cg();

// WCode specific
//
// There are 4 cases for outgoing branch sequences
Expand All @@ -551,40 +551,61 @@ TR::S390zOSSystemLinkage::generateInstructionsForCall(TR::Node * callNode, TR::R
// a) disp is an offset in the environment (aka ADA) containing the
// function descriptor body (i.e. not pointer to function descriptor)
TR_XPLinkCallTypes callType;

TR::Register* aeReg = deps->searchPostConditionRegister(getENVPointerRegister());
TR::Register* epReg = deps->searchPostConditionRegister(getEntryPointRegister());
TR::Register* raReg = deps->searchPostConditionRegister(getReturnAddressRegister());

// Find GPR6 (xplink) or GPR15 (os linkage) in post conditions
TR::Register * systemEntryPointRegister = deps->searchPostConditionRegister(getEntryPointRegister());
// Find GPR7 (xplik) or GPR14 (os linkage) in post conditions
TR::Register * systemReturnAddressRegister = deps->searchPostConditionRegister(getReturnAddressRegister());

TR::RegisterDependencyConditions * preDeps = new (trHeapMemory()) TR::RegisterDependencyConditions(deps->getPreConditions(), NULL, deps->getAddCursorForPre(), 0, cg());
TR::RegisterDependencyConditions* preDeps = new (trHeapMemory()) TR::RegisterDependencyConditions(deps->getPreConditions(), NULL, deps->getAddCursorForPre(), 0, cg());
TR::RegisterDependencyConditions* postDeps = new (trHeapMemory()) TR::RegisterDependencyConditions(NULL, deps->getPostConditions(), 0, deps->getAddCursorForPost(), cg());

if (callNode->getOpCode().isIndirect())
{
generateRRInstruction(cg(), InstOpCode::BASR, callNode, systemReturnAddressRegister, systemEntryPointRegister, preDeps);
TR::Register* targetAddress = cg()->evaluate(callNode->getFirstChild());

generateRSInstruction(cg(), TR::InstOpCode::getLoadMultipleOpCode(), callNode, aeReg, epReg, generateS390MemoryReference(targetAddress, 0, cg()));
generateRRInstruction(cg(), InstOpCode::BASR, callNode, raReg, epReg, preDeps);
callType = TR_XPLinkCallType_BASR;
}
else
{
TR::SymbolReference* callSymRef = callNode->getSymbolReference();
TR::Symbol* callSymbol = callSymRef->getSymbol();

if (comp()->isRecursiveMethodTarget(callSymbol))
{
// No need to load the environment or the entry point for recursive calls because these values are not used
// within OMR compiled methods
TR::Instruction* callInstr = new (cg()->trHeapMemory()) TR::S390RILInstruction(TR::InstOpCode::BRASL, callNode, raReg, callSymbol, callSymRef, cg());
callInstr->setDependencyConditions(preDeps);
}
else
{
struct FunctionDescriptor
{
void* environment;
void* func;
};

FunctionDescriptor* fd = reinterpret_cast<FunctionDescriptor*>(callSymbol->castToMethodSymbol()->getMethodAddress());

TR::SymbolReference *callSymRef = callNode->getSymbolReference();
TR::Symbol *callSymbol = callSymRef->getSymbol();
genLoadAddressConstant(cg(), callNode, reinterpret_cast<uintptr_t>(fd), epReg);
generateRSInstruction(cg(), TR::InstOpCode::getLoadMultipleOpCode(), callNode, aeReg, epReg, generateS390MemoryReference(epReg, 0, cg()));

TR::Instruction* callInstr = new (cg()->trHeapMemory()) TR::S390RILInstruction(TR::InstOpCode::BRASL, callNode, raReg, fd->func, callSymRef, cg());
callInstr->setDependencyConditions(preDeps);
}

TR::Instruction * callInstr = new (cg()->trHeapMemory()) TR::S390RILInstruction(TR::InstOpCode::BRASL, callNode, systemReturnAddressRegister, callSymbol, callSymRef, cg());
callInstr->setDependencyConditions(preDeps);
callType = TR_XPLinkCallType_BRASL7;
}

auto cursor = generateS390LabelInstruction(codeGen, InstOpCode::LABEL, callNode, returnFromJNICallLabel);
auto cursor = generateS390LabelInstruction(cg(), InstOpCode::LABEL, callNode, returnFromJNICallLabel);

genCallNOPAndDescriptor(cursor, callNode, callNode, callType);

// Append post-dependencies after NOP
TR::LabelSymbol * afterNOP = generateLabelSymbol(cg());
TR::RegisterDependencyConditions * postDeps =
new (trHeapMemory()) TR::RegisterDependencyConditions(NULL,
deps->getPostConditions(), 0, deps->getAddCursorForPost(), cg());
generateS390LabelInstruction(codeGen, InstOpCode::LABEL, callNode, afterNOP, postDeps);
TR::LabelSymbol* depsLabel = generateLabelSymbol(cg());
generateS390LabelInstruction(cg(), InstOpCode::LABEL, callNode, depsLabel, postDeps);
}
TR::LabelSymbol*
TR::S390zOSSystemLinkage::getEntryPointMarkerLabel() const
Expand Down Expand Up @@ -1117,3 +1138,54 @@ TR::S390zOSSystemLinkage::XPLINKCallDescriptorRelocation::apply(TR::CodeGenerato
uint8_t* p = getUpdateLocation();
*reinterpret_cast<int16_t*>(p) = static_cast<int16_t>(offsetToCallDescriptor);
}

TR::S390zOSSystemLinkage::XPLINKFunctionDescriptorSnippet::XPLINKFunctionDescriptorSnippet(TR::CodeGenerator* cg)
:
TR::S390ConstantDataSnippet(cg, NULL, NULL, cg->comp()->target().is32Bit() ? 8 : 16)
{
if (cg->comp()->target().is32Bit())
{
*(reinterpret_cast<uint32_t*>(_value) + 0) = 0;
*(reinterpret_cast<uint32_t*>(_value) + 1) = 0;
}
else
{
*(reinterpret_cast<uint64_t*>(_value) + 0) = 0;
*(reinterpret_cast<uint64_t*>(_value) + 1) = 0;
}
}

uint8_t*
TR::S390zOSSystemLinkage::XPLINKFunctionDescriptorSnippet::emitSnippetBody()
{
uint8_t* cursor = cg()->getBinaryBufferCursor();

// TODO: We should not have to do this here. This should be done by the caller.
getSnippetLabel()->setCodeLocation(cursor);

// Update the method symbol address to point to the function descriptor
cg()->comp()->getMethodSymbol()->setMethodAddress(cursor);

if (cg()->comp()->target().is32Bit())
{
// Address of function's environment
*reinterpret_cast<uint32_t*>(cursor) = 0;
cursor += sizeof(uint32_t);

// Function of function
*reinterpret_cast<uint32_t**>(cursor) = reinterpret_cast<uint32_t*>(cg()->getCodeStart());
cursor += sizeof(uint32_t);
}
else
{
// Address of function's environment
*reinterpret_cast<uint64_t*>(cursor) = 0;
cursor += sizeof(uint64_t);

// Function of function
*reinterpret_cast<uint64_t**>(cursor) = reinterpret_cast<uint64_t*>(cg()->getCodeStart());
cursor += sizeof(uint64_t);
}

return cursor;
}
19 changes: 19 additions & 0 deletions compiler/z/codegen/SystemLinkagezOS.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "codegen/SystemLinkage.hpp"
#include "codegen/snippet/PPA1Snippet.hpp"
#include "codegen/snippet/PPA2Snippet.hpp"
#include "codegen/ConstantDataSnippet.hpp"
#include "env/TRMemory.hpp"
#include "env/jittypes.h"
#include "il/DataTypes.hpp"
Expand Down Expand Up @@ -105,6 +106,23 @@ class S390zOSSystemLinkage : public TR::SystemLinkage
TR::Instruction* _nop;
};

/** \brief
*
* Represents the XPLINK function descriptor which is a data structure that represents the address of a function
* retrieved via the C '&' operator. The data structure holds the actual value of the execution entry point of the
* function it describes.
*
* [1] https://www-01.ibm.com/servers/resourcelink/svc00100.nsf/pages/zOSV2R3SA380688/$file/ceev100_v2r3.pdf (page 140)
*/
class XPLINKFunctionDescriptorSnippet : public TR::S390ConstantDataSnippet
{
public:

XPLINKFunctionDescriptorSnippet(TR::CodeGenerator* cg);

virtual uint8_t* emitSnippetBody();
};

public:

/** \brief
Expand Down Expand Up @@ -174,6 +192,7 @@ class S390zOSSystemLinkage : public TR::SystemLinkage
TR::LabelSymbol* _entryPointMarkerLabel;
TR::LabelSymbol* _stackPointerUpdateLabel;

XPLINKFunctionDescriptorSnippet* _xplinkFunctionDescriptorSnippet;
TR::PPA1Snippet* _ppa1Snippet;
TR::PPA2Snippet* _ppa2Snippet;
};
Expand Down
Loading