Path: blob/master/runtime/compiler/z/codegen/J9TreeEvaluator.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2000, 2022 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122//On zOS XLC linker can't handle files with same name at link time23//This workaround with pragma is needed. What this does is essentially24//give a different name to the codesection (csect) for this file. So it25//doesn't conflict with another file with same name.26#pragma csect(CODE,"TRJ9ZTreeEvalBase#C")27#pragma csect(STATIC,"TRJ9ZTreeEvalBase#S")28#pragma csect(TEST,"TRJ9ZTreeEvalBase#T")2930#include <algorithm>31#include <limits.h>32#include <math.h>33#include <stdint.h>34#include "j9.h"35#include "j9cfg.h"36#include "j9consts.h"37#include "omrmodroncore.h"38#include "thrdsup.h"39#include "thrtypes.h"40#include "codegen/AheadOfTimeCompile.hpp"41#include "codegen/CodeGenerator.hpp"42#include "codegen/CodeGenerator_inlines.hpp"43#include "codegen/J9WatchedStaticFieldSnippet.hpp"44#include "codegen/Linkage_inlines.hpp"45#include "codegen/Machine.hpp"46#include "codegen/S390CHelperLinkage.hpp"47#include "codegen/S390PrivateLinkage.hpp"48#include "codegen/TreeEvaluator.hpp"49#include "compile/ResolvedMethod.hpp"50#include "compile/VirtualGuard.hpp"51#include "env/CompilerEnv.hpp"52#include "env/IO.hpp"53#include "env/jittypes.h"54#include "env/VMJ9.h"55#include "il/DataTypes.hpp"56#include "il/LabelSymbol.hpp"57#include "il/Node.hpp"58#include "il/Node_inlines.hpp"59#include "il/ResolvedMethodSymbol.hpp"60#include "il/RegisterMappedSymbol.hpp"61#include "il/ParameterSymbol.hpp"62#include "il/StaticSymbol.hpp"63#include "il/Symbol.hpp"64#include "il/TreeTop.hpp"65#include "il/TreeTop_inlines.hpp"66#include "infra/Bit.hpp"67#include "OMR/Bytes.hpp"68#include "ras/Delimiter.hpp"69#include "ras/DebugCounter.hpp"70#include "env/VMJ9.h"71#include "z/codegen/J9S390Snippet.hpp"72#include "z/codegen/BinaryCommutativeAnalyser.hpp"73#include "z/codegen/S390J9CallSnippet.hpp"74#include "z/codegen/ForceRecompilationSnippet.hpp"75#include "z/codegen/ReduceSynchronizedFieldLoad.hpp"76#include "z/codegen/S390Evaluator.hpp"77#include "z/codegen/S390GenerateInstructions.hpp"78#include "z/codegen/S390HelperCallSnippet.hpp"79#include "z/codegen/S390Instruction.hpp"80#include "z/codegen/S390Recompilation.hpp"81#include "z/codegen/S390Register.hpp"82#include "z/codegen/SystemLinkage.hpp"83#include "runtime/J9Profiler.hpp"8485/*86* List of functions that is needed by J9 Specific Evaluators that were moved from codegen.87* Since other evaluators in codegen still calls these, extern here in order to call them.88*/89extern void updateReferenceNode(TR::Node * node, TR::Register * reg);90extern void killRegisterIfNotLocked(TR::CodeGenerator * cg, TR::RealRegister::RegNum reg, TR::Instruction * instr , TR::RegisterDependencyConditions * deps = NULL);91extern TR::Register * iDivRemGenericEvaluator(TR::Node * node, TR::CodeGenerator * cg, bool isDivision, TR::MemoryReference * divchkDivisorMR);92extern TR::Instruction * generateS390CompareOps(TR::Node * node, TR::CodeGenerator * cg, TR::InstOpCode::S390BranchCondition fBranchOpCond, TR::InstOpCode::S390BranchCondition rBranchOpCond, TR::LabelSymbol * targetLabel);9394void95J9::Z::TreeEvaluator::inlineEncodeASCII(TR::Node *node, TR::CodeGenerator *cg)96{97// tree looks as follows:98// encodeASCIISymbol99// input ptr100// output ptr101// input length (in elements)102//103// The original Java loop that this IL is inlining is found in StringCoding.encodeASCII:104/* if (coder == LATIN1) {105byte[] dst = new byte[val.length];106for (int i = 0; i < val.length; i++) {107if (val[i] < 0) {108dst[i] = '?';109} else {110dst[i] = val[i];111}112}113return dst;114}115*/116// Get the children117TR::Register *inputPtrReg = cg->gprClobberEvaluate(node->getChild(0));118TR::Register *outputPtrReg = cg->gprClobberEvaluate(node->getChild(1));119TR::Register *inputLengthRegister = cg->evaluate(node->getChild(2));120121TR::LabelSymbol *processMultiple16CharsStart = generateLabelSymbol(cg);122TR::LabelSymbol *processMultiple16CharsEnd = generateLabelSymbol(cg);123124TR::LabelSymbol *processSaturatedInput1 = generateLabelSymbol(cg);125126TR::LabelSymbol *cFlowRegionEnd = generateLabelSymbol(cg);127128TR::Register *vInput1 = cg->allocateRegister(TR_VRF);129TR::Register *vRange = cg->allocateRegister(TR_VRF);130TR::Register *vRangeControl = cg->allocateRegister(TR_VRF);131TR::Register *numCharsLeftToProcess = cg->allocateRegister();132TR::Register *firstSaturatedCharacter = cg->allocateRegister(TR_VRF);133134uint32_t saturatedRange = 127;135uint8_t saturatedRangeControl = 0x20; // > comparison136137// Replicate the limit character and comparison controller into vector registers138generateVRIaInstruction(cg, TR::InstOpCode::VREPI, node, vRange, saturatedRange, 0);139generateVRIaInstruction(cg, TR::InstOpCode::VREPI, node, vRangeControl, saturatedRangeControl, 0);140141// Copy length into numCharsLeftToProcess142generateRRInstruction(cg, TR::InstOpCode::LR, node, numCharsLeftToProcess, inputLengthRegister);143144// Branch to the end of this section if there are less than 16 chars left to process145generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, numCharsLeftToProcess, 16, TR::InstOpCode::COND_BL, processMultiple16CharsEnd, false, false);146147generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processMultiple16CharsStart);148processMultiple16CharsStart->setStartInternalControlFlow();149150generateVRXInstruction(cg, TR::InstOpCode::VL, node, vInput1, generateS390MemoryReference(inputPtrReg, 0, cg));151// Check for vector saturation and branch to copy the unsaturated bytes152// VSTRC here will do an unsigned comparison and set the CC if any byte in the input vector is above 127.153// If all numbers are below 128, then we can do a straight copy of the 16 bytes. If not, then we branch to154// processSaturatedInput1 label that corrects the first 'bad' character and stores all characters up to and including the 'bad' character155// in the output destination. Then we branch back to this mainline loop and continue processing the rest of the array.156// The penalty for encountering 1 or more bad characters in a row can be big, but we bet that such cases are not157// common.158generateVRRdInstruction(cg, TR::InstOpCode::VSTRC, node, firstSaturatedCharacter, vInput1, vRange, vRangeControl, 0x1, 0);159// If atleast one bad character was found, CC=1. So branch to handle this case.160generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC1, node, processSaturatedInput1);161162// If we didn't take the branch above, then all 16 bytes can be copied directly over.163generateVRXInstruction(cg, TR::InstOpCode::VST, node, vInput1, generateS390MemoryReference(outputPtrReg, 0, cg));164165// Update the counters166generateRXInstruction(cg, TR::InstOpCode::getLoadAddressOpCode(), node, outputPtrReg, generateS390MemoryReference(outputPtrReg, 16, cg));167generateRXInstruction(cg, TR::InstOpCode::getLoadAddressOpCode(), node, inputPtrReg, generateS390MemoryReference(inputPtrReg, 16, cg));168generateRILInstruction(cg, TR::InstOpCode::SLFI, node, numCharsLeftToProcess, 16);169170// Branch back up if we still have more than 16 characters to process.171generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, numCharsLeftToProcess, 15, TR::InstOpCode::COND_BH, processMultiple16CharsStart, false, false);172173generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processMultiple16CharsEnd);174175// start of sequence to process under 16 characters176177// numCharsLeftToProcess holds length of final load.178// Branch to the end if there is no residue179generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, numCharsLeftToProcess, 0, TR::InstOpCode::COND_BE, cFlowRegionEnd, false, false);180181// Zero out the input register to avoid invalid VSTRC result182generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, vInput1, 0, 0 /*unused*/);183184// VLL and VSTL work on indices so we must subtract 1185TR::Register *numCharsLeftToProcessMinus1 = cg->allocateRegister();186// Due to the check above, the value in numCharsLeftToProcessMinus1 is guaranteed to be 0 or higher.187generateRIEInstruction(cg, TR::InstOpCode::AHIK, node, numCharsLeftToProcessMinus1, numCharsLeftToProcess, -1);188// Load residue bytes and check for saturation189generateVRSbInstruction(cg, TR::InstOpCode::VLL, node, vInput1, numCharsLeftToProcessMinus1, generateS390MemoryReference(inputPtrReg, 0, cg));190191// Check for vector saturation and branch to copy the unsaturated bytes192generateVRRdInstruction(cg, TR::InstOpCode::VSTRC, node, firstSaturatedCharacter, vInput1, vRange, vRangeControl, 0x1, 0);193generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC1, node, processSaturatedInput1);194195// If no bad characters found, the store with length.196generateVRSbInstruction(cg, TR::InstOpCode::VSTL, node, vInput1, numCharsLeftToProcessMinus1, generateS390MemoryReference(outputPtrReg, 0, cg), 0);197// Branch to end.198generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);199200// Encountered an out of range character via the VSTRC instruction. Find it, replace it with '?', then jump back to mainline201// to continue processing. This sequence is not the most efficient and hitting it one or more times can be expensive,202// but we bet that this won't happen often for the targeted workload.203// Algorithm works as follows:204// First store upto and not including the bad character.205// Then store '?' in place for the bad character.206// Then, update the counters with the number of characters we have processed.207// Then go back to mainline code. Where we jump to depends on how many characters are left to process.208generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processSaturatedInput1);209210TR::Register *firstSaturatedCharacterGR = cg->allocateRegister();211// Extract the index of the first saturated char in the 2nd vector register212generateVRScInstruction(cg, TR::InstOpCode::VLGV, node, firstSaturatedCharacterGR, firstSaturatedCharacter, generateS390MemoryReference(7, cg), 0);213214// Needed as VSTL operate on 0-based index.215TR::Register *firstSaturatedCharacterMinus1GR = cg->allocateRegister();216217generateRIEInstruction(cg, TR::InstOpCode::AHIK, node, firstSaturatedCharacterMinus1GR, firstSaturatedCharacterGR, -1);218219// If the result is less than 0, then it means the first character is saturated. So skip storing any good characters and jump to fixing the bad220// character.221TR::LabelSymbol *fixReplacementCharacter = generateLabelSymbol(cg);222generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC1, node, fixReplacementCharacter);223224// Copy only the unsaturated results using the index we calculated earlier225generateVRSbInstruction(cg, TR::InstOpCode::VSTL, node, vInput1, firstSaturatedCharacterMinus1GR, generateS390MemoryReference(outputPtrReg, 0, cg), 0);226generateRRInstruction(cg, cg->comp()->target().is64Bit() ? TR::InstOpCode::AGFR : TR::InstOpCode::AR, node, outputPtrReg, firstSaturatedCharacterGR);227228generateS390LabelInstruction(cg, TR::InstOpCode::label, node, fixReplacementCharacter);229const uint32_t replacementCharacter = 63;230generateSIInstruction(cg, TR::InstOpCode::MVI, node, generateS390MemoryReference(outputPtrReg, 0, cg), replacementCharacter);231232generateRILInstruction(cg, cg->comp()->target().is64Bit() ? TR::InstOpCode::AGFI : TR::InstOpCode::AFI, node, outputPtrReg, 1);233234// Now update the counters235generateRXInstruction(cg, TR::InstOpCode::getLoadAddressOpCode(), node, inputPtrReg, generateS390MemoryReference(inputPtrReg, firstSaturatedCharacterGR, 1, cg));236generateRILInstruction(cg, TR::InstOpCode::AFI, node, numCharsLeftToProcess, -1);237generateRRInstruction(cg, TR::InstOpCode::SR, node, numCharsLeftToProcess, firstSaturatedCharacterGR);238239// Counters have been updated. Now branch back to mainline. Where we branch depends on how many chars are left.240generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, numCharsLeftToProcess, 15, TR::InstOpCode::COND_BH, processMultiple16CharsStart, false, false);241generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, processMultiple16CharsEnd);242243TR::RegisterDependencyConditions* dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 11, cg);244dependencies->addPostConditionIfNotAlreadyInserted(vInput1, TR::RealRegister::AssignAny);245dependencies->addPostConditionIfNotAlreadyInserted(firstSaturatedCharacter, TR::RealRegister::AssignAny);246dependencies->addPostConditionIfNotAlreadyInserted(vRange, TR::RealRegister::AssignAny);247dependencies->addPostConditionIfNotAlreadyInserted(vRangeControl, TR::RealRegister::AssignAny);248dependencies->addPostConditionIfNotAlreadyInserted(outputPtrReg, TR::RealRegister::AssignAny);249dependencies->addPostConditionIfNotAlreadyInserted(inputPtrReg, TR::RealRegister::AssignAny);250dependencies->addPostConditionIfNotAlreadyInserted(numCharsLeftToProcess, TR::RealRegister::AssignAny);251dependencies->addPostConditionIfNotAlreadyInserted(numCharsLeftToProcessMinus1, TR::RealRegister::AssignAny);252dependencies->addPostConditionIfNotAlreadyInserted(inputLengthRegister, TR::RealRegister::AssignAny);253dependencies->addPostConditionIfNotAlreadyInserted(firstSaturatedCharacterGR, TR::RealRegister::AssignAny);254dependencies->addPostConditionIfNotAlreadyInserted(firstSaturatedCharacterMinus1GR, TR::RealRegister::AssignAny);255256generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, dependencies);257cFlowRegionEnd->setEndInternalControlFlow();258259cg->decReferenceCount(node->getChild(0));260cg->decReferenceCount(node->getChild(1));261cg->decReferenceCount(node->getChild(2));262263cg->stopUsingRegister(vInput1);264cg->stopUsingRegister(firstSaturatedCharacter);265cg->stopUsingRegister(vRange);266cg->stopUsingRegister(vRangeControl);267cg->stopUsingRegister(numCharsLeftToProcess);268cg->stopUsingRegister(numCharsLeftToProcessMinus1);269cg->stopUsingRegister(firstSaturatedCharacterGR);270cg->stopUsingRegister(firstSaturatedCharacterMinus1GR);271}272273TR::Register*274J9::Z::TreeEvaluator::inlineStringLatin1Inflate(TR::Node *node, TR::CodeGenerator *cg)275{276static bool disableStringInflate = feGetEnv("TR_DisableStringInflate") != NULL;277if (disableStringInflate)278{279return NULL;280}281TR_ASSERT_FATAL(cg->getSupportsInlineStringLatin1Inflate(), "This evaluator should only be triggered when inlining StringLatin1.inflate([BI[CII)V is enabled on Java 11 onwards!\n");282TR::Node *sourceArrayReferenceNode = node->getChild(0);283TR::Node *srcOffNode = node->getChild(1);284TR::Node *charArrayReferenceNode = node->getChild(2);285TR::Node *dstOffNode = node->getChild(3);286TR::Node *lenNode = node->getChild(4);287288TR::Register *lenRegister = cg->evaluate(lenNode);289TR::Register *sourceArrayReferenceRegister = cg->gprClobberEvaluate(sourceArrayReferenceNode);290TR::Register *srcOffRegister = cg->gprClobberEvaluate(srcOffNode);291TR::Register *charArrayReferenceRegister = cg->gprClobberEvaluate(charArrayReferenceNode);292TR::Register *dstOffRegister = cg->gprClobberEvaluate(dstOffNode);293294// Adjust the array reference (source and destination) with offset in advance295if (srcOffNode->getOpCodeValue() == TR::iconst)296{297if (srcOffNode->getInt() != 0)298{299generateRILInstruction(cg, TR::InstOpCode::AFI, node, sourceArrayReferenceRegister, srcOffNode->getInt());300}301}302else303{304generateRRInstruction(cg, TR::InstOpCode::AGFR, node, sourceArrayReferenceRegister, srcOffRegister);305}306307if (dstOffNode->getOpCodeValue() == TR::iconst)308{309if (dstOffNode->getInt() != 0)310{311generateRILInstruction(cg, TR::InstOpCode::AFI, node, charArrayReferenceRegister, dstOffNode->getInt() * 2);312}313}314else315{316generateRSInstruction(cg, TR::InstOpCode::SLAK, node, dstOffRegister, dstOffRegister, 1);317generateRRInstruction(cg, TR::InstOpCode::AGFR, node, charArrayReferenceRegister, dstOffRegister);318}319320// The vector tight loop (starting at vectorLoopStart label) overwrites sourceArrayReferenceRegister as it processes characters. So we keep a backup of the321// copy here so that we can refer to it when handling the residual digits after the tight loop is finished executing.322TR::Register *sourceArrayReferenceRegister2 = cg->allocateRegister();323generateRRInstruction(cg, TR::InstOpCode::LGR, node, sourceArrayReferenceRegister2, sourceArrayReferenceRegister);324325// charArrayReference is the destination array. Since the vector loop below processes 16 bytes into 16 chars per iteration, we will store 32 bytes per iteration.326// We use the `VST` instruction twice to store 16 bytes at a time. Hence, we need a "low" and "high" memref for the char array in order to store all 32 bytes per iteration327// of the vector loop.328TR::MemoryReference *charArrayReferenceMemRefLow = generateS390MemoryReference(charArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg);329TR::MemoryReference *charArrayReferenceMemRefHigh = generateS390MemoryReference(charArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 16, cg);330331// numCharsMinusResidue is used as a scratch register to hold temporary values throughout the algorithm.332TR::Register *numCharsMinusResidue = cg->allocateRegister();333generateRRInstruction(cg, TR::InstOpCode::LR, node, numCharsMinusResidue, lenRegister);334generateRILInstruction(cg, TR::InstOpCode::SLFI, node, numCharsMinusResidue, 16);335generateRRInstruction(cg, TR::InstOpCode::AR, node, numCharsMinusResidue, srcOffRegister);336337TR::LabelSymbol *cFlowRegionStart = generateLabelSymbol(cg);338cFlowRegionStart->setStartInternalControlFlow();339generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);340341TR::LabelSymbol *cFlowRegionEnd = generateLabelSymbol(cg);342TR::LabelSymbol *gprSequenceLabel = generateLabelSymbol(cg);343cFlowRegionEnd->setEndInternalControlFlow();344// Before starting the tight loop, check if length is 0. If so, then jump to end as there's no work to be done.345generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, lenRegister, 0, TR::InstOpCode::COND_BE, cFlowRegionEnd, false, false);346// Also check if length < 8. If yes, then jump to gprSequenceLabel to handle this case with regular GPRs for speed.347generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, lenRegister, 8, TR::InstOpCode::COND_BL, gprSequenceLabel, false, false);348349TR::LabelSymbol *vectorLoopStart = generateLabelSymbol(cg);350generateS390LabelInstruction(cg, TR::InstOpCode::label, node, vectorLoopStart);351TR::LabelSymbol *handleResidueLabel = generateLabelSymbol(cg);352353// We keep executing the vector tight loop below until only the residual characters remain to process.354generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CR, node, srcOffRegister, numCharsMinusResidue, TR::InstOpCode::COND_BH, handleResidueLabel, false, false);355TR::Register* registerV1 = cg->allocateRegister(TR_VRF);356TR::MemoryReference *sourceArrayMemRef = generateS390MemoryReference(sourceArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg);357// Do a vector load to batch process the characters.358generateVRXInstruction(cg, TR::InstOpCode::VL, node, registerV1, sourceArrayMemRef);359TR::Register* registerV2 = cg->allocateRegister(TR_VRF);360// Unpack the 1st and 2nd halves of the input vector. This will efectively inflate each character from 1 byte to 2 bytes.361generateVRRaInstruction(cg, TR::InstOpCode::VUPLH, node, registerV2, registerV1);362generateVRRaInstruction(cg, TR::InstOpCode::VUPLL, node, registerV1, registerV1);363364// Store all characters.365generateVRXInstruction(cg, TR::InstOpCode::VST, node, registerV2, charArrayReferenceMemRefLow);366generateVRXInstruction(cg, TR::InstOpCode::VST, node, registerV1, charArrayReferenceMemRefHigh);367368// Done storing 16 chars. Now do some bookkeeping and then branch back to start label.369generateRILInstruction(cg, TR::InstOpCode::AFI, node, srcOffRegister, 16);370generateRXInstruction(cg, TR::InstOpCode::getLoadAddressOpCode(), node, sourceArrayReferenceRegister, generateS390MemoryReference(sourceArrayReferenceRegister, 16, cg));371generateRXInstruction(cg, TR::InstOpCode::getLoadAddressOpCode(), node, charArrayReferenceRegister, generateS390MemoryReference(charArrayReferenceRegister, 32, cg));372generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, vectorLoopStart);373374// Once we reach this label, only the residual characters need to be processed.375generateS390LabelInstruction(cg, TR::InstOpCode::label, node, handleResidueLabel);376377TR::MemoryReference *sourceArrayMemRef2 = generateS390MemoryReference(sourceArrayReferenceRegister2, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg);378TR::MemoryReference *charArrayReferenceMemRefLow2 = generateS390MemoryReference(charArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg);379TR::MemoryReference *charArrayReferenceMemRefHigh2 = generateS390MemoryReference(charArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 16, cg);380381TR::Register *quoRegister = cg->allocateRegister();382// Do lenRegister / 16 to calculate remaining number of chars using the Divide Logical (DLR) instruction.383// The dividend in a DLR instruction is a 64-bit integer. The top half is in remRegister, and the bottom half is in quoRegister.384// In our case the dividend is always a 32-bit integer (i.e. the length of the array). So we must always zero out the top half (i.e. remRegister) in order to make sure the dividend is never corrupted.385// The bottom half doesn't need to be zeroed out because we move a 32-bit integer in it, and then never use that register again.386TR::Register *remRegister = cg->allocateRegister();387generateRRInstruction(cg, TR::InstOpCode::XGR, node, remRegister, remRegister);388TR::RegisterPair *divRegisterPair = cg->allocateConsecutiveRegisterPair(quoRegister, remRegister); // rem is legal even of the pair389generateRRInstruction(cg, TR::InstOpCode::LR, node, quoRegister, lenRegister);390TR::Register *tempReg = cg->allocateRegister();391generateRILInstruction(cg, TR::InstOpCode::LGFI, node, /*divisor*/ tempReg, 16);392generateRRInstruction(cg, TR::InstOpCode::DLR, node, divRegisterPair, tempReg/*divisor*/);393394// Branch to end if length was a multiple of 16. (We would have processed this in the vectorloop already).395generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, remRegister, 0, TR::InstOpCode::COND_BE, cFlowRegionEnd, false, false);396// Now do srcOffRegister = lenRegister - remRegister to position index at the next character that we need to copy.397generateRRRInstruction(cg, TR::InstOpCode::SRK, node, srcOffRegister, lenRegister, remRegister);398// Now add that result to the base register399generateRRInstruction(cg, TR::InstOpCode::AGFR, node, sourceArrayReferenceRegister2, srcOffRegister);400401// Now that you have the new index and the number of remaining characters, load those many chars into registerV1. We are guaranteed to have numChars < 16402//403// First load remainder (i.e. number of remaining chars) value into remRegister2 (Which is just a 0-index based version of remRegister).404// Then we subtract remRegister2 by 1 to get an indexed number. Then we use VLL to load the remaining bytes int registerV1.405TR::Register *remRegister2 = cg->allocateRegister();406generateRRInstruction(cg, TR::InstOpCode::LR, node, remRegister2, remRegister);407generateRILInstruction(cg, TR::InstOpCode::SLFI, node, remRegister2, 1);408generateVRSbInstruction(cg, TR::InstOpCode::VLL, node, registerV1, remRegister2, sourceArrayMemRef2);409// Now unpack the low order. If we have less than 8 chars to process, there will be zeros in the register410generateVRRaInstruction(cg, TR::InstOpCode::VUPLH, node, registerV2, registerV1);411// Multiply numChars remaining by 2 to get the number of bytes we need to write412generateRSInstruction(cg, TR::InstOpCode::SLAK, node, tempReg, remRegister, 1);413// Subtract one from tempReg since the byte position is 0 based.414generateRILInstruction(cg, TR::InstOpCode::SLFI, node, tempReg, 1);415generateVRSbInstruction(cg, TR::InstOpCode::VSTL, node, registerV2, tempReg, charArrayReferenceMemRefLow2, 0);416// Now subtract numChars by 8 and see if there's still more bytes left to write417generateRILInstruction(cg, TR::InstOpCode::SLFI, node, remRegister, 8);418generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, remRegister, 0, TR::InstOpCode::COND_BNH, cFlowRegionEnd, false, false);419// If we didn't branch, then there are still more characters to process, and the remaining amount is in remRegister.420// So unpack the characters and store back in memory421generateVRRaInstruction(cg, TR::InstOpCode::VUPLL, node, registerV1, registerV1);422generateRSInstruction(cg, TR::InstOpCode::SLAK, node, tempReg, remRegister, 1);423generateRILInstruction(cg, TR::InstOpCode::SLFI, node, tempReg, 1);424generateVRSbInstruction(cg, TR::InstOpCode::VSTL, node, registerV1, tempReg, charArrayReferenceMemRefHigh2, 0);425generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);426427// We should only end up here if we initially detect that the input string's length < 8.428// For the GPR sequence we simply load one byte at a time using LLC, then store it as a char.429// If we are here, then lenRegister is less than remaining chars is in numCharsMinusResidue.430generateS390LabelInstruction(cg, TR::InstOpCode::label, node, gprSequenceLabel);431432// Repurpose numCharsMinusResidue here as a temp/scratch reg.433generateRSInstruction(cg, TR::InstOpCode::SLAK, node, numCharsMinusResidue, lenRegister, 1);434generateRSInstruction(cg, TR::InstOpCode::SLAK, node, tempReg, lenRegister, 3);435generateRRInstruction(cg, TR::InstOpCode::AR, node, numCharsMinusResidue, tempReg);436437// First we figure out exactly how many chars are left.438generateRILInstruction(cg, TR::InstOpCode::LARL, node, tempReg, cFlowRegionEnd);439440generateRRInstruction(cg, TR::InstOpCode::SR, node, tempReg, numCharsMinusResidue);441TR::Instruction *cursor = generateS390RegInstruction(cg, TR::InstOpCode::BCR, node, tempReg);442((TR::S390RegInstruction *)cursor)->setBranchCondition(TR::InstOpCode::COND_BCR);443444// 7 chars left445generateRXInstruction(cg, TR::InstOpCode::LLC, node, tempReg, generateS390MemoryReference(sourceArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 6, cg));446generateRXInstruction(cg, TR::InstOpCode::STH, node, tempReg, generateS390MemoryReference(charArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 12, cg));447// 6 chars left448generateRXInstruction(cg, TR::InstOpCode::LLC, node, tempReg, generateS390MemoryReference(sourceArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 5, cg));449generateRXInstruction(cg, TR::InstOpCode::STH, node, tempReg, generateS390MemoryReference(charArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 10, cg));450// 5 chars left451generateRXInstruction(cg, TR::InstOpCode::LLC, node, tempReg, generateS390MemoryReference(sourceArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 4, cg));452generateRXInstruction(cg, TR::InstOpCode::STH, node, tempReg, generateS390MemoryReference(charArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 8, cg));453// 4 chars left454generateRXInstruction(cg, TR::InstOpCode::LLC, node, tempReg, generateS390MemoryReference(sourceArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 3, cg));455generateRXInstruction(cg, TR::InstOpCode::STH, node, tempReg, generateS390MemoryReference(charArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 6, cg));456// 3 chars left457generateRXInstruction(cg, TR::InstOpCode::LLC, node, tempReg, generateS390MemoryReference(sourceArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 2, cg));458generateRXInstruction(cg, TR::InstOpCode::STH, node, tempReg, generateS390MemoryReference(charArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 4, cg));459// 2 chars left460generateRXInstruction(cg, TR::InstOpCode::LLC, node, tempReg, generateS390MemoryReference(sourceArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 1, cg));461generateRXInstruction(cg, TR::InstOpCode::STH, node, tempReg, generateS390MemoryReference(charArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 2, cg));462// 1 chars left463generateRXInstruction(cg, TR::InstOpCode::LLC, node, tempReg, generateS390MemoryReference(sourceArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 0, cg));464generateRXInstruction(cg, TR::InstOpCode::STH, node, tempReg, generateS390MemoryReference(charArrayReferenceRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes() + 0, cg));465466TR::RegisterDependencyConditions* dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 14, cg);467dependencies->addPostConditionIfNotAlreadyInserted(sourceArrayReferenceRegister, TR::RealRegister::AssignAny);468dependencies->addPostConditionIfNotAlreadyInserted(lenRegister, TR::RealRegister::AssignAny);469dependencies->addPostConditionIfNotAlreadyInserted(srcOffRegister, TR::RealRegister::AssignAny);470dependencies->addPostConditionIfNotAlreadyInserted(dstOffRegister, TR::RealRegister::AssignAny);471dependencies->addPostConditionIfNotAlreadyInserted(charArrayReferenceRegister, TR::RealRegister::AssignAny);472dependencies->addPostConditionIfNotAlreadyInserted(numCharsMinusResidue, TR::RealRegister::AssignAny);473dependencies->addPostConditionIfNotAlreadyInserted(registerV1, TR::RealRegister::AssignAny);474dependencies->addPostConditionIfNotAlreadyInserted(registerV2, TR::RealRegister::AssignAny);475dependencies->addPostConditionIfNotAlreadyInserted(divRegisterPair, TR::RealRegister::EvenOddPair);476dependencies->addPostConditionIfNotAlreadyInserted(remRegister, TR::RealRegister::LegalEvenOfPair);477dependencies->addPostConditionIfNotAlreadyInserted(quoRegister, TR::RealRegister::LegalOddOfPair);478dependencies->addPostConditionIfNotAlreadyInserted(tempReg, TR::RealRegister::AssignAny);479dependencies->addPostConditionIfNotAlreadyInserted(sourceArrayReferenceRegister2, TR::RealRegister::AssignAny);480dependencies->addPostConditionIfNotAlreadyInserted(remRegister2, TR::RealRegister::AssignAny);481482generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, dependencies);483484cg->decReferenceCount(srcOffNode);485cg->decReferenceCount(dstOffNode);486cg->decReferenceCount(lenNode);487cg->decReferenceCount(sourceArrayReferenceNode);488cg->decReferenceCount(charArrayReferenceNode);489490cg->stopUsingRegister(remRegister2);491cg->stopUsingRegister(numCharsMinusResidue);492cg->stopUsingRegister(registerV1);493cg->stopUsingRegister(registerV2);494cg->stopUsingRegister(divRegisterPair);495cg->stopUsingRegister(tempReg);496cg->stopUsingRegister(sourceArrayReferenceRegister2);497return charArrayReferenceRegister;498}499500TR::Register*501J9::Z::TreeEvaluator::zdloadEvaluator(TR::Node *node, TR::CodeGenerator *cg)502{503return TR::TreeEvaluator::pdloadEvaluator(node, cg);504}505506TR::Register*507J9::Z::TreeEvaluator::zdloadiEvaluator(TR::Node *node, TR::CodeGenerator *cg)508{509return TR::TreeEvaluator::pdloadEvaluator(node, cg);510}511512TR::Register*513J9::Z::TreeEvaluator::zdstoreEvaluator(TR::Node *node, TR::CodeGenerator *cg)514{515return TR::TreeEvaluator::pdstoreEvaluator(node, cg);516}517518TR::Register*519J9::Z::TreeEvaluator::zdstoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg)520{521return TR::TreeEvaluator::pdstoreEvaluator(node, cg);522}523524TR::Register*525J9::Z::TreeEvaluator::zdsleLoadEvaluator(TR::Node *node, TR::CodeGenerator *cg)526{527return TR::TreeEvaluator::pdloadEvaluator(node, cg);528}529530TR::Register*531J9::Z::TreeEvaluator::zdslsLoadEvaluator(TR::Node *node, TR::CodeGenerator *cg)532{533return TR::TreeEvaluator::pdloadEvaluator(node, cg);534}535536TR::Register*537J9::Z::TreeEvaluator::zdstsLoadEvaluator(TR::Node *node, TR::CodeGenerator *cg)538{539return TR::TreeEvaluator::pdloadEvaluator(node, cg);540}541542TR::Register*543J9::Z::TreeEvaluator::zdsleLoadiEvaluator(TR::Node *node, TR::CodeGenerator *cg)544{545return TR::TreeEvaluator::pdloadEvaluator(node, cg);546}547548TR::Register*549J9::Z::TreeEvaluator::zdslsLoadiEvaluator(TR::Node *node, TR::CodeGenerator *cg)550{551return TR::TreeEvaluator::pdloadEvaluator(node, cg);552}553554TR::Register*555J9::Z::TreeEvaluator::zdstsLoadiEvaluator(TR::Node *node, TR::CodeGenerator *cg)556{557return TR::TreeEvaluator::pdloadEvaluator(node, cg);558}559560TR::Register*561J9::Z::TreeEvaluator::zdsleStoreEvaluator(TR::Node *node, TR::CodeGenerator *cg)562{563return TR::TreeEvaluator::pdstoreEvaluator(node, cg);564}565566TR::Register*567J9::Z::TreeEvaluator::zdslsStoreEvaluator(TR::Node *node, TR::CodeGenerator *cg)568{569return TR::TreeEvaluator::pdstoreEvaluator(node, cg);570}571572TR::Register*573J9::Z::TreeEvaluator::zdstsStoreEvaluator(TR::Node *node, TR::CodeGenerator *cg)574{575return TR::TreeEvaluator::pdstoreEvaluator(node, cg);576}577578TR::Register*579J9::Z::TreeEvaluator::zdsleStoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg)580{581return TR::TreeEvaluator::pdstoreEvaluator(node, cg);582}583584TR::Register*585J9::Z::TreeEvaluator::zdslsStoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg)586{587return TR::TreeEvaluator::pdstoreEvaluator(node, cg);588}589590TR::Register*591J9::Z::TreeEvaluator::zdstsStoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg)592{593return TR::TreeEvaluator::pdstoreEvaluator(node, cg);594}595596TR::Register*597J9::Z::TreeEvaluator::zd2zdsleEvaluator(TR::Node *node, TR::CodeGenerator *cg)598{599return TR::TreeEvaluator::zdsle2zdEvaluator(node, cg);600}601602TR::Register*603J9::Z::TreeEvaluator::zd2zdstsEvaluator(TR::Node *node, TR::CodeGenerator *cg)604{605return TR::TreeEvaluator::zd2zdslsEvaluator(node, cg);606}607608TR::Register*609J9::Z::TreeEvaluator::zdsle2pdEvaluator(TR::Node *node, TR::CodeGenerator *cg)610{611return TR::TreeEvaluator::unImpOpEvaluator(node, cg);612}613614TR::Register*615J9::Z::TreeEvaluator::zdsts2pdEvaluator(TR::Node *node, TR::CodeGenerator *cg)616{617return TR::TreeEvaluator::zdsls2pdEvaluator(node, cg);618}619620TR::Register*621J9::Z::TreeEvaluator::zdsts2zdEvaluator(TR::Node *node, TR::CodeGenerator *cg)622{623return TR::TreeEvaluator::zdsls2zdEvaluator(node, cg);624}625626TR::Register*627J9::Z::TreeEvaluator::pd2zdslsSetSignEvaluator(TR::Node *node, TR::CodeGenerator *cg)628{629return TR::TreeEvaluator::pd2zdslsEvaluator(node, cg);630}631632TR::Register*633J9::Z::TreeEvaluator::pd2zdstsEvaluator(TR::Node *node, TR::CodeGenerator *cg)634{635return TR::TreeEvaluator::pd2zdslsEvaluator(node, cg);636}637638TR::Register*639J9::Z::TreeEvaluator::pd2zdstsSetSignEvaluator(TR::Node *node, TR::CodeGenerator *cg)640{641return TR::TreeEvaluator::pd2zdslsEvaluator(node, cg);642}643644TR::Register*645J9::Z::TreeEvaluator::udLoadEvaluator(TR::Node *node, TR::CodeGenerator *cg)646{647return TR::TreeEvaluator::pdloadEvaluator(node, cg);648}649650TR::Register*651J9::Z::TreeEvaluator::udslLoadEvaluator(TR::Node *node, TR::CodeGenerator *cg)652{653return TR::TreeEvaluator::pdloadEvaluator(node, cg);654}655656TR::Register*657J9::Z::TreeEvaluator::udstLoadEvaluator(TR::Node *node, TR::CodeGenerator *cg)658{659return TR::TreeEvaluator::pdloadEvaluator(node, cg);660}661662TR::Register*663J9::Z::TreeEvaluator::udLoadiEvaluator(TR::Node *node, TR::CodeGenerator *cg)664{665return TR::TreeEvaluator::pdloadEvaluator(node, cg);666}667668TR::Register*669J9::Z::TreeEvaluator::udslLoadiEvaluator(TR::Node *node, TR::CodeGenerator *cg)670{671return TR::TreeEvaluator::pdloadEvaluator(node, cg);672}673674TR::Register*675J9::Z::TreeEvaluator::udstLoadiEvaluator(TR::Node *node, TR::CodeGenerator *cg)676{677return TR::TreeEvaluator::pdloadEvaluator(node, cg);678}679680TR::Register*681J9::Z::TreeEvaluator::udStoreEvaluator(TR::Node *node, TR::CodeGenerator *cg)682{683return TR::TreeEvaluator::pdstoreEvaluator(node, cg);684}685686TR::Register*687J9::Z::TreeEvaluator::udslStoreEvaluator(TR::Node *node, TR::CodeGenerator *cg)688{689return TR::TreeEvaluator::pdstoreEvaluator(node, cg);690}691692TR::Register*693J9::Z::TreeEvaluator::udstStoreEvaluator(TR::Node *node, TR::CodeGenerator *cg)694{695return TR::TreeEvaluator::pdstoreEvaluator(node, cg);696}697698TR::Register*699J9::Z::TreeEvaluator::udStoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg)700{701return TR::TreeEvaluator::pdstoreEvaluator(node, cg);702}703704TR::Register*705J9::Z::TreeEvaluator::udslStoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg)706{707return TR::TreeEvaluator::pdstoreEvaluator(node, cg);708}709710TR::Register*711J9::Z::TreeEvaluator::udstStoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg)712{713return TR::TreeEvaluator::pdstoreEvaluator(node, cg);714}715716TR::Register*717J9::Z::TreeEvaluator::pd2udstEvaluator(TR::Node *node, TR::CodeGenerator *cg)718{719return TR::TreeEvaluator::pd2udslEvaluator(node, cg);720}721722TR::Register*723J9::Z::TreeEvaluator::udsl2udEvaluator(TR::Node *node, TR::CodeGenerator *cg)724{725return TR::TreeEvaluator::unImpOpEvaluator(node, cg);726}727728TR::Register*729J9::Z::TreeEvaluator::udst2udEvaluator(TR::Node *node, TR::CodeGenerator *cg)730{731return TR::TreeEvaluator::unImpOpEvaluator(node, cg);732}733734TR::Register*735J9::Z::TreeEvaluator::udst2pdEvaluator(TR::Node *node, TR::CodeGenerator *cg)736{737return TR::TreeEvaluator::udsl2pdEvaluator(node, cg);738}739740TR::Register*741J9::Z::TreeEvaluator::pdloadiEvaluator(TR::Node *node, TR::CodeGenerator *cg)742{743return TR::TreeEvaluator::pdloadEvaluator(node, cg);744}745746TR::Register*747J9::Z::TreeEvaluator::pdstoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg)748{749return TR::TreeEvaluator::pdstoreEvaluator(node, cg);750}751752TR::Register*753J9::Z::TreeEvaluator::pddivEvaluator(TR::Node *node, TR::CodeGenerator *cg)754{755return TR::TreeEvaluator::pddivremEvaluator(node, cg);756}757758TR::Register*759J9::Z::TreeEvaluator::pdremEvaluator(TR::Node *node, TR::CodeGenerator *cg)760{761return TR::TreeEvaluator::pddivremEvaluator(node, cg);762}763764TR::Register*765J9::Z::TreeEvaluator::pdabsEvaluator(TR::Node *node, TR::CodeGenerator *cg)766{767return TR::TreeEvaluator::unImpOpEvaluator(node, cg);768}769770TR::Register*771J9::Z::TreeEvaluator::pdshrSetSignEvaluator(TR::Node *node, TR::CodeGenerator *cg)772{773return TR::TreeEvaluator::unImpOpEvaluator(node, cg);774}775776TR::Register*777J9::Z::TreeEvaluator::pdshlSetSignEvaluator(TR::Node *node, TR::CodeGenerator *cg)778{779return TR::TreeEvaluator::unImpOpEvaluator(node, cg);780}781782TR::Register*783J9::Z::TreeEvaluator::pdshlOverflowEvaluator(TR::Node *node, TR::CodeGenerator *cg)784{785return TR::TreeEvaluator::pdshlEvaluator(node, cg);786}787788TR::Register*789J9::Z::TreeEvaluator::pd2iOverflowEvaluator(TR::Node *node, TR::CodeGenerator *cg)790{791return TR::TreeEvaluator::pd2iEvaluator(node, cg);792}793794TR::Register*795J9::Z::TreeEvaluator::pd2iuEvaluator(TR::Node *node, TR::CodeGenerator *cg)796{797return TR::TreeEvaluator::pd2iEvaluator(node, cg);798}799800TR::Register*801J9::Z::TreeEvaluator::iu2pdEvaluator(TR::Node *node, TR::CodeGenerator *cg)802{803return TR::TreeEvaluator::unImpOpEvaluator(node, cg);804}805806TR::Register*807J9::Z::TreeEvaluator::pd2lOverflowEvaluator(TR::Node *node, TR::CodeGenerator *cg)808{809return TR::TreeEvaluator::pd2lEvaluator(node, cg);810}811812TR::Register*813J9::Z::TreeEvaluator::pd2luEvaluator(TR::Node *node, TR::CodeGenerator *cg)814{815return TR::TreeEvaluator::pd2lEvaluator(node, cg);816}817818TR::Register*819J9::Z::TreeEvaluator::lu2pdEvaluator(TR::Node *node, TR::CodeGenerator *cg)820{821return TR::TreeEvaluator::unImpOpEvaluator(node, cg);822}823824TR::Register*825J9::Z::TreeEvaluator::pd2fEvaluator(TR::Node *node, TR::CodeGenerator *cg)826{827return TR::TreeEvaluator::unImpOpEvaluator(node, cg);828}829830TR::Register*831J9::Z::TreeEvaluator::pd2dEvaluator(TR::Node *node, TR::CodeGenerator *cg)832{833return TR::TreeEvaluator::unImpOpEvaluator(node, cg);834}835836TR::Register*837J9::Z::TreeEvaluator::f2pdEvaluator(TR::Node *node, TR::CodeGenerator *cg)838{839return TR::TreeEvaluator::unImpOpEvaluator(node, cg);840}841842TR::Register*843J9::Z::TreeEvaluator::d2pdEvaluator(TR::Node *node, TR::CodeGenerator *cg)844{845return TR::TreeEvaluator::unImpOpEvaluator(node, cg);846}847848TR::Register*849J9::Z::TreeEvaluator::pdcleanEvaluator(TR::Node *node, TR::CodeGenerator *cg)850{851return TR::TreeEvaluator::unImpOpEvaluator(node, cg);852}853854TR::Register*855J9::Z::TreeEvaluator::pdclearSetSignEvaluator(TR::Node *node, TR::CodeGenerator *cg)856{857return TR::TreeEvaluator::pdclearEvaluator(node, cg);858}859860/* Moved from Codegen to FE */861///////////////////////////////////////////////////////////////////////////////////862// Generate code to perform a comparison and branch to a snippet.863// This routine is used mostly by bndchk evaluator.864//865// The comparison type is determined by the choice of CMP operators:866// - fBranchOp: Operator used for forward operation -> A fCmp B867// - rBranchOp: Operator user for reverse operation -> B rCmp A <=> A fCmp B868//869// TODO - avoid code duplication, this routine may be able to merge with the one870// above which has the similar logic.871///////////////////////////////////////////////////////////////////////////////////872TR::Instruction *873generateS390CompareBranchLabel(TR::Node * node, TR::CodeGenerator * cg, TR::InstOpCode::Mnemonic branchOp, TR::InstOpCode::S390BranchCondition fBranchOpCond, TR::InstOpCode::S390BranchCondition rBranchOpCond,874TR::LabelSymbol * label)875{876return generateS390CompareOps(node, cg, fBranchOpCond, rBranchOpCond, label);877}878879/* Moved from Codegen to FE since only awrtbarEvaluator calls this function */880static TR::Register *881allocateWriteBarrierInternalPointerRegister(TR::CodeGenerator * cg, TR::Node * sourceChild)882{883TR::Register * sourceRegister;884885if (sourceChild->getRegister() != NULL && !cg->canClobberNodesRegister(sourceChild))886{887if (!sourceChild->getRegister()->containsInternalPointer())888{889sourceRegister = cg->allocateCollectedReferenceRegister();890}891else892{893sourceRegister = cg->allocateRegister();894sourceRegister->setPinningArrayPointer(sourceChild->getRegister()->getPinningArrayPointer());895sourceRegister->setContainsInternalPointer();896}897generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), sourceChild, sourceRegister, sourceChild->getRegister());898}899else900{901sourceRegister = cg->evaluate(sourceChild);902}903904return sourceRegister;905}906907908extern TR::Register *909doubleMaxMinHelper(TR::Node *node, TR::CodeGenerator *cg, bool isMaxOp)910{911TR_ASSERT(node->getNumChildren() >= 1 || node->getNumChildren() <= 2, "node has incorrect number of children");912913/* ===================== Allocating Registers ===================== */914915TR::Register * v16 = cg->allocateRegister(TR_VRF);916TR::Register * v17 = cg->allocateRegister(TR_VRF);917TR::Register * v18 = cg->allocateRegister(TR_VRF);918919/* ===================== Generating instructions ===================== */920921/* ====== LD FPR0,16(GPR5) Load a ====== */922TR::Register * v0 = cg->fprClobberEvaluate(node->getFirstChild());923924/* ====== LD FPR2, 0(GPR5) Load b ====== */925TR::Register * v2 = cg->evaluate(node->getSecondChild());926927/* ====== WFTCIDB V16,V0,X'F' a == NaN ====== */928generateVRIeInstruction(cg, TR::InstOpCode::VFTCI, node, v16, v0, 0xF, 8, 3);929930/* ====== For Max: WFCHE V17,V0,V2 Compare a >= b ====== */931if(isMaxOp)932{933generateVRRcInstruction(cg, TR::InstOpCode::VFCH, node, v17, v0, v2, 0, 8, 3);934}935/* ====== For Min: WFCHE V17,V0,V2 Compare a <= b ====== */936else937{938generateVRRcInstruction(cg, TR::InstOpCode::VFCH, node, v17, v2, v0, 0, 8, 3);939}940941/* ====== VO V16,V16,V17 (a >= b) || (a == NaN) ====== */942generateVRRcInstruction(cg, TR::InstOpCode::VO, node, v16, v16, v17, 0, 0, 0);943944/* ====== For Max: WFTCIDB V17,V0,X'800' a == +0 ====== */945if(isMaxOp)946{947generateVRIeInstruction(cg, TR::InstOpCode::VFTCI, node, v17, v0, 0x800, 8, 3);948}949/* ====== For Min: WFTCIDB V17,V0,X'400' a == -0 ====== */950else951{952generateVRIeInstruction(cg, TR::InstOpCode::VFTCI, node, v17, v0, 0x400, 8, 3);953}954/* ====== WFTCIDB V18,V2,X'C00' b == 0 ====== */955generateVRIeInstruction(cg, TR::InstOpCode::VFTCI, node, v18, v2, 0xC00, 8, 3);956957/* ====== VN V17,V17,V18 (a == -0) && (b == 0) ====== */958generateVRRcInstruction(cg, TR::InstOpCode::VN, node, v17, v17, v18, 0, 0, 0);959960/* ====== VO V16,V16,V17 (a >= b) || (a == NaN) || ((a == -0) && (b == 0)) ====== */961generateVRRcInstruction(cg, TR::InstOpCode::VO, node, v16, v16, v17, 0, 0, 0);962963/* ====== VSEL V0,V0,V2,V16 ====== */964generateVRReInstruction(cg, TR::InstOpCode::VSEL, node, v0, v0, v2, v16);965966/* ===================== Deallocating Registers ===================== */967cg->stopUsingRegister(v2);968cg->stopUsingRegister(v16);969cg->stopUsingRegister(v17);970cg->stopUsingRegister(v18);971972node->setRegister(v0);973974cg->decReferenceCount(node->getFirstChild());975cg->decReferenceCount(node->getSecondChild());976977return node->getRegister();978}979980TR::Register*981J9::Z::TreeEvaluator::inlineVectorizedStringIndexOf(TR::Node* node, TR::CodeGenerator* cg, bool isUTF16)982{983#define iComment(str) if (compDebug) compDebug->addInstructionComment(cursor, (const_cast<char*>(str)));984TR::Compilation *comp = cg->comp();985const uint32_t elementSizeMask = isUTF16 ? 1 : 0;986const int8_t vectorSize = cg->machine()->getVRFSize();987const uintptr_t headerSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();988const bool supportsVSTRS = comp->target().cpu.supportsFeature(OMR_FEATURE_S390_VECTOR_FACILITY_ENHANCEMENT_2);989TR_Debug *compDebug = comp->getDebug();990TR::Instruction* cursor;991992static bool disableIndexOfStringIntrinsic = feGetEnv("TR_DisableIndexOfStringIntrinsic") != NULL;993if (disableIndexOfStringIntrinsic)994return NULL;995996if (comp->getOption(TR_TraceCG))997traceMsg(comp, "inlineVectorizedStringIndexOf. Is isUTF16 %d\n", isUTF16);998999// This evaluator function handles different indexOf() intrinsics, some of which are static calls without a1000// receiver. Hence, the need for static call check.1001const bool isStaticCall = node->getSymbolReference()->getSymbol()->castToMethodSymbol()->isStatic();1002const uint8_t firstCallArgIdx = isStaticCall ? 0 : 1;10031004TR_S390ScratchRegisterManager *srm = cg->generateScratchRegisterManager(9);10051006// Get call parameters where stringValue and patternValue are byte arrays1007TR::Register* stringValueReg = cg->evaluate(node->getChild(firstCallArgIdx));1008TR::Register* stringLenReg = cg->gprClobberEvaluate(node->getChild(firstCallArgIdx+1));1009TR::Register* patternValueReg = cg->evaluate(node->getChild(firstCallArgIdx+2));1010TR::Register* patternLenReg = cg->gprClobberEvaluate(node->getChild(firstCallArgIdx+3));1011TR::Register* stringIndexReg = cg->gprClobberEvaluate(node->getChild(firstCallArgIdx+4));10121013// Registers1014TR::Register* matchIndexReg = cg->allocateRegister();1015TR::Register* maxIndexReg = srm->findOrCreateScratchRegister();1016TR::Register* patternIndexReg = srm->findOrCreateScratchRegister();1017TR::Register* loadLenReg = srm->findOrCreateScratchRegister();1018TR::Register* stringVReg = srm->findOrCreateScratchRegister(TR_VRF);1019TR::Register* patternVReg = srm->findOrCreateScratchRegister(TR_VRF);1020TR::Register* searchResultVReg = srm->findOrCreateScratchRegister(TR_VRF);10211022// Register dependencies1023TR::RegisterDependencyConditions* regDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, supportsVSTRS ? 16 : 13, cg);10241025regDeps->addPostCondition(stringValueReg, TR::RealRegister::AssignAny);1026regDeps->addPostCondition(stringLenReg, TR::RealRegister::AssignAny);1027regDeps->addPostCondition(patternValueReg, TR::RealRegister::AssignAny);1028regDeps->addPostCondition(patternLenReg, TR::RealRegister::AssignAny);1029regDeps->addPostCondition(stringIndexReg, TR::RealRegister::AssignAny);1030regDeps->addPostCondition(matchIndexReg, TR::RealRegister::AssignAny);10311032// Labels1033TR::LabelSymbol* labelStart = generateLabelSymbol(cg);1034TR::LabelSymbol* labelFindPatternHead = generateLabelSymbol(cg);1035TR::LabelSymbol* labelLoadString16Bytes = generateLabelSymbol(cg);1036TR::LabelSymbol* labelLoadStringLenDone = generateLabelSymbol(cg);1037TR::LabelSymbol* labelMatchPatternLoop = generateLabelSymbol(cg);1038TR::LabelSymbol* labelMatchPatternResidue = generateLabelSymbol(cg);1039TR::LabelSymbol* labelMatchPatternLoopSetup = generateLabelSymbol(cg);1040TR::LabelSymbol* labelPartialPatternMatch = generateLabelSymbol(cg);1041TR::LabelSymbol* labelLoadResult = generateLabelSymbol(cg);1042TR::LabelSymbol* labelResultDone = generateLabelSymbol(cg);1043TR::LabelSymbol* labelPatternNotFound = generateLabelSymbol(cg);1044TR::LabelSymbol* labelDone = generateLabelSymbol(cg);10451046cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelStart);1047iComment("retrieve string len, pattern len and starting pos");1048labelStart->setStartInternalControlFlow();10491050// Decompressed strings have [byte_length = char_length * 2]1051if (isUTF16 && comp->target().is64Bit())1052{1053generateShiftThenKeepSelected64Bit(node, cg, stringLenReg, stringLenReg, 31, 62, 1);1054generateShiftThenKeepSelected64Bit(node, cg, patternLenReg, patternLenReg, 31, 62, 1);1055generateShiftThenKeepSelected64Bit(node, cg, stringIndexReg, stringIndexReg, 31, 62, 1);1056}1057else1058{1059generateRRInstruction(cg, TR::InstOpCode::LGFR, node, stringLenReg, stringLenReg);1060generateRRInstruction(cg, TR::InstOpCode::LGFR, node, patternLenReg, patternLenReg);1061generateRRInstruction(cg, TR::InstOpCode::LGFR, node, stringIndexReg, stringIndexReg);10621063if (isUTF16)1064{1065generateRSInstruction(cg, TR::InstOpCode::SLL, node, stringLenReg, 1);1066generateRSInstruction(cg, TR::InstOpCode::SLL, node, patternLenReg, 1);1067generateRSInstruction(cg, TR::InstOpCode::SLL, node, stringIndexReg, 1);1068}1069}10701071cursor = generateRRRInstruction(cg, TR::InstOpCode::getSubtractThreeRegOpCode(), node, maxIndexReg, stringLenReg, patternLenReg);1072iComment("maximum valid index for a potential match");1073generateRIEInstruction(cg, TR::InstOpCode::getCmpRegAndBranchRelOpCode(), node, maxIndexReg, stringIndexReg, labelPatternNotFound, TR::InstOpCode::COND_BLR);10741075// patternLen debug counters1076static bool enableIndexOfDebugCounter = feGetEnv("TR_EnableIndexOfDebugCounter") != NULL;1077if (enableIndexOfDebugCounter)1078{1079TR::LabelSymbol* labelPatternLenGT10 = generateLabelSymbol(cg);1080TR::LabelSymbol* labelPatternLenGT30 = generateLabelSymbol(cg);1081TR::LabelSymbol* labelPatternLenGT60 = generateLabelSymbol(cg);1082TR::LabelSymbol* labelPatternLenGT100 = generateLabelSymbol(cg);1083TR::LabelSymbol* labelPatternLenCheckDone = generateLabelSymbol(cg);10841085uint8_t boundary10Char = isUTF16 ? 20 : 10;1086uint8_t boundary30Char = isUTF16 ? 60 : 30;1087uint8_t boundary60Char = isUTF16 ? 120 : 60;1088uint8_t boundary100Char = isUTF16 ? 200 : 100;10891090generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, patternLenReg, boundary10Char, labelPatternLenGT10, TR::InstOpCode::COND_BH);1091cg->generateDebugCounter("indexOfString/PatternLen/below-10", 1, TR::DebugCounter::Cheap);1092generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelPatternLenCheckDone);10931094generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelPatternLenGT10);1095generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, patternLenReg, boundary30Char, labelPatternLenGT30, TR::InstOpCode::COND_BH);1096cg->generateDebugCounter("indexOfString/PatternLen/10-30", 1, TR::DebugCounter::Cheap);1097generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelPatternLenCheckDone);10981099generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelPatternLenGT30);1100generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, patternLenReg, boundary60Char, labelPatternLenGT60, TR::InstOpCode::COND_BH);1101cg->generateDebugCounter("indexOfString/PatternLen/30-60", 1, TR::DebugCounter::Cheap);1102generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelPatternLenCheckDone);11031104generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelPatternLenGT60);1105generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, patternLenReg, boundary100Char, labelPatternLenGT100, TR::InstOpCode::COND_BH);1106cg->generateDebugCounter("indexOfString/PatternLen/60-100", 1, TR::DebugCounter::Cheap);1107generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelPatternLenCheckDone);11081109generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelPatternLenGT100);1110cg->generateDebugCounter("indexOfString/PatternLen/above-100", 1, TR::DebugCounter::Cheap);11111112generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelPatternLenCheckDone);1113}11141115if (supportsVSTRS)1116{1117TR::Register* patternHeadVReg = srm->findOrCreateScratchRegister(TR_VRF); // used for first 16 bytes of the pattern1118TR::Register* patternLenVReg = srm->findOrCreateScratchRegister(TR_VRF); // length of the pattern being searched for through VSTRS instruction11191120// Load the first piece of patternValue (pattern header) which is either 16 bytes or patternLen1121TR::LabelSymbol* labelPatternLoad16Bytes = generateLabelSymbol(cg);1122TR::LabelSymbol* labelPatternLoadDone = generateLabelSymbol(cg);11231124generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, patternLenReg, (int8_t)vectorSize, labelPatternLoad16Bytes, TR::InstOpCode::COND_BNL);1125generateRIEInstruction(cg, TR::InstOpCode::getAddHalfWordImmDistinctOperandOpCode(), node, loadLenReg, patternLenReg, -1);1126generateVRSbInstruction(cg, TR::InstOpCode::VLL, node, patternHeadVReg, loadLenReg, generateS390MemoryReference(patternValueReg, headerSize, cg));1127generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, loadLenReg, patternLenReg);1128generateVRSbInstruction(cg, TR::InstOpCode::VLVG, node, patternLenVReg, patternLenReg, generateS390MemoryReference(7, cg), 0);1129generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelPatternLoadDone);11301131cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelPatternLoad16Bytes);1132iComment("load first 16 bytes of the pattern");1133generateVRXInstruction(cg, TR::InstOpCode::VL, node, patternHeadVReg, generateS390MemoryReference(patternValueReg, headerSize, cg));1134generateRIInstruction(cg, TR::InstOpCode::LHI, node, loadLenReg, vectorSize);1135generateVRSbInstruction(cg, TR::InstOpCode::VLVG, node, patternLenVReg, loadLenReg, generateS390MemoryReference(7, cg), 0);1136cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelPatternLoadDone);1137iComment("min(16,pattern length) bytes have been loaded");11381139// Loop to search for pattern header in string1140cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelFindPatternHead);1141iComment("look for pattern head in the string");11421143// Determine string load length and load a piece of string1144generateRRRInstruction(cg, TR::InstOpCode::getSubtractThreeRegOpCode(), node, loadLenReg, stringLenReg, stringIndexReg);1145generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, loadLenReg, (int8_t)vectorSize, labelLoadString16Bytes, TR::InstOpCode::COND_BNL);1146TR::Register* stringCharPtrReg = srm->findOrCreateScratchRegister();1147generateRRRInstruction(cg, TR::InstOpCode::getAddThreeRegOpCode(), node, stringCharPtrReg, stringValueReg, stringIndexReg);1148// Needs -1 because VLL's third operand is the highest index to load.1149// e.g. If the load length is 8 bytes, the highest index is 7. Hence, the need for -1.1150cursor = generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, loadLenReg, -1);1151iComment("needs -1 because VLL's third operand is the highest index to load");1152generateVRSbInstruction(cg, TR::InstOpCode::VLL, node, stringVReg, loadLenReg, generateS390MemoryReference(stringCharPtrReg, headerSize, cg));1153generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, loadLenReg, 1);1154generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelLoadStringLenDone);1155srm->reclaimScratchRegister(stringCharPtrReg);1156cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelLoadString16Bytes);1157iComment("load 16 bytes of the string");1158generateVRXInstruction(cg, TR::InstOpCode::VL, node, stringVReg, generateS390MemoryReference(stringValueReg, stringIndexReg, headerSize, cg));1159generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, loadLenReg, vectorSize);1160cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelLoadStringLenDone);1161iComment("16 bytes of the string have been loaded");11621163// VSTRS sets CC with the following values:1164// CC = 0, no match or partial match, AND (zs = 0 OR no zero byte in source VRF)1165// CC = 1, no match AND (zs = 1) AND (zero byte in source VRF)1166// CC = 2, full match1167// CC = 3, partial match but no full match.1168TR::LabelSymbol* labelPatternHeadFullMatch = generateLabelSymbol(cg);1169TR::LabelSymbol* labelPatternHeadPartMatch = generateLabelSymbol(cg);11701171generateVRRdInstruction(cg, TR::InstOpCode::VSTRS, node, searchResultVReg, stringVReg, patternHeadVReg, patternLenVReg, 0, elementSizeMask);1172generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC2, node, labelPatternHeadFullMatch);1173generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC3, node, labelPatternHeadPartMatch);11741175// pattern header not found in first 16 bytes of the string1176// Load the next 16 bytes of the string and continue1177generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, stringIndexReg, loadLenReg);1178cursor = generateRIEInstruction(cg, TR::InstOpCode::getCmpRegAndBranchRelOpCode(), node, stringIndexReg, maxIndexReg, labelPatternNotFound, TR::InstOpCode::COND_BH);1179iComment("Updated stringIndex for next iteration exceeds maxIndex of valid match. Full pattern cannot be matched.")1180cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelFindPatternHead);1181iComment("neither full nor partial match was found for pattern head, load next 16 bytes of the string and try again");11821183// pattern header full match1184cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelPatternHeadFullMatch);1185iComment("full match found of pattern head");11861187// If patternLen <= 16 then we are done, otherwise we continue to check the rest of pattern. We first handle residue bytes1188// of pattern, then handle the rest 16-byte chunks.1189cursor = generateVRScInstruction(cg, TR::InstOpCode::VLGV, node, matchIndexReg, searchResultVReg, generateS390MemoryReference(7, cg), 0);1190iComment("check 7th index of search result vec for byte index");1191generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, matchIndexReg, stringIndexReg);1192cursor = generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, patternLenReg, (int8_t)vectorSize, labelLoadResult, TR::InstOpCode::COND_BNH);1193iComment("if patternLen <= 16 then we are done, otherwise we continue to check the rest of pattern");1194cursor = generateRIEInstruction(cg, TR::InstOpCode::getCmpRegAndBranchRelOpCode(), node, stringIndexReg, maxIndexReg, labelPatternNotFound, TR::InstOpCode::COND_BH);1195iComment("Updated stringIndex for start of matched section exceeds maxIndex. Full pattern cannot be matched.");1196generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, stringIndexReg, loadLenReg);1197generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, patternIndexReg, vectorSize);1198cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelMatchPatternResidue);1199iComment("find residual pattern");12001201// pattern header partial match1202cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelPatternHeadPartMatch);1203iComment("partial match of first 16 bytes of pattern was found");12041205// Starting from the beginning of the partial match, load the next 16 bytes from string and redo pattern header search.1206// This implies that the partial match will be re-matched by the next VSTRS. This can potentially benefit string1207// search cases where pattern is shorter than 16 bytes. For short string strings, string search can potentially be done in1208// the next VSTRS and can we avoid residue matching which requires several index adjustments that do not provide1209// performance benefits.1210cursor = generateVRScInstruction(cg, TR::InstOpCode::VLGV, node, matchIndexReg, searchResultVReg, generateS390MemoryReference(7, cg), 0);1211iComment("check 7th index of search result vec for byte index");1212generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, stringIndexReg, matchIndexReg);1213generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelFindPatternHead);12141215srm->reclaimScratchRegister(patternLenVReg);1216srm->reclaimScratchRegister(patternHeadVReg);1217}1218else1219{1220TR::Register* patternFirstCharVReg = srm->findOrCreateScratchRegister(TR_VRF);12211222/************************************** 1st char of pattern ******************************************/1223cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelFindPatternHead);1224iComment("find first character of pattern");1225generateVRXInstruction(cg, TR::InstOpCode::VLREP, node, patternFirstCharVReg, generateS390MemoryReference(patternValueReg, headerSize, cg), elementSizeMask);12261227// Determine string load length. loadLenReg is either vectorSize-1 (15) or the 1st_char_matching residue length.1228generateRIEInstruction(cg, TR::InstOpCode::getAddHalfWordImmDistinctOperandOpCode(), node, loadLenReg, stringIndexReg, vectorSize);1229generateRIEInstruction(cg, TR::InstOpCode::getCmpRegAndBranchRelOpCode(), node, loadLenReg, stringLenReg, labelLoadString16Bytes, TR::InstOpCode::COND_BNHR);1230generateRRRInstruction(cg, TR::InstOpCode::getSubtractThreeRegOpCode(), node, loadLenReg, stringLenReg, stringIndexReg);1231generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, loadLenReg, -1);1232generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelLoadStringLenDone);12331234cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelLoadString16Bytes);1235iComment("update loadLenReg to load 16 characters from the string later on");1236generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, loadLenReg, vectorSize-1);12371238cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelLoadStringLenDone);1239iComment("load 16 characters into string VRF register and search for first chracter of the pattern");12401241TR::Register* stringCharPtrReg = srm->findOrCreateScratchRegister();1242TR::LabelSymbol* labelExtractFirstCharPos = generateLabelSymbol(cg);1243generateRRRInstruction(cg, TR::InstOpCode::getAddThreeRegOpCode(), node, stringCharPtrReg, stringValueReg, stringIndexReg);1244generateVRSbInstruction(cg, TR::InstOpCode::VLL, node, stringVReg, loadLenReg, generateS390MemoryReference(stringCharPtrReg, headerSize, cg));1245generateVRRbInstruction(cg, TR::InstOpCode::VFEE, node, searchResultVReg, stringVReg, patternFirstCharVReg, 0x1, elementSizeMask);1246generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC1, node, labelExtractFirstCharPos);1247srm->reclaimScratchRegister(stringCharPtrReg);12481249// 1st char not found. Loop back and retry from the next chunk1250generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, stringIndexReg, loadLenReg);1251generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, stringIndexReg, 1);1252generateRIEInstruction(cg, TR::InstOpCode::getCmpRegAndBranchRelOpCode(), node, stringIndexReg, maxIndexReg, labelPatternNotFound, TR::InstOpCode::COND_BHR);1253cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelFindPatternHead);1254iComment("1st char not found. Loop back and retry from the next chunk");12551256// Found 1st char. check it's byte index in searchResultVReg byte 7.1257cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelExtractFirstCharPos);1258iComment("check 7th index of search result vec for byte index");12591260generateVRScInstruction(cg, TR::InstOpCode::VLGV, node, matchIndexReg, searchResultVReg, generateS390MemoryReference(7, cg), 0);1261generateRIEInstruction(cg, TR::InstOpCode::getCmpRegAndBranchRelOpCode(), node, matchIndexReg, loadLenReg, labelPatternNotFound, TR::InstOpCode::COND_BHR);12621263generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, matchIndexReg, stringIndexReg); // convert relative index to absolute index1264generateRIEInstruction(cg, TR::InstOpCode::getCmpRegAndBranchRelOpCode(), node, matchIndexReg, maxIndexReg, labelPatternNotFound, TR::InstOpCode::COND_BHR);12651266/************************************** s2 Residue matching ******************************************/1267generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, stringIndexReg, matchIndexReg); // use the absolute match index as starting index when matching rest of the pattern1268srm->reclaimScratchRegister(patternFirstCharVReg);1269}12701271srm->addScratchRegistersToDependencyList(regDeps);1272cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelMatchPatternResidue);1273iComment("match remainder of the pattern");12741275// pattern residue length = patternLenReg mod 161276generateRRInstruction(cg, TR::InstOpCode::LLGHR, node, loadLenReg, patternLenReg);1277generateRIInstruction(cg, TR::InstOpCode::NILL, node, loadLenReg, 0x000F);1278generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, loadLenReg, (int8_t)0, labelMatchPatternLoopSetup, TR::InstOpCode::COND_BE);12791280TR::Register* stringCharPtrReg = srm->findOrCreateScratchRegister();1281generateRRRInstruction(cg, TR::InstOpCode::getAddThreeRegOpCode(), node, stringCharPtrReg, stringValueReg, stringIndexReg);12821283// Vector loads use load index. And [load_index = load_len - 1]1284generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, loadLenReg, -1);1285generateVRSbInstruction(cg, TR::InstOpCode::VLL, node, stringVReg, loadLenReg, generateS390MemoryReference(stringCharPtrReg, headerSize, cg));1286srm->reclaimScratchRegister(stringCharPtrReg);1287// If VSTRS is supported, the first VSTRS already handled the 1st 16 bytes at this point (full match in the 1st 161288// bytes). Hence, residue offset starts at 16.1289uint32_t patternResidueDisp = headerSize + (supportsVSTRS ? vectorSize : 0);12901291generateVRSbInstruction(cg, TR::InstOpCode::VLL, node, patternVReg, loadLenReg, generateS390MemoryReference(patternValueReg, patternResidueDisp, cg));1292generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, loadLenReg, 1);12931294if (supportsVSTRS)1295{1296generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, patternIndexReg, vectorSize);1297}12981299generateVRRbInstruction(cg, TR::InstOpCode::VCEQ, node, searchResultVReg, stringVReg, patternVReg, 1, elementSizeMask);1300generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC0, node, labelMatchPatternLoopSetup);13011302// The residue does not match. Continue to find the 1st char in string, starting from the next element.1303generateRIEInstruction(cg, TR::InstOpCode::getAddHalfWordImmDistinctOperandOpCode(), node, stringIndexReg, matchIndexReg, isUTF16 ? 2 : 1);1304generateRIEInstruction(cg, TR::InstOpCode::getCmpRegAndBranchRelOpCode(), node, stringIndexReg, maxIndexReg, labelPatternNotFound, TR::InstOpCode::COND_BHR);1305generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelFindPatternHead);13061307/************************************** pattern matching loop ENTRY ******************************************/13081309cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelMatchPatternLoopSetup);1310iComment("loop setup to search for rest of the pattern");1311generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, stringIndexReg, loadLenReg);13121313if (supportsVSTRS)1314{1315generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, patternIndexReg, loadLenReg);1316}1317else1318{1319generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, patternIndexReg, loadLenReg);1320}13211322srm->reclaimScratchRegister(loadLenReg);1323TR::Register* loopCountReg = srm->findOrCreateScratchRegister();1324generateRSInstruction(cg, TR::InstOpCode::SRLG, node, loopCountReg, patternLenReg, 4);13251326if (supportsVSTRS)1327{1328generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, loopCountReg, -1);1329}13301331generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, loopCountReg, static_cast<int8_t>(0), labelLoadResult, TR::InstOpCode::COND_BE);13321333/************************************** pattern matching loop ******************************************/1334cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelMatchPatternLoop);1335iComment("start search for reset of the pattern");1336// Start to match the reset of pattern1337generateVRXInstruction(cg, TR::InstOpCode::VL, node, stringVReg, generateS390MemoryReference(stringValueReg, stringIndexReg, headerSize, cg));1338generateVRXInstruction(cg, TR::InstOpCode::VL, node, patternVReg, generateS390MemoryReference(patternValueReg, patternIndexReg, headerSize, cg));13391340generateVRRbInstruction(cg, TR::InstOpCode::VCEQ, node, searchResultVReg, stringVReg, patternVReg, 1, elementSizeMask);1341generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC0, node, labelPartialPatternMatch);13421343// pattern chunk does not match. Go back and search again1344generateRIEInstruction(cg, TR::InstOpCode::getAddHalfWordImmDistinctOperandOpCode(), node, stringIndexReg, matchIndexReg, isUTF16 ? 2 : 1);1345generateRIEInstruction(cg, TR::InstOpCode::getCmpRegAndBranchRelOpCode(), node, stringIndexReg, maxIndexReg, labelPatternNotFound, TR::InstOpCode::COND_BHR);1346cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelFindPatternHead);1347iComment("pattern chunk does not match. Go back and search again");13481349cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelPartialPatternMatch);1350iComment("there was a complete match for the characters currently loaded in pattern VRF register");1351generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, stringIndexReg, vectorSize);1352generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, patternIndexReg, vectorSize);1353generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, loopCountReg, -1);1354generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, loopCountReg, (int8_t)0, labelMatchPatternLoop, TR::InstOpCode::COND_BNE);1355srm->reclaimScratchRegister(loopCountReg);1356// Load -1 if pattern is no found in string or load the character index of the 1st character of pattern in string1357cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelLoadResult);13581359if (isUTF16)1360{1361// Byte-index to char-index conversion1362cursor = generateRSInstruction(cg, TR::InstOpCode::SRA, node, matchIndexReg, 1);1363iComment("byte-index to char-index conversion");1364}1365generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelResultDone);13661367cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelPatternNotFound);1368iComment("pattern was not found in the string");1369generateRIInstruction(cg, TR::InstOpCode::LHI, node, matchIndexReg, -1);13701371generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelResultDone);13721373// Result debug counters1374if (enableIndexOfDebugCounter)1375{1376TR::LabelSymbol* labelResultGT10 = generateLabelSymbol(cg);1377TR::LabelSymbol* labelResultGT30 = generateLabelSymbol(cg);1378TR::LabelSymbol* labelResultGT60 = generateLabelSymbol(cg);1379TR::LabelSymbol* labelResultGT100 = generateLabelSymbol(cg);1380TR::LabelSymbol* labelResultCheckDone = generateLabelSymbol(cg);13811382uint8_t boundary10Char = 10;1383uint8_t boundary30Char = 30;1384uint8_t boundary60Char = 60;1385uint8_t boundary100Char = 100;13861387generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, patternLenReg, boundary10Char, labelResultGT10, TR::InstOpCode::COND_BH);1388cg->generateDebugCounter("indexOfString/result/below-10", 1, TR::DebugCounter::Cheap);1389generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelResultCheckDone);13901391generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelResultGT10);1392generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, patternLenReg, boundary30Char, labelResultGT30, TR::InstOpCode::COND_BH);1393cg->generateDebugCounter("indexOfString/result/10-30", 1, TR::DebugCounter::Cheap);1394generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelResultCheckDone);13951396generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelResultGT30);1397generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, patternLenReg, boundary60Char, labelResultGT60, TR::InstOpCode::COND_BH);1398cg->generateDebugCounter("indexOfString/result/30-60", 1, TR::DebugCounter::Cheap);1399generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelResultCheckDone);14001401generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelResultGT60);1402generateRIEInstruction(cg, TR::InstOpCode::getCmpImmBranchRelOpCode(), node, patternLenReg, boundary100Char, labelResultGT100, TR::InstOpCode::COND_BH);1403cg->generateDebugCounter("indexOfString/result/60-100", 1, TR::DebugCounter::Cheap);1404generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelResultCheckDone);14051406generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelResultGT100);1407cg->generateDebugCounter("indexOfString/result/above-100", 1, TR::DebugCounter::Cheap);14081409generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelResultCheckDone);1410}14111412generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelDone, regDeps);1413labelDone->setEndInternalControlFlow();14141415node->setRegister(matchIndexReg);14161417for (int32_t i = 0; i < node->getNumChildren(); ++i)1418{1419cg->decReferenceCount(node->getChild(i));1420}1421cg->stopUsingRegister(stringIndexReg);1422srm->stopUsingRegisters();14231424return matchIndexReg;1425}142614271428/** \brief1429* Attempts to use vector registers to perform SIMD conversion of characters from lowercase to uppercase.1430*1431* \detail1432* Uses vector registers to convert 16 bytes at a time.1433*1434* \param node1435* The node representing the HW optimized toUpper and toLower recognized calls.1436*1437* \param cg1438* The code generator used to generate the instructions.1439*1440* \param isToUpper1441* Boolean representing case conversion, either to upper or to lower.1442*1443* \param isCompressedString1444* Boolean representing the string's compression.1445*1446* \return1447* A register containing the return value of the Java call. The return value1448* will be 1 if the entire contents of the input array was translated and 0 if1449* we were unable to translate the entire contents of the array (up to the specified length).1450*/1451TR::Register * caseConversionHelper(TR::Node* node, TR::CodeGenerator* cg, bool isToUpper, bool isCompressedString)1452{1453TR::Register* sourceRegister = cg->evaluate(node->getChild(1));1454TR::Register* destRegister = cg->evaluate(node->getChild(2));1455TR::Register* lengthRegister = cg->gprClobberEvaluate(node->getChild(3));14561457TR::Register* addressOffset = cg->allocateRegister();1458TR::Register* loadLength = cg->allocateRegister();14591460// Loopcounter register for number of 16 byte conversions, when it is used, the length is not needed anymore1461TR::Register* loopCounter = lengthRegister;14621463TR::Register* charBufferVector = cg->allocateRegister(TR_VRF);1464TR::Register* selectionVector = cg->allocateRegister(TR_VRF);1465TR::Register* modifiedCaseVector = cg->allocateRegister(TR_VRF);1466TR::Register* charOffsetVector = cg->allocateRegister(TR_VRF);1467TR::Register* alphaRangeVector = cg->allocateRegister(TR_VRF);1468TR::Register* alphaCondVector = cg->allocateRegister(TR_VRF);1469TR::Register* invalidRangeVector = cg->allocateRegister(TR_VRF);1470TR::Register* invalidCondVector = cg->allocateRegister(TR_VRF);14711472TR::LabelSymbol* cFlowRegionStart = generateLabelSymbol( cg);1473TR::LabelSymbol* fullVectorConversion = generateLabelSymbol( cg);1474TR::LabelSymbol* cFlowRegionEnd = generateLabelSymbol( cg);1475TR::LabelSymbol* success = generateLabelSymbol( cg);1476TR::LabelSymbol* handleInvalidChars = generateLabelSymbol( cg);1477TR::LabelSymbol* loop = generateLabelSymbol( cg);14781479TR::Instruction* cursor;14801481const int elementSizeMask = (isCompressedString) ? 0x0 : 0x1; // byte or halfword mask1482const int32_t sizeOfVector = cg->machine()->getVRFSize();1483const bool is64 = cg->comp()->target().is64Bit();1484uintptr_t headerSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();14851486TR::RegisterDependencyConditions * regDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 13, cg);1487regDeps->addPostCondition(sourceRegister, TR::RealRegister::AssignAny);1488regDeps->addPostCondition(destRegister, TR::RealRegister::AssignAny);1489regDeps->addPostCondition(lengthRegister, TR::RealRegister::AssignAny);1490regDeps->addPostCondition(addressOffset, TR::RealRegister::AssignAny);1491regDeps->addPostCondition(loadLength, TR::RealRegister::AssignAny);1492regDeps->addPostCondition(charBufferVector, TR::RealRegister::AssignAny);1493regDeps->addPostCondition(selectionVector, TR::RealRegister::AssignAny);1494regDeps->addPostCondition(modifiedCaseVector, TR::RealRegister::AssignAny);1495regDeps->addPostCondition(charOffsetVector, TR::RealRegister::AssignAny);1496regDeps->addPostCondition(alphaRangeVector, TR::RealRegister::AssignAny);1497regDeps->addPostCondition(alphaCondVector, TR::RealRegister::AssignAny);1498regDeps->addPostCondition(invalidRangeVector, TR::RealRegister::AssignAny);1499regDeps->addPostCondition(invalidCondVector, TR::RealRegister::AssignAny);15001501generateRRInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node, addressOffset, addressOffset);15021503generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, alphaRangeVector, 0, 0);1504generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, alphaCondVector, 0, 0);1505generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, invalidRangeVector, 0, 0);1506generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, invalidCondVector, 0, 0);15071508// Characters a-z (0x61-0x7A) when to upper and A-Z (0x41-0x5A) when to lower1509generateVRIaInstruction (cg, TR::InstOpCode::VLEIH, node, alphaRangeVector, isToUpper ? 0x617A : 0x415A, 0x0);1510// Characters (0xE0-0xF6) when to upper and (0xC0-0xD6) when to lower1511generateVRIaInstruction (cg, TR::InstOpCode::VLEIH, node, alphaRangeVector, isToUpper ? 0xE0F6 : 0xC0D6, 0x1);1512// Characters (0xF8-0xFE) when to upper and (0xD8-0xDE) when to lower1513generateVRIaInstruction (cg, TR::InstOpCode::VLEIH, node, alphaRangeVector, isToUpper ? 0xF8FE : 0xD8DE, 0X2);15141515if (!isCompressedString)1516{1517generateVRRaInstruction(cg, TR::InstOpCode::VUPLH, node, alphaRangeVector, alphaRangeVector, 0, 0, 0, 0);1518}15191520// Condition codes for >= (bits 0 and 2) and <= (bits 0 and 1)1521if (isCompressedString)1522{1523generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, alphaCondVector, 0XA0C0, 0X0);1524generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, alphaCondVector, 0XA0C0, 0X1);1525generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, alphaCondVector, 0XA0C0, 0X2);1526}1527else1528{1529generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, alphaCondVector, 0XA000, 0X0);1530generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, alphaCondVector, 0XC000, 0X1);1531generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, alphaCondVector, 0XA000, 0X2);1532generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, alphaCondVector, 0XC000, 0X3);1533generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, alphaCondVector, 0XA000, 0X4);1534generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, alphaCondVector, 0XC000, 0X5);1535}15361537if (isToUpper)1538{1539// Can't uppercase \u00DF (capital sharp s) nor \u00B5 (mu) with a simple addition of 0x20 so we do an equality1540// comparison (bit 0) and greater than or equal comparison (bits 0 and 2) for codes larger than or equal to 0xFF1541generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidRangeVector, 0xDFDF, 0x0);1542generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidRangeVector, 0xB5B5, 0x1);1543generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidRangeVector, 0xFFFF, 0x2);15441545if (isCompressedString)1546{1547generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidCondVector, 0x8080, 0x0);1548generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidCondVector, 0x8080, 0x1);1549generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidCondVector, 0xA0A0, 0x2);1550}1551else1552{1553generateVRRaInstruction(cg, TR::InstOpCode::VUPLH, node, invalidRangeVector, invalidRangeVector, 0, 0, 0, 0);15541555generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidCondVector, 0x8000, 0x0);1556generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidCondVector, 0x8000, 0x1);1557generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidCondVector, 0x8000, 0x2);1558generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidCondVector, 0x8000, 0x3);1559generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidCondVector, 0xA000, 0x4);1560generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidCondVector, 0xA000, 0x5);1561}1562}1563else if (!isCompressedString)1564{1565// Can't lowercase codes larger than 0xFF but we only need to check this if our input is not compressed since1566// all compressed values will be <= 0xFF1567generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidRangeVector, 0x00FF, 0x0);1568generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidRangeVector, 0x00FF, 0x1);15691570generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidCondVector, 0x2000, 0x0);1571generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, invalidCondVector, 0x2000, 0x1);1572}15731574// Constant value of 0x20, used to convert between upper and lower1575generateVRIaInstruction(cg, TR::InstOpCode::VREPI, node, charOffsetVector, 0x20, elementSizeMask);15761577generateRRInstruction(cg, TR::InstOpCode::LR, node, loadLength, lengthRegister);1578generateRILInstruction(cg, TR::InstOpCode::NILF, node, loadLength, 0xF);1579generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);1580cFlowRegionStart->setStartInternalControlFlow();1581generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BZ, node, fullVectorConversion);15821583// VLL and VSTL take an index, not a count, so subtract the input length by 11584generateRILInstruction(cg, TR::InstOpCode::SLFI, node, loadLength, 1);15851586generateVRSbInstruction(cg, TR::InstOpCode::VLL, node, charBufferVector, loadLength, generateS390MemoryReference(sourceRegister, headerSize, cg));15871588// Check for invalid characters, go to fallback individual character conversion implementation1589if (isToUpper || !isCompressedString)1590{1591generateVRRdInstruction(cg, TR::InstOpCode::VSTRC, node, selectionVector, charBufferVector, invalidRangeVector, invalidCondVector, 0x1 , elementSizeMask);1592generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC1, node, handleInvalidChars);1593}15941595generateVRRdInstruction(cg, TR::InstOpCode::VSTRC, node, selectionVector, charBufferVector, alphaRangeVector, alphaCondVector, 0x4, elementSizeMask);1596generateVRRcInstruction(cg, isToUpper ? TR::InstOpCode::VS : TR::InstOpCode::VA, node, modifiedCaseVector, charBufferVector, charOffsetVector, 0x0, 0x0, elementSizeMask);1597generateVRReInstruction(cg, TR::InstOpCode::VSEL, node, modifiedCaseVector, modifiedCaseVector, charBufferVector, selectionVector);15981599generateVRSbInstruction(cg, TR::InstOpCode::VSTL, node, modifiedCaseVector, loadLength, generateS390MemoryReference(destRegister, headerSize, cg), 0);16001601// Increment index by the remainder then add 1, since the loadLength contains the highest index, we must go one past that1602generateRIEInstruction(cg, TR::InstOpCode::AHIK, node, addressOffset, loadLength, 1);16031604generateS390LabelInstruction(cg, TR::InstOpCode::label, node, fullVectorConversion);16051606generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node,1607lengthRegister, sizeOfVector,1608TR::InstOpCode::COND_BL, success, false);16091610// Set the loopCounter to the amount of groups of 16 bytes left, ignoring already accounted for remainder1611generateRSInstruction(cg, TR::InstOpCode::SRL, node, loopCounter, loopCounter, 4);16121613generateS390LabelInstruction(cg, TR::InstOpCode::label, node, loop);16141615generateVRXInstruction(cg, TR::InstOpCode::VL, node, charBufferVector, generateS390MemoryReference(sourceRegister, addressOffset, headerSize, cg));16161617if (isToUpper || !isCompressedString)1618{1619generateVRRdInstruction(cg, TR::InstOpCode::VSTRC, node, selectionVector, charBufferVector, invalidRangeVector, invalidCondVector, 0x1 , elementSizeMask);1620generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC1, node, handleInvalidChars);1621}16221623generateVRRdInstruction(cg, TR::InstOpCode::VSTRC, node, selectionVector, charBufferVector, alphaRangeVector, alphaCondVector, 0x4, elementSizeMask);1624generateVRRcInstruction(cg, isToUpper ? TR::InstOpCode::VS : TR::InstOpCode::VA, node, modifiedCaseVector, charBufferVector, charOffsetVector, 0x0, 0x0, elementSizeMask);1625generateVRReInstruction(cg, TR::InstOpCode::VSEL, node, modifiedCaseVector, modifiedCaseVector, charBufferVector, selectionVector);16261627generateVRXInstruction(cg, TR::InstOpCode::VST, node, modifiedCaseVector, generateS390MemoryReference(destRegister, addressOffset, headerSize, cg), 0);16281629generateRXInstruction(cg, TR::InstOpCode::getLoadAddressOpCode(), node, addressOffset, generateS390MemoryReference(addressOffset, sizeOfVector, cg));1630generateS390BranchInstruction(cg, TR::InstOpCode::BRCT, node, loopCounter, loop);16311632generateS390LabelInstruction(cg, TR::InstOpCode::label, node, success);16331634generateRIInstruction(cg, TR::InstOpCode::LHI, node, lengthRegister, 1);16351636generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);16371638generateS390LabelInstruction(cg, TR::InstOpCode::label, node, handleInvalidChars);1639cg->generateDebugCounter(isToUpper? "z13/simd/toUpper/null" : "z13/simd/toLower/null", 1, TR::DebugCounter::Cheap);1640generateRRInstruction(cg, TR::InstOpCode::XR, node, lengthRegister, lengthRegister);16411642generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, regDeps);1643cFlowRegionEnd->setEndInternalControlFlow();16441645cg->stopUsingRegister(addressOffset);1646cg->stopUsingRegister(loadLength);16471648cg->stopUsingRegister(charBufferVector);1649cg->stopUsingRegister(selectionVector);1650cg->stopUsingRegister(modifiedCaseVector);1651cg->stopUsingRegister(charOffsetVector);1652cg->stopUsingRegister(alphaRangeVector);1653cg->stopUsingRegister(alphaCondVector);1654cg->stopUsingRegister(invalidRangeVector);1655cg->stopUsingRegister(invalidCondVector);16561657node->setRegister(lengthRegister);16581659cg->decReferenceCount(node->getChild(0));1660cg->decReferenceCount(node->getChild(1));1661cg->decReferenceCount(node->getChild(2));1662cg->decReferenceCount(node->getChild(3));16631664return node->getRegister();1665}16661667TR::Register *1668J9::Z::TreeEvaluator::inlineIntrinsicIndexOf(TR::Node * node, TR::CodeGenerator * cg, bool isLatin1)1669{1670cg->generateDebugCounter("z13/simd/indexOf", 1, TR::DebugCounter::Free);16711672TR::Register* array = cg->evaluate(node->getChild(1));1673TR::Register* ch = cg->evaluate(node->getChild(2));1674TR::Register* offset = cg->evaluate(node->getChild(3));1675TR::Register* length = cg->gprClobberEvaluate(node->getChild(4));167616771678const int32_t sizeOfVector = cg->machine()->getVRFSize();16791680// load length isn't used after loop, size must is adjusted to become bytes left1681TR::Register* loopCounter = length;1682TR::Register* loadLength = cg->allocateRegister();1683TR::Register* indexRegister = cg->allocateRegister();1684TR::Register* offsetAddress = cg->allocateRegister();1685TR::Register* scratch = offsetAddress;16861687TR::Register* charBufferVector = cg->allocateRegister(TR_VRF);1688TR::Register* resultVector = cg->allocateRegister(TR_VRF);1689TR::Register* valueVector = cg->allocateRegister(TR_VRF);16901691TR::LabelSymbol* cFlowRegionStart = generateLabelSymbol( cg);1692TR::LabelSymbol* loopLabel = generateLabelSymbol( cg);1693TR::LabelSymbol* fullVectorLabel = generateLabelSymbol( cg);1694TR::LabelSymbol* notFoundInResidue = generateLabelSymbol( cg);1695TR::LabelSymbol* foundLabel = generateLabelSymbol( cg);1696TR::LabelSymbol* foundLabelExtractedScratch = generateLabelSymbol( cg);1697TR::LabelSymbol* failureLabel = generateLabelSymbol( cg);1698TR::LabelSymbol* cFlowRegionEnd = generateLabelSymbol( cg);16991700TR::RegisterDependencyConditions* regDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 8, cg);1701regDeps->addPostCondition(array, TR::RealRegister::AssignAny);1702regDeps->addPostCondition(loopCounter, TR::RealRegister::AssignAny);1703regDeps->addPostCondition(indexRegister, TR::RealRegister::AssignAny);1704regDeps->addPostCondition(loadLength, TR::RealRegister::AssignAny);1705regDeps->addPostCondition(offsetAddress, TR::RealRegister::AssignAny);1706regDeps->addPostCondition(charBufferVector, TR::RealRegister::AssignAny);1707regDeps->addPostCondition(resultVector, TR::RealRegister::AssignAny);1708regDeps->addPostCondition(valueVector, TR::RealRegister::AssignAny);17091710generateVRRfInstruction(cg, TR::InstOpCode::VLVGP, node, valueVector, offset, ch);17111712// Byte or halfword mask1713const int elementSizeMask = isLatin1 ? 0x0 : 0x1;1714generateVRIcInstruction(cg, TR::InstOpCode::VREP, node, valueVector, valueVector, (cg->machine()->getVRFSize() / (1 << elementSizeMask)) - 1, elementSizeMask);1715generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, resultVector, 0, 0);1716generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, charBufferVector, 0, 0);17171718if (cg->comp()->target().is64Bit())1719{1720generateRREInstruction(cg, TR::InstOpCode::LLGFR, node, indexRegister, offset);1721}1722else1723{1724generateRRInstruction(cg, TR::InstOpCode::LR, node, indexRegister, offset);1725}1726generateRRInstruction(cg, TR::InstOpCode::SR, node, length, offset);17271728if (!isLatin1)1729{1730generateRSInstruction(cg, TR::InstOpCode::SLL, node, length, 1);1731generateRSInstruction(cg, TR::InstOpCode::SLL, node, indexRegister, 1);1732}17331734generateRRInstruction(cg, TR::InstOpCode::LR, node, loadLength, length);1735generateRILInstruction(cg, TR::InstOpCode::NILF, node, loadLength, 0xF);1736generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);1737cFlowRegionStart->setStartInternalControlFlow();1738generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BZ, node, fullVectorLabel);17391740// VLL takes an index, not a count, so subtract 1 from the count1741generateRILInstruction(cg, TR::InstOpCode::SLFI, node, loadLength, 1);17421743generateRXInstruction(cg, TR::InstOpCode::LA, node, offsetAddress, generateS390MemoryReference(array, indexRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg));1744generateVRSbInstruction(cg, TR::InstOpCode::VLL, node, charBufferVector, loadLength, generateS390MemoryReference(offsetAddress, 0, cg));17451746generateVRRbInstruction(cg, TR::InstOpCode::VFEE, node, resultVector, charBufferVector, valueVector, 0x1, elementSizeMask);1747generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK1, node, notFoundInResidue);17481749generateVRScInstruction(cg, TR::InstOpCode::VLGV, node, scratch, resultVector, generateS390MemoryReference(7, cg), 0);1750generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CR, node,1751scratch, loadLength,1752TR::InstOpCode::COND_BNH, foundLabelExtractedScratch);17531754generateS390LabelInstruction(cg, TR::InstOpCode::label, node, notFoundInResidue);17551756// Increment index by loaded length + 1, since we subtracted 1 earlier1757generateRIEInstruction(cg, TR::InstOpCode::AHIK, node, loadLength, loadLength, 1);1758generateRRInstruction(cg, TR::InstOpCode::AR, node, indexRegister, loadLength);17591760generateS390LabelInstruction(cg, TR::InstOpCode::label, node, fullVectorLabel);17611762generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node,1763length, sizeOfVector,1764TR::InstOpCode::COND_BL, failureLabel);17651766// Set loopcounter to 1/16 of the length, remainder has already been accounted for1767generateRSInstruction(cg, TR::InstOpCode::SRL, node, loopCounter, loopCounter, 4);17681769generateS390LabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);17701771generateVRXInstruction(cg, TR::InstOpCode::VL, node, charBufferVector, generateS390MemoryReference(array, indexRegister, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg));17721773generateVRRbInstruction(cg, TR::InstOpCode::VFEE, node, resultVector, charBufferVector, valueVector, 0x1, elementSizeMask);1774generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK4, node, foundLabel);17751776generateRILInstruction(cg, TR::InstOpCode::AFI, node, indexRegister, cg->machine()->getVRFSize());17771778generateS390BranchInstruction(cg, TR::InstOpCode::BRCT, node, loopCounter, loopLabel);17791780generateS390LabelInstruction(cg, TR::InstOpCode::label, node, failureLabel);1781generateRIInstruction(cg, TR::InstOpCode::LHI, node, indexRegister, 0xFFFF);1782generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_B, node, cFlowRegionEnd);17831784generateS390LabelInstruction(cg, TR::InstOpCode::label, node, foundLabel);1785generateVRScInstruction(cg, TR::InstOpCode::VLGV, node, scratch, resultVector, generateS390MemoryReference(7, cg), 0);17861787generateS390LabelInstruction(cg, TR::InstOpCode::label, node, foundLabelExtractedScratch);1788generateRRInstruction(cg, TR::InstOpCode::AR, node, indexRegister, scratch);17891790if (!isLatin1)1791{1792generateRSInstruction(cg, TR::InstOpCode::SRL, node, indexRegister, indexRegister, 1);1793}17941795generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, regDeps);1796cFlowRegionEnd->setEndInternalControlFlow();17971798cg->stopUsingRegister(loopCounter);1799cg->stopUsingRegister(loadLength);1800cg->stopUsingRegister(offsetAddress);18011802cg->stopUsingRegister(charBufferVector);1803cg->stopUsingRegister(resultVector);1804cg->stopUsingRegister(valueVector);18051806node->setRegister(indexRegister);18071808cg->recursivelyDecReferenceCount(node->getChild(0));1809cg->decReferenceCount(node->getChild(1));1810cg->decReferenceCount(node->getChild(2));1811cg->decReferenceCount(node->getChild(3));1812cg->decReferenceCount(node->getChild(4));18131814return indexRegister;1815}18161817TR::Register*1818J9::Z::TreeEvaluator::inlineUTF16BEEncode(TR::Node *node, TR::CodeGenerator *cg)1819{1820TR::Compilation* comp = cg->comp();18211822// Create the necessary registers1823TR::Register* output = cg->gprClobberEvaluate(node->getChild(1));1824TR::Register* input = cg->gprClobberEvaluate(node->getChild(0));18251826TR::Register* inputLen = cg->gprClobberEvaluate(node->getChild(2));1827TR::Register* inputLen8 = cg->allocateRegister();18281829TR::Register* temp1 = cg->allocateRegister();1830TR::Register* temp2 = cg->allocateRegister();18311832// Number of bytes currently translated (also used as a stride register)1833TR::Register* translated = cg->allocateRegister();18341835// Convert input length in number of characters to number of bytes1836generateRSInstruction(cg, TR::InstOpCode::getShiftLeftLogicalSingleOpCode(), node, inputLen, inputLen, 1);18371838// Calculate inputLen8 = inputLen / 81839generateRSInstruction(cg, TR::InstOpCode::SRLK, node, inputLen8, inputLen, 3);18401841// Initialize the number of translated bytes to 01842generateRREInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node, translated, translated);18431844// Create the necessary labels1845TR::LabelSymbol * processChar4 = generateLabelSymbol( cg);1846TR::LabelSymbol * processChar4End = generateLabelSymbol( cg);1847TR::LabelSymbol * processChar1 = generateLabelSymbol( cg);1848TR::LabelSymbol * processChar1End = generateLabelSymbol( cg);1849TR::LabelSymbol * processChar1Copy = generateLabelSymbol( cg);18501851const uint16_t surrogateRange1 = 0xD800;1852const uint16_t surrogateRange2 = 0xDFFF;18531854const uint32_t surrogateMaskAND = 0xF800F800;1855const uint32_t surrogateMaskXOR = 0xD800D800;18561857TR::RegisterDependencyConditions* dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 7, cg);18581859// ----------------- Incoming branch -----------------18601861generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processChar4);1862processChar4->setStartInternalControlFlow();18631864// Branch to the end if there are no more multiples of 4 chars left to process1865generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, inputLen8, 0, TR::InstOpCode::COND_MASK8, processChar4End, false, false, NULL, dependencies);18661867// Load 4 input characters from memory and make a copy1868generateRXInstruction(cg, TR::InstOpCode::LG, node, temp1, generateS390MemoryReference(input, translated, 0, cg));1869generateRREInstruction(cg, TR::InstOpCode::LGR, node, temp2, temp1);18701871// AND temp2 by the surrogate mask1872generateRILInstruction(cg, TR::InstOpCode::NIHF, node, temp2, surrogateMaskAND);1873generateRILInstruction(cg, TR::InstOpCode::NILF, node, temp2, surrogateMaskAND);18741875// XOR temp2 by the surrogate mask and branch if CC = 1 (meaning there is a surrogate)1876generateRILInstruction(cg, TR::InstOpCode::XIHF, node, temp2, surrogateMaskXOR);1877generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC1, node, processChar4End);1878generateRILInstruction(cg, TR::InstOpCode::XILF, node, temp2, surrogateMaskXOR);1879generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC1, node, processChar4End);18801881generateRXInstruction(cg, TR::InstOpCode::STG, node, temp1, generateS390MemoryReference(output, translated, 0, cg));18821883// Advance the number of bytes processed1884generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, translated, 8);18851886// Branch back to the start of the loop1887generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK15, node, processChar4);18881889// ----------------- Incoming branch -----------------18901891generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processChar4End);1892processChar4End->setEndInternalControlFlow();1893generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processChar1);1894processChar1->setStartInternalControlFlow();18951896// Branch to the end if there are no more characters left to process1897generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, translated, inputLen, TR::InstOpCode::COND_BNL, processChar1End, false, false);18981899// Load an input character from memory1900generateRXInstruction(cg, TR::InstOpCode::LLH, node, temp1, generateS390MemoryReference(input, translated, 0, cg));19011902// Compare the input character against the lower bound surrogate character range1903generateRILInstruction(cg, TR::InstOpCode::getCmpImmOpCode(), node, temp1, surrogateRange1);19041905// Branch if < (non-surrogate char)1906generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK4, node, processChar1Copy);19071908// Compare the input character against the upper bound surrogate character range1909generateRILInstruction(cg, TR::InstOpCode::getCmpImmOpCode(), node, temp1, surrogateRange2);19101911// Branch if > (non-surrogate char)1912generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK2, node, processChar1Copy);19131914// If we get here it must be a surrogate char1915generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK15, node, processChar1End);19161917// ----------------- Incoming branch -----------------19181919generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processChar1Copy);19201921// Store the lower byte of the character into the output buffer1922generateRXInstruction (cg, TR::InstOpCode::STH, node, temp1, generateS390MemoryReference(output, translated, 0, cg));19231924// Advance the number of bytes processed1925generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, translated, 2);19261927// Branch back to the start of the loop1928generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK15, node, processChar1);19291930// Set up the proper register dependencies1931dependencies->addPostCondition(input, TR::RealRegister::AssignAny);1932dependencies->addPostCondition(inputLen, TR::RealRegister::AssignAny);1933dependencies->addPostCondition(inputLen8, TR::RealRegister::AssignAny);1934dependencies->addPostCondition(temp1, TR::RealRegister::AssignAny);1935dependencies->addPostCondition(temp2, TR::RealRegister::AssignAny);1936dependencies->addPostCondition(output, TR::RealRegister::AssignAny);1937dependencies->addPostCondition(translated, TR::RealRegister::AssignAny);19381939// ----------------- Incoming branch -----------------19401941generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processChar1End, dependencies);1942processChar1End->setEndInternalControlFlow();19431944// Convert translated length in number of bytes to number of characters1945generateRSInstruction(cg, TR::InstOpCode::getShiftRightLogicalSingleOpCode(), node, translated, translated, 1);19461947// Cleanup nodes before returning1948cg->decReferenceCount(node->getChild(0));1949cg->decReferenceCount(node->getChild(1));1950cg->decReferenceCount(node->getChild(2));19511952// Cleanup registers before returning1953cg->stopUsingRegister(input);1954cg->stopUsingRegister(inputLen);1955cg->stopUsingRegister(inputLen8);1956cg->stopUsingRegister(temp1);1957cg->stopUsingRegister(temp2);1958cg->stopUsingRegister(output);19591960return node->setRegister(translated);1961}19621963TR::Register*1964J9::Z::TreeEvaluator::inlineUTF16BEEncodeSIMD(TR::Node *node, TR::CodeGenerator *cg)1965{1966TR::Compilation* comp = cg->comp();19671968// Create the necessary registers1969TR::Register* output = cg->gprClobberEvaluate(node->getChild(1));1970TR::Register* input = cg->gprClobberEvaluate(node->getChild(0));19711972TR::Register* inputLen;1973TR::Register* inputLen16 = cg->allocateRegister();1974TR::Register* inputLenMinus1 = inputLen16;19751976// Number of characters currently translated1977TR::Register* translated = cg->allocateRegister();19781979// Initialize the number of translated characters to 01980generateRREInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node, translated, translated);19811982TR::Node* inputLenNode = node->getChild(2);19831984// Optimize the constant length case1985bool isLenConstant = inputLenNode->getOpCode().isLoadConst() && performTransformation(comp, "O^O [%p] Reduce input length to constant.\n", inputLenNode);19861987if (isLenConstant)1988{1989inputLen = cg->allocateRegister();19901991// Convert input length in number of characters to number of bytes1992generateLoad32BitConstant(cg, inputLenNode, ((getIntegralValue(inputLenNode) * 2)), inputLen, true);1993generateLoad32BitConstant(cg, inputLenNode, ((getIntegralValue(inputLenNode) * 2) >> 4) << 4, inputLen16, true);1994}1995else1996{1997inputLen = cg->gprClobberEvaluate(inputLenNode, true);19981999// Convert input length in number of characters to number of bytes2000generateRSInstruction(cg, TR::InstOpCode::getShiftLeftLogicalSingleOpCode(), node, inputLen, inputLen, 1);20012002// Sign extend the value if needed2003if (cg->comp()->target().is64Bit() && !(inputLenNode->getOpCode().isLong()))2004{2005generateRRInstruction(cg, TR::InstOpCode::getLoadRegWidenOpCode(), node, inputLen, inputLen);2006generateRRInstruction(cg, TR::InstOpCode::getLoadRegWidenOpCode(), node, inputLen16, inputLen);2007}2008else2009{2010generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, inputLen16, inputLen);2011}20122013// Truncate the 4 right most bits2014generateRIInstruction(cg, TR::InstOpCode::NILL, node, inputLen16, static_cast <int16_t> (0xFFF0));2015}20162017// Create the necessary vector registers2018TR::Register* vInput = cg->allocateRegister(TR_VRF);2019TR::Register* vSurrogate = cg->allocateRegister(TR_VRF); // Track index of first surrogate char20202021TR::Register* vRange = cg->allocateRegister(TR_VRF);2022TR::Register* vRangeControl = cg->allocateRegister(TR_VRF);20232024// Initialize the vector registers2025uint16_t surrogateRange1 = 0xD800;2026uint16_t surrogateRange2 = 0xDFFF;20272028uint16_t surrogateControl1 = 0xA000; // >= comparison2029uint16_t surrogateControl2 = 0xC000; // <= comparison20302031generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, vRange, 0, 0 /*unused*/);2032generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, vRangeControl, 0, 0 /*unused*/);20332034generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, vRange, surrogateRange1, 0);2035generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, vRange, surrogateRange2, 1);20362037generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, vRangeControl, surrogateControl1, 0);2038generateVRIaInstruction(cg, TR::InstOpCode::VLEIH, node, vRangeControl, surrogateControl2, 1);20392040// Create the necessary labels2041TR::LabelSymbol * process8Chars = generateLabelSymbol(cg);2042TR::LabelSymbol * process8CharsEnd = generateLabelSymbol(cg);20432044TR::LabelSymbol * processUnder8Chars = generateLabelSymbol(cg);2045TR::LabelSymbol * processUnder8CharsEnd = generateLabelSymbol(cg);20462047TR::LabelSymbol * processSurrogate = generateLabelSymbol(cg);2048TR::LabelSymbol * processSurrogateEnd = generateLabelSymbol(cg);20492050// Branch to the end if there are no more multiples of 8 chars left to process2051generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, inputLen16, 0, TR::InstOpCode::COND_MASK8, process8CharsEnd, false, false);20522053// ----------------- Incoming branch -----------------20542055generateS390LabelInstruction(cg, TR::InstOpCode::label, node, process8Chars);2056process8Chars->setStartInternalControlFlow();20572058// Load 16 bytes (8 chars) into vector register2059generateVRXInstruction(cg, TR::InstOpCode::VL, node, vInput, generateS390MemoryReference(input, translated, 0, cg));20602061// Check for vector surrogates and branch to copy the non-surrogate bytes2062generateVRRdInstruction(cg, TR::InstOpCode::VSTRC, node, vSurrogate, vInput, vRange, vRangeControl, 0x1, 1);2063generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC1, node, processSurrogate);20642065// Store the result2066generateVRXInstruction(cg, TR::InstOpCode::VST, node, vInput, generateS390MemoryReference(output, translated, 0, cg));20672068// Advance the stride register2069generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, translated, 16);20702071// Loop back if there is at least 8 chars left to process2072generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, translated, inputLen16, TR::InstOpCode::COND_BL, process8Chars, false, false);20732074generateS390LabelInstruction(cg, TR::InstOpCode::label, node, process8CharsEnd);2075process8CharsEnd->setEndInternalControlFlow();20762077// ----------------- Incoming branch -----------------20782079generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processUnder8Chars);2080processUnder8Chars->setStartInternalControlFlow();20812082// Calculate the number of residue bytes available2083generateRRInstruction(cg, TR::InstOpCode::getSubstractRegOpCode(), node, inputLen, translated);20842085// Branch to the end if there is no residue2086generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC0, node, processUnder8CharsEnd);20872088// VLL and VSTL work on indices so we must subtract 12089generateRIEInstruction(cg, TR::InstOpCode::getAddLogicalRegRegImmediateOpCode(), node, inputLenMinus1, inputLen, -1);20902091// Zero out the input register to avoid invalid VSTRC result2092generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, vInput, 0, 0 /*unused*/);20932094// VLL instruction can only handle memory references of type D(B), so increment the base input address2095generateRRInstruction (cg, TR::InstOpCode::getAddRegOpCode(), node, input, translated);20962097// Load residue bytes into vector register2098generateVRSbInstruction(cg, TR::InstOpCode::VLL, node, vInput, inputLenMinus1, generateS390MemoryReference(input, 0, cg));20992100// Check for vector surrogates and branch to copy the non-surrogate bytes2101generateVRRdInstruction(cg, TR::InstOpCode::VSTRC, node, vSurrogate, vInput, vRange, vRangeControl, 0x1, 1);21022103generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC3, node, processSurrogateEnd);21042105// ----------------- Incoming branch -----------------21062107generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processSurrogate);21082109// Extract the index of the first surrogate char2110generateVRScInstruction(cg, TR::InstOpCode::VLGV, node, inputLen, vSurrogate, generateS390MemoryReference(7, cg), 0);21112112// Return in the case of saturation at index 02113generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, inputLen, 0, TR::InstOpCode::COND_CC0, processUnder8CharsEnd, false, false);21142115// VLL and VSTL work on indices so we must subtract 12116generateRIEInstruction(cg, TR::InstOpCode::getAddLogicalRegRegImmediateOpCode(), node, inputLenMinus1, inputLen, -1);21172118// ----------------- Incoming branch -----------------21192120generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processSurrogateEnd);21212122// VSTL instruction can only handle memory references of type D(B), so increment the base output address2123generateRRInstruction (cg, TR::InstOpCode::getAddRegOpCode(), node, output, translated);21242125// Store the result2126generateVRSbInstruction(cg, TR::InstOpCode::VSTL, node, vInput, inputLenMinus1, generateS390MemoryReference(output, 0, cg), 0);21272128// Advance the stride register2129generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, translated, inputLen);21302131// Set up the proper register dependencies2132TR::RegisterDependencyConditions* dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 9, cg);21332134dependencies->addPostCondition(input, TR::RealRegister::AssignAny);2135dependencies->addPostCondition(inputLen, TR::RealRegister::AssignAny);2136dependencies->addPostCondition(inputLen16, TR::RealRegister::AssignAny);2137dependencies->addPostCondition(output, TR::RealRegister::AssignAny);2138dependencies->addPostCondition(translated, TR::RealRegister::AssignAny);21392140dependencies->addPostCondition(vInput, TR::RealRegister::AssignAny);2141dependencies->addPostCondition(vSurrogate, TR::RealRegister::AssignAny);2142dependencies->addPostCondition(vRange, TR::RealRegister::AssignAny);2143dependencies->addPostCondition(vRangeControl, TR::RealRegister::AssignAny);21442145// ----------------- Incoming branch -----------------21462147generateS390LabelInstruction(cg, TR::InstOpCode::label, node, processUnder8CharsEnd, dependencies);2148processUnder8CharsEnd->setEndInternalControlFlow();21492150// Convert translated length in number of bytes to number of characters2151generateRSInstruction(cg, TR::InstOpCode::getShiftRightLogicalSingleOpCode(), node, translated, translated, 1);21522153// Cleanup nodes before returning2154cg->decReferenceCount(node->getChild(0));2155cg->decReferenceCount(node->getChild(1));2156cg->decReferenceCount(node->getChild(2));21572158// Cleanup registers before returning2159cg->stopUsingRegister(input);2160cg->stopUsingRegister(inputLen);2161cg->stopUsingRegister(inputLen16);2162cg->stopUsingRegister(output);21632164cg->stopUsingRegister(vInput);2165cg->stopUsingRegister(vSurrogate);2166cg->stopUsingRegister(vRange);2167cg->stopUsingRegister(vRangeControl);21682169return node->setRegister(translated);2170}21712172TR::Register*2173J9::Z::TreeEvaluator::inlineStringHashCode(TR::Node* node, TR::CodeGenerator* cg, bool isCompressed)2174{2175TR::Compilation* comp = cg->comp();2176//stringSize = Number of bytes to load to process 4 characters in SIMD loop2177//terminateVal = SIMD loop cotroller allowing characters in multiple of 4 to be processes by loop2178//VLLEZ instruction will load word(compressed String) or double word (decompressed String), elementSize is used for that2179const short stringSize = (isCompressed ? 4 : 8);2180const short terminateVal = (isCompressed ? 3 : 6);2181const short elementSize = (isCompressed ? 2 : 3);21822183TR::Node* nodeValue = node->getChild(0);2184TR::Node* nodeIndex = node->getChild(1);2185TR::Node* nodeCount = node->getChild(2);21862187// Create the necessary labels2188TR::LabelSymbol * cFlowRegionStart = generateLabelSymbol(cg);21892190TR::LabelSymbol * labelVector = generateLabelSymbol(cg);2191TR::LabelSymbol * labelVectorLoop = generateLabelSymbol(cg);2192TR::LabelSymbol * labelVectorReduce = generateLabelSymbol(cg);21932194TR::LabelSymbol * labelSerial = generateLabelSymbol(cg);21952196TR::LabelSymbol * labelSerialLoop = generateLabelSymbol(cg);21972198TR::LabelSymbol * cFlowRegionEnd = generateLabelSymbol(cg);21992200// Create the necessary registers2201TR::Register* registerHash = cg->allocateRegister();22022203TR::Register* registerValue = cg->evaluate(nodeValue);2204TR::Register* registerIndex = cg->gprClobberEvaluate(nodeIndex);2205TR::Register* registerCount = cg->gprClobberEvaluate(nodeCount);22062207if (cg->comp()->target().is64Bit())2208{2209generateRRInstruction(cg, TR::InstOpCode::getLoadRegWidenOpCode(), node, registerIndex, registerIndex);2210generateRRInstruction(cg, TR::InstOpCode::getLoadRegWidenOpCode(), node, registerCount, registerCount);2211}22122213TR::Register* registerVA = cg->allocateRegister(TR_VRF);2214TR::Register* registerVB = cg->allocateRegister(TR_VRF);2215TR::Register* registerVC = cg->allocateRegister(TR_VRF);22162217TR::Register* registerEnd = cg->allocateRegister(TR_GPR);22182219TR::RegisterDependencyConditions* dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 12, cg);22202221generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);2222cFlowRegionStart->setStartInternalControlFlow();22232224if(!isCompressed)2225{2226// registerIndex *= 2 and registerCount *= 22227generateRSInstruction(cg, TR::InstOpCode::getShiftLeftLogicalSingleOpCode(), node, registerIndex, registerIndex, 1);2228generateRSInstruction(cg, TR::InstOpCode::getShiftLeftLogicalSingleOpCode(), node, registerCount, registerCount, 1);2229}22302231// registerEnd = registerIndex + registerCount2232generateRXInstruction(cg, TR::InstOpCode::getLoadAddressOpCode(), node, registerEnd, generateS390MemoryReference(registerIndex, registerCount, 0, cg));22332234// registerHash = 02235generateRREInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node, registerHash, registerHash);22362237// Branch to labelSerial if registerCount < stringSize2238generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, registerCount, static_cast<int32_t>(stringSize), TR::InstOpCode::COND_MASK4, labelSerial, false, false);22392240generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelVector);22412242// registerEnd -= terminateVal2243generateRILInstruction(cg, TR::InstOpCode::getSubtractLogicalImmOpCode(), node, registerEnd, terminateVal);22442245// snippetData1 = [31^4, 31^4, 31^4, 31^4]2246int32_t snippetData1[4] = {923521, 923521, 923521, 923521};22472248TR::MemoryReference* memrefSnippet1 = generateS390MemoryReference(cg->findOrCreateConstant(node, snippetData1, 16), cg, 0, node);22492250dependencies->addAssignAnyPostCondOnMemRef(memrefSnippet1);22512252// registerVA = snippetData12253generateVRXInstruction(cg, TR::InstOpCode::VL, node, registerVA, memrefSnippet1);22542255// registerVB = 02256generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, registerVB, 0, 0 /*unused*/);22572258// ----------------- Incoming branch -----------------22592260generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelVectorLoop);22612262// registerVC = 4 consecutive chars (16 bit shorts or 8 bit bytes depending on String Compression) at the current index2263generateVRXInstruction(cg, TR::InstOpCode::VLLEZ, node, registerVC, generateS390MemoryReference(registerValue, registerIndex, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg), elementSize);22642265if (!isCompressed)2266{2267// registerVC = unpack 4 (16 bit) short elements into 4 (32 bit) int elements2268generateVRRaInstruction(cg, TR::InstOpCode::VUPLH, node, registerVC, registerVC, 0, 0, 1);2269}2270else2271{2272// registerVC = unpack 4 (8 bit) byte elements into 4 (32 bit) int elements2273generateVRRaInstruction(cg, TR::InstOpCode::VUPLH, node, registerVC, registerVC, 0, 0, 0);2274generateVRRaInstruction(cg, TR::InstOpCode::VUPLL, node, registerVC, registerVC, 0, 0, 1);2275}22762277// registerVB = registerVB * registerVA + registerVC2278generateVRRdInstruction(cg, TR::InstOpCode::VMAL, node, registerVB, registerVB, registerVA, registerVC, 0, 2);22792280// registerIndex += stringSize2281generateRXInstruction(cg, TR::InstOpCode::getLoadAddressOpCode(), node, registerIndex, generateS390MemoryReference(registerIndex, stringSize, cg));22822283// Branch to labelVectorLoop if registerIndex < registerEnd2284generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpLogicalRegOpCode(), node, registerIndex, registerEnd, TR::InstOpCode::COND_MASK4, labelVectorLoop, false, false);22852286generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelVectorReduce);22872288// snippetData2 = [31^3, 31^2, 31^1, 31^0]2289int32_t snippetData2[4] = {29791, 961, 31, 1};22902291TR::MemoryReference* memrefSnippet2 = generateS390MemoryReference(cg->findOrCreateConstant(node, snippetData2, 16), cg, 0, node);22922293dependencies->addAssignAnyPostCondOnMemRef(memrefSnippet2);22942295// registerVA = snippetData22296generateVRXInstruction(cg, TR::InstOpCode::VL, node, registerVA, memrefSnippet2);22972298// registerVB = registerVB * registerVA2299generateVRRcInstruction(cg, TR::InstOpCode::VML, node, registerVB, registerVB, registerVA, 2);23002301// registerVA = 02302generateVRIaInstruction(cg, TR::InstOpCode::VGBM, node, registerVA, 0, 0 /*unused*/);23032304// registerVA = sum of 4 (32 bit) int elements2305generateVRRcInstruction(cg, TR::InstOpCode::VSUMQ, node, registerVA, registerVB, registerVA, 0, 0, 2);23062307// registerEnd += terminateVal2308generateRXInstruction(cg, TR::InstOpCode::getLoadAddressOpCode(), node, registerEnd, generateS390MemoryReference(registerEnd, terminateVal, cg));23092310generateVRScInstruction(cg, TR::InstOpCode::VLGV, node, registerHash, registerVA, generateS390MemoryReference(3, cg), 2);23112312// ----------------- Incoming branch -----------------23132314generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelSerial);2315labelSerial->setEndInternalControlFlow();23162317// Branch to labelEnd if registerIndex >= registerEnd2318generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpLogicalRegOpCode(), node, registerIndex, registerEnd, TR::InstOpCode::COND_MASK10, cFlowRegionEnd, false, false);23192320// ----------------- Incoming branch -----------------23212322generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelSerialLoop);2323labelSerialLoop->setStartInternalControlFlow();23242325TR::Register* registerTemp = registerCount;23262327// registerTemp = registerHash << 52328generateRSInstruction(cg, TR::InstOpCode::SLLK, node, registerTemp, registerHash, 5);23292330// registerTemp -= registerHash2331generateRRInstruction(cg, TR::InstOpCode::getSubstractRegOpCode(), node, registerTemp, registerHash);23322333// registerHash = char at registerIndex2334if(isCompressed)2335generateRXInstruction(cg, TR::InstOpCode::LLGC, node, registerHash, generateS390MemoryReference(registerValue, registerIndex, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg));2336else2337generateRXInstruction(cg, TR::InstOpCode::LLH, node, registerHash, generateS390MemoryReference(registerValue, registerIndex, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg));23382339if(isCompressed) //registerIndex += 12340generateRXInstruction(cg, TR::InstOpCode::getLoadAddressOpCode(), node, registerIndex, generateS390MemoryReference(registerIndex, 1, cg));2341else //registerIndex += 22342generateRXInstruction(cg, TR::InstOpCode::getLoadAddressOpCode(), node, registerIndex, generateS390MemoryReference(registerIndex, 2, cg));234323442345// registerHash += registerTemp2346generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, registerHash, registerTemp);23472348// Branch to labelSerialLoop if registerIndex < registerEnd2349generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpLogicalRegOpCode(), node, registerIndex, registerEnd, TR::InstOpCode::COND_MASK4, labelSerialLoop, false, false);23502351// Set up the proper register dependencies2352dependencies->addPostConditionIfNotAlreadyInserted(registerValue, TR::RealRegister::AssignAny);2353dependencies->addPostConditionIfNotAlreadyInserted(registerIndex, TR::RealRegister::AssignAny);2354dependencies->addPostConditionIfNotAlreadyInserted(registerCount, TR::RealRegister::AssignAny);23552356dependencies->addPostConditionIfNotAlreadyInserted(registerHash, TR::RealRegister::AssignAny);2357dependencies->addPostConditionIfNotAlreadyInserted(registerEnd, TR::RealRegister::AssignAny);23582359dependencies->addPostConditionIfNotAlreadyInserted(registerVA, TR::RealRegister::AssignAny);2360dependencies->addPostConditionIfNotAlreadyInserted(registerVB, TR::RealRegister::AssignAny);2361dependencies->addPostConditionIfNotAlreadyInserted(registerVC, TR::RealRegister::AssignAny);23622363generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, dependencies);2364cFlowRegionEnd->setEndInternalControlFlow();23652366// Cleanup nodes before returning2367cg->decReferenceCount(nodeValue);2368cg->decReferenceCount(nodeIndex);2369cg->decReferenceCount(nodeCount);23702371// Cleanup registers before returning2372cg->stopUsingRegister(registerValue);2373cg->stopUsingRegister(registerIndex);2374cg->stopUsingRegister(registerCount);23752376cg->stopUsingRegister(registerEnd);23772378cg->stopUsingRegister(registerVA);2379cg->stopUsingRegister(registerVB);2380cg->stopUsingRegister(registerVC);23812382return node->setRegister(registerHash);2383}23842385TR::Register*2386J9::Z::TreeEvaluator::toUpperIntrinsic(TR::Node *node, TR::CodeGenerator *cg, bool isCompressedString)2387{2388cg->generateDebugCounter("z13/simd/toUpper", 1, TR::DebugCounter::Free);2389return caseConversionHelper(node, cg, true, isCompressedString);2390}23912392TR::Register*2393J9::Z::TreeEvaluator::toLowerIntrinsic(TR::Node *node, TR::CodeGenerator *cg, bool isCompressedString)2394{2395cg->generateDebugCounter("z13/simd/toLower", 1, TR::DebugCounter::Free);2396return caseConversionHelper(node, cg, false, isCompressedString);2397}23982399TR::Register*2400J9::Z::TreeEvaluator::inlineDoubleMax(TR::Node *node, TR::CodeGenerator *cg)2401{2402cg->generateDebugCounter("z13/simd/doubleMax", 1, TR::DebugCounter::Free);2403return doubleMaxMinHelper(node, cg, true);2404}24052406TR::Register*2407J9::Z::TreeEvaluator::inlineDoubleMin(TR::Node *node, TR::CodeGenerator *cg)2408{2409cg->generateDebugCounter("z13/simd/doubleMin", 1, TR::DebugCounter::Free);2410return doubleMaxMinHelper(node, cg, false);2411}24122413TR::Register *2414J9::Z::TreeEvaluator::inlineMathFma(TR::Node *node, TR::CodeGenerator *cg)2415{2416TR_ASSERT_FATAL(node->getNumChildren() == 3,2417"In function inlineMathFma, the node at address %p should have exactly 3 children, but got %u instead", node, node->getNumChildren());24182419TR::Register * targetRegister = cg->allocateRegister(TR_FPR);24202421TR::Register * v1 = cg->evaluate(node->getFirstChild());2422TR::Register * v2 = cg->evaluate(node->getSecondChild());2423TR::Register * v3 = cg->evaluate(node->getThirdChild());24242425uint8_t mask6 = getVectorElementSizeMask(TR::DataType::getSize(node->getDataType()));2426generateVRReInstruction(cg, TR::InstOpCode::VFMA, node, targetRegister, v1, v2, v3, mask6, 0);24272428node->setRegister(targetRegister);24292430cg->decReferenceCount(node->getFirstChild());2431cg->decReferenceCount(node->getSecondChild());2432cg->decReferenceCount(node->getThirdChild());24332434return targetRegister;2435}24362437/*2438* J9 S390 specific tree evaluator table overrides2439*/2440extern void TEMPORARY_initJ9S390TreeEvaluatorTable(TR::CodeGenerator *cg)2441{2442TR_TreeEvaluatorFunctionPointer *tet = cg->getTreeEvaluatorTable();24432444tet[TR::monent] = TR::TreeEvaluator::monentEvaluator;2445tet[TR::monexit] = TR::TreeEvaluator::monexitEvaluator;2446tet[TR::monexitfence] = TR::TreeEvaluator::monexitfenceEvaluator;2447tet[TR::asynccheck] = TR::TreeEvaluator::asynccheckEvaluator;2448tet[TR::instanceof] = TR::TreeEvaluator::instanceofEvaluator;2449tet[TR::checkcast] = TR::TreeEvaluator::checkcastEvaluator;2450tet[TR::checkcastAndNULLCHK] = TR::TreeEvaluator::checkcastAndNULLCHKEvaluator;2451tet[TR::New] = TR::TreeEvaluator::newObjectEvaluator;2452tet[TR::variableNew] = TR::TreeEvaluator::newObjectEvaluator;2453tet[TR::newarray] = TR::TreeEvaluator::newArrayEvaluator;2454tet[TR::anewarray] = TR::TreeEvaluator::anewArrayEvaluator;2455tet[TR::variableNewArray] = TR::TreeEvaluator::anewArrayEvaluator;2456tet[TR::multianewarray] = TR::TreeEvaluator::multianewArrayEvaluator;2457tet[TR::arraylength] = TR::TreeEvaluator::arraylengthEvaluator;2458tet[TR::ResolveCHK] = TR::TreeEvaluator::resolveCHKEvaluator;2459tet[TR::DIVCHK] = TR::TreeEvaluator::DIVCHKEvaluator;2460tet[TR::BNDCHK] = TR::TreeEvaluator::BNDCHKEvaluator;2461tet[TR::ArrayCopyBNDCHK] = TR::TreeEvaluator::ArrayCopyBNDCHKEvaluator;2462tet[TR::BNDCHKwithSpineCHK] = TR::TreeEvaluator::BNDCHKwithSpineCHKEvaluator;2463tet[TR::SpineCHK] = TR::TreeEvaluator::BNDCHKwithSpineCHKEvaluator;2464tet[TR::ArrayStoreCHK] = TR::TreeEvaluator::ArrayStoreCHKEvaluator;2465tet[TR::ArrayCHK] = TR::TreeEvaluator::ArrayCHKEvaluator;2466tet[TR::MethodEnterHook] = TR::TreeEvaluator::conditionalHelperEvaluator;2467tet[TR::MethodExitHook] = TR::TreeEvaluator::conditionalHelperEvaluator;24682469tet[TR::tstart] = TR::TreeEvaluator::tstartEvaluator;2470tet[TR::tfinish] = TR::TreeEvaluator::tfinishEvaluator;2471tet[TR::tabort] = TR::TreeEvaluator::tabortEvaluator;24722473tet[TR::NULLCHK] = TR::TreeEvaluator::NULLCHKEvaluator;2474tet[TR::ResolveAndNULLCHK] = TR::TreeEvaluator::resolveAndNULLCHKEvaluator;2475}247624772478TR::Instruction *2479J9::Z::TreeEvaluator::genLoadForObjectHeaders(TR::CodeGenerator *cg, TR::Node *node, TR::Register *reg, TR::MemoryReference *tempMR, TR::Instruction *iCursor)2480{2481if (TR::Compiler->om.compressObjectReferences())2482return generateRXInstruction(cg, TR::InstOpCode::LLGF, node, reg, tempMR, iCursor);2483return generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, reg, tempMR, iCursor);2484}24852486TR::Instruction *2487J9::Z::TreeEvaluator::genLoadForObjectHeadersMasked(TR::CodeGenerator *cg, TR::Node *node, TR::Register *reg, TR::MemoryReference *tempMR, TR::Instruction *iCursor)2488{2489// Bit-mask for masking J9Object header to extract J9Class2490uint16_t mask = 0xFF00;2491TR::Compilation *comp = cg->comp();2492TR::Instruction *loadInstr;24932494if (TR::Compiler->om.compressObjectReferences())2495{2496if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_S390_Z13))2497{2498iCursor = generateRXInstruction(cg, TR::InstOpCode::LLZRGF, node, reg, tempMR, iCursor);2499loadInstr = iCursor;2500cg->generateDebugCounter("z13/LoadAndMask", 1, TR::DebugCounter::Free);2501}2502else2503{2504// Zero out top 32 bits and load the unmasked J9Class2505iCursor = generateRXInstruction(cg, TR::InstOpCode::LLGF, node, reg, tempMR, iCursor);2506loadInstr = iCursor;2507// Now mask it to get the actual pointer2508iCursor = generateRIInstruction(cg, TR::InstOpCode::NILL, node, reg, mask, iCursor);2509}2510}2511else2512{2513if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_S390_Z13))2514{2515iCursor = generateRXInstruction(cg, TR::InstOpCode::getLoadAndMaskOpCode(), node, reg, tempMR, iCursor);2516loadInstr = iCursor;2517cg->generateDebugCounter("z13/LoadAndMask", 1, TR::DebugCounter::Free);2518}2519else2520{2521iCursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, reg, tempMR, iCursor);2522loadInstr = iCursor;2523iCursor = generateRIInstruction(cg, TR::InstOpCode::NILL, node, reg, mask, iCursor);2524}2525}25262527// The intended functionality of rdbar/wrtbar IL nodes is to first report to the VM that a field is being watched2528// (i.e. being read or being written to), and then perform the actual load/store operation. To achieve this, evaluators2529// for rdbar/wrtbar opcodes first call helper routines to generate code that will report to the VM that a field is being2530// read or written to. Following this, they will perform the actual load/store operation on the field.2531// The helper routines can call this routine in order to determine if fieldwatch is enabled2532// on a particular Java class. In those cases we may end up loading the Java class before the actual indirect load occurs2533// on the field. In general, if the object we are trying to load is null, an exception is thrown during the load.2534// To handle this we need to set an exception point and the GC Map for the VM. We must do the same here for rdbar/wrtbar for2535// the above explained reason.2536if (node->getOpCode().isReadBar() || node->getOpCode().isWrtBar())2537{2538cg->setImplicitExceptionPoint(loadInstr);2539loadInstr->setNeedsGCMap(0x0000FFFF);2540if (node->getOpCodeValue() == TR::checkcastAndNULLCHK)2541{2542loadInstr->setNode(comp->findNullChkInfo(node));2543}2544}2545return iCursor;2546}25472548// max number of cache slots used by checkcat/instanceof2549#define NUM_PICS 325502551static TR::Instruction *2552genTestIsSuper(TR::CodeGenerator * cg, TR::Node * node,2553TR::Register * objClassReg, TR::Register * castClassReg,2554TR::Register * scratch1Reg, TR::Register * scratch2Reg, TR::Register * resultReg,2555TR::Register * litPoolBaseReg, int32_t castClassDepth,2556TR::LabelSymbol * failLabel, TR::LabelSymbol * trueLabel, TR::LabelSymbol * callHelperLabel,2557TR::RegisterDependencyConditions * conditions, TR::Instruction * cursor,2558bool addDataSnippetAsSecondaryCache,2559TR::Register * classObjectClazzSnippetReg,2560TR::Register * instanceOfClazzSnippetReg2561)2562{2563TR::Compilation *comp = cg->comp();2564TR_Debug * debugObj = cg->getDebug();25652566int32_t superClassOffset = castClassDepth * TR::Compiler->om.sizeofReferenceAddress();2567bool outOfBound = (superClassOffset > MAX_IMMEDIATE_VAL || superClassOffset < MIN_IMMEDIATE_VAL) ? true : false;2568// For the scenario where a call to Class.isInstance() is converted to instanceof,2569// we need to load the class depth at runtime because we don't have it at compile time2570bool dynamicCastClass = (castClassDepth == -1);2571bool eliminateSuperClassArraySizeCheck = (!dynamicCastClass && (castClassDepth < comp->getOptions()->_minimumSuperclassArraySize));257225732574#ifdef OMR_GC_COMPRESSED_POINTERS2575// objClassReg contains the class offset, so we may need to2576// convert this offset to a real J9Class pointer2577#endif2578if (dynamicCastClass)2579{2580TR::LabelSymbol * notInterfaceLabel = generateLabelSymbol(cg);2581TR_ASSERT((node->getOpCodeValue() == TR::instanceof &&2582node->getSecondChild()->getOpCodeValue() != TR::loadaddr), "genTestIsSuper: castClassDepth == -1 is only supported for transformed isInstance calls.");25832584// check if cast class is an interface2585cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratch1Reg,2586generateS390MemoryReference(castClassReg, offsetof(J9Class, romClass), cg), cursor);25872588cursor = generateRXInstruction(cg, TR::InstOpCode::L, node, scratch1Reg,2589generateS390MemoryReference(scratch1Reg, offsetof(J9ROMClass, modifiers), cg), cursor);259025912592TR_ASSERT(((J9AccInterface | J9AccClassArray) < UINT_MAX && (J9AccInterface | J9AccClassArray) > 0),2593"genTestIsSuper::(J9AccInterface | J9AccClassArray) is not a 32-bit number\n");25942595cursor = generateRILInstruction(cg, TR::InstOpCode::NILF, node, scratch1Reg, static_cast<int32_t>((J9AccInterface | J9AccClassArray)), cursor);25962597if (debugObj)2598debugObj->addInstructionComment(cursor, "Check if castClass is an interface or class array and jump to helper sequence");25992600// insert snippet check2601if ( addDataSnippetAsSecondaryCache )2602{2603cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, notInterfaceLabel, cursor);2604// classObjectClazzSnippet and instanceOfClazzSnippet stores values of currentObject and cast Object when2605// the helper call returns success.2606// test if class is interface of not.2607// if interface, we do the following.2608//2609// insert instanceof site snippet test2610// cmp objectClassReg, classObjectClazzSnippet2611// jne helper call2612// cmp castclassreg, instanceOfClazzSnippet2613// je true_label2614// jump to outlined label2615// test jitInstanceOf results2616// JE fail_label // instanceof result is not true2617//2618// the following will be done at the end of instanceof evaluation when we do helperCall2619// cmp snippet1 with value -12620// jne true_label // snippet already updated2621// update classObjectClazzSnippet, instanceOfClazzSnippet with object class and instance of class2622// jmp true_label2623//NO need for cache test for z, if it is dynamic we will already have failed cache test if we got here.2624cursor = generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, objClassReg, generateS390MemoryReference(classObjectClazzSnippetReg,0,cg), cursor);2625cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, callHelperLabel, cursor);2626cursor = generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, castClassReg, generateS390MemoryReference(instanceOfClazzSnippetReg,0,cg), cursor);2627cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, trueLabel, cursor);2628cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, callHelperLabel, cursor);2629cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, notInterfaceLabel, cursor);2630}2631else2632{2633cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, callHelperLabel, cursor);2634}2635}263626372638TR::InstOpCode::Mnemonic loadOp;2639int32_t bytesOffset;26402641if (comp->target().is64Bit())2642{2643loadOp = TR::InstOpCode::LLGH;2644bytesOffset = 6;2645}2646else2647{2648loadOp = TR::InstOpCode::LLH;2649bytesOffset = 2;2650}26512652if (dynamicCastClass)2653{2654cursor = generateRXInstruction(cg, loadOp, node, scratch2Reg,2655generateS390MemoryReference(castClassReg, offsetof(J9Class, classDepthAndFlags) + bytesOffset, cg), cursor);26562657TR_ASSERT(sizeof(((J9Class*)0)->classDepthAndFlags) == sizeof(uintptr_t),2658"genTestIsSuper::J9Class->classDepthAndFlags is wrong size\n");2659}26602661if (!eliminateSuperClassArraySizeCheck)2662{2663if (resultReg)2664{2665cursor = generateRIInstruction(cg, TR::InstOpCode::LHI, node, resultReg, 0, cursor);2666}26672668cursor = generateRXInstruction(cg, loadOp, node, scratch1Reg,2669generateS390MemoryReference(objClassReg, offsetof(J9Class, classDepthAndFlags) + bytesOffset, cg) , cursor);2670TR_ASSERT(sizeof(((J9Class*)0)->classDepthAndFlags) == sizeof(uintptr_t),2671"genTestIsSuper::J9Class->classDepthAndFlags is wrong size\n");26722673bool generateCompareAndBranchIsPossible = false;26742675if (dynamicCastClass)2676generateCompareAndBranchIsPossible = true;2677else if (outOfBound)2678{2679if (comp->target().is64Bit())2680{2681cursor = genLoadLongConstant(cg, node, castClassDepth, scratch2Reg, cursor, conditions, litPoolBaseReg);2682}2683else2684{2685cursor = generateLoad32BitConstant(cg, node, castClassDepth, scratch2Reg, false, cursor, conditions, litPoolBaseReg);2686}2687generateCompareAndBranchIsPossible = true;2688}2689else2690{2691cursor = generateRIInstruction(cg, TR::InstOpCode::getCmpHalfWordImmOpCode(), node, scratch1Reg, castClassDepth, cursor);2692}26932694if (generateCompareAndBranchIsPossible)2695cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, scratch1Reg, scratch2Reg, TR::InstOpCode::COND_BNH, failLabel, false, false);2696else2697cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, failLabel, cursor);26982699if (debugObj)2700debugObj->addInstructionComment(cursor, "Fail if depth(obj) > depth(castClass)");27012702}27032704if (resultReg)2705{2706cursor = generateRIInstruction(cg, TR::InstOpCode::LHI, node, resultReg, 1, cursor);2707}2708#ifdef OMR_GC_COMPRESSED_POINTERS2709// objClassReg contains the class offset, so we may need to2710// convert this offset to a real J9Class pointer2711#endif2712cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratch1Reg,2713generateS390MemoryReference(objClassReg, offsetof(J9Class, superclasses), cg), cursor);27142715if (outOfBound || dynamicCastClass)2716{2717if (comp->target().is64Bit())2718{2719cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, scratch2Reg, scratch2Reg, 3, cursor);2720}2721else2722{2723cursor = generateRSInstruction(cg, TR::InstOpCode::SLL, node, scratch2Reg, 2, cursor);2724}2725#ifdef OMR_GC_COMPRESSED_POINTERS2726// castClassReg contains the class offset, but the memory reference below will2727// generate a J9Class pointer. We may need to convert this pointer to an offset2728#endif2729cursor = generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, castClassReg,2730generateS390MemoryReference(scratch1Reg, scratch2Reg, 0, cg), cursor);2731}2732else2733{2734#ifdef OMR_GC_COMPRESSED_POINTERS2735// castClassReg contains the class offset, but the memory reference below will2736// generate a J9Class pointer. We may need to convert this pointer to an offset2737#endif2738cursor = generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, castClassReg,2739generateS390MemoryReference(scratch1Reg, superClassOffset, cg), cursor);2740}27412742if (debugObj)2743debugObj->addInstructionComment(cursor, "Check if objClass is subclass of castClass");27442745return cursor;2746}27472748// Checks for the scenario where a call to Class.isInstance() is converted to instanceof,2749// and we need to load the j9class of the cast class at runtime because we don't have it at compile time2750static bool isDynamicCastClassPointer(TR::Node * castOrInstanceOfNode)2751{2752if (castOrInstanceOfNode->getOpCodeValue() == TR::instanceof)2753{2754TR::Node * castClassNode = castOrInstanceOfNode->getSecondChild();2755TR_OpaqueClassBlock* castClassAddr = TR::TreeEvaluator::getCastClassAddress(castClassNode);27562757bool isUnresolved = castOrInstanceOfNode->getOpCode().hasSymbolReference() && castOrInstanceOfNode->getSymbolReference()->isUnresolved();27582759// came from transformed call isInstance to node instanceof, can't resolve at compile time2760return !castClassAddr && !isUnresolved;2761}2762return false;2763}27642765/*2766* generate test if object class is reference array2767* testerReg = load (objectClassReg+offset_romClass)2768* andImmediate with J9AccClassArray(0x10000)2769* MASK6 failLabel(If not Array we Fail)2770* testerReg = load (objectClassReg + leafcomponent_offset)2771* testerReg = load (objectClassReg + offset_romClass)2772* testerReg = load (objectClassReg + offset_modifiers)2773* andImmediate with J9AccClassInternalPrimitiveType(0x20000)2774* MASK6 trueLabel(if equal we fail, not equal we succeed)2775*/2776static void genIsReferenceArrayTest(TR::Node *node,2777TR::Register *objectClassReg,2778TR::Register *scratchReg1,2779TR::Register *scratchReg2,2780TR::Register *resultReg,2781TR::LabelSymbol *failLabel,2782TR::LabelSymbol *trueLabel,2783bool needsResult,2784bool trueFallThrough,2785TR::CodeGenerator *cg)2786{2787if (needsResult)2788{2789generateRIInstruction(cg, TR::InstOpCode::LHI, node, resultReg, 0);2790}2791generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratchReg1,2792generateS390MemoryReference(objectClassReg, offsetof(J9Class,romClass), cg));2793generateRXInstruction(cg, TR::InstOpCode::L, node, scratchReg1,2794generateS390MemoryReference(scratchReg1, offsetof(J9ROMClass, modifiers), cg));2795generateRILInstruction(cg, TR::InstOpCode::NILF, node, scratchReg1, static_cast<int32_t>(J9AccClassArray));2796generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, failLabel);27972798generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratchReg1,2799generateS390MemoryReference(objectClassReg, offsetof(J9ArrayClass,componentType), cg));2800generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratchReg1,2801generateS390MemoryReference(scratchReg1, offsetof(J9Class,romClass), cg));2802generateRXInstruction(cg, TR::InstOpCode::L, node, scratchReg1,2803generateS390MemoryReference(scratchReg1, offsetof(J9ROMClass, modifiers), cg));2804generateRILInstruction(cg, TR::InstOpCode::NILF, node, scratchReg1, static_cast<int32_t>(J9AccClassInternalPrimitiveType));28052806generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, failLabel);2807if (needsResult)2808{2809generateRIInstruction(cg, TR::InstOpCode::LHI, node, resultReg, 1);2810}2811if (!trueFallThrough)2812{2813generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, trueLabel);2814}2815}2816// only need a helper call if the class is not super and not final, otherwise2817// it can be determined without a call-out2818static bool needHelperCall(TR::Node * castOrInstanceOfNode, bool testCastClassIsSuper, bool isFinalClass)2819{2820return (!testCastClassIsSuper || isDynamicCastClassPointer(castOrInstanceOfNode)) && !isFinalClass;2821}28222823static bool needTestCache(bool cachingEnabled, bool needsHelperCall, bool superClassTest)2824{2825return cachingEnabled && needsHelperCall && !superClassTest;2826}28272828static TR::Register * establishLitPoolBaseReg(TR::Node * castOrInstanceOfNode, TR::CodeGenerator * cg)2829{2830if (castOrInstanceOfNode->getNumChildren() != 3)2831{2832return NULL;2833}2834else2835{2836TR::Node* litPoolBaseChild = castOrInstanceOfNode->getLastChild();2837TR_ASSERT((litPoolBaseChild->getOpCodeValue()==TR::aload) || (litPoolBaseChild->getOpCodeValue()==TR::aRegLoad),2838"Literal pool base child expected\n");2839return cg->evaluate(litPoolBaseChild);2840}2841}28422843// this is messy and a rough approximation - there can be no more than 102844// post dependencies in instance-of.2845static int maxInstanceOfPostDependencies()2846{2847return 10;2848}28492850// similarly yucky... instanceof takes 2 parms and kills the return address2851bool killedByInstanceOfHelper(int32_t regIndex, TR::Node * node, TR::CodeGenerator * cg)2852{2853if (regIndex == -1)2854{2855return false; // not mapped to a specific register2856}28572858TR::Compilation *comp = cg->comp();2859int realReg = cg->getGlobalRegister(regIndex);28602861#if defined(TR_TARGET_64BIT)2862bool needsHelperCall = false;2863#if defined(J9ZOS390)2864if (comp->getOption(TR_EnableRMODE64))2865#endif2866{2867TR::Node * castClassNode = node->getSecondChild();2868TR::SymbolReference * castClassSymRef = castClassNode->getSymbolReference();2869bool testCastClassIsSuper = TR::TreeEvaluator::instanceOfOrCheckCastNeedSuperTest(node, cg);2870bool isFinalClass = (castClassSymRef == NULL) ? false : castClassSymRef->isNonArrayFinal(comp);2871needsHelperCall = needHelperCall(node, testCastClassIsSuper, isFinalClass);2872}28732874#endif28752876if (realReg == TR::RealRegister::GPR1 ||2877realReg == TR::RealRegister::GPR2 ||2878realReg == cg->getReturnAddressRegister()2879#if defined(TR_TARGET_64BIT)2880|| (needsHelperCall &&2881#if defined(J9ZOS390)2882comp->getOption(TR_EnableRMODE64) &&2883#endif2884realReg == cg->getEntryPointRegister())2885#endif2886)2887{2888return true;2889}2890else2891{2892return false;2893}2894}28952896static bool generateInlineTest(TR::CodeGenerator * cg, TR::Node * node, TR::Node * castClassNode,2897TR::Register * objClassReg, TR::Register * resultReg,2898TR::Register * scratchReg, TR::Register * litPoolReg,2899bool needsResult, TR::LabelSymbol * falseLabel,2900TR::LabelSymbol * trueLabel, TR::LabelSymbol * doneLabel, bool isCheckCast, int32_t maxNum_PICS = NUM_PICS)2901{2902TR::Compilation *comp = cg->comp();2903TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());2904TR_OpaqueClassBlock* guessClassArray[NUM_PICS];2905TR_OpaqueClassBlock* castClassAddr = TR::TreeEvaluator::getCastClassAddress(castClassNode);2906uint8_t num_PICs = 0, i;29072908if (!castClassAddr)2909{2910return false;2911}29122913if (isCheckCast)2914{2915TR_OpaqueClassBlock *tempGuessClassArray[NUM_PICS];2916uint8_t numberOfGuessClasses = TR::TreeEvaluator::interpreterProfilingInstanceOfOrCheckCastInfo(cg, node, tempGuessClassArray);2917if (numberOfGuessClasses > 0)2918{2919for (i = 0; i < numberOfGuessClasses; i++)2920{2921if (fej9->instanceOfOrCheckCast((J9Class*)tempGuessClassArray[i], (J9Class*)castClassAddr))2922{2923guessClassArray[num_PICs++] = tempGuessClassArray[i];2924if (maxNum_PICS == num_PICs) break;2925}2926}2927}2928}2929else2930{2931num_PICs = TR::TreeEvaluator::interpreterProfilingInstanceOfOrCheckCastInfo(cg, node, guessClassArray);2932}29332934// defect 929012935// if test fails, in case of checkcast, there is no need to generate inline check for guess value2936if (num_PICs == 0)2937return false;29382939bool result_bool;2940TR::LabelSymbol *result_label;2941TR::Instruction * unloadableConstInstr[NUM_PICS];2942num_PICs = ((num_PICs > maxNum_PICS) ? maxNum_PICS : num_PICs);2943for (i = 0; i < num_PICs; i++)2944{2945dumpOptDetails(comp, "inline test with guess class address of %p\n", guessClassArray[i]);2946if (cg->needClassAndMethodPointerRelocations())2947unloadableConstInstr[i] = generateRegLitRefInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratchReg,(uintptr_t) guessClassArray[i], TR_ClassPointer, NULL, NULL, NULL);2948else2949unloadableConstInstr[i] = generateRILInstruction(cg, TR::InstOpCode::LARL, node, scratchReg, guessClassArray[i]);29502951if (fej9->isUnloadAssumptionRequired((TR_OpaqueClassBlock *)(guessClassArray[i]), comp->getCurrentMethod()))2952comp->getStaticPICSites()->push_front(unloadableConstInstr[i]);29532954if (cg->wantToPatchClassPointer(guessClassArray[i], node))2955comp->getStaticHCRPICSites()->push_front(unloadableConstInstr[i]);29562957result_bool = fej9->instanceOfOrCheckCast((J9Class*)(guessClassArray[i]), (J9Class*)castClassAddr);2958result_label = (falseLabel != trueLabel ) ? (result_bool ? trueLabel : falseLabel) : doneLabel;29592960if (needsResult)2961generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, resultReg, (int32_t)result_bool);2962generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpLogicalRegOpCode(), node, objClassReg, scratchReg, TR::InstOpCode::COND_BE, result_label);29632964}2965return true;2966}2967static void2968generateTestBitFlag(2969TR::CodeGenerator *cg,2970TR::Node *node,2971TR::Register *mdReg,2972int32_t offset,2973int32_t size,2974uint64_t bitFlag)2975{2976TR::MemoryReference * tempMR;2977int shiftForFlag = TR::TreeEvaluator::checkNonNegativePowerOfTwo((int64_t) bitFlag);2978TR_ASSERT(shiftForFlag > 0, "generateTestBitFlag: flag is assumed to be power of 2\n");29792980// point offset to the end of the word we point to, so we can make a byte comparison using tm2981offset += size - 1;29822983// TM tests the bits for one byte, so we calculate several displacements for different flags2984// Even though TM does not require the flag to be a power of two, the following code and the previous assumption require it2985if (shiftForFlag < 8)2986{2987tempMR = generateS390MemoryReference(mdReg, offset, cg);2988}2989else if (shiftForFlag < 16)2990{2991tempMR = generateS390MemoryReference(mdReg, offset - 1, cg);2992bitFlag = bitFlag >> 8;2993}2994else if (shiftForFlag < 24)2995{2996tempMR = generateS390MemoryReference(mdReg, offset - 2, cg);2997bitFlag = bitFlag >> 16;2998}2999else if (shiftForFlag < 32)3000{3001tempMR = generateS390MemoryReference(mdReg, offset - 3, cg);3002bitFlag = bitFlag >> 24;3003}3004#if defined(TR_TARGET_64BIT)3005else if (shiftForFlag < 40)3006{3007tempMR = generateS390MemoryReference(mdReg, offset - 4, cg);3008bitFlag = bitFlag >> 32;3009}3010else if (shiftForFlag < 48)3011{3012tempMR = generateS390MemoryReference(mdReg, offset - 5, cg);3013bitFlag = bitFlag >> 40;3014}3015else if (shiftForFlag < 56)3016{3017tempMR = generateS390MemoryReference(mdReg, offset - 6, cg);3018bitFlag = bitFlag >> 48;3019}3020else if (shiftForFlag < 64)3021{3022tempMR = generateS390MemoryReference(mdReg, offset - 7, cg);3023bitFlag = bitFlag >> 56;3024}3025#endif3026else3027{3028TR_ASSERT(0, "generateTestBitFlag: flag size assumption incorrect\n");3029}30303031generateSIInstruction(cg, TR::InstOpCode::TM, node, tempMR, (uint32_t) bitFlag);3032}30333034static void3035VMnonNullSrcWrtBarCardCheckEvaluator(3036TR::Node * node,3037TR::Register * owningObjectReg,3038TR::Register * srcReg,3039TR::Register *temp1Reg,3040TR::Register *temp2Reg,3041TR::LabelSymbol *doneLabel,3042TR::SymbolReference *wbRef ,3043TR::RegisterDependencyConditions *conditions,3044TR::CodeGenerator *cg,3045bool doCompileTimeCheckForHeapObj = true)3046{3047TR::Compilation *comp = cg->comp();3048TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());3049auto gcMode = TR::Compiler->om.writeBarrierType();3050bool doWrtBar = (gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always);3051//We need to do a runtime check on cardmarking for gencon policy if our owningObjReg is in tenure3052bool doCrdMrk = (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck);30533054TR_ASSERT(srcReg != NULL, "VMnonNullSrcWrtBarCardCheckEvaluator: Cannot send in a null source object...look at the fcn name\n");3055TR_ASSERT(doWrtBar == true,"VMnonNullSrcWrtBarCardCheckEvaluator: Invalid call to VMnonNullSrcWrtBarCardCheckEvaluator\n");30563057TR::Node * wrtbarNode = NULL;3058TR::LabelSymbol * helperSnippetLabel = generateLabelSymbol(cg);3059if (node->getOpCodeValue() == TR::awrtbari || node->getOpCodeValue() == TR::awrtbar)3060wrtbarNode = node;3061else if (node->getOpCodeValue() == TR::ArrayStoreCHK)3062wrtbarNode = node->getFirstChild();3063if (gcMode != gc_modron_wrtbar_always)3064{3065bool is64Bit = comp->target().is64Bit();3066bool isConstantHeapBase = !comp->getOptions()->isVariableHeapBaseForBarrierRange0();3067bool isConstantHeapSize = !comp->getOptions()->isVariableHeapSizeForBarrierRange0();3068int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();3069TR::InstOpCode::Mnemonic opLoadReg = TR::InstOpCode::getLoadRegOpCode();3070TR::InstOpCode::Mnemonic opSubtractReg = TR::InstOpCode::getSubstractRegOpCode();3071TR::InstOpCode::Mnemonic opSubtract = TR::InstOpCode::getSubstractOpCode();3072TR::InstOpCode::Mnemonic opCmpLog = TR::InstOpCode::getCmpLogicalOpCode();3073bool disableSrcObjCheck = true; //comp->getOption(TR_DisableWrtBarSrcObjCheck);3074bool constantHeapCase = ((!comp->compileRelocatableCode()) && isConstantHeapBase && isConstantHeapSize && shiftAmount == 0 && (!is64Bit || TR::Compiler->om.generateCompressedObjectHeaders()));3075if (constantHeapCase)3076{3077// these return uintptr_t but because of the if(constantHeapCase) they are guaranteed to be <= MAX(uint32_t). The uses of heapSize, heapBase, and heapSum need to be uint32_t.3078uint32_t heapSize = comp->getOptions()->getHeapSizeForBarrierRange0();3079uint32_t heapBase = comp->getOptions()->getHeapBaseForBarrierRange0();30803081if (!doCrdMrk && !disableSrcObjCheck)3082{3083uint32_t heapSum = heapBase + heapSize;3084generateRRInstruction(cg, opLoadReg, node, temp1Reg, owningObjectReg);3085generateRILInstruction(cg, TR::InstOpCode::IILF, node, temp2Reg, heapSum);3086generateRRInstruction(cg, opSubtractReg, node, temp1Reg, temp2Reg);3087generateRRInstruction(cg, opSubtractReg, node, temp2Reg, srcReg);3088generateRRInstruction(cg, is64Bit ? TR::InstOpCode::NGR : TR::InstOpCode::NR, node, temp1Reg, temp2Reg);3089generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC1, node, doneLabel);3090}3091else3092{3093generateRRInstruction(cg, opLoadReg, node, temp1Reg, owningObjectReg); //copy owning into temp3094generateRILInstruction(cg, is64Bit ? TR::InstOpCode::SLGFI : TR::InstOpCode::SLFI, node, temp1Reg, heapBase); //temp = temp - heapbase3095generateS390CompareAndBranchInstruction(cg, is64Bit ? TR::InstOpCode::CLG : TR::InstOpCode::CL, node, temp1Reg, static_cast<int64_t>(heapSize), TR::InstOpCode::COND_BH, doneLabel, false, false, NULL, conditions);3096}3097}3098else3099{3100TR::MemoryReference * offset = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(), offsetof(J9VMThread, heapBaseForBarrierRange0), cg);3101TR::MemoryReference * size = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(), offsetof(J9VMThread, heapSizeForBarrierRange0), cg);3102generateRRInstruction(cg, opLoadReg, node, temp1Reg, owningObjectReg);3103generateRXInstruction(cg, opSubtract, node, temp1Reg, offset);3104generateRXInstruction(cg, opCmpLog, node, temp1Reg, size);3105generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BH, node, doneLabel);3106}31073108TR::LabelSymbol *noChkLabel = generateLabelSymbol(cg);31093110if (!comp->getOptions()->realTimeGC())3111{3112bool isDefinitelyNonHeapObj = false, isDefinitelyHeapObj = false;3113if (wrtbarNode != NULL && doCompileTimeCheckForHeapObj)3114{3115isDefinitelyNonHeapObj = wrtbarNode->isNonHeapObjectWrtBar();3116isDefinitelyHeapObj = wrtbarNode->isHeapObjectWrtBar();3117}3118if (doCrdMrk && !isDefinitelyNonHeapObj)3119{3120TR::LabelSymbol *srcObjChkLabel = generateLabelSymbol(cg);3121// CompileTime check for heap object3122// SRLG r2, rHeapAddr, cardSize3123// L r1, cardTableVirtualStartOffset(metaData)3124// LHI r3,0x13125// STC r3,0x0(r1,r2)3126uintptr_t cardSize = comp->getOptions()->getGcCardSize();3127int32_t shiftValue = TR::TreeEvaluator::checkNonNegativePowerOfTwo((int32_t) cardSize);3128TR::Register * cardOffReg = temp1Reg;3129TR::Register * mdReg = cg->getMethodMetaDataRealRegister();31303131// If conditions are NULL, we handle early assignment here.3132// O.w. caller is responsible for handling early assignment and making sure GPR1, GPR2 and RAREG are3133// available in conditions3134TR_ASSERT(shiftValue > 0,"VMnonNullSrcWrtBarCardCheckEvaluator: Card size must be power of 2");3135static_assert(CARD_DIRTY <= MAX_IMMEDIATE_VAL, "VMCardCheckEvaluator: CARD_DIRTY flag is assumed to be small enough for an imm op");31363137// If it is tarok balanced policy, we must generate card marking sequence.3138//3139auto gcMode = TR::Compiler->om.writeBarrierType();3140if (!(gcMode == gc_modron_wrtbar_cardmark_incremental || gcMode == gc_modron_wrtbar_satb))3141{3142generateTestBitFlag(cg, node, mdReg, offsetof(J9VMThread, privateFlags), sizeof(UDATA), J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE);3143// If the flag is not set, then we skip card marking3144generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, srcObjChkLabel);3145}3146// dirty(activeCardTableBase + temp3Reg >> card_size_shift)3147if (comp->target().is64Bit())3148generateRSInstruction(cg, TR::InstOpCode::SRLG, node, cardOffReg, cardOffReg, shiftValue);3149else3150generateRSInstruction(cg, TR::InstOpCode::SRL, node, cardOffReg, shiftValue);31513152generateRXInstruction(cg, TR::InstOpCode::getAddOpCode(), node, cardOffReg,3153generateS390MemoryReference(mdReg, offsetof(J9VMThread, activeCardTableBase), cg));3154// Store the flag to the card's byte.3155generateSIInstruction(cg, TR::InstOpCode::MVI, node, generateS390MemoryReference(cardOffReg,0x0,cg), CARD_DIRTY);31563157if (!disableSrcObjCheck)3158generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, noChkLabel);3159// If condition is NULL, the early assignment is handled by caller.3160// If not, early assignment handled here3161generateS390LabelInstruction(cg, TR::InstOpCode::label, node, srcObjChkLabel, conditions);3162}3163}3164else3165TR_ASSERT(0, "card marking not supported for RT");31663167//Either if cardmarking is not on at compile time or runtime, we want to test srcobj because if its not in nursery, then3168//we don't have to do wrtbarrier3169if (!disableSrcObjCheck && !(!doCrdMrk && constantHeapCase))3170{3171generateRRInstruction(cg, opLoadReg, node, temp1Reg, srcReg);3172if (constantHeapCase)3173{3174// these return uintptr_t but because of the if(constantHeapCase) they are guaranteed to be <= MAX(uint32_t). The uses of heapSize, heapBase, and heapSum need to be uint32_t.3175uint32_t heapBase = comp->getOptions()->getHeapBaseForBarrierRange0();3176uint32_t heapSize = comp->getOptions()->getHeapSizeForBarrierRange0();3177generateRILInstruction(cg, is64Bit ? TR::InstOpCode::SLGFI : TR::InstOpCode::SLFI, node, temp1Reg, heapBase);3178generateS390CompareAndBranchInstruction(cg, is64Bit ? TR::InstOpCode::CLG : TR::InstOpCode::CL, node, temp1Reg, static_cast<int64_t>(heapSize), TR::InstOpCode::COND_BL, doneLabel, false);3179}3180else3181{3182TR::MemoryReference *offset = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(),3183offsetof(J9VMThread, heapBaseForBarrierRange0), cg);3184TR::MemoryReference *size = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(),3185offsetof(J9VMThread, heapSizeForBarrierRange0), cg);3186generateRXInstruction(cg, opSubtract, node, temp1Reg, offset);3187generateRXInstruction(cg, opCmpLog, node, temp1Reg, size);3188generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BL, node, doneLabel);3189}3190}3191//If cardmarking is on at compile time (mode=wrtbaroldcrdmrkcheck) then need a label for when cardmarking is done3192//in which case we need to skip the srcobj check3193if (doCrdMrk)3194generateS390LabelInstruction(cg, TR::InstOpCode::label, node, noChkLabel, conditions);31953196// inline checking remembered bit for generational or (gencon+cardmarking is inlined).3197static_assert(J9_OBJECT_HEADER_REMEMBERED_MASK_FOR_TEST <= 0xFF, "The constant is too big");3198int32_t offsetToAgeBits = TR::Compiler->om.offsetOfHeaderFlags() + 3;3199#if defined(J9VM_INTERP_FLAGS_IN_CLASS_SLOT) && defined(TR_TARGET_64BIT)3200if (!TR::Compiler->om.compressObjectReferences())3201offsetToAgeBits += 4;3202#endif3203TR::MemoryReference * tempMR = generateS390MemoryReference(owningObjectReg, offsetToAgeBits, cg);3204generateSIInstruction(cg, TR::InstOpCode::TM, node, tempMR, J9_OBJECT_HEADER_REMEMBERED_MASK_FOR_TEST);3205//Need to do wrtbarrer, go to the snippet3206generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK8, node, helperSnippetLabel);3207}3208else3209generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperSnippetLabel);32103211//Create a snipper to make the call so the fall through path is to doneLabel, we expect to call the helper less, this would remove a3212//branch3213cg->addSnippet(new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, helperSnippetLabel, wbRef, doneLabel));3214}32153216static void3217VMCardCheckEvaluator(3218TR::Node * node,3219TR::Register * owningObjectReg,3220TR::Register * tempReg,3221TR::RegisterDependencyConditions * conditions,3222TR::CodeGenerator * cg,3223bool clobberDstReg,3224TR::LabelSymbol *doneLabel = NULL,3225bool doCompileTimeCheckForHeapObj = true)3226{3227TR::Compilation *comp = cg->comp();3228if (!comp->getOptions()->realTimeGC())3229{3230TR::Node * wrtbarNode = NULL;3231if (node->getOpCodeValue() == TR::awrtbari || node->getOpCodeValue() == TR::awrtbar)3232wrtbarNode = node;3233else if (node->getOpCodeValue() == TR::ArrayStoreCHK)3234wrtbarNode = node->getFirstChild();32353236// CompileTime check for heap object3237bool isDefinitelyNonHeapObj = false, isDefinitelyHeapObj = false;32383239if (wrtbarNode != NULL && doCompileTimeCheckForHeapObj)3240{3241isDefinitelyNonHeapObj = wrtbarNode->isNonHeapObjectWrtBar();3242isDefinitelyHeapObj = wrtbarNode->isHeapObjectWrtBar();3243}32443245// 83613: We used to do inline CM for Old&CM Objects.3246// However, since all Old objects will go through the wrtbar helper,3247// which will CM too, our inline CM would become redundant.3248TR_ASSERT( (TR::Compiler->om.writeBarrierType()==gc_modron_wrtbar_cardmark || TR::Compiler->om.writeBarrierType()==gc_modron_wrtbar_cardmark_incremental) && !isDefinitelyNonHeapObj,3249"VMCardCheckEvaluator: Invalid call to cardCheckEvaluator\n");3250TR_ASSERT(doneLabel, "VMCardCheckEvaluator: doneLabel must be defined\n");3251TR_ASSERT((conditions && tempReg || clobberDstReg), "VMCardCheckEvaluator: Either a tempReg must be sent in to be used, or we should be able to clobber the owningObjReg\n");3252TR_ASSERT(!(clobberDstReg && tempReg), "VMCardCheckEvaluator: If owningObjReg is clobberable, don't allocate a tempReg\n");32533254// We do not card-mark non-heap objects.3255if (!isDefinitelyNonHeapObj)3256{3257// SRLG r2, rHeapAddr, cardSize3258// L r1, cardTableVirtualStartOffset(metaData)3259// LHI r3,0x13260// STC r3,0x0(r1,r2)32613262uintptr_t cardSize = comp->getOptions()->getGcCardSize();3263int32_t shiftValue = TR::TreeEvaluator::checkNonNegativePowerOfTwo((int32_t) cardSize);32643265TR::Register * cardOffReg;3266TR::Register * mdReg = cg->getMethodMetaDataRealRegister();32673268if (!clobberDstReg)3269cardOffReg = tempReg;3270else if (clobberDstReg)3271cardOffReg = owningObjectReg;32723273TR_ASSERT(shiftValue > 0,"VMCardCheckEvaluator: Card size must be power of 2");3274static_assert(CARD_DIRTY <= MAX_IMMEDIATE_VAL, "VMCardCheckEvaluator: CARD_DIRTY flag is assumed to be small enough for an imm op");32753276// If it is tarok balanced policy, we must generate card marking sequence.3277auto gcMode = TR::Compiler->om.writeBarrierType();3278if (!(gcMode == gc_modron_wrtbar_cardmark_incremental || gcMode == gc_modron_wrtbar_satb))3279{3280generateTestBitFlag(cg, node, mdReg, offsetof(J9VMThread, privateFlags), sizeof(UDATA), J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE);3281// If the flag is not set, then we skip card marking3282generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, doneLabel);3283}32843285// cardOffReg (Temp) = owningObjectReg - heapBaseForBarrierRange03286// Defect 91242 - If we can clobber the destination reg, then use owningObjectReg instead of cardOffReg.3287if (!clobberDstReg)3288generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, cardOffReg, owningObjectReg);3289generateRXInstruction(cg, TR::InstOpCode::getSubstractOpCode(), node, cardOffReg,3290generateS390MemoryReference(mdReg, offsetof(J9VMThread, heapBaseForBarrierRange0), cg));32913292// Unless we know it's definitely a heap object, we need to check if offset3293// from base is less than heap size to determine if object resides in heap.3294if (!isDefinitelyHeapObj)3295{3296// if (cardOffReg(Temp) >= heapSizeForBarrierRage0), object not in the heap3297generateRXInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, cardOffReg,3298generateS390MemoryReference(mdReg, offsetof(J9VMThread, heapSizeForBarrierRange0), cg));3299generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNL, node, doneLabel);3300}33013302// dirty(activeCardTableBase + temp3Reg >> card_size_shift)3303if (comp->target().is64Bit())3304generateRSInstruction(cg, TR::InstOpCode::SRLG, node, cardOffReg, cardOffReg, shiftValue);3305else3306generateRSInstruction(cg, TR::InstOpCode::SRL, node, cardOffReg, shiftValue);33073308//add the ActiveCardTableBase to the card offset3309generateRXInstruction(cg, TR::InstOpCode::getAddOpCode(), node, cardOffReg,3310generateS390MemoryReference(mdReg, offsetof(J9VMThread, activeCardTableBase), cg));3311// Store the flag to the card's byte.3312generateSIInstruction(cg, TR::InstOpCode::MVI, node, generateS390MemoryReference(cardOffReg, 0x0, cg), CARD_DIRTY);3313}3314}3315else3316TR_ASSERT(0, "VMCardCheckEvaluator not supported for RT");3317}33183319static void3320VMwrtbarEvaluator(3321TR::Node * node,3322TR::Register * srcReg,3323TR::Register * owningObjectReg,3324bool srcNonNull,3325TR::CodeGenerator * cg)3326{3327TR::Instruction * cursor;3328TR::Compilation *comp = cg->comp();3329auto gcMode = TR::Compiler->om.writeBarrierType();3330bool doWrtBar = (gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always);3331bool doCrdMrk = ((gcMode == gc_modron_wrtbar_cardmark ||gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental)&& !node->isNonHeapObjectWrtBar());33323333// See VM Design 2048 for when wrtbar can be skipped, as determined by VP.3334if ( (node->getOpCode().isWrtBar() && node->skipWrtBar()) ||3335((node->getOpCodeValue() == TR::ArrayStoreCHK) && node->getFirstChild()->getOpCode().isWrtBar() && node->getFirstChild()->skipWrtBar() ) )3336return;3337TR::RegisterDependencyConditions * conditions;3338TR::LabelSymbol * doneLabel = generateLabelSymbol(cg);3339if (doWrtBar)3340conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 4, cg);3341else3342conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 1, cg);33433344if (doWrtBar) // generational or gencon3345{3346TR::SymbolReference * wbRef = NULL;3347if (gcMode == gc_modron_wrtbar_always)3348wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreSymbolRef();3349else // use jitWriteBarrierStoreGenerational for both generational and gencon, because we inline card marking.3350{3351static char *disable = feGetEnv("TR_disableGenWrtBar");3352wbRef = disable ?3353comp->getSymRefTab()->findOrCreateWriteBarrierStoreSymbolRef() :3354comp->getSymRefTab()->findOrCreateWriteBarrierStoreGenerationalSymbolRef();3355}3356TR::Register *epReg, *raReg;3357epReg = cg->allocateRegister();3358raReg = cg->allocateRegister();3359conditions->addPostCondition(raReg, cg->getReturnAddressRegister());3360conditions->addPostCondition(owningObjectReg, TR::RealRegister::GPR1);3361conditions->addPostCondition(srcReg, TR::RealRegister::GPR2);3362conditions->addPostCondition(epReg, cg->getEntryPointRegister());3363if (srcNonNull == false)3364{3365// If object is NULL, done3366generateRRInstruction(cg, TR::InstOpCode::getLoadTestRegOpCode(), node, srcReg, srcReg);3367generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, doneLabel);3368}3369// Inlines cardmarking and remembered bit check for gencon.3370VMnonNullSrcWrtBarCardCheckEvaluator(node, owningObjectReg, srcReg, epReg, raReg, doneLabel, wbRef, conditions, cg, false);3371cg->stopUsingRegister(epReg);3372cg->stopUsingRegister(raReg);3373}3374else if (doCrdMrk) // -Xgc:optavgpause, concurrent marking only3375{3376conditions->addPostCondition(owningObjectReg, TR::RealRegister::AssignAny);3377VMCardCheckEvaluator(node, owningObjectReg, NULL, conditions, cg, true, doneLabel);3378}3379generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);3380}33813382///////////////////////////////////////////////////////////////////////////////////////3383// monentEvaluator: acquire lock for synchronising method3384///////////////////////////////////////////////////////////////////////////////////////3385TR::Register *3386J9::Z::TreeEvaluator::monentEvaluator(TR::Node * node, TR::CodeGenerator * cg)3387{3388return TR::TreeEvaluator::VMmonentEvaluator(node, cg);3389}33903391///////////////////////////////////////////////////////////////////////////////////////3392// monexitEvaluator: release lock for synchronising method3393///////////////////////////////////////////////////////////////////////////////////////3394TR::Register *3395J9::Z::TreeEvaluator::monexitEvaluator(TR::Node * node, TR::CodeGenerator * cg)3396{3397return TR::TreeEvaluator::VMmonexitEvaluator(node, cg);3398}33993400///////////////////////////////////////////////////////////////////////////////////////3401// asynccheckEvaluator: GC point3402///////////////////////////////////////////////////////////////////////////////////////3403TR::Register *3404J9::Z::TreeEvaluator::asynccheckEvaluator(TR::Node * node, TR::CodeGenerator * cg)3405{3406// used by asynccheck3407// The child contains an inline test.3408//3409TR::Node * testNode = node->getFirstChild();3410TR::Node * firstChild = testNode->getFirstChild();3411TR::Node * secondChild = testNode->getSecondChild();3412TR::Compilation *comp = cg->comp();3413intptr_t value = comp->target().is64Bit() ? secondChild->getLongInt() : secondChild->getInt();34143415TR_ASSERT( testNode->getOpCodeValue() == (comp->target().is64Bit() ? TR::lcmpeq : TR::icmpeq), "asynccheck bad format");3416TR_ASSERT( secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL, "asynccheck bad format");34173418TR::LabelSymbol * snippetLabel = generateLabelSymbol(cg);3419TR::LabelSymbol * cFlowRegionStart = generateLabelSymbol(cg);3420TR::Instruction * gcPoint;34213422TR::LabelSymbol * reStartLabel = generateLabelSymbol(cg);34233424// (0) asynccheck #4[0x004d7a88]Method[jitCheckAsyncMessages]3425// (1) icmpeq3426// (1) iload #281[0x00543138] MethodMeta[stackOverflowMark]+283427// (1) iconst -134283429if (comp->target().is32Bit() &&3430(firstChild->getOpCodeValue() == TR::iload) &&3431firstChild->getRegister() == NULL && value < 0)3432{3433// instead of comparing to the value itself, we can compare to 03434// and, if the value is less than zero, we know it must be an async-check3435// since non-code addresses are always positive in 31-bit 390 code so the only3436// negative address we could have would be the 'bogus' -1 address to force3437// async-check.3438// (the VM ensures that all malloc'ed storage has the high-order-bit cleared)3439TR::Register * testRegister = cg->allocateRegister();3440TR::MemoryReference * tempMR = TR::MemoryReference::create(cg, firstChild);34413442TR_ASSERT( getIntegralValue(secondChild) == -1, "asynccheck bad format");3443TR_ASSERT( comp->target().is32Bit(), "ICM can be used for 32bit code-gen only!");34443445static char * dontUseTM = feGetEnv("TR_DONTUSETMFORASYNC");3446if (firstChild->getReferenceCount()>1 || dontUseTM)3447{3448generateRSInstruction(cg, TR::InstOpCode::ICM, firstChild, testRegister, (uint32_t) 0xF, tempMR);3449gcPoint = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BL, node, snippetLabel);3450}3451else3452{3453generateSIInstruction(cg, TR::InstOpCode::TM, firstChild, tempMR, 0xFF);3454gcPoint = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BO, node, snippetLabel);3455}34563457firstChild->setRegister(testRegister);3458tempMR->stopUsingMemRefRegister(cg);3459}3460else3461{3462if (value >= MIN_IMMEDIATE_VAL && value <= MAX_IMMEDIATE_VAL)3463{3464TR::MemoryReference * tempMR = TR::MemoryReference::create(cg, firstChild);34653466if (tempMR->getIndexRegister() != NULL && tempMR->getBaseRegister() != NULL)3467{3468TR::SymbolReference * symRef = firstChild->getSymbolReference();3469TR::Symbol * symbol = symRef->getSymbol();3470TR::Register * src1Reg = NULL;3471if (firstChild->getDataType() == TR::Address &&3472!symbol->isInternalPointer() &&3473!symbol->isNotCollected() &&3474!symbol->isAddressOfClassObject())3475{3476src1Reg = cg->allocateCollectedReferenceRegister();3477}3478else3479{3480src1Reg = cg->allocateRegister();3481}3482generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), firstChild, src1Reg, tempMR);34833484updateReferenceNode(firstChild, src1Reg);3485firstChild->setRegister(src1Reg);34863487generateRIInstruction(cg, TR::InstOpCode::getCmpHalfWordImmOpCode(), node, src1Reg, value);3488}3489else3490{3491generateSILInstruction(cg, TR::InstOpCode::getCmpHalfWordImmToMemOpCode(), node, tempMR, value);3492}3493tempMR->stopUsingMemRefRegister(cg);3494}3495else3496{3497TR::Register * src1Reg = cg->evaluate(firstChild);3498TR::Register * tempReg = cg->evaluate(secondChild);3499generateRRInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, src1Reg, tempReg);3500}3501gcPoint = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, snippetLabel);3502}35033504TR::RegisterDependencyConditions * dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 2, cg);3505TR::Register * rRA = cg->allocateRegister();3506// only 64bit zLinux and zOS trampoline requires rEP3507#if defined(TR_TARGET_64BIT)3508TR::Register * rEP = NULL;3509#if defined(J9ZOS390)3510if (comp->getOption(TR_EnableRMODE64))3511#endif3512{3513rEP = cg->allocateRegister();3514dependencies->addPostCondition(rEP, cg->getEntryPointRegister());3515}3516#endif35173518dependencies->addPostCondition(rRA, cg->getReturnAddressRegister());35193520TR_Debug * debugObj = cg->getDebug();3521if (debugObj)3522debugObj->addInstructionComment(gcPoint, "Branch to OOL asyncCheck sequence");35233524// starts OOL sequence, replacing the helper call snippet3525TR_S390OutOfLineCodeSection *outlinedHelperCall = NULL;3526outlinedHelperCall = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(snippetLabel, reStartLabel, cg);3527cg->getS390OutOfLineCodeSectionList().push_front(outlinedHelperCall);3528outlinedHelperCall->swapInstructionListsWithCompilation();35293530// snippetLabel : OOL Start label3531TR::Instruction * cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, snippetLabel);3532if (debugObj)3533debugObj->addInstructionComment(cursor, "Denotes start of OOL asyncCheck sequence");35343535// BRASL R14, VMHelper, gc stack map on BRASL3536gcPoint = generateDirectCall(cg, node, false, node->getSymbolReference(), dependencies, cursor);3537gcPoint->setDependencyConditions(dependencies);35383539cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, reStartLabel);3540if (debugObj)3541debugObj->addInstructionComment(cursor, "Denotes end of OOL asyncCheck sequence: return to mainline");35423543// Done using OOL with manual code generation3544outlinedHelperCall->swapInstructionListsWithCompilation();3545cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, reStartLabel);3546if (debugObj)3547debugObj->addInstructionComment(cursor, "OOL asyncCheck return label");35483549gcPoint->setNeedsGCMap(0x0000FFFF);35503551cg->decReferenceCount(firstChild);3552cg->decReferenceCount(secondChild);3553cg->decReferenceCount(testNode);3554#if defined(TR_TARGET_64BIT)3555#if defined(J9ZOS390)3556if (comp->getOption(TR_EnableRMODE64))3557#endif3558{3559cg->stopUsingRegister(rEP);3560}3561#endif3562cg->stopUsingRegister(rRA);35633564return NULL;35653566}35673568/** \brief Generates ArrayOfJavaLangObjectTest (object class is reference array) for instanceOf or checkCast node3569* \details3570* scratchReg1 = load (objectClassReg+offset_romClass)3571* scratchReg1 = load (ROMClass+J9ROMClass+modifiers)3572* andImmediate with J9AccClassArray(0x10000)3573* If not Array -> Branch to Fail Label3574* testerReg = load (objectClassReg + leafcomponent_offset)3575* testerReg = load (objectClassReg + offset_romClass)3576* testerReg = load (objectClassReg + offset_modifiers)3577* andImmediate with J9AccClassInternalPrimitiveType(0x20000)3578* if not arrays of primitive set condition code to Zero indicating true result3579*/3580static3581void genInstanceOfOrCheckcastArrayOfJavaLangObjectTest(TR::Node *node, TR::CodeGenerator *cg, TR::Register *objectClassReg, TR::LabelSymbol *failLabel, TR_S390ScratchRegisterManager *srm)3582{3583TR::Compilation *comp = cg->comp();3584TR_Debug *debugObj = cg->getDebug();3585TR::Instruction *cursor = NULL;3586TR::Register *scratchReg1 = srm->findOrCreateScratchRegister();3587generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratchReg1, generateS390MemoryReference(objectClassReg, offsetof(J9Class,romClass), cg));3588generateRXInstruction(cg, TR::InstOpCode::L, node, scratchReg1, generateS390MemoryReference(scratchReg1, offsetof(J9ROMClass, modifiers), cg));3589generateRILInstruction(cg, TR::InstOpCode::NILF, node, scratchReg1, static_cast<int32_t>(J9AccClassArray));3590cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, failLabel);3591if (debugObj)3592debugObj->addInstructionComment(cursor,"Fail instanceOf/checkCast if Not Array");3593generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratchReg1, generateS390MemoryReference(objectClassReg, offsetof(J9ArrayClass,componentType), cg));3594generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratchReg1, generateS390MemoryReference(scratchReg1, offsetof(J9Class,romClass), cg));3595generateRXInstruction(cg, TR::InstOpCode::L, node, scratchReg1, generateS390MemoryReference(scratchReg1, offsetof(J9ROMClass, modifiers), cg));3596generateRILInstruction(cg, TR::InstOpCode::NILF, node, scratchReg1, static_cast<int32_t>(J9AccClassInternalPrimitiveType));3597srm->reclaimScratchRegister(scratchReg1);3598}35993600/** \brief Generates Superclass Test for both checkcast and instanceof nodes.3601* \details3602* It will generate pseudocode as follows.3603* if (objectClassDepth <= castClassDepth) call Helper3604* else3605* load superClassArrReg,superClassOfObjectClass3606* cmp superClassArrReg[castClassDepth], castClass3607* Here It sets up the condition code for callee to react on.3608*/3609static3610bool genInstanceOfOrCheckcastSuperClassTest(TR::Node *node, TR::CodeGenerator *cg, TR::Register *objClassReg, TR::Register *castClassReg, int32_t castClassDepth,3611TR::LabelSymbol *falseLabel, TR::LabelSymbol *callHelperLabel, TR_S390ScratchRegisterManager *srm)3612{3613TR::Compilation *comp = cg->comp();3614int32_t superClassDepth = castClassDepth * TR::Compiler->om.sizeofReferenceAddress();3615TR::Register *castClassDepthReg = NULL;3616TR::InstOpCode::Mnemonic loadOp;3617int32_t byteOffset;3618TR::Instruction *cursor = NULL;3619if (cg->comp()->target().is64Bit())3620{3621loadOp = TR::InstOpCode::LLGH;3622byteOffset = 6;3623}3624else3625{3626loadOp = TR::InstOpCode::LLH;3627byteOffset = 2;3628}3629//Following Changes are for dynamicCastClass only3630bool dynamicCastClass = castClassDepth == -1;3631bool eliminateSuperClassArraySizeCheck = (!dynamicCastClass && (castClassDepth < cg->comp()->getOptions()->_minimumSuperclassArraySize));3632// In case of dynamic Cast Class, We do not know the depth of the cast Class at compile time. So following routine compares depth at run time.3633if ( dynamicCastClass )3634{3635TR::Register *scratchRegister1 = srm->findOrCreateScratchRegister();3636//TR::Register *scratchRegister1 = scratch1Reg;3637TR_ASSERT((node->getOpCodeValue() == TR::instanceof &&3638node->getSecondChild()->getOpCodeValue() != TR::loadaddr), "genTestIsSuper: castClassDepth == -1 is only supported for transformed isInstance calls.");3639cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratchRegister1,3640generateS390MemoryReference(castClassReg, offsetof(J9Class, romClass), cg), cursor);3641cursor = generateRXInstruction(cg, TR::InstOpCode::L, node, scratchRegister1,3642generateS390MemoryReference(scratchRegister1, offsetof(J9ROMClass, modifiers), cg), cursor);3643TR_ASSERT(((J9AccInterface | J9AccClassArray) < UINT_MAX && (J9AccInterface | J9AccClassArray) > 0),3644"genTestIsSuper::(J9AccInterface | J9AccClassArray) is not a 32-bit number\n");3645cursor = generateRILInstruction(cg, TR::InstOpCode::NILF, node, scratchRegister1, static_cast<int32_t>((J9AccInterface | J9AccClassArray)), cursor);3646cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, callHelperLabel, cursor);3647castClassDepthReg = srm->findOrCreateScratchRegister();3648cursor = generateRXInstruction(cg, loadOp, node, castClassDepthReg,3649generateS390MemoryReference(castClassReg, offsetof(J9Class, classDepthAndFlags) + byteOffset, cg), cursor);36503651srm->reclaimScratchRegister(scratchRegister1);3652TR_ASSERT(sizeof(((J9Class*)0)->classDepthAndFlags) == sizeof(uintptr_t),3653"genTestIsSuper::J9Class->classDepthAndFlags is wrong size\n");3654}365536563657//objectClassDepthReg <- objectClassDepth3658if (!eliminateSuperClassArraySizeCheck)3659{3660TR::Register *objectClassDepthReg = srm->findOrCreateScratchRegister();3661cursor = generateRXInstruction(cg, loadOp, node, objectClassDepthReg,3662generateS390MemoryReference(objClassReg, offsetof(J9Class, classDepthAndFlags) + byteOffset, cg) , NULL);36633664//Compare objectClassDepth and castClassDepth3665if (dynamicCastClass)3666cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, objectClassDepthReg, castClassDepthReg, TR::InstOpCode::COND_BNH, falseLabel, false, false);3667else3668cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, objectClassDepthReg, castClassDepth, TR::InstOpCode::COND_BNH, falseLabel, true, false, cursor);3669srm->reclaimScratchRegister(objectClassDepthReg);3670}36713672//superClassArrReg <- objectClass->superClasses3673TR::Register *superClassArrReg = srm->findOrCreateScratchRegister();3674cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, superClassArrReg,3675generateS390MemoryReference(objClassReg, offsetof(J9Class, superclasses), cg), cursor);3676if (dynamicCastClass)3677{3678if (cg->comp()->target().is64Bit())3679{3680cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, castClassDepthReg, castClassDepthReg, 3, cursor);3681}3682else3683{3684cursor = generateRSInstruction(cg, TR::InstOpCode::SLL, node, castClassDepthReg, 2, cursor);3685}3686cursor = generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, castClassReg,3687generateS390MemoryReference(superClassArrReg, castClassDepthReg, 0, cg), cursor);3688srm->reclaimScratchRegister(castClassDepthReg);3689}3690else3691{3692//CG superClassArrReg[castClassDepth],castClassReg3693cursor = generateRXInstruction (cg, TR::InstOpCode::getCmpOpCode(), node, castClassReg,3694generateS390MemoryReference(superClassArrReg, superClassDepth, cg), cursor);3695}3696srm->reclaimScratchRegister(superClassArrReg);3697return dynamicCastClass;3698//We expect Result of the test reflects in Condition Code. Callee should react on this.3699}37003701///////////////////////////////////////////////////////////////////////////////////////3702// instanceofEvaluator: symref is the class object, cp index is in the "int" field,3703// child is the object reference3704///////////////////////////////////////////////////////////////////////////////////////3705TR::Register *3706J9::Z::TreeEvaluator::instanceofEvaluator(TR::Node * node, TR::CodeGenerator * cg)3707{3708TR::Compilation *comp = cg->comp();3709static bool initialResult = feGetEnv("TR_instanceOfInitialValue") != NULL;3710traceMsg(comp,"Initial result = %d\n",initialResult);3711// Complementing Initial Result to True if the floag is not passed.3712return VMgenCoreInstanceofEvaluator(node,cg,NULL,NULL,!initialResult,1,NULL,false);3713}37143715/** \brief3716* Generates null test of \p objectReg for instanceof or checkcast[AndNULLCHK] \p node. In case a NULLCHK is3717* required this function will generate the sequence which throws the appropriate exception.3718*3719* \param node3720* The instanceof, checkcast, or checkcastAndNULLCHK node.3721*3722* \param cg3723* The code generator used to generate the instructions.3724*3725* \param objectReg3726* The object to null test.3727*3728* \return3729* \c true if a boolean condition code is set and the callee is expected to act on it; \c false otherwise, meaning3730* a NULLCHK was performed and if \p objectReg was null an exception throwing fallback path will be taken.3731*/3732static bool3733genInstanceOfOrCheckCastNullTest(TR::Node* node, TR::CodeGenerator* cg, TR::Register* objectReg)3734{3735if (node->getOpCodeValue() == TR::checkcastAndNULLCHK)3736{3737if (cg->getHasResumableTrapHandler())3738{3739TR::Instruction* compareAndTrapInstruction = generateRIEInstruction(cg, TR::InstOpCode::getCmpImmTrapOpCode(), node, objectReg, 0, TR::InstOpCode::COND_BE);3740compareAndTrapInstruction->setExceptBranchOp();3741compareAndTrapInstruction->setNeedsGCMap(0x0000FFFF);3742}3743else3744{3745generateRRInstruction(cg, TR::InstOpCode::getLoadTestRegOpCode(), node, objectReg, objectReg);37463747TR::Compilation* comp = cg->comp();3748TR::LabelSymbol* snippetLabel = generateLabelSymbol(cg);3749TR::Node* nullChkInfo = comp->findNullChkInfo(node);37503751TR::Instruction* branchInstruction = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, nullChkInfo, snippetLabel);3752branchInstruction->setExceptBranchOp();3753branchInstruction->setNeedsGCMap(0x0000FFFF);37543755TR::SymbolReference* symRef = comp->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp->getMethodSymbol());3756cg->addSnippet(new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, nullChkInfo, snippetLabel, symRef));3757}37583759return false;3760}3761else3762{3763generateRRInstruction(cg, TR::InstOpCode::getLoadTestRegOpCode(), node, objectReg, objectReg);37643765return true;3766}3767}37683769///////////////////////////////////////////////////////////////////////////////////////3770// checkcastEvaluator - checkcast3771///////////////////////////////////////////////////////////////////////////////////////3772TR::Register *3773J9::Z::TreeEvaluator::checkcastEvaluator(TR::Node * node, TR::CodeGenerator * cg)3774{3775TR::Compilation *comp = cg->comp();37763777// TODO: This is not the place to make such checks. If we really want to optimize for space or disable inlining3778// of instanceof/checkcast we should still go through the else path to the common infrastructure and it should just3779// generate a call to the helper (along with any null tests if needed for checkcastAndNULLCHK). This should be3780// handled at the common level.3781TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());3782TR_OpaqueClassBlock *profiledClass, *compileTimeGuessClass;37833784int32_t maxProfiledClasses = comp->getOptions()->getCheckcastMaxProfiledClassTests();3785traceMsg(comp, "%s:Maximum Profiled Classes = %d\n", node->getOpCode().getName(),maxProfiledClasses);3786InstanceOfOrCheckCastProfiledClasses* profiledClassesList = (InstanceOfOrCheckCastProfiledClasses*)alloca(maxProfiledClasses * sizeof(InstanceOfOrCheckCastProfiledClasses));3787InstanceOfOrCheckCastSequences sequences[InstanceOfOrCheckCastMaxSequences];37883789// We use this information to decide if we want to do SuperClassTest inline or not3790bool topClassWasCastClass=false;3791float topClassProbability=0.0;3792bool dynamicCastClass = false;3793uint32_t numberOfProfiledClass;3794uint32_t numSequencesRemaining = calculateInstanceOfOrCheckCastSequences(node, sequences, &compileTimeGuessClass, cg, profiledClassesList, &numberOfProfiledClass, maxProfiledClasses, &topClassProbability, &topClassWasCastClass);37953796TR::Node *objectNode = node->getFirstChild();3797TR::Node *castClassNode = node->getSecondChild();3798TR::Register *objectReg = NULL;3799TR::Register *castClassReg = NULL;3800TR::Register *objClassReg = NULL;3801TR::Register *objectCopyReg = NULL;3802TR::Register *castClassCopyReg = NULL;3803TR::Register *resultReg = NULL;38043805// We need here at maximum two scratch registers so forcing scratchRegisterManager to create pool of two registers only.3806TR_S390ScratchRegisterManager *srm = cg->generateScratchRegisterManager(2);38073808TR::Instruction *gcPoint = NULL;3809TR::Instruction *cursor = NULL;3810TR_S390OutOfLineCodeSection *outlinedSlowPath = NULL;3811TR::LabelSymbol *doneOOLLabel = NULL;3812TR::LabelSymbol *startOOLLabel = NULL;3813TR::LabelSymbol *helperReturnOOLLabel = NULL;3814TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);3815TR::LabelSymbol *callLabel = generateLabelSymbol(cg);3816TR::LabelSymbol *resultLabel = doneLabel;38173818TR_Debug * debugObj = cg->getDebug();3819objectReg = cg->evaluate(objectNode);38203821// When we topProfiledClass in the profiled information is cast class with frequency greater than 0.5, we expect class equality to succeed so we put rest of the test outlined.3822bool outLinedTest = numSequencesRemaining >= 2 && sequences[numSequencesRemaining-2] == SuperClassTest && topClassProbability >= 0.5 && topClassWasCastClass;3823traceMsg(comp, "Outline Super Class Test: %d\n", outLinedTest);3824InstanceOfOrCheckCastSequences *iter = &sequences[0];38253826while (numSequencesRemaining > 1)3827{3828switch(*iter)3829{3830case EvaluateCastClass:3831TR_ASSERT(!castClassReg, "Cast class already evaluated");3832if (comp->getOption(TR_TraceCG))3833traceMsg(comp, "%s: Class Not Evaluated. Evaluating it\n", node->getOpCode().getName());3834castClassReg = cg->evaluate(castClassNode);3835break;3836case LoadObjectClass:3837if (comp->getOption(TR_TraceCG))3838traceMsg(comp, "%s: Loading Object Class\n",node->getOpCode().getName());3839objClassReg = cg->allocateRegister();3840TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, objClassReg, generateS390MemoryReference(objectReg, static_cast<int32_t>(TR::Compiler->om.offsetOfObjectVftField()), cg), NULL);3841break;3842case GoToTrue:3843TR_ASSERT(false, "Doesn't Make sense, GoToTrue should not be part of multiple sequences");3844break;3845case GoToFalse:3846TR_ASSERT(false, "Doesn't make sense, GoToFalse should be the terminal sequence");3847break;3848case NullTest:3849{3850//If Object is Null, no need to carry out rest of test and jump to Done Label3851if (comp->getOption(TR_TraceCG))3852traceMsg(comp, "%s: Emitting NullTest\n", node->getOpCode().getName());3853TR_ASSERT(!objectNode->isNonNull(), "Object is known to be non-null, no need for a null test");3854const bool isCCSet = genInstanceOfOrCheckCastNullTest(node, cg, objectReg);38553856if (isCCSet)3857{3858generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, doneLabel);3859}3860}3861break;3862case ClassEqualityTest:3863if (comp->getOption(TR_TraceCG))3864traceMsg(comp, "%s: Emitting Class Equality Test\n", node->getOpCode().getName());3865if (outLinedTest)3866{3867// This is the case when we are going to have an Internal Control Flow in the OOL3868startOOLLabel = generateLabelSymbol(cg);3869doneOOLLabel = doneLabel;3870helperReturnOOLLabel = generateLabelSymbol(cg);3871cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/EqualOOL", comp->signature()),1,TR::DebugCounter::Undetermined);3872generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, castClassReg, objClassReg, TR::InstOpCode::COND_BNE, startOOLLabel, false, false);3873cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/EqualOOLPass", comp->signature()),1,TR::DebugCounter::Undetermined);3874outlinedSlowPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(startOOLLabel,doneOOLLabel,cg);3875cg->getS390OutOfLineCodeSectionList().push_front(outlinedSlowPath);3876outlinedSlowPath->swapInstructionListsWithCompilation();3877generateS390LabelInstruction(cg, TR::InstOpCode::label, node, startOOLLabel);3878resultLabel = helperReturnOOLLabel;3879}3880else3881{3882cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/Equal", comp->signature()),1,TR::DebugCounter::Undetermined);3883generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, castClassReg, objClassReg, TR::InstOpCode::COND_BE, doneLabel, false, false);3884cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/EqualFail", comp->signature()),1,TR::DebugCounter::Undetermined);3885}3886break;3887case SuperClassTest:3888{3889cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/SuperClass", comp->signature()),1,TR::DebugCounter::Undetermined);3890int32_t castClassDepth = castClassNode->getSymbolReference()->classDepth(comp);3891TR_ASSERT(numSequencesRemaining == 2, "SuperClassTest should always be followed by a GoToFalse and must always be the second last test generated");3892if (comp->getOption(TR_TraceCG))3893traceMsg(comp, "%s: Emitting Super Class Test, Cast Class Depth=%d\n", node->getOpCode().getName(),castClassDepth);3894dynamicCastClass = genInstanceOfOrCheckcastSuperClassTest(node, cg, objClassReg, castClassReg, castClassDepth, callLabel, NULL, srm);3895/* outlinedSlowPath will be non-NULL if we have a higher probability of ClassEqualityTest succeeding.3896* In such cases we will do rest of the tests in OOL section, and as such we need to skip the helper call3897* if the result of SuperClassTest is true and branch to resultLabel which will branch back to the doneLabel from OOL code.3898* In normal cases SuperClassTest will be inlined with doneLabel as fallThroughLabel so we need to branch to callLabel to generate CastClassException3899* through helper call if result of SuperClassTest turned out to be false.3900*/3901cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, outlinedSlowPath != NULL ? TR::InstOpCode::COND_BE : TR::InstOpCode::COND_BNE, node, outlinedSlowPath ? resultLabel : callLabel);3902break;3903}3904/** Following switch case generates sequence of instructions for profiled class test for this checkCast node3905* arbitraryClassReg1 <= profiledClass3906* if (arbitraryClassReg1 == objClassReg)3907* JMP DoneLabel3908* else3909* continue to NextTest3910*/3911case ProfiledClassTest:3912{3913if (comp->getOption(TR_TraceCG))3914traceMsg(comp, "%s: Emitting Profiled Class Test\n", node->getOpCode().getName());3915TR::Register *arbitraryClassReg1 = srm->findOrCreateScratchRegister();3916uint8_t numPICs = 0;3917TR::Instruction *temp= NULL;3918cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/Profiled", comp->signature()),1,TR::DebugCounter::Undetermined);3919while (numPICs < numberOfProfiledClass)3920{3921if (cg->needClassAndMethodPointerRelocations())3922temp = generateRegLitRefInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, arbitraryClassReg1, (uintptr_t) profiledClassesList[numPICs].profiledClass, TR_ClassPointer, NULL, NULL, NULL);3923else3924temp = generateRILInstruction(cg, TR::InstOpCode::LARL, node, arbitraryClassReg1, profiledClassesList[numPICs].profiledClass);39253926// Adding profiled classes to static PIC sites3927if (fej9->isUnloadAssumptionRequired((TR_OpaqueClassBlock *)(profiledClassesList[numPICs].profiledClass), comp->getCurrentMethod()))3928comp->getStaticPICSites()->push_front(temp);3929// Adding profiled classes to HCR PIC sites3930if (cg->wantToPatchClassPointer(profiledClassesList[numPICs].profiledClass, node))3931comp->getStaticHCRPICSites()->push_front(temp);39323933temp = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, arbitraryClassReg1, objClassReg, TR::InstOpCode::COND_BE, resultLabel, false, false);3934numPICs++;3935}3936cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/ProfiledFail", comp->signature()),1,TR::DebugCounter::Undetermined);3937srm->reclaimScratchRegister(arbitraryClassReg1);3938break;3939}3940case CompileTimeGuessClassTest:3941{3942if (comp->getOption(TR_TraceCG))3943traceMsg(comp, "%s: Emitting Compile Time Guess Class Test\n", node->getOpCode().getName());3944cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/CompTimeGuess", comp->signature()),1,TR::DebugCounter::Undetermined);3945TR::Register *arbitraryClassReg2 = srm->findOrCreateScratchRegister();3946genLoadAddressConstant(cg, node, (uintptr_t)compileTimeGuessClass, arbitraryClassReg2);3947cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, arbitraryClassReg2, objClassReg, TR::InstOpCode::COND_BE, resultLabel , false, false);3948cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/CompTimeFail", comp->signature()),1,TR::DebugCounter::Undetermined);3949srm->reclaimScratchRegister(arbitraryClassReg2);3950break;3951}3952case ArrayOfJavaLangObjectTest:3953{3954cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/ArrayTest", comp->signature()),1,TR::DebugCounter::Undetermined);3955if (comp->getOption(TR_TraceCG))3956traceMsg(comp,"%s: Emitting ArrayOfJavaLangObjectTest\n",node->getOpCode().getName());3957genInstanceOfOrCheckcastArrayOfJavaLangObjectTest(node, cg, objClassReg, callLabel, srm) ;3958cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, doneLabel);3959break;3960}3961/** Following switch case generates sequence of instructions for cast class cache test for this checkCast node3962* Load castClassCacheReg, offsetOf(J9Class,castClassCache)3963* if castClassCacheReg == castClassReg3964* JMP DoneLabel3965* else3966* continue to NextTest3967*/3968case CastClassCacheTest:3969{3970if (comp->getOption(TR_TraceCG))3971traceMsg(comp,"%s: Emitting CastClassCacheTest\n",node->getOpCode().getName());3972TR::Register *castClassCacheReg = srm->findOrCreateScratchRegister();3973cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/Cache", comp->signature()),1,TR::DebugCounter::Undetermined);3974generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, castClassCacheReg,3975generateS390MemoryReference(objClassReg, offsetof(J9Class, castClassCache), cg));3976cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, castClassCacheReg, castClassReg, TR::InstOpCode::COND_BE, resultLabel , false, false);3977cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/CacheFail", comp->signature()),1,TR::DebugCounter::Undetermined);3978srm->reclaimScratchRegister(castClassCacheReg);3979break;3980}3981case HelperCall:3982TR_ASSERT(false, "Doesn't make sense, HelperCall should be the terminal sequence");3983break;3984default:3985break;3986}3987--numSequencesRemaining;3988++iter;3989}39903991TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 7+srm->numAvailableRegisters(), cg);3992TR::RegisterDependencyConditions *outlinedConditions = NULL;39933994// In case of Higher probability of quality test to pass, we put rest of the test outlined3995if (!outlinedSlowPath)3996outlinedConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 4, cg);3997else3998outlinedConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 4+srm->numAvailableRegisters(), cg);39994000conditions->addPostCondition(objectReg, TR::RealRegister::AssignAny);4001if (objClassReg)4002conditions->addPostCondition(objClassReg, TR::RealRegister::AssignAny);400340044005srm->addScratchRegistersToDependencyList(conditions);4006J9::Z::CHelperLinkage *helperLink = static_cast<J9::Z::CHelperLinkage*>(cg->getLinkage(TR_CHelper));4007// We will be generating sequence to call Helper if we have either GoToFalse or HelperCall Test4008if (numSequencesRemaining > 0 && *iter != GoToTrue)4009{40104011TR_ASSERT(*iter == HelperCall || *iter == GoToFalse, "Expecting helper call or fail here");4012bool helperCallForFailure = *iter != HelperCall;4013if (comp->getOption(TR_TraceCG))4014traceMsg(comp, "%s: Emitting helper call%s\n", node->getOpCode().getName(),helperCallForFailure?" for failure":"");4015//Following code is needed to put the Helper Call Outlined.4016if (!outlinedSlowPath)4017{4018// As SuperClassTest is the costliest test and is guaranteed to give results for checkCast node. Hence it will always be second last test4019// in iter array followed by GoToFalse as last test for checkCastNode4020if ( *(iter-1) != SuperClassTest)4021generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, callLabel);4022doneOOLLabel = doneLabel;4023helperReturnOOLLabel = generateLabelSymbol(cg);4024outlinedSlowPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(callLabel,doneOOLLabel,cg);4025cg->getS390OutOfLineCodeSectionList().push_front(outlinedSlowPath);4026outlinedSlowPath->swapInstructionListsWithCompilation();4027}402840294030generateS390LabelInstruction(cg, TR::InstOpCode::label, node, callLabel);4031outlinedConditions->addPostCondition(objectReg, TR::RealRegister::AssignAny);4032if (outLinedTest)4033{4034outlinedConditions->addPostCondition(objClassReg, TR::RealRegister::AssignAny);4035srm->addScratchRegistersToDependencyList(outlinedConditions);4036}40374038if(!castClassReg)4039castClassReg = cg->evaluate(castClassNode);4040conditions->addPostCondition(castClassReg, TR::RealRegister::AssignAny);4041outlinedConditions->addPostCondition(castClassReg, TR::RealRegister::AssignAny);4042cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCast/(%s)/Helper", comp->signature()),1,TR::DebugCounter::Undetermined);4043TR::RegisterDependencyConditions *deps = NULL;4044resultReg = startOOLLabel ? helperLink->buildDirectDispatch(node, &deps) : helperLink->buildDirectDispatch(node);4045if (resultReg)4046outlinedConditions->addPostCondition(resultReg, TR::RealRegister::AssignAny);40474048cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/HelperCall", comp->signature()),1,TR::DebugCounter::Undetermined);4049if(outlinedSlowPath)4050{4051TR::RegisterDependencyConditions *mergeConditions = NULL;4052if (startOOLLabel)4053mergeConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(outlinedConditions, deps, cg);4054else4055mergeConditions = outlinedConditions;4056generateS390LabelInstruction(cg, TR::InstOpCode::label, node, helperReturnOOLLabel, mergeConditions);4057generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, doneOOLLabel);4058outlinedSlowPath->swapInstructionListsWithCompilation();4059}4060}4061if (resultReg)4062cg->stopUsingRegister(resultReg);4063generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);4064cg->stopUsingRegister(castClassReg);4065if (objClassReg)4066cg->stopUsingRegister(objClassReg);4067srm->stopUsingRegisters();4068cg->decReferenceCount(objectNode);4069cg->decReferenceCount(castClassNode);4070return NULL;4071}40724073///////////////////////////////////////////////////////////////////////////////////////4074// checkcastAndNULLCHKEvaluator - checkcastAndNULLCHK4075///////////////////////////////////////////////////////////////////////////////////////4076TR::Register *4077J9::Z::TreeEvaluator::checkcastAndNULLCHKEvaluator(TR::Node * node, TR::CodeGenerator * cg)4078{4079return checkcastEvaluator(node, cg);4080}40814082/** \brief Generates helper call sequence for all VMNew nodes.4083*4084* \param node4085* A new allocation node for which helper call is going to be generated4086*4087* \param cg4088* The code generator used to generate the instructions.4089*4090* \param doInlineAllocation4091* A boolean to notify if we have generated inline allocation sequence or not4092*4093* \param4094* A register to store return value from helper4095*4096* \return4097* A register that contains return value from helper.4098*4099* \details4100* Generates a helper call sequence for all new allocation nodes. It also handles special cases where we need to generate 64-bit extended children of call node4101*/4102TR::Register *4103J9::Z::TreeEvaluator::generateHelperCallForVMNewEvaluators(TR::Node *node, TR::CodeGenerator *cg, bool doInlineAllocation, TR::Register *resReg)4104{4105J9::Z::CHelperLinkage *helperLink = static_cast<J9::Z::CHelperLinkage*>(cg->getLinkage(TR_CHelper));4106TR::ILOpCodes opCode = node->getOpCodeValue();4107TR::Node *helperCallNode = TR::Node::createWithSymRef(node, TR::acall, (opCode == TR::New || opCode == TR::variableNew) ? 1 : 2, node->getSymbolReference());4108TR::Node *firstChild = node->getFirstChild();4109if (!(opCode == TR::New || opCode == TR::variableNew))4110{4111// For 64 bit target we need to make sure we use whole 64 bit register even for loading integers as helper expects arguments like that4112// For these scenarios where children of original node is 32-bit we generate a following helper call node4113// acall4114// #IF (firstChild ->iconst || iRegLoad ) && 64-bit platform4115// -> i2l4116// -> firstChild4117// #ELSE4118// ->firstChild4119// #ENDIF4120// #IF (secondChild -> iconst || iRegLoad) && 64-bit platform4121// -> i2l4122// -> secondChild4123// #ELSE4124// ->secondChild4125// #ENDIF4126// If we generate i2l node, we need to artificially set reference count of node to 1.4127// After helper call is generated we decrease reference count of this node so that a register will be marked dead for RA.4128TR::Node *secondChild = node->getSecondChild();4129if (cg->comp()->target().is64Bit())4130{4131if (firstChild->getOpCode().isLoadConst() || firstChild->getOpCodeValue() == TR::iRegLoad)4132{4133firstChild = TR::Node::create(TR::i2l, 1, firstChild);4134firstChild->setReferenceCount(1);4135}4136if (secondChild->getOpCode().isLoadConst() || secondChild->getOpCodeValue() == TR::iRegLoad)4137{4138secondChild = TR::Node::create(TR::i2l, 1, secondChild);4139secondChild->setReferenceCount(1);4140}4141}4142helperCallNode->setChild(1, secondChild);4143}4144helperCallNode->setChild(0, firstChild);4145resReg = helperLink->buildDirectDispatch(helperCallNode, resReg);4146for (auto i=0; i < helperCallNode->getNumChildren(); i++)4147{4148if (helperCallNode->getChild(i)->getOpCodeValue() == TR::i2l)4149cg->decReferenceCount(helperCallNode->getChild(i));4150}4151// For some cases, we can not generate inline allocation sequence such as variableNew*. In these cases only helper call is generated.4152// So for these cases we need to decrease reference count of node here.4153if (!doInlineAllocation)4154{4155node->setRegister(resReg);4156for (auto i=0; i<node->getNumChildren(); i++)4157cg->decReferenceCount(node->getChild(i));4158}4159return resReg;4160}41614162///////////////////////////////////////////////////////////////////////////////////////4163// newObjectEvaluator: new symref is the class object4164///////////////////////////////////////////////////////////////////////////////////////4165TR::Register *4166J9::Z::TreeEvaluator::newObjectEvaluator(TR::Node * node, TR::CodeGenerator * cg)4167{4168TR::Compilation* comp = cg->comp();4169if (cg->comp()->suppressAllocationInlining() ||4170TR::TreeEvaluator::requireHelperCallValueTypeAllocation(node, cg))4171return generateHelperCallForVMNewEvaluators(node, cg);4172else4173return TR::TreeEvaluator::VMnewEvaluator(node, cg);4174}41754176///////////////////////////////////////////////////////////////////////////////////////4177// newArrayEvaluator: new array of primitives4178///////////////////////////////////////////////////////////////////////////////////////4179TR::Register *4180J9::Z::TreeEvaluator::newArrayEvaluator(TR::Node * node, TR::CodeGenerator * cg)4181{4182if (cg->comp()->suppressAllocationInlining())4183return generateHelperCallForVMNewEvaluators(node, cg);4184else4185return TR::TreeEvaluator::VMnewEvaluator(node, cg);4186}41874188///////////////////////////////////////////////////////////////////////////////////////4189// newArrayEvaluator: new array of objects4190///////////////////////////////////////////////////////////////////////////////////////4191TR::Register *4192J9::Z::TreeEvaluator::anewArrayEvaluator(TR::Node * node, TR::CodeGenerator * cg)4193{4194if (cg->comp()->suppressAllocationInlining())4195return generateHelperCallForVMNewEvaluators(node, cg);4196else4197return TR::TreeEvaluator::VMnewEvaluator(node, cg);4198}41994200///////////////////////////////////////////////////////////////////////////////////////4201// multianewArrayEvaluator: multi-dimensional new array of objects4202///////////////////////////////////////////////////////////////////////////////////////4203TR::Register *4204J9::Z::TreeEvaluator::multianewArrayEvaluator(TR::Node * node, TR::CodeGenerator * cg)4205{4206#define iComment(str) if (compDebug) compDebug->addInstructionComment(cursor, (const_cast<char*>(str)));4207TR::Compilation *comp = cg->comp();4208TR_Debug *compDebug = comp->getDebug();4209TR_ASSERT_FATAL(comp->target().is64Bit(), "multianewArrayEvaluator is only supported on 64-bit JVMs!");4210TR_J9VMBase *fej9 = static_cast<TR_J9VMBase *>(comp->fe());4211TR::Register *targetReg = cg->allocateRegister();4212TR::Instruction *cursor = NULL;42134214TR::Node *firstChild = node->getFirstChild();4215TR::Node *secondChild = node->getSecondChild();4216TR::Node *thirdChild = node->getThirdChild();42174218TR::LabelSymbol *cFlowRegionStart = generateLabelSymbol(cg);4219TR::LabelSymbol *nonZeroFirstDimLabel = generateLabelSymbol(cg);4220TR::LabelSymbol *cFlowRegionEnd = generateLabelSymbol(cg);4221TR::LabelSymbol *oolFailLabel = generateLabelSymbol(cg);42224223// oolJumpLabel is a common point that all branches will jump to. From this label, we branch to OOL code.4224// We do this instead of jumping directly to OOL code from mainline because the RA can only handle the case where there's4225// a single jump point to OOL code.4226TR::LabelSymbol *oolJumpLabel = generateLabelSymbol(cg);42274228cFlowRegionStart->setStartInternalControlFlow();4229cFlowRegionEnd->setEndInternalControlFlow();42304231generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);42324233TR::Register *dimsPtrReg = cg->evaluate(firstChild);4234TR::Register *dimReg = cg->evaluate(secondChild);4235TR::Register *classReg = cg->evaluate(thirdChild);42364237// In the mainline, first load the first and second dimensions' lengths into registers.4238TR::Register *firstDimLenReg = cg->allocateRegister();4239cursor = generateRXInstruction(cg, TR::InstOpCode::LGF, node, firstDimLenReg, generateS390MemoryReference(dimsPtrReg, 4, cg));4240iComment("Load 1st dim length.");42414242TR::Register *secondDimLenReg = cg->allocateRegister();4243cursor = generateRXInstruction(cg, TR::InstOpCode::L, node, secondDimLenReg, generateS390MemoryReference(dimsPtrReg, 0, cg));4244iComment("Load 2nd dim length.");42454246// Check to see if second dimension is indeed 0. If yes, then proceed to handle the case here. Otherwise jump to OOL code.4247cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CL, node, secondDimLenReg, 0, TR::InstOpCode::COND_BNE, oolJumpLabel, false);4248iComment("if 2nd dim is 0, we handle it here. Else, jump to oolJumpLabel.");42494250// Now check to see if first dimension is also 0. If yes, continue below to handle the case when length for both dimensions is 0. Otherwise jump to nonZeroFirstDimLabel.4251cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CL, node, firstDimLenReg, 0, TR::InstOpCode::COND_BNE, nonZeroFirstDimLabel, false);4252iComment("if 1st dim is also 0, we handle it here. Else, jump to nonZeroFirstDimLabel.");42534254// First dimension zero, so only allocate 1 zero-length object array4255TR::Register *vmThreadReg = cg->getMethodMetaDataRealRegister();4256generateRXInstruction(cg, TR::InstOpCode::LG, node, targetReg, generateS390MemoryReference(vmThreadReg, offsetof(J9VMThread, heapAlloc), cg));42574258// Take into account alignment requirements for the size of the zero-length array header4259int32_t zeroArraySizeAligned = OMR::align(TR::Compiler->om.discontiguousArrayHeaderSizeInBytes(), TR::Compiler->om.getObjectAlignmentInBytes());42604261// Branch to OOL if there's not enough space for an array of size 0.4262TR::Register *temp1Reg = cg->allocateRegister();4263if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_S390_Z196))4264{4265generateRIEInstruction(cg, TR::InstOpCode::AGHIK, node, temp1Reg, targetReg, zeroArraySizeAligned);4266}4267else4268{4269generateRRInstruction(cg, TR::InstOpCode::LGR, node, temp1Reg, targetReg);4270generateRILInstruction(cg, TR::InstOpCode::AGFI, node, temp1Reg, zeroArraySizeAligned);4271}42724273generateRXInstruction(cg, TR::InstOpCode::CLG, node, temp1Reg, generateS390MemoryReference(vmThreadReg, offsetof(J9VMThread, heapTop), cg));4274cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BH, node, oolJumpLabel);4275iComment("Branch to oolJumpLabel if there isn't enough space for a 0 size array.");42764277// If there's enough space, then we can continue to allocate.4278generateRXInstruction(cg, TR::InstOpCode::STG, node, temp1Reg, generateS390MemoryReference(vmThreadReg, offsetof(J9VMThread, heapAlloc), cg));42794280bool use64BitClasses = comp->target().is64Bit() && !TR::Compiler->om.generateCompressedObjectHeaders();42814282// Init class field, then jump to end of ICF4283generateRXInstruction(cg, use64BitClasses ? TR::InstOpCode::STG : TR::InstOpCode::ST, node, classReg, generateS390MemoryReference(targetReg, TR::Compiler->om.offsetOfObjectVftField(), cg));4284cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);4285iComment("Init class field and jump to end of ICF.");42864287// We end up in this region of the ICF if the first dimension is non-zero and the second dimension is zero.4288cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, nonZeroFirstDimLabel);4289iComment("nonZeroFirstDimLabel, 2nd dim length is 0.");42904291TR::Register *componentClassReg = cg->allocateRegister();4292generateRXInstruction(cg, TR::InstOpCode::LG, node, componentClassReg, generateS390MemoryReference(classReg, offsetof(J9ArrayClass, componentType), cg));42934294// Calculate maximum allowable object size in elements and jump to OOL if firstDimLenReg is higher than it.4295int32_t elementSize = TR::Compiler->om.sizeofReferenceField();4296uintptr_t maxObjectSize = cg->getMaxObjectSizeGuaranteedNotToOverflow();4297uintptr_t maxObjectSizeInElements = maxObjectSize / elementSize;4298cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CL, node, firstDimLenReg, static_cast<int32_t>(maxObjectSizeInElements), TR::InstOpCode::COND_BHR, oolJumpLabel, false);4299iComment("Jump to oolJumpLabel if 1st dim len > the num of elements a block can fit.");43004301// Now check to see if we have enough space to do the allocation. If not then jump to OOL code.4302int32_t elementSizeAligned = OMR::align(elementSize, TR::Compiler->om.getObjectAlignmentInBytes());4303int32_t alignmentCompensation = (elementSize == elementSizeAligned) ? 0 : elementSizeAligned - 1;4304static const uint8_t multiplierToStrideMap[] = {0, 0, 1, 0, 2, 0, 0, 0, 3};4305TR_ASSERT_FATAL(elementSize <= 8, "multianewArrayEvaluator - elementSize cannot be greater than 8!");4306generateRSInstruction(cg, TR::InstOpCode::SLLG, node, temp1Reg, firstDimLenReg, multiplierToStrideMap[elementSize]);4307generateRILInstruction(cg, TR::InstOpCode::AGFI, node, temp1Reg, static_cast<int32_t>(TR::Compiler->om.contiguousArrayHeaderSizeInBytes()) + alignmentCompensation);43084309if (alignmentCompensation != 0)4310{4311generateRILInstruction(cg, TR::InstOpCode::NILF, node, temp1Reg, -elementSizeAligned);4312}43134314TR::Register *temp2Reg = cg->allocateRegister();4315generateRRInstruction(cg, TR::InstOpCode::LGR, node, temp2Reg, firstDimLenReg);4316generateRILInstruction(cg, TR::InstOpCode::MSGFI, node, temp2Reg, zeroArraySizeAligned);43174318cursor = generateRRInstruction(cg, TR::InstOpCode::AGR, node, temp2Reg, temp1Reg);4319iComment("Calculates (firstDimLen * zeroArraySizeAligned) + (arrayStrideInBytes + arrayHeaderSize)");43204321generateRXInstruction(cg, TR::InstOpCode::LG, node, targetReg, generateS390MemoryReference(vmThreadReg, offsetof(J9VMThread, heapAlloc), cg));4322generateRRInstruction(cg, TR::InstOpCode::AGR, node, temp2Reg, targetReg);4323generateRXInstruction(cg, TR::InstOpCode::CLG, node, temp2Reg, generateS390MemoryReference(vmThreadReg, offsetof(J9VMThread, heapTop), cg));43244325cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BH, node, oolJumpLabel);4326iComment("Branch to oolJumpLabel if we don't have enough space for both 1st and 2nd dim.");43274328// We have enough space, so proceed with the allocation.4329generateRXInstruction(cg, TR::InstOpCode::STG, node, temp2Reg, generateS390MemoryReference(vmThreadReg, offsetof(J9VMThread, heapAlloc), cg));433043314332// Init 1st dim array class and size fields.4333cursor = generateRXInstruction(cg, use64BitClasses ? TR::InstOpCode::STG : TR::InstOpCode::ST, node, classReg, generateS390MemoryReference(targetReg, TR::Compiler->om.offsetOfObjectVftField(), cg));4334iComment("Init 1st dim class field.");4335cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, firstDimLenReg, generateS390MemoryReference(targetReg, fej9->getOffsetOfContiguousArraySizeField(), cg));4336iComment("Init 1st dim size field.");4337// temp2 point to end of 1st dim array i.e. start of 2nd dim4338generateRRInstruction(cg, TR::InstOpCode::LGR, node, temp2Reg, targetReg);4339generateRRInstruction(cg, TR::InstOpCode::AGR, node, temp2Reg, temp1Reg);4340if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_S390_Z196))4341{4342generateRIEInstruction(cg, TR::InstOpCode::AGHIK, node, temp1Reg, targetReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes());4343}4344else4345{4346generateRRInstruction(cg, TR::InstOpCode::LGR, node, temp1Reg, targetReg);4347generateRILInstruction(cg, TR::InstOpCode::AGFI, node, temp1Reg, static_cast<int32_t>(TR::Compiler->om.contiguousArrayHeaderSizeInBytes()));4348}43494350// Loop start4351TR::LabelSymbol *loopLabel = generateLabelSymbol(cg);4352cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);4353iComment("loopLabel: init 2nd dim's class field.");43544355// Init 2nd dim element's class4356cursor = generateRXInstruction(cg, use64BitClasses ? TR::InstOpCode::STG : TR::InstOpCode::ST, node, componentClassReg, generateS390MemoryReference(temp2Reg, TR::Compiler->om.offsetOfObjectVftField(), cg));4357iComment("Init 2nd dim class field.");43584359// Store 2nd dim element into 1st dim array slot, compress temp2 if needed4360TR::Register *temp3Reg = cg->allocateRegister();4361if (comp->target().is64Bit() && comp->useCompressedPointers())4362{4363int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();4364generateRRInstruction(cg, TR::InstOpCode::LGR, node, temp3Reg, temp2Reg);4365if (shiftAmount != 0)4366{4367generateRSInstruction(cg, TR::InstOpCode::SRAG, node, temp3Reg, temp3Reg, shiftAmount);4368}4369generateRXInstruction(cg, TR::InstOpCode::ST, node, temp3Reg, generateS390MemoryReference(temp1Reg, 0, cg));4370}4371else4372{4373generateRXInstruction(cg, TR::InstOpCode::STG, node, temp2Reg, generateS390MemoryReference(temp1Reg, 0, cg));4374}43754376// Advance cursors temp1 and temp2. Then branch back or fall through if done.4377generateRIInstruction(cg, TR::InstOpCode::AGHI, node, temp2Reg, zeroArraySizeAligned);4378generateRIInstruction(cg, TR::InstOpCode::AGHI, node, temp1Reg, elementSize);43794380generateRILInstruction(cg, TR::InstOpCode::SLFI, node, firstDimLenReg, 1);4381generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CL, node, firstDimLenReg, 0, TR::InstOpCode::COND_BNE, loopLabel, false);4382generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);43834384TR::RegisterDependencyConditions *dependencies = generateRegisterDependencyConditions(0,10,cg);4385dependencies->addPostCondition(dimReg, TR::RealRegister::AssignAny);4386dependencies->addPostCondition(secondDimLenReg, TR::RealRegister::AssignAny);4387dependencies->addPostCondition(firstDimLenReg, TR::RealRegister::AssignAny);4388dependencies->addPostCondition(targetReg, TR::RealRegister::AssignAny);4389dependencies->addPostCondition(dimsPtrReg, TR::RealRegister::AssignAny);4390dependencies->addPostCondition(temp1Reg, TR::RealRegister::AssignAny);4391dependencies->addPostCondition(classReg, TR::RealRegister::AssignAny);4392dependencies->addPostCondition(componentClassReg, TR::RealRegister::AssignAny);4393dependencies->addPostCondition(temp2Reg, TR::RealRegister::AssignAny);4394dependencies->addPostCondition(temp3Reg, TR::RealRegister::AssignAny);43954396generateS390LabelInstruction(cg, TR::InstOpCode::label, node, oolJumpLabel);4397generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, oolFailLabel);43984399generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, dependencies);44004401TR::Register *targetRegisterFinal = cg->allocateCollectedReferenceRegister();4402generateRRInstruction(cg, TR::InstOpCode::LGR, node, targetRegisterFinal, targetReg);44034404// Generate the OOL code before final bookkeeping.4405TR_S390OutOfLineCodeSection *outlinedSlowPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(oolFailLabel, cFlowRegionEnd, cg);4406cg->getS390OutOfLineCodeSectionList().push_front(outlinedSlowPath);4407outlinedSlowPath->swapInstructionListsWithCompilation();4408generateS390LabelInstruction(cg, TR::InstOpCode::label, node, oolFailLabel);44094410TR::ILOpCodes opCode = node->getOpCodeValue();4411TR::Node::recreate(node, TR::acall);4412TR::Register *targetReg2 = TR::TreeEvaluator::performCall(node, false, cg);4413TR::Node::recreate(node, opCode);44144415generateRRInstruction(cg, TR::InstOpCode::LGR, node, targetReg, targetReg2);4416generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);4417outlinedSlowPath->swapInstructionListsWithCompilation();44184419// Note: We don't decrement the ref count node's children here (i.e. cg->decReferenceCount(node->getFirstChild())) because it is done by the performCall in the OOL code above.4420// Doing so here would end up double decrementing the children nodes' ref count.44214422cg->stopUsingRegister(targetReg);4423cg->stopUsingRegister(firstDimLenReg);4424cg->stopUsingRegister(secondDimLenReg);4425cg->stopUsingRegister(temp1Reg);4426cg->stopUsingRegister(temp2Reg);4427cg->stopUsingRegister(temp3Reg);4428cg->stopUsingRegister(componentClassReg);44294430node->setRegister(targetRegisterFinal);4431return targetRegisterFinal;4432#undef iComment4433}44344435TR::Register *4436J9::Z::TreeEvaluator::arraylengthEvaluator(TR::Node *node, TR::CodeGenerator *cg)4437{4438TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());4439TR::Register *objectReg = cg->evaluate(node->getFirstChild());4440TR::Register *lengthReg = cg->allocateRegister();44414442TR::MemoryReference *contiguousArraySizeMR = generateS390MemoryReference(objectReg, fej9->getOffsetOfContiguousArraySizeField(), cg);4443TR::MemoryReference *discontiguousArraySizeMR = generateS390MemoryReference(objectReg, fej9->getOffsetOfDiscontiguousArraySizeField(), cg);44444445// Load the Contiguous Array Size and test if it's zero.4446generateRSInstruction(cg, TR::InstOpCode::ICM, node, lengthReg, (uint32_t) 0xF, contiguousArraySizeMR);44474448if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_S390_Z196))4449{4450// Conditionally load from discontiguousArraySize if contiguousArraySize is zero4451generateRSInstruction(cg, TR::InstOpCode::LOC, node, lengthReg, 0x8, discontiguousArraySizeMR);4452}4453else4454{4455TR::LabelSymbol * oolStartLabel = generateLabelSymbol(cg);4456TR::LabelSymbol * oolReturnLabel = generateLabelSymbol(cg);44574458// Branch to OOL if contiguous array size is zero4459TR::Instruction * temp = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, oolStartLabel);44604461TR_S390OutOfLineCodeSection *outlinedDiscontigPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(oolStartLabel,oolReturnLabel,cg);4462cg->getS390OutOfLineCodeSectionList().push_front(outlinedDiscontigPath);4463outlinedDiscontigPath->swapInstructionListsWithCompilation();44644465generateS390LabelInstruction(cg, TR::InstOpCode::label, node, oolStartLabel);44664467if (cg->getDebug())4468{4469cg->getDebug()->addInstructionComment(temp, "Start of OOL arraylength sequence");4470}44714472// Load from discontiguousArraySize if contiguousArraySize is zero4473generateRXInstruction(cg, TR::InstOpCode::L, node, lengthReg, discontiguousArraySizeMR);44744475TR::Instruction* returnInsturction = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, oolReturnLabel);44764477if (cg->getDebug())4478{4479cg->getDebug()->addInstructionComment(returnInsturction, "End of OOL arraylength sequence");4480}44814482outlinedDiscontigPath->swapInstructionListsWithCompilation();44834484generateS390LabelInstruction(cg, TR::InstOpCode::label, node, oolReturnLabel);4485}44864487cg->decReferenceCount(node->getFirstChild());4488node->setRegister(lengthReg);4489return lengthReg;4490}449144924493///////////////////////////////////////////////////////////////////////////////////////4494// DIVCHKEvaluator - Divide by zero check. child 1 is the divide. Symbolref indicates4495// failure action/destination4496///////////////////////////////////////////////////////////////////////////////////////4497TR::Register *4498J9::Z::TreeEvaluator::DIVCHKEvaluator(TR::Node * node, TR::CodeGenerator * cg)4499{4500TR::Compilation *comp = cg->comp();4501TR::Node * secondChild = node->getFirstChild()->getSecondChild();4502TR::DataType dtype = secondChild->getType();4503bool constDivisor = secondChild->getOpCode().isLoadConst();4504TR::Snippet * snippet;4505TR::LabelSymbol * snippetLabel = generateLabelSymbol(cg);4506TR::Instruction * cursor = NULL; // Point to instruction that will assign targetReg4507TR::MemoryReference * divisorMr = NULL;45084509bool divisorIsFieldAccess = false;4510bool willUseIndexAndBaseReg = false;4511if (secondChild->getNumChildren() != 0 &&4512secondChild->getOpCode().isMemoryReference() &&4513secondChild->getReferenceCount() == 1 &&4514secondChild->getRegister() == NULL)4515{4516divisorIsFieldAccess = (secondChild->getFirstChild()->getOpCodeValue() != TR::aladd &&4517secondChild->getFirstChild()->getOpCodeValue() != TR::aiadd);4518// Defect 1510614519// The following comes from com/ibm/oti/vm/BootstrapClassLoader.addPackage4520// in hello world with a compressed pointers build4521//4522// [0x0000020007522994] ( 0) DIVCHK #11[0x000002000752293c] Method[jitThrowArithmeticException]4523// [0x0000020007522904] ( 2) irem <flags:"0x8000" (simpleDivCheck )/>4524// [0x000002000752262c] ( 1) iand <flags:"0x1100" (X>=0 cannotOverflow )/>4525// ( 3) ==>icall at [0x00000200075223f8] (in GPR_0049) <flags:"0x30" (arithmeticPreference invalid8BitGlobalRegister)/>4526// [0x00000200075225f4] ( 1) iconst 0x7fffffff <flags:"0x104" (X!=0 X>=0 )/>4527// [0x00000200075228cc] ( 1) iiload #251[0x000002000745c940]+12 Shadow[<array-size>] <flags:"0x1100" (X>=0 cannotOverflow )/>4528// [0x00000200074665d0] ( 1) l2a4529// [0x000002000745c908] ( 1) lshl <flags:"0x800" (compressionSequence )/>4530// ( 2) ==>iu2l at [0x000002000745c8d0] (in GPR_0072) <flags:"0x4" (X!=0 )/>4531// [0x000002000745c860] ( 2) iconst 14532//4533// When generating a memref, because of the shift=1, the memref will use the same register4534// for the base and index register in order to avoid generating a shift instruction4535// But CLGHSI cannot take a memref which uses the index reg45364537willUseIndexAndBaseReg = secondChild->getFirstChild() != NULL &&4538secondChild->getFirstChild()->getOpCodeValue() == TR::l2a &&4539secondChild->getFirstChild()->getFirstChild() != NULL &&4540secondChild->getFirstChild()->getFirstChild()->chkCompressionSequence() &&4541TR::Compiler->om.compressedReferenceShiftOffset() == 1;4542}45434544bool disableS390CompareAndTrap = comp->getOption(TR_DisableTraps);45454546// Try to compare directly to memory if the child is a field access (load with no index reg)4547if (divisorIsFieldAccess &&4548!willUseIndexAndBaseReg &&4549(node->getFirstChild()->getOpCodeValue() == TR::idiv ||4550node->getFirstChild()->getOpCodeValue() == TR::irem))4551{4552divisorMr = TR::MemoryReference::create(cg, secondChild);45534554TR::InstOpCode::Mnemonic op = (dtype.isInt64())? TR::InstOpCode::CLGHSI : TR::InstOpCode::CLFHSI;4555generateSILInstruction(cg, op, node, divisorMr, 0);4556cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, snippetLabel);45574558cursor->setExceptBranchOp();45594560TR::Snippet * snippet = new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference());4561cg->addSnippet(snippet);4562}4563else if (cg->getHasResumableTrapHandler() && !disableS390CompareAndTrap)4564{4565TR::InstOpCode::Mnemonic op = (dtype.isInt64())? TR::InstOpCode::CLGIT : TR::InstOpCode::CLFIT;4566TR::Register * srcReg = cg->evaluate(secondChild);4567TR::S390RIEInstruction* cursor =4568new (cg->trHeapMemory()) TR::S390RIEInstruction(op, node, srcReg, (int16_t)0, TR::InstOpCode::COND_BE, cg);4569cursor->setExceptBranchOp();4570cg->setCanExceptByTrap(true);4571cursor->setNeedsGCMap(0x0000FFFF);4572if (cg->comp()->target().isZOS())4573{4574killRegisterIfNotLocked(cg, TR::RealRegister::GPR4, cursor);4575}4576}4577// z9 legacy instructions4578else4579{4580// Generate explicit div by 0 test and snippet to jump to4581if (!constDivisor || (dtype.isInt32() && secondChild->getInt() == 0) || (dtype.isInt64() && secondChild->getLongInt() == 0))4582{4583// if divisor is a constant of zero, branch to the snippet to throw exception4584if (constDivisor)4585{4586cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, snippetLabel);4587cursor->setExceptBranchOp();4588}4589else4590{4591// if divisor is non-constant, need explicit test for 04592TR::Register * srcReg;4593srcReg = cg->evaluate(secondChild);4594TR::InstOpCode::Mnemonic op = dtype.isInt64() ? TR::InstOpCode::LTGR : TR::InstOpCode::LTR;4595generateRRInstruction(cg, op, node, srcReg, srcReg);4596cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, snippetLabel);4597cursor->setExceptBranchOp();4598}4599TR::Snippet * snippet = new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference());4600cg->addSnippet(snippet);4601}4602}46034604if (divisorMr)4605{4606switch (node->getFirstChild()->getOpCodeValue())4607{4608case TR::idiv:4609iDivRemGenericEvaluator(node->getFirstChild(), cg, true, divisorMr);4610break;4611case TR::irem:4612iDivRemGenericEvaluator(node->getFirstChild(), cg, false, divisorMr);4613break;4614}4615divisorMr->stopUsingMemRefRegister(cg);4616}4617else4618{4619cg->evaluate(node->getFirstChild());4620}4621cg->decReferenceCount(node->getFirstChild());46224623return NULL;4624}462546264627///////////////////////////////////////////////////////////////////////////////////////4628// BNDCHKEvaluator - Array bounds check, checks that child 1 > child 2 >= 04629// (child 1 is bound, 2 is index). Symbolref indicates failure action/destination4630///////////////////////////////////////////////////////////////////////////////////////4631TR::Register *4632J9::Z::TreeEvaluator::BNDCHKEvaluator(TR::Node * node, TR::CodeGenerator * cg)4633{4634TR::Node * firstChild = node->getFirstChild();4635TR::Node * secondChild = node->getSecondChild();4636TR::LabelSymbol * boundCheckFailureLabel = generateLabelSymbol(cg);4637TR::Snippet * snippet;4638bool swap;4639TR::Instruction* cursor = NULL;4640TR::Compilation *comp = cg->comp();46414642TR::Register * arrayLengthReg = firstChild->getRegister();4643TR::Register * arrayIndexReg = secondChild->getRegister();46444645// skip l2i. Grab the low order register if it's a register pair.4646bool skipArrayLengthReg = false;4647bool skipArrayIndexReg = false;4648if (firstChild->getOpCodeValue() == TR::l2i &&4649firstChild->getReferenceCount() == 1 &&4650firstChild->getRegister() == NULL &&4651firstChild->getFirstChild() &&4652firstChild->getFirstChild()->getRegister())4653{4654arrayLengthReg = firstChild->getFirstChild()->getRegister();4655skipArrayLengthReg = true;4656if(arrayLengthReg->getRegisterPair())4657{4658arrayLengthReg = arrayLengthReg->getRegisterPair()->getLowOrder();4659}4660}46614662if (secondChild->getOpCodeValue() == TR::l2i &&4663secondChild->getReferenceCount() == 1 &&4664secondChild->getRegister() == NULL &&4665secondChild->getFirstChild() &&4666secondChild->getFirstChild()->getRegister())4667{4668arrayIndexReg = secondChild->getFirstChild()->getRegister();4669skipArrayIndexReg = true;4670if(arrayIndexReg->getRegisterPair())4671{4672arrayIndexReg = arrayIndexReg->getRegisterPair()->getLowOrder();4673}4674}46754676// use CLRT (RR) if possible4677bool useS390CompareAndTrap = !comp->getOption(TR_DisableTraps) && cg->getHasResumableTrapHandler();46784679if (useS390CompareAndTrap &&4680(arrayIndexReg != NULL && arrayLengthReg != NULL))4681{4682//arrayIndex/arrayLength are max uint32, so 31 bit logical compare even in 64 bit JIT4683// The optimizer does not always fold away the BNDCHK if the index is a negative constant.4684// Explicit index<0 check is not needed here because negative array index is interpreted4685// as a large positive by the CLRT instruction.46864687// ** Generate a NOP LR R0,R0. The signal handler has to walk backwards to pattern match4688// the trap instructions. All trap instructions besides CRT/CLRT are 6-bytes in length.4689// Insert 2-byte NOP in front of the 4-byte CLRT to ensure we do not mismatch accidentally.4690cursor = new (cg->trHeapMemory()) TR::S390NOPInstruction(TR::InstOpCode::NOP, 2, node, cg);46914692TR::Instruction* cursor = generateRRFInstruction(cg, TR::InstOpCode::CLRT,4693node, arrayIndexReg, arrayLengthReg,4694getMaskForBranchCondition(TR::InstOpCode::COND_BNLR), true);4695cursor->setExceptBranchOp();4696cursor->setNeedsGCMap(0x0000FFFF);4697cg->setCanExceptByTrap(true);46984699if (cg->comp()->target().isZOS()) killRegisterIfNotLocked(cg, TR::RealRegister::GPR4, cursor);47004701if (skipArrayLengthReg)4702{4703cg->decReferenceCount(firstChild->getFirstChild());4704}4705if (skipArrayIndexReg)4706{4707cg->decReferenceCount(secondChild->getFirstChild());4708}4709cg->decReferenceCount(firstChild);4710cg->decReferenceCount(secondChild);47114712return NULL;4713}4714else4715{4716// Perform a bound check.4717//4718// Value propagation or profile-directed optimization may have determined4719// that the array bound is a constant, and lowered TR::arraylength into an4720// iconst. In this case, make sure that the constant is the second child.4721//4722// Only type of scenario where first/second children are const is if we need it to force a branch4723// otherwise simplifier should have cleaned it up47244725/**4726* Both Length and Index are constants4727*/4728if (firstChild->getOpCode().isLoadConst() && secondChild->getOpCode().isLoadConst())4729{4730int64_t secondChildConstValue = secondChild->get64bitIntegralValue();4731if (firstChild->getInt() > secondChildConstValue && secondChildConstValue >= 0)4732{4733//nothing to do since inside limit4734}4735else4736{4737// We must evaluate the non-const child if it has not been evaluated4738//4739if (!firstChild->getOpCode().isLoadConst() && firstChild->getRegister() == NULL)4740{4741cg->evaluate(firstChild);4742}47434744// Check will always fail, just jump to failure snippet4745cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, boundCheckFailureLabel);4746cg->addSnippet(new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, boundCheckFailureLabel, node->getSymbolReference()));4747cursor->setExceptBranchOp();4748}4749cg->decReferenceCount(firstChild);4750cg->decReferenceCount(secondChild);4751return NULL;4752}47534754/**4755* One of Length and Index is a constant4756*/4757bool isForward = false;4758TR::Node * constNode = NULL;4759TR::Node * nonConstNode = NULL;4760bool oneConst = false; // exactly one child is a constant4761TR::Node * skippedL2iNode = NULL;47624763if (firstChild->getOpCode().isLoadConst() || secondChild->getOpCode().isLoadConst())4764{4765oneConst = true;4766if (firstChild->getOpCode().isLoadConst())4767{4768isForward = false;4769constNode = firstChild;4770nonConstNode = secondChild;4771}4772else4773{4774isForward = true;4775constNode = secondChild;4776nonConstNode = firstChild;4777}47784779skippedL2iNode = NULL;4780if (nonConstNode->getOpCodeValue() == TR::l2i &&4781nonConstNode->getRegister() == NULL &&4782nonConstNode->getReferenceCount() ==1)4783{4784skippedL2iNode = nonConstNode;4785nonConstNode = nonConstNode->getFirstChild();4786}4787}47884789int64_t value = -1;4790int32_t constValue = -1;4791if (constNode)4792{4793value = getIntegralValue(constNode);4794constValue = constNode->getInt();4795}47964797// always fail the BNDCHK if the index is negative.4798bool alwaysFailBNDCHK = oneConst && (constValue < 0) && isForward;47994800if (oneConst &&4801constValue <= MAX_UNSIGNED_IMMEDIATE_VAL && // CLFIT takes 16bit unsigned immediate4802(constValue & 0xFF00) != 0xB900 && // signal handler might get confused with CLR (opcode 0xB973), etc4803useS390CompareAndTrap)4804{4805// Any constValue <= MAX_UNSIGNED_IMMEDIATE_VAL is taken here.4806// The length is assumed to be non-negative and is within [0, max_uint32] range.4807// The index can be negative or [0, max_uint32]. An unconditional branch is generated if it's negative.4808// No need to use unconditional BRC because it requires a proceeding NO-OP instruction for proper signal4809// handling. And NOP+BRC is of the same length as CLFIT.4810TR::Register * testRegister = cg->evaluate(nonConstNode);4811TR::InstOpCode::S390BranchCondition bc = alwaysFailBNDCHK ? TR::InstOpCode::COND_BRC :4812isForward ? TR::InstOpCode::COND_BNH :4813TR::InstOpCode::COND_BNL ;48144815TR::Instruction* cursor = generateRIEInstruction(cg, TR::InstOpCode::CLFIT,4816node, testRegister, (int16_t)constValue, bc);481748184819cursor->setExceptBranchOp();4820cg->setCanExceptByTrap(true);4821cursor->setNeedsGCMap(0x0000FFFF);48224823if (cg->comp()->target().isZOS())4824{4825killRegisterIfNotLocked(cg, TR::RealRegister::GPR4, cursor);4826}48274828if (skippedL2iNode)4829{4830cg->decReferenceCount(skippedL2iNode);4831}4832cg->decReferenceCount(constNode);4833cg->decReferenceCount(nonConstNode);48344835return NULL;4836}4837else if (useS390CompareAndTrap &&4838((firstChild->getOpCode().isLoadVar() &&4839firstChild->getReferenceCount() == 1 &&4840firstChild->getRegister() == NULL) ||4841(secondChild->getOpCode().isLoadVar() &&4842secondChild->getReferenceCount() == 1 &&4843secondChild->getRegister() == NULL)) &&4844cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_S390_ZEC12))4845{4846// Assume 1st child is the memory operand.4847TR::Node * memChild = firstChild;4848TR::Node * regChild = secondChild;4849TR::InstOpCode::S390BranchCondition compareCondition = TR::InstOpCode::COND_BNL;48504851// Check if first child is really the memory operand4852if (!(firstChild->getOpCode().isLoadVar() &&4853firstChild->getReferenceCount() == 1 &&4854firstChild->getRegister() == NULL))4855{4856// Nope... the second child is!4857memChild = secondChild;4858regChild = firstChild;4859compareCondition = TR::InstOpCode::COND_BNH;4860}48614862// Ensure register operand is evaluated into register4863if (regChild->getRegister() == NULL)4864cg->evaluate(regChild);48654866TR::InstOpCode::Mnemonic opCode = (regChild->getDataType()==TR::Int64) ? TR::InstOpCode::CLGT :4867TR::InstOpCode::CLT;4868cursor = generateRSInstruction(cg, opCode,4869node, regChild->getRegister(),4870getMaskForBranchCondition(compareCondition),4871TR::MemoryReference::create(cg, memChild));4872cursor->setExceptBranchOp();4873cg->setCanExceptByTrap(true);4874cursor->setNeedsGCMap(0x0000FFFF);48754876if (cg->comp()->target().isZOS())4877killRegisterIfNotLocked(cg, TR::RealRegister::GPR4, cursor);48784879cg->decReferenceCount(memChild);4880cg->decReferenceCount(regChild);48814882return NULL;4883}4884else if (oneConst)4885{4886TR::Register * testRegister = cg->evaluate(nonConstNode);4887TR::InstOpCode::S390BranchCondition bc = alwaysFailBNDCHK ? TR::InstOpCode::COND_BRC :4888isForward ? TR::InstOpCode::COND_BNH :4889TR::InstOpCode::COND_BNL;4890TR::Instruction* cursor = NULL;48914892if (alwaysFailBNDCHK)4893{4894cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, bc, node, boundCheckFailureLabel);4895}4896else4897{4898cursor = generateS390CompareAndBranchInstruction(cg,4899TR::InstOpCode::CL,4900node,4901testRegister,4902constValue,4903bc,4904boundCheckFailureLabel, false, true);4905}49064907cursor->setExceptBranchOp();49084909if (skippedL2iNode)4910{4911cg->decReferenceCount(skippedL2iNode);4912}4913cg->decReferenceCount(constNode);4914cg->decReferenceCount(nonConstNode);4915}491649174918// We assume that there is no GRA stuff hanging of this node4919TR_ASSERT( node->getNumChildren() < 3,"BNDCHK Eval: We are not expecting a third child on BNDCHK trees");49204921/**4922* Neither Length nor Index is constant4923*/4924if (!oneConst)4925{4926// logical compare child1 (bound) and child2 (index).4927// Logical because all neg # > any pos # in unsigned form - for check that index > 0.4928// if child1 <= child2, branch on not high,4929// if the operands are switched, i.e. compare child2 < child1, branch on high4930TR_S390BinaryCommutativeAnalyser temp(cg);4931temp.genericAnalyser(node, TR::InstOpCode::CLR, TR::InstOpCode::CL, TR::InstOpCode::LR, true);4932swap = temp.getReversedOperands();49334934// There should be no register attached to the BNDCHK node, otherwise4935// the register would be kept live longer than it should.4936node->unsetRegister();4937cg->decReferenceCount(firstChild);4938cg->decReferenceCount(secondChild);49394940// Generate compare code, find out if ops were reversed4941// MASK10 - reversed. MASK12 - not reversed.4942TR::InstOpCode::Mnemonic brOp = TR::InstOpCode::BRC;4943TR::InstOpCode::S390BranchCondition brCond = (swap) ? TR::InstOpCode::COND_BNL : TR::InstOpCode::COND_BNH;4944cursor = generateS390BranchInstruction(cg, brOp, brCond, node, boundCheckFailureLabel);4945cursor->setExceptBranchOp();4946}49474948cg->addSnippet(new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, boundCheckFailureLabel, node->getSymbolReference()));4949}49504951return NULL;4952}4953495449554956///////////////////////////////////////////////////////////////////////////////////////4957// ArrayCopyBNDCHKEvaluator - Array bounds check for arraycopy, checks that child 1 >= child 24958///////////////////////////////////////////////////////////////////////////////////////4959TR::Register *4960J9::Z::TreeEvaluator::ArrayCopyBNDCHKEvaluator(TR::Node * node, TR::CodeGenerator * cg)4961{4962// Check that first child >= second child4963//4964// If the first child is a constant and the second isn't, swap the children.4965//4966TR::Node * firstChild = node->getFirstChild();4967TR::Node * secondChild = node->getSecondChild();4968TR::LabelSymbol * boundCheckFailureLabel = generateLabelSymbol(cg);4969TR::Instruction * instr = NULL;4970bool useCIJ = false;4971TR::Compilation *comp = cg->comp();49724973bool skipL2iArrayTargetLengthReg = false;4974bool skipL2iArrayCopyLengthReg = false;4975TR::Register * arrayTargetLengthReg = NULL;4976TR::Register * arrayCopyLengthReg = NULL;49774978arrayTargetLengthReg = firstChild->getRegister();4979arrayCopyLengthReg = secondChild->getRegister();49804981if (firstChild->getOpCodeValue() == TR::l2i &&4982firstChild->getFirstChild()->getRegister() != NULL &&4983firstChild->getReferenceCount() == 1 &&4984arrayTargetLengthReg == NULL)4985{4986skipL2iArrayTargetLengthReg = true;4987arrayTargetLengthReg = firstChild->getFirstChild()->getRegister();4988}49894990if (secondChild->getOpCodeValue() == TR::l2i &&4991secondChild->getFirstChild()->getRegister() != NULL &&4992secondChild->getReferenceCount() == 1 &&4993arrayCopyLengthReg == NULL)4994{4995skipL2iArrayCopyLengthReg = true;4996arrayCopyLengthReg = secondChild->getFirstChild()->getRegister();4997}49984999bool disableS390CompareAndTrap = comp->getOption(TR_DisableTraps);5000static const char*disableS390CompareAndBranch = feGetEnv("TR_DISABLES390CompareAndBranch");5001if (cg->getHasResumableTrapHandler() &&5002!disableS390CompareAndTrap &&5003arrayTargetLengthReg != NULL &&5004arrayCopyLengthReg != NULL )5005{5006//arrayIndex/arrayLength are max uint32, so 31 bit compare even in 64 bit JIT50075008// Generate a NOP LR R0,R0. The signal handler has to walk backwards to pattern match5009// the trap instructions. All trap instructions besides CRT/CLRT are 6-bytes in length.5010// Insert 2-byte NOP in front of the 4-byte CRT to ensure we do not mismatch accidentally.5011TR::Instruction *cursor = new (cg->trHeapMemory()) TR::S390NOPInstruction(TR::InstOpCode::NOP, 2, node, cg);50125013cursor = new (cg->trHeapMemory()) TR::S390RRFInstruction(TR::InstOpCode::CRT, node, arrayCopyLengthReg, arrayTargetLengthReg, getMaskForBranchCondition(TR::InstOpCode::COND_BH), true, cg);50145015cursor->setExceptBranchOp();5016cg->setCanExceptByTrap(true);5017cursor->setNeedsGCMap(0x0000FFFF);5018if (cg->comp()->target().isZOS()) killRegisterIfNotLocked(cg, TR::RealRegister::GPR4, cursor);50195020if (skipL2iArrayTargetLengthReg)5021{5022cg->decReferenceCount(firstChild->getFirstChild());5023}5024if (skipL2iArrayCopyLengthReg)5025{5026cg->decReferenceCount(secondChild->getFirstChild());5027}5028cg->decReferenceCount(firstChild);5029cg->decReferenceCount(secondChild);50305031return NULL;5032}5033else5034{5035if (firstChild->getOpCode().isLoadConst())5036{5037if (secondChild->getOpCode().isLoadConst())5038{5039if (firstChild->getInt() < secondChild->getInt())5040{5041// Check will always fail, just jump to failure snippet5042//5043instr = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, boundCheckFailureLabel);5044instr->setExceptBranchOp();5045}5046else5047{5048// Check will always succeed, no need for an instruction5049//5050instr = NULL;5051}5052cg->decReferenceCount(firstChild);5053cg->decReferenceCount(secondChild);5054}5055else5056{5057int32_t arrayTargetLengthConst = firstChild->getInt();50585059// CIT uses 16-bit immediates5060if (cg->getHasResumableTrapHandler() &&5061arrayTargetLengthConst <= MAX_IMMEDIATE_VAL &&5062arrayTargetLengthConst >= MIN_IMMEDIATE_VAL &&5063(arrayTargetLengthConst & 0xFF00) != 0xB900 && // signal handler might get confused with CRT (opcode 0xB972), etc5064!disableS390CompareAndTrap )5065{5066if (arrayCopyLengthReg == NULL)5067{5068arrayCopyLengthReg = cg->evaluate(secondChild);5069}50705071TR::S390RIEInstruction* cursor =5072new (cg->trHeapMemory()) TR::S390RIEInstruction(TR::InstOpCode::CIT, node, arrayCopyLengthReg, (int16_t)arrayTargetLengthConst, TR::InstOpCode::COND_BH, cg);5073cursor->setExceptBranchOp();5074cursor->setNeedsGCMap(0x0000FFFF);5075cg->setCanExceptByTrap(true);5076if (cg->comp()->target().isZOS()) killRegisterIfNotLocked(cg, TR::RealRegister::GPR4, cursor);50775078if (skipL2iArrayCopyLengthReg)5079{5080cg->decReferenceCount(secondChild->getFirstChild());5081}5082cg->decReferenceCount(firstChild);5083cg->decReferenceCount(secondChild);50845085return NULL;5086}5087// check if we can use Compare-and-Branch at least5088else if (arrayTargetLengthConst <= MAX_IMMEDIATE_BYTE_VAL &&5089arrayTargetLengthConst >= MIN_IMMEDIATE_BYTE_VAL &&5090!disableS390CompareAndBranch)5091{5092useCIJ = true;5093if (arrayCopyLengthReg == NULL)5094{5095arrayCopyLengthReg = cg->evaluate(secondChild);5096}50975098TR::Instruction* cursor =5099generateS390CompareAndBranchInstruction(cg,5100TR::InstOpCode::C,5101node,5102arrayCopyLengthReg,5103arrayTargetLengthConst,5104TR::InstOpCode::COND_BH,5105boundCheckFailureLabel,5106false,5107false,5108NULL,5109NULL);5110cursor->setExceptBranchOp();51115112if (skipL2iArrayCopyLengthReg)5113{5114cg->decReferenceCount(secondChild->getFirstChild());5115}5116cg->decReferenceCount(firstChild);5117cg->decReferenceCount(secondChild);5118}5119// z9 Instructions5120else5121{5122node->swapChildren();5123instr = generateS390CompareBranchLabel(node, cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BH, TR::InstOpCode::COND_BL, boundCheckFailureLabel);5124node->swapChildren();5125instr->setExceptBranchOp();5126}5127}5128}5129else5130{5131// The first child is not loadConstant5132// CIT uses 16-bit immediates5133if (secondChild->getOpCode().isLoadConst() &&5134cg->getHasResumableTrapHandler() &&5135secondChild->getInt() <= MAX_IMMEDIATE_VAL &&5136secondChild->getInt() >= MIN_IMMEDIATE_VAL &&5137(secondChild->getInt() & 0xFF00) != 0xB900 && // signal handler might get confused with CRT (opcode 0xB972), etc5138!disableS390CompareAndTrap )5139{5140int32_t arrayCopyLengthConst = secondChild->getInt();5141if (arrayTargetLengthReg == NULL)5142{5143arrayTargetLengthReg = cg->evaluate(firstChild);5144}51455146TR::S390RIEInstruction* cursor =5147new (cg->trHeapMemory()) TR::S390RIEInstruction(TR::InstOpCode::CIT, node, arrayTargetLengthReg, (int16_t)arrayCopyLengthConst, TR::InstOpCode::COND_BL, cg);5148cursor->setExceptBranchOp();5149cursor->setNeedsGCMap(0x0000FFFF);5150cg->setCanExceptByTrap(true);5151if (cg->comp()->target().isZOS()) killRegisterIfNotLocked(cg, TR::RealRegister::GPR4, cursor);51525153if (skipL2iArrayTargetLengthReg)5154{5155cg->decReferenceCount(firstChild->getFirstChild());5156}5157cg->decReferenceCount(firstChild);5158cg->decReferenceCount(secondChild);51595160return NULL;5161}5162// check if we can use Compare-and-Branch at least5163else if (secondChild->getOpCode().isLoadConst() &&5164secondChild->getInt() <= MAX_IMMEDIATE_BYTE_VAL &&5165secondChild->getInt() >= MIN_IMMEDIATE_BYTE_VAL &&5166!disableS390CompareAndBranch)5167{5168int32_t arrayCopyLengthConst = secondChild->getInt();5169if (arrayTargetLengthReg == NULL)5170{5171arrayTargetLengthReg = cg->evaluate(firstChild);5172}51735174useCIJ = true;5175TR::Instruction* cursor =5176generateS390CompareAndBranchInstruction(cg,5177TR::InstOpCode::C,5178node,5179arrayTargetLengthReg,5180arrayCopyLengthConst,5181TR::InstOpCode::COND_BL,5182boundCheckFailureLabel,5183false,5184false,5185NULL,5186NULL);51875188cursor->setExceptBranchOp();51895190if (skipL2iArrayTargetLengthReg)5191{5192cg->decReferenceCount(firstChild->getFirstChild());5193}5194cg->decReferenceCount(firstChild);5195cg->decReferenceCount(secondChild);5196}5197// z95198else5199{5200instr = generateS390CompareOps(node, cg, TR::InstOpCode::COND_BL, TR::InstOpCode::COND_BH, boundCheckFailureLabel);52015202instr->setExceptBranchOp();5203}5204}52055206if (instr || useCIJ)5207{5208cg->addSnippet(new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, boundCheckFailureLabel, node->getSymbolReference()));5209}5210}52115212return NULL;5213}52145215void5216J9::Z::TreeEvaluator::generateFillInDataBlockSequenceForUnresolvedField(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *dataSnippetRegister)5217{5218TR::LabelSymbol *unresolvedLabel = generateLabelSymbol(cg);5219TR::LabelSymbol *mergePointLabel = generateLabelSymbol(cg);5220TR::SymbolReference *symRef = node->getSymbolReference();5221bool isStatic = symRef->getSymbol()->getKind() == TR::Symbol::IsStatic;52225223TR::Register *offsetReg = cg->allocateRegister();5224TR::Register *dataBlockReg = cg->allocateRegister();52255226generateRILInstruction(cg, TR::InstOpCode::LARL, node, dataBlockReg, dataSnippet);52275228intptr_t offsetInDataBlock = isStatic ? offsetof(J9JITWatchedStaticFieldData, fieldAddress) : offsetof(J9JITWatchedInstanceFieldData, offset);5229generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, offsetReg, generateS390MemoryReference(dataBlockReg, offsetInDataBlock, cg));5230// If the offset is not -1 then the field is already resolved. No more work is required and we can fall through to end (mergePointLabel).5231generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, offsetReg, -1, TR::InstOpCode::COND_BE, unresolvedLabel, false, false, NULL, NULL);52325233// If the offset is -1, then we must call a VM helper routine (indicated by helperLink below) to resolve this field. The OOL code (below) inside unresolvedLabel5234// will prepare the registers and generate a directCall to the VM helper routine.5235TR_S390OutOfLineCodeSection *outlinedSlowPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(unresolvedLabel, mergePointLabel, cg);5236cg->getS390OutOfLineCodeSectionList().push_front(outlinedSlowPath);5237outlinedSlowPath->swapInstructionListsWithCompilation();52385239// OOL code start.5240generateS390LabelInstruction(cg, TR::InstOpCode::label, node, unresolvedLabel);52415242if (isStatic)5243{5244// Fills in J9JITWatchedStaticFieldData.fieldClass.5245TR::Register *fieldClassReg;5246if (isWrite)5247{5248fieldClassReg = cg->allocateRegister();5249generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, fieldClassReg, generateS390MemoryReference(sideEffectRegister, cg->comp()->fej9()->getOffsetOfClassFromJavaLangClassField(), cg));5250}5251else5252{5253fieldClassReg = sideEffectRegister;5254}5255generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, fieldClassReg, generateS390MemoryReference(dataBlockReg, offsetof(J9JITWatchedStaticFieldData, fieldClass), cg));5256if (isWrite)5257{5258cg->stopUsingRegister(fieldClassReg);5259}5260}52615262// These will be used as argument registers for the direct call to the VM helper.5263TR::Register *cpAddressReg = cg->allocateRegister();5264TR::Register *cpIndexReg = cg->allocateRegister();52655266// Populate the argument registers.5267TR::ResolvedMethodSymbol *methodSymbol = node->getByteCodeInfo().getCallerIndex() == -1 ? cg->comp()->getMethodSymbol() : cg->comp()->getInlinedResolvedMethodSymbol(node->getByteCodeInfo().getCallerIndex());5268generateRegLitRefInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, cpAddressReg, reinterpret_cast<uintptr_t>(methodSymbol->getResolvedMethod()->constantPool()), TR_ConstantPool, NULL, 0, 0);5269generateRILInstruction(cg, TR::InstOpCode::LGFI, node, cpIndexReg, symRef->getCPIndex());52705271TR_RuntimeHelper helperIndex = isWrite? (isStatic ? TR_jitResolveStaticFieldSetterDirect: TR_jitResolveFieldSetterDirect) :5272(isStatic ? TR_jitResolveStaticFieldDirect: TR_jitResolveFieldDirect);5273J9::Z::HelperLinkage *helperLink = static_cast<J9::Z::HelperLinkage*>(cg->getLinkage(runtimeHelperLinkage(helperIndex)));527452755276// We specify 2 preConditions because we need to provide 2 register arguments.5277// We specify 4 postConditions because both of the argument registers need to be specified as5278// register dependencies (GPR 1 as a dummy dependency and GPR2 is a return register), and we5279// need to specify 2 more register dependencies for Entry Point and Return Address register5280// when making a direct call.5281TR::RegisterDependencyConditions *deps = generateRegisterDependencyConditions(2, 4, cg);5282int numArgs = 0;52835284// The VM helper routine that we call expects cpAddress to be in GPR1 and cpIndex inside GPR2.5285// So we set those dependencies here.5286deps->addPreCondition(cpAddressReg, helperLink->getIntegerArgumentRegister(numArgs));5287deps->addPostCondition(cpAddressReg, helperLink->getIntegerArgumentRegister(numArgs));5288numArgs++;52895290// Add pre and post condition because GPR2 is an argument register as well as return register.5291deps->addPreCondition(cpIndexReg, helperLink->getIntegerArgumentRegister(numArgs));5292deps->addPostCondition(cpIndexReg, helperLink->getIntegerReturnRegister()); // cpIndexReg (i.e. GPR2) will also hold the return value of the helper routine call.52935294// These two registers are used for Return Address and Entry Point registers. These dependencies are required when generating directCalls on Z.5295TR::Register *scratchReg1 = cg->allocateRegister();5296TR::Register *scratchReg2 = cg->allocateRegister();5297deps->addPostCondition(scratchReg1, cg->getEntryPointRegister());5298deps->addPostCondition(scratchReg2, cg->getReturnAddressRegister());52995300// Now make the call. Return value of the call is in GPR2 (cpIndexReg).5301TR::Instruction *call = generateDirectCall(cg, node, false /*myself*/, cg->symRefTab()->findOrCreateRuntimeHelper(helperIndex), deps);5302call->setNeedsGCMap(0x0000FFFF);5303call->setDependencyConditions(deps);53045305// For instance fields, the offset (i.e. result value) returned by the vmhelper includes the header size.5306// We subtract the header size from the return value here to get the actual offset.5307if (!isStatic)5308{5309generateRILInstruction(cg, TR::InstOpCode::getSubtractLogicalImmOpCode(), node, cpIndexReg, static_cast<uint32_t>(TR::Compiler->om.objectHeaderSizeInBytes()));5310}53115312// Store the field value into the data snippet to resolve it.5313generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, cpIndexReg, generateS390MemoryReference(dataBlockReg, offsetInDataBlock, cg));53145315// End of OOL code. Branch back to mainline.5316generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, mergePointLabel);5317outlinedSlowPath->swapInstructionListsWithCompilation();5318generateS390LabelInstruction(cg, TR::InstOpCode::label, node, mergePointLabel);53195320cg->stopUsingRegister(cpIndexReg);5321cg->stopUsingRegister(scratchReg1);5322cg->stopUsingRegister(scratchReg2);5323cg->stopUsingRegister(cpAddressReg);5324cg->stopUsingRegister(dataBlockReg);5325cg->stopUsingRegister(offsetReg);5326}53275328/*5329* This method will prepare the registers and then make a VM Helper call to report that a fieldwatch event has occurred5330* in a Java class with field watch enabled.5331*5332* The possible VM Helpers are:5333*5334* For indirect nodes (i.e. instance fields):5335* jitReportInstanceFieldRead (if node is indirect)5336* arg1 pointer to static data block5337* arg2 object being read5338*5339* jitReportInstanceFieldWrite (if node is indirect)5340* arg1 pointer to static data block5341* arg2 object being written to (represented by sideEffectRegister)5342* arg3 pointer to value being written5343*5344* For direct nodes (i.e. static fields):5345* jitReportStaticFieldRead (for direct/static nodes)5346* arg1 pointer to static data block5347*5348* jitReportStaticFieldWrite5349* arg1 pointer to static data block5350* arg2 pointer to value being written5351*/5352void generateReportFieldAccessOutlinedInstructions(TR::Node *node, TR::LabelSymbol *fieldReportLabel, TR::LabelSymbol *mergePointLabel, TR::Snippet *dataSnippet, bool isWrite, TR::CodeGenerator *cg, TR::Register *sideEffectRegister, TR::Register *valueReg)5353{5354bool isInstanceField = node->getSymbolReference()->getSymbol()->getKind() != TR::Symbol::IsStatic;5355// Figure out the VM Helper we need to call.5356TR_RuntimeHelper helperIndex = isWrite ? (isInstanceField ? TR_jitReportInstanceFieldWrite: TR_jitReportStaticFieldWrite):5357(isInstanceField ? TR_jitReportInstanceFieldRead: TR_jitReportStaticFieldRead);53585359// Figure out the number of dependencies needed to make the VM Helper call.5360// numPreConditions is equal to the number of arguments required by the VM Helper.5361uint8_t numPreConditions = 1; // All helpers need at least one parameter.5362if (helperIndex == TR_jitReportInstanceFieldWrite)5363{5364numPreConditions = 3;5365}5366else if (helperIndex == TR_jitReportInstanceFieldRead || helperIndex == TR_jitReportStaticFieldWrite)5367{5368numPreConditions = 2;5369}5370// Note: All preConditions need to be added as post dependencies (dummy dependencies). We also need to specify 2 more5371// post dependencies for Return Address register and Entry Point register.5372TR::RegisterDependencyConditions *dependencies = generateRegisterDependencyConditions(numPreConditions, numPreConditions + 2, cg);5373J9::Z::HelperLinkage *helperLink = static_cast<J9::Z::HelperLinkage*>(cg->getLinkage(runtimeHelperLinkage(helperIndex)));5374int numArgs = 0;53755376// Initialize OOL path and generate label that marks beginning of the OOL code.5377TR_S390OutOfLineCodeSection *outlinedSlowPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(fieldReportLabel, mergePointLabel, cg);5378cg->getS390OutOfLineCodeSectionList().push_front(outlinedSlowPath);5379outlinedSlowPath->swapInstructionListsWithCompilation();5380generateS390LabelInstruction(cg, TR::InstOpCode::label, node, fieldReportLabel);53815382// Populate the first argument needed by the VM Helper (address to the data snippet), and set the dependencies.5383TR::Register *dataBlockReg = cg->allocateRegister();5384generateRILInstruction(cg, TR::InstOpCode::LARL, node, dataBlockReg, dataSnippet);5385dependencies->addPreCondition(dataBlockReg, helperLink->getIntegerArgumentRegister(numArgs));5386dependencies->addPostCondition(dataBlockReg, helperLink->getIntegerArgumentRegister(numArgs));5387dataBlockReg->setPlaceholderReg();5388numArgs++;53895390// Populate the next argument if needed.5391TR::Register *objectReg = NULL;5392if (isInstanceField)5393{5394dependencies->addPreCondition(sideEffectRegister, helperLink->getIntegerArgumentRegister(numArgs));5395dependencies->addPostCondition(sideEffectRegister, helperLink->getIntegerArgumentRegister(numArgs));5396sideEffectRegister->setPlaceholderReg();5397numArgs++;5398}53995400// Populate the final argument if needed.5401// Note: In the event that we have to write to a value, the VM helper routine expects that a pointer to the value being written to5402// is passed in as a parameter. So we must store the value into memory and then load the address back into a register in order5403// to pass the address of that value as an argument. We prepare the register below.5404if (isWrite)5405{5406TR::Node *valueNode = node->getFirstChild();5407if (isInstanceField)5408{5409// Pass in valueNode so it can be set to the correct node.5410TR::TreeEvaluator::getIndirectWrtbarValueNode(cg, node, valueNode, false);5411}54125413// First load the actual value into the register.5414TR::Register *valueReferenceReg = valueReg;54155416TR::DataType nodeType = valueNode->getDataType();5417TR::SymbolReference *sr = cg->allocateLocalTemp(nodeType);5418TR::MemoryReference *valueMR = generateS390MemoryReference(valueNode, sr, cg);5419if (valueReferenceReg->getKind() == TR_GPR)5420{5421// Use STG if the dataType is an uncompressed TR::Address or TR::Int64. ST otherwise.5422auto mnemonic = TR::DataType::getSize(nodeType) == 8 ? TR::InstOpCode::STG : TR::InstOpCode::ST;5423// Now store the value onto the stack.5424generateRXInstruction(cg, mnemonic, node, valueReferenceReg, valueMR);5425}5426else if (valueReferenceReg->getKind() == TR_FPR)5427{5428auto mnemonic = nodeType == TR::Float ? TR::InstOpCode::STE : TR::InstOpCode::STD;5429// Now store the value onto the stack.5430generateRXInstruction(cg, mnemonic, node, valueReferenceReg, valueMR);5431}5432else5433{5434TR_ASSERT_FATAL(false, "Unsupported register kind (%d) for fieldwatch.", valueReferenceReg->getKind());5435}5436valueReferenceReg = cg->allocateRegister();54375438// Now load the memory location back into the register so that it can be used5439// as an argument register for the VM helper call.5440TR::MemoryReference *tempMR = generateS390MemoryReference(*valueMR, 0, cg);5441generateRXInstruction(cg, TR::InstOpCode::LA, node, valueReferenceReg, tempMR);54425443dependencies->addPreCondition(valueReferenceReg, helperLink->getIntegerArgumentRegister(numArgs));5444dependencies->addPostCondition(valueReferenceReg, helperLink->getIntegerArgumentRegister(numArgs));5445valueReferenceReg->setPlaceholderReg();54465447cg->stopUsingRegister(valueReferenceReg);5448}54495450// These registers will hold Entry Point and Return Address registers, which are required when generating a directCall.5451TR::Register *scratch1 = cg->allocateRegister();5452TR::Register *scratch2 = cg->allocateRegister();5453dependencies->addPostCondition(scratch1, cg->getEntryPointRegister());5454dependencies->addPostCondition(scratch2, cg->getReturnAddressRegister());54555456// Now generate the call to VM Helper to report the fieldwatch.5457TR::Instruction *call = generateDirectCall(cg, node, false /*myself*/, cg->symRefTab()->findOrCreateRuntimeHelper(helperIndex), dependencies);5458call->setNeedsGCMap(0x0000FFFF);5459call->setDependencyConditions(dependencies);54605461// After returning from the VM Helper, branch back to mainline code.5462generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, mergePointLabel);5463// End of OOL.5464outlinedSlowPath->swapInstructionListsWithCompilation();54655466cg->stopUsingRegister(scratch1);5467cg->stopUsingRegister(scratch2);54685469cg->stopUsingRegister(dataBlockReg);5470}54715472void5473J9::Z::TreeEvaluator::generateTestAndReportFieldWatchInstructions(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *valueReg, TR::Register *dataSnippetRegister)5474{5475bool isResolved = !node->getSymbolReference()->isUnresolved();5476TR::LabelSymbol *mergePointLabel = generateLabelSymbol(cg);5477TR::LabelSymbol *fieldReportLabel = generateLabelSymbol(cg);54785479TR::Register *fieldClassReg;5480TR::Register *fieldClassFlags = cg->allocateRegister();5481bool opCodeIsIndirect = node->getOpCode().isIndirect();54825483if (opCodeIsIndirect)5484{5485// Load the class of the instance object into fieldClassReg.5486fieldClassReg = cg->allocateRegister();5487TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, fieldClassReg, generateS390MemoryReference(sideEffectRegister, static_cast<int32_t>(TR::Compiler->om.offsetOfObjectVftField()), cg), NULL);5488}5489else5490{5491if (isResolved)5492{5493fieldClassReg = cg->allocateRegister();5494J9Class *fieldClass = static_cast<TR::J9WatchedStaticFieldSnippet *>(dataSnippet)->getFieldClass();5495if (!(cg->needClassAndMethodPointerRelocations()) && cg->canUseRelativeLongInstructions(reinterpret_cast<int64_t>(fieldClass)))5496{5497// For non-AOT (JIT and JITServer) compiles we don't need to use sideEffectRegister here as the class information is available to us at compile time.5498TR_ASSERT_FATAL(fieldClass != NULL, "A valid J9Class must be provided for direct rdbar/wrtbar opcodes %p\n", node);5499generateRILInstruction(cg, TR::InstOpCode::LARL, node, fieldClassReg, static_cast<void *>(fieldClass));5500}5501else5502{5503// If this is an AOT compile, we generate instructions to load the fieldClass directly from the snippet because the fieldClass will be invalid5504// if we load using the dataSnippet's helper query at compile time.5505generateRILInstruction(cg, TR::InstOpCode::LARL, node, fieldClassReg, dataSnippet);5506generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, fieldClassReg, generateS390MemoryReference(fieldClassReg, offsetof(J9JITWatchedStaticFieldData, fieldClass), cg));5507}5508}5509else5510{5511if (isWrite)5512{5513fieldClassReg = cg->allocateRegister();5514generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, fieldClassReg, generateS390MemoryReference(sideEffectRegister, cg->comp()->fej9()->getOffsetOfClassFromJavaLangClassField(), cg));5515}5516else5517{5518fieldClassReg = sideEffectRegister;5519}5520}5521}5522// First load the class flags into a register.5523generateRXInstruction(cg, TR::InstOpCode::L, node, fieldClassFlags, generateS390MemoryReference(fieldClassReg, cg->comp()->fej9()->getOffsetOfClassFlags(), cg));5524// Then test the bit to test with the relevant flag to check if fieldwatch is enabled.5525generateRIInstruction(cg, TR::InstOpCode::TMLL, node, fieldClassFlags, J9ClassHasWatchedFields);5526// If Condition Code from above test is not 0, then we branch to OOL (instructions) to report the fieldwatch event. Otherwise fall through to mergePointLabel.5527generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRNZ, node, fieldReportLabel);55285529// Generate instructions to call a VM Helper and report the fieldwatch event. Also generates an instruction to5530// branch back to mainline (mergePointLabel).5531generateReportFieldAccessOutlinedInstructions(node, fieldReportLabel, mergePointLabel, dataSnippet, isWrite, cg, sideEffectRegister, valueReg);55325533generateS390LabelInstruction(cg, TR::InstOpCode::label, node, mergePointLabel);55345535if (opCodeIsIndirect || isResolved || isWrite)5536{5537cg->stopUsingRegister(fieldClassReg);5538}55395540cg->stopUsingRegister(fieldClassFlags);5541}55425543TR::Register *5544J9::Z::TreeEvaluator::irdbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)5545{5546// For rdbar and wrtbar nodes we first evaluate the children we need to5547// handle the side effects. Then we delegate the evaluation of the remaining5548// children and the load/store operation to the appropriate load/store evaluator.5549TR::Node *sideEffectNode = node->getFirstChild();5550TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);55515552if (cg->comp()->getOption(TR_EnableFieldWatch))5553{5554TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);5555}5556cg->decReferenceCount(sideEffectNode);5557return TR::TreeEvaluator::iloadEvaluator(node, cg);5558}55595560TR::Register *5561J9::Z::TreeEvaluator::irdbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)5562{5563// For rdbar and wrtbar nodes we first evaluate the children we need to5564// handle the side effects. Then we delegate the evaluation of the remaining5565// children and the load/store operation to the appropriate load/store evaluator.5566TR::Register *sideEffectRegister = cg->evaluate(node->getFirstChild());55675568if (cg->comp()->getOption(TR_EnableFieldWatch))5569{5570TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);5571}55725573// Note: For indirect rdbar nodes, the first child (sideEffectNode) is also used by the5574// load evaluator. The load evaluator will also evaluate+decrement it. In order to avoid double5575// decrementing the node we skip doing it here and let the load evaluator do it.5576return TR::TreeEvaluator::iloadEvaluator(node, cg);5577}55785579TR::Register *5580J9::Z::TreeEvaluator::ardbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)5581{5582// For rdbar and wrtbar nodes we first evaluate the children we need to5583// handle the side effects. Then we delegate the evaluation of the remaining5584// children and the load/store operation to the appropriate load/store evaluator.5585TR::Node *sideEffectNode = node->getFirstChild();5586TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);55875588if (cg->comp()->getOption(TR_EnableFieldWatch))5589{5590TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);5591}5592cg->decReferenceCount(sideEffectNode);5593return TR::TreeEvaluator::aloadEvaluator(node, cg);5594}55955596TR::Register *5597J9::Z::TreeEvaluator::ardbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)5598{5599// For rdbar and wrtbar nodes we first evaluate the children we need to5600// handle the side effects. Then we delegate the evaluation of the remaining5601// children and the load/store operation to the appropriate load/store evaluator.5602TR::Register *sideEffectRegister = cg->evaluate(node->getFirstChild());56035604if (cg->comp()->getOption(TR_EnableFieldWatch))5605{5606TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);5607}56085609TR::Register* resultReg = NULL;5610if (TR::Compiler->om.readBarrierType() != gc_modron_readbar_none)5611{5612bool dynLitPoolLoad = false;5613resultReg = TR::TreeEvaluator::checkAndAllocateReferenceRegister(node, cg, dynLitPoolLoad);5614// MemRef can generate BRCL to unresolved data snippet if needed.5615TR::MemoryReference* loadMemRef = TR::MemoryReference::create(cg, node);56165617if (cg->comp()->target().cpu.supportsFeature(OMR_FEATURE_S390_GUARDED_STORAGE))5618{5619TR::TreeEvaluator::checkAndSetMemRefDataSnippetRelocationType(node, cg, loadMemRef);5620TR::InstOpCode::Mnemonic loadOp = cg->comp()->useCompressedPointers() ? TR::InstOpCode::LLGFSG : TR::InstOpCode::LGG;5621generateRXInstruction(cg, loadOp, node, resultReg, loadMemRef);5622}5623else5624{5625TR::TreeEvaluator::generateSoftwareReadBarrier(node, cg, resultReg, loadMemRef);5626}5627node->setRegister(resultReg);5628}5629else5630{5631resultReg = TR::TreeEvaluator::aloadEvaluator(node, cg);5632}5633// Note: For indirect rdbar nodes, the first child (sideEffectNode) is also used by the5634// load evaluator. The load evaluator will also evaluate+decrement it. In order to avoid double5635// decrementing the node we skip doing it here and let the load evaluator do it.5636return resultReg;5637}56385639TR::Register *5640J9::Z::TreeEvaluator::fwrtbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)5641{5642// For rdbar and wrtbar nodes we first evaluate the children we need to5643// handle the side effects. Then we delegate the evaluation of the remaining5644// children and the load/store operation to the appropriate load/store evaluator.5645TR::Register *valueReg = cg->evaluate(node->getSecondChild());5646TR::Node *sideEffectNode = node->getThirdChild();5647TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);56485649if (cg->comp()->getOption(TR_EnableFieldWatch))5650{5651TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);5652}56535654// Note: The reference count for valueReg's node is not decremented here because the5655// store evaluator also uses it and so it will evaluate+decrement it. Thus we must skip decrementing here5656// to avoid double decrementing.5657cg->decReferenceCount(sideEffectNode);5658return TR::TreeEvaluator::fstoreEvaluator(node, cg);5659}56605661TR::Register *5662J9::Z::TreeEvaluator::fwrtbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)5663{5664// For rdbar and wrtbar nodes we first evaluate the children we need to5665// handle the side effects. Then we delegate the evaluation of the remaining5666// children and the load/store operation to the appropriate load/store evaluator.5667TR::Register *valueReg = cg->evaluate(node->getFirstChild());5668TR::Node *sideEffectNode = node->getSecondChild();5669TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);56705671if (cg->comp()->getOption(TR_EnableFieldWatch))5672{5673TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);5674}56755676// Note: The reference count for valueReg's node is not decremented here because the5677// store evaluator also uses it and so it will evaluate+decrement it. Thus we must skip decrementing here5678// to avoid double decrementing.5679cg->decReferenceCount(sideEffectNode);5680return TR::TreeEvaluator::fstoreEvaluator(node, cg);5681}56825683TR::Register *5684J9::Z::TreeEvaluator::dwrtbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)5685{5686// For rdbar and wrtbar nodes we first evaluate the children we need to5687// handle the side effects. Then we delegate the evaluation of the remaining5688// children and the load/store operation to the appropriate load/store evaluator.5689TR::Register *valueReg = cg->evaluate(node->getSecondChild());5690TR::Node *sideEffectNode = node->getThirdChild();5691TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);56925693if (cg->comp()->getOption(TR_EnableFieldWatch))5694{5695TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);5696}56975698// Note: The reference count for valueReg's node is not decremented here because the5699// store evaluator also uses it and so it will evaluate+decrement it. Thus we must skip decrementing here5700// to avoid double decrementing.5701cg->decReferenceCount(sideEffectNode);5702return TR::TreeEvaluator::dstoreEvaluator(node, cg);5703}57045705TR::Register *5706J9::Z::TreeEvaluator::dwrtbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)5707{5708// For rdbar and wrtbar nodes we first evaluate the children we need to5709// handle the side effects. Then we delegate the evaluation of the remaining5710// children and the load/store operation to the appropriate load/store evaluator.5711TR::Register *valueReg = cg->evaluate(node->getFirstChild());5712TR::Node *sideEffectNode = node->getSecondChild();5713TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);57145715if (cg->comp()->getOption(TR_EnableFieldWatch))5716{5717TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);5718}57195720// Note: The reference count for valueReg's node is not decremented here because the5721// store evaluator also uses it and so it will evaluate+decrement it. Thus we must skip decrementing here5722// to avoid double decrementing.5723cg->decReferenceCount(sideEffectNode);5724return TR::TreeEvaluator::dstoreEvaluator(node, cg);5725}57265727TR::Register *5728J9::Z::TreeEvaluator::awrtbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)5729{5730return TR::TreeEvaluator::awrtbariEvaluator(node, cg);5731}57325733TR::Register *5734J9::Z::TreeEvaluator::awrtbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)5735{5736TR::Node *owningObjectChild;5737TR::Node *sourceChild;5738TR::Compilation *comp = cg->comp();5739bool opCodeIsIndirect = node->getOpCode().isIndirect();5740if (opCodeIsIndirect)5741{5742owningObjectChild = node->getChild(2);5743sourceChild = node->getSecondChild();5744}5745else5746{5747owningObjectChild = node->getSecondChild();5748sourceChild = node->getFirstChild();5749}57505751bool usingCompressedPointers = false;5752if (opCodeIsIndirect)5753{5754// Pass in valueNode so it can be set to the correct node. If the sourceChild is modified, usingCompressedPointers will be true.5755usingCompressedPointers = TR::TreeEvaluator::getIndirectWrtbarValueNode(cg, node, sourceChild, true);5756}57575758bool doWrtBar = (TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_oldcheck ||5759TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_cardmark_and_oldcheck ||5760TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_always);5761bool doCrdMrk = ((TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_cardmark ||5762TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_cardmark_incremental ||5763TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_cardmark_and_oldcheck) && !node->isNonHeapObjectWrtBar());57645765bool canSkip = false;5766TR::Register *owningObjectRegister = NULL;5767TR::Register *sourceRegister = NULL;57685769if ((node->getOpCode().isWrtBar() && node->skipWrtBar()) ||5770((node->getOpCodeValue() == TR::ArrayStoreCHK) &&5771node->getFirstChild()->getOpCode().isWrtBar() &&5772node->getFirstChild()->skipWrtBar()))5773{5774canSkip = true;5775}57765777if ((doWrtBar || doCrdMrk) && !canSkip)5778{5779owningObjectRegister = cg->gprClobberEvaluate(owningObjectChild);5780}5781else5782{5783owningObjectRegister = cg->evaluate(owningObjectChild);5784}57855786if (canSkip || opCodeIsIndirect)5787{5788sourceRegister = cg->evaluate(sourceChild);5789}5790else5791{5792sourceRegister = allocateWriteBarrierInternalPointerRegister(cg, sourceChild);5793}57945795TR::Register * compressedRegister = sourceRegister;5796if (usingCompressedPointers)5797{5798compressedRegister = cg->evaluate(node->getSecondChild());5799}58005801// Handle fieldwatch side effect first if it's enabled.5802if (cg->comp()->getOption(TR_EnableFieldWatch) && !node->getSymbolReference()->getSymbol()->isArrayShadowSymbol())5803{5804TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, owningObjectRegister /* sideEffectRegister */, sourceRegister /* valueReg */);5805}58065807// We need to evaluate all the children first before we generate memory reference5808// since it will screw up the code sequence for patching when we do symbol resolution.5809TR::MemoryReference *tempMR = TR::MemoryReference::create(cg, node);5810TR::InstOpCode::Mnemonic storeOp = usingCompressedPointers ? TR::InstOpCode::ST : TR::InstOpCode::getStoreOpCode();5811TR::Instruction * instr = generateRXInstruction(cg, storeOp, node, opCodeIsIndirect ? compressedRegister : sourceRegister, tempMR);58125813// When a new object is stored into an old object, we need to invoke jitWriteBarrierStore5814// helper to update the remembered sets for GC. Helper call is needed only if the object5815// is in old space or is scanned (black). Since the checking involves control flow, we delay5816// the code gen for write barrier since RA cannot handle control flow.5817VMwrtbarEvaluator(node, sourceRegister, owningObjectRegister, sourceChild->isNonNull(), cg);58185819if (opCodeIsIndirect && comp->useCompressedPointers())5820{5821node->setStoreAlreadyEvaluated(true);5822}58235824cg->decReferenceCount(sourceChild);5825if (usingCompressedPointers)5826{5827cg->decReferenceCount(node->getSecondChild());5828cg->recursivelyDecReferenceCount(owningObjectChild);5829}5830else5831{5832cg->decReferenceCount(owningObjectChild);5833}58345835if (owningObjectRegister)5836{5837cg->stopUsingRegister(owningObjectRegister);5838}5839cg->stopUsingRegister(sourceRegister);5840tempMR->stopUsingMemRefRegister(cg);5841return NULL;5842}58435844TR::Register *5845J9::Z::TreeEvaluator::BNDCHKwithSpineCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)5846{5847bool needsBoundCheck = (node->getOpCodeValue() == TR::BNDCHKwithSpineCHK);5848TR::Compilation *comp = cg->comp();5849TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());5850TR::Node *loadOrStoreChild = node->getFirstChild();5851TR::Node *baseArrayChild = node->getSecondChild();5852TR::Node *arrayLengthChild;5853TR::Node *indexChild;58545855if (needsBoundCheck)5856{5857arrayLengthChild = node->getChild(2);5858indexChild = node->getChild(3);5859}5860else5861{5862arrayLengthChild = NULL;5863indexChild = node->getChild(2);5864}58655866if (comp->getOption(TR_TraceCG))5867traceMsg(comp,"loadOrStoreChild: %p baseArrayChild: %p arrayLengthChild: %p indexChild: %p\n",loadOrStoreChild, baseArrayChild, arrayLengthChild, indexChild);58685869// Order of evaluation dictates that the value to be stored needs to be evaluated first.5870if (loadOrStoreChild->getOpCode().isStore() && !loadOrStoreChild->getRegister())5871{5872TR::Node *valueChild = loadOrStoreChild->getSecondChild();5873cg->evaluate(valueChild);5874}58755876TR::Register *baseArrayReg = cg->evaluate(baseArrayChild);5877preEvaluateEscapingNodesForSpineCheck(node, cg);58785879// Generate the SpinCheck.5880TR::MemoryReference *contiguousArraySizeMR = generateS390MemoryReference(baseArrayReg, fej9->getOffsetOfContiguousArraySizeField(), cg);5881TR::MemoryReference *discontiguousArraySizeMR = generateS390MemoryReference(baseArrayReg, fej9->getOffsetOfDiscontiguousArraySizeField(), cg);58825883bool doLoadOrStore = false;5884bool doAddressComputation = true;58855886TR::Register* loadOrStoreReg = NULL;5887TR_Debug * debugObj = cg->getDebug();58885889TR::LabelSymbol * oolStartLabel = generateLabelSymbol(cg);5890TR::LabelSymbol * oolReturnLabel = generateLabelSymbol(cg);5891TR::Register *indexReg = cg->evaluate(indexChild);5892TR::Register *valueReg = NULL;58935894TR::Instruction * branchToOOL;58955896if (needsBoundCheck)5897{5898generateRXInstruction(cg, TR::InstOpCode::CL, node, indexReg, contiguousArraySizeMR);58995900// OOL Will actually throw the AIOB if necessary.5901branchToOOL = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNL, node, oolStartLabel);5902if (debugObj)5903debugObj->addInstructionComment(branchToOOL, "Start of OOL BNDCHKwithSpineCHK sequence");5904}5905else5906{5907// Load the Contiguous Array Size and test if it's zero.5908TR::Register *tmpReg = cg->allocateRegister();5909generateRSInstruction(cg, TR::InstOpCode::ICM, node, tmpReg, (uint32_t) 0xF, contiguousArraySizeMR);5910cg->stopUsingRegister(tmpReg);59115912// Branch to OOL if contiguous array size is zero.5913branchToOOL = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, oolStartLabel);5914if (debugObj)5915debugObj->addInstructionComment(branchToOOL, "Start of OOL BNDCHKwithSpineCHK sequence");5916}59175918// For reference stores, only evaluate the array element address because the store cannot5919// happen here (it must be done via the array store check).5920//5921// For primitive stores, evaluate them now.5922//5923// For loads, evaluate them now.5924//5925TR::Node * actualLoadOrStoreChild = loadOrStoreChild;5926TR::Node * evaluateConversionNode = loadOrStoreChild; // We want to match the top most conversion node and evaluate that.59275928bool doLoadDecompress = false;59295930// Top-level check whether a decompression sequence is necessary, because the first child5931// may have been created by a PRE temp.5932if ((loadOrStoreChild->getOpCodeValue() == TR::aload || loadOrStoreChild->getOpCodeValue() == TR::aRegLoad) &&5933node->isSpineCheckWithArrayElementChild() && cg->comp()->target().is64Bit() && comp->useCompressedPointers())5934{5935doLoadDecompress = true;5936}59375938while (actualLoadOrStoreChild->getOpCode().isConversion() ||5939( ( actualLoadOrStoreChild->getOpCode().isAdd() || actualLoadOrStoreChild->getOpCode().isSub() ||5940actualLoadOrStoreChild->getOpCode().isLeftShift() || actualLoadOrStoreChild->getOpCode().isRightShift()) &&5941actualLoadOrStoreChild->containsCompressionSequence()))5942{5943// If we find a compression sequence, then reset the topmost conversion node to the child of the compression sequence.5944// i.e. lshl5945// i2l <--- set evaluateConversionNode to this node5946//5947if (! (actualLoadOrStoreChild->getOpCode().isConversion()))5948{5949evaluateConversionNode = actualLoadOrStoreChild->getFirstChild();5950}5951actualLoadOrStoreChild = actualLoadOrStoreChild->getFirstChild();5952}59535954TR::Node * evaluatedNode = NULL;59555956if (actualLoadOrStoreChild->getOpCode().isStore())5957{5958if (actualLoadOrStoreChild->getReferenceCount() > 1)5959{5960TR_ASSERT(actualLoadOrStoreChild->getOpCode().isWrtBar(), "Opcode must be wrtbar");5961loadOrStoreReg = cg->evaluate(actualLoadOrStoreChild->getFirstChild());5962cg->decReferenceCount(actualLoadOrStoreChild->getFirstChild());5963evaluatedNode = actualLoadOrStoreChild->getFirstChild();5964}5965else5966{5967loadOrStoreReg = cg->evaluate(actualLoadOrStoreChild);5968valueReg = actualLoadOrStoreChild->getSecondChild()->getRegister();5969evaluatedNode = actualLoadOrStoreChild;5970}5971}5972else5973{5974evaluatedNode = evaluateConversionNode;5975loadOrStoreReg = cg->evaluate(evaluateConversionNode);5976}59775978if (comp->getOption(TR_TraceCG))5979traceMsg(comp,"Identified actualLoadOrStoreChild: %p and evaluated node: %p\n",actualLoadOrStoreChild, evaluatedNode);5980generateS390LabelInstruction(cg, TR::InstOpCode::label, node, oolReturnLabel);59815982if (loadOrStoreChild != evaluatedNode)5983cg->evaluate(loadOrStoreChild);59845985// ---------------------------------------------5986// OOL Sequence to handle arraylet calculations.5987// ---------------------------------------------5988TR_S390OutOfLineCodeSection *outlinedDiscontigPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(oolStartLabel,oolReturnLabel,cg);5989cg->getS390OutOfLineCodeSectionList().push_front(outlinedDiscontigPath);5990outlinedDiscontigPath->swapInstructionListsWithCompilation();5991TR::Instruction * cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, oolStartLabel);59925993// get the correct liveLocals from the OOL entry branch instruction, so the GC maps can be correct in OOL slow path5994cursor->setLiveLocals(branchToOOL->getLiveLocals());59955996// Generate BNDCHK code.5997if (needsBoundCheck)5998{5999TR::LabelSymbol * boundCheckFailureLabel = generateLabelSymbol(cg);60006001// Check if contiguous arraysize is zero first. If not, throw AIOB6002TR::MemoryReference* contiguousArraySizeMR2 = generateS390MemoryReference(*contiguousArraySizeMR, 0, cg);6003TR::Register *tmpReg = cg->allocateRegister();6004cursor = generateRSInstruction(cg, TR::InstOpCode::ICM, node, tmpReg, (uint32_t) 0xF, contiguousArraySizeMR2, cursor);6005cg->stopUsingRegister(tmpReg);60066007// Throw AIOB if continuousArraySizeMR is zero.6008cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, boundCheckFailureLabel, cursor);6009cursor->setExceptBranchOp();60106011// Don't use CompareAndTrap to save the load of discontiguousArraySize into a register6012cursor = generateRXInstruction(cg, TR::InstOpCode::CL, node, indexReg, discontiguousArraySizeMR, cursor);60136014cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNL, node, boundCheckFailureLabel, cursor);6015cursor->setExceptBranchOp();6016cg->addSnippet(new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, boundCheckFailureLabel, node->getSymbolReference()));6017}60186019// TODO: Generate Arraylet calculation.6020TR::DataType dt = loadOrStoreChild->getDataType();6021int32_t elementSize = 0;6022if (dt == TR::Address)6023{6024elementSize = TR::Compiler->om.sizeofReferenceField();6025}6026else6027{6028elementSize = TR::Symbol::convertTypeToSize(dt);6029}60306031int32_t spinePointerSize = (cg->comp()->target().is64Bit() && !comp->useCompressedPointers()) ? 8 : 4;6032int32_t arrayHeaderSize = TR::Compiler->om.discontiguousArrayHeaderSizeInBytes();6033int32_t arrayletMask = fej9->getArrayletMask(elementSize);60346035// Load the arraylet from the spine.6036int32_t spineShift = fej9->getArraySpineShift(elementSize);6037int32_t spinePtrShift = TR::TreeEvaluator::checkNonNegativePowerOfTwo(spinePointerSize);6038int32_t elementShift = TR::TreeEvaluator::checkNonNegativePowerOfTwo(elementSize);6039TR::Register* tmpReg = cg->allocateRegister();6040if (cg->comp()->target().is64Bit())6041{6042if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_S390_ZEC12))6043{6044cursor = generateRIEInstruction(cg, TR::InstOpCode::RISBGN, node, tmpReg, indexReg,(32+spineShift-spinePtrShift), (128+63-spinePtrShift),(64-spineShift+spinePtrShift),cursor);6045}6046else6047{6048cursor = generateRIEInstruction(cg, TR::InstOpCode::RISBG, node, tmpReg, indexReg,(32+spineShift-spinePtrShift), (128+63-spinePtrShift),(64-spineShift+spinePtrShift),cursor);6049}6050}6051else6052{6053cursor = generateRRInstruction(cg, TR::InstOpCode::LR, node, tmpReg, indexReg, cursor);6054cursor = generateRSInstruction(cg, TR::InstOpCode::SRA, node, tmpReg, tmpReg, spineShift, cursor);6055cursor = generateRSInstruction(cg, TR::InstOpCode::SLL, node, tmpReg, tmpReg, spinePtrShift, cursor);6056}60576058// Load Arraylet pointer from Spine6059// Pointer is compressed on 64-bit CmpRefs6060bool useCompressedPointers = cg->comp()->target().is64Bit() && comp->useCompressedPointers();6061TR::MemoryReference * spineMR = generateS390MemoryReference(baseArrayReg, tmpReg, arrayHeaderSize, cg);6062cursor = generateRXInstruction(cg, (useCompressedPointers)?TR::InstOpCode::LLGF:TR::InstOpCode::getLoadOpCode(), node, tmpReg, spineMR, cursor);60636064// Handle the compress shifting and addition of heap base.6065if (useCompressedPointers)6066{6067// Shift by compressed pointers shift amount if necessary.6068uint32_t cmpRefsShift = TR::Compiler->om.compressedReferenceShift();6069if (cmpRefsShift == 1)6070{6071TR::MemoryReference *cmpRefsShift1MR = generateS390MemoryReference(tmpReg, tmpReg, 0, cg);6072cursor = generateRXInstruction(cg, TR::InstOpCode::LA, node, tmpReg, cmpRefsShift1MR, cursor);6073}6074else if (cmpRefsShift >= 2)6075{6076cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, tmpReg, tmpReg, cmpRefsShift, cursor);6077}6078}60796080// Calculate the offset with the arraylet for the index.6081TR::Register* tmpReg2 = cg->allocateRegister();6082TR::MemoryReference *arrayletMR;6083if (cg->comp()->target().is64Bit())6084{6085if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_S390_ZEC12))6086{6087cursor = generateRIEInstruction(cg, TR::InstOpCode::RISBGN, node, tmpReg2, indexReg,(64-spineShift- elementShift), (128+63-elementShift),(elementShift),cursor);6088}6089else6090{6091cursor = generateRIEInstruction(cg, TR::InstOpCode::RISBG, node, tmpReg2, indexReg,(64-spineShift- elementShift), (128+63-elementShift),(elementShift),cursor);6092}6093}6094else6095{6096generateShiftThenKeepSelected31Bit(node, cg, tmpReg2, indexReg, 32-spineShift - elementShift, 31-elementShift, elementShift);6097}60986099arrayletMR = generateS390MemoryReference(tmpReg, tmpReg2, 0, cg);6100cg->stopUsingRegister(tmpReg);6101cg->stopUsingRegister(tmpReg2);61026103if (!actualLoadOrStoreChild->getOpCode().isStore())6104{6105TR::InstOpCode::Mnemonic op = TR::InstOpCode::bad;61066107TR::MemoryReference *highArrayletMR = NULL;6108TR::Register *highRegister = NULL;6109bool clearHighOrderBitsForUnsignedHalfwordLoads = false;61106111// If we're not loading an array shadow then this must be an effective6112// address computation on the array element (for a write barrier).6113if ((!actualLoadOrStoreChild->getOpCode().hasSymbolReference() ||6114!actualLoadOrStoreChild->getSymbolReference()->getSymbol()->isArrayShadowSymbol()) &&6115!node->isSpineCheckWithArrayElementChild())6116{6117op = TR::InstOpCode::LA;6118}6119else6120{6121switch (dt)6122{6123case TR::Int8: if (loadOrStoreChild->isZeroExtendedAtSource())6124op = (cg->comp()->target().is64Bit() ? TR::InstOpCode::LLGC : TR::InstOpCode::LLC);6125else6126op = (cg->comp()->target().is64Bit() ? TR::InstOpCode::LGB : TR::InstOpCode::LB);6127break;6128case TR::Int16:6129if (loadOrStoreChild->isZeroExtendedAtSource())6130op = (cg->comp()->target().is64Bit() ? TR::InstOpCode::LLGH : TR::InstOpCode::LLH);6131else6132op = (cg->comp()->target().is64Bit() ? TR::InstOpCode::LGH : TR::InstOpCode::LH);6133break;6134case TR::Int32:6135if (loadOrStoreChild->isZeroExtendedAtSource())6136op = (cg->comp()->target().is64Bit() ? TR::InstOpCode::LLGF : TR::InstOpCode::L);6137else6138op = (cg->comp()->target().is64Bit() ? TR::InstOpCode::LGF : TR::InstOpCode::L);6139break;6140case TR::Int64:6141if (cg->comp()->target().is64Bit())6142op = TR::InstOpCode::LG;6143else6144{6145TR_ASSERT(loadOrStoreReg->getRegisterPair(), "expecting a register pair");61466147op = TR::InstOpCode::L;6148highArrayletMR = generateS390MemoryReference(*arrayletMR, 4, cg);6149highRegister = loadOrStoreReg->getHighOrder();6150loadOrStoreReg = loadOrStoreReg->getLowOrder();6151}6152break;61536154case TR::Float: op = TR::InstOpCode::LE; break;6155case TR::Double: op = TR::InstOpCode::LD; break;61566157case TR::Address:6158if (cg->comp()->target().is32Bit())6159op = TR::InstOpCode::L;6160else if (comp->useCompressedPointers())6161op = TR::InstOpCode::LLGF;6162else6163op = TR::InstOpCode::LG;6164break;61656166default:6167TR_ASSERT(0, "unsupported array element load type");6168}6169}6170cursor = generateRXInstruction(cg, op, node, loadOrStoreReg, arrayletMR, cursor);61716172if (doLoadDecompress)6173{6174TR_ASSERT( dt == TR::Address, "Expecting loads with decompression trees to have data type TR::Address");61756176// Shift by compressed pointers shift amount if necessary.6177//6178uint32_t cmpRefsShift = TR::Compiler->om.compressedReferenceShift();6179if (cmpRefsShift == 1)6180{6181TR::MemoryReference *cmpRefsShift1MR = generateS390MemoryReference(loadOrStoreReg, loadOrStoreReg, 0, cg);6182cursor = generateRXInstruction(cg, TR::InstOpCode::LA, node, loadOrStoreReg, cmpRefsShift1MR, cursor);6183}6184else if (cmpRefsShift >= 2)6185{6186cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, loadOrStoreReg, loadOrStoreReg, cmpRefsShift, cursor);6187}6188}61896190if (highArrayletMR)6191{6192cursor = generateRXInstruction(cg, op, node, highRegister, highArrayletMR, cursor);6193}6194// We may need to clear the upper 16-bits of a unsign halfword load.6195if (clearHighOrderBitsForUnsignedHalfwordLoads)6196cursor = generateRIInstruction(cg, TR::InstOpCode::NILH, node, loadOrStoreReg, (int16_t)0x0000, cursor);6197}6198else6199{6200if (dt != TR::Address)6201{6202TR::InstOpCode::Mnemonic op;6203bool needStore = true;62046205switch (dt)6206{6207case TR::Int8: op = TR::InstOpCode::STC; break;6208case TR::Int16: op = TR::InstOpCode::STH; break;6209case TR::Int32: op = TR::InstOpCode::ST; break;6210case TR::Int64:6211if (cg->comp()->target().is64Bit())6212{6213op = TR::InstOpCode::STG;6214}6215else6216{6217TR_ASSERT(valueReg->getRegisterPair(), "value must be a register pair");6218cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, valueReg->getLowOrder(), arrayletMR, cursor);6219cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, valueReg->getHighOrder(), generateS390MemoryReference(*arrayletMR,4,cg), cursor);6220needStore = false;6221}6222break;62236224case TR::Float: op = TR::InstOpCode::STE; break;6225case TR::Double: op = TR::InstOpCode::STD; break;62266227default:6228TR_ASSERT(0, "unsupported array element store type");6229op = TR::InstOpCode::bad;6230}62316232if (needStore)6233cursor = generateRXInstruction(cg, op, node, valueReg, arrayletMR, cursor);6234}6235else6236{6237TR_ASSERT(0, "OOL reference stores not supported yet");6238}6239}624062416242cursor = generateS390BranchInstruction(cg,TR::InstOpCode::BRC,TR::InstOpCode::COND_BRC,node,oolReturnLabel, cursor);6243if (debugObj)6244debugObj->addInstructionComment(cursor, "End of OOL BNDCHKwithSpineCHK sequence");62456246outlinedDiscontigPath->swapInstructionListsWithCompilation();62476248cg->decReferenceCount(loadOrStoreChild);6249cg->decReferenceCount(baseArrayChild);6250cg->decReferenceCount(indexChild);6251if (arrayLengthChild)6252cg->recursivelyDecReferenceCount(arrayLengthChild);62536254return NULL;6255}62566257static void6258VMarrayStoreCHKEvaluator(6259TR::Node * node,6260J9::Z::CHelperLinkage *helperLink,6261TR::Node *callNode,6262TR::Register * srcReg,6263TR::Register * owningObjectReg,6264TR::Register * t1Reg,6265TR::Register * t2Reg,6266TR::Register * litPoolBaseReg,6267TR::Register * owningObjectRegVal,6268TR::Register * srcRegVal,6269TR::LabelSymbol * wbLabel,6270TR::RegisterDependencyConditions * conditions,6271TR::CodeGenerator * cg)6272{6273TR::LabelSymbol * helperCallLabel = generateLabelSymbol(cg);6274TR::LabelSymbol * startOOLLabel = generateLabelSymbol(cg);6275TR::LabelSymbol * exitOOLLabel = generateLabelSymbol(cg);6276TR::LabelSymbol * exitPointLabel = wbLabel;6277TR::Compilation *comp = cg->comp();6278TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());62796280TR_S390OutOfLineCodeSection *arrayStoreCHKOOL;6281TR_Debug * debugObj = cg->getDebug();62826283TR::InstOpCode::Mnemonic loadOp;6284TR::Instruction * cursor;6285TR::Instruction * gcPoint;6286J9::Z::PrivateLinkage * linkage = static_cast<J9::Z::PrivateLinkage *>(cg->getLinkage());6287int bytesOffset;62886289TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, owningObjectRegVal, generateS390MemoryReference(owningObjectReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), cg), NULL);6290TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, srcRegVal, generateS390MemoryReference( srcReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), cg), NULL);62916292// may need to convert the class offset from t1Reg into a J9Class pointer6293cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, t1Reg, generateS390MemoryReference(owningObjectRegVal, (int32_t) offsetof(J9ArrayClass, componentType), cg));62946295// check if obj.class(in t1Reg) == array.componentClass in t2Reg6296if (TR::Compiler->om.compressObjectReferences())6297cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CR, node, t1Reg, srcRegVal, TR::InstOpCode::COND_BER, wbLabel, false, false);6298else6299cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpLogicalRegOpCode(), node, t1Reg, srcRegVal, TR::InstOpCode::COND_BE, wbLabel, false, false);63006301if (debugObj)6302debugObj->addInstructionComment(cursor, "Check if src.type == array.type");63036304intptr_t objectClass = (intptr_t) fej9->getSystemClassFromClassName("java/lang/Object", 16, true);6305/*6306* objectClass is used for Object arrays check optimization: when we are storing to Object arrays we can skip all other array store checks6307* However, TR_J9SharedCacheVM::getSystemClassFromClassName can return 0 when it's impossible to relocate j9class later for AOT loads6308* in that case we don't want to generate the Object arrays check6309*/6310bool doObjectArrayCheck = objectClass != 0;63116312if (doObjectArrayCheck && (cg->wantToPatchClassPointer((TR_OpaqueClassBlock*)objectClass, node) || cg->needClassAndMethodPointerRelocations()))6313{6314if (cg->isLiteralPoolOnDemandOn())6315{6316TR::S390ConstantDataSnippet * targetsnippet;6317if (cg->comp()->target().is64Bit())6318{6319targetsnippet = cg->findOrCreate8ByteConstant(node, (int64_t)objectClass);6320cursor = (TR::S390RILInstruction *) generateRILInstruction(cg, TR::InstOpCode::CLGRL, node, t1Reg, targetsnippet, 0);6321}6322else6323{6324targetsnippet = cg->findOrCreate4ByteConstant(node, (int32_t)objectClass);6325cursor = (TR::S390RILInstruction *) generateRILInstruction(cg, TR::InstOpCode::CLRL, node, t1Reg, targetsnippet, 0);6326}63276328if(comp->getOption(TR_EnableHCR))6329comp->getSnippetsToBePatchedOnClassRedefinition()->push_front(targetsnippet);6330if (cg->needClassAndMethodPointerRelocations())6331{6332targetsnippet->setReloType(TR_ClassPointer);6333AOTcgDiag4(comp, "generateRegLitRefInstruction constantDataSnippet=%x symbolReference=%x symbol=%x reloType=%x\n",6334targetsnippet, targetsnippet->getSymbolReference(), targetsnippet->getSymbolReference()->getSymbol(), TR_ClassPointer);6335}6336}6337else6338{6339if (cg->needClassAndMethodPointerRelocations())6340{6341generateRegLitRefInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, t2Reg,(uintptr_t) objectClass, TR_ClassPointer, conditions, NULL, NULL);6342}6343else6344{6345genLoadAddressConstantInSnippet(cg, node, (intptr_t)objectClass, t2Reg, cursor, conditions, litPoolBaseReg, true);6346}63476348if (TR::Compiler->om.compressObjectReferences())6349generateRRInstruction(cg, TR::InstOpCode::CR, node, t1Reg, t2Reg);6350else6351generateRRInstruction(cg, TR::InstOpCode::getCmpLogicalRegOpCode(), node, t1Reg, t2Reg);6352}6353}6354else if (doObjectArrayCheck)6355{6356// make sure that t1Reg contains the class offset and not the J9Class pointer6357if (cg->comp()->target().is64Bit())6358generateS390ImmOp(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, t1Reg, t1Reg, (int64_t) objectClass, conditions, litPoolBaseReg);6359else6360generateS390ImmOp(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, t1Reg, t1Reg, (int32_t) objectClass, conditions, litPoolBaseReg);6361}63626363// Bringing back tests from outlined keeping only helper call in outlined section6364// TODO Attaching helper call predependency to BRASL instruction and combine ICF conditions with post dependency conditions of6365// helper call should fix the issue of unnecessary spillings in ICF. Currently bringing the tests back to main line here but6366// check performance of both case.6367cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, wbLabel);6368if (debugObj)6369debugObj->addInstructionComment(cursor, "Check if array.type is type object, if yes jump to wbLabel");63706371generateRXInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, t1Reg,6372generateS390MemoryReference(srcRegVal, offsetof(J9Class, castClassCache), cg));63736374cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, wbLabel);6375if (debugObj)6376debugObj->addInstructionComment(cursor, "Check if src.class(in t1Reg).castClassCache == array.componentClass");63776378// Check to see if array-type is a super-class of the src object6379if (cg->comp()->target().is64Bit())6380{6381loadOp = TR::InstOpCode::LLGH;6382bytesOffset = 6;6383}6384else6385{6386loadOp = TR::InstOpCode::LLH;6387bytesOffset = 2;6388}63896390// Get array element depth6391cursor = generateRXInstruction(cg, loadOp, node, owningObjectRegVal,6392generateS390MemoryReference(t1Reg, offsetof(J9Class, classDepthAndFlags) + bytesOffset, cg));63936394// Get src depth6395cursor = generateRXInstruction(cg, loadOp, node, t2Reg,6396generateS390MemoryReference(srcRegVal, offsetof(J9Class, classDepthAndFlags) + bytesOffset, cg));63976398TR_ASSERT(sizeof(((J9Class*)0)->classDepthAndFlags) == sizeof(uintptr_t),6399"VMarrayStoreCHKEvaluator::J9Class->classDepthAndFlags is wrong size\n");64006401// Check super class values6402static_assert(J9AccClassDepthMask == 0xffff, "VMarrayStoreCHKEvaluator::J9AccClassDepthMask should have be 16 bit of ones");64036404// Compare depths and makes sure depth(src) >= depth(array-type)6405generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, owningObjectRegVal, t2Reg, TR::InstOpCode::COND_BH, helperCallLabel, false, false);6406if (debugObj)6407debugObj->addInstructionComment(cursor, "Failure if depth(src) < depth(array-type)");64086409if (cg->comp()->target().is64Bit())6410{6411generateRSInstruction(cg, TR::InstOpCode::SLLG, node, owningObjectRegVal, owningObjectRegVal, 3);6412}6413else6414{6415generateRSInstruction(cg, TR::InstOpCode::SLL, node, owningObjectRegVal, 2);6416}64176418generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, t2Reg,6419generateS390MemoryReference(srcRegVal, offsetof(J9Class, superclasses), cg));64206421generateRXInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, t1Reg,6422generateS390MemoryReference(t2Reg, owningObjectRegVal, 0, cg));64236424if (debugObj)6425debugObj->addInstructionComment(cursor, "Check if src.type is subclass");6426cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRNE, node, helperCallLabel);6427// FAIL6428arrayStoreCHKOOL = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(helperCallLabel,wbLabel,cg);6429cg->getS390OutOfLineCodeSectionList().push_front(arrayStoreCHKOOL);6430arrayStoreCHKOOL->swapInstructionListsWithCompilation();6431generateS390LabelInstruction(cg, TR::InstOpCode::label, node, helperCallLabel);6432TR::Register *dummyResReg = helperLink->buildDirectDispatch(callNode);6433if (dummyResReg)6434cg->stopUsingRegister(dummyResReg);6435generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, wbLabel);6436arrayStoreCHKOOL->swapInstructionListsWithCompilation();6437}64386439///////////////////////////////////////////////////////////////////////////////////////6440// ArrayStoreCHKEvaluator - Array store check. child 1 is object, 2 is array.6441// Symbolref indicates failure action/destination6442///////////////////////////////////////////////////////////////////////////////////////6443TR::Register *6444J9::Z::TreeEvaluator::ArrayStoreCHKEvaluator(TR::Node * node, TR::CodeGenerator * cg)6445{6446// Note: we take advantages of the register conventions of the helpers by limiting register usages on6447// the fast-path (most likely 4 registers; at most, 6 registers)64486449TR::Compilation * comp = cg->comp();6450TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());6451TR::Node * firstChild = node->getFirstChild();6452auto gcMode = TR::Compiler->om.writeBarrierType();6453// As arguments to ArrayStoreCHKEvaluator helper function is children of first child,6454// We need to create a dummy call node for helper call with children containing arguments to helper call.6455bool doWrtBar = (gcMode == gc_modron_wrtbar_oldcheck ||6456gcMode == gc_modron_wrtbar_cardmark_and_oldcheck ||6457gcMode == gc_modron_wrtbar_always);64586459bool doCrdMrk = ((gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental) && !firstChild->isNonHeapObjectWrtBar());64606461TR::Node * litPoolBaseChild=NULL;6462TR::Node * sourceChild = firstChild->getSecondChild();6463TR::Node * classChild = firstChild->getChild(2);64646465bool nopASC = false;6466if (comp->performVirtualGuardNOPing() && node->getArrayStoreClassInNode() &&6467!fej9->classHasBeenExtended(node->getArrayStoreClassInNode()))6468nopASC = true;64696470bool usingCompressedPointers = false;6471if (comp->useCompressedPointers() && firstChild->getOpCode().isIndirect())6472{6473usingCompressedPointers = true;6474while (sourceChild->getNumChildren() > 06475&& sourceChild->getOpCodeValue() != TR::a2l)6476{6477sourceChild = sourceChild->getFirstChild();6478}6479if (sourceChild->getOpCodeValue() == TR::a2l)6480{6481sourceChild = sourceChild->getFirstChild();6482}6483// artificially bump up the refCount on the value so6484// that different registers are allocated for the actual6485// and compressed values6486//6487sourceChild->incReferenceCount();6488}6489TR::Node * memRefChild = firstChild->getFirstChild();64906491TR::Register * srcReg, * classReg, * txReg, * tyReg, * baseReg, * indexReg, *litPoolBaseReg=NULL,*memRefReg;6492TR::MemoryReference * mr1, * mr2;6493TR::LabelSymbol * wbLabel, * cFlowRegionEnd, * simpleStoreLabel, * cFlowRegionStart;6494TR::RegisterDependencyConditions * conditions;6495J9::Z::PrivateLinkage * linkage = static_cast<J9::Z::PrivateLinkage *>(cg->getLinkage());6496TR::Register * tempReg = NULL;6497TR::Instruction *cursor;64986499cFlowRegionStart = generateLabelSymbol(cg);6500wbLabel = generateLabelSymbol(cg);6501cFlowRegionEnd = generateLabelSymbol(cg);6502simpleStoreLabel = generateLabelSymbol(cg);65036504txReg = cg->allocateRegister();6505tyReg = cg->allocateRegister();65066507TR::Register * owningObjectRegVal = cg->allocateRegister();6508TR::Register * srcRegVal = cg->allocateRegister();65096510// dst reg is read-only when we don't do wrtbar or crdmark6511// if destination node is the same as source node we also6512// need to create a copy because destination & source6513// are 1st and 2nd arguments to the call and as such6514// they need to be in 2 different registers6515if (doWrtBar || doCrdMrk || (classChild==sourceChild))6516{6517classReg = cg->gprClobberEvaluate(classChild);6518// evaluate using load and test6519if (sourceChild->getOpCode().isLoadVar() && sourceChild->getRegister()==NULL && !sourceChild->isNonNull())6520{6521srcReg = cg->allocateCollectedReferenceRegister();65226523generateRXInstruction(cg, TR::InstOpCode::getLoadTestOpCode(), sourceChild, srcReg, TR::MemoryReference::create(cg, sourceChild));65246525sourceChild->setRegister(srcReg);6526}6527else6528{6529srcReg = cg->gprClobberEvaluate(sourceChild);6530}6531}6532else6533{6534classReg = cg->evaluate(classChild);6535srcReg = cg->evaluate(sourceChild);6536}6537TR::Node *callNode = TR::Node::createWithSymRef(node, TR::call, 2, node->getSymbolReference());6538callNode->setChild(0, sourceChild);6539callNode->setChild(1, classChild);6540mr1 = TR::MemoryReference::create(cg, firstChild);65416542TR::Register *compressedReg = srcReg;6543if (usingCompressedPointers)6544compressedReg = cg->evaluate(firstChild->getSecondChild());65456546// We need deps to setup args for arrayStoreCHK helper and/or wrtBAR helper call.6547// We need 2 more regs for inline version of arrayStoreCHK (txReg & tyReg). We use RA/EP for these6548// We then need two extra regs for memref for the actual store.6549// A seventh, eighth and ninth post dep may be needed to manufacture imm values6550// used by the inlined version of arrayStoreCHK6551// The tenth post dep may be needed to generateDirectCall if it creates a RegLitRefInstruction.6552conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 11, cg);6553conditions->addPostCondition(classReg, linkage->getIntegerArgumentRegister(0));6554conditions->addPostCondition(srcReg, linkage->getIntegerArgumentRegister(1));6555if (usingCompressedPointers)6556{6557conditions->addPostConditionIfNotAlreadyInserted(compressedReg, TR::RealRegister::AssignAny);6558}6559conditions->addPostCondition(txReg, linkage->getReturnAddressRegister());6560conditions->addPostCondition(tyReg, linkage->getEntryPointRegister());6561conditions->addPostCondition(srcRegVal, TR::RealRegister::AssignAny);6562conditions->addPostCondition(owningObjectRegVal, TR::RealRegister::AssignAny);65636564TR::Instruction *current = cg->getAppendInstruction();6565TR_ASSERT( current != NULL, "Could not get current instruction");65666567if (node->getNumChildren()==2)6568{6569litPoolBaseChild=node->getSecondChild();6570TR_ASSERT((litPoolBaseChild->getOpCodeValue()==TR::aload) || (litPoolBaseChild->getOpCodeValue()==TR::aRegLoad),6571"Literal pool base child expected\n");6572litPoolBaseReg=cg->evaluate(litPoolBaseChild);6573conditions->addPostCondition(litPoolBaseReg, TR::RealRegister::AssignAny);6574}65756576if (!sourceChild->isNonNull())6577{6578// Note the use of 64-bit compare for compressedRefs and use of the decompressed `srcReg` register6579// Compare object with NULL. If NULL, branch around ASC, WrtBar and CrdMrk as they are not required6580generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, srcReg, 0, TR::InstOpCode::COND_BE, (doWrtBar || doCrdMrk)?simpleStoreLabel:wbLabel, false, true);6581}65826583J9::Z::CHelperLinkage *helperLink = static_cast<J9::Z::CHelperLinkage*>(cg->getLinkage(TR_CHelper));6584if (nopASC)6585{6586// Speculatively NOP the array store check if VP is able to prove that the ASC6587// would always succeed given the current state of the class hierarchy.6588//6589TR::LabelSymbol * oolASCLabel = generateLabelSymbol(cg);6590TR_VirtualGuard *virtualGuard = TR_VirtualGuard::createArrayStoreCheckGuard(comp, node, node->getArrayStoreClassInNode());6591TR::Instruction *vgnopInstr = generateVirtualGuardNOPInstruction(cg, node, virtualGuard->addNOPSite(), NULL, oolASCLabel);65926593// nopASC assumes OOL is enabled6594TR_S390OutOfLineCodeSection *outlinedSlowPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(oolASCLabel, wbLabel, cg);6595cg->getS390OutOfLineCodeSectionList().push_front(outlinedSlowPath);6596outlinedSlowPath->swapInstructionListsWithCompilation();65976598generateS390LabelInstruction(cg, TR::InstOpCode::label, node, oolASCLabel);6599TR::Register *dummyResReg = helperLink->buildDirectDispatch(callNode);6600if (dummyResReg)6601cg->stopUsingRegister(dummyResReg);66026603generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, wbLabel);6604outlinedSlowPath->swapInstructionListsWithCompilation();6605}6606else6607VMarrayStoreCHKEvaluator(node, helperLink, callNode, srcReg, classReg, txReg, tyReg, litPoolBaseReg, owningObjectRegVal, srcRegVal, wbLabel, conditions, cg);66086609generateS390LabelInstruction(cg, TR::InstOpCode::label, node, wbLabel);66106611if (mr1->getBaseRegister())6612{6613conditions->addPostConditionIfNotAlreadyInserted(mr1->getBaseRegister(), TR::RealRegister::AssignAny);6614}6615if (mr1->getIndexRegister())6616{6617conditions->addPostConditionIfNotAlreadyInserted(mr1->getIndexRegister(), TR::RealRegister::AssignAny);6618}66196620if (usingCompressedPointers)6621generateRXInstruction(cg, TR::InstOpCode::ST, node, compressedReg, mr1);6622else6623generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, srcReg, mr1);66246625if (doWrtBar)6626{6627TR::SymbolReference *wbRef ;6628if (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_oldcheck)6629wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreGenerationalSymbolRef(comp->getMethodSymbol());6630else6631wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreSymbolRef(comp->getMethodSymbol());66326633// Cardmarking is not inlined for gencon. Consider doing so when perf issue arises.6634VMnonNullSrcWrtBarCardCheckEvaluator(firstChild, classReg, srcReg, tyReg, txReg, cFlowRegionEnd, wbRef, conditions, cg, false);6635}6636else if (doCrdMrk)6637{6638VMCardCheckEvaluator(firstChild, classReg, NULL, conditions, cg, true, cFlowRegionEnd);6639}66406641// Store for case where we have a NULL ptr detected at runtime and6642// branches around the wrtbar6643//6644// For the non-NULL case we chose to simply exec the ST twice as this is6645// cheaper than branching around the a single ST inst.6646//6647if (!sourceChild->isNonNull() && (doWrtBar || doCrdMrk))6648{6649// As we could hit a gc when doing the gencon wrtbar, we have to not6650// re-do the ST. We must branch around the second store.6651//6652if (doWrtBar)6653{6654generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);6655}66566657generateS390LabelInstruction(cg, TR::InstOpCode::label, node, simpleStoreLabel);66586659mr2 = generateS390MemoryReference(*mr1, 0, cg);6660if (usingCompressedPointers)6661generateRXInstruction(cg, TR::InstOpCode::ST, node, compressedReg, mr2);6662else6663generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, srcReg, mr2);6664}66656666generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, conditions);6667cFlowRegionEnd->setEndInternalControlFlow();66686669if (comp->useCompressedPointers() && firstChild->getOpCode().isIndirect())6670firstChild->setStoreAlreadyEvaluated(true);66716672cg->decReferenceCount(sourceChild);6673cg->decReferenceCount(classChild);6674if (litPoolBaseChild!=NULL) cg->decReferenceCount(litPoolBaseChild);6675cg->decReferenceCount(firstChild);6676if (usingCompressedPointers)6677{6678cg->decReferenceCount(firstChild->getSecondChild());6679cg->stopUsingRegister(compressedReg);6680}6681mr1->stopUsingMemRefRegister(cg);6682cg->stopUsingRegister(txReg);6683cg->stopUsingRegister(tyReg);6684cg->stopUsingRegister(classReg);6685cg->stopUsingRegister(srcReg);6686cg->stopUsingRegister(owningObjectRegVal);6687cg->stopUsingRegister(srcRegVal);66886689if (tempReg)6690{6691cg->stopUsingRegister(tempReg);6692}66936694// determine where internal control flow begins by looking for the first branch6695// instruction after where the label instruction would have been inserted6696TR::Instruction *next = current->getNext();6697while(next != NULL && !next->isBranchOp())6698next = next->getNext();6699TR_ASSERT( next != NULL && next->getPrev() != NULL, "Could not find branch instruction where internal control flow begins");6700generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart, next->getPrev());6701cFlowRegionStart->setStartInternalControlFlow();67026703return NULL;6704}67056706///////////////////////////////////////////////////////////////////////////////////////6707// ArrayCHKEvaluator - Array compatibility check. child 1 is object1, 2 is object2.6708// Symbolref indicates failure action/destination6709///////////////////////////////////////////////////////////////////////////////////////6710TR::Register *6711J9::Z::TreeEvaluator::ArrayCHKEvaluator(TR::Node * node, TR::CodeGenerator * cg)6712{6713return TR::TreeEvaluator::VMarrayCheckEvaluator(node, cg);6714}67156716TR::Register *6717J9::Z::TreeEvaluator::conditionalHelperEvaluator(TR::Node * node, TR::CodeGenerator * cg)6718{6719// used by methodEnterhook, and methodExitHook6720// Decrement the reference count on the constant placeholder parameter to6721// the MethodEnterHook call. An evaluation isn't necessary because the6722// constant value isn't used here.6723//6724if (node->getOpCodeValue() == TR::MethodEnterHook)6725{6726if (node->getSecondChild()->getOpCode().isCall() && node->getSecondChild()->getNumChildren() > 1)6727{6728cg->decReferenceCount(node->getSecondChild()->getFirstChild());6729}6730}67316732// The child contains an inline test.6733//6734TR::Node * testNode = node->getFirstChild();6735TR::Node * firstChild = testNode->getFirstChild();6736TR::Node * secondChild = testNode->getSecondChild();6737TR::Register * src1Reg = cg->evaluate(firstChild);6738if (secondChild->getOpCode().isLoadConst())6739// &&6740// secondChild->getRegister() == NULL)6741{6742int32_t value = secondChild->getInt();6743TR::Node * firstChild = testNode->getFirstChild();67446745if (value >= MIN_IMMEDIATE_VAL && value <= MAX_IMMEDIATE_VAL)6746{6747generateRIInstruction(cg, TR::InstOpCode::CHI, node, src1Reg, value);6748}6749else6750{6751TR::Register * tempReg = cg->evaluate(secondChild);6752generateRRInstruction(cg, TR::InstOpCode::CR, node, src1Reg, tempReg);6753}6754}6755else6756{6757TR::Register * src2Reg = cg->evaluate(secondChild);6758generateRRInstruction(cg, TR::InstOpCode::CR, node, src1Reg, src2Reg);6759}67606761TR::LabelSymbol * cFlowRegionStart = generateLabelSymbol(cg);6762TR::LabelSymbol * snippetLabel = generateLabelSymbol(cg);6763TR::Instruction * gcPoint;67646765TR::Register * tempReg1 = cg->allocateRegister();6766TR::Register * tempReg2 = cg->allocateRegister();6767TR::RegisterDependencyConditions * dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 2, cg);6768dependencies->addPostCondition(tempReg1, cg->getEntryPointRegister());6769dependencies->addPostCondition(tempReg2, cg->getReturnAddressRegister());6770snippetLabel->setEndInternalControlFlow();67716772generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);6773cFlowRegionStart->setStartInternalControlFlow();6774gcPoint = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, testNode->getOpCodeValue() == TR::icmpeq ? TR::InstOpCode::COND_BE : TR::InstOpCode::COND_BNE, node, snippetLabel);67756776TR::LabelSymbol * reStartLabel = generateLabelSymbol(cg);6777TR::Snippet * snippet = new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference(), reStartLabel);6778cg->addSnippet(snippet);6779generateS390LabelInstruction(cg, TR::InstOpCode::label, node, reStartLabel, dependencies);67806781gcPoint->setNeedsGCMap(0x0000FFFF);67826783cg->decReferenceCount(firstChild);6784cg->decReferenceCount(secondChild);6785cg->decReferenceCount(testNode);6786cg->stopUsingRegister(tempReg1);6787cg->stopUsingRegister(tempReg2);67886789return NULL;6790}67916792/**6793* Null check a pointer. child 1 is indirect reference. Symbolref6794* indicates failure action/destination6795*/6796TR::Register *6797J9::Z::TreeEvaluator::NULLCHKEvaluator(TR::Node * node, TR::CodeGenerator * cg)6798{6799return TR::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(node, false, cg);6800}68016802/**6803* resolveAndNULLCHKEvaluator - Resolve check a static, field or method and Null check6804* the underlying pointer. child 1 is reference to be resolved. Symbolref indicates6805* failure action/destination6806*/6807TR::Register *6808J9::Z::TreeEvaluator::resolveAndNULLCHKEvaluator(TR::Node * node, TR::CodeGenerator * cg)6809{6810return TR::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(node, true, cg);6811}68126813/**6814* This is a helper function used to generate the snippet6815*/6816TR::Register *6817J9::Z::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(TR::Node * node, bool needsResolve, TR::CodeGenerator * cg)6818{6819// NOTE:6820// If no code is generated for the null check, just evaluate the6821// child and decrement its use count UNLESS the child is a pass-through node6822// in which case some kind of explicit test or indirect load must be generated6823// to force the null check at this point.68246825TR::Node * firstChild = node->getFirstChild();6826TR::ILOpCode & opCode = firstChild->getOpCode();6827TR::Compilation *comp = cg->comp();6828TR::Node * reference = NULL;6829TR::InstOpCode::S390BranchCondition branchOpCond = TR::InstOpCode::COND_BZ;68306831bool hasCompressedPointers = false;68326833TR::Node * n = firstChild;68346835// NULLCHK has a special case with compressed pointers.6836// In the scenario where the first child is TR::l2a, the6837// node to be null checked is not the iiload, but its child.6838// i.e. aload, aRegLoad, etc.6839if (comp->useCompressedPointers()6840&& firstChild->getOpCodeValue() == TR::l2a)6841{6842hasCompressedPointers = true;6843TR::ILOpCodes loadOp = comp->il.opCodeForIndirectLoad(TR::Int32);6844TR::ILOpCodes rdbarOp = comp->il.opCodeForIndirectReadBarrier(TR::Int32);6845while (n->getOpCodeValue() != loadOp && n->getOpCodeValue() != rdbarOp)6846n = n->getFirstChild();6847reference = n->getFirstChild();6848}6849else6850{6851reference = node->getNullCheckReference();6852}68536854// Skip the NULLCHK for TR::loadaddr nodes.6855//6856if (cg->getSupportsImplicitNullChecks()6857&& reference->getOpCodeValue() == TR::loadaddr)6858{6859cg->evaluate(firstChild);6860cg->decReferenceCount(firstChild);6861return NULL;6862}68636864bool needExplicitCheck = true;6865bool needLateEvaluation = true;68666867// Add the explicit check after this instruction6868//6869TR::Instruction *appendTo = NULL;68706871// determine if an explicit check is needed6872if (cg->getSupportsImplicitNullChecks()6873&& !firstChild->isUnneededIALoad())6874{6875if (opCode.isLoadVar()6876|| (cg->comp()->target().is64Bit() && opCode.getOpCodeValue()==TR::l2i)6877|| (hasCompressedPointers && firstChild->getFirstChild()->getOpCode().getOpCodeValue() == TR::i2l))6878{6879TR::SymbolReference *symRef = NULL;68806881if (opCode.getOpCodeValue()==TR::l2i)6882symRef = n->getFirstChild()->getSymbolReference();6883else6884symRef = n->getSymbolReference();68856886// We prefer to generate an explicit NULLCHK vs an implicit one6887// to prevent potential costs of a cache miss on an unnecessary load.6888if (n->getReferenceCount() == 16889&& !n->getSymbolReference()->isUnresolved())6890{6891// If the child is only used here, we don't need to evaluate it6892// since all we need is the grandchild which will be evaluated by6893// the generation of the explicit check below.6894needLateEvaluation = false;68956896// at this point, n is the raw iiload (created by lowerTrees) and6897// reference is the aload of the object. node->getFirstChild is the6898// l2a sequence; as a result, n's refCount will always be 16899// and node->getFirstChild's refCount will be at least 2 (one under the nullchk6900// and the other under the translate treetop)6901//6902if (hasCompressedPointers6903&& node->getFirstChild()->getReferenceCount() > 2)6904needLateEvaluation = true;6905}69066907// Check if offset from a NULL reference will fall into the inaccessible bytes,6908// resulting in an implicit trap being raised.6909else if (symRef6910&& ((symRef->getSymbol()->getOffset() + symRef->getOffset()) < cg->getNumberBytesReadInaccessible()))6911{6912needExplicitCheck = false;69136914// If the child is an arraylength which has been reduced to an iiload,6915// and is only going to be used immediately in a BNDCHK, combine the checks.6916//6917TR::TreeTop *nextTreeTop = cg->getCurrentEvaluationTreeTop()->getNextTreeTop();6918if (n->getReferenceCount() == 2 && nextTreeTop)6919{6920TR::Node *nextTopNode = nextTreeTop->getNode();69216922if (nextTopNode)6923{6924if (nextTopNode->getOpCode().isBndCheck())6925{6926if ((nextTopNode->getOpCode().isSpineCheck() && (nextTopNode->getChild(2) == n))6927|| (!nextTopNode->getOpCode().isSpineCheck() && (nextTopNode->getFirstChild() == n)))6928{6929needLateEvaluation = false;6930nextTopNode->setHasFoldedImplicitNULLCHK(true);6931traceMsg(comp, "\nMerging NULLCHK [%p] and BNDCHK [%p] of load child [%p]", node, nextTopNode, n);6932}6933}6934else if (nextTopNode->getOpCode().isIf()6935&& nextTopNode->isNonoverriddenGuard()6936&& nextTopNode->getFirstChild() == firstChild)6937{6938needLateEvaluation = false;6939needExplicitCheck = true;6940reference->incReferenceCount(); // will be decremented again later6941}6942}6943}6944}6945}6946else if (opCode.isStore())6947{6948TR::SymbolReference *symRef = n->getSymbolReference();6949if (n->getOpCode().hasSymbolReference()6950&& (symRef->getSymbol()->getOffset() + symRef->getOffset() < cg->getNumberBytesWriteInaccessible()))6951{6952needExplicitCheck = false;6953}6954}6955else if (opCode.isCall()6956&& opCode.isIndirect()6957&& (cg->getNumberBytesReadInaccessible() > TR::Compiler->om.offsetOfObjectVftField()))6958{6959needExplicitCheck = false;6960}6961else if (opCode.getOpCodeValue() == TR::iushr6962&& (cg->getNumberBytesReadInaccessible() > cg->fe()->getOffsetOfContiguousArraySizeField()))6963{6964// If the child is an arraylength which has been reduced to an iushr,6965// we must evaluate it here so that the implicit exception will occur6966// at the right point in the program.6967//6968// This can occur when the array length is represented in bytes, not elements.6969// The optimizer must intervene for this to happen.6970//6971cg->evaluate(n->getFirstChild());6972needExplicitCheck = false;6973}6974else if (opCode.getOpCodeValue() == TR::monent6975|| opCode.getOpCodeValue() == TR::monexit)6976{6977// The child may generate inline code that provides an implicit null check6978// but we won't know until the child is evaluated.6979//6980reference->incReferenceCount(); // will be decremented again later6981needLateEvaluation = false;6982cg->evaluate(reference);6983appendTo = cg->getAppendInstruction();6984cg->evaluate(firstChild);69856986if (cg->getImplicitExceptionPoint()6987&& (cg->getNumberBytesReadInaccessible() > cg->fe()->getOffsetOfContiguousArraySizeField()))6988{6989needExplicitCheck = false;6990cg->decReferenceCount(reference);6991}6992}6993}69946995// Generate the code for the null check6996//6997if(needExplicitCheck)6998{6999TR::Register * targetRegister = NULL;7000if (cg->getHasResumableTrapHandler())7001{7002// Use Load-And-Trap on zHelix if available.7003// This loads the field and performance a NULLCHK on the field value.7004// i.e. o.f == NULL7005if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_S390_ZEC12)7006&& reference->getOpCode().isLoadVar()7007&& (reference->getOpCodeValue() != TR::ardbari)7008&& reference->getRegister() == NULL)7009{7010targetRegister = cg->allocateCollectedReferenceRegister();7011appendTo = generateRXInstruction(cg, TR::InstOpCode::getLoadAndTrapOpCode(), node, targetRegister, TR::MemoryReference::create(cg, reference), appendTo);7012reference->setRegister(targetRegister);7013}7014else if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_S390_ZEC12)7015&& reference->getRegister() == NULL7016&& comp->useCompressedPointers()7017&& reference->getOpCodeValue() == TR::l2a7018&& reference->getFirstChild()->getOpCodeValue() == TR::iu2l7019&& reference->getFirstChild()->getFirstChild()->getOpCode().isLoadVar()7020&& TR::Compiler->om.compressedReferenceShiftOffset() == 0)7021{7022targetRegister = cg->evaluate(reference);7023appendTo = cg->getAppendInstruction();7024if (appendTo->getOpCodeValue() == TR::InstOpCode::LLGF)7025{7026appendTo->setOpCodeValue(TR::InstOpCode::LLGFAT);7027appendTo->setNode(node);7028}7029else7030{7031appendTo = generateRIEInstruction(cg, TR::InstOpCode::getCmpImmTrapOpCode(), node, targetRegister, (int16_t)0, TR::InstOpCode::COND_BE, appendTo);7032}7033}7034else7035{7036targetRegister = reference->getRegister();70377038if (targetRegister == NULL)7039targetRegister = cg->evaluate(reference);70407041appendTo = generateRIEInstruction(cg, TR::InstOpCode::getCmpImmTrapOpCode(), node, targetRegister, (int16_t)0, TR::InstOpCode::COND_BE, appendTo);7042}70437044TR::Instruction* cursor = appendTo;7045cursor->setThrowsImplicitException();7046cursor->setExceptBranchOp();7047cg->setCanExceptByTrap(true);7048cursor->setNeedsGCMap(0x0000FFFF);7049if (cg->comp()->target().isZOS())7050killRegisterIfNotLocked(cg, TR::RealRegister::GPR4, cursor);7051}7052else7053{7054// NULLCHK snippet label.7055TR::LabelSymbol * snippetLabel = generateLabelSymbol(cg);7056TR::SymbolReference *symRef = node->getSymbolReference();7057cg->addSnippet(new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, snippetLabel, symRef));70587059if (!firstChild->getOpCode().isCall()7060&& reference->getOpCode().isLoadVar()7061&& (reference->getOpCodeValue() != TR::ardbari) // ardbari needs to be evaluated before being NULLCHK'ed because of its side effect.7062&& reference->getOpCode().hasSymbolReference()7063&& reference->getRegister() == NULL)7064{7065bool isInternalPointer = reference->getSymbolReference()->getSymbol()->isInternalPointer();7066if ((reference->getOpCode().isLoadIndirect() || reference->getOpCodeValue() == TR::aload)7067&& !isInternalPointer)7068{7069targetRegister = cg->allocateCollectedReferenceRegister();7070}7071else7072{7073targetRegister = cg->allocateRegister();7074if (isInternalPointer)7075{7076targetRegister->setPinningArrayPointer(reference->getSymbolReference()->getSymbol()->castToInternalPointerAutoSymbol()->getPinningArrayPointer());7077targetRegister->setContainsInternalPointer();7078}7079}70807081reference->setRegister(targetRegister);7082TR::MemoryReference * tempMR = TR::MemoryReference::create(cg, reference);7083appendTo = generateRXInstruction(cg, TR::InstOpCode::getLoadTestOpCode(), reference, targetRegister, tempMR, appendTo);7084tempMR->stopUsingMemRefRegister(cg);70857086appendTo = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, snippetLabel, appendTo);7087TR::Instruction *brInstr = appendTo;7088brInstr->setExceptBranchOp();7089}7090else7091{7092TR::Node *n = NULL;70937094// After the NULLCHK is generated, the nodes are guaranteed7095// to be non-zero. Mark the nodes, so that subsequent7096// evaluations can be optimized.7097if (comp->useCompressedPointers()7098&& reference->getOpCodeValue() == TR::l2a)7099{7100reference->setIsNonNull(true);7101n = reference->getFirstChild();7102TR::ILOpCodes loadOp = comp->il.opCodeForIndirectLoad(TR::Int32);7103TR::ILOpCodes rdbarOp = comp->il.opCodeForIndirectReadBarrier(TR::Int32);7104while (n->getOpCodeValue() != loadOp && n->getOpCodeValue() != rdbarOp)7105{7106n->setIsNonZero(true);7107n = n->getFirstChild();7108}7109n->setIsNonZero(true);7110}71117112TR::InstOpCode::Mnemonic cmpOpCode = TR::InstOpCode::bad;71137114// For compressed pointers case, if we find the compressed value,7115// and it has already been evaluated into a register,7116// we can take advantage of the uncompressed value and evaluate7117// the compare result earlier.7118//7119// If it hasn't been evalauted yet, we want to evaluate the entire7120// l2a tree, which might generate LLGF. In that case, the better7121// choice is to perform the NULLCHK on the decompressed address.7122if (n != NULL && n->getRegister() != NULL)7123{7124targetRegister = n->getRegister();7125cg->evaluate(reference);71267127// For concurrent scavenge the source is loaded and shifted by the guarded load, thus we need to use CG7128// here for a non-zero compressedrefs shift value7129if (TR::Compiler->om.readBarrierType() != gc_modron_readbar_none)7130{7131cmpOpCode = TR::InstOpCode::getCmpOpCode();7132}7133else7134{7135cmpOpCode = (n->getOpCode().getSize() > 4) ? TR::InstOpCode::CG: TR::InstOpCode::C;7136}7137}7138else7139{7140targetRegister = cg->evaluate(reference);7141cmpOpCode = TR::InstOpCode::getCmpOpCode(); // reference is always an address type7142}7143appendTo = generateS390CompareAndBranchInstruction(cg, cmpOpCode, node, targetRegister, NULLVALUE, branchOpCond, snippetLabel, false, true, appendTo);7144TR::Instruction * cursor = appendTo;7145cursor->setExceptBranchOp();7146}7147}7148}71497150if (needLateEvaluation)7151{7152cg->evaluate(firstChild);7153}7154else if (needExplicitCheck)7155{7156cg->decReferenceCount(reference);7157}71587159if (comp->useCompressedPointers())7160cg->decReferenceCount(node->getFirstChild());7161else7162cg->decReferenceCount(firstChild);71637164// If an explicit check has not been generated for the null check, there is7165// an instruction that will cause a hardware trap if the exception is to be7166// taken. If this method may catch the exception, a GC stack map must be7167// created for this instruction. All registers are valid at this GC point7168// TODO - if the method may not catch the exception we still need to note7169// that the GC point exists, since maps before this point and after it cannot7170// be merged.7171//7172if (cg->getSupportsImplicitNullChecks() && !needExplicitCheck)7173{7174TR::Instruction *faultingInstruction = cg->getImplicitExceptionPoint();7175if (faultingInstruction)7176{7177faultingInstruction->setNeedsGCMap(0x0000FFFF);7178faultingInstruction->setThrowsImplicitNullPointerException();7179cg->setCanExceptByTrap(true);71807181TR_Debug * debugObj = cg->getDebug();7182if (debugObj)7183{7184debugObj->addInstructionComment(faultingInstruction, "Throws Implicit Null Pointer Exception");7185}7186}7187}71887189if (comp->useCompressedPointers()7190&& reference->getOpCodeValue() == TR::l2a)7191{7192reference->setIsNonNull(true);7193TR::Node *n = NULL;7194n = reference->getFirstChild();7195TR::ILOpCodes loadOp = comp->il.opCodeForIndirectLoad(TR::Int32);7196TR::ILOpCodes rdbarOp = comp->il.opCodeForIndirectReadBarrier(TR::Int32);7197while (n->getOpCodeValue() != loadOp && n->getOpCodeValue() != rdbarOp)7198{7199n->setIsNonZero(true);7200n = n->getFirstChild();7201}7202n->setIsNonZero(true);7203}72047205reference->setIsNonNull(true);72067207return NULL;7208}72097210static TR::Register *7211reservationLockEnter(TR::Node *node, int32_t lwOffset, TR::Register *objectClassReg, TR::CodeGenerator *cg, J9::Z::CHelperLinkage *helperLink)7212{7213TR::Register *objReg, *monitorReg, *valReg, *tempReg;7214TR::Register *EPReg, *returnAddressReg;7215TR::LabelSymbol *resLabel, *callLabel, *doneLabel;7216TR::Instruction *instr;7217TR::Compilation * comp = cg->comp();7218TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());7219int numICFDeps = 6 + (comp->getOptions()->enableDebugCounters() ? 4: 0);7220TR::RegisterDependencyConditions *ICFConditions =7221new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numICFDeps, cg);72227223if (objectClassReg)7224objReg = objectClassReg;7225else7226objReg = node->getFirstChild()->getRegister();72277228TR::Register *metaReg = cg->getMethodMetaDataRealRegister();72297230monitorReg = cg->allocateRegister();7231valReg = cg->allocateRegister();7232tempReg = cg->allocateRegister();72337234resLabel = generateLabelSymbol(cg);7235callLabel = generateLabelSymbol(cg);7236doneLabel = generateLabelSymbol(cg);72377238// TODO - primitive monitors are disabled. Enable it after testing7239//TR::TreeEvaluator::isPrimitiveMonitor(node, cg);7240//7241TR::LabelSymbol *helperReturnOOLLabel, *doneOOLLabel = NULL;7242TR::LabelSymbol * cFlowRegionStart = generateLabelSymbol(cg);7243TR_S390OutOfLineCodeSection *outlinedSlowPath = NULL;7244TR_Debug *debugObj = cg->getDebug();7245TR::Snippet *snippet = NULL;72467247// This is just for test. (may not work in all cases)7248static bool enforcePrimitive = feGetEnv("EnforcePrimitiveLockRes")? 1 : 0;7249bool isPrimitive = enforcePrimitive ? 1 : node->isPrimitiveLockedRegion();72507251// Opcodes:7252bool use64b = true;7253if (cg->comp()->target().is64Bit() && fej9->generateCompressedLockWord())7254use64b = false;7255else if (!cg->comp()->target().is64Bit())7256use64b = false;7257TR::InstOpCode::Mnemonic loadOp = use64b ? TR::InstOpCode::LG : TR::InstOpCode::L;7258TR::InstOpCode::Mnemonic loadRegOp = use64b ? TR::InstOpCode::LGR : TR::InstOpCode::LR;7259TR::InstOpCode::Mnemonic orImmOp = TR::InstOpCode::OILF;7260TR::InstOpCode::Mnemonic compareOp = use64b ? TR::InstOpCode::CGR : TR::InstOpCode::CR;7261TR::InstOpCode::Mnemonic compareImmOp = use64b ? TR::InstOpCode::CG : TR::InstOpCode::C;7262TR::InstOpCode::Mnemonic addImmOp = use64b ? TR::InstOpCode::AGHI : TR::InstOpCode::AHI;7263TR::InstOpCode::Mnemonic storeOp = use64b ? TR::InstOpCode::STG : TR::InstOpCode::ST;7264TR::InstOpCode::Mnemonic xorOp = use64b ? TR::InstOpCode::XGR : TR::InstOpCode::XR;7265TR::InstOpCode::Mnemonic casOp = use64b ? TR::InstOpCode::CSG : TR::InstOpCode::CS;7266TR::InstOpCode::Mnemonic loadImmOp = use64b ? TR::InstOpCode::LGHI : TR::InstOpCode::LHI ;7267TR::InstOpCode::Mnemonic andOp = use64b ? TR::InstOpCode::NGR : TR::InstOpCode::NR;72687269//ICF RA constraints7270//////////////7271ICFConditions->addPostConditionIfNotAlreadyInserted(objReg, TR::RealRegister::AssignAny);7272ICFConditions->addPostConditionIfNotAlreadyInserted(monitorReg, TR::RealRegister::AssignAny);7273ICFConditions->addPostConditionIfNotAlreadyInserted(valReg, TR::RealRegister::AssignAny);7274ICFConditions->addPostConditionIfNotAlreadyInserted(tempReg, TR::RealRegister::AssignAny);7275//////////////72767277// Main path instruction sequence (non-primitive).7278// L monitorReg, #lwOffset(objectReg)7279// LR valReg, metaReg7280// OILF valReg, LR-Bit7281// CRJ valReg, monitorReg, MASK6, callLabel7282// AHI monitorReg, INC_DEC_VALUE7283// ST monitorReg, #lwOffset(objectReg)72847285// load monitor reg7286generateRXInstruction(cg, loadOp, node, monitorReg, generateS390MemoryReference(objReg, lwOffset, cg));7287// load r13|LOCK_RESERVATION_BIT7288generateRRInstruction(cg, loadRegOp, node, valReg, metaReg);7289generateRILInstruction(cg, orImmOp, node, valReg, LOCK_RESERVATION_BIT);72907291// Jump to OOL path if lock is not reserved (monReg != r13|LOCK_RESERVATION_BIT)7292generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);7293cFlowRegionStart->setStartInternalControlFlow();7294instr = generateS390CompareAndBranchInstruction(cg, compareOp, node, valReg, monitorReg,7295TR::InstOpCode::COND_BNE, resLabel, false, false);72967297helperReturnOOLLabel = generateLabelSymbol(cg);7298doneOOLLabel = generateLabelSymbol(cg);7299if (debugObj)7300debugObj->addInstructionComment(instr, "Branch to OOL reservation enter sequence");7301outlinedSlowPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(resLabel, doneOOLLabel, cg);7302cg->getS390OutOfLineCodeSectionList().push_front(outlinedSlowPath);73037304cg->generateDebugCounter("LockEnt/LR/LRSuccessfull", 1, TR::DebugCounter::Undetermined);7305if (!isPrimitive)7306{7307generateRIInstruction (cg, addImmOp, node, monitorReg, (uintptr_t) LOCK_INC_DEC_VALUE);7308generateRXInstruction(cg, storeOp, node, monitorReg, generateS390MemoryReference(objReg, lwOffset, cg));7309}73107311if (outlinedSlowPath) // Means we have OOL7312{7313TR::LabelSymbol *reserved_checkLabel = generateLabelSymbol(cg);7314outlinedSlowPath->swapInstructionListsWithCompilation(); // Toggle instruction list7315TR::Instruction *temp = generateS390LabelInstruction(cg,TR::InstOpCode::label,node,resLabel);7316if (debugObj)7317{7318if (isPrimitive)7319debugObj->addInstructionComment(temp, "Denotes start of OOL primitive reservation enter sequence");7320else7321debugObj->addInstructionComment(temp, "Denotes start of OOL non-primitive reservation enter sequence");7322}7323// XXX: Temporary fix, OOL instruction stream does not pick up live locals or monitors correctly.7324TR_ASSERT(!temp->getLiveLocals() && !temp->getLiveMonitors(), "Expecting first OOL instruction to not have live locals/monitors info");7325temp->setLiveLocals(instr->getLiveLocals());7326temp->setLiveMonitors(instr->getLiveMonitors());73277328// Non-Primitive lockReservation enter sequence: Primitive lockReservation enter sequence:73297330// CIJ monitorReg, 0, MASK6, checkLabel TODO - Add Primitive lockReservation enter sequence7331// AHI valReg, INC_DEC_VALUE7332// XR monitorReg, monitorReg7333// CS monitorReg, valReg, #lwOffset(objectReg)7334// BRC MASK6, callHelper7335// BRC returnLabel7336// checkLabel:7337// LGFI tempReg, LOCK_RES_NON_PRIMITIVE_ENTER_MASK7338// NR tempReg, monitorReg7339// CRJ tempReg, valReg, MASK6, callHelper7340// AHI monitorReg, INC_DEC_VALUE7341// ST monitorReg, #lwOffset(objectReg)7342// BRC returnLabel7343// callHelper:7344// BRASL R14, jitMonitorEntry7345//returnLabel:73467347// Avoid CAS in case lock value is not zero7348generateS390CompareAndBranchInstruction(cg, compareImmOp, node, monitorReg, 0, TR::InstOpCode::COND_BNE, reserved_checkLabel, false);7349if (!isPrimitive)7350{7351generateRIInstruction (cg, addImmOp, node, valReg, (uintptr_t) LOCK_INC_DEC_VALUE);7352}7353// Try to acquire the lock using CAS7354generateRRInstruction(cg, xorOp, node, monitorReg, monitorReg);7355generateRSInstruction(cg, casOp, node, monitorReg, valReg, generateS390MemoryReference(objReg, lwOffset, cg));7356// Call VM helper if the CAS fails (contention)7357instr = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, callLabel);73587359cg->generateDebugCounter("LockEnt/LR/CASSuccessfull", 1, TR::DebugCounter::Undetermined);73607361// Lock is acquired successfully7362generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperReturnOOLLabel);73637364generateS390LabelInstruction(cg,TR::InstOpCode::label,node,reserved_checkLabel);7365// Mask the counter7366// Mask is 8 bit value which will be sign extended, We will be using cheaper instruction like LGHI or LHI7367generateRIInstruction(cg, loadImmOp, node, tempReg, ~(isPrimitive ? LOCK_RES_PRIMITIVE_ENTER_MASK : LOCK_RES_NON_PRIMITIVE_ENTER_MASK));7368generateRRInstruction(cg, andOp, node, tempReg, monitorReg);73697370// Call VM helper if the R13 != (masked MonReg)7371generateS390CompareAndBranchInstruction(cg, compareOp,node, tempReg, valReg,7372TR::InstOpCode::COND_BNE, callLabel, false, false);73737374cg->generateDebugCounter("LockEnt/LR/Recursive", 1, TR::DebugCounter::Undetermined);73757376// Recursive lock. Increment the counter7377if (!isPrimitive)7378{7379generateRIInstruction (cg, addImmOp, node, monitorReg, (uintptr_t) LOCK_INC_DEC_VALUE);7380generateRXInstruction(cg, storeOp, node, monitorReg, generateS390MemoryReference(objReg, lwOffset, cg));7381}7382generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperReturnOOLLabel);7383// call to jithelper7384generateS390LabelInstruction(cg, TR::InstOpCode::label, node, callLabel);7385cg->generateDebugCounter("LockEnt/LR/VMHelper", 1, TR::DebugCounter::Undetermined);7386uintptr_t returnAddress = (uintptr_t) (node->getSymbolReference()->getMethodAddress());73877388// We are calling helper within ICF so we need to combine dependency from ICF and helper call at merge label7389TR::RegisterDependencyConditions *deps = NULL;7390helperLink->buildDirectDispatch(node, &deps);7391TR::RegisterDependencyConditions *mergeConditions = mergeConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(ICFConditions, deps, cg);7392// OOL return label7393instr = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, helperReturnOOLLabel, mergeConditions);7394helperReturnOOLLabel->setEndInternalControlFlow();7395if (debugObj)7396{7397debugObj->addInstructionComment(instr, "OOL reservation enter VMHelper return label");7398}73997400instr = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, doneOOLLabel);7401if (debugObj)7402{7403if (isPrimitive)7404debugObj->addInstructionComment(instr, "Denotes end of OOL primitive reservation enter sequence: return to mainline");7405else7406debugObj->addInstructionComment(instr, "Denotes end of OOL non-primitive reservation enter sequence: return to mainline");7407}74087409outlinedSlowPath->swapInstructionListsWithCompilation(); // Toggle instruction list74107411instr = generateS390LabelInstruction(cg,TR::InstOpCode::label,node,doneOOLLabel);7412if (debugObj)7413debugObj->addInstructionComment(instr, "OOL reservation enter return label");7414generateS390LabelInstruction(cg,TR::InstOpCode::label,node, doneLabel);7415}7416else7417{7418TR_ASSERT(0, "Not implemented:Lock reservation with Disable OOL.");7419}7420if (monitorReg)7421cg->stopUsingRegister(monitorReg);7422if (valReg)7423cg->stopUsingRegister(valReg);7424if (tempReg)7425cg->stopUsingRegister(tempReg);74267427cg->decReferenceCount(node->getFirstChild());7428return NULL;7429}74307431static TR::Register *7432reservationLockExit(TR::Node *node, int32_t lwOffset, TR::Register *objectClassReg, TR::CodeGenerator *cg, J9::Z::CHelperLinkage *helperLink )7433{7434TR::Register *objReg, *monitorReg, *valReg, *tempReg;7435TR::Register *EPReg, *returnAddressReg;7436TR::LabelSymbol *resLabel, *callLabel, *doneLabel;7437TR::Instruction *instr;7438TR::Instruction *startICF = NULL;7439TR::Compilation *comp = cg->comp();7440TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());74417442int numICFDeps = 6 + (comp->getOptions()->enableDebugCounters() ? 4: 0);7443TR::RegisterDependencyConditions *ICFConditions =7444new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numICFDeps, cg);7445if (objectClassReg)7446objReg = objectClassReg;7447else7448objReg = node->getFirstChild()->getRegister();74497450TR::Register *metaReg = cg->getMethodMetaDataRealRegister();74517452monitorReg = cg->allocateRegister();7453valReg = cg->allocateRegister();7454tempReg = cg->allocateRegister();745574567457//ICF RA constraints7458//////////////7459ICFConditions->addPostConditionIfNotAlreadyInserted(objReg, TR::RealRegister::AssignAny);7460ICFConditions->addPostConditionIfNotAlreadyInserted(monitorReg, TR::RealRegister::AssignAny);7461ICFConditions->addPostConditionIfNotAlreadyInserted(valReg, TR::RealRegister::AssignAny);7462ICFConditions->addPostConditionIfNotAlreadyInserted(tempReg, TR::RealRegister::AssignAny);74637464resLabel = generateLabelSymbol(cg);7465callLabel = generateLabelSymbol(cg);7466doneLabel = generateLabelSymbol(cg);74677468TR::LabelSymbol * cFlowRegionStart = generateLabelSymbol(cg);74697470TR::LabelSymbol *helperReturnOOLLabel, *doneOOLLabel = NULL;7471TR_S390OutOfLineCodeSection *outlinedSlowPath = NULL;7472TR_Debug *debugObj = cg->getDebug();7473TR::Snippet *snippet = NULL;7474static bool enforcePrimitive = feGetEnv("EnforcePrimitiveLockRes")? 1 : 0;7475bool isPrimitive = enforcePrimitive ? 1 : node->isPrimitiveLockedRegion();74767477// Opcodes:7478bool use64b = true;7479if (cg->comp()->target().is64Bit() && fej9->generateCompressedLockWord())7480use64b = false;7481else if (!cg->comp()->target().is64Bit())7482use64b = false;7483TR::InstOpCode::Mnemonic loadOp = use64b ? TR::InstOpCode::LG : TR::InstOpCode::L;7484TR::InstOpCode::Mnemonic loadRegOp = use64b ? TR::InstOpCode::LGR : TR::InstOpCode::LR;7485TR::InstOpCode::Mnemonic orImmOp = TR::InstOpCode::OILF;7486TR::InstOpCode::Mnemonic compareOp = use64b ? TR::InstOpCode::CGR : TR::InstOpCode::CR;7487TR::InstOpCode::Mnemonic compareImmOp = use64b ? TR::InstOpCode::CG : TR::InstOpCode::C;7488TR::InstOpCode::Mnemonic addImmOp = use64b ? TR::InstOpCode::AGHI : TR::InstOpCode::AHI;7489TR::InstOpCode::Mnemonic storeOp = use64b ? TR::InstOpCode::STG : TR::InstOpCode::ST;7490TR::InstOpCode::Mnemonic xorOp = use64b ? TR::InstOpCode::XGR : TR::InstOpCode::XR;7491TR::InstOpCode::Mnemonic casOp = use64b ? TR::InstOpCode::CSG : TR::InstOpCode::CS;7492TR::InstOpCode::Mnemonic loadImmOp = use64b ? TR::InstOpCode::LGHI : TR::InstOpCode::LHI;7493TR::InstOpCode::Mnemonic andOp = use64b ? TR::InstOpCode::NGR : TR::InstOpCode::NR;7494TR::InstOpCode::Mnemonic andImmOp = TR::InstOpCode::NILF;74957496// Main path instruction sequence (non-primitive).7497// L monitorReg, #lwOffset(objectReg)7498// LR valReg, metaReg7499// OILF valReg, INC_DEC_VALUE | LR-Bit7500// CRJ valReg, monitorReg, BNE, callLabel7501// AHI valReg, -INC_DEC_VALUE7502// ST valReg, #lwOffset(objectReg)75037504generateRXInstruction(cg, loadOp, node, monitorReg, generateS390MemoryReference(objReg, lwOffset, cg));7505if (!isPrimitive)7506{7507generateRRInstruction(cg, loadRegOp, node, tempReg, metaReg);7508generateRILInstruction(cg, orImmOp, node, tempReg, LOCK_RESERVATION_BIT + LOCK_INC_DEC_VALUE);7509instr = generateS390CompareAndBranchInstruction(cg, compareOp, node, tempReg, monitorReg,7510TR::InstOpCode::COND_BNE, resLabel, false, false);7511cg->generateDebugCounter("LockExit/LR/LRSuccessfull", 1, TR::DebugCounter::Undetermined);7512}7513else7514{7515generateRRInstruction(cg, loadRegOp, node, tempReg, monitorReg);7516generateRILInstruction(cg, andImmOp, node, tempReg, LOCK_RES_PRIMITIVE_EXIT_MASK);7517instr = generateS390CompareAndBranchInstruction(cg, compareImmOp, node, tempReg, LOCK_RESERVATION_BIT,7518TR::InstOpCode::COND_BNE, resLabel, false);7519}75207521helperReturnOOLLabel = generateLabelSymbol(cg);7522doneOOLLabel = generateLabelSymbol(cg);7523if (debugObj)7524debugObj->addInstructionComment(instr, "Branch to OOL reservation exit sequence");7525outlinedSlowPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(resLabel, doneOOLLabel, cg);7526cg->getS390OutOfLineCodeSectionList().push_front(outlinedSlowPath);75277528if (!isPrimitive)7529{7530generateRIInstruction (cg, use64b? TR::InstOpCode::AGHI : TR::InstOpCode::AHI, node, tempReg, -LOCK_INC_DEC_VALUE);7531generateRXInstruction(cg, use64b? TR::InstOpCode::STG : TR::InstOpCode::ST,7532node, tempReg, generateS390MemoryReference(objReg, lwOffset, cg));7533}75347535if (outlinedSlowPath) // Means we have OOL7536{7537outlinedSlowPath->swapInstructionListsWithCompilation(); // Toggle instruction list7538TR::Instruction *temp = generateS390LabelInstruction(cg,TR::InstOpCode::label,node,resLabel);7539if (debugObj)7540{7541if (isPrimitive)7542debugObj->addInstructionComment(temp, "Denotes start of OOL primitive reservation exit sequence");7543else7544debugObj->addInstructionComment(temp, "Denotes start of OOL non-primitive reservation exit sequence");7545}7546// XXX: Temporary fix, OOL instruction stream does not pick up live locals or monitors correctly.7547TR_ASSERT(!temp->getLiveLocals() && !temp->getLiveMonitors(), "Expecting first OOL instruction to not have live locals/monitors info");7548temp->setLiveLocals(instr->getLiveLocals());7549temp->setLiveMonitors(instr->getLiveMonitors());75507551// Non-PRIMITIVE reservationLock exit sequence PRIMITIVE reservationLock exit sequence7552// LGFI tempReg, LOCK_RES_OWNING TODO - PRIMITIVE reservationLock exit sequence7553// NR tempReg, monitorReg7554// LR valReg, metaReg7555// AHI valReg, LR-Bit7556// CRJ tempReg, valReg, BNE, callHelper7557// LR tempReg, monitorReg7558// NILF tempReg, LOCK_RES_NON_PRIMITIVE_EXIT_MASK7559// BRC BERC, callHelper7560// AHI monitorReg, -INC_DEC_VALUE7561// ST monitorReg, #lwOffset(objectReg)7562// BRC returnLabel7563// callHelper:7564// BRASL R14, jitMonitorExit7565// returnLabel:75667567generateRIInstruction(cg, loadImmOp, node, tempReg, ~(LOCK_RES_OWNING_COMPLEMENT));7568generateRRInstruction(cg, andOp, node, tempReg, monitorReg);7569generateRRInstruction(cg, loadRegOp, node, valReg, metaReg);7570generateRIInstruction (cg, addImmOp, node, valReg, (uintptr_t) LOCK_RESERVATION_BIT);75717572generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);7573cFlowRegionStart->setStartInternalControlFlow();7574generateS390CompareAndBranchInstruction(cg, compareOp, node, tempReg, valReg,7575TR::InstOpCode::COND_BNE, callLabel, false, false);75767577generateRRInstruction(cg, loadRegOp, node, tempReg, monitorReg);7578generateRILInstruction(cg, andImmOp, node, tempReg,7579isPrimitive ? OBJECT_HEADER_LOCK_RECURSION_MASK : LOCK_RES_NON_PRIMITIVE_EXIT_MASK);75807581if (isPrimitive)7582generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, helperReturnOOLLabel);7583else7584{7585generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, callLabel/*,conditions*/);7586}7587cg->generateDebugCounter("LockExit/LR/Recursive", 1, TR::DebugCounter::Undetermined);7588generateRIInstruction (cg, addImmOp, node, monitorReg,7589(uintptr_t) (isPrimitive ? LOCK_INC_DEC_VALUE : -LOCK_INC_DEC_VALUE) & 0x0000FFFF);7590generateRXInstruction(cg, storeOp, node, monitorReg, generateS390MemoryReference(objReg, lwOffset, cg));75917592if (!isPrimitive)7593generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperReturnOOLLabel);7594// call to jithelper7595generateS390LabelInstruction(cg, TR::InstOpCode::label, node, callLabel);7596cg->generateDebugCounter("LockExit/LR/VMHelper", 1, TR::DebugCounter::Undetermined);7597uintptr_t returnAddress = (uintptr_t) (node->getSymbolReference()->getMethodAddress());7598TR::RegisterDependencyConditions *deps = NULL;7599helperLink->buildDirectDispatch(node, &deps);7600TR::RegisterDependencyConditions *mergeConditions = mergeConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(ICFConditions, deps, cg);7601instr = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, helperReturnOOLLabel, mergeConditions);7602// OOL return label7603helperReturnOOLLabel->setEndInternalControlFlow();7604if (debugObj)7605{7606debugObj->addInstructionComment(instr, "OOL reservation exit VMHelper return label");7607}7608instr = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, doneOOLLabel);7609if (debugObj)7610{7611if (isPrimitive)7612debugObj->addInstructionComment(instr, "Denotes end of OOL primitive reversation exit sequence: return to mainline");7613else7614debugObj->addInstructionComment(instr, "Denotes end of OOL non-primitive reversation exit sequence: return to mainline");7615}7616outlinedSlowPath->swapInstructionListsWithCompilation(); // Toggle instruction list7617instr = generateS390LabelInstruction(cg,TR::InstOpCode::label,node,doneOOLLabel);7618if (debugObj)7619debugObj->addInstructionComment(instr, "OOL reservation exit return label");76207621generateS390LabelInstruction(cg,TR::InstOpCode::label,node, doneLabel);7622}7623else7624{7625TR_ASSERT(0, "Not implemented: Lock reservation with Disable OOL.");7626}76277628if (monitorReg)7629cg->stopUsingRegister(monitorReg);7630if (valReg)7631cg->stopUsingRegister(valReg);7632if (tempReg)7633cg->stopUsingRegister(tempReg);76347635cg->decReferenceCount(node->getFirstChild());7636return NULL;7637}76387639// the following routine is a bit grotty - it has to determine if there are any GRA7640// assigned real registers that will conflict with real registers required by7641// instance-of generation.7642// it also has to verify that instance-of won't require more registers than are7643// available.7644static bool graDepsConflictWithInstanceOfDeps(TR::Node * depNode, TR::Node * node, TR::CodeGenerator * cg)7645{7646TR::Node * castClassNode = node->getSecondChild();7647TR::SymbolReference * castClassSymRef = castClassNode->getSymbolReference();7648TR::Compilation *comp = cg->comp();76497650bool testCastClassIsSuper = TR::TreeEvaluator::instanceOfOrCheckCastNeedSuperTest(node, cg);7651bool isFinalClass = (castClassSymRef == NULL) ? false : castClassSymRef->isNonArrayFinal(comp);7652bool needsHelperCall = needHelperCall(node, testCastClassIsSuper, isFinalClass);76537654if (maxInstanceOfPostDependencies() + depNode->getNumChildren() > cg->getMaximumNumberOfAssignableGPRs())7655{7656return true;7657}7658if (!needsHelperCall)7659{7660return false;7661}76627663for (int i=0; i<depNode->getNumChildren(); i++)7664{7665TR::Node * child = depNode->getChild(i);7666if ((child->getOpCodeValue() == TR::lRegLoad || child->getOpCodeValue() == TR::PassThrough)7667&& cg->comp()->target().is32Bit())7668{7669int32_t regIndex = child->getHighGlobalRegisterNumber();7670if (killedByInstanceOfHelper(regIndex, node, cg))7671{7672return true;7673}76747675regIndex = child->getLowGlobalRegisterNumber();7676if (killedByInstanceOfHelper(regIndex, node, cg))7677{7678return true;7679}7680}7681else7682{7683int32_t regIndex = child->getGlobalRegisterNumber();7684if (killedByInstanceOfHelper(regIndex, node, cg))7685{7686return true;7687}7688}7689}7690return false;7691}76927693/** \brief7694* Generates a dynamicCache test with helper call for instanceOf/ifInstanceOf node7695*7696* \details7697* This function generates a sequence to check per site cache for object class and cast class before calling out to jitInstanceOf helper7698*/7699static7700void genInstanceOfDynamicCacheAndHelperCall(TR::Node *node, TR::CodeGenerator *cg, TR::Register *castClassReg, TR::Register *objClassReg, TR::Register *resultReg, TR::RegisterDependencyConditions *deps, TR_S390ScratchRegisterManager *srm, TR::LabelSymbol *doneLabel, TR::LabelSymbol *helperCallLabel, TR::LabelSymbol *dynamicCacheTestLabel, TR::LabelSymbol *branchLabel, TR::LabelSymbol *trueLabel, TR::LabelSymbol *falseLabel, bool dynamicCastClass, bool generateDynamicCache, bool cacheCastClass, bool ifInstanceOf, bool trueFallThrough )7701{7702TR::Compilation *comp = cg->comp();7703bool needResult = resultReg != NULL;7704if (!castClassReg)7705castClassReg = cg->gprClobberEvaluate(node->getSecondChild());77067707int32_t maxOnsiteCacheSlots = comp->getOptions()->getMaxOnsiteCacheSlotForInstanceOf();7708int32_t sizeofJ9ClassFieldWithinReference = TR::Compiler->om.sizeofReferenceField();7709bool isTarget64Bit = comp->target().is64Bit();7710bool isCompressedRef = comp->useCompressedPointers();7711/* Layout of the writable data snippet7712* Case - 1 : Cast class is runtime variable7713* Case - 1A: 64 Bit Compressedrefs / 31-Bit JVM7714* -----------------------------------------------------------------------------------------7715* |Header | ObjectClassSlot-0 | CastClassSlot-0 |...| ObjectClassSlot-N | CastClassSlot-N |7716* -----------------------------------------------------------------------------------------7717* 0 8 12 ... 8n 8n+47718* Case - 1B: 64 Bit Non Compressedrefs7719* -----------------------------------------------------------------------------------------7720* |Header | ObjectClassSlot-0 | CastClassSlot-0 |...| ObjectClassSlot-N | CastClassSlot-N |7721* -----------------------------------------------------------------------------------------7722* 0 16 24 ... 16n 16n+87723* Case - 2 : Cast Class is resolved7724* Case - 2A: 64 Bit Compressedrefs / 31-Bit JVM7725* --------------------------------------------------------------------------7726* | Header | ObjectClassSlot-0 | ObjectClassSlot-1 |...| ObjectClassSlot-N |7727* --------------------------------------------------------------------------7728* 0 4 8 ... 4n7729* Case - 2B: 64 Bit Non Compressedrefs7730* --------------------------------------------------------------------------7731* | Header | ObjectClassSlot-0 | ObjectClassSlot-1 |...| ObjectClassSlot-N |7732* --------------------------------------------------------------------------7733* 0 8 16 ... 8n7734*7735* If there is only one cache slot, we will not have header.7736* Last bit of cached objectClass will set to 1 indicating false cast7737*7738* We can request the snippet size of power 2. Following Table summarizes bytes needed for corresponding number of cache slots.7739*7740* Following is the table for the number of bytes in snippet needed by each of the Cases mentioned above7741*7742* Number Of Slots | Case 1A | Case 1B | Case 2A | Case 2B |7743* 1 | 8 | 16 | 4 | 8 |7744* 2 | 16 | 64 | 16 | 32 |7745* 3 | 32 | 64 | 16 | 32 |7746* 4 | 64 | 128 | 32 | 64 |7747* 5 | 64 | 128 | 32 | 64 |7748* 6 | 64 | 128 | 32 | 64 |7749*7750*/77517752int32_t snippetSizeInBytes = ((cacheCastClass ? 2 : 1) * maxOnsiteCacheSlots * sizeofJ9ClassFieldWithinReference) + (sizeofJ9ClassFieldWithinReference * (maxOnsiteCacheSlots != 1) * (cacheCastClass ? 2 : 1));7753TR::Register *dynamicCacheReg = NULL;7754TR::Register *cachedObjectClass = NULL;7755TR::Register *cachedCastClass = NULL;7756TR::RegisterPair *cachedClassDataRegPair = NULL;77577758if (generateDynamicCache)7759{7760TR::S390WritableDataSnippet *dynamicCacheSnippet = NULL;7761int32_t requestedBytes = 1 << (int) (log2(snippetSizeInBytes-1)+1);7762if (comp->getOption(TR_TraceCG))7763{7764traceMsg(comp, "Number Of Dynamic Cache Slots = %d, Caching CastClass: %s\n"7765"Bytes needed for Snippet = %d, requested Bytes = %d\n",maxOnsiteCacheSlots, cacheCastClass ? "true" : "false", snippetSizeInBytes, requestedBytes);7766}77677768TR_ASSERT_FATAL(maxOnsiteCacheSlots <= 7, "Maximum 7 slots per site allowed because we use a fixed stack allocated buffer to construct the snippet\n");7769U_32 initialSnippet[32] = { 0 };7770initialSnippet[0] = static_cast<U_32>( sizeofJ9ClassFieldWithinReference * (cacheCastClass ? 2 : 1) );7771dynamicCacheSnippet = (TR::S390WritableDataSnippet*)cg->CreateConstant(node, initialSnippet, requestedBytes, true);77727773int32_t currentIndex = maxOnsiteCacheSlots > 1 ? sizeofJ9ClassFieldWithinReference * (cacheCastClass ? 2 : 1) : 0;77747775dynamicCacheReg = srm->findOrCreateScratchRegister();77767777// Start of the Dyanamic Cache Test7778generateS390LabelInstruction(cg, TR::InstOpCode::label, node, dynamicCacheTestLabel);7779generateRILInstruction(cg, TR::InstOpCode::LARL, node, dynamicCacheReg, dynamicCacheSnippet, 0);77807781// For 64-Bit Non Compressedrefs JVM, we need to make sure that we are loading associated class data from the cache that appears quadwoerd concurrent as observed by other CPUs/7782// For that reason, We need to use LPQ/STPQ instruction which needs register pair.7783// In case of 64 bit compressedrefs or 31-Bit JVM, size of J9Class pointer takes 4 bytes only, so in loading associated class data from the cache we can use instruction for 8 byte load/store.7784if (cacheCastClass && isTarget64Bit && !isCompressedRef)7785{7786cachedObjectClass = cg->allocateRegister();7787cachedCastClass = cg->allocateRegister();7788cachedClassDataRegPair = cg->allocateConsecutiveRegisterPair(cachedCastClass, cachedObjectClass);7789deps->addPostCondition(cachedObjectClass, TR::RealRegister::LegalEvenOfPair);7790deps->addPostCondition(cachedCastClass, TR::RealRegister::LegalOddOfPair);7791deps->addPostCondition(cachedClassDataRegPair, TR::RealRegister::EvenOddPair);7792}7793else7794{7795cachedObjectClass = srm->findOrCreateScratchRegister();7796}7797/**7798* Instructions generated for dynamicCache Test are as follows.7799* dynamicCacheTestLabel :7800* LARL dynamicCacheReg, dynamicCacheSnippet7801* if (cacheCastClass)7802* if (isCompressedRef || targetIs31Bit)7803* LG cachedData, @(dynamicCacheReg, currentIndex)7804* CLRJ castClass, cachedData, COND_BNE, gotoNextTest7805* RISBG cachaedData, cachedData, 32, 191, 32 // cachedData >> 327806* else7807* LPQ cachedObjectClass:cachedCastClass, @(dynamicCacheReg, currentIndex)7808* CLGRJ castClass, cachedCastClass, COND_BNE, gotoNextTest7809* else7810* Load cachedObjectClass, @(dynamicCacheReg, currentIndex)7811* XOR cachedData/cachedObjectClass, objClass7812* if (cachedData/cachedObjectClass == 0) gotoTrueLabel7813* else if (cachedData/cachedObjectClass == 1) gotoFalseLabel7814* gotoNextTest:7815*/78167817TR::LabelSymbol *gotoNextTest = NULL;7818for (auto i=0; i<maxOnsiteCacheSlots; i++)7819{7820if (cacheCastClass)7821{7822gotoNextTest = (i+1 == maxOnsiteCacheSlots) ? helperCallLabel : generateLabelSymbol(cg);7823if (isTarget64Bit && !isCompressedRef)7824{7825generateRXInstruction(cg, TR::InstOpCode::LPQ, node, cachedClassDataRegPair, generateS390MemoryReference(dynamicCacheReg, currentIndex, cg));7826generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, castClassReg, cachedCastClass, TR::InstOpCode::COND_BNE, gotoNextTest, false);7827}7828else7829{7830generateRXInstruction(cg, TR::InstOpCode::LG, node, cachedObjectClass, generateS390MemoryReference(dynamicCacheReg, currentIndex, cg));7831generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CLR, node, castClassReg, cachedObjectClass, TR::InstOpCode::COND_BNE, gotoNextTest, false);7832generateRIEInstruction(cg, TR::InstOpCode::RISBG, node, cachedObjectClass, cachedObjectClass, 32, 191, 32);7833}7834}7835else7836{7837generateRXInstruction(cg, isTarget64Bit ? (isCompressedRef ? TR::InstOpCode::LLGF : TR::InstOpCode::LG) : TR::InstOpCode::L, node, cachedObjectClass, generateS390MemoryReference(dynamicCacheReg,currentIndex,cg));7838}78397840generateRRInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node,cachedObjectClass, objClassReg);78417842if (i+1 == maxOnsiteCacheSlots)7843{7844if (trueFallThrough)7845{7846generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, cachedObjectClass, 1, TR::InstOpCode::COND_BE, falseLabel, false, false);7847generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, helperCallLabel);7848}7849else7850{7851generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, trueLabel);7852generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, cachedObjectClass, 1, TR::InstOpCode::COND_BNE, helperCallLabel, false, false);7853}7854}7855else7856{7857generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, trueLabel);7858generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, cachedObjectClass, 1, TR::InstOpCode::COND_BE, falseLabel, false, false);7859}78607861if (gotoNextTest && gotoNextTest != helperCallLabel)7862generateS390LabelInstruction(cg, TR::InstOpCode::label, node, gotoNextTest);78637864currentIndex += ( cacheCastClass ? 2 : 1 ) * sizeofJ9ClassFieldWithinReference;7865}7866if (!cacheCastClass || !isTarget64Bit || isCompressedRef)7867srm->reclaimScratchRegister(cachedObjectClass);7868}7869else if (!dynamicCastClass)7870{7871// If dynamic Cache Test is not generated and it is not dynamicCastClass, we need to generate following branch7872// In cases of dynamic cache test / dynamic Cast Class, we would have a branch to helper call at appropriate location.7873generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperCallLabel);7874}78757876TR_S390OutOfLineCodeSection *outlinedSlowPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(helperCallLabel, doneLabel, cg);7877cg->getS390OutOfLineCodeSectionList().push_front(outlinedSlowPath);7878outlinedSlowPath->swapInstructionListsWithCompilation();78797880generateS390LabelInstruction(cg, TR::InstOpCode::label, node, helperCallLabel);7881cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOf/(%s)/Helper", comp->signature()),1,TR::DebugCounter::Undetermined);7882J9::Z::CHelperLinkage *helperLink = static_cast<J9::Z::CHelperLinkage*>(cg->getLinkage(TR_CHelper));7883resultReg = helperLink->buildDirectDispatch(node, resultReg);78847885if (generateDynamicCache)7886{7887TR::RegisterDependencyConditions *OOLConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 9, cg);7888if (cacheCastClass && isTarget64Bit && !comp->useCompressedPointers())7889{7890OOLConditions->addPostCondition(cachedObjectClass, TR::RealRegister::LegalEvenOfPair);7891OOLConditions->addPostCondition(cachedCastClass, TR::RealRegister::LegalOddOfPair);7892OOLConditions->addPostCondition(cachedClassDataRegPair, TR::RealRegister::EvenOddPair);7893}7894OOLConditions->addPostCondition(objClassReg, TR::RealRegister::AssignAny);7895OOLConditions->addPostCondition(castClassReg, TR::RealRegister::AssignAny);7896OOLConditions->addPostCondition(resultReg, TR::RealRegister::AssignAny);7897OOLConditions->addPostCondition(dynamicCacheReg, TR::RealRegister::AssignAny);78987899TR::LabelSymbol *cFlowRegionStart = generateLabelSymbol(cg);7900generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);7901cFlowRegionStart->setStartInternalControlFlow();7902TR::LabelSymbol *skipSettingBitForFalseResult = generateLabelSymbol(cg);7903generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, resultReg, 1, TR::InstOpCode::COND_BE, skipSettingBitForFalseResult, false);7904// We will set the last bit of objectClassRegister to 1 if helper returns false.7905generateRIInstruction(cg, TR::InstOpCode::OILL, node, objClassReg, 0x1);7906generateS390LabelInstruction(cg, TR::InstOpCode::label, node, skipSettingBitForFalseResult);7907TR::MemoryReference *updateMemRef = NULL;7908// Update cache sequence79097910TR::Register *offsetRegister = NULL;7911if (maxOnsiteCacheSlots == 1)7912{7913updateMemRef = generateS390MemoryReference(dynamicCacheReg, 0, cg);7914}7915else7916{7917offsetRegister = cg->allocateRegister();7918OOLConditions->addPostCondition(offsetRegister, TR::RealRegister::AssignAny);7919generateRXInstruction(cg, TR::InstOpCode::LLGF, node, offsetRegister, generateS390MemoryReference(dynamicCacheReg,0,cg));7920updateMemRef = generateS390MemoryReference(dynamicCacheReg, offsetRegister, 0, cg);7921}79227923if (cacheCastClass)7924{7925if (isTarget64Bit && !isCompressedRef)7926{7927generateRRInstruction(cg, TR::InstOpCode::LGR, node, cachedObjectClass, objClassReg);7928generateRRInstruction(cg, TR::InstOpCode::LGR, node, cachedCastClass, castClassReg);7929generateRXInstruction(cg, TR::InstOpCode::STPQ, node, cachedClassDataRegPair, updateMemRef);7930}7931else7932{7933TR::Register *storeDataCacheReg = castClassReg;7934if (!isTarget64Bit)7935{7936storeDataCacheReg = cg->allocateRegister();7937OOLConditions->addPostCondition(storeDataCacheReg, TR::RealRegister::AssignAny);7938generateRRInstruction(cg, TR::InstOpCode::LGFR, node, storeDataCacheReg, castClassReg);7939}7940generateRIEInstruction(cg, TR::InstOpCode::RISBG, node, storeDataCacheReg, objClassReg, 0, 31, 32);7941generateRXInstruction(cg, TR::InstOpCode::STG, node, storeDataCacheReg, updateMemRef);7942if (!isTarget64Bit)7943cg->stopUsingRegister(storeDataCacheReg);7944}7945}7946else7947{7948generateRXInstruction(cg, sizeofJ9ClassFieldWithinReference == 8 ? TR::InstOpCode::STG : TR::InstOpCode::ST, node, objClassReg, updateMemRef);7949}79507951if (maxOnsiteCacheSlots != 1)7952{7953generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, offsetRegister, static_cast<int32_t>(cacheCastClass?sizeofJ9ClassFieldWithinReference*2:sizeofJ9ClassFieldWithinReference));7954TR::LabelSymbol *skipResetOffsetLabel = generateLabelSymbol(cg);7955generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, offsetRegister, snippetSizeInBytes, TR::InstOpCode::COND_BNE, skipResetOffsetLabel, false);7956generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode() , node, offsetRegister, sizeofJ9ClassFieldWithinReference * (cacheCastClass ? 2 : 1));7957generateS390LabelInstruction(cg, TR::InstOpCode::label, node, skipResetOffsetLabel);7958generateRXInstruction(cg, TR::InstOpCode::ST, node, offsetRegister, generateS390MemoryReference(dynamicCacheReg,0,cg));7959}79607961TR::LabelSymbol *doneCacheUpdateLabel = generateLabelSymbol(cg);7962generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneCacheUpdateLabel, OOLConditions);7963doneCacheUpdateLabel->setEndInternalControlFlow();7964srm->reclaimScratchRegister(dynamicCacheReg);7965if (offsetRegister != NULL)7966cg->stopUsingRegister(offsetRegister);7967}79687969// WARNING: It is not recommended to have two exit point in OOL section7970// In this case we need it in case of ifInstanceOf to save additional complex logic in mainline section7971// In case if there is GLRegDeps attached to ifInstanceOf node, it will be evaluated and attached as post dependency conditions7972// at the end of node7973// We can take a risk of having two exit points in OOL here as there is no other register instruction between them7974if (ifInstanceOf)7975{7976generateRRInstruction(cg, TR::InstOpCode::getLoadTestRegOpCode(), node, resultReg, resultReg);7977if (trueFallThrough)7978generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, branchLabel);7979else7980generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, branchLabel);7981}79827983generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, doneLabel);7984outlinedSlowPath->swapInstructionListsWithCompilation();7985if (!needResult)7986cg->stopUsingRegister(resultReg);7987}79887989/** \brief Generates inlined sequence of tests for instanceOf/ifInstanceOf node.7990* \details7991* It calls common function to generate list of inlined tests and generates instructions handling both instanceOf and ifInstanceOf case.7992*/7993TR::Register *7994J9::Z::TreeEvaluator::VMgenCoreInstanceofEvaluator(TR::Node * node, TR::CodeGenerator * cg, TR::LabelSymbol *trueLabel, TR::LabelSymbol *falseLabel,7995bool initialResult, bool needResult, TR::RegisterDependencyConditions *graDeps, bool ifInstanceOf)7996{7997TR::Compilation *comp = cg->comp();7998TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());7999TR_OpaqueClassBlock *compileTimeGuessClass;8000int32_t maxProfiledClasses = comp->getOptions()->getCheckcastMaxProfiledClassTests();8001traceMsg(comp, "%s:Maximum Profiled Classes = %d\n", node->getOpCode().getName(),maxProfiledClasses);8002InstanceOfOrCheckCastProfiledClasses* profiledClassesList = (InstanceOfOrCheckCastProfiledClasses*)alloca(maxProfiledClasses * sizeof(InstanceOfOrCheckCastProfiledClasses));80038004TR::Node *objectNode = node->getFirstChild();8005TR::Node *castClassNode = node->getSecondChild();80068007TR::Register *objectReg = cg->evaluate(objectNode);8008TR::Register *objClassReg = NULL;8009TR::Register *resultReg = NULL;8010TR::Register *castClassReg = NULL;80118012// In the evaluator, We need at maximum two scratch registers, so creating a pool of scratch registers with 2 size.8013TR_S390ScratchRegisterManager *srm = cg->generateScratchRegisterManager(2);8014bool topClassWasCastClass=false;8015float topClassProbability=0.0;8016InstanceOfOrCheckCastSequences sequences[InstanceOfOrCheckCastMaxSequences];8017uint32_t numberOfProfiledClass;8018uint32_t numSequencesRemaining = calculateInstanceOfOrCheckCastSequences(node, sequences, &compileTimeGuessClass, cg, profiledClassesList, &numberOfProfiledClass, maxProfiledClasses, &topClassProbability, &topClassWasCastClass);8019bool outLinedSuperClass = false;8020TR::Instruction *cursor = NULL;8021TR::Instruction *gcPoint = NULL;80228023// We load resultReg with the parameter initialResult when we need result as outcome for routine8024if (needResult)8025{8026resultReg = cg->allocateRegister();8027cursor = generateRIInstruction(cg,TR::InstOpCode::getLoadHalfWordImmOpCode(),node,resultReg,static_cast<int32_t>(initialResult));8028}80298030TR_S390OutOfLineCodeSection *outlinedSlowPath = NULL;80318032TR::LabelSymbol *doneOOLLabel = NULL;8033TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);8034TR::LabelSymbol *callLabel = generateLabelSymbol(cg);8035TR::LabelSymbol *doneTestCacheLabel = NULL;8036TR::LabelSymbol *oppositeResultLabel = generateLabelSymbol(cg);8037TR::LabelSymbol *helperTrueLabel = NULL;8038TR::LabelSymbol *helperFalseLabel = NULL;8039TR::LabelSymbol *helperReturnLabel = NULL;8040TR::LabelSymbol *dynamicCacheTestLabel = NULL;8041TR::LabelSymbol *branchLabel = NULL;8042TR::LabelSymbol *jmpLabel = NULL;80438044TR::InstOpCode::S390BranchCondition branchCond;8045TR_Debug *debugObj = cg->getDebug();8046bool trueFallThrough;8047bool dynamicCastClass = false;8048bool generateGoToFalseBRC = true;80498050if (ifInstanceOf)8051{8052if (trueLabel)8053{8054traceMsg(comp,"IfInstanceOf Node : Branch True\n");8055falseLabel = (needResult) ? oppositeResultLabel : doneLabel;8056branchLabel = trueLabel;8057branchCond = TR::InstOpCode::COND_BE;8058jmpLabel = falseLabel;8059trueFallThrough = false;8060}8061else8062{8063traceMsg(comp,"IfInstanceOf Node : Branch False\n");8064trueLabel = (needResult)? oppositeResultLabel : doneLabel;8065branchLabel = falseLabel;8066branchCond = TR::InstOpCode::COND_BNE;8067jmpLabel = trueLabel;8068trueFallThrough = true;8069}8070}8071else8072{8073if (initialResult)8074{8075trueLabel = doneLabel;8076falseLabel = oppositeResultLabel;8077branchCond = TR::InstOpCode::COND_BE;8078trueFallThrough = false;8079}8080else8081{8082trueLabel = oppositeResultLabel;8083falseLabel = doneLabel;8084branchCond = TR::InstOpCode::COND_BNE;8085trueFallThrough = true;8086}8087branchLabel = doneLabel;8088jmpLabel = oppositeResultLabel;8089}80908091bool generateDynamicCache = false;8092bool cacheCastClass = false;8093InstanceOfOrCheckCastSequences *iter = &sequences[0];8094while (numSequencesRemaining > 1 || (numSequencesRemaining==1 && *iter!=HelperCall))8095{8096switch (*iter)8097{8098case EvaluateCastClass:8099TR_ASSERT(!castClassReg, "Cast class already evaluated");8100if (comp->getOption(TR_TraceCG))8101traceMsg(comp, "%s: Class Not Evaluated. Evaluating it\n", node->getOpCode().getName());8102castClassReg = cg->gprClobberEvaluate(node->getSecondChild());8103break;8104case LoadObjectClass:8105if (comp->getOption(TR_TraceCG))8106traceMsg(comp, "%s: Loading Object Class\n",node->getOpCode().getName());8107objClassReg = cg->allocateRegister();8108TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, objClassReg, generateS390MemoryReference(objectReg, static_cast<int32_t>(TR::Compiler->om.offsetOfObjectVftField()), cg), NULL);8109break;8110case GoToTrue:8111traceMsg(comp, "%s: Emitting GoToTrue\n", node->getOpCode().getName());8112// If fall through in True (Initial Result False)8113//if (trueLabel != oppositeResultLabel)8114if (trueLabel != oppositeResultLabel || (ifInstanceOf && !trueFallThrough))8115generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BC, node, trueLabel);8116break;8117case GoToFalse:8118traceMsg(comp, "%s: Emitting GoToFalse\n", node->getOpCode().getName());8119// There is only one case when we generate a GoToFalse branch here, when we have a primitive Cast Class other wise all tests take care of generating terminating sequence8120if (generateGoToFalseBRC)8121generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BC, node, falseLabel);8122break;8123case NullTest:8124{8125if (comp->getOption(TR_TraceCG))8126traceMsg(comp, "%s: Emitting NullTest\n", node->getOpCode().getName());8127TR_ASSERT(!objectNode->isNonNull(), "Object is known to be non-null, no need for a null test");8128const bool isCCSet = genInstanceOfOrCheckCastNullTest(node, cg, objectReg);81298130if (isCCSet)8131{8132// If object is Null, and initialResult is true, go to oppositeResultLabel else goto done Label8133generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, falseLabel);8134}8135}8136break;8137case ClassEqualityTest:8138if (comp->getOption(TR_TraceCG))8139traceMsg(comp, "%s: Emitting Class Equality Test\n", node->getOpCode().getName());8140cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfStats/(%s)/Equality", comp->signature()),1,TR::DebugCounter::Undetermined);8141/* #IF NextTest = GoToFalse8142* branchCond = ifInstanceOf ? (!trueFallThrough ? COND_BE : COND_BNE ) : (init=true ? COND_BE : COND_BNE )8143* branchLabel = ifInstanceOf ? (!trueFallThrough ? trueLabel : falseLabel ) : doneLabel8144* CGRJ castClassReg, objClassReg, branchCond, branchLabel8145* #ELSE8146* CGRJ castClassReg, objClassReg, COND_BE, trueLabel8147*/8148if ( *(iter+1) == GoToFalse )8149{8150cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, castClassReg, objClassReg, branchCond, branchLabel, false, false);8151generateGoToFalseBRC = false;8152}8153else8154{8155cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, castClassReg, objClassReg, TR::InstOpCode::COND_BE, trueLabel, false, false);8156generateGoToFalseBRC = true;8157}8158if (debugObj)8159debugObj->addInstructionComment(cursor, "ClassEqualityTest");8160cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfStats/(%s)/EqualityFail", comp->signature()),1,TR::DebugCounter::Undetermined);8161break;8162case SuperClassTest:8163{8164/*** genInstanceOfOrCheckcastSuperClassTest generates sequences for Super Class Test handling all cases when we have a normal static class or dynamic class8165* Mostly this will be last test except in case of dynamic cast class.8166* case-1 instanceof , initial Result = false: BRC 0x8, doneLabel8167* case-2 instanceof , initial Result = true: BRC 0x6, doneLabel8168* case-3 ifInstanceOf , trueLabel == branchLabel : BRC 0x8, branchLabel8169* case-4 ifInstanceOf , falseLabel == branchLabel : BRC 0x6, branchLabel8170*/8171int32_t castClassDepth = castClassNode->getSymbolReference()->classDepth(comp);8172dynamicCacheTestLabel = generateLabelSymbol(cg);8173if (comp->getOption(TR_TraceCG))8174traceMsg(comp, "%s: Emitting Super Class Test, Cast Class Depth = %d\n", node->getOpCode().getName(),castClassDepth);8175cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfStats/(%s)/SuperClassTest", comp->signature()),1,TR::DebugCounter::Undetermined);8176// For dynamic cast class genInstanceOfOrCheckcastSuperClassTest will generate branch to either helper call or dynamicCacheTest depending on the next generated test.8177dynamicCastClass = genInstanceOfOrCheckcastSuperClassTest(node, cg, objClassReg, castClassReg, castClassDepth, falseLabel, *(iter+1) == DynamicCacheDynamicCastClassTest ? dynamicCacheTestLabel : callLabel, srm);8178generateS390BranchInstruction(cg, TR::InstOpCode::BRC, branchCond, node, branchLabel);8179// If next test is dynamicCacheTest then generate a Branch to Skip it.8180if (*(iter+1) == DynamicCacheDynamicCastClassTest)8181generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BC, node, jmpLabel);8182generateGoToFalseBRC=false;8183break;8184}8185/** Following switch case generates sequence of instructions for profiled class test for instanceOf node8186* arbitraryClassReg1 <= profiledClass8187* if (arbitraryClassReg1 == objClassReg)8188* profiledClassIsInstanceOfCastClass ? return true : return false8189* else8190* continue to NextTest8191*/8192case ProfiledClassTest:8193{8194if (comp->getOption(TR_TraceCG))8195traceMsg(comp, "%s: Emitting ProfiledClass Test\n", node->getOpCode().getName());8196TR::Register *arbitraryClassReg1 = srm->findOrCreateScratchRegister();8197uint8_t numPICs = 0;8198TR::Instruction *temp= NULL;8199cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfStats/(%s)/Profile", comp->signature()),1,TR::DebugCounter::Undetermined);8200while (numPICs < numberOfProfiledClass)8201{8202if (cg->needClassAndMethodPointerRelocations())8203temp = generateRegLitRefInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, arbitraryClassReg1, (uintptr_t) profiledClassesList[numPICs].profiledClass, TR_ClassPointer, NULL, NULL, NULL);8204else8205temp = generateRILInstruction(cg, TR::InstOpCode::LARL, node, arbitraryClassReg1, profiledClassesList[numPICs].profiledClass);82068207// Adding profiled class to the static PIC slots.8208if (fej9->isUnloadAssumptionRequired((TR_OpaqueClassBlock *)(profiledClassesList[numPICs].profiledClass), comp->getCurrentMethod()))8209comp->getStaticPICSites()->push_front(temp);8210// Adding profiled class to static HCR PIC sites.8211if (cg->wantToPatchClassPointer(profiledClassesList[numPICs].profiledClass, node))8212comp->getStaticHCRPICSites()->push_front(temp);82138214if (profiledClassesList[numPICs].isProfiledClassInstanceOfCastClass)8215generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, arbitraryClassReg1, objClassReg, TR::InstOpCode::COND_BE, trueLabel, false, false);8216else8217generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, arbitraryClassReg1, objClassReg, TR::InstOpCode::COND_BE, falseLabel, false, false);8218numPICs++;8219}8220cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfStats/(%s)/ProfileFail", comp->signature()),1,TR::DebugCounter::Undetermined);8221srm->reclaimScratchRegister(arbitraryClassReg1);8222break;8223}8224/** In case of Single Implementer of the Interface,8225* arbitraryClassReg1 <= compileTimeGuessClass8226* CGRJ arbitraryClassReg,objClassReg,0x8,trueLabel8227*/8228case CompileTimeGuessClassTest:8229{8230TR::Register *arbitraryClassReg2 = srm->findOrCreateScratchRegister();8231cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfStats/(%s)/compTimeGuess", comp->signature()),1,TR::DebugCounter::Undetermined);8232genLoadAddressConstant(cg, node, (uintptr_t)compileTimeGuessClass, arbitraryClassReg2);8233generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, arbitraryClassReg2, objClassReg, TR::InstOpCode::COND_BE, trueLabel, false, false);8234cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfStats/(%s)/compTimeGuessFail", comp->signature()),1,TR::DebugCounter::Undetermined);8235srm->reclaimScratchRegister(arbitraryClassReg2);8236break;8237}8238case ArrayOfJavaLangObjectTest:8239{8240if (comp->getOption(TR_TraceCG))8241traceMsg(comp,"Emitting ArrayOfJavaLangObjectTest\n",node->getOpCode().getName());8242cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfStats/(%s)/ArrayTest", comp->signature()),1,TR::DebugCounter::Undetermined);8243genInstanceOfOrCheckcastArrayOfJavaLangObjectTest(node, cg, objClassReg, falseLabel, srm) ;8244generateS390BranchInstruction(cg, TR::InstOpCode::BRC, branchCond, node, branchLabel);8245generateGoToFalseBRC = false;8246break;8247}8248/** Following switch case generates sequence of instructions for cast class cache test8249* Load castClassCacheReg, offsetOf(J9Class,castClassCache)8250* castClassCacheReg <= castClassCacheReg XOR castClassReg8251* if castClassCacheReg == 0 (Success)8252* return true8253* else if castClassCacheReg == 1 (Failed instanceOf)8254* return false8255* else8256* continue8257*/8258case CastClassCacheTest:8259{8260doneTestCacheLabel = generateLabelSymbol(cg);8261if (comp->getOption(TR_TraceCG))8262traceMsg(comp,"Emitting CastClassCacheTest\n",node->getOpCode().getName());8263TR::Register *castClassCacheReg = srm->findOrCreateScratchRegister();8264generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, castClassCacheReg,8265generateS390MemoryReference(objClassReg, offsetof(J9Class, castClassCache), cg));8266generateRRInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node, castClassCacheReg, castClassReg);8267generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, trueLabel);8268generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, castClassCacheReg, 1, TR::InstOpCode::COND_BE, falseLabel, false, false);8269srm->reclaimScratchRegister(castClassCacheReg);8270break;8271}8272case DynamicCacheObjectClassTest:8273{8274generateDynamicCache = true;8275dynamicCacheTestLabel = generateLabelSymbol(cg);8276if (comp->getOption(TR_TraceCG))8277traceMsg(comp,"Emitting Dynamic Cache for ObjectClass only\n",node->getOpCode().getName());8278break;8279}8280case DynamicCacheDynamicCastClassTest:8281{8282generateDynamicCache = true;8283cacheCastClass = true;8284TR_ASSERT(dynamicCacheTestLabel!=NULL, "DynamicCacheDynamicCastClassTest: dynamicCacheTestLabel should be generated by SuperClassTest before reaching this point");8285if (comp->getOption(TR_TraceCG))8286traceMsg(comp,"Emitting Dynamic Cache for CastClass and ObjectClass\n",node->getOpCode().getName());8287break;8288}8289case HelperCall:8290TR_ASSERT(false, "Doesn't make sense, HelperCall should be the terminal sequence");8291break;8292default:8293break;8294}8295--numSequencesRemaining;8296++iter;8297}82988299TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(graDeps, 0, 8+srm->numAvailableRegisters(), cg);8300if (numSequencesRemaining > 0 && *iter == HelperCall)8301genInstanceOfDynamicCacheAndHelperCall(node, cg, castClassReg, objClassReg, resultReg, conditions, srm, doneLabel, callLabel, dynamicCacheTestLabel, branchLabel, trueLabel, falseLabel, dynamicCastClass, generateDynamicCache, cacheCastClass, ifInstanceOf, trueFallThrough);83028303if (needResult)8304{8305generateS390LabelInstruction(cg, TR::InstOpCode::label, node, oppositeResultLabel);8306generateRIInstruction(cg,TR::InstOpCode::getLoadHalfWordImmOpCode(),node,resultReg,static_cast<int32_t>(!initialResult));8307}83088309if (objClassReg)8310conditions->addPostConditionIfNotAlreadyInserted(objClassReg, TR::RealRegister::AssignAny);8311if (needResult)8312conditions->addPostCondition(resultReg, TR::RealRegister::AssignAny);8313conditions->addPostConditionIfNotAlreadyInserted(objectReg, TR::RealRegister::AssignAny);8314if (castClassReg)8315conditions->addPostConditionIfNotAlreadyInserted(castClassReg, TR::RealRegister::AssignAny);8316srm->addScratchRegistersToDependencyList(conditions);8317generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);8318if (objClassReg)8319cg->stopUsingRegister(objClassReg);8320if (castClassReg)8321cg->stopUsingRegister(castClassReg);8322srm->stopUsingRegisters();8323cg->decReferenceCount(objectNode);8324cg->decReferenceCount(castClassNode);8325TR::Register *ret = needResult ? resultReg : NULL;8326conditions->stopUsingDepRegs(cg, objectReg, ret);8327if (needResult)8328node->setRegister(resultReg);8329return resultReg;8330}83318332/** \brief Sets up parameters for VMgenCoreInstanceOfEvaluator when we have a ifInstanceOf node8333* \details8334* For ifInstanceOf node, it checks if the node has GRA dependency node as third child and if it has, calls normal instanceOf8335* Otherwise calls VMgenCoreInstanceOfEvaluator with parameters to generate instructions for ifInstanceOf.8336*/8337TR::Register *8338J9::Z::TreeEvaluator::VMifInstanceOfEvaluator(TR::Node * node, TR::CodeGenerator * cg)8339{8340TR::Node * graDepNode = NULL;8341TR::ILOpCodes opCode = node->getOpCodeValue();8342TR::Node * instanceOfNode = node->getFirstChild();8343TR::Node * valueNode = node->getSecondChild();8344int32_t value = valueNode->getInt();8345TR::LabelSymbol * branchLabel = node->getBranchDestination()->getNode()->getLabel();8346TR::RegisterDependencyConditions * graDeps = NULL;83478348TR::LabelSymbol * falseLabel = NULL;8349TR::LabelSymbol * trueLabel = NULL;83508351if (node->getNumChildren() == 3)8352{8353graDepNode = node->getChild(2);8354}83558356if (graDepNode && graDepsConflictWithInstanceOfDeps(graDepNode, instanceOfNode, cg))8357{8358return (TR::Register*) 1;8359}83608361bool needResult = (instanceOfNode->getReferenceCount() > 1);83628363if ((opCode == TR::ificmpeq && value == 1) || (opCode != TR::ificmpeq && value == 0))8364trueLabel = branchLabel;8365else8366falseLabel = branchLabel;83678368if (graDepNode)8369{8370cg->evaluate(graDepNode);8371graDeps = generateRegisterDependencyConditions(cg, graDepNode, 0);8372}8373bool initialResult = trueLabel != NULL;83748375VMgenCoreInstanceofEvaluator(instanceOfNode, cg, trueLabel, falseLabel, initialResult, needResult, graDeps, true);83768377cg->decReferenceCount(instanceOfNode);8378node->setRegister(NULL);83798380return NULL;8381}83828383/**8384* Generates a quick runtime test for valueType/valueBased node and in case if node is of valueType or valueBased, generates a branch to helper call8385*8386* @param node monent/exit node8387* @param mergeLabel Label pointing to merge point8388* @param helperCallLabel Label pointing to helper call dispatch sequence.8389* @param cg Codegenerator object8390* @return Returns a register containing objectClassPointer8391*/8392static TR::Register*8393generateCheckForValueMonitorEnterOrExit(TR::Node *node, TR::LabelSymbol* mergeLabel, TR::LabelSymbol *helperCallLabel, TR::CodeGenerator *cg)8394{8395TR::Register *objReg = cg->evaluate(node->getFirstChild());8396TR::Register *objectClassReg = cg->allocateRegister();83978398TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, objectClassReg, generateS390MemoryReference(objReg, TR::Compiler->om.offsetOfObjectVftField(), cg), NULL);83998400TR::Register *tempReg = cg->allocateRegister();8401generateLoad32BitConstant(cg, node, J9_CLASS_DISALLOWS_LOCKING_FLAGS, tempReg, false);84028403TR::MemoryReference *classFlagsMemRef = generateS390MemoryReference(objectClassReg, static_cast<uint32_t>(static_cast<TR_J9VMBase *>(cg->comp()->fe())->getOffsetOfClassFlags()), cg);8404generateRXInstruction(cg, TR::InstOpCode::N, node, tempReg, classFlagsMemRef);84058406bool generateOOLSection = helperCallLabel == NULL;8407if (generateOOLSection)8408helperCallLabel = generateLabelSymbol(cg);84098410generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRNZ, node, helperCallLabel);84118412// TODO: There is now the possibility of multiple distinct OOL sections with helper calls to be generated when8413// evaluating the TR::monent or TR::monexit nodes:8414//8415// 1. Monitor cache lookup OOL8416// 2. Lock reservation OOL8417// 3. Value types or value based object OOL8418// 4. Recursive CAS sequence for Locking8419//8420// These distinct OOL sections may perform non-trivial logic but what they all have in common is they all have a8421// call to the same JIT helper which acts as a fall back. This complexity exists because of the way the evaluators8422// are currently architected and due to the restriction that we cannot have nested OOL code sections. Whenever8423// making future changes to these evaluators we should consider refactoring them to reduce the complexity and8424// attempt to consolidate the calls to the JIT helper so as to not have multiple copies.8425if (generateOOLSection)8426{8427TR_S390OutOfLineCodeSection *helperCallOOLSection = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(helperCallLabel, mergeLabel, cg);8428cg->getS390OutOfLineCodeSectionList().push_front(helperCallOOLSection);8429helperCallOOLSection->swapInstructionListsWithCompilation();84308431TR::Instruction *cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, helperCallLabel);84328433TR_Debug *debugObj = cg->getDebug();8434if (debugObj)8435debugObj->addInstructionComment(cursor, "Denotes Start of OOL for ValueType or ValueBased Node");84368437cg->getLinkage(TR_CHelper)->buildDirectDispatch(node);8438cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, mergeLabel);84398440if (debugObj)8441debugObj->addInstructionComment(cursor, "Denotes End of OOL for ValueType or ValueBased Node");84428443helperCallOOLSection->swapInstructionListsWithCompilation();8444}84458446cg->stopUsingRegister(tempReg);8447return objectClassReg;8448}84498450TR::Register *8451J9::Z::TreeEvaluator::VMmonentEvaluator(TR::Node * node, TR::CodeGenerator * cg)8452{8453TR::Compilation *comp = cg->comp();8454TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());8455int32_t lwOffset = fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node));8456J9::Z::CHelperLinkage *helperLink = static_cast<J9::Z::CHelperLinkage*>(cg->getLinkage(TR_CHelper));8457TR_YesNoMaybe isMonitorValueBasedOrValueType = cg->isMonitorValueBasedOrValueType(node);84588459if ((isMonitorValueBasedOrValueType == TR_yes) ||8460comp->getOption(TR_DisableInlineMonEnt) ||8461comp->getOption(TR_FullSpeedDebug)) // Required for Live Monitor Meta Data in FSD.8462{8463TR::ILOpCodes opCode = node->getOpCodeValue();8464TR::Node::recreate(node, TR::call);8465TR::Register *targetRegister = helperLink->buildDirectDispatch(node);8466cg->decReferenceCount(node->getFirstChild());8467TR::Node::recreate(node, opCode);8468return targetRegister;8469}847084718472TR_S390ScratchRegisterManager *srm = cg->generateScratchRegisterManager();84738474TR::Node *objNode = node->getFirstChild();8475TR::Register *objReg = cg->evaluate(objNode);8476TR::Register *baseReg = objReg;8477TR::Register *monitorReg = cg->allocateRegister();8478TR::Register *objectClassReg = NULL;8479TR::Register *lookupOffsetReg = NULL;8480TR::Register *tempRegister = NULL;8481TR::Register *metaReg = cg->getMethodMetaDataRealRegister();8482TR::Register *wasteReg = NULL;8483TR::Register *lockPreservingReg = NULL;8484TR::Register *dummyResultReg = NULL;848584868487TR::LabelSymbol *cFlowRegionEnd = generateLabelSymbol(cg);8488TR::LabelSymbol *callLabel = generateLabelSymbol(cg);8489TR::LabelSymbol *monitorLookupCacheLabel = generateLabelSymbol(cg);8490TR::Instruction *gcPoint = NULL;8491TR::Instruction *startICF = NULL;8492static char * disableInlineRecursiveMonitor = feGetEnv("TR_DisableInlineRecursiveMonitor");84938494bool inlineRecursive = true;8495if (disableInlineRecursiveMonitor)8496inlineRecursive = false;84978498int32_t numDeps = 4;84998500if (lwOffset <=0)8501{8502numDeps +=2;8503if (comp->getOption(TR_EnableMonitorCacheLookup))8504{8505numDeps +=2; // extra one for lit pool reg in disableZ9 mode8506}8507}85088509if (comp->getOptions()->enableDebugCounters())8510numDeps += 5;8511bool simpleLocking = false;8512bool reserveLocking = false, normalLockWithReservationPreserving = false;85138514if (isMonitorValueBasedOrValueType == TR_maybe)8515{8516numDeps += 1;8517// If we are generating code for MonitorCacheLookup then we will not have a separate OOL for inlineRecursive, and callLabel points8518// to the OOL Containing only helper call. Otherwise, OOL will have other code apart from helper call which we do not want to execute8519// for ValueType or ValueBased object and in that scenario we will need to generate another OOL that just contains helper call.8520objectClassReg = generateCheckForValueMonitorEnterOrExit(node, cFlowRegionEnd, lwOffset <= 0 ? callLabel : NULL, cg);8521}8522TR::RegisterDependencyConditions * conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numDeps, cg);85238524TR_Debug * debugObj = cg->getDebug();852585268527conditions->addPostCondition(objReg, TR::RealRegister::AssignAny);8528conditions->addPostCondition(monitorReg, TR::RealRegister::AssignAny);8529if (objectClassReg != NULL)8530conditions->addPostCondition(objectClassReg, TR::RealRegister::AssignAny);85318532static const char * peekFirst = feGetEnv("TR_PeekingMonEnter");8533// This debug option is for printing the locking mechanism.8534static int printMethodSignature = feGetEnv("PrintMethodSignatureForLockResEnt")? 1 : 0;8535if (lwOffset <= 0)8536{8537inlineRecursive = false;8538// should not happen often, only on a subset of objects that don't have a lockword8539// set with option -Xlockword85408541TR::LabelSymbol *helperCallLabel = generateLabelSymbol(cg);8542TR::LabelSymbol *helperReturnOOLLabel = generateLabelSymbol(cg);8543TR::MemoryReference * tempMR = NULL;8544if (objectClassReg == NULL)8545{8546tempMR = generateS390MemoryReference(objReg, TR::Compiler->om.offsetOfObjectVftField(), cg);8547// TODO We don't need objectClassReg except in this ifCase. We can use scratchRegisterManager to allocate one here.8548objectClassReg = cg->allocateRegister();8549conditions->addPostCondition(objectClassReg, TR::RealRegister::AssignAny);8550TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, objectClassReg, tempMR, NULL);8551}8552int32_t offsetOfLockOffset = offsetof(J9Class, lockOffset);8553tempMR = generateS390MemoryReference(objectClassReg, offsetOfLockOffset, cg);85548555tempRegister = cg->allocateRegister();8556TR::LabelSymbol *targetLabel = callLabel;8557if (comp->getOption(TR_EnableMonitorCacheLookup))8558targetLabel = monitorLookupCacheLabel;85598560generateRXInstruction(cg, TR::InstOpCode::getLoadTestOpCode(), node, tempRegister, tempMR);85618562TR::Instruction *cmpInstr = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, targetLabel);85638564if(cg->comp()->target().is64Bit())8565generateRXInstruction(cg, TR::InstOpCode::LA, node, tempRegister, generateS390MemoryReference(objReg, tempRegister, 0, cg));8566else8567generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, tempRegister, objReg);85688569if (comp->getOption(TR_EnableMonitorCacheLookup))8570{8571TR::RegisterDependencyConditions * OOLConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 5, cg);8572OOLConditions->addPostCondition(objReg, TR::RealRegister::AssignAny);8573OOLConditions->addPostCondition(monitorReg, TR::RealRegister::AssignAny);8574OOLConditions->addPostCondition(tempRegister, TR::RealRegister::AssignAny);8575// pulling this chunk of code into OOL sequence for better Register allocation and avoid branches8576TR_S390OutOfLineCodeSection *monitorCacheLookupOOL;8577monitorCacheLookupOOL = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(monitorLookupCacheLabel,cFlowRegionEnd,cg);8578cg->getS390OutOfLineCodeSectionList().push_front(monitorCacheLookupOOL);8579monitorCacheLookupOOL->swapInstructionListsWithCompilation();85808581TR::Instruction *cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, monitorLookupCacheLabel);85828583if (debugObj)8584{8585debugObj->addInstructionComment(cmpInstr, "Branch to OOL monent monitorLookupCache");8586debugObj->addInstructionComment(cursor, "Denotes start of OOL monent monitorLookupCache");8587}85888589lookupOffsetReg = cg->allocateRegister();8590OOLConditions->addPostCondition(lookupOffsetReg, TR::RealRegister::AssignAny);85918592int32_t offsetOfMonitorLookupCache = offsetof(J9VMThread, objectMonitorLookupCache);8593int32_t t = trailingZeroes(TR::Compiler->om.getObjectAlignmentInBytes());8594int32_t shiftAmount = trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()) - t;8595int32_t end = 63 - trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField());8596int32_t start = end - trailingZeroes(J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE) + 1;85978598if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_S390_ZEC12) && cg->comp()->target().is64Bit())8599generateRIEInstruction(cg, TR::InstOpCode::RISBGN, node, lookupOffsetReg, objReg, start, end+0x80, shiftAmount);8600else if(cg->comp()->target().is64Bit())8601generateRIEInstruction(cg, TR::InstOpCode::RISBG, node, lookupOffsetReg, objReg, start, end+0x80, shiftAmount);8602else8603{8604generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, lookupOffsetReg, objReg);86058606if (cg->comp()->target().is64Bit())8607generateRSInstruction(cg, TR::InstOpCode::SRAG, node, lookupOffsetReg, lookupOffsetReg, t);8608else8609generateRSInstruction(cg, TR::InstOpCode::SRA, node, lookupOffsetReg, t);86108611J9JavaVM * jvm = fej9->getJ9JITConfig()->javaVM;86128613if (cg->comp()->target().is32Bit())8614generateS390ImmOp(cg, TR::InstOpCode::getAndOpCode(), node, lookupOffsetReg, lookupOffsetReg, (int32_t) J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, OOLConditions, 0);8615else8616generateS390ImmOp(cg, TR::InstOpCode::getAndOpCode(), node, lookupOffsetReg, lookupOffsetReg, (int64_t) J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, OOLConditions, 0);86178618if (cg->comp()->target().is64Bit())8619generateRSInstruction(cg, TR::InstOpCode::SLLG, node, lookupOffsetReg, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));8620else8621generateRSInstruction(cg, TR::InstOpCode::SLL, node, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));8622}86238624TR::MemoryReference * temp2MR = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(), lookupOffsetReg, offsetOfMonitorLookupCache, cg);86258626if (TR::Compiler->om.compressObjectReferences())8627{8628generateRXInstruction(cg, TR::InstOpCode::LLGF, node, tempRegister, temp2MR, NULL);8629startICF = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, tempRegister, NULLVALUE, TR::InstOpCode::COND_BE, helperCallLabel, false, true);8630}8631else8632{8633generateRXInstruction(cg, TR::InstOpCode::getLoadTestOpCode(), node, tempRegister, temp2MR);8634startICF = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, helperCallLabel);8635}86368637int32_t offsetOfMonitor = offsetof(J9ObjectMonitor, monitor);8638temp2MR = generateS390MemoryReference(tempRegister, offsetOfMonitor, cg);8639generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, objReg, temp2MR);8640generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, helperCallLabel);86418642int32_t offsetOfAlternateLockWord = offsetof(J9ObjectMonitor, alternateLockword);86438644baseReg = tempRegister;8645lwOffset = 0 + offsetOfAlternateLockWord;86468647if (cg->comp()->target().is64Bit() && fej9->generateCompressedLockWord())8648generateRRInstruction(cg, TR::InstOpCode::XR, node, monitorReg, monitorReg);8649else8650generateRRInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node, monitorReg, monitorReg);86518652if (peekFirst)8653{8654generateRXInstruction(cg, TR::InstOpCode::C, node, monitorReg, generateS390MemoryReference(baseReg, lwOffset, cg));8655generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, helperCallLabel);8656}86578658if (cg->comp()->target().is64Bit() && fej9->generateCompressedLockWord())8659generateRSInstruction(cg, TR::InstOpCode::CS, node, monitorReg, metaReg,8660generateS390MemoryReference(baseReg, lwOffset, cg));8661else8662generateRSInstruction(cg, TR::InstOpCode::getCmpAndSwapOpCode(), node, monitorReg, metaReg,8663generateS390MemoryReference(baseReg, lwOffset, cg));86648665generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, helperReturnOOLLabel);8666generateS390LabelInstruction(cg, TR::InstOpCode::label, node, helperCallLabel );8667TR::RegisterDependencyConditions *deps = NULL;8668dummyResultReg = helperLink->buildDirectDispatch(node, &deps);8669TR::RegisterDependencyConditions *mergeConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(OOLConditions, deps, cg);8670generateS390LabelInstruction(cg, TR::InstOpCode::label, node, helperReturnOOLLabel , mergeConditions);86718672cursor = generateS390BranchInstruction(cg,TR::InstOpCode::BRC,TR::InstOpCode::COND_BRC,node,cFlowRegionEnd);8673if (debugObj)8674debugObj->addInstructionComment(cursor, "Denotes end of OOL monent monitorCacheLookup: return to mainline");86758676// Done using OOL with manual code generation8677monitorCacheLookupOOL->swapInstructionListsWithCompilation();8678}86798680simpleLocking = true;8681lwOffset = 0;8682baseReg = tempRegister;8683}86848685// Lock Reservation happens only for objects with lockword.8686// evaluateLockForReservation may output three different results:8687// 1- Lock Reservation: (reserveLocking = true)8688// 2- ReservationPreserving: (normalLockWithReservationPreserving = true)8689// 3- Normal lock: otherwise8690if (!simpleLocking && comp->getOption(TR_ReservingLocks))8691TR::TreeEvaluator::evaluateLockForReservation(node, &reserveLocking, &normalLockWithReservationPreserving, cg);86928693if (printMethodSignature)8694printf("%s:\t%s\t%s\n",simpleLocking ? "lwOffset <= 0" : reserveLocking ? "Lock Reservation" :8695normalLockWithReservationPreserving ? "Reservation Preserving" : "Normal Lock",8696comp->signature(),comp->getHotnessName(comp->getMethodHotness()));86978698if (reserveLocking)8699{87008701// TODO - ScratchRegisterManager Should Manage these temporary Registers.8702if (wasteReg)8703cg->stopUsingRegister(wasteReg);8704cg->stopUsingRegister(monitorReg);8705// TODO : objectClassReg contains the J9Class for object which is set in lwOffset <= 0 case. Usually that is NULL in the following function call8706return reservationLockEnter(node, lwOffset, objectClassReg, cg, helperLink);8707}87088709if (normalLockWithReservationPreserving)8710{8711lockPreservingReg = cg->allocateRegister();8712conditions->addPostCondition(lockPreservingReg, TR::RealRegister::AssignAny);8713}8714const char* debugCounterNamePrefix = normalLockWithReservationPreserving? "LockEnt/Preserving": "LockEnt/Normal";8715// Opcodes:8716bool use64b = true;8717if (cg->comp()->target().is64Bit() && fej9->generateCompressedLockWord())8718use64b = false;8719else if (!cg->comp()->target().is64Bit())8720use64b = false;8721TR::InstOpCode::Mnemonic loadOp = use64b ? TR::InstOpCode::LG : TR::InstOpCode::L;8722TR::InstOpCode::Mnemonic loadRegOp = use64b ? TR::InstOpCode::LGR : TR::InstOpCode::LR;8723TR::InstOpCode::Mnemonic orImmOp = TR::InstOpCode::OILF;8724TR::InstOpCode::Mnemonic compareOp = use64b ? TR::InstOpCode::CGR : TR::InstOpCode::CR;8725TR::InstOpCode::Mnemonic addImmOp = use64b ? TR::InstOpCode::AGHI : TR::InstOpCode::AHI;8726TR::InstOpCode::Mnemonic storeOp = use64b ? TR::InstOpCode::STG : TR::InstOpCode::ST;8727TR::InstOpCode::Mnemonic xorOp = use64b ? TR::InstOpCode::XGR : TR::InstOpCode::XR;8728TR::InstOpCode::Mnemonic casOp = use64b ? TR::InstOpCode::CSG : TR::InstOpCode::CS;8729TR::InstOpCode::Mnemonic andOp = use64b ? TR::InstOpCode::NGR : TR::InstOpCode::NR;8730TR::InstOpCode::Mnemonic loadHalfWordImmOp = use64b ? TR::InstOpCode::LGHI : TR::InstOpCode::LHI;87318732// MonitorReg = 08733generateRRInstruction(cg, xorOp, node, monitorReg, monitorReg);87348735// PeekFirst option read the lock value first and then issue CAS only the lock value is zero.8736// This causes an extra load operation when the lock is free, but it leads to avoidance of unnecessary CAS operations.8737if (peekFirst)8738{8739generateRXInstruction(cg, TR::InstOpCode::C, node, monitorReg, generateS390MemoryReference(baseReg, lwOffset, cg));8740generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, callLabel);8741}8742// Main path instruction sequence.8743// This sequence is the same for both normal locks and lock preservation.8744// XR monitorReg,monitorReg8745// CS monitorReg,GPR13,#lwOffset(objectReg)8746// BRC BLRC(0x4), callLabel (OOL path)87478748//Compare and Swap the lock value with R13 if the lock value is 0.8749generateRSInstruction(cg, casOp, node, monitorReg, metaReg, generateS390MemoryReference(baseReg, lwOffset, cg));87508751// Jump to OOL branch in case that the CAS is unsuccessful (Lockword had contained a non-zero value before CAS)8752// Both TR::InstOpCode::MASK6 and TR::InstOpCode::MASK4 are ok here. TR::InstOpCode::MASK4 is directly testing failure condition.8753generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BL, node, callLabel);8754cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "%s/CSSuccessfull", debugCounterNamePrefix), 1, TR::DebugCounter::Undetermined);8755TR_S390OutOfLineCodeSection *outlinedHelperCall = NULL;8756TR::Instruction *cursor;8757TR::LabelSymbol *returnLabel = generateLabelSymbol(cg);87588759outlinedHelperCall = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(callLabel, cFlowRegionEnd, cg);8760cg->getS390OutOfLineCodeSectionList().push_front(outlinedHelperCall);8761outlinedHelperCall->swapInstructionListsWithCompilation();8762cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, callLabel);8763if (debugObj)8764debugObj->addInstructionComment(cursor, "Denotes start of OOL monent sequence");87658766if (inlineRecursive)8767{8768TR::LabelSymbol * callHelper = generateLabelSymbol(cg);87698770//Using OOL but generating code manually8771//Tasuki lock, inlined nested monitor handling8772//(on entry objectReg has been set up)87738774// Normal Lock Lock reservation preserving8775// L monitorReg, #lwOffset(objectReg) L monitorReg, #lwOffset(objectReg)8776// LHI wasteReg, NON_INC_DEC_MASK DIFF LHI wasteReg, LOCK_RES_PRESERVE_ENTER8777// AHI monitorReg, INC_DEC_VALUE DIFF8778// NR wasteReg, monitorReg NR wasteReg, monitorReg8779// DIFF LR lockPreservingReg, metaReg8780// DIFF OILF lockPreservingReg, LR-BIT8781// CRJ wasteReg, metaReg, MASK6, callHelper DIFF CRJ wasteReg, lockPreservingReg, MASK6, callHelper8782// DIFF AHI monitorReg,INC_DEC_VALUE8783// ST monitorReg, #lwOffset(objectReg) ST monitorReg, #lwOffset(objectReg)8784// BRC returnLabel BRC returnLabel8785// callHelper: callHelper:8786// BRASL R14, jitMonitorEnter BRASL R14, jitMonitorEnter8787// returnLabel: returnLabel:87888789TR::MemoryReference * tempMR = generateS390MemoryReference(baseReg, lwOffset, cg);8790TR::MemoryReference * tempMR1 = generateS390MemoryReference(baseReg, lwOffset, cg);8791wasteReg = cg->allocateRegister();8792conditions->addPostCondition(wasteReg, TR::RealRegister::AssignAny);8793// Loading Lock value into monitorReg8794generateRXInstruction(cg, loadOp, node, monitorReg, tempMR);8795generateRIInstruction(cg, loadHalfWordImmOp, node, wasteReg,8796normalLockWithReservationPreserving ? ~LOCK_RES_PRESERVE_ENTER_COMPLEMENT : ~OBJECT_HEADER_LOCK_RECURSION_MASK);87978798// In normal lock, we first increment the counter and then do the mask and comparison.8799// However, in lock preserving first we do mask and compare and then we increment the counter8800// We can do the same technique for both. The reason for current implementation is to expose less differences between8801// this implementation and other architecture implementations.8802if (!normalLockWithReservationPreserving)8803generateRIInstruction(cg, addImmOp, node, monitorReg, OBJECT_HEADER_LOCK_FIRST_RECURSION_BIT);8804// Mask out the counter value from lockword.8805generateRRInstruction(cg, andOp, node, wasteReg, monitorReg);8806if (normalLockWithReservationPreserving)8807{8808generateRRInstruction(cg,loadRegOp, node, lockPreservingReg, metaReg);8809generateRILInstruction(cg, orImmOp, node, lockPreservingReg, LOCK_RESERVATION_BIT);8810}88118812// The lock value (after masking out the counter) is being compared with R13 (or R13|LRbit for reservation preserving case)8813// to check whether the same thread has acquired the lock before.8814// if comparison fails (masked lock value != R13) that means another thread owns the lock.8815// In this case we call helper function and let the VM handle the situation.8816startICF = generateS390CompareAndBranchInstruction(cg, compareOp, node, wasteReg, normalLockWithReservationPreserving ? lockPreservingReg : metaReg, TR::InstOpCode::COND_BNE, callHelper, false, false);88178818cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "%s/Recursive", debugCounterNamePrefix), 1, TR::DebugCounter::Undetermined);8819// In case of recursive lock, the counter should be incremented.8820if (normalLockWithReservationPreserving)8821generateRIInstruction(cg, addImmOp, node, monitorReg, OBJECT_HEADER_LOCK_FIRST_RECURSION_BIT);8822generateRXInstruction(cg, storeOp, node, monitorReg, tempMR1);88238824generateS390BranchInstruction(cg,TR::InstOpCode::BRC,TR::InstOpCode::COND_BRC,node,returnLabel);88258826tempMR->stopUsingMemRefRegister(cg);8827tempMR1->stopUsingMemRefRegister(cg);88288829// Helper Call8830cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, callHelper);8831}88328833cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "%s/VMHelper", debugCounterNamePrefix), 1, TR::DebugCounter::Undetermined);8834TR::RegisterDependencyConditions *deps = NULL;8835dummyResultReg = inlineRecursive ? helperLink->buildDirectDispatch(node, &deps) : helperLink->buildDirectDispatch(node);8836TR::RegisterDependencyConditions *mergeConditions = NULL;8837if (inlineRecursive)8838mergeConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(conditions, deps, cg);8839else8840mergeConditions = conditions;8841generateS390LabelInstruction(cg,TR::InstOpCode::label,node,returnLabel,mergeConditions);88428843// End of OOl path.8844cursor = generateS390BranchInstruction(cg,TR::InstOpCode::BRC,TR::InstOpCode::COND_BRC,node,cFlowRegionEnd);8845if (debugObj)8846{8847debugObj->addInstructionComment(cursor, "Denotes end of OOL monent: return to mainline");8848}88498850// Done using OOL with manual code generation8851outlinedHelperCall->swapInstructionListsWithCompilation();88528853generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, conditions);88548855cg->stopUsingRegister(monitorReg);8856if (wasteReg)8857cg->stopUsingRegister(wasteReg);8858if (objectClassReg)8859cg->stopUsingRegister(objectClassReg);8860if (lookupOffsetReg)8861cg->stopUsingRegister(lookupOffsetReg);8862if (tempRegister && (tempRegister != objectClassReg))8863cg->stopUsingRegister(tempRegister);8864if (lockPreservingReg)8865cg->stopUsingRegister(lockPreservingReg);8866cg->decReferenceCount(objNode);8867return NULL;8868}88698870TR::Register *8871J9::Z::TreeEvaluator::VMmonexitEvaluator(TR::Node * node, TR::CodeGenerator * cg)8872{8873TR::Compilation *comp = cg->comp();8874TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());8875int32_t lwOffset = fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node));8876J9::Z::CHelperLinkage *helperLink = static_cast<J9::Z::CHelperLinkage*>(cg->getLinkage(TR_CHelper));8877TR_YesNoMaybe isMonitorValueBasedOrValueType = cg->isMonitorValueBasedOrValueType(node);88788879if ((isMonitorValueBasedOrValueType == TR_yes) ||8880comp->getOption(TR_DisableInlineMonExit) ||8881comp->getOption(TR_FullSpeedDebug)) // Required for Live Monitor Meta Data in FSD.8882{8883TR::ILOpCodes opCode = node->getOpCodeValue();8884TR::Node::recreate(node, TR::call);8885TR::Register * targetRegister = helperLink->buildDirectDispatch(node);8886cg->decReferenceCount(node->getFirstChild());8887TR::Node::recreate(node, opCode);8888return targetRegister;8889}88908891TR::Node *objNode = node->getFirstChild();889288938894//TODO Use scratchRegisterManager here to avoid allocating un-necessary registers8895TR::Register *dummyResultRegister = NULL;8896TR::Register *objReg = cg->evaluate(objNode);8897TR::Register *baseReg = objReg;8898TR::Register *objectClassReg = NULL;8899TR::Register *lookupOffsetReg = NULL;8900TR::Register *tempRegister = NULL;8901TR::Register *monitorReg = cg->allocateRegister();8902TR::Register *metaReg = cg->getMethodMetaDataRealRegister();8903TR::Register *scratchRegister = NULL;8904TR::Instruction *startICF = NULL;89058906static char * disableInlineRecursiveMonitor = feGetEnv("TR_DisableInlineRecursiveMonitor");8907bool inlineRecursive = true;8908if (disableInlineRecursiveMonitor)8909inlineRecursive = false;89108911TR::LabelSymbol *callLabel = generateLabelSymbol(cg);8912TR::LabelSymbol *monitorLookupCacheLabel = generateLabelSymbol(cg);8913TR::LabelSymbol *cFlowRegionEnd = generateLabelSymbol(cg);8914TR::LabelSymbol *callHelper = generateLabelSymbol(cg);8915TR::LabelSymbol *returnLabel = generateLabelSymbol(cg);89168917int32_t numDeps = 4;8918if (lwOffset <=0)8919{8920numDeps +=2;8921if (comp->getOption(TR_EnableMonitorCacheLookup))8922{8923numDeps +=2; // extra one for lit pool reg in disableZ9 mode8924}8925}89268927if (comp->getOptions()->enableDebugCounters())8928numDeps += 4;89298930if (isMonitorValueBasedOrValueType == TR_maybe)8931{8932numDeps += 1;8933objectClassReg = generateCheckForValueMonitorEnterOrExit(node, cFlowRegionEnd, lwOffset <= 0 ? callLabel : NULL, cg);8934}8935TR::RegisterDependencyConditions * conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numDeps, cg);893689378938TR::Instruction * gcPoint;8939TR_Debug * debugObj = cg->getDebug();89408941bool reserveLocking = false;8942bool normalLockWithReservationPreserving = false;8943bool simpleLocking = false;894489458946conditions->addPostCondition(objReg, TR::RealRegister::AssignAny);8947conditions->addPostCondition(monitorReg, TR::RealRegister::AssignAny);8948if (objectClassReg != NULL)8949conditions->addPostCondition(objectClassReg, TR::RealRegister::AssignAny);895089518952if (lwOffset <= 0)8953{8954inlineRecursive = false; // should not happen often, only on a subset of objects that don't have a lockword, set with option -Xlockword89558956TR::LabelSymbol *helperCallLabel = generateLabelSymbol(cg);8957TR::LabelSymbol *helperReturnOOLLabel = generateLabelSymbol(cg);8958TR::MemoryReference *tempMR = NULL;89598960if (objectClassReg == NULL)8961{8962tempMR = generateS390MemoryReference(objReg, TR::Compiler->om.offsetOfObjectVftField(), cg);8963objectClassReg = cg->allocateRegister();8964conditions->addPostCondition(objectClassReg, TR::RealRegister::AssignAny);8965TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, objectClassReg, tempMR, NULL);8966}8967int32_t offsetOfLockOffset = offsetof(J9Class, lockOffset);8968tempMR = generateS390MemoryReference(objectClassReg, offsetOfLockOffset, cg);89698970tempRegister = cg->allocateRegister();8971TR::LabelSymbol *targetLabel = callLabel;8972if (comp->getOption(TR_EnableMonitorCacheLookup))8973targetLabel = monitorLookupCacheLabel;89748975generateRXInstruction(cg, TR::InstOpCode::getLoadTestOpCode(), node, tempRegister, tempMR);89768977TR::Instruction *cmpInstr = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, targetLabel);89788979if(comp->target().is64Bit())8980generateRXInstruction(cg, TR::InstOpCode::LA, node, tempRegister, generateS390MemoryReference(objReg, tempRegister, 0, cg));8981else8982generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, tempRegister, objReg);89838984if (comp->getOption(TR_EnableMonitorCacheLookup))8985{8986lookupOffsetReg = cg->allocateRegister();8987TR::RegisterDependencyConditions * OOLConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 5, cg);8988OOLConditions->addPostCondition(objReg, TR::RealRegister::AssignAny);8989OOLConditions->addPostCondition(monitorReg, TR::RealRegister::AssignAny);8990// TODO Should be using SRM for tempRegister8991OOLConditions->addPostCondition(tempRegister, TR::RealRegister::AssignAny);8992OOLConditions->addPostCondition(lookupOffsetReg, TR::RealRegister::AssignAny);899389948995// pulling this chunk of code into OOL sequence for better Register allocation and avoid branches8996TR_S390OutOfLineCodeSection *monitorCacheLookupOOL = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(monitorLookupCacheLabel,cFlowRegionEnd,cg);8997cg->getS390OutOfLineCodeSectionList().push_front(monitorCacheLookupOOL);8998monitorCacheLookupOOL->swapInstructionListsWithCompilation();89999000TR::Instruction *cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, monitorLookupCacheLabel);90019002if (debugObj)9003{9004debugObj->addInstructionComment(cmpInstr, "Branch to OOL monexit monitorLookupCache");9005debugObj->addInstructionComment(cursor, "Denotes start of OOL monexit monitorLookupCache");9006}900790089009int32_t offsetOfMonitorLookupCache = offsetof(J9VMThread, objectMonitorLookupCache);9010int32_t t = trailingZeroes(TR::Compiler->om.getObjectAlignmentInBytes());9011int32_t shiftAmount = trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()) - t;9012int32_t end = 63 - trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField());9013int32_t start = end - trailingZeroes(J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE) + 1;90149015if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_S390_ZEC12) && comp->target().is64Bit())9016generateRIEInstruction(cg, TR::InstOpCode::RISBGN, node, lookupOffsetReg, objReg, start, end+0x80, shiftAmount);9017else if(comp->target().is64Bit())9018generateRIEInstruction(cg, TR::InstOpCode::RISBG, node, lookupOffsetReg, objReg, start, end+0x80, shiftAmount);9019else9020{9021generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, lookupOffsetReg, objReg);90229023if (comp->target().is64Bit())9024generateRSInstruction(cg, TR::InstOpCode::SRAG, node, lookupOffsetReg, lookupOffsetReg, t);9025else9026generateRSInstruction(cg, TR::InstOpCode::SRA, node, lookupOffsetReg, t);90279028J9JavaVM * jvm = fej9->getJ9JITConfig()->javaVM;90299030if (comp->target().is32Bit())9031generateS390ImmOp(cg, TR::InstOpCode::getAndOpCode(), node, lookupOffsetReg, lookupOffsetReg, (int32_t) J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, OOLConditions, 0);9032else9033generateS390ImmOp(cg, TR::InstOpCode::getAndOpCode(), node, lookupOffsetReg, lookupOffsetReg, (int64_t) J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, OOLConditions, 0);90349035if (comp->target().is64Bit())9036generateRSInstruction(cg, TR::InstOpCode::SLLG, node, lookupOffsetReg, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));9037else9038generateRSInstruction(cg, TR::InstOpCode::SLL, node, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));9039}90409041// TODO No Need to use Memory Reference Here. Combine it with generateRXInstruction9042TR::MemoryReference * temp2MR = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(), lookupOffsetReg, offsetOfMonitorLookupCache, cg);90439044if (TR::Compiler->om.compressObjectReferences())9045{9046generateRXInstruction(cg, TR::InstOpCode::LLGF, node, tempRegister, temp2MR, NULL);9047startICF = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, tempRegister, NULLVALUE, TR::InstOpCode::COND_BE, helperCallLabel, false, true);9048}9049else9050{9051generateRXInstruction(cg, TR::InstOpCode::getLoadTestOpCode(), node, tempRegister, temp2MR);9052startICF = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, helperCallLabel);9053}90549055int32_t offsetOfMonitor = offsetof(J9ObjectMonitor, monitor);9056// TODO No Need to use Memory Reference Here. Combine it with generateRXInstruction9057temp2MR = generateS390MemoryReference(tempRegister, offsetOfMonitor, cg);9058generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, objReg, temp2MR);9059generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, helperCallLabel);90609061int32_t offsetOfAlternateLockWord = offsetof(J9ObjectMonitor, alternateLockword);90629063baseReg = tempRegister;9064lwOffset = 0 + offsetOfAlternateLockWord;90659066// Check if the lockWord in the object contains our VMThread9067if (comp->target().is64Bit() && fej9->generateCompressedLockWord())9068generateRXInstruction(cg, TR::InstOpCode::C, node, metaReg, generateS390MemoryReference(baseReg, lwOffset, cg));9069else9070generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, metaReg, generateS390MemoryReference(baseReg, lwOffset, cg));90719072// If VMThread does not match, call helper.9073TR::Instruction* helperBranch = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, helperCallLabel);90749075// If VMThread matches, we can safely perform the monitor exit by zero'ing9076// out the lockWord on the object9077if (comp->target().is64Bit() && fej9->generateCompressedLockWord())9078gcPoint = generateSILInstruction(cg, TR::InstOpCode::MVHI, node, generateS390MemoryReference(baseReg, lwOffset, cg), 0);9079else9080gcPoint = generateSILInstruction(cg, TR::InstOpCode::getMoveHalfWordImmOpCode(), node, generateS390MemoryReference(baseReg, lwOffset, cg), 0);90819082generateS390BranchInstruction(cg,TR::InstOpCode::BRC,TR::InstOpCode::COND_BRC,node,helperReturnOOLLabel);90839084generateS390LabelInstruction(cg, TR::InstOpCode::label , node, helperCallLabel );9085TR::RegisterDependencyConditions *deps = NULL;9086helperLink->buildDirectDispatch(node, &deps);9087TR::RegisterDependencyConditions *mergeConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(OOLConditions, deps, cg);9088generateS390LabelInstruction(cg, TR::InstOpCode::label, node, helperReturnOOLLabel , mergeConditions);90899090cursor = generateS390BranchInstruction(cg,TR::InstOpCode::BRC,TR::InstOpCode::COND_BRC,node,cFlowRegionEnd);9091if (debugObj)9092debugObj->addInstructionComment(cursor, "Denotes end of OOL monexit monitorCacheLookup: return to mainline");90939094// Done using OOL with manual code generation9095monitorCacheLookupOOL->swapInstructionListsWithCompilation();9096}90979098lwOffset = 0;9099baseReg = tempRegister;9100simpleLocking = true;9101}91029103// Lock Reservation happens only for objects with lockword.9104if (!simpleLocking && comp->getOption(TR_ReservingLocks))9105TR::TreeEvaluator::evaluateLockForReservation(node, &reserveLocking, &normalLockWithReservationPreserving, cg);9106if (reserveLocking)9107{9108// TODO - It would be much better to find a way not allocating these registers at the first place.9109cg->stopUsingRegister(monitorReg);9110return reservationLockExit(node, lwOffset, objectClassReg, cg, helperLink);9111}9112////////////9113// Opcodes:9114bool use64b = true;9115if (comp->target().is64Bit() && fej9->generateCompressedLockWord())9116use64b = false;9117else if (!comp->target().is64Bit())9118use64b = false;9119TR::InstOpCode::Mnemonic loadOp = use64b ? TR::InstOpCode::LG : TR::InstOpCode::L;9120TR::InstOpCode::Mnemonic loadRegOp = use64b ? TR::InstOpCode::LGR : TR::InstOpCode::LR;9121TR::InstOpCode::Mnemonic orImmOp = TR::InstOpCode::OILF;9122TR::InstOpCode::Mnemonic compareOp = use64b ? TR::InstOpCode::CGR : TR::InstOpCode::CR;9123TR::InstOpCode::Mnemonic compareImmOp = use64b ? TR::InstOpCode::CG : TR::InstOpCode::C;9124TR::InstOpCode::Mnemonic addImmOp = use64b ? TR::InstOpCode::AGHI : TR::InstOpCode::AHI;9125TR::InstOpCode::Mnemonic storeOp = use64b ? TR::InstOpCode::STG : TR::InstOpCode::ST;9126TR::InstOpCode::Mnemonic xorOp = use64b ? TR::InstOpCode::XGR : TR::InstOpCode::XR;9127TR::InstOpCode::Mnemonic casOp = use64b ? TR::InstOpCode::CSG : TR::InstOpCode::CS;9128TR::InstOpCode::Mnemonic loadImmOp = TR::InstOpCode::LGFI;9129TR::InstOpCode::Mnemonic andOp = use64b ? TR::InstOpCode::NGR : TR::InstOpCode::NR;9130TR::InstOpCode::Mnemonic andImmOp = TR::InstOpCode::NILF;9131TR::InstOpCode::Mnemonic moveImmOp = use64b ? TR::InstOpCode::MVGHI : TR::InstOpCode::MVHI;9132TR::InstOpCode::Mnemonic loadHalfWordImmOp = use64b ? TR::InstOpCode::LGHI : TR::InstOpCode::LHI;91339134// Main path instruction sequence.9135// This sequence is the same for both normal locks and lock preservation.9136// C metaReg, #lwOffset(objectReg)9137// BRC MASK6, callLabel9138// MVHI #lwOffset(objectReg), 091399140//TODO - use compareAndBranch instruction9141// Check if the lockWord in the object contains our VMThread9142generateRXInstruction(cg, compareImmOp, node, metaReg, generateS390MemoryReference(baseReg, lwOffset, cg));9143// If VMThread does not match, call helper.9144generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, callLabel);9145if (normalLockWithReservationPreserving)9146cg->generateDebugCounter("LockExit/Preserving/MVHISuccessfull", 1, TR::DebugCounter::Undetermined);9147else9148cg->generateDebugCounter("LockExit/Normal/MVHISuccessfull", 1, TR::DebugCounter::Undetermined);9149// If VMThread matches, we can safely perform the monitor exit by zero'ing9150// out the lockWord on the object9151generateSILInstruction(cg, moveImmOp, node, generateS390MemoryReference(baseReg, lwOffset, cg), 0);91529153TR_S390OutOfLineCodeSection *outlinedHelperCall = NULL;91549155outlinedHelperCall = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(callLabel,cFlowRegionEnd,cg);9156cg->getS390OutOfLineCodeSectionList().push_front(outlinedHelperCall);9157outlinedHelperCall->swapInstructionListsWithCompilation();91589159TR::Instruction *cursor = generateS390LabelInstruction(cg,TR::InstOpCode::label,node,callLabel);91609161if (inlineRecursive)9162{9163// inlineRecursive is only enabled when OOL is enabled9164if (debugObj)9165{9166debugObj->addInstructionComment(cursor, "Denotes start of OOL monexit sequence");9167}91689169// (on entry objectReg has been set up)91709171// Normal Lock Lock reservation preserving9172// L monitorReg, #lwOffset(objectReg) L monitorReg, #lwOffset(objectReg)9173// LHI wasteReg, ~LOCK_RECURSION_MASK LHI wasteReg, LOCK_OWNING_NON_INFLATED9174// AHI monitorReg, -INC_DEC_VALUE9175// NR wasteReg, monitorReg NR wasteReg, monitorReg9176// CRJ wasteReg, metaReg, MASK6, callHelper CRJ wasteReg, metaReg, MASK6, callHelper9177// LHI wasteReg, LOCK_RECURSION_MASK9178// NR wasteReg, monitorReg9179// BRC BERC, callHelper9180// LHI wasteReg, LOCK_OWNING_NON_INFLATED9181// NR wasteReg, monitorReg9182// CIJ wasteReg, callHelper, BERC, LOCK_RES_CONTENDED_VALUE9183// AHI monitorReg, -INC_DEC_VALUE9184// ST monitorReg, #lwOffset(objectReg) ST monitorReg, #lwOffset(objectReg)9185// BRC returnLabel BRC returnLabel9186// callHelper: callHelper:9187// BRASL R14,jitMonitorExit BRASL R14, jitMonitorExit9188// returnLabel: returnLabel:9189scratchRegister = cg->allocateRegister();9190conditions->addPostCondition(scratchRegister, TR::RealRegister::AssignAny);91919192TR::MemoryReference * tempMR = generateS390MemoryReference(baseReg, lwOffset, cg);9193TR::MemoryReference * tempMR1 = generateS390MemoryReference(baseReg, lwOffset, cg);9194if(!normalLockWithReservationPreserving)9195{9196generateRXInstruction(cg, loadOp, node, monitorReg, tempMR);9197generateRIInstruction(cg, loadHalfWordImmOp, node, scratchRegister, ~OBJECT_HEADER_LOCK_RECURSION_MASK);9198generateRIInstruction(cg, addImmOp, node, monitorReg, -OBJECT_HEADER_LOCK_FIRST_RECURSION_BIT);9199generateRRInstruction(cg, andOp, node, scratchRegister, monitorReg);9200startICF = generateS390CompareAndBranchInstruction(cg, compareOp, node, scratchRegister, metaReg, TR::InstOpCode::COND_BNE, callHelper, false, false);9201cg->generateDebugCounter("LockExit/Normal/Recursive", 1, TR::DebugCounter::Undetermined);9202generateRXInstruction(cg, storeOp, node, monitorReg, tempMR1);9203}9204else9205{9206generateRXInstruction(cg, loadOp, node, monitorReg, tempMR);9207generateRIInstruction(cg, loadHalfWordImmOp, node, scratchRegister, ~LOCK_OWNING_NON_INFLATED_COMPLEMENT);9208generateRRInstruction(cg, andOp, node, scratchRegister, monitorReg);9209startICF = generateS390CompareAndBranchInstruction(cg, compareOp, node, scratchRegister, metaReg, TR::InstOpCode::COND_BNE, callHelper, false, false);9210generateRIInstruction(cg, loadHalfWordImmOp, node, scratchRegister, OBJECT_HEADER_LOCK_RECURSION_MASK);9211generateRRInstruction(cg, andOp, node, scratchRegister, monitorReg);9212generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, callHelper);9213generateRIInstruction(cg, loadHalfWordImmOp, node, scratchRegister, LOCK_OWNING_NON_INFLATED_COMPLEMENT);9214generateRRInstruction(cg, andOp, node, scratchRegister, monitorReg);9215generateS390CompareAndBranchInstruction(cg, compareImmOp, node, scratchRegister, LOCK_RES_CONTENDED_VALUE, TR::InstOpCode::COND_BE, callHelper, false, false);9216cg->generateDebugCounter("LockExit/Preserving/Recursive", 1, TR::DebugCounter::Undetermined);9217generateRIInstruction(cg, addImmOp, node, monitorReg, -OBJECT_HEADER_LOCK_FIRST_RECURSION_BIT);9218generateRXInstruction(cg, storeOp, node, monitorReg, tempMR1);9219}9220generateS390BranchInstruction(cg,TR::InstOpCode::BRC,TR::InstOpCode::COND_BRC,node,returnLabel);9221tempMR->stopUsingMemRefRegister(cg);9222tempMR1->stopUsingMemRefRegister(cg);92239224cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, callHelper);9225if (normalLockWithReservationPreserving)9226cg->generateDebugCounter("LockExit/Preserving/VMHelper", 1, TR::DebugCounter::Undetermined);9227else9228cg->generateDebugCounter("LockExit/Normal/VMHelper", 1, TR::DebugCounter::Undetermined);9229}9230TR::RegisterDependencyConditions *deps = NULL;9231TR::Register *dummyResultReg = inlineRecursive ? helperLink->buildDirectDispatch(node, &deps) : helperLink->buildDirectDispatch(node);9232TR::RegisterDependencyConditions *mergeConditions = NULL;9233if (inlineRecursive)9234mergeConditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(conditions, deps, cg);9235else9236mergeConditions = conditions;92379238generateS390LabelInstruction(cg,TR::InstOpCode::label,node,returnLabel,mergeConditions);92399240cursor = generateS390BranchInstruction(cg,TR::InstOpCode::BRC,TR::InstOpCode::COND_BRC,node,cFlowRegionEnd);9241if (debugObj)9242{9243debugObj->addInstructionComment(cursor, "Denotes end of OOL monexit: return to mainline");9244}9245// Done using OOL with manual code generation9246outlinedHelperCall->swapInstructionListsWithCompilation();92479248generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, conditions);92499250cg->stopUsingRegister(monitorReg);9251if (objectClassReg)9252cg->stopUsingRegister(objectClassReg);9253if (lookupOffsetReg)9254cg->stopUsingRegister(lookupOffsetReg);9255if (tempRegister && (tempRegister != objectClassReg))9256cg->stopUsingRegister(tempRegister);9257if (scratchRegister)9258cg->stopUsingRegister(scratchRegister);9259cg->decReferenceCount(objNode);92609261return NULL;9262}92639264static void9265roundArrayLengthToObjectAlignment(TR::CodeGenerator* cg, TR::Node* node, TR::Instruction*& iCursor, TR::Register* dataSizeReg,9266TR::RegisterDependencyConditions* conditions, TR::Register *litPoolBaseReg, int32_t allocSize, int32_t elementSize, TR::Register* sizeReg, TR::LabelSymbol * exitOOLLabel = NULL)9267{9268TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());9269int32_t alignmentConstant = TR::Compiler->om.getObjectAlignmentInBytes();9270if (exitOOLLabel)9271{9272TR_Debug * debugObj = cg->getDebug();9273iCursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, exitOOLLabel);9274//TODO if not outline stuff?9275if (debugObj)9276debugObj->addInstructionComment(iCursor, "Exit OOL, going back to main line");9277}92789279// Size of array is headerSize + dataSize. If either aren't9280// multiples of alignment then their sum likely won't be9281bool needsAlignment = ( ((allocSize % alignmentConstant) != 0) ||9282((elementSize % alignmentConstant) != 0) );92839284bool canCombineAGRs = ( ((allocSize % alignmentConstant) == 0) &&9285(elementSize < alignmentConstant));92869287if(!canCombineAGRs)9288iCursor = generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, sizeReg, dataSizeReg, iCursor);92899290if(needsAlignment)9291{9292iCursor = generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, sizeReg, alignmentConstant - 1 + allocSize, iCursor);9293if (cg->comp()->target().is64Bit())9294iCursor = generateS390ImmOp(cg, TR::InstOpCode::getAndOpCode(), node, sizeReg, sizeReg, -((int64_t) (alignmentConstant)), conditions, litPoolBaseReg);9295else9296iCursor = generateS390ImmOp(cg, TR::InstOpCode::getAndOpCode(), node, sizeReg, sizeReg, -((int32_t) (alignmentConstant)), conditions, litPoolBaseReg);9297}9298else9299{9300iCursor = generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, sizeReg, allocSize, iCursor);9301}9302}930393049305static void9306genHeapAlloc(TR::Node * node, TR::Instruction *& iCursor, bool isVariableLen, TR::Register * enumReg, TR::Register * resReg,9307TR::Register * zeroReg, TR::Register * dataSizeReg, TR::Register * sizeReg, TR::LabelSymbol * callLabel, int32_t allocSize,9308int32_t elementSize, TR::CodeGenerator * cg, TR::Register * litPoolBaseReg, TR::RegisterDependencyConditions * conditions,9309TR::Instruction *& firstBRCToOOL, TR::Instruction *& secondBRCToOOL, TR::LabelSymbol * exitOOLLabel = NULL)9310{9311TR::Compilation *comp = cg->comp();9312TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());9313if (!comp->getOptions()->realTimeGC())9314{9315TR::Register *metaReg = cg->getMethodMetaDataRealRegister();93169317// bool sizeInReg = (isVariableLen || (allocSize > MAX_IMMEDIATE_VAL));93189319int alignmentConstant = TR::Compiler->om.getObjectAlignmentInBytes();93209321if (isVariableLen)9322{9323if (exitOOLLabel)9324{9325TR_Debug * debugObj = cg->getDebug();9326iCursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, exitOOLLabel);9327if (debugObj)9328debugObj->addInstructionComment(iCursor, "Exit OOL, going back to main line");9329}9330// Detect large or negative number of elements, and call the helper in that case.9331// This 1MB limit comes from the cg.93329333TR::Register * tmp = sizeReg;9334if (allocSize % alignmentConstant == 0 && elementSize < alignmentConstant)9335{9336tmp = dataSizeReg;9337}93389339if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_S390_Z196))9340{9341iCursor = generateRSInstruction(cg, TR::InstOpCode::SRAK, node, tmp, enumReg, 16, iCursor);9342}9343else9344{9345iCursor = generateRRInstruction(cg, TR::InstOpCode::LR, node, tmp, enumReg, iCursor);9346iCursor = generateRSInstruction(cg, TR::InstOpCode::SRA, node, tmp, 16, iCursor);9347}93489349iCursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, callLabel, iCursor);9350if(!firstBRCToOOL)9351{9352firstBRCToOOL = iCursor;9353}9354else9355{9356secondBRCToOOL = iCursor;9357}9358}93599360// We are loading up a partially constructed object. Don't let GC interfere with us9361// at this moment9362if (isVariableLen)9363{9364//Call helper to turn array length into size in bytes and do object alignment if necessary9365roundArrayLengthToObjectAlignment(cg, node, iCursor, dataSizeReg, conditions, litPoolBaseReg, allocSize, elementSize, sizeReg);93669367#if defined(J9VM_INTERP_FLAGS_IN_CLASS_SLOT)9368// All arrays in combo builds will always be at least 12 bytes in size in all specs:9369//9370// 1) class pointer + contig length + one or more elements9371// 2) class pointer + 0 + 0 (for zero length arrays)9372//9373//Since objects are aligned to 8 bytes then the minimum size for an array must be 16 after rounding93749375static_assert(J9_GC_MINIMUM_OBJECT_SIZE >= 8, "Expecting a minimum object size >= 8");9376#endif9377}93789379// Calculate the after-allocation heapAlloc: if the size is huge,9380// we need to check address wrap-around also. This is unsigned9381// integer arithmetic, checking carry bit is enough to detect it.9382// For variable length array, we did an up-front check already.93839384static char * disableInitClear = feGetEnv("TR_disableInitClear");9385static char * disableBatchClear = feGetEnv("TR_DisableBatchClear");93869387static char * useDualTLH = feGetEnv("TR_USEDUALTLH");93889389TR::Register * addressReg = NULL, * lengthReg = NULL, * shiftReg = NULL;9390if (disableBatchClear && disableInitClear==NULL)9391{9392addressReg = cg->allocateRegister();9393lengthReg = cg->allocateRegister();9394shiftReg = cg->allocateRegister();93959396if (conditions != NULL)9397{9398conditions->resetIsUsed();9399conditions->addPostCondition(addressReg, TR::RealRegister::AssignAny);9400conditions->addPostCondition(shiftReg, TR::RealRegister::AssignAny);9401conditions->addPostCondition(lengthReg, TR::RealRegister::AssignAny);9402}9403}94049405if (isVariableLen)9406{9407if (disableBatchClear && disableInitClear==NULL)9408iCursor = generateRRInstruction(cg, TR::InstOpCode::LGR, node, lengthReg, sizeReg, iCursor);9409if (!comp->getOption(TR_DisableDualTLH) && useDualTLH && node->canSkipZeroInitialization())9410{9411iCursor = generateRXInstruction(cg, TR::InstOpCode::getAddOpCode(), node, sizeReg,9412generateS390MemoryReference(metaReg, offsetof(J9VMThread, nonZeroHeapAlloc), cg), iCursor);9413}9414else9415{9416iCursor = generateRXInstruction(cg, TR::InstOpCode::getAddOpCode(), node, sizeReg,9417generateS390MemoryReference(metaReg, offsetof(J9VMThread, heapAlloc), cg), iCursor);9418}9419}9420else9421{9422if (comp->target().is64Bit())9423iCursor = genLoadLongConstant(cg, node, allocSize, sizeReg, iCursor, conditions);9424else9425iCursor = generateLoad32BitConstant(cg, node, allocSize, sizeReg, true, iCursor, conditions);94269427if (disableBatchClear && disableInitClear==NULL)9428iCursor = generateRRInstruction(cg, TR::InstOpCode::LGR, node, lengthReg, sizeReg, iCursor);94299430if (!comp->getOption(TR_DisableDualTLH) && useDualTLH && node->canSkipZeroInitialization())9431{9432iCursor = generateRXInstruction(cg, TR::InstOpCode::getAddOpCode(), node, sizeReg,9433generateS390MemoryReference(metaReg, offsetof(J9VMThread, nonZeroHeapAlloc), cg), iCursor);9434}9435else9436{9437iCursor = generateRXInstruction(cg, TR::InstOpCode::getAddOpCode(), node, sizeReg,9438generateS390MemoryReference(metaReg, offsetof(J9VMThread, heapAlloc), cg), iCursor);9439}94409441}94429443if (allocSize > cg->getMaxObjectSizeGuaranteedNotToOverflow())9444{9445iCursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BO, node, callLabel, iCursor);9446if(!firstBRCToOOL)9447{9448firstBRCToOOL = iCursor;9449}9450else9451{9452secondBRCToOOL = iCursor;9453}9454}94559456if (!comp->getOption(TR_DisableDualTLH) && useDualTLH && node->canSkipZeroInitialization())9457{9458iCursor = generateRXInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, sizeReg,9459generateS390MemoryReference(metaReg, offsetof(J9VMThread, nonZeroHeapTop), cg), iCursor);94609461// Moving the BRC before load so that the return object can be dead right after BRASL when heap alloc OOL opt is enabled9462iCursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BH, node, callLabel, iCursor);9463if(!firstBRCToOOL)9464{9465firstBRCToOOL = iCursor;9466}9467else9468{9469secondBRCToOOL = iCursor;9470}947194729473iCursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, resReg,9474generateS390MemoryReference(metaReg, offsetof(J9VMThread, nonZeroHeapAlloc), cg), iCursor);9475}9476else9477{9478iCursor = generateRXInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, sizeReg,9479generateS390MemoryReference(metaReg, offsetof(J9VMThread, heapTop), cg), iCursor);94809481// Moving the BRC before load so that the return object can be dead right after BRASL when heap alloc OOL opt is enabled9482iCursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BH, node, callLabel, iCursor);9483if(!firstBRCToOOL)9484{9485firstBRCToOOL = iCursor;9486}9487else9488{9489secondBRCToOOL = iCursor;9490}949194929493iCursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, resReg,9494generateS390MemoryReference(metaReg, offsetof(J9VMThread, heapAlloc), cg), iCursor);9495}949694979498if (!comp->getOption(TR_DisableDualTLH) && useDualTLH && node->canSkipZeroInitialization())9499iCursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, sizeReg,9500generateS390MemoryReference(metaReg, offsetof(J9VMThread, nonZeroHeapAlloc), cg), iCursor);9501else9502iCursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, sizeReg,9503generateS390MemoryReference(metaReg, offsetof(J9VMThread, heapAlloc), cg), iCursor);9504TR::LabelSymbol * fillerRemLabel = generateLabelSymbol(cg);9505TR::LabelSymbol * doneLabel = generateLabelSymbol(cg);95069507TR::LabelSymbol * fillerLoopLabel = generateLabelSymbol(cg);95089509// do this clear, if disableBatchClear is on9510if (disableBatchClear && disableInitClear==NULL) //&& (node->getOpCodeValue() == TR::anewarray) && (node->getFirstChild()->getInt()>0) && (node->getFirstChild()->getInt()<6) )9511{9512iCursor = generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, addressReg, resReg, iCursor);9513// Dont overwrite the class9514//9515iCursor = generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, shiftReg, lengthReg, iCursor);9516iCursor = generateRSInstruction(cg, TR::InstOpCode::SRA, node, shiftReg, 8);95179518iCursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BZ, node, fillerRemLabel, iCursor);9519iCursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, fillerLoopLabel);9520iCursor = generateSS1Instruction(cg, TR::InstOpCode::XC, node, 255, generateS390MemoryReference(addressReg, 0, cg), generateS390MemoryReference(addressReg, 0, cg), iCursor);95219522iCursor = generateRXInstruction(cg, TR::InstOpCode::LA, node, addressReg, generateS390MemoryReference(addressReg, 256, cg), iCursor);95239524iCursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRCT, node, shiftReg, fillerLoopLabel);9525iCursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, fillerRemLabel);95269527// and to only get the right 8 bits (remainder)9528iCursor = generateRIInstruction(cg, TR::InstOpCode::NILL, node, lengthReg, 0x00FF);9529iCursor = generateRIInstruction(cg, TR::InstOpCode::AHI, node, lengthReg, -1);9530// branch to done if length < 095319532iCursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BL, node, doneLabel, iCursor);95339534iCursor = generateSS1Instruction(cg, TR::InstOpCode::XC, node, 0, generateS390MemoryReference(addressReg, 0, cg), generateS390MemoryReference(addressReg, 0, cg), iCursor);95359536// minus 1 from lengthreg since xc auto adds 1 to it95379538iCursor = generateEXDispatch(node, cg, lengthReg, shiftReg, iCursor);9539iCursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);9540}9541cg->stopUsingRegister(addressReg);9542cg->stopUsingRegister(shiftReg);9543cg->stopUsingRegister(lengthReg);95449545if (zeroReg != NULL)9546{9547iCursor = generateRRInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node, zeroReg, zeroReg, iCursor);9548}9549}9550else9551{9552TR_ASSERT(0, "genHeapAlloc() not supported for RT");9553}9554}9555955695579558static void9559genInitObjectHeader(TR::Node * node, TR::Instruction *& iCursor, TR_OpaqueClassBlock * classAddress, TR::Register * classReg, TR::Register * resReg,9560TR::Register * zeroReg, TR::Register * temp1Reg, TR::Register * litPoolBaseReg,9561TR::RegisterDependencyConditions * conditions,9562TR::CodeGenerator * cg, TR::Register * enumReg = NULL, bool canUseIIHF = false)9563{9564TR::Compilation *comp = cg->comp();9565TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());9566TR_J9VM *fej9vm = (TR_J9VM *)(comp->fe());9567if (!comp->getOptions()->realTimeGC())9568{9569J9ROMClass *romClass = 0;9570int32_t staticFlag = 0;9571uint32_t orFlag = 0;9572TR::Register *metaReg = cg->getMethodMetaDataRealRegister();9573TR_ASSERT(classAddress, "Cannot have a null OpaqueClassBlock\n");9574romClass = TR::Compiler->cls.romClassOf(classAddress);9575staticFlag = romClass->instanceShape;95769577// a pointer to the virtual register that will actually hold the class pointer.9578TR::Register * clzReg = classReg;9579// TODO: Following approach for initializing object header for array of objects in AOT is conservative.9580// We need support for relocation in generating RIL type instruction. If we have support, we can use9581// same sequence generated in JIT which saves us a load and store.9582if (comp->compileRelocatableCode())9583{9584if (node->getOpCodeValue() == TR::newarray)9585{9586iCursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, temp1Reg,9587generateS390MemoryReference(metaReg, offsetof(J9VMThread, javaVM), cg), iCursor);9588iCursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, temp1Reg,9589generateS390MemoryReference(temp1Reg,9590fej9vm->getPrimitiveArrayOffsetInJavaVM(node->getSecondChild()->getInt()), cg),9591iCursor);9592clzReg = temp1Reg;9593}9594else if (node->getOpCodeValue() == TR::anewarray)9595{9596TR_ASSERT(classReg, "must have a classReg for TR::anewarray in AOT mode");9597iCursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, temp1Reg,9598generateS390MemoryReference(classReg, offsetof(J9Class, arrayClass), cg), iCursor);9599clzReg = temp1Reg;9600//clzReg = classReg;9601}9602else9603{9604TR_ASSERT(node->getOpCodeValue() == TR::New && classReg,9605"must have a classReg for TR::New in AOT mode");9606clzReg = classReg;9607}9608}96099610// Store the class9611if (clzReg == NULL)9612{9613if (cg->wantToPatchClassPointer(classAddress, node))9614{9615iCursor = genLoadAddressConstantInSnippet(cg, node, (intptr_t) classAddress | (intptr_t)orFlag, temp1Reg, iCursor, conditions, litPoolBaseReg, true);9616if (orFlag != 0)9617{9618if (TR::Compiler->om.compressObjectReferences())9619iCursor = generateS390ImmOp(cg, TR::InstOpCode::O, node, temp1Reg, temp1Reg, (int32_t)orFlag, conditions, litPoolBaseReg);9620else9621{9622if (comp->target().is64Bit())9623iCursor = generateS390ImmOp(cg, TR::InstOpCode::OG, node, temp1Reg, temp1Reg, (int64_t)orFlag, conditions, litPoolBaseReg);9624else9625iCursor = generateS390ImmOp(cg, TR::InstOpCode::O, node, temp1Reg, temp1Reg, (int32_t)orFlag, conditions, litPoolBaseReg);9626}9627}9628}9629else9630{9631//case for arraynew and anewarray for compressedrefs and 31 bit9632/*9633* node->getOpCodeValue() == TR::newarray9634[0x484DF88C20] LGFI GPR15,6740098569635[0x484DF88DD8] ST GPR15,#613 0(GPR3)9636[0x484DF88F60] ST GPR2,#614 4(GPR3)96379638to9639IIHF9640STG GPR2,#614 0(GPR3)96419642*/96439644if (!canUseIIHF)9645iCursor = genLoadAddressConstant(cg, node, (intptr_t) classAddress | (intptr_t)orFlag, temp1Reg, iCursor, conditions, litPoolBaseReg);9646}9647if (canUseIIHF)9648{9649iCursor = generateRILInstruction(cg, TR::InstOpCode::IIHF, node, enumReg, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(classAddress)) | orFlag, iCursor);9650}9651else9652{9653if (TR::Compiler->om.compressObjectReferences())9654// must store just 32 bits (class offset)96559656iCursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, temp1Reg,9657generateS390MemoryReference(resReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), cg), iCursor);9658else9659iCursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, temp1Reg,9660generateS390MemoryReference(resReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), cg), iCursor);9661}9662}9663else9664{9665if (TR::Compiler->om.compressObjectReferences())9666// must store just 32 bits (class offset)9667iCursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, clzReg,9668generateS390MemoryReference(resReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), cg), iCursor);9669else9670iCursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, clzReg,9671generateS390MemoryReference(resReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), cg), iCursor);9672}96739674#ifndef J9VM_INTERP_FLAGS_IN_CLASS_SLOT9675#if defined(J9VM_OPT_NEW_OBJECT_HASH)96769677TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());9678bool isStaticFlag = fej9->isStaticObjectFlags();96799680// If the object flags cannot be determined at compile time, we have to add a load9681// for it. And then, OR it with temp1Reg.9682if (isStaticFlag)9683{9684// The object flags can be determined at compile time.9685staticFlag |= fej9->getStaticObjectFlags();9686if (staticFlag != 0)9687{9688if (staticFlag >= MIN_IMMEDIATE_VAL && staticFlag <= MAX_IMMEDIATE_VAL)9689{9690iCursor = generateSILInstruction(cg, TR::InstOpCode::MVHI, node, generateS390MemoryReference(resReg, TMP_OFFSETOF_J9OBJECT_FLAGS, cg), staticFlag, iCursor);9691}9692else9693{9694iCursor = generateLoad32BitConstant(cg, node, staticFlag, temp1Reg, true, iCursor, conditions, litPoolBaseReg);9695// Store the flags9696iCursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, temp1Reg,9697generateS390MemoryReference(resReg, TMP_OFFSETOF_J9OBJECT_FLAGS, cg), iCursor);9698}9699}9700}9701else9702{9703// If the object flags cannot be determined at compile time, we add a load for it.9704if(!comp->getOption(TR_DisableDualTLH) && useDualTLH && node->canSkipZeroInitialization())9705iCursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, temp1Reg,9706generateS390MemoryReference(metaReg, offsetof(J9VMThread, nonZeroAllocateThreadLocalHeap.objectFlags), cg), iCursor);9707else9708iCursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, temp1Reg,9709generateS390MemoryReference(metaReg, offsetof(J9VMThread, allocateThreadLocalHeap.objectFlags), cg), iCursor);97109711// OR staticFlag with temp1Reg9712if (staticFlag)9713iCursor = generateS390ImmOp(cg, TR::InstOpCode::O, node, temp1Reg, temp1Reg, staticFlag, conditions, litPoolBaseReg);9714// Store the flags9715iCursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, temp1Reg,9716generateS390MemoryReference(resReg, TMP_OFFSETOF_J9OBJECT_FLAGS, cg), iCursor);9717//iCursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, temp1Reg,9718// generateS390MemoryReference(resReg, TMP_OFFSETOF_J9OBJECT_FLAGS, cg), iCursor);9719}9720#endif /* J9VM_OPT_NEW_OBJECT_HASH */9721#endif /* FLAGS_IN_CLASS_SLOT */9722}9723else9724{9725TR_ASSERT(0, "genInitObjecHeader not supported for RT");9726}97279728}972997309731static void9732genAlignDoubleArray(TR::Node * node, TR::Instruction *& iCursor, bool isVariableLen, TR::Register * resReg, int32_t objectSize,9733int32_t dataBegin, TR::Register * dataSizeReg, TR::Register * temp1Reg, TR::Register * temp2Reg, TR::Register * litPoolBaseReg,9734TR::RegisterDependencyConditions * conditions, TR::CodeGenerator * cg)9735{9736TR::LabelSymbol * slotAtStart = generateLabelSymbol(cg);9737TR::LabelSymbol * doneAlign = generateLabelSymbol(cg);97389739iCursor = generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, temp1Reg, resReg, iCursor);9740iCursor = generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, temp2Reg, 3, iCursor);9741iCursor = generateS390ImmOp(cg, TR::InstOpCode::N, node, temp1Reg, temp1Reg, 7, conditions, litPoolBaseReg);9742iCursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNZ, node, slotAtStart, iCursor);97439744// The slop bytes are at the end of the allocated object.9745if (isVariableLen)9746{9747if (cg->comp()->target().is64Bit())9748{9749iCursor = generateRRInstruction(cg, TR::InstOpCode::LGFR, node, dataSizeReg, dataSizeReg, iCursor);9750}97519752iCursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, temp2Reg,9753generateS390MemoryReference(resReg, dataSizeReg, dataBegin, cg), iCursor);9754}9755else if (objectSize >= MAXDISP)9756{9757iCursor = genLoadAddressConstant(cg, node, (intptr_t) objectSize, temp1Reg, iCursor, conditions);9758iCursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, temp2Reg,9759generateS390MemoryReference(resReg, temp1Reg, 0, cg), iCursor);9760}9761else9762{9763iCursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, temp2Reg,9764generateS390MemoryReference(resReg, objectSize, cg), iCursor);9765}9766iCursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, doneAlign, iCursor);97679768// the slop bytes are at the start of the allocation9769iCursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, slotAtStart, iCursor);9770iCursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, temp2Reg,9771generateS390MemoryReference(resReg, (int32_t) 0, cg), iCursor);9772iCursor = generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, resReg, 4, iCursor);9773iCursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneAlign, iCursor);9774}977597769777static void9778genInitArrayHeader(TR::Node * node, TR::Instruction *& iCursor, bool isVariableLen, TR_OpaqueClassBlock * classAddress, TR::Register * classReg,9779TR::Register * resReg, TR::Register * zeroReg, TR::Register * eNumReg, TR::Register * dataSizeReg, TR::Register * temp1Reg,9780TR::Register * litPoolBaseReg, TR::RegisterDependencyConditions * conditions, TR::CodeGenerator * cg)9781{9782TR::Compilation *comp = cg->comp();9783TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());9784bool canUseIIHF= false;9785if (!comp->compileRelocatableCode() && (node->getOpCodeValue() == TR::newarray || node->getOpCodeValue() == TR::anewarray)9786&& (TR::Compiler->om.compressObjectReferences() || comp->target().is32Bit())9787#ifndef J9VM_INTERP_FLAGS_IN_CLASS_SLOT9788#if defined(J9VM_OPT_NEW_OBJECT_HASH)9789&& false9790#endif /* J9VM_OPT_NEW_OBJECT_HASH */9791#endif /* FLAGS_IN_CLASS_SLOT */9792)9793{9794canUseIIHF = true;9795}9796genInitObjectHeader(node, iCursor, classAddress, classReg, resReg, zeroReg, temp1Reg, litPoolBaseReg, conditions, cg, eNumReg, canUseIIHF);97979798// Store the array size9799if (canUseIIHF)9800{9801iCursor = generateRXInstruction(cg, TR::InstOpCode::STG, node, eNumReg,9802generateS390MemoryReference(resReg, TR::Compiler->om.offsetOfObjectVftField(), cg), iCursor);9803}9804else9805iCursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, eNumReg,9806generateS390MemoryReference(resReg, fej9->getOffsetOfContiguousArraySizeField(), cg), iCursor);98079808static char * allocZeroArrayWithVM = feGetEnv("TR_VMALLOCZEROARRAY");9809static char * useDualTLH = feGetEnv("TR_USEDUALTLH");9810//write 09811if(!comp->getOption(TR_DisableDualTLH) && useDualTLH && node->canSkipZeroInitialization() && allocZeroArrayWithVM == NULL)9812iCursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, eNumReg,9813generateS390MemoryReference(resReg, fej9->getOffsetOfDiscontiguousArraySizeField(), cg), iCursor);9814}98159816TR::Register *9817J9::Z::TreeEvaluator::VMnewEvaluator(TR::Node * node, TR::CodeGenerator * cg)9818{9819int32_t allocateSize, objectSize, dataBegin;9820TR::ILOpCodes opCode;9821TR_OpaqueClassBlock * classAddress = 0;9822TR::Register *classReg = NULL;9823TR::Register *resReg = NULL;9824TR::Register *zeroReg = NULL;9825TR::Register *litPoolBaseReg = NULL;9826TR::Register *enumReg = NULL;9827TR::Register *copyReg = NULL;9828TR::Register *classRegAOT = NULL;9829TR::Register *temp1Reg = NULL;9830TR::Register *callResult = NULL;9831TR::Register *dataSizeReg = NULL;9832TR::Node *litPoolBaseChild = NULL;9833TR::Register *copyClassReg = NULL;98349835TR_S390ScratchRegisterManager *srm = cg->generateScratchRegisterManager();98369837TR::LabelSymbol * callLabel, * cFlowRegionEnd;9838TR_S390OutOfLineCodeSection* outlinedSlowPath = NULL;9839TR::RegisterDependencyConditions * conditions;9840TR::Instruction * iCursor = NULL;9841bool isArray = false, isDoubleArray = false;9842bool isVariableLen;9843int32_t litPoolRegTotalUse, temp2RegTotalUse;9844int32_t elementSize;9845TR::Compilation *comp = cg->comp();9846TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());984798489849/* New Evaluator Optimization: Using OOL instead of snippet for heap alloc9850* The purpose of moving to an OOL from a snippet is that we don't need to9851* hard code dependencies at the merge label, hence it could possibly reduce9852* spills. When we have a snippet, then all registers used in between the9853* branch to the snippet and the merge label need to be assigned to specific9854* registers and added to the dependencies at the merge label.9855* Option to disable it: disableHeapAllocOOL */98569857/* Variables needed for Heap alloc OOL Opt */9858TR::Register * tempResReg;//Temporary register used to get the result from the BRASL call in heap alloc OOL9859TR::RegisterDependencyConditions * heapAllocDeps1;//Dependencies needed for BRASL call in heap alloc OOL9860TR::Instruction *firstBRCToOOL = NULL;9861TR::Instruction *secondBRCToOOL = NULL;98629863bool generateArraylets = comp->generateArraylets();98649865// in time, the tlh will probably always be batch cleared, and therefore it will not be9866// necessary for the JIT-generated inline code to do the clearing of fields. But, 2 things9867// have to happen first:9868// 1.The JVM has to change it's code so that it has batch clearing on for 390 (it is currently only9869// on if turned on as a runtime option)9870// 2.The JVM has to support the call - on z/OS, Modron GC is not enabled yet and so batch tlh clearing9871// can not be enabled yet.9872bool needZeroReg = !fej9->tlhHasBeenCleared();98739874opCode = node->getOpCodeValue();98759876// Since calls to canInlineAllocate could result in different results during the same compilation,9877// We must be conservative and only do inline allocation if the first call (in LocalOpts.cpp) has succeeded and we have the litPoolBaseChild added.9878// Refer to defects 161084 and 870899879if (cg->doInlineAllocate(node)9880&& performTransformation(comp, "O^O Inlining Allocation of %s [0x%p].\n", node->getOpCode().getName(), node))9881{9882objectSize = comp->canAllocateInline(node, classAddress);9883isVariableLen = (objectSize == 0);9884allocateSize = objectSize;9885callLabel = generateLabelSymbol(cg);9886cFlowRegionEnd = generateLabelSymbol(cg);9887conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(10, 13, cg);9888if (!comp->getOption(TR_DisableHeapAllocOOL))9889{9890heapAllocDeps1 = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(2, 4, cg);9891}9892TR::Node * firstChild = node->getFirstChild();9893TR::Node * secondChild = NULL;98949895// load literal pool register9896if (((node->getNumChildren()==3) && ((node->getOpCodeValue()==TR::anewarray)9897|| (node->getOpCodeValue()==TR::newarray))) ||9898((node->getNumChildren()==2) && (node->getOpCodeValue()==TR::New)))9899{9900litPoolBaseChild=node->getLastChild();9901TR_ASSERT((litPoolBaseChild->getOpCodeValue()==TR::aload) || (litPoolBaseChild->getOpCodeValue()==TR::aRegLoad),9902"Literal pool base child expected\n");9903litPoolBaseReg=cg->evaluate(litPoolBaseChild);9904litPoolRegTotalUse = litPoolBaseReg->getTotalUseCount();9905}99069907//////////////////////////////////////////////////////////////////////////////////////////////////////9908///============================ STAGE 1: Evaluate Children ========================================///9909//////////////////////////////////////////////////////////////////////////////////////////////////////9910if (opCode == TR::New)9911{9912classReg = cg->evaluate(firstChild);9913dataBegin = TR::Compiler->om.objectHeaderSizeInBytes();9914}9915else9916{9917isArray = true;9918TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());9919if (generateArraylets || TR::Compiler->om.useHybridArraylets())9920{9921if (node->getOpCodeValue() == TR::newarray)9922elementSize = TR::Compiler->om.getSizeOfArrayElement(node);9923else if (comp->useCompressedPointers())9924elementSize = TR::Compiler->om.sizeofReferenceField();9925else9926elementSize = TR::Compiler->om.sizeofReferenceAddress();99279928if (generateArraylets)9929dataBegin = fej9->getArrayletFirstElementOffset(elementSize, comp);9930else9931dataBegin = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();9932}9933else9934{9935dataBegin = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();9936elementSize = TR::Compiler->om.getSizeOfArrayElement(node);9937}9938secondChild = node->getSecondChild();9939// For TR::newarray, classReg is not the real class actually.9940if (!comp->getOption(TR_DisableHeapAllocOOL))9941{9942/* Evaluate the second child node with info about the type of object in the mainline only9943* when it's an evaluation for anewarray or packed anewarray or if the second child's opcode9944* is not a load const. Otherwise, we evaluate the second child manually in OOL since it's9945* not used anywhere in the mainline, hence keeping a register unnecessarily live for a very9946* long time before it is killed. */99479948if (!secondChild->getOpCode().isLoadConst() || node->getOpCodeValue() == TR::anewarray)9949{9950classReg = cg->evaluate(secondChild);9951}9952}9953else9954{9955classReg = cg->evaluate(secondChild);9956}99579958// Potential helper call requires us to evaluate the arguments always.9959enumReg = cg->evaluate(firstChild);9960if (!cg->canClobberNodesRegister(firstChild))9961{9962copyReg = cg->allocateRegister();9963TR::InstOpCode::Mnemonic loadOpCode = (firstChild->getType().isInt64()) ? TR::InstOpCode::LGR : TR::InstOpCode::LR;9964iCursor = generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, copyReg, enumReg, iCursor);9965enumReg = copyReg;9966}9967}99689969//////////////////////////////////////////////////////////////////////////////////////////////////////9970///============================ STAGE 1: Setup Register Dependencies===============================///9971//////////////////////////////////////////////////////////////////////////////////////////////////////99729973temp1Reg = srm->findOrCreateScratchRegister();9974resReg = cg->allocateCollectedReferenceRegister();99759976if (needZeroReg)9977zeroReg = srm->findOrCreateScratchRegister();9978conditions->addPostCondition(classReg, TR::RealRegister::AssignAny);9979if (enumReg)9980{9981conditions->addPostCondition(enumReg, TR::RealRegister::AssignAny);9982traceMsg(comp,"enumReg = %s\n", enumReg->getRegisterName(comp));9983}9984conditions->addPostCondition(resReg, TR::RealRegister::AssignAny);9985traceMsg(comp, "classReg = %s , resReg = %s \n", classReg->getRegisterName(comp), resReg->getRegisterName(comp));9986/* VM helper function for heap alloc expects these parameters to have these values:9987* GPR1 -> Type of Object9988* GPR2 -> Size/Number of objects (if applicable) */9989// We don't need these many registers dependencies as Outlined path will only contain helper call9990TR::Register *copyEnumReg = enumReg;9991TR::Register *copyClassReg = classReg;99929993//////////////////////////////////////////////////////////////////////////////////////////////////////9994///============================ STAGE 2: Calculate Allocation Size ================================///9995//////////////////////////////////////////////////////////////////////////////////////////////////////9996// Three possible outputs:9997// if variable-length array - dataSizeReg will contain the (calculated) size9998// if outlined - tmpReg will contain the value of9999// otherwise - size is in (int) allocateSize10000int alignmentConstant = TR::Compiler->om.getObjectAlignmentInBytes();1000110002if (isVariableLen)10003allocateSize += dataBegin;10004else10005allocateSize = (allocateSize + alignmentConstant - 1) & (-alignmentConstant);1000610007TR::LabelSymbol * exitOOLLabel = NULL;100081000910010if (isVariableLen)10011{1001210013//want to fold some of the10014/*10015* figure out packed arrays10016* LTGFR GPR14,GPR210017* SLLG GPR14,GPR14,110018BRC BE(0x8), Snippet Label [0x484BD04470] <------combine LTGFR + SLLG to RSIBG1001910020LR GPR15,GPR210021SRA GPR15,1610022BRC MASK6(0x6), Snippet Label [0x484BD04470] # (Start of internal control flow)10023LG GPR3,#511 96(GPR13)100241 AGHI GPR14,7 <---can combine 1 & 3 when allocateSize (8) is multiple of alignmentConstant (8), but need10025to re-arrange some of the registers, result is expected in GPR15100262 NILF GPR14,-8100273 LGHI GPR15,8100284 AGR GPR15,GPR14100295 AGR GPR15,GPR310030CLG GPR15,#513 104(GPR13)1003110032final:1003310034*10035*/10036TR::Register * tmp = NULL;10037dataSizeReg = srm->findOrCreateScratchRegister();10038if (allocateSize % alignmentConstant == 0 && elementSize < alignmentConstant)10039{10040tmp = temp1Reg;10041}10042else10043{10044tmp = dataSizeReg;10045}1004610047/* if (elementSize >= 2)10048{10049if (comp->target().is64Bit())10050iCursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, dataSizeReg, dataSizeReg, trailingZeroes(elementSize), iCursor);10051else10052iCursor = generateRSInstruction(cg, TR::InstOpCode::SLL, node, dataSizeReg, trailingZeroes(elementSize), iCursor);10053} */10054if (callLabel != NULL && (node->getOpCodeValue() == TR::anewarray ||10055node->getOpCodeValue() == TR::newarray))10056{10057TR_Debug * debugObj = cg->getDebug();10058TR::LabelSymbol * startOOLLabel = generateLabelSymbol(cg);10059exitOOLLabel = generateLabelSymbol(cg);10060TR_S390OutOfLineCodeSection *zeroSizeArrayChckOOL;10061if (comp->target().is64Bit())10062{10063//need 31 bit as well, combining lgfr + sllg into rsibg10064int32_t shift_amount = trailingZeroes(elementSize);10065iCursor = generateRIEInstruction(cg, TR::InstOpCode::RISBG, node, tmp, enumReg, (int8_t) (32 - shift_amount),10066(int8_t)((63 - shift_amount) |0x80), (int8_t) shift_amount);10067}10068else10069{10070iCursor = generateRRInstruction(cg, TR::InstOpCode::getLoadTestRegWidenOpCode(), node, tmp, enumReg, iCursor);10071if (elementSize >= 2)10072{10073if (comp->target().is64Bit())10074iCursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, tmp, tmp, trailingZeroes(elementSize), iCursor);10075else10076iCursor = generateRSInstruction(cg, TR::InstOpCode::SLL, node, tmp, trailingZeroes(elementSize), iCursor);10077}10078}1007910080static char * allocZeroArrayWithVM = feGetEnv("TR_VMALLOCZEROARRAY");10081// DualTLH: Remove when performance confirmed10082static char * useDualTLH = feGetEnv("TR_USEDUALTLH");1008310084if (comp->getOption(TR_DisableDualTLH) && useDualTLH || allocZeroArrayWithVM == NULL)10085{10086iCursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, startOOLLabel, iCursor);10087TR_Debug * debugObj = cg->getDebug();10088zeroSizeArrayChckOOL = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(startOOLLabel,exitOOLLabel,cg);10089cg->getS390OutOfLineCodeSectionList().push_front(zeroSizeArrayChckOOL);10090zeroSizeArrayChckOOL->swapInstructionListsWithCompilation();10091// Check to see if array-type is a super-class of the src object10092//10093TR::Instruction * cursor;10094cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, startOOLLabel);10095if (debugObj)10096debugObj->addInstructionComment(cursor, "Denotes start of OOL for allocating zero size arrays");1009710098/* using TR::Compiler->om.discontiguousArrayHeaderSizeInBytes() - TR::Compiler->om.contiguousArrayHeaderSizeInBytes()10099* for byte size for discontiguous 0 size arrays because later instructions do ( + 15 & -8) to round it to object size header and adding a j9 class header10100*10101*10102----------- OOL: Beginning of out-of-line code section ---------------10103Label [0x484BE2AC80]: ; Denotes start of OOL for allocating zero size arrays10104AGHI GPR_0x484BE2A900,1610105BRC J(0xf), Label [0x484BE2ACE0]10106--------------- OOL: End of out-of-line code section ------------------1010710108Label [0x484BE2ACE0]: ; Exit OOL, going back to main line10109LR GPR_0x484BE2AAE0,GPR_0x484BE2A7A010110SRA GPR_0x484BE2AAE0,1610111BRC MASK6(0x6), Snippet Label [0x484BE2A530] # (Start of internal control flow)10112AGHI GPR_0x484BE2A900,15 <----add 7 + 810113NILF GPR_0x484BE2A900,-8 <---round to object size10114AG GPR_0x484BE2A900,#490 96(GPR13)1011510116*/10117cursor = generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, tmp,10118TR::Compiler->om.discontiguousArrayHeaderSizeInBytes() - TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cursor);1011910120generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, exitOOLLabel,cursor);10121zeroSizeArrayChckOOL->swapInstructionListsWithCompilation();10122}10123else10124{10125iCursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, callLabel, iCursor);10126if(!firstBRCToOOL)10127{10128firstBRCToOOL = iCursor;10129}10130else10131{10132secondBRCToOOL = iCursor;10133}10134}10135}10136else10137{10138iCursor = generateRRInstruction(cg, TR::InstOpCode::getLoadRegWidenOpCode(), node, tmp, enumReg, iCursor);1013910140if (elementSize >= 2)10141{10142if (comp->target().is64Bit())10143iCursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, tmp, tmp, trailingZeroes(elementSize), iCursor);10144else10145iCursor = generateRSInstruction(cg, TR::InstOpCode::SLL, node, tmp, trailingZeroes(elementSize), iCursor);10146}10147}1014810149}1015010151//////////////////////////////////////////////////////////////////////////////////////////////////////10152///============================ STAGE 3: Generate HeapTop Test=====================================///10153//////////////////////////////////////////////////////////////////////////////////////////////////////10154TR::Instruction *current;10155TR::Instruction *firstInstruction;10156srm->addScratchRegistersToDependencyList(conditions);1015710158current = cg->getAppendInstruction();1015910160TR_ASSERT(current != NULL, "Could not get current instruction");1016110162static char * useDualTLH = feGetEnv("TR_USEDUALTLH");10163//Here we set up backout paths if we overflow nonZeroTLH in genHeapAlloc.10164//If we overflow the nonZeroTLH, set the destination to the right VM runtime helper (eg jitNewObjectNoZeroInit, etc...)10165//The zeroed-TLH versions have their correct destinations already setup in TR_ByteCodeIlGenerator::genNew, TR_ByteCodeIlGenerator::genNewArray, TR_ByteCodeIlGenerator::genANewArray10166//To retrieve the destination node->getSymbolReference() is used below after genHeapAlloc.10167if(!comp->getOption(TR_DisableDualTLH) && useDualTLH && node->canSkipZeroInitialization())10168{10169// For value types, the backout path should call jitNewValue helper call which is set up before code gen10170if ((node->getOpCodeValue() == TR::New)10171&& (!TR::Compiler->om.areValueTypesEnabled() || (node->getSymbolReference() != comp->getSymRefTab()->findOrCreateNewValueSymbolRef(comp->getMethodSymbol()))))10172node->setSymbolReference(comp->getSymRefTab()->findOrCreateNewObjectNoZeroInitSymbolRef(comp->getMethodSymbol()));10173else if (node->getOpCodeValue() == TR::newarray)10174node->setSymbolReference(comp->getSymRefTab()->findOrCreateNewArrayNoZeroInitSymbolRef(comp->getMethodSymbol()));10175else if (node->getOpCodeValue() == TR::anewarray)10176node->setSymbolReference(comp->getSymRefTab()->findOrCreateANewArrayNoZeroInitSymbolRef(comp->getMethodSymbol()));10177}1017810179if (enumReg == NULL && opCode != TR::New)10180{10181enumReg = cg->allocateRegister();10182conditions->addPostCondition(enumReg, TR::RealRegister::AssignAny);10183traceMsg(comp,"enumReg = %s\n", enumReg->getRegisterName(comp));10184}10185// classReg and enumReg have to be intact still, in case we have to call the helper.10186// On return, zeroReg is set to 0, and dataSizeReg is set to the size of data area if10187// isVariableLen is true.10188genHeapAlloc(node, iCursor, isVariableLen, enumReg, resReg, zeroReg, dataSizeReg, temp1Reg, callLabel, allocateSize, elementSize, cg,10189litPoolBaseReg, conditions, firstBRCToOOL, secondBRCToOOL, exitOOLLabel);1019010191//////////////////////////////////////////////////////////////////////////////////////////////////////10192///============================ STAGE 4: Generate Fall-back Path ==================================///10193//////////////////////////////////////////////////////////////////////////////////////////////////////10194/* New Evaluator Optimization: Using OOL instead of snippet for heap alloc */1019510196/* Example of the OOL for newarray10197* Outlined Label L0048: ; Denotes start of OOL for heap alloc10198* LHI GPR_0120,0x510199* assocreg10200* PRE:10201* {GPR2:GPR_0112:R} {GPR1:GPR_0120:R}10202* BRASL GPR_0117,0x0000000010203* POST:10204* {GPR1:D_GPR_0116:R}* {GPR14:GPR_0117:R} {GPR2:&GPR_0118:R}10205* LR &GPR_0115,&GPR_011810206* BRC J(0xf), Label L0049*/1020710208TR_Debug * debugObj = cg->getDebug();10209TR_S390OutOfLineCodeSection *heapAllocOOL = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(callLabel, cFlowRegionEnd, cg);10210cg->getS390OutOfLineCodeSectionList().push_front(heapAllocOOL);10211heapAllocOOL->swapInstructionListsWithCompilation();10212TR::Instruction * cursorHeapAlloc;10213// Generating OOL label: Outlined Label L00XX10214cursorHeapAlloc = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, callLabel);10215if (debugObj)10216debugObj->addInstructionComment(cursorHeapAlloc, "Denotes start of OOL for heap alloc");10217generateHelperCallForVMNewEvaluators(node, cg, true, resReg);10218/* Copying the return value from the temporary register to the actual register that is returned */10219/* Generating the branch to jump back to the merge label:10220* BRCL J(0xf), Label L00YZ, labelTargetAddr=0xZZZZZZZZ*/10221generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);10222heapAllocOOL->swapInstructionListsWithCompilation();10223//////////////////////////////////////////////////////////////////////////////////////////////////////10224///============================ STAGE 5: Initialize the new object header ==========================///10225//////////////////////////////////////////////////////////////////////////////////////////////////////10226if (isArray)10227{10228if ( comp->compileRelocatableCode() && opCode == TR::anewarray)10229genInitArrayHeader(node, iCursor, isVariableLen, classAddress, classReg, resReg, zeroReg,10230enumReg, dataSizeReg, temp1Reg, litPoolBaseReg, conditions, cg);10231else10232genInitArrayHeader(node, iCursor, isVariableLen, classAddress, NULL, resReg, zeroReg,10233enumReg, dataSizeReg, temp1Reg, litPoolBaseReg, conditions, cg);1023410235#ifdef TR_TARGET_64BIT10236/* Here we'll update dataAddr slot for both fixed and variable length arrays. Fixed length arrays are10237* simple as we just need to check first child of the node for array size. For variable length arrays10238* runtime size checks are needed to determine whether to use contiguous or discontiguous header layout.10239*10240* In both scenarios, arrays of non-zero size use contiguous header layout while zero size arrays use10241* discontiguous header layout.10242*/10243TR::Register *offsetReg = NULL;10244TR::MemoryReference *dataAddrMR = NULL;10245TR::MemoryReference *dataAddrSlotMR = NULL;1024610247if (isVariableLen && TR::Compiler->om.compressObjectReferences())10248{10249/* We need to check enumReg (array size) at runtime to determine correct offset of dataAddr field.10250* Here we deal only with compressed refs because dataAddr offset for discontiguous10251* and contiguous arrays is the same in full refs.10252*/10253if (comp->getOption(TR_TraceCG))10254traceMsg(comp, "Node (%p): Dealing with compressed refs variable length array.\n", node);1025510256TR_ASSERT_FATAL_WITH_NODE(node,10257(fej9->getOffsetOfDiscontiguousDataAddrField() - fej9->getOffsetOfContiguousDataAddrField()) == 8,10258"Offset of dataAddr field in discontiguous array is expected to be 8 bytes more than contiguous array. "10259"But was %d bytes for discontigous and %d bytes for contiguous array.\n",10260fej9->getOffsetOfDiscontiguousDataAddrField(), fej9->getOffsetOfContiguousDataAddrField());1026110262offsetReg = cg->allocateRegister();10263// Invert enumReg sign. 0 and negative numbers remain unchanged.10264iCursor = generateRREInstruction(cg, TR::InstOpCode::LNGFR, node, offsetReg, enumReg, iCursor);10265iCursor = generateRSInstruction(cg, TR::InstOpCode::SRLG, node, temp1Reg, offsetReg, 63, iCursor);10266iCursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, offsetReg, temp1Reg, 3, iCursor);10267// Inverting the sign bit will leave us with either -8 (if enumCopyReg > 0) or 0 (if enumCopyReg == 0).10268iCursor = generateRREInstruction(cg, TR::InstOpCode::LNGR, node, offsetReg, offsetReg, iCursor);1026910270dataAddrMR = generateS390MemoryReference(resReg, offsetReg, TR::Compiler->om.discontiguousArrayHeaderSizeInBytes(), cg);10271dataAddrSlotMR = generateS390MemoryReference(resReg, offsetReg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg);10272}10273else if (!isVariableLen && node->getFirstChild()->getOpCode().isLoadConst() && node->getFirstChild()->getInt() == 0)10274{10275if (comp->getOption(TR_TraceCG))10276traceMsg(comp, "Node (%p): Dealing with full/compressed refs fixed length zero size array.\n", node);1027710278dataAddrMR = generateS390MemoryReference(resReg, TR::Compiler->om.discontiguousArrayHeaderSizeInBytes(), cg);10279dataAddrSlotMR = generateS390MemoryReference(resReg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg);10280}10281else10282{10283if (comp->getOption(TR_TraceCG))10284{10285traceMsg(comp,10286"Node (%p): Dealing with either full/compressed refs fixed length non-zero size array or full refs variable length array.\n",10287node);10288}1028910290if (!TR::Compiler->om.compressObjectReferences())10291{10292TR_ASSERT_FATAL_WITH_NODE(node,10293fej9->getOffsetOfDiscontiguousDataAddrField() == fej9->getOffsetOfContiguousDataAddrField(),10294"dataAddr field offset is expected to be same for both contiguous and discontiguous arrays in full refs. "10295"But was %d bytes for discontiguous and %d bytes for contiguous array.\n",10296fej9->getOffsetOfDiscontiguousDataAddrField(), fej9->getOffsetOfContiguousDataAddrField());10297}1029810299dataAddrMR = generateS390MemoryReference(resReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg);10300dataAddrSlotMR = generateS390MemoryReference(resReg, fej9->getOffsetOfContiguousDataAddrField(), cg);10301}1030210303iCursor = generateRXInstruction(cg, TR::InstOpCode::LAY, node, temp1Reg, dataAddrMR, iCursor);10304iCursor = generateRXInstruction(cg, TR::InstOpCode::STG, node, temp1Reg, dataAddrSlotMR, iCursor);1030510306if (offsetReg)10307{10308conditions->addPostCondition(offsetReg, TR::RealRegister::AssignAny);10309cg->stopUsingRegister(offsetReg);10310}10311#endif /* TR_TARGET_64BIT */10312// Write Arraylet Pointer10313if (generateArraylets)10314{10315iCursor = generateS390ImmOp(cg, TR::InstOpCode::getAddOpCode(), node, temp1Reg, resReg, dataBegin, conditions, litPoolBaseReg);10316iCursor = generateS390ImmOp(cg, TR::InstOpCode::getAddOpCode(), node, temp1Reg, temp1Reg, -((int64_t)(0)), conditions, litPoolBaseReg);10317if(TR::Compiler->om.compressedReferenceShiftOffset() > 0)10318iCursor = generateRSInstruction(cg, TR::InstOpCode::SRL, node, temp1Reg, TR::Compiler->om.compressedReferenceShiftOffset(), iCursor);1031910320iCursor = generateRXInstruction(cg, (comp->target().is64Bit()&& !comp->useCompressedPointers()) ? TR::InstOpCode::STG : TR::InstOpCode::ST, node, temp1Reg,10321generateS390MemoryReference(resReg, fej9->getOffsetOfContiguousArraySizeField(), cg), iCursor);1032210323}10324}10325else10326{10327genInitObjectHeader(node, iCursor, classAddress, classReg , resReg, zeroReg, temp1Reg, litPoolBaseReg, conditions, cg);10328}1032910330TR_ASSERT((fej9->tlhHasBeenCleared() || J9JIT_TOSS_CODE), "");1033110332//////////////////////////////////////////////////////////////////////////////////////////////////////10333///============================ STAGE 5b: Prefetch after stores ===================================///10334//////////////////////////////////////////////////////////////////////////////////////////////////////10335if (cg->enableTLHPrefetching())10336{10337iCursor = generateS390MemInstruction(cg, TR::InstOpCode::PFD, node, 2, generateS390MemoryReference(resReg, 0x100, cg), iCursor);10338}1033910340//////////////////////////////////////////////////////////////////////////////////////////////////////10341///============================ STAGE 6: AOT Relocation Records ===================================///10342//////////////////////////////////////////////////////////////////////////////////////////////////////10343if (comp->compileRelocatableCode() && (opCode == TR::New || opCode == TR::anewarray) )10344{10345firstInstruction = current->getNext();10346TR_RelocationRecordInformation *recordInfo =10347(TR_RelocationRecordInformation *) comp->trMemory()->allocateMemory(sizeof(TR_RelocationRecordInformation), heapAlloc);10348recordInfo->data1 = allocateSize;10349recordInfo->data2 = node->getInlinedSiteIndex();10350recordInfo->data3 = (uintptr_t) callLabel;10351recordInfo->data4 = (uintptr_t) firstInstruction;10352TR::SymbolReference * classSymRef;10353TR_ExternalRelocationTargetKind reloKind;10354TR_OpaqueClassBlock *classToValidate = classAddress;1035510356if (opCode == TR::New)10357{10358classSymRef = node->getFirstChild()->getSymbolReference();10359reloKind = TR_VerifyClassObjectForAlloc;10360}10361else10362{10363classSymRef = node->getSecondChild()->getSymbolReference();10364reloKind = TR_VerifyRefArrayForAlloc;10365// In AOT without SVM, we validate the class by pulling it from the constant pool which is not the array class as anewarray bytecode refers to the component class.10366// In the evaluator we directly refer to the array class. In AOT with SVM we need to remember to validate the component class since relocation infrastructure is10367// expecting component class.10368if (comp->getOption(TR_UseSymbolValidationManager))10369classToValidate = comp->fej9()->getComponentClassFromArrayClass(classToValidate);10370}10371if (comp->getOption(TR_UseSymbolValidationManager))10372{10373TR_ASSERT_FATAL(classToValidate != NULL, "ClassToValidate Should not be NULL, clazz = %p\n", classAddress);10374recordInfo->data5 = (uintptr_t)classToValidate;10375}10376cg->addExternalRelocation(new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(firstInstruction,10377(uint8_t *) classSymRef,10378(uint8_t *) recordInfo,10379reloKind, cg),10380__FILE__, __LINE__, node);1038110382}1038310384//////////////////////////////////////////////////////////////////////////////////////////////////////10385///============================ STAGE 7: Done. Housekeeping items =================================///10386//////////////////////////////////////////////////////////////////////////////////////////////////////1038710388// Add these registers to the dep list if they are actually used in the evaluator body10389// We detect use by observing if the totalUseCounts on the registers increased since their first10390// instance at the top of the evaluator.10391//10392if (litPoolBaseReg!=NULL && litPoolBaseReg->getTotalUseCount()>litPoolRegTotalUse)10393{10394// reset the isUSed bit on the condition, this prevents the assertion10395// "ERROR: cannot add conditions to an used dependency, create a copy first" from firing up.10396conditions->resetIsUsed();10397if (comp->getOption(TR_DisableHeapAllocOOL))10398conditions->addPostCondition(litPoolBaseReg, TR::RealRegister::AssignAny);10399}1040010401if (!comp->getOption(TR_DisableHeapAllocOOL))10402{10403if (secondBRCToOOL)10404{10405TR::LabelSymbol * cFlowRegionStart = generateLabelSymbol(cg);10406TR::LabelSymbol * cFlowRegionEnd = generateLabelSymbol(cg);1040710408generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart, firstBRCToOOL->getPrev());10409cFlowRegionStart->setStartInternalControlFlow();1041010411generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, conditions, secondBRCToOOL);10412cFlowRegionEnd->setEndInternalControlFlow();10413}10414iCursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd);10415}10416else10417{10418// determine where internal control flow begins by looking for the first branch10419// instruction after where the label instruction would have been inserted10420TR::LabelSymbol * cFlowRegionStart = generateLabelSymbol(cg);1042110422TR::Instruction *next = current->getNext();10423while(next != NULL && !next->isBranchOp())10424next = next->getNext();10425TR_ASSERT(next != NULL && next->getPrev() != NULL, "Could not find branch instruction where internal control flow begins");10426generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart, next->getPrev());10427cFlowRegionStart->setStartInternalControlFlow();1042810429iCursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, conditions);10430cFlowRegionEnd->setEndInternalControlFlow();10431}1043210433cg->decReferenceCount(firstChild);10434if (secondChild)10435{10436cg->decReferenceCount(secondChild);10437}10438if (litPoolBaseChild!=NULL)10439{10440cg->decReferenceCount(litPoolBaseChild);10441}1044210443if (classReg)10444cg->stopUsingRegister(classReg);10445if (copyClassReg)10446cg->stopUsingRegister(copyClassReg);10447if (copyEnumReg != enumReg)10448cg->stopUsingRegister(copyEnumReg);10449if (enumReg)10450cg->stopUsingRegister(enumReg);10451if (copyReg)10452cg->stopUsingRegister(copyReg);10453srm->stopUsingRegisters();10454node->setRegister(resReg);10455return resReg;10456}10457else10458{10459// The call to doInlineAllocate may return true during LocalOpts, but subsequent optimizations may prove10460// that the anewarray cannot be allocated inline (i.e. it will end up going to helper). An example is10461// when arraysize is proven to be 0, which is considered a discontiguous array size in balanced mode GC.10462// In such cases, we need to remove the last litpool child before calling directCallEvaluator.10463if (((node->getNumChildren()==3) && ((node->getOpCodeValue()==TR::anewarray) || (node->getOpCodeValue()==TR::newarray))) ||10464((node->getNumChildren()==2) && (node->getOpCodeValue()==TR::New)))10465{10466// Remove the last literal pool child.10467node->removeLastChild();10468}10469return generateHelperCallForVMNewEvaluators(node, cg);10470}10471}1047210473TR::Register *10474J9::Z::TreeEvaluator::VMarrayCheckEvaluator(TR::Node *node, TR::CodeGenerator *cg)10475{10476TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());10477TR::Node *object1 = node->getFirstChild();10478TR::Node *object2 = node->getSecondChild();10479TR::Register *object1Reg = cg->evaluate(object1);10480TR::Register *object2Reg = cg->evaluate(object2);1048110482TR::LabelSymbol *cFlowRegionStart = generateLabelSymbol(cg);10483TR::LabelSymbol *fallThrough = generateLabelSymbol(cg);10484TR::LabelSymbol *snippetLabel = NULL;10485TR::Snippet *snippet = NULL;10486TR::Register *tempReg = cg->allocateRegister();10487TR::Register *tempClassReg = cg->allocateRegister();10488TR::InstOpCode::Mnemonic loadOpcode;10489TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 7, cg);104901049110492// If the objects are the same and one of them is known to be an array, they10493// are compatible.10494//10495if (node->isArrayChkPrimitiveArray1() ||10496node->isArrayChkReferenceArray1() ||10497node->isArrayChkPrimitiveArray2() ||10498node->isArrayChkReferenceArray2())10499{10500generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);10501cFlowRegionStart->setStartInternalControlFlow();10502generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, object1Reg, object2Reg, TR::InstOpCode::COND_BE, fallThrough, false, false);10503}1050410505else10506{10507// Neither object is known to be an array10508// Check that object 1 is an array. If not, throw exception.10509//10510TR::Register * class1Reg = cg->allocateRegister();10511TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, class1Reg, generateS390MemoryReference(object1Reg, TR::Compiler->om.offsetOfObjectVftField(), cg), NULL);1051210513// TODO: Can we check the value of J9AccClassRAMArray and use NILF here?10514#ifdef TR_HOST_64BIT10515genLoadLongConstant(cg, node, J9AccClassRAMArray, tempReg, NULL, deps, NULL);10516generateRXInstruction(cg, TR::InstOpCode::NG, node, tempReg,10517new (cg->trHeapMemory()) TR::MemoryReference(class1Reg, offsetof(J9Class, classDepthAndFlags), cg));10518#else10519generateLoad32BitConstant(cg, node, J9AccClassRAMArray, tempReg, true, NULL, deps, NULL);10520generateRXInstruction(cg, TR::InstOpCode::N, node, tempReg,10521new (cg->trHeapMemory()) TR::MemoryReference(class1Reg, offsetof(J9Class, classDepthAndFlags), cg));10522#endif10523cg->stopUsingRegister(class1Reg);1052410525if (!snippetLabel)10526{10527snippetLabel = generateLabelSymbol(cg);10528generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);10529cFlowRegionStart->setStartInternalControlFlow();10530generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BZ, node, snippetLabel);1053110532snippet = new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference());10533cg->addSnippet(snippet);10534}10535else10536{10537generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);10538cFlowRegionStart->setStartInternalControlFlow();10539generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BZ, node, snippetLabel);10540}10541}1054210543// Test equality of the object classes.10544//10545TR::TreeEvaluator::genLoadForObjectHeaders(cg, node, tempReg, generateS390MemoryReference(object1Reg, TR::Compiler->om.offsetOfObjectVftField(), cg), NULL);1054610547if (TR::Compiler->om.compressObjectReferences())10548generateRXInstruction(cg, TR::InstOpCode::X, node, tempReg, generateS390MemoryReference(object2Reg, TR::Compiler->om.offsetOfObjectVftField(), cg));10549else10550generateRXInstruction(cg, TR::InstOpCode::getXOROpCode(), node, tempReg, generateS390MemoryReference(object2Reg, TR::Compiler->om.offsetOfObjectVftField(), cg));1055110552TR::TreeEvaluator::generateVFTMaskInstruction(node, tempReg, cg);1055310554// XOR doesn't set the proper condition codes, so test explicitly10555generateRIInstruction(cg, TR::InstOpCode::getCmpHalfWordImmOpCode(), node, tempReg, 0);1055610557// If either object is known to be a primitive array, we are done. Either10558// the equality test fails and we throw the exception or it succeeds and10559// we finish.10560//10561if (node->isArrayChkPrimitiveArray1() || node->isArrayChkPrimitiveArray2())10562{10563if (!snippetLabel)10564{10565snippetLabel = generateLabelSymbol(cg);10566generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, snippetLabel);1056710568snippet = new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference());10569cg->addSnippet(snippet);10570}10571else10572{10573generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, snippetLabel);10574}10575}1057610577// Otherwise, there is more testing to do. If the classes are equal we10578// are done, and branch to the fallThrough label.10579//10580else10581{10582generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, fallThrough);1058310584// If either object is not known to be a reference array type, check it10585// We already know that object1 is an array type but we may have to now10586// check object2.10587//10588if (!node->isArrayChkReferenceArray1())10589{10590TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, tempClassReg, generateS390MemoryReference(object1Reg, TR::Compiler->om.offsetOfObjectVftField(), cg), NULL);1059110592// ramclass->classDepth&flags10593generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, tempReg,10594new (cg->trHeapMemory()) TR::MemoryReference(tempClassReg, offsetof(J9Class, classDepthAndFlags), cg));1059510596// X = (ramclass->ClassDepthAndFlags)>>J9AccClassRAMShapeShift10597generateRSInstruction(cg, TR::InstOpCode::SRL, node, tempReg, J9AccClassRAMShapeShift);1059810599// X & OBJECT_HEADER_SHAPE_MASK10600generateRRInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node, tempClassReg, tempClassReg);10601generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, tempClassReg, OBJECT_HEADER_SHAPE_MASK);10602generateRRInstruction(cg, TR::InstOpCode::NR, node, tempClassReg, tempReg);1060310604generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, tempReg, OBJECT_HEADER_SHAPE_POINTERS);1060510606if (!snippetLabel)10607{10608snippetLabel = generateLabelSymbol(cg);10609generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CR, node, tempReg, tempClassReg, TR::InstOpCode::COND_BNZ, snippetLabel, false, false);1061010611snippet = new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference());10612cg->addSnippet(snippet);10613}10614else10615{10616generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CR, node, tempReg, tempClassReg, TR::InstOpCode::COND_BNZ, snippetLabel, false, false);10617}10618}10619if (!node->isArrayChkReferenceArray2())10620{10621// Check that object 2 is an array. If not, throw exception.10622TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, tempClassReg, generateS390MemoryReference(object2Reg, TR::Compiler->om.offsetOfObjectVftField(), cg), NULL);1062310624// TODO: Can we check the value of J9AccClassRAMArray and use NILF here?10625#ifdef TR_HOST_64BIT10626{10627genLoadLongConstant(cg, node, J9AccClassRAMArray, tempReg, NULL, deps, NULL);10628generateRXInstruction(cg, TR::InstOpCode::NG, node, tempReg,10629new (cg->trHeapMemory()) TR::MemoryReference(tempClassReg, offsetof(J9Class, classDepthAndFlags), cg));10630}10631#else10632{10633generateLoad32BitConstant(cg, node, J9AccClassRAMArray, tempReg, true, NULL, deps, NULL);10634generateRXInstruction(cg, TR::InstOpCode::N, node, tempReg,10635new (cg->trHeapMemory()) TR::MemoryReference(tempClassReg, offsetof(J9Class, classDepthAndFlags), cg));10636}10637#endif10638if (!snippetLabel)10639{10640snippetLabel = generateLabelSymbol(cg);10641generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BZ, node, snippetLabel);1064210643snippet = new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference());10644cg->addSnippet(snippet);10645}10646else10647{10648generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BZ, node, snippetLabel);10649}1065010651//* Test object2 is reference array10652TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, tempClassReg, generateS390MemoryReference(object2Reg, TR::Compiler->om.offsetOfObjectVftField(), cg), NULL);1065310654// ramclass->classDepth&flags10655generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, tempReg,10656new (cg->trHeapMemory()) TR::MemoryReference(tempClassReg, offsetof(J9Class, classDepthAndFlags), cg));1065710658// X = (ramclass->ClassDepthAndFlags)>>J9AccClassRAMShapeShift10659generateRSInstruction(cg, TR::InstOpCode::SRL, node, tempReg, J9AccClassRAMShapeShift);1066010661// X & OBJECT_HEADER_SHAPE_MASK10662generateRRInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node, tempClassReg, tempClassReg);10663generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, tempClassReg,OBJECT_HEADER_SHAPE_MASK);10664generateRRInstruction(cg, TR::InstOpCode::NR, node, tempClassReg, tempReg);1066510666generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, tempReg, OBJECT_HEADER_SHAPE_POINTERS);1066710668generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CR, node, tempReg, tempClassReg, TR::InstOpCode::COND_BNZ, snippetLabel, false, false);10669}1067010671// Now both objects are known to be reference arrays, so they are10672// compatible for arraycopy.10673}1067410675// Now generate the fall-through label10676//10677deps->addPostCondition(object1Reg, TR::RealRegister::AssignAny);10678deps->addPostConditionIfNotAlreadyInserted(object2Reg, TR::RealRegister::AssignAny); // 1st and 2nd object may be the same.10679deps->addPostCondition(tempReg, TR::RealRegister::AssignAny);10680deps->addPostCondition(tempClassReg, TR::RealRegister::AssignAny);10681generateS390LabelInstruction(cg, TR::InstOpCode::label, node, fallThrough, deps);10682fallThrough->setEndInternalControlFlow();1068310684cg->stopUsingRegister(tempClassReg);10685cg->stopUsingRegister(tempReg);10686cg->decReferenceCount(object1);10687cg->decReferenceCount(object2);1068810689return 0;10690}10691106921069310694/////////////////////////////////////////////////////////////////////////////////10695/////////////////////////////////////////////////////////////////////////////////10696static bool inlineIsAssignableFrom(TR::Node *node, TR::CodeGenerator *cg)10697{10698static char *disable = feGetEnv("TR_disableInlineIsAssignableFrom");10699TR::Compilation *comp = cg->comp();10700TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());1070110702if (disable)10703return false;1070410705TR::Node *thisClass = node->getFirstChild();10706if (thisClass->getOpCodeValue() == TR::aloadi &&10707thisClass->getFirstChild()->getOpCodeValue() == TR::loadaddr)10708{10709TR::SymbolReference *thisClassSymRef = thisClass->getFirstChild()->getSymbolReference();1071010711if (thisClassSymRef->isClassInterface(comp) || thisClassSymRef->isClassAbstract(comp))10712{10713return false;10714}10715}1071610717int32_t classDepth = -1;10718TR::Node *javaLangClassFrom = node->getFirstChild();10719if((javaLangClassFrom->getOpCodeValue() == TR::aloadi10720&& javaLangClassFrom->getSymbolReference() == comp->getSymRefTab()->findJavaLangClassFromClassSymbolRef()10721&& javaLangClassFrom->getFirstChild()->getOpCodeValue() == TR::loadaddr))10722{10723TR::Node *castClassRef =javaLangClassFrom->getFirstChild();1072410725TR::SymbolReference *castClassSymRef = NULL;10726if(castClassRef->getOpCode().hasSymbolReference())10727castClassSymRef= castClassRef->getSymbolReference();1072810729TR::StaticSymbol *castClassSym = NULL;10730if (castClassSymRef && !castClassSymRef->isUnresolved())10731castClassSym= castClassSymRef ? castClassSymRef->getSymbol()->getStaticSymbol() : NULL;1073210733TR_OpaqueClassBlock * clazz = NULL;10734if (castClassSym)10735clazz = (TR_OpaqueClassBlock *) castClassSym->getStaticAddress();1073610737if(clazz)10738classDepth = (int32_t)TR::Compiler->cls.classDepthOf(clazz);10739}1074010741TR::Register *returnRegister = NULL;10742TR::SymbolReference *symRef = node->getSymbolReference();10743TR::MethodSymbol *callSymbol = symRef->getSymbol()->castToMethodSymbol();1074410745TR::LabelSymbol *startLabel = generateLabelSymbol(cg);10746// startLabel->setStartInternalControlFlow();10747TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);10748TR::LabelSymbol *failLabel = generateLabelSymbol(cg);10749TR::LabelSymbol *outlinedCallLabel = generateLabelSymbol(cg);10750// doneLabel->setEndInternalControlFlow();1075110752TR::Register *thisClassReg = cg->evaluate(node->getFirstChild());10753TR::Register *checkClassReg = cg->evaluate(node->getSecondChild());1075410755TR::RegisterDependencyConditions * deps = NULL;107561075710758TR::Register *tempReg = cg->allocateRegister();10759TR::Register *objClassReg, *castClassReg, *scratch1Reg,*scratch2Reg;10760int8_t numOfPostDepConditions = (thisClassReg == checkClassReg)? 2 : 3;107611076210763if (classDepth != -1)10764{10765deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numOfPostDepConditions+4, cg);10766objClassReg = cg->allocateRegister();10767castClassReg = cg->allocateRegister();10768scratch1Reg = cg->allocateRegister();10769scratch2Reg = cg->allocateRegister();10770deps->addPostCondition(scratch1Reg, TR::RealRegister::AssignAny);10771deps->addPostCondition(scratch2Reg, TR::RealRegister::AssignAny);10772deps->addPostCondition(castClassReg, TR::RealRegister::AssignAny);10773deps->addPostCondition(objClassReg, TR::RealRegister::AssignAny);1077410775}10776else10777{10778deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numOfPostDepConditions, cg);10779objClassReg = tempReg;10780}1078110782deps->addPostCondition(thisClassReg, TR::RealRegister::AssignAny);10783if (thisClassReg != checkClassReg)10784{10785deps->addPostCondition(checkClassReg, TR::RealRegister::AssignAny);10786}10787deps->addPostCondition(tempReg, TR::RealRegister::AssignAny);1078810789generateS390LabelInstruction(cg, TR::InstOpCode::label, node, startLabel);1079010791generateRRInstruction(cg, TR::InstOpCode::getLoadTestRegOpCode(), node, thisClassReg, thisClassReg);10792generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, outlinedCallLabel);10793generateRRInstruction(cg, TR::InstOpCode::getLoadTestRegOpCode(), node, checkClassReg, checkClassReg);10794generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, outlinedCallLabel);1079510796generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, objClassReg,10797generateS390MemoryReference(checkClassReg, fej9->getOffsetOfClassFromJavaLangClassField(), cg));1079810799generateRXInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, objClassReg,10800generateS390MemoryReference(thisClassReg, fej9->getOffsetOfClassFromJavaLangClassField(), cg));1080110802generateRIInstruction(cg, TR::InstOpCode::LHI, node, tempReg, 1);1080310804TR_Debug * debugObj = cg->getDebug();10805if (classDepth != -1)10806{10807generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, doneLabel);10808generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, castClassReg,10809generateS390MemoryReference(thisClassReg, fej9->getOffsetOfClassFromJavaLangClassField(), cg));1081010811genTestIsSuper(cg, node, objClassReg, castClassReg, scratch1Reg, scratch2Reg, tempReg, NULL, classDepth, failLabel, doneLabel, NULL, deps, NULL, false, NULL, NULL);1081210813generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, doneLabel);10814}10815else10816{10817generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, outlinedCallLabel);10818}108191082010821TR_S390OutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(node, TR::icall, tempReg, outlinedCallLabel, doneLabel, cg);10822cg->getS390OutOfLineCodeSectionList().push_front(outlinedHelperCall);10823outlinedHelperCall->generateS390OutOfLineCodeSectionDispatch();108241082510826cg->decReferenceCount(node->getFirstChild());10827cg->decReferenceCount(node->getSecondChild());1082810829node->setRegister(tempReg);1083010831if (classDepth != -1)10832{10833generateS390LabelInstruction(cg, TR::InstOpCode::label, node, failLabel, deps);10834generateRIInstruction(cg, TR::InstOpCode::LHI, node, tempReg, 0);1083510836cg->stopUsingRegister(objClassReg);10837cg->stopUsingRegister(castClassReg);10838cg->stopUsingRegister(scratch1Reg);10839cg->stopUsingRegister(scratch2Reg);10840}10841generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);1084210843return true;10844}108451084610847bool10848J9::Z::TreeEvaluator::VMinlineCallEvaluator(TR::Node * node, bool indirect, TR::CodeGenerator * cg)10849{10850TR::ResolvedMethodSymbol * methodSymbol = node->getSymbol()->getResolvedMethodSymbol();1085110852if (!methodSymbol)10853{10854return false;10855}108561085710858bool callWasInlined = false;10859if (methodSymbol)10860{10861switch (methodSymbol->getRecognizedMethod())10862{10863case TR::java_lang_Class_isAssignableFrom:10864{10865callWasInlined = inlineIsAssignableFrom(node, cg);10866break;10867}10868}10869}1087010871return callWasInlined;10872}1087310874void10875J9::Z::TreeEvaluator::genGuardedLoadOOL(TR::Node *node, TR::CodeGenerator *cg,10876TR::Register *byteSrcReg, TR::Register *byteDstReg,10877TR::Register *byteLenReg, TR::LabelSymbol *mergeLabel,10878TR_S390ScratchRegisterManager *srm, bool isForward)10879{10880TR::LabelSymbol* slowPathLabel = generateLabelSymbol(cg);10881TR::Register *vmReg = cg->getMethodMetaDataRealRegister();10882auto baseMemRef = generateS390MemoryReference(vmReg, TR::Compiler->vm.thisThreadGetEvacuateBaseAddressOffset(cg->comp()), cg);10883generateSILInstruction(cg, cg->comp()->useCompressedPointers() ? TR::InstOpCode::CHSI : TR::InstOpCode::CGHSI, node, baseMemRef, -1);10884generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, slowPathLabel);1088510886TR_S390OutOfLineCodeSection* outOfLineCodeSection = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(slowPathLabel, mergeLabel, cg);10887cg->getS390OutOfLineCodeSectionList().push_front(outOfLineCodeSection);10888outOfLineCodeSection->swapInstructionListsWithCompilation();10889generateS390LabelInstruction(cg, TR::InstOpCode::label, node, slowPathLabel);1089010891cg->generateDebugCounter(TR::DebugCounter::debugCounterName(cg->comp(), "readBar/arraycopy/OOL"), 1, TR::DebugCounter::Cheap);1089210893// Call to generateMemToMemElementCopy generates core Array Copy sequence and identify starting instruction in ICF.10894TR::RegisterDependencyConditions *loopDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 10, cg);10895TR::TreeEvaluator::generateMemToMemElementCopy(node, cg, byteSrcReg, byteDstReg, byteLenReg, srm, isForward, true, false, loopDeps);1089610897TR::LabelSymbol *doneOOLLabel = generateLabelSymbol(cg);10898loopDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(loopDeps, 0, 3+srm->numAvailableRegisters(), cg);10899loopDeps->addPostCondition(byteSrcReg, TR::RealRegister::AssignAny);10900loopDeps->addPostCondition(byteDstReg, TR::RealRegister::AssignAny);10901loopDeps->addPostCondition(byteLenReg, TR::RealRegister::AssignAny);10902srm->addScratchRegistersToDependencyList(loopDeps);10903generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneOOLLabel, loopDeps);10904doneOOLLabel->setEndInternalControlFlow();1090510906generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, mergeLabel);10907outOfLineCodeSection->swapInstructionListsWithCompilation();10908}1090910910void10911J9::Z::TreeEvaluator::genArrayCopyWithArrayStoreCHK(TR::Node* node,10912TR::Register *srcObjReg,10913TR::Register *dstObjReg,10914TR::Register *srcAddrReg,10915TR::Register *dstAddrReg,10916TR::Register *lengthReg,10917TR::CodeGenerator *cg)10918{10919TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());1092010921TR::RegisterDependencyConditions * deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(9, 9, cg);10922TR::LabelSymbol * doneLabel = generateLabelSymbol(cg);10923TR::LabelSymbol * callLabel = generateLabelSymbol(cg);10924TR::LabelSymbol * OKLabel = generateLabelSymbol(cg);10925TR::Linkage * linkage = cg->getLinkage(node->getSymbol()->castToMethodSymbol()->getLinkageConvention());10926TR::SystemLinkage *sysLink = (TR::SystemLinkage *) cg->getLinkage(TR_System);1092710928TR::RealRegister *sspRegReal = sysLink->getStackPointerRealRegister();10929TR::Register *sspReg;1093010931TR::Compilation *comp = cg->comp();1093210933if (sspRegReal->getState() == TR::RealRegister::Locked)10934{10935sspReg = sspRegReal;10936}10937else10938{10939sspReg = cg->allocateRegister();10940}1094110942TR::Register *helperReg = cg->allocateRegister();10943int32_t offset = sysLink->getOffsetToFirstParm();10944int32_t ptrSize = (int32_t)TR::Compiler->om.sizeofReferenceAddress();1094510946// Set the following parms in C parm area10947// 1) VM Thread10948// 2) srcObj10949// 3) dstObj10950// 4) srcAddr10951// 5) dstAddr10952// 6) num of slots10953// 7) VM referenceArrayCopy func desc10954TR::Register *metaReg = cg->getMethodMetaDataRealRegister();1095510956if (sspRegReal->getState() != TR::RealRegister::Locked)10957{10958deps->addPreCondition(sspReg, TR::RealRegister::GPR4);10959deps->addPostCondition(sspReg, TR::RealRegister::GPR4);10960}10961if (cg->supportsJITFreeSystemStackPointer())10962{10963generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, sspReg,10964generateS390MemoryReference(metaReg, (int32_t)(fej9->thisThreadGetSystemSPOffset()), cg));10965generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, helperReg, 0);10966generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, helperReg,10967generateS390MemoryReference(metaReg, (int32_t)(fej9->thisThreadGetSystemSPOffset()), cg));10968}1096910970// Ready parameter 5: count reg10971TR::Register *countReg = cg->allocateRegister();10972generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, countReg, lengthReg);10973generateRSInstruction(cg, TR::InstOpCode::SRL, node, countReg, trailingZeroes(TR::Compiler->om.sizeofReferenceField()));1097410975// Ready parameter 6: helper reg10976intptr_t *funcdescrptr = (intptr_t*) fej9->getReferenceArrayCopyHelperAddress();10977if (comp->compileRelocatableCode() || comp->isOutOfProcessCompilation())10978{10979generateRegLitRefInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, helperReg, (intptr_t)funcdescrptr, TR_ArrayCopyHelper, NULL, NULL, NULL);10980}10981else10982{10983genLoadAddressConstant(cg, node, (long) funcdescrptr, helperReg);10984}1098510986// Store 7 parameters10987generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, metaReg,10988generateS390MemoryReference(sspReg, offset+0*ptrSize, cg));10989generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, srcObjReg,10990generateS390MemoryReference(sspReg, offset+1*ptrSize, cg));10991generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, dstObjReg,10992generateS390MemoryReference(sspReg, offset+2*ptrSize, cg));10993generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, srcAddrReg,10994generateS390MemoryReference(sspReg, offset+3*ptrSize, cg));10995generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, dstAddrReg,10996generateS390MemoryReference(sspReg, offset+4*ptrSize, cg));10997generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, countReg,10998generateS390MemoryReference(sspReg, offset+5*ptrSize, cg));10999generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, helperReg,11000generateS390MemoryReference(sspReg, offset+6*ptrSize, cg));1100111002cg->stopUsingRegister(countReg);11003cg->stopUsingRegister(helperReg);1100411005TR::Register *rcReg = cg->allocateRegister();11006TR::Register *raReg = cg->allocateRegister();11007TR::Register *tmpReg = cg->allocateRegister();11008TR::Register *R2SaveReg = cg->allocateRegister();1100911010TR::SymbolReference* helperCallSymRef = cg->symRefTab()->findOrCreateRuntimeHelper(TR_S390referenceArrayCopyHelper);11011TR::Snippet * helperCallSnippet = new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, callLabel,11012helperCallSymRef, doneLabel);11013cg->addSnippet(helperCallSnippet);1101411015// The snippet kill r14 and may kill r15, the rc is in r211016deps->addPostCondition(rcReg, linkage->getIntegerReturnRegister());11017deps->addPostCondition(raReg, linkage->getReturnAddressRegister());11018deps->addPostCondition(tmpReg, linkage->getEntryPointRegister());1101911020TR::Instruction *gcPoint =11021generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, callLabel);11022gcPoint->setNeedsGCMap(0xFFFFFFFF);1102311024generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);1102511026if (cg->supportsJITFreeSystemStackPointer())11027{11028generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, sspReg,11029generateS390MemoryReference(metaReg, (int32_t)(fej9->thisThreadGetSystemSPOffset()), cg));11030}1103111032if (sspRegReal->getState() != TR::RealRegister::Locked)11033{11034cg->stopUsingRegister(sspReg);11035}1103611037generateRIInstruction(cg, TR::InstOpCode::getCmpHalfWordImmOpCode(), node, rcReg, 65535);11038generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, OKLabel);1103911040// raise exceptions11041TR::SymbolReference *throwSymRef = comp->getSymRefTab()->findOrCreateArrayStoreExceptionSymbolRef(comp->getJittedMethodSymbol());11042TR::LabelSymbol *exceptionSnippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, throwSymRef);11043if (exceptionSnippetLabel == NULL)11044{11045exceptionSnippetLabel = generateLabelSymbol(cg);11046cg->addSnippet(new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, exceptionSnippetLabel, throwSymRef));11047}1104811049gcPoint = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, exceptionSnippetLabel);11050gcPoint->setNeedsGCMap(0xFFFFFFFF);1105111052generateS390LabelInstruction(cg, TR::InstOpCode::label, node, OKLabel, deps);1105311054cg->stopUsingRegister(raReg);11055cg->stopUsingRegister(tmpReg);11056cg->stopUsingRegister(rcReg);11057cg->stopUsingRegister(R2SaveReg);1105811059return;11060}1106111062void11063J9::Z::TreeEvaluator::restoreGPR7(TR::Node *node, TR::CodeGenerator *cg)11064{11065TR::MemoryReference * tempMR = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(), offsetof(J9VMThread, tempSlot), cg);11066TR::Register * tempReg = cg->allocateRegister();11067generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, cg->machine()->getRealRegister(TR::RealRegister::GPR7), tempMR);11068}1106911070void J9::Z::TreeEvaluator::genWrtbarForArrayCopy(TR::Node *node, TR::Register *srcReg, TR::Register *dstReg, bool srcNonNull, TR::CodeGenerator *cg)11071{11072TR::Instruction * cursor;11073TR::RegisterDependencyConditions * conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 4, cg);11074TR::Compilation * comp = cg->comp();1107511076auto gcMode = TR::Compiler->om.writeBarrierType();11077bool doWrtBar = (gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always);11078// Do not do card marking when gcMode is gc_modron_wrtbar_cardmark_and_oldcheck - we go through helper, which performs CM, so it is redundant.11079bool doCrdMrk = (gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_incremental);11080TR::LabelSymbol * doneLabel = generateLabelSymbol(cg);1108111082if (doWrtBar)11083{11084TR::Register * tempReg = cg->allocateRegister();11085TR::Register * tempReg2 = cg->allocateRegister();11086TR::SymbolReference * wbref = comp->getSymRefTab()->findOrCreateWriteBarrierBatchStoreSymbolRef(comp->getMethodSymbol());1108711088TR::Register * srcObjReg = srcReg;11089TR::Register * dstObjReg;11090// It's possible to have srcReg and dstReg point to same array11091// If so, we need to copy before calling helper11092if (srcReg == dstReg){11093dstObjReg = cg->allocateRegister();11094generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, dstObjReg, dstReg);11095}11096else11097dstObjReg = dstReg;1109811099conditions->addPostCondition(tempReg, cg->getReturnAddressRegister());11100conditions->addPostCondition(tempReg2, cg->getEntryPointRegister());11101conditions->addPostCondition(dstObjReg, TR::RealRegister::GPR1);1110211103/*** Start of VMnonNullSrcWrtBarEvaluator ***********************/11104// 83613: If this condition changes, please verify that the inline CM11105// conditions are still correct. Currently, we don't perform inline CM11106// for old&CM objects, since this wrtbarEvaluator will call the helper,which11107// also performs CM.1110811109// check for old space or color black (fej9->getWriteBarrierGCFlagMaskAsByte())11110//11111// object layout11112// -------------11113// |class_pointer|11114// -------------11115// |***** flag|11116// -------------11117// .....11118//11119// flag is in the lower 2 bytes in a 8 byte slot on 64 bit obj.(4 byte slot in 32bit obj)11120// so the offset should be ...1112111122if (gcMode != gc_modron_wrtbar_always)11123{11124bool is64Bit = comp->target().is64Bit();11125bool isConstantHeapBase = !comp->getOptions()->isVariableHeapBaseForBarrierRange0();11126bool isConstantHeapSize = !comp->getOptions()->isVariableHeapSizeForBarrierRange0();11127TR::Register * temp1Reg = cg->allocateRegister();1112811129conditions->addPostCondition(temp1Reg, TR::RealRegister::AssignAny);1113011131TR::MemoryReference * offset = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(), offsetof(J9VMThread, heapBaseForBarrierRange0), cg);11132TR::MemoryReference * size = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(), offsetof(J9VMThread, heapSizeForBarrierRange0), cg);11133generateRRInstruction(cg, is64Bit ? TR::InstOpCode::LGR : TR::InstOpCode::LR, node, temp1Reg, dstObjReg);11134generateRXInstruction(cg, is64Bit ? TR::InstOpCode::SG : TR::InstOpCode::S, node, temp1Reg, offset);11135generateRXInstruction(cg, is64Bit ? TR::InstOpCode::CLG : TR::InstOpCode::CL, node, temp1Reg, size);11136generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BH, node, doneLabel);11137cg->stopUsingRegister(temp1Reg);11138// if not match, callout to the helper11139}1114011141generateDirectCall(cg, node, false, wbref, conditions);11142/*** End Of *****************************************************/11143cg->stopUsingRegister(tempReg);11144cg->stopUsingRegister(tempReg2);11145if (srcReg == dstReg)11146cg->stopUsingRegister(dstObjReg);11147}1114811149else if (doCrdMrk)11150{11151if (!comp->getOptions()->realTimeGC())11152{11153TR::Register * temp1Reg = cg->allocateRegister();11154conditions->addPostCondition(temp1Reg, TR::RealRegister::AssignAny);11155conditions->addPostCondition(dstReg, TR::RealRegister::AssignAny);11156VMCardCheckEvaluator(node, dstReg, temp1Reg, conditions, cg, false, doneLabel);11157cg->stopUsingRegister(temp1Reg);11158}11159else11160TR_ASSERT(0, "genWrtbarForArrayCopy card marking not supported for RT");11161}11162generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);11163}1116411165TR::Register*11166J9::Z::TreeEvaluator::VMinlineCompareAndSwap(TR::Node *node, TR::CodeGenerator *cg, TR::InstOpCode::Mnemonic casOp, bool isObj)11167{11168TR::Register *scratchReg = NULL;11169TR::Register *objReg, *oldVReg, *newVReg;11170TR::Register *resultReg = cg->allocateRegister();11171TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);11172TR::MemoryReference* casMemRef = NULL;1117311174TR::Compilation * comp = cg->comp();1117511176TR::Node* thisNode = node->getChild(0);11177TR::Node* objNode = node->getChild(1);11178TR::Node* offsetNode = node->getChild(2);11179TR::Node* oldVNode = node->getChild(3);11180TR::Node* newVNode = node->getChild(4);1118111182// The card mark write barrier helper expects the source register to be a decompressed reference. As such if the11183// value we are storing (last argument) has been lowered we must extract the decompressed reference from the11184// compression sequence.11185bool isValueCompressedReference = false;1118611187TR::Node* decompressedValueNode = newVNode;1118811189if (isObj && comp->useCompressedPointers() && decompressedValueNode->getOpCodeValue() == TR::l2i)11190{11191// Pattern match the sequence:11192//11193// <node>11194// <thisNode>11195// <objNode>11196// <offsetNode>11197// <oldVNode>11198// l2i11199// lushr11200// a2l11201// <decompressedValueNode>11202// iconst1120311204if (decompressedValueNode->getOpCode().isConversion())11205{11206decompressedValueNode = decompressedValueNode->getFirstChild();11207}1120811209if (decompressedValueNode->getOpCode().isRightShift())11210{11211decompressedValueNode = decompressedValueNode->getFirstChild();11212}1121311214isValueCompressedReference = true;1121511216while ((decompressedValueNode->getNumChildren() > 0) && (decompressedValueNode->getOpCodeValue() != TR::a2l))11217{11218decompressedValueNode = decompressedValueNode->getFirstChild();11219}1122011221if (decompressedValueNode->getOpCodeValue() == TR::a2l)11222{11223decompressedValueNode = decompressedValueNode->getFirstChild();11224}1122511226// Artificially bump the reference count on the value so that different registers are allocated for the11227// compressed and decompressed values. This is done so that the card mark write barrier helper uses the11228// decompressed value.11229decompressedValueNode->incReferenceCount();11230}1123111232// Eval old and new vals11233//11234objReg = cg->evaluate(objNode);11235oldVReg = cg->gprClobberEvaluate(oldVNode); // CS oldReg, newReg, OFF(objReg)11236newVReg = cg->evaluate(newVNode); // oldReg is clobbered1123711238TR::Register* compressedValueRegister = newVReg;1123911240if (isValueCompressedReference)11241{11242compressedValueRegister = cg->evaluate(decompressedValueNode);11243}1124411245bool needsDup = false;1124611247if (objReg == newVReg)11248{11249// Make a copy of the register - reg deps later on expect them in different registers.11250newVReg = cg->allocateCollectedReferenceRegister();11251generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, newVReg, objReg);11252if (!isValueCompressedReference)11253compressedValueRegister = newVReg;1125411255needsDup = true;11256}1125711258generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, resultReg, 0x0);1125911260// We can run into trouble when the offset value gets too big, or it may11261// simply not nbe known at compile time.11262//11263if (offsetNode->getOpCode().isLoadConst() && offsetNode->getRegister()==NULL)11264{11265// We know at compile time11266intptr_t offsetValue = offsetNode->getLongInt();11267if (offsetValue>=0 && offsetValue<MAXDISP)11268{11269casMemRef = generateS390MemoryReference(objReg, offsetValue, cg);11270}11271// ADD Golden Eagle support here if we ever see this path take (unlikely)11272}1127311274// We couldn't figure out how to get the offset into the DISP field of the CAS inst11275// So use an explicit local ADD11276//11277if (casMemRef == NULL) // Not setup, hence we need a reg11278{11279scratchReg = cg->gprClobberEvaluate(offsetNode);1128011281generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, scratchReg,objReg);11282casMemRef = generateS390MemoryReference(scratchReg, 0, cg);11283}1128411285if (TR::Compiler->om.readBarrierType() != gc_modron_readbar_none && isObj)11286{11287TR::Register* tempReadBarrier = cg->allocateRegister();11288if (comp->target().cpu.supportsFeature(OMR_FEATURE_S390_GUARDED_STORAGE))11289{11290auto guardedLoadMnemonic = comp->useCompressedPointers() ? TR::InstOpCode::LLGFSG : TR::InstOpCode::LGG;1129111292// Compare-And-Swap on object reference, while primarily is a store operation, it is also an implicit read (it11293// reads the existing value to be compared with a provided compare value, before the store itself), hence needs11294// a read barrier11295generateS390IEInstruction(cg, TR::InstOpCode::NIAI, 1, 0, node);11296generateRXInstruction(cg, guardedLoadMnemonic, node, tempReadBarrier, generateS390MemoryReference(*casMemRef, 0, cg));11297}11298else11299{11300TR::TreeEvaluator::generateSoftwareReadBarrier(node, cg, tempReadBarrier, generateS390MemoryReference(*casMemRef, 0, cg));11301}11302cg->stopUsingRegister(tempReadBarrier);11303}1130411305// Compare and swap11306//11307generateRSInstruction(cg, casOp, node, oldVReg, newVReg, casMemRef);1130811309// Setup return11310//11311generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, doneLabel);1131211313generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, resultReg, 0x1);1131411315TR::RegisterDependencyConditions* cond = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 1, cg);11316cond->addPostCondition(resultReg, TR::RealRegister::AssignAny);1131711318generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, cond);1131911320// Do wrtbar for Objects11321//11322auto gcMode = TR::Compiler->om.writeBarrierType();11323bool doWrtBar = (gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck ||11324gcMode == gc_modron_wrtbar_always);11325bool doCrdMrk = (gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck ||11326gcMode == gc_modron_wrtbar_cardmark_incremental);1132711328if (isObj && (doWrtBar || doCrdMrk))11329{11330TR::LabelSymbol *doneLabelWrtBar = generateLabelSymbol(cg);11331TR::Register *epReg = cg->allocateRegister();11332TR::Register *raReg = cg->allocateRegister();11333TR::RegisterDependencyConditions* condWrtBar = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 5, cg);11334condWrtBar->addPostCondition(objReg, TR::RealRegister::GPR1);11335if (compressedValueRegister != newVReg)11336condWrtBar->addPostCondition(newVReg, TR::RealRegister::AssignAny); //defect 9200111337if (compressedValueRegister != objReg) // add this because I got conflicting dependencies on GPR1 and GPR2!11338condWrtBar->addPostCondition(compressedValueRegister, TR::RealRegister::GPR2); //defect 9200111339condWrtBar->addPostCondition(epReg, cg->getEntryPointRegister());11340condWrtBar->addPostCondition(raReg, cg->getReturnAddressRegister());11341// Cardmarking is not inlined for gencon. Consider doing so when perf issue arises.11342if (doWrtBar)11343{11344TR::SymbolReference *wbRef;11345auto gcMode = TR::Compiler->om.writeBarrierType();1134611347if (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_oldcheck)11348wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreGenerationalSymbolRef(comp->getMethodSymbol());11349else11350wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreSymbolRef(comp->getMethodSymbol());11351VMnonNullSrcWrtBarCardCheckEvaluator(node, objReg, compressedValueRegister, epReg, raReg, doneLabelWrtBar, wbRef, condWrtBar, cg, false);11352}1135311354else if (doCrdMrk)11355{11356VMCardCheckEvaluator(node, objReg, epReg, condWrtBar, cg, false, doneLabelWrtBar, false);11357// true #1 -> copy of objReg just happened, it's safe to clobber tempReg11358// false #2 -> Don't do compile time check for heap obj11359}1136011361generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabelWrtBar, condWrtBar);1136211363cg->stopUsingRegister(epReg);11364cg->stopUsingRegister(raReg);11365}1136611367// Value is not used, and not eval'd to avoid the extra reg11368// So recursively decrement to compensate11369//11370cg->recursivelyDecReferenceCount(thisNode);1137111372cg->decReferenceCount(objNode);11373cg->decReferenceCount(offsetNode);11374cg->decReferenceCount(oldVNode);11375cg->decReferenceCount(newVNode);1137611377cg->stopUsingRegister(oldVReg);1137811379if (needsDup)11380{11381cg->stopUsingRegister(newVReg);11382}11383if (scratchReg)11384{11385cg->stopUsingRegister(scratchReg);11386}1138711388if (isValueCompressedReference)11389cg->decReferenceCount(decompressedValueNode);1139011391node->setRegister(resultReg);11392return resultReg;11393}113941139511396/////////////////////////////////////////////////////////////////////////////////11397// getTOCOffset()11398// return codertTOC offset from vmThread (R13)11399////////////////////////////////////////////////////////////////////////////////11400int11401getTOCOffset()11402{11403return (offsetof(J9VMThread, codertTOC));11404}1140511406TR::Instruction *11407J9::Z::TreeEvaluator::generateVFTMaskInstruction(TR::Node *node, TR::Register *reg, TR::CodeGenerator *cg, TR::Instruction *preced)11408{11409TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());11410TR::Instruction *result = preced;11411uintptr_t mask = TR::Compiler->om.maskOfObjectVftField();11412if (~mask == 0)11413{11414// no mask instruction required11415}11416else if (~mask <= 0xffff)11417{11418result = generateRIInstruction(cg, TR::InstOpCode::NILL, node, reg, mask, preced);11419}11420else11421{11422TR_ASSERT(0, "Can't mask out flag bits beyond the low 16 from the VFT pointer");11423}11424return result;11425}1142611427// This routine generates RION and RIOFF guarded by VMThread->jitCurrentRIFlags11428// based on test for bit: J9_JIT_TOGGLE_RI_IN_COMPILED_CODE11429TR::Instruction *11430J9::Z::TreeEvaluator::generateRuntimeInstrumentationOnOffSequence(TR::CodeGenerator *cg, TR::InstOpCode::Mnemonic op, TR::Node *node, TR::Instruction *preced, bool postRA)11431{11432TR::Compilation *comp = cg->comp();11433TR_ASSERT(op == TR::InstOpCode::RION || op == TR::InstOpCode::RIOFF, "Unexpected Runtime Instrumentation OpCode");1143411435#ifdef TR_HOST_S39011436TR::LabelSymbol * OOLStartLabel = generateLabelSymbol(cg);11437TR::LabelSymbol * OOLReturnLabel = generateLabelSymbol(cg);11438TR_Debug * debugObj = cg->getDebug();1143911440// Test the last byte of vmThread->jitCurrentRIFlags11441TR_ASSERT(0 != (J9_JIT_TOGGLE_RI_IN_COMPILED_CODE & 0xFF), "Cannot use TM to test for J9_JIT_TOGGLE_RI_IN_COMPILED_CODE");11442TR::MemoryReference *vmThreadMemRef = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(), offsetof(J9VMThread, jitCurrentRIFlags) + sizeof(((J9VMThread *)0)->jitCurrentRIFlags) - 1, cg);11443preced = generateSIInstruction(cg, TR::InstOpCode::TM, node, vmThreadMemRef, J9_JIT_TOGGLE_RI_IN_COMPILED_CODE, preced);11444preced = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK7, node, OOLStartLabel, preced);1144511446if (debugObj)11447if (op == TR::InstOpCode::RION)11448debugObj->addInstructionComment(preced, "-->OOL RION");11449else11450debugObj->addInstructionComment(preced, "-->OOL RIOFF");114511145211453TR_S390OutOfLineCodeSection *RIOnOffOOL = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(OOLStartLabel, OOLReturnLabel, cg);11454cg->getS390OutOfLineCodeSectionList().push_front(RIOnOffOOL);11455RIOnOffOOL->swapInstructionListsWithCompilation();1145611457TR::Instruction * cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, OOLStartLabel);11458if (debugObj)11459debugObj->addInstructionComment(cursor, "OOL RION/OFF seq");1146011461// Generate the RION/RIOFF instruction.11462cursor = generateRuntimeInstrumentationInstruction(cg, op, node, NULL, cursor);1146311464cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, OOLReturnLabel, cursor);1146511466RIOnOffOOL->swapInstructionListsWithCompilation();1146711468preced = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, OOLReturnLabel, preced);1146911470// OOL's are appended to the instruction stream during RA. If this is11471// emitted postRA, we have to attach it ourselves.11472if (postRA)11473{11474TR::Instruction *appendInstruction = cg->getAppendInstruction();11475appendInstruction->setNext(RIOnOffOOL->getFirstInstruction());11476RIOnOffOOL->getFirstInstruction()->setPrev(appendInstruction);11477cg->setAppendInstruction(RIOnOffOOL->getAppendInstruction());11478}11479#endif /* TR_HOST_S390 */11480return preced;11481}114821148311484#if defined(TR_HOST_S390) && defined(J9ZOS390)11485// psuedo-call to asm function11486extern "C" void _getSTCKLSOOffset(int32_t* offsetArray); /* 390 asm stub */11487#endif1148811489TR::Register*11490J9::Z::TreeEvaluator::inlineSinglePrecisionSQRT(TR::Node *node, TR::CodeGenerator *cg)11491{11492TR::Node * firstChild = node->getFirstChild();11493TR::Register * targetRegister = NULL;11494TR::Register * opRegister = cg->evaluate(firstChild);1149511496if (cg->canClobberNodesRegister(firstChild))11497{11498targetRegister = opRegister;11499}11500else11501{11502targetRegister = cg->allocateRegister(TR_FPR);11503}11504generateRRInstruction(cg, TR::InstOpCode::SQEBR, node, targetRegister, opRegister);11505node->setRegister(targetRegister);11506cg->decReferenceCount(firstChild);11507return node->getRegister();11508}1150911510TR::Register*11511J9::Z::TreeEvaluator::inlineCurrentTimeMaxPrecision(TR::CodeGenerator* cg, TR::Node* node)11512{11513// STCKF is an S instruction and requires a 64-bit memory reference11514TR::SymbolReference* reusableTempSlot = cg->allocateReusableTempSlot();1151511516generateSInstruction(cg, TR::InstOpCode::STCKF, node, generateS390MemoryReference(node, reusableTempSlot, cg));1151711518// Dynamic literal pool could have assigned us a literal base register11519TR::Register* literalBaseRegister = (node->getNumChildren() == 1) ? cg->evaluate(node->getFirstChild()) : NULL;1152011521TR::Register* targetRegister = cg->allocateRegister();1152211523#if defined(TR_HOST_S390) && defined(J9ZOS390)11524int32_t offsets[3];11525_getSTCKLSOOffset(offsets);1152611527TR::Register* tempRegister = cg->allocateRegister();1152811529// z/OS requires time correction to account for leap seconds. The number of leap seconds is stored in the LSO11530// field of the MVS data area.11531if (cg->comp()->target().isZOS())11532{11533// Load FFCVT(R0)11534generateRXInstruction(cg, TR::InstOpCode::LLGT, node, tempRegister, generateS390MemoryReference(offsets[0], cg));1153511536// Load CVTEXT2 - CVT11537generateRXInstruction(cg, TR::InstOpCode::LLGT, node, tempRegister, generateS390MemoryReference(tempRegister, offsets[1], cg));11538}11539#endif1154011541generateRXInstruction(cg, TR::InstOpCode::LG, node, targetRegister, generateS390MemoryReference(node, reusableTempSlot, cg));1154211543int64_t todJanuary1970 = 0x7D91048BCA000000LL;11544generateRegLitRefInstruction(cg, TR::InstOpCode::SLG, node, targetRegister, todJanuary1970, NULL, NULL, literalBaseRegister);1154511546#if defined(TR_HOST_S390) && defined(J9ZOS390)11547if (cg->comp()->target().isZOS())11548{11549// Subtract the LSO offset11550generateRXInstruction(cg, TR::InstOpCode::SLG, node, targetRegister, generateS390MemoryReference(tempRegister, offsets[2],cg));11551}1155211553cg->stopUsingRegister(tempRegister);11554#endif1155511556// Get current time in terms of 1/2048 of micro-seconds11557generateRSInstruction(cg, TR::InstOpCode::SRLG, node, targetRegister, targetRegister, 1);1155811559cg->freeReusableTempSlot();1156011561if (literalBaseRegister != NULL)11562{11563cg->decReferenceCount(node->getFirstChild());11564}1156511566node->setRegister(targetRegister);1156711568return targetRegister;11569}1157011571TR::Register*11572J9::Z::TreeEvaluator::inlineAtomicOps(TR::Node *node, TR::CodeGenerator *cg, int8_t size, TR::MethodSymbol *method, bool isArray)11573{11574TR::Compilation *comp = cg->comp();11575TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());11576TR::Node *valueChild = node->getFirstChild();11577TR::Node *deltaChild = NULL;11578TR::Register *valueReg = cg->evaluate(valueChild);11579TR::Register *deltaReg = NULL;11580TR::Register *resultReg = NULL;1158111582int32_t delta = 0;11583int32_t numDeps = 4;1158411585bool isAddOp = true;11586bool isGetAndOp = true;11587bool isLong = false;11588bool isArgConstant = false;1158911590TR::RecognizedMethod currentMethod = method->getRecognizedMethod();1159111592// Gather information about the method11593//11594switch (currentMethod)11595{11596case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:11597case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:11598case TR::java_util_concurrent_atomic_AtomicLong_getAndSet:11599case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:11600case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:11601case TR::java_util_concurrent_atomic_AtomicLongArray_getAndSet:11602case TR::java_util_concurrent_atomic_AtomicReferenceArray_getAndSet:11603{11604isAddOp = false;11605break;11606}11607case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:11608case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:11609{11610isGetAndOp = false;11611}11612case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:11613case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:11614{11615break;11616}11617case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:11618case TR::java_util_concurrent_atomic_AtomicIntegerArray_incrementAndGet:11619{11620isGetAndOp = false;11621}11622case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:11623case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:11624{11625delta = (int32_t)1;11626isArgConstant = true;11627resultReg = cg->allocateRegister();11628break;11629}11630case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:11631case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:11632{11633isGetAndOp = false;11634}11635case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:11636case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:11637{11638delta = (int32_t)-1;11639isArgConstant = true;11640resultReg = cg->allocateRegister();11641break;11642}11643case TR::java_util_concurrent_atomic_AtomicLong_addAndGet:11644case TR::java_util_concurrent_atomic_AtomicLongArray_addAndGet:11645{11646isGetAndOp = false;11647}11648case TR::java_util_concurrent_atomic_AtomicLong_getAndAdd:11649case TR::java_util_concurrent_atomic_AtomicLongArray_getAndAdd:11650{11651isLong = true;11652break;11653}11654case TR::java_util_concurrent_atomic_AtomicLong_incrementAndGet:11655case TR::java_util_concurrent_atomic_AtomicLongArray_incrementAndGet:11656{11657isGetAndOp = false;11658}11659case TR::java_util_concurrent_atomic_AtomicLong_getAndIncrement:11660case TR::java_util_concurrent_atomic_AtomicLongArray_getAndIncrement:11661{11662isLong = true;11663delta = (int64_t)1;11664break;11665}11666case TR::java_util_concurrent_atomic_AtomicLong_decrementAndGet:11667case TR::java_util_concurrent_atomic_AtomicLongArray_decrementAndGet:11668{11669isGetAndOp = false;11670}11671case TR::java_util_concurrent_atomic_AtomicLong_getAndDecrement:11672case TR::java_util_concurrent_atomic_AtomicLongArray_getAndDecrement:11673{11674isLong = true;11675delta = (int64_t)-1;11676break;11677}11678}1167911680//Determine the offset of the value field11681//11682int32_t shiftAmount = 0;11683TR::Node *indexChild = NULL;11684TR::Register *indexRegister = NULL;11685TR::Register *fieldOffsetReg = NULL;11686int32_t fieldOffset;1168711688if (!isArray)11689{11690TR_OpaqueClassBlock * bdClass;11691char *className, *fieldSig;11692int32_t classNameLen, fieldSigLen;1169311694fieldSigLen = 1;1169511696switch (currentMethod)11697{11698case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:11699className = "Ljava/util/concurrent/atomic/AtomicBoolean;";11700classNameLen = 43;11701fieldSig = "I"; // not a typo, the field is int11702break;11703case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:11704case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:11705case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:11706case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:11707case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:11708case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:11709case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:11710className = "Ljava/util/concurrent/atomic/AtomicInteger;";11711classNameLen = 43;11712fieldSig = "I";11713break;11714case TR::java_util_concurrent_atomic_AtomicLong_getAndSet:11715case TR::java_util_concurrent_atomic_AtomicLong_addAndGet:11716case TR::java_util_concurrent_atomic_AtomicLong_getAndAdd:11717case TR::java_util_concurrent_atomic_AtomicLong_incrementAndGet:11718case TR::java_util_concurrent_atomic_AtomicLong_getAndIncrement:11719case TR::java_util_concurrent_atomic_AtomicLong_decrementAndGet:11720case TR::java_util_concurrent_atomic_AtomicLong_getAndDecrement:11721className = "Ljava/util/concurrent/atomic/AtomicLong;";11722classNameLen = 40;11723fieldSig = "J";11724break;11725case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:11726className = "Ljava/util/concurrent/atomic/AtomicReference;";11727classNameLen = 45;11728fieldSig = "Ljava/lang/Object;";11729fieldSigLen = 18;11730break;11731default:11732TR_ASSERT( 0, "Unknown atomic operation method\n");11733return NULL;11734}1173511736TR_ResolvedMethod *owningMethod = node->getSymbolReference()->getOwningMethod(comp);11737TR_OpaqueClassBlock *containingClass = fej9->getClassFromSignature(className, classNameLen, owningMethod, true);11738fieldOffset = fej9->getInstanceFieldOffset(containingClass, "value", 5, fieldSig, fieldSigLen)11739+ fej9->getObjectHeaderSizeInBytes(); // size of a J9 object header11740}11741else11742{11743if (isArray)11744{11745indexChild = node->getChild(1);11746indexRegister = cg->evaluate(indexChild);11747fieldOffset = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();11748if (size == 4)11749shiftAmount = 2;11750else if (size == 8)11751shiftAmount = 3;1175211753fieldOffsetReg = cg->allocateRegister();11754generateRSInstruction(cg, TR::InstOpCode::SLL, node, fieldOffsetReg, indexRegister, shiftAmount);11755}11756}1175711758// Exploit z196 interlocked-update instructions11759if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_S390_Z196))11760{11761if (isAddOp) //getAndAdd or andAndGet11762{11763if (node->getNumChildren() > 1)11764{11765// 2nd operand needs to be in a register11766deltaChild = node->getSecondChild();11767deltaReg = cg->evaluate(deltaChild);11768cg->decReferenceCount(deltaChild);11769}11770else11771{11772// no 2nd child = Atomic.increment or decrement, delta should be +/- 111773deltaReg = cg->allocateRegister();11774if (!isLong)11775{11776generateRIInstruction(cg, TR::InstOpCode::LHI, node, deltaReg, delta);11777}11778else11779{11780generateRIInstruction(cg, TR::InstOpCode::LGHI, node, deltaReg, delta);11781}11782}1178311784// Load And Add: LAA R1,R2,Mem11785// R1 = Mem; Mem = Mem + R2;11786// IMPORTANT: LAAG throws hardware exception if Mem is not double word aligned11787// Class AtomicLong currently has its value field d.word aligned11788if (!resultReg)11789resultReg = cg->allocateRegister();1179011791if (!isLong)11792{11793if (fieldOffsetReg)11794generateRSInstruction(cg, TR::InstOpCode::LAA, node, resultReg, deltaReg, new (cg->trHeapMemory()) TR::MemoryReference(valueReg, fieldOffsetReg, fieldOffset, cg));11795else11796generateRSInstruction(cg, TR::InstOpCode::LAA, node, resultReg, deltaReg, new (cg->trHeapMemory()) TR::MemoryReference(valueReg, fieldOffset, cg));11797}11798else11799{11800if (fieldOffsetReg)11801generateRSInstruction(cg, TR::InstOpCode::LAAG, node, resultReg, deltaReg, new (cg->trHeapMemory()) TR::MemoryReference(valueReg, fieldOffsetReg, fieldOffset, cg));11802else11803generateRSInstruction(cg, TR::InstOpCode::LAAG, node, resultReg, deltaReg, new (cg->trHeapMemory()) TR::MemoryReference(valueReg, fieldOffset, cg));11804}11805if (!isGetAndOp)11806{11807// for addAndGet, the result needs to be recomputed. LAA loaded the original value into resultReg.11808if (!isLong)11809generateRRInstruction(cg, TR::InstOpCode::AR, node, resultReg, deltaReg);11810else11811generateRRInstruction(cg, TR::InstOpCode::AGR, node, resultReg, deltaReg);11812}1181311814cg->stopUsingRegister(deltaReg);11815cg->decReferenceCount(valueChild);11816cg->stopUsingRegister(valueReg);1181711818node->setRegister(resultReg);11819return resultReg;11820}11821}1182211823if (node->getNumChildren() > 1)11824{11825deltaChild = node->getSecondChild();1182611827//Determine if the delta is a constant.11828//11829if (deltaChild->getOpCode().isLoadConst() && !deltaChild->getRegister())11830{11831delta = (int32_t)(deltaChild->getInt());11832isArgConstant = true;11833resultReg = cg->allocateRegister();11834}11835else if (isAddOp)11836{11837deltaReg = cg->evaluate(deltaChild);11838resultReg = cg->allocateRegister();11839}11840else11841{11842resultReg = cg->evaluate(deltaChild);11843}11844}1184511846TR::RegisterDependencyConditions * dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numDeps, cg);11847TR::LabelSymbol *cFlowRegionEnd = generateLabelSymbol(cg);11848TR::LabelSymbol *loopLabel = generateLabelSymbol(cg);118491185011851// If this is a getAndSet of a constant, load the constant outside the loop.11852//11853if (!isAddOp && isArgConstant)11854generateLoad32BitConstant(cg, node, delta, resultReg, true);1185511856// Get the existing value11857//11858TR::Register *tempReg = cg->allocateRegister();11859if (fieldOffsetReg)11860generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, tempReg, new (cg->trHeapMemory()) TR::MemoryReference(valueReg, fieldOffsetReg, fieldOffset, cg));11861else11862generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, tempReg, new (cg->trHeapMemory()) TR::MemoryReference(valueReg, fieldOffset, cg));1186311864generateS390LabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);11865loopLabel->setStartInternalControlFlow();1186611867// Perform the addition operation, if necessary11868//11869if (isAddOp)11870{11871generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(),node, resultReg, tempReg);11872if(isArgConstant)11873{11874generateS390ImmOp(cg, TR::InstOpCode::getAddOpCode(), node, resultReg, resultReg, (int32_t) delta, dependencies, NULL);11875}11876else11877{11878generateRRInstruction(cg, TR::InstOpCode::getAddRegOpCode(), node, resultReg ,deltaReg);11879}11880}1188111882// Compare and swap!11883//11884if (fieldOffsetReg)11885generateRSInstruction(cg, TR::InstOpCode::CS, node, tempReg, resultReg, new (cg->trHeapMemory()) TR::MemoryReference(valueReg, fieldOffsetReg, fieldOffset, cg));11886else11887generateRSInstruction(cg, TR::InstOpCode::CS, node, tempReg, resultReg, new (cg->trHeapMemory()) TR::MemoryReference(valueReg, fieldOffset, cg));1188811889// Branch if the compare and swap failed and try again.11890//11891generateS390BranchInstruction(cg, TR::InstOpCode::BRC,TR::InstOpCode::COND_BL, node, loopLabel);1189211893dependencies->addPostCondition(valueReg, TR::RealRegister::AssignAny);11894dependencies->addPostCondition(tempReg, TR::RealRegister::AssignAny);1189511896if (resultReg)11897dependencies->addPostCondition(resultReg, TR::RealRegister::AssignAny);11898if (deltaReg)11899dependencies->addPostCondition(deltaReg, TR::RealRegister::AssignAny);1190011901generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, dependencies);11902cFlowRegionEnd->setEndInternalControlFlow();1190311904if (deltaChild != NULL)11905cg->decReferenceCount(deltaChild);11906if (deltaReg)11907cg->stopUsingRegister(deltaReg);1190811909cg->decReferenceCount(valueChild);11910cg->stopUsingRegister(valueReg);1191111912if (isGetAndOp)11913{11914// For Get And Op, the return value be stored in the temp register11915//11916if(resultReg)11917cg->stopUsingRegister(resultReg);11918node->setRegister(tempReg);11919return tempReg;11920}11921else11922{11923// For Op And Get, the return value will be stored in the result register11924//11925cg->stopUsingRegister(tempReg);11926node->setRegister(resultReg);11927return resultReg;11928}11929}1193011931static TR::Register *11932evaluateTwo32BitLoadsInA64BitRegister(11933TR::Node *node,11934TR::CodeGenerator *cg,11935TR::Node * highNode,11936TR::Node *lowNode)11937{11938TR::Register * targetRegister = cg->gprClobberEvaluate(highNode);11939TR::Instruction * cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, targetRegister, targetRegister, 32);1194011941generateRRInstruction(cg, TR::InstOpCode::LR, node, targetRegister, cg->evaluate(lowNode));11942return targetRegister;11943}1194411945//TODO: CS clobbers first arg, and padLow ,refFirst11946static TR::RegisterPair *11947evaluateTwo32BitLoadsInAConsecutiveEvenOddPair(11948TR::Node *node,11949TR::CodeGenerator *cg,11950TR::Node * highNode,11951TR::Node *lowNode,11952TR::RegisterDependencyConditions * dependencies,11953bool isRefFirst,11954bool isClobberEval)11955{11956TR::Register * evenReg = (isClobberEval || (!isRefFirst))? cg->gprClobberEvaluate(highNode) : cg->evaluate(highNode);11957TR::Register * oddReg = (isClobberEval || (isRefFirst))? cg->gprClobberEvaluate(lowNode) : cg->evaluate(lowNode);11958TR::Register * padReg = isRefFirst ? oddReg : evenReg;11959generateRSInstruction(cg, TR::InstOpCode::SLLG, node, padReg, padReg, 32);1196011961TR::RegisterPair * newRegisterPair = cg->allocateConsecutiveRegisterPair(oddReg, evenReg);11962dependencies->addPostCondition(evenReg, TR::RealRegister::LegalEvenOfPair);11963dependencies->addPostCondition(oddReg, TR::RealRegister::LegalOddOfPair);11964dependencies->addPostCondition(newRegisterPair, TR::RealRegister::EvenOddPair);11965TR_ASSERT( newRegisterPair->getHighOrder() == evenReg, "evenReg is not high order\n");11966return newRegisterPair;11967}1196811969TR::Register*11970J9::Z::TreeEvaluator::inlineAtomicFieldUpdater(TR::Node *node, TR::CodeGenerator *cg, TR::MethodSymbol *method)11971{11972TR::Compilation *comp = cg->comp();11973TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());11974TR::Register * resultReg;11975TR::RecognizedMethod currentMethod = method->getRecognizedMethod();1197611977//Gather information about the method11978bool isAddOp = true;11979bool isGetAndOp = true;11980bool isArgConstant = false;11981int32_t delta = 1;11982char* className = "java/util/concurrent/atomic/AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl";11983int32_t classNameLen = 83;1198411985switch (currentMethod)11986{11987case TR::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_getAndDecrement:11988delta = -1;11989case TR::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_getAndIncrement:11990isArgConstant = true;11991case TR::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_getAndAdd:11992break;11993case TR::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_decrementAndGet:11994delta = -1;11995case TR::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_incrementAndGet:11996isArgConstant = true;11997case TR::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_addAndGet:11998isGetAndOp = false;11999break;12000}1200112002// getting the offsets to various fields: tclass, class, offset12003TR_ResolvedMethod *owningMethod = node->getSymbolReference()->getOwningMethod(comp);12004TR_OpaqueClassBlock *containingClass = fej9->getClassFromSignature(className, classNameLen, owningMethod, true);12005int32_t offset = fej9->getInstanceFieldOffset(containingClass, "offset", 6, "J", 1)12006+ fej9->getObjectHeaderSizeInBytes(); // size of a J9 object header12007int32_t cclass = fej9->getInstanceFieldOffset(containingClass, "cclass", 6, "Ljava/lang/Class;", 17)12008+ fej9->getObjectHeaderSizeInBytes(); // size of a J9 object header12009int32_t tclass = fej9->getInstanceFieldOffset(containingClass, "tclass", 6, "Ljava/lang/Class;", 17)12010+ fej9->getObjectHeaderSizeInBytes(); // size of a J9 object header1201112012TR::Register * thisReg = cg->evaluate(node->getFirstChild());12013TR::Register * objReg = cg->evaluate(node->getSecondChild());12014TR::Register * tempReg = cg->allocateRegister();12015TR::Register * trueReg = cg->machine()->getRealRegister(TR::RealRegister::GPR5);12016TR::Register * deltaReg;12017TR::Register * offsetReg = cg->allocateRegister();12018TR::Register * tClassReg = cg->allocateRegister();12019TR::Register * objClassReg = cg->allocateRegister();1202012021TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);12022TR::LabelSymbol *callLabel = generateLabelSymbol(cg);1202312024// evaluate the delta node if it exists12025if (isArgConstant)12026{12027deltaReg = cg->allocateRegister();12028generateRIInstruction(cg, TR::InstOpCode::LHI, node, deltaReg, delta);12029}12030else12031{12032deltaReg = cg->evaluate(node->getChild(2));12033}1203412035bool is64Bit = comp->target().is64Bit() && !comp->useCompressedPointers();1203612037// cclass == null?12038generateRRInstruction(cg, is64Bit ? TR::InstOpCode::XGR : TR::InstOpCode::XR, node, tempReg, tempReg);12039generateRXInstruction(cg, is64Bit ? TR::InstOpCode::CG : TR::InstOpCode::C, node, tempReg, generateS390MemoryReference(thisReg, cclass, cg));12040generateRRFInstruction(cg, TR::InstOpCode::LOCR, node, tempReg, trueReg, getMaskForBranchCondition(TR::InstOpCode::COND_BNER), true);1204112042// obj == null?12043generateRRInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::LTGR : TR::InstOpCode::LTR, node, objReg, objReg);12044generateRRFInstruction(cg, TR::InstOpCode::LOCR, node, tempReg, trueReg, getMaskForBranchCondition(TR::InstOpCode::COND_BER), true);1204512046TR::TreeEvaluator::genLoadForObjectHeadersMasked(cg, node, objClassReg, generateS390MemoryReference(objReg, TR::Compiler->om.offsetOfObjectVftField(), cg), NULL);1204712048// obj.getClass() == tclass?12049if (comp->useCompressedPointers())12050{12051// inline the getClass() method = grab it from j9class12052generateRXInstruction(cg, TR::InstOpCode::LG, node, objClassReg, generateS390MemoryReference(objClassReg, fej9->getOffsetOfJavaLangClassFromClassField(), cg));1205312054// get tclass12055generateRXInstruction(cg, TR::InstOpCode::LLGF, node, tClassReg, generateS390MemoryReference(thisReg, tclass, cg));12056int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();12057if (shiftAmount != 0)12058{12059generateRSInstruction(cg, TR::InstOpCode::SLLG, node, tClassReg, tClassReg, shiftAmount);12060}12061}12062else12063{12064// inline the getClass() method = grab it from j9class12065generateRXInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::LG : TR::InstOpCode::L, node, objClassReg, generateS390MemoryReference(objClassReg, fej9->getOffsetOfJavaLangClassFromClassField(), cg));1206612067// get tclass12068generateRXInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::LG : TR::InstOpCode::L, node, tClassReg, generateS390MemoryReference(thisReg, tclass, cg));12069}12070generateRRInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::CGR : TR::InstOpCode::CR, node, objClassReg, tClassReg);12071generateRRFInstruction(cg, TR::InstOpCode::LOCR, node, tempReg, trueReg, getMaskForBranchCondition(TR::InstOpCode::COND_BNER), true);1207212073// if any of the above has set the flag, we need to revert back to call the original method via OOL12074generateRRInstruction(cg, TR::InstOpCode::LTR, node, tempReg, tempReg);12075generateS390BranchInstruction (cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, callLabel);1207612077// start OOL12078TR_S390OutOfLineCodeSection *outlinedCall = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(callLabel, doneLabel, cg);12079cg->getS390OutOfLineCodeSectionList().push_front(outlinedCall);12080outlinedCall->swapInstructionListsWithCompilation();12081TR::Instruction * cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, callLabel);1208212083if (cg->getDebug())12084cg->getDebug()->addInstructionComment(cursor, "Denotes start of OOL AtomicFieldUpdater");1208512086// original call, this decrements node counts12087resultReg = TR::TreeEvaluator::performCall(node, false, cg);1208812089cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, doneLabel);12090if (cg->getDebug())12091cg->getDebug()->addInstructionComment(cursor, "Denotes end of OOL AtomicFieldUpdater");1209212093outlinedCall->swapInstructionListsWithCompilation();1209412095// inline fast path: use Load-and-add. Get the offset of the value from the reflection object12096generateRXInstruction(cg, TR::InstOpCode::LG, node, offsetReg, generateS390MemoryReference(thisReg, offset, cg));12097generateRSInstruction(cg, TR::InstOpCode::LAA, node, resultReg, deltaReg, new (cg->trHeapMemory()) TR::MemoryReference(objReg, offsetReg, 0, cg));1209812099// for addAndGet we need to recompute the resultReg12100if (!isGetAndOp)12101{12102generateRRInstruction(cg, TR::InstOpCode::AR, node, resultReg, deltaReg);12103}1210412105generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);1210612107cg->stopUsingRegister(tempReg);12108cg->stopUsingRegister(deltaReg);12109cg->stopUsingRegister(offsetReg);12110cg->stopUsingRegister(tClassReg);12111cg->stopUsingRegister(objClassReg);1211212113return resultReg;12114}1211512116TR::Register*12117J9::Z::TreeEvaluator::inlineKeepAlive(TR::Node *node, TR::CodeGenerator *cg)12118{12119TR::Node *paramNode = node->getFirstChild();12120TR::Register *paramReg = cg->evaluate(paramNode);12121TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg);12122conditions->addPreCondition(paramReg, TR::RealRegister::AssignAny);12123conditions->addPostCondition(paramReg, TR::RealRegister::AssignAny);12124TR::LabelSymbol *label = generateLabelSymbol(cg);12125generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label, conditions);12126cg->decReferenceCount(paramNode);12127return NULL;12128}1212912130/**12131* Helper routine to generate a write barrier sequence for the Transactional Memory inlined sequences.12132*/12133static void12134genWrtBarForTM(12135TR::Node *node,12136TR::CodeGenerator *cg,12137TR::Register * objReg,12138TR::Register * srcReg,12139TR::Register * resultReg,12140bool checkResultRegForTMSuccess)12141{12142TR::Compilation *comp = cg->comp();12143auto gcMode = TR::Compiler->om.writeBarrierType();12144bool doWrtBar = (gcMode == gc_modron_wrtbar_oldcheck ||12145gcMode == gc_modron_wrtbar_cardmark_and_oldcheck ||12146gcMode == gc_modron_wrtbar_always);12147bool doCrdMrk = (gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental);1214812149if (doWrtBar || doCrdMrk)12150{12151TR::LabelSymbol *doneLabelWrtBar = generateLabelSymbol(cg);12152TR::Register *epReg = cg->allocateRegister();12153TR::Register *raReg = cg->allocateRegister();1215412155TR::RegisterDependencyConditions* condWrtBar = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 5, cg);1215612157condWrtBar->addPostCondition(objReg, TR::RealRegister::GPR1);12158condWrtBar->addPostCondition(srcReg, TR::RealRegister::GPR2);12159condWrtBar->addPostCondition(epReg, cg->getEntryPointRegister());12160condWrtBar->addPostCondition(raReg, cg->getReturnAddressRegister());1216112162// tmOffer returns 0 if transaction succeeds, tmPoll returns a non-Null object pointer if the transaction succeeds12163// we skip the wrtbar if TM failed12164if (checkResultRegForTMSuccess)12165{12166// the resultReg is not in the reg deps for tmOffer, add it for internal control flow12167condWrtBar->addPostCondition(resultReg, TR::RealRegister::AssignAny);12168generateRRInstruction(cg, TR::InstOpCode::LTR, node, resultReg, resultReg);12169generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, doneLabelWrtBar);12170}12171else12172{12173generateRRInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::LTGR : TR::InstOpCode::LTR, node, resultReg, resultReg);12174generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, doneLabelWrtBar);12175}1217612177if (doWrtBar)12178{12179TR::SymbolReference *wbRef;1218012181if (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_oldcheck)12182wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreGenerationalSymbolRef(comp->getMethodSymbol());12183else12184wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreSymbolRef(comp->getMethodSymbol());1218512186VMnonNullSrcWrtBarCardCheckEvaluator(node, objReg, srcReg, epReg, raReg, doneLabelWrtBar,12187wbRef, condWrtBar, cg, false);12188}12189else if (doCrdMrk)12190{12191VMCardCheckEvaluator(node, objReg, epReg, condWrtBar, cg, false, doneLabelWrtBar, false);12192// true #1 -> copy of objReg just happened, it's safe to clobber tempReg12193// false #2 -> Don't do compile time check for heap obj12194}1219512196generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabelWrtBar, condWrtBar);1219712198cg->stopUsingRegister(epReg);12199cg->stopUsingRegister(raReg);12200}12201}1220212203TR::Register*12204J9::Z::TreeEvaluator::inlineConcurrentLinkedQueueTMOffer(TR::Node *node, TR::CodeGenerator *cg)12205{12206int32_t offsetTail = 0;12207int32_t offsetNext = 0;12208TR_OpaqueClassBlock * classBlock1 = NULL;12209TR_OpaqueClassBlock * classBlock2 = NULL;12210TR::Register * rReturn = cg->allocateRegister();12211TR::Register * rThis = cg->evaluate(node->getFirstChild());12212TR::Register * rP = cg->allocateCollectedReferenceRegister();12213TR::Register * rQ = cg->allocateCollectedReferenceRegister();12214TR::Register * rN = cg->evaluate(node->getSecondChild());12215TR::Instruction * cursor = NULL;12216TR::LabelSymbol * insertLabel = generateLabelSymbol(cg);12217TR::LabelSymbol * doneLabel = generateLabelSymbol(cg);12218TR::LabelSymbol * failLabel = generateLabelSymbol(cg);1221912220TR::Compilation *comp = cg->comp();12221TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());1222212223TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 5, cg);1222412225deps->addPostCondition(rReturn, TR::RealRegister::AssignAny);12226deps->addPostCondition(rThis, TR::RealRegister::AssignAny);12227deps->addPostCondition(rP, TR::RealRegister::AssignAny);12228deps->addPostCondition(rQ, TR::RealRegister::AssignAny);12229deps->addPostCondition(rN, TR::RealRegister::AssignAny);1223012231bool usesCompressedrefs = comp->useCompressedPointers();12232int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();12233static char * disableTMOfferenv = feGetEnv("TR_DisableTMOffer");12234bool disableTMOffer = (disableTMOfferenv != NULL);1223512236classBlock1 = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49, comp->getCurrentMethod(), true);12237classBlock2 = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue;", 44, comp->getCurrentMethod(), true);122381223912240if (classBlock1 && classBlock2)12241{12242offsetNext = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock1, "next", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);12243offsetTail = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock2, "tail", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);12244}12245else12246disableTMOffer = true;1224712248cursor = generateRIInstruction(cg, TR::InstOpCode::LHI, node, rReturn, 1);1224912250static char * debugTM= feGetEnv("TR_DebugTM");1225112252if (debugTM)12253{12254if (disableTMOffer)12255{12256printf ("\nTM: disabling TM CLQ.Offer in %s (%s)", comp->signature(), comp->getHotnessName(comp->getMethodHotness()));12257fflush(stdout);12258}12259else12260{12261printf ("\nTM: use TM CLQ.Offer in %s (%s)", comp->signature(), comp->getHotnessName(comp->getMethodHotness()));12262fflush(stdout);12263}12264}1226512266static char * useNonConstrainedTM = feGetEnv("TR_UseNonConstrainedTM");12267static char * disableNIAI = feGetEnv("TR_DisableNIAI");1226812269// the Transaction Diagnostic Block (TDB) is a memory location for the OS to write state info in the event of an abort12270TR::MemoryReference* TDBmemRef = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(), fej9->thisThreadGetTDBOffset(), cg);1227112272if (!disableTMOffer)12273{12274if (useNonConstrainedTM)12275{12276// immediate field described in TR::TreeEvaluator::tstartEvaluator12277cursor = generateSILInstruction(cg, TR::InstOpCode::TBEGIN, node, TDBmemRef, 0xFF02);1227812279cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK7, node, failLabel);12280}12281else12282{12283// No TDB for constrained transactions. Immediate field reflects TBEGINC can't filter interrupts12284cursor = generateSILInstruction(cg, TR::InstOpCode::TBEGINC, node, generateS390MemoryReference(0, cg), 0xFF00);12285}1228612287if (!disableNIAI)12288cursor = generateS390IEInstruction(cg, TR::InstOpCode::NIAI, 1, 0, node);1228912290if (usesCompressedrefs)12291{12292cursor = generateRXInstruction(cg, TR::InstOpCode::LLGF, node, rP, generateS390MemoryReference(rThis, offsetTail, cg));1229312294if (shiftAmount != 0)12295{12296cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, rP, rP, shiftAmount);12297}12298}12299else12300{12301cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, rP, generateS390MemoryReference(rThis, offsetTail, cg));12302}1230312304if (!disableNIAI)12305cursor = generateS390IEInstruction(cg, TR::InstOpCode::NIAI, 1, 0, node);1230612307if (usesCompressedrefs)12308{12309cursor = generateRXInstruction(cg, TR::InstOpCode::LT, node, rQ, generateS390MemoryReference(rP, offsetNext, cg));12310cursor = generateRRInstruction(cg, TR::InstOpCode::LLGFR, node, rQ, rQ);1231112312if (shiftAmount != 0)12313{12314cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, rQ, rQ, shiftAmount);12315}12316}12317else12318{12319cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadTestOpCode(), node, rQ, generateS390MemoryReference(rP, offsetNext, cg));12320}1232112322cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, insertLabel);12323cursor = generateRRInstruction(cg, TR::InstOpCode::getLoadRegOpCode(), node, rP, rQ);1232412325if (!disableNIAI)12326cursor = generateS390IEInstruction(cg, TR::InstOpCode::NIAI, 1, 0, node);1232712328if (usesCompressedrefs)12329{12330cursor = generateRXInstruction(cg, TR::InstOpCode::LT, node, rQ, generateS390MemoryReference(rP, offsetNext, cg));12331cursor = generateRRInstruction(cg, TR::InstOpCode::LLGFR, node, rQ, rQ);12332if (shiftAmount != 0)12333{12334cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, rQ, rQ, shiftAmount);12335}12336}12337else12338{12339cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadTestOpCode(), node, rQ, generateS390MemoryReference(rP, offsetNext, cg));12340}1234112342cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, insertLabel);12343cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, doneLabel);1234412345cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, insertLabel);1234612347if (usesCompressedrefs)12348{12349if (shiftAmount != 0)12350{12351cursor = generateRSInstruction(cg, TR::InstOpCode::SRLG, node, rQ, rN, shiftAmount);12352cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, rQ, generateS390MemoryReference(rP, offsetNext, cg));12353cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, rQ, generateS390MemoryReference(rThis, offsetTail, cg));12354}12355else12356{12357cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, rN, generateS390MemoryReference(rP, offsetNext, cg));12358cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, rN, generateS390MemoryReference(rThis, offsetTail, cg));12359}12360}12361else12362{12363cursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, rN, generateS390MemoryReference(rP, offsetNext, cg));12364cursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, rN, generateS390MemoryReference(rThis, offsetTail, cg));12365}1236612367cursor = generateRRInstruction(cg, TR::InstOpCode::XR, node, rReturn, rReturn);1236812369cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);1237012371cursor = generateSInstruction(cg, TR::InstOpCode::TEND, node, generateS390MemoryReference(cg->machine()->getRealRegister(TR::RealRegister::GPR0),0,cg));12372}1237312374if (useNonConstrainedTM || disableTMOffer)12375cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, failLabel, deps);1237612377genWrtBarForTM(node, cg, rP, rN, rReturn, true);12378genWrtBarForTM(node, cg, rThis, rN, rReturn, true);1237912380cg->decReferenceCount(node->getFirstChild());12381cg->decReferenceCount(node->getSecondChild());12382cg->stopUsingRegister(rP);12383cg->stopUsingRegister(rQ);1238412385node->setRegister(rReturn);12386return rReturn;12387}1238812389TR::Register*12390J9::Z::TreeEvaluator::inlineConcurrentLinkedQueueTMPoll(TR::Node *node, TR::CodeGenerator *cg)12391{12392int32_t offsetHead = 0;12393int32_t offsetNext = 0;12394int32_t offsetItem = 0;12395TR_OpaqueClassBlock * classBlock1 = NULL;12396TR_OpaqueClassBlock * classBlock2 = NULL;1239712398TR::Register * rE = cg->allocateCollectedReferenceRegister();12399TR::Register * rP = cg->allocateCollectedReferenceRegister();12400TR::Register * rQ = cg->allocateCollectedReferenceRegister();12401TR::Register * rThis = cg->evaluate(node->getFirstChild());12402TR::Register * rTmp = NULL;12403TR::Instruction * cursor = NULL;12404TR::LabelSymbol * doneLabel = generateLabelSymbol(cg);12405TR::LabelSymbol * failLabel = generateLabelSymbol(cg);1240612407TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 5, cg);12408deps->addPostCondition(rE, TR::RealRegister::AssignAny);12409deps->addPostCondition(rP, TR::RealRegister::AssignAny);12410deps->addPostCondition(rQ, TR::RealRegister::AssignAny);12411deps->addPostCondition(rThis, TR::RealRegister::AssignAny);1241212413TR::Compilation *comp = cg->comp();12414TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());1241512416bool usesCompressedrefs = comp->useCompressedPointers();12417int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();1241812419if (usesCompressedrefs && shiftAmount !=0)12420{12421rTmp = cg->allocateRegister();12422deps->addPostCondition(rTmp, TR::RealRegister::AssignAny);12423}1242412425static char * disableTMPollenv = feGetEnv("TR_DisableTMPoll");12426bool disableTMPoll = disableTMPollenv;1242712428classBlock1 = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue;", 44, comp->getCurrentMethod(), true);12429classBlock2 = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49, comp->getCurrentMethod(), true);1243012431if (classBlock1 && classBlock2)12432{12433offsetHead = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock1, "head", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);12434offsetNext = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock2, "next", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);12435offsetItem = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock2, "item", 4, "Ljava/lang/Object;", 18);12436}12437else12438disableTMPoll = true;1243912440cursor = generateRRInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node, rE, rE);1244112442static char * debugTM= feGetEnv("TR_DebugTM");1244312444if (debugTM)12445{12446if (disableTMPoll)12447{12448printf ("\nTM: disabling TM CLQ.Poll in %s (%s)", comp->signature(), comp->getHotnessName(comp->getMethodHotness()));12449fflush(stdout);12450}12451else12452{12453printf ("\nTM: use TM CLQ.Poll in %s (%s)", comp->signature(), comp->getHotnessName(comp->getMethodHotness()));12454fflush(stdout);12455}12456}1245712458static char * useNonConstrainedTM = feGetEnv("TR_UseNonConstrainedTM");12459static char * disableNIAI = feGetEnv("TR_DisableNIAI");1246012461// the Transaction Diagnostic Block (TDB) is a memory location for the OS to write state info in the event of an abort12462TR::MemoryReference* TDBmemRef = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(), fej9->thisThreadGetTDBOffset(), cg);1246312464if (!disableTMPoll)12465{12466if (useNonConstrainedTM)12467{12468// immediate field described in TR::TreeEvaluator::tstartEvaluator12469cursor = generateSILInstruction(cg, TR::InstOpCode::TBEGIN, node, TDBmemRef, 0xFF02);1247012471cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK7, node, failLabel);12472}12473else12474{12475// No TDB for constrained transactions. Immediate field reflects TBEGINC can't filter interrupts12476cursor = generateSILInstruction(cg, TR::InstOpCode::TBEGINC, node, generateS390MemoryReference(0, cg), 0xFF00);12477}1247812479if (!disableNIAI)12480cursor = generateS390IEInstruction(cg, TR::InstOpCode::NIAI, 1, 0, node);1248112482if (usesCompressedrefs)12483{12484cursor = generateRXInstruction(cg, TR::InstOpCode::LLGF, node, rP, generateS390MemoryReference(rThis, offsetHead, cg));1248512486if (shiftAmount != 0)12487{12488cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, rP, rP, shiftAmount);12489}12490}12491else12492{12493cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, rP, generateS390MemoryReference(rThis, offsetHead, cg));12494}1249512496if (!disableNIAI)12497cursor = generateS390IEInstruction(cg, TR::InstOpCode::NIAI, 1, 0, node);1249812499if (usesCompressedrefs)12500{12501cursor = generateRXInstruction(cg, TR::InstOpCode::LLGF, node, rE, generateS390MemoryReference(rP, offsetItem, cg));1250212503if (shiftAmount != 0)12504{12505cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, rE, rE, shiftAmount);12506}12507}12508else12509{12510cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, rE, generateS390MemoryReference(rP, offsetItem, cg));12511}1251212513if (!disableNIAI)12514cursor = generateS390IEInstruction(cg, TR::InstOpCode::NIAI, 1, 0, node);1251512516if (usesCompressedrefs)12517{12518cursor = generateRXInstruction(cg, TR::InstOpCode::LT, node, rQ, generateS390MemoryReference(rP, offsetNext, cg));12519cursor = generateSILInstruction(cg, TR::InstOpCode::MVHI, node, generateS390MemoryReference(rP, offsetItem, cg), 0);12520}12521else12522{12523cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadTestOpCode(), node, rQ, generateS390MemoryReference(rP, offsetNext, cg));12524cursor = generateSILInstruction(cg, TR::InstOpCode::getMoveHalfWordImmOpCode(), node, generateS390MemoryReference(rP, offsetItem, cg), 0);12525}1252612527cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, doneLabel);1252812529if (usesCompressedrefs)12530{12531cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, rQ, generateS390MemoryReference(rThis, offsetHead, cg));12532if (shiftAmount != 0)12533{12534cursor = generateRSInstruction(cg, TR::InstOpCode::SRLG, node, rTmp, rP, shiftAmount);12535cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, rTmp, generateS390MemoryReference(rP, offsetNext, cg));12536}12537else12538{12539cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, rP, generateS390MemoryReference(rP, offsetNext, cg));12540}12541}12542else12543{12544cursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, rQ, generateS390MemoryReference(rThis, offsetHead, cg));12545cursor = generateRXInstruction(cg, TR::InstOpCode::getStoreOpCode(), node, rP, generateS390MemoryReference(rP, offsetNext, cg));12546}1254712548if (useNonConstrainedTM)12549cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);12550else12551cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);1255212553cursor = generateSInstruction(cg, TR::InstOpCode::TEND, node, generateS390MemoryReference(cg->machine()->getRealRegister(TR::RealRegister::GPR0),0,cg));12554}1255512556if (useNonConstrainedTM || disableTMPoll)12557cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, failLabel, deps);1255812559if (usesCompressedrefs)12560{12561generateRRInstruction(cg, TR::InstOpCode::LLGFR, node, rQ, rQ);1256212563if (shiftAmount != 0)12564{12565cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, rQ, rQ, shiftAmount);12566}12567}1256812569genWrtBarForTM(node, cg, rThis, rQ, rQ, false);12570// we don't need wrtbar for P, it is dead (or has NULL)1257112572cg->decReferenceCount(node->getFirstChild());12573cg->stopUsingRegister(rP);12574cg->stopUsingRegister(rQ);1257512576if (usesCompressedrefs && shiftAmount != 0)12577{12578cg->stopUsingRegister(rTmp);12579}1258012581node->setRegister(rE);1258212583return rE;12584}1258512586void12587VMgenerateCatchBlockBBStartPrologue(12588TR::Node *node,12589TR::Instruction *fenceInstruction,12590TR::CodeGenerator *cg)12591{12592TR::Compilation *comp = cg->comp();12593TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());1259412595TR::Block *block = node->getBlock();1259612597// Encourage recompilation12598if (fej9->shouldPerformEDO(block, comp))12599{12600TR::Register * biAddrReg = cg->allocateRegister();1260112602// Load address of counter into biAddrReg12603genLoadAddressConstant(cg, node, (uintptr_t) comp->getRecompilationInfo()->getCounterAddress(), biAddrReg);1260412605// Counter is 32-bit, so only use 32-bit opcodes12606TR::MemoryReference * recompMR = generateS390MemoryReference(biAddrReg, 0, cg);12607generateSIInstruction(cg, TR::InstOpCode::ASI, node, recompMR, -1);12608recompMR->stopUsingMemRefRegister(cg);1260912610// Check counter and induce recompilation if counter = 012611TR::LabelSymbol * cFlowRegionStart = generateLabelSymbol(cg);12612TR::LabelSymbol * snippetLabel = generateLabelSymbol(cg);12613TR::LabelSymbol * restartLabel = generateLabelSymbol(cg);1261412615snippetLabel->setEndInternalControlFlow();1261612617TR::Register * tempReg1 = cg->allocateRegister();12618TR::Register * tempReg2 = cg->allocateRegister();1261912620TR::RegisterDependencyConditions * dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 2, cg);12621dependencies->addPostCondition(tempReg1, cg->getEntryPointRegister());12622dependencies->addPostCondition(tempReg2, cg->getReturnAddressRegister());12623// Branch to induceRecompilation helper routine if counter is 0 - based on condition code of the preceding adds.12624generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);12625cFlowRegionStart->setStartInternalControlFlow();12626generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, snippetLabel);1262712628TR::Snippet * snippet = new (cg->trHeapMemory()) TR::S390ForceRecompilationSnippet(cg, node, restartLabel, snippetLabel);12629cg->addSnippet(snippet);12630generateS390LabelInstruction(cg, TR::InstOpCode::label, node, restartLabel, dependencies);1263112632cg->stopUsingRegister(tempReg1);12633cg->stopUsingRegister(tempReg2);1263412635cg->stopUsingRegister(biAddrReg);12636}12637}1263812639float12640J9::Z::TreeEvaluator::interpreterProfilingInstanceOfOrCheckCastTopProb(TR::CodeGenerator * cg, TR::Node * node)12641{12642TR::Compilation *comp = cg->comp();12643TR_ByteCodeInfo bcInfo = node->getByteCodeInfo();12644TR_ValueProfileInfoManager * valueProfileInfo = TR_ValueProfileInfoManager::get(comp);1264512646if (!valueProfileInfo)12647return 0;1264812649TR_AddressInfo *valueInfo = static_cast<TR_AddressInfo*>(valueProfileInfo->getValueInfo(bcInfo, comp, AddressInfo, TR_ValueProfileInfoManager::justInterpreterProfileInfo));12650if (!valueInfo || valueInfo->getNumProfiledValues()==0)12651{12652return 0;12653}1265412655TR_OpaqueClassBlock *topValue = (TR_OpaqueClassBlock *) valueInfo->getTopValue();12656if (!topValue)12657{12658return 0;12659}1266012661if (valueInfo->getTopProbability() < TR::Options::getMinProfiledCheckcastFrequency())12662return 0;1266312664if (comp->getPersistentInfo()->isObsoleteClass(topValue, cg->fe()))12665{12666return 0;12667}1266812669return valueInfo->getTopProbability();12670}1267112672/**12673* countDigitsEvaluator - count the number of decimal digits of an integer/long binary12674* value (excluding the negative sign). The original counting digits Java loop is12675* reduced to this IL node by idiom recognition.12676*/12677TR::Register *12678J9::Z::TreeEvaluator::countDigitsEvaluator(TR::Node * node, TR::CodeGenerator * cg)12679{12680// Idiom recognition will reduce the appropriate loop into the following12681// form:12682// TR::countDigits12683// inputValue // either int or long12684// digits10LookupTable12685//12686// Original loop:12687// do { count ++; } while((l /= 10) != 0);12688//12689// Since the maximum number of decimal digits for an int is 10, and a long is 19,12690// we can perform binary search comparing the input value with pre-computed digits.126911269212693TR::Node * inputNode = node->getChild(0);12694TR::Register * inputReg = cg->gprClobberEvaluate(inputNode);12695TR::Register * workReg = cg->evaluate(node->getChild(1));12696TR::Register * countReg = cg->allocateRegister();1269712698TR_ASSERT( inputNode->getDataType() == TR::Int64 || inputNode->getDataType() == TR::Int32, "child of TR::countDigits must be of integer type");1269912700bool isLong = (inputNode->getDataType() == TR::Int64);12701TR_ASSERT( !isLong || cg->comp()->target().is64Bit(), "CountDigitEvaluator requires 64-bit support for longs");1270212703TR::RegisterDependencyConditions * dependencies;12704dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 3, cg);12705dependencies->addPostCondition(inputReg, TR::RealRegister::AssignAny);12706dependencies->addPostCondition(workReg, TR::RealRegister::AssignAny);12707dependencies->addPostCondition(countReg, TR::RealRegister::AssignAny);1270812709TR::MemoryReference * work[18];12710TR::LabelSymbol * label[18];12711TR::LabelSymbol * cFlowRegionEnd = generateLabelSymbol(cg);1271212713// Get the negative input value (2's complement) - We treat all numbers as12714// negative to simplify the absolute comparison, and take advance of the12715// CC trick in countsDigitHelper.1271612717// If the input is a 32-bit value on 64-bit architecture, we cannot simply use TR::InstOpCode::LNGR because the input may not be sign-extended.12718// If you want to use TR::InstOpCode::LNGR for a 32-bit value on 64-bit architecture, you'll need to additionally generate TR::InstOpCode::LGFR for the input.12719generateRRInstruction(cg, !isLong ? TR::InstOpCode::LNR : TR::InstOpCode::LNGR, node, inputReg, inputReg);1272012721TR::LabelSymbol * cFloWRegionStart = generateLabelSymbol(cg);12722generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFloWRegionStart);12723cFloWRegionStart->setStartInternalControlFlow();1272412725if (isLong)12726{12727for (int32_t i = 0; i < 18; i++)12728{12729work[i] = generateS390MemoryReference(workReg, i*8, cg);12730label[i] = generateLabelSymbol(cg);12731}1273212733generateRXInstruction(cg, TR::InstOpCode::CG, node, inputReg, work[7]);12734generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[11]);1273512736// LABEL 312737generateRXInstruction(cg, TR::InstOpCode::CG, node, inputReg, work[3]);12738generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[5]);1273912740// LABEL 112741generateRXInstruction(cg, TR::InstOpCode::CG, node, inputReg, work[1]);12742generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[2]);1274312744countDigitsHelper(node, cg, 0, work[0], inputReg, countReg, cFlowRegionEnd, isLong); // 0 and 11274512746generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[2]); // LABEL 212747countDigitsHelper(node, cg, 2, work[2], inputReg, countReg, cFlowRegionEnd, isLong); // 2 and 31274812749generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[5]); // LABEL 51275012751generateRXInstruction(cg, TR::InstOpCode::CG, node, inputReg, work[5]);12752generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[6]);1275312754countDigitsHelper(node, cg, 4, work[4], inputReg, countReg, cFlowRegionEnd, isLong); // 4 and 51275512756generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[6]); // LABEL 612757countDigitsHelper(node, cg, 6, work[6], inputReg, countReg, cFlowRegionEnd, isLong); // 6 and 71275812759generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[11]); // LABEL 111276012761generateRXInstruction(cg, TR::InstOpCode::CG, node, inputReg, work[11]);12762generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[14]);1276312764// LABEL 912765generateRXInstruction(cg, TR::InstOpCode::CG, node, inputReg, work[9]);12766generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[10]);1276712768countDigitsHelper(node, cg, 8, work[8], inputReg, countReg, cFlowRegionEnd, isLong); // 8 and 91276912770generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[10]); // LABEL 1012771countDigitsHelper(node, cg, 10, work[10], inputReg, countReg, cFlowRegionEnd, isLong); // 10 and 111277212773generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[14]); // LABEL 141277412775generateRXInstruction(cg, TR::InstOpCode::CG, node, inputReg, work[14]);12776generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[16]);1277712778// LABEL 1212779generateRXInstruction(cg, TR::InstOpCode::CG, node, inputReg, work[12]); // 1212780generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, countReg, 12+1);12781generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BH, node, cFlowRegionEnd);1278212783// LABEL 1312784countDigitsHelper(node, cg, 13, work[13], inputReg, countReg, cFlowRegionEnd, isLong); // 13 and 141278512786generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[16]); // LABEL 161278712788generateRXInstruction(cg, TR::InstOpCode::CG, node, inputReg, work[16]);12789generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[17]);12790// LABEL 1512791countDigitsHelper(node, cg, 15, work[15], inputReg, countReg, cFlowRegionEnd, isLong); // 15 and 161279212793generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[17]); // LABEL 1712794countDigitsHelper(node, cg, 17, work[17], inputReg, countReg, cFlowRegionEnd, isLong); // 17 and 181279512796for (int32_t i = 0; i < 18; i++)12797{12798work[i]->stopUsingMemRefRegister(cg);12799}12800}12801else12802{12803for (int32_t i = 0; i < 9; i++)12804{12805work[i] = generateS390MemoryReference(workReg, i*8+4, cg); // lower 32-bit12806label[i] = generateLabelSymbol(cg);12807}1280812809// We already generate the label instruction, why would we generate it again?12810//generateS390LabelInstruction(cg, TR::InstOpCode::label, node, startLabel);1281112812generateRXInstruction(cg, TR::InstOpCode::C, node, inputReg, work[3]);12813generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[5]);1281412815// LABEL 112816generateRXInstruction(cg, TR::InstOpCode::C, node, inputReg, work[1]);12817generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[2]);1281812819countDigitsHelper(node, cg, 0, work[0], inputReg, countReg, cFlowRegionEnd, isLong); // 0 and 11282012821generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[2]); // LABEL 212822countDigitsHelper(node, cg, 2, work[2], inputReg, countReg, cFlowRegionEnd, isLong); // 2 and 31282312824generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[5]); // LABEL 51282512826generateRXInstruction(cg, TR::InstOpCode::C, node, inputReg, work[5]);12827generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[7]);1282812829countDigitsHelper(node, cg, 4, work[4], inputReg, countReg, cFlowRegionEnd, isLong); // 4 and 51283012831generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[7]); // LABEL 71283212833generateRXInstruction(cg, TR::InstOpCode::C, node, inputReg, work[7]);12834generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNH, node, label[8]);1283512836countDigitsHelper(node, cg, 6, work[6], inputReg, countReg, cFlowRegionEnd, isLong); // 6 and 71283712838generateS390LabelInstruction(cg, TR::InstOpCode::label, node, label[8]); // LABEL 812839countDigitsHelper(node, cg, 8, work[8], inputReg, countReg, cFlowRegionEnd, isLong); // 8 and 9128401284112842for (int32_t i = 0; i < 9; i++)12843{12844work[i]->stopUsingMemRefRegister(cg);12845}12846}1284712848cg->stopUsingRegister(inputReg);12849cg->stopUsingRegister(workReg);1285012851// End12852generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, dependencies);12853cFlowRegionEnd->setEndInternalControlFlow();1285412855node->setRegister(countReg);1285612857cg->decReferenceCount(inputNode);12858cg->decReferenceCount(node->getChild(1));12859return countReg;12860}1286112862/**12863* countDigitsHelper emits code to determine whether the given input value has12864* memRefIndex or memRefIndex+1 digits.12865*/12866void12867J9::Z::TreeEvaluator::countDigitsHelper(TR::Node * node, TR::CodeGenerator * cg,12868int32_t memRefIndex, TR::MemoryReference * memRef,12869TR::Register* inputReg, TR::Register* countReg,12870TR::LabelSymbol *doneLabel, bool isLong)12871{12872// Compare input value with the binary memRefIndex value. The instruction12873// sets CC1 if input <= [memRefIndex], which is also the borrow CC. Since12874// the numbers are all negative, the equivalent comparison is set if12875// inputValue > [memRefIndex].12876generateRXInstruction(cg, (isLong)?TR::InstOpCode::CG:TR::InstOpCode::C, node, inputReg, memRef); \1287712878// Clear countRegister and set it to 1 if inputValue > [memRefIndex].12879generateRRInstruction(cg, TR::InstOpCode::getSubtractWithBorrowOpCode(), node, countReg, countReg);12880generateRRInstruction(cg, TR::InstOpCode::getLoadComplementOpCode(), node, countReg, countReg);1288112882// Calculate final count of digits by adding to memRefIndex + 1. The +1 is12883// required as our memRefIndex starts with index 0, but digit counts starts with 1.12884generateRIInstruction(cg, TR::InstOpCode::getAddHalfWordImmOpCode(), node, countReg, memRefIndex+1);1288512886// CountReg has the number of digits. Jump to done label.12887generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, doneLabel);1288812889}128901289112892/**12893* tstartEvaluator: begin a transaction12894*/12895TR::Register *12896J9::Z::TreeEvaluator::tstartEvaluator(TR::Node * node, TR::CodeGenerator * cg)12897{12898// [0x00000000803797c8] ( 0) tstart12899// [0x0000000080379738] ( 1) branch --> block 28 BBStart at [0x0000000080378bc8]12900// [0x00000000803f15f8] ( 1) GlRegDeps12901// ( 3) ==>aRegLoad at [0x00000000803f1568] (in &GPR_0048)12902// ( 2) ==>aRegLoad at [0x00000000803f15b0] (in &GPR_0049)12903// [0x0000000080379780] ( 1) branch --> block 29 BBStart at [0x0000000080378ed8]12904// [0x00000000803f1640] ( 1) GlRegDeps12905// ( 3) ==>aRegLoad at [0x00000000803f1568] (in &GPR_0048)12906// ( 2) ==>aRegLoad at [0x00000000803f15b0] (in &GPR_0049)12907// [0x00000000803796f0] ( 1) aload #422[0x000000008035e4b0] Auto[<temp slot 2 holds monitoredObject syncMethod>] <flags:"0x4" (X!=0 )/>12908// [0x00000000803f1688] ( 1) GlRegDeps12909// ( 3) ==>aRegLoad at [0x00000000803f1568] (in &GPR_0048)129101291112912// TBEGIN 0(R0),0xFF0012913// BRNEZ OOL TM ; CC0 = success12914// ------ OOL TM ----12915// BRH Block_Transient_Handler ; CC2 = transient failure12916// POST deps (persistent path)12917// BRC Block_Persistent_Handler ; CC1,CC3 = persistent failure12918// Post deps (transient path)12919// BRC mainline ; we need this brc for OOL mechanism, though it's never taken12920// -----------------------12921// LT Rlw, lockword (obj)12922// BEQ Label Start12923// TEND12924// BRC Block_Transient_Handler12925// Label Start12926// POST Deps1292712928TR::Compilation *comp = cg->comp();12929TR_J9VMBase *fej9 = static_cast<TR_J9VMBase*>(cg->fe());12930TR::Instruction * cursor = NULL;1293112932TR::Node * brPersistentNode = node->getFirstChild();12933TR::Node * brTransientNode = node->getSecondChild();12934TR::Node * fallThrough = node->getThirdChild();12935TR::Node * objNode = node->getChild(3);12936TR::Node * GRAChild = NULL;1293712938TR::LabelSymbol * labelPersistentFailure = brPersistentNode->getBranchDestination()->getNode()->getLabel();12939TR::LabelSymbol * labelTransientFailure = brTransientNode->getBranchDestination()->getNode()->getLabel();12940TR::LabelSymbol * startLabel = fallThrough->getBranchDestination()->getNode()->getLabel();1294112942TR::Register * objReg = cg->evaluate(objNode);12943TR::Register * monitorReg = cg->allocateRegister();1294412945TR::RegisterDependencyConditions *deps = NULL;12946TR::RegisterDependencyConditions *depsPersistent = NULL;12947TR::RegisterDependencyConditions *depsTransient = NULL;1294812949// GRA12950if (fallThrough->getNumChildren() !=0)12951{12952GRAChild = fallThrough->getFirstChild();12953cg->evaluate(GRAChild);12954deps = generateRegisterDependencyConditions(cg, GRAChild, 0);12955cg->decReferenceCount(GRAChild);12956}1295712958if (brPersistentNode->getNumChildren() != 0)12959{12960GRAChild = brPersistentNode->getFirstChild();12961cg->evaluate(GRAChild);12962depsPersistent = generateRegisterDependencyConditions(cg, GRAChild, 0);12963cg->decReferenceCount(GRAChild);12964}1296512966if (brTransientNode->getNumChildren() != 0)12967{12968GRAChild = brTransientNode->getFirstChild();12969cg->evaluate(GRAChild);12970depsTransient = generateRegisterDependencyConditions(cg, GRAChild, 0);12971cg->decReferenceCount(GRAChild);12972}1297312974// the Transaction Diagnostic Block (TDB) is a memory location for the OS to write state info in the event of an abort12975TR::MemoryReference* TDBmemRef = generateS390MemoryReference(cg->getMethodMetaDataRealRegister(), fej9->thisThreadGetTDBOffset(), cg);1297612977static char * debugTM = feGetEnv("debugTM");1297812979if (debugTM)12980{12981// artificially set CC to transientFailure, objReg is always > 012982cursor = generateRRInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::LTGR : TR::InstOpCode::LTR, node, objReg, objReg);12983}12984else12985{12986/// Immediate field of TBEGIN:12987/// bits 0-7: FF - General Register Save Mask used to tell the hardware which pairs of registers need to be rolled back.12988/// always set to FF here because GRA will later decide which registers we actually need to roll back.12989/// bits 8-11: 0 - not used by hardware, always zero.12990/// bit 12: 0 - Allow access register modification12991/// bit 13: 0 - Allow floating-point operation12992/// bits 14-15: 2 - Program-Interruption-Filtering Control12993/// PIFC bits needs to be set to 2, to allow 0C4 and 0C7 interrupts to resume, instead of being thrown.12994/// Since all interrupts cause aborts, the PSW is rolled back to TBEGIN on interrupts. The 0C7 interrupts12995/// are generated by trap instructions for Java exception handling. The 0C4 interrupts are used by z/OS LE to12996/// detect guarded page exceptions which are used to trigger XPLINK stack growth. In both cases, either the12997/// LE or JIT signal handler need the PSW of the actual instruction that generated the interrupt, not the12998/// rolled back PSW pointing to TBEGIN. Without filtering these interrupts, the program will crash. Filtering12999/// the interrupts allows us to resume execution following the abort and go to slow path so the exceptions13000/// can be properly caught and handled.1300113002cursor = generateSILInstruction(cg, TR::InstOpCode::TBEGIN, node, TDBmemRef, 0xFF02);13003}1300413005if (labelTransientFailure == labelPersistentFailure)13006{13007if (depsPersistent != depsTransient) //only possible to be equal if they are NULL (i.e. non existent)13008{13009TR_ASSERT( depsPersistent && depsTransient, "regdeps wrong in tstart evaluator");13010uint32_t i = depsPersistent->getNumPostConditions();13011uint32_t j = depsTransient->getNumPostConditions();13012TR_ASSERT( i == j, "regdep postcondition number not the same");13013depsPersistent->getPostConditions()->getRegisterDependency(i);13014i = depsPersistent->getNumPreConditions();13015j = depsTransient->getNumPreConditions();13016TR_ASSERT( i == j, "regdep precondition number not the same");13017}13018cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK7, node, labelTransientFailure, depsPersistent);13019}13020else13021{13022cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BH, node, labelTransientFailure, depsTransient);13023cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK7, node, labelPersistentFailure, depsPersistent);13024}130251302613027int32_t lwOffset = cg->fej9()->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node));1302813029if (comp->target().is64Bit() && cg->fej9()->generateCompressedLockWord())13030cursor = generateRXInstruction(cg, TR::InstOpCode::LT, node, monitorReg, generateS390MemoryReference(objReg, lwOffset, cg), cursor);13031else13032cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadTestOpCode(), node, monitorReg, generateS390MemoryReference(objReg, lwOffset, cg),cursor);1303313034cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, startLabel, deps, cursor);1303513036TR::MemoryReference * tempMR1 = generateS390MemoryReference(cg->machine()->getRealRegister(TR::RealRegister::GPR0),0,cg);1303713038// use TEND + BRC instead of TABORT for better performance13039cursor = generateSInstruction(cg, TR::InstOpCode::TEND, node, tempMR1, cursor);1304013041cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, labelTransientFailure, depsTransient, cursor);1304213043cg->stopUsingRegister(monitorReg);13044cg->decReferenceCount(objNode);13045cg->decReferenceCount(brPersistentNode);13046cg->decReferenceCount(brTransientNode);13047cg->decReferenceCount(fallThrough);1304813049return NULL;13050}1305113052/**13053* tfinishEvaluator: end a transaction13054*/13055TR::Register *13056J9::Z::TreeEvaluator::tfinishEvaluator(TR::Node * node, TR::CodeGenerator * cg)13057{13058TR::MemoryReference * tempMR1 = generateS390MemoryReference(cg->machine()->getRealRegister(TR::RealRegister::GPR0),0,cg);13059TR::Instruction * cursor = generateSInstruction(cg, TR::InstOpCode::TEND, node, tempMR1);1306013061return NULL;13062}1306313064/**13065* tabortEvaluator: abort a transaction13066*/13067TR::Register *13068J9::Z::TreeEvaluator::tabortEvaluator(TR::Node * node, TR::CodeGenerator * cg)13069{13070TR::Instruction *cursor;13071TR::LabelSymbol * labelDone = generateLabelSymbol(cg);13072TR::Register *codeReg = cg->allocateRegister();13073generateRIInstruction(cg, cg->comp()->target().is64Bit() ? TR::InstOpCode::LGHI : TR::InstOpCode::LHI, node, codeReg, 0);13074//Get the nesting depth13075cursor = generateRREInstruction(cg, TR::InstOpCode::ETND, node, codeReg, codeReg);1307613077generateRIInstruction(cg, TR::InstOpCode::CHI, node, codeReg, 0);13078//branch on zero to done label13079generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK8, node, labelDone);13080generateRIInstruction(cg, cg->comp()->target().is64Bit() ? TR::InstOpCode::LGHI : TR::InstOpCode::LHI, node, codeReg, 0x100);13081TR::MemoryReference *codeMR = generateS390MemoryReference(codeReg, 0, cg);13082cursor = generateSInstruction(cg, TR::InstOpCode::TABORT, node, codeMR);13083generateS390LabelInstruction(cg, TR::InstOpCode::label, node, labelDone);13084cg->stopUsingRegister(codeReg);13085return NULL;13086}1308713088/**13089* \details13090* Resolved and unresolved reference field load get two slightly different sequences.13091*13092* Resolved reference fields load sequence for -XnocompressedRefs:13093* \verbatim13094*13095* Label: startICF13096* LG R_obj, Ref_field_MemRef13097*13098* // range check with implicit CS cycle check13099* CLG R_obj, EvacuateBase(R_vmthread)13100* BRC COND_BL, doneLabel13101* CLG R_obj, EvacuateTop(R_vmthread)13102* BRC COND_BH, doneLabel13103*13104* LAY R_addr, Ref_field_MemRef13105* BRC helper_call_snippet13106*13107* Label: jitReadBarrier return label13108* // reload evacuated reference13109* LG R_obj, 0(R_addr)13110*13111* doneLabel: endICF13112* \endverbatim13113*13114*13115* Unresolved reference fields load sequence for -XnocompressedRefs:13116* \verbatim13117*13118* Label: startICF13119* LAY R_addr, Ref_field_MemRef13120* LG R_obj, 0(R_addr)13121*13122* // range check with implicit CS cycle check13123* CLG R_obj, EvacuateBase(R_vmthread)13124* BRC COND_BL, doneLabel13125* CLG R_obj, EvacuateTop(R_vmthread)13126* BRC COND_BH, doneLabel13127*13128* BRC helper_call_snippet13129*13130* Label: jitReadBarrier return label13131* // reload evacuated reference13132* LG R_obj, 0(R_addr)13133*13134* doneLabel: endICF13135* \endverbatim13136*13137* If compressed pointer is enabled, the LG instructions above are replaced by LLGF+SLLG.13138*/13139TR::Register *13140J9::Z::TreeEvaluator::generateSoftwareReadBarrier(TR::Node* node,13141TR::CodeGenerator* cg,13142TR::Register* resultReg,13143TR::MemoryReference* loadMemRef,13144TR::RegisterDependencyConditions* deps,13145bool produceUnshiftedValue)13146{13147TR::Compilation* comp = cg->comp();13148TR::Register* fieldAddrReg = cg->allocateRegister();13149TR::RealRegister* raReg = cg->machine()->getRealRegister(cg->getReturnAddressRegister());13150bool isCompressedRef = comp->useCompressedPointers();1315113152if (!isCompressedRef)13153{13154TR::TreeEvaluator::checkAndSetMemRefDataSnippetRelocationType(node, cg, loadMemRef);13155}1315613157const bool fieldUnresolved = node->getSymbolReference()->isUnresolved();13158if (comp->getOption(TR_TraceCG))13159{13160traceMsg(comp, "SoftwareReadBarrier: symbol is %s. Compr shift %d. RA reg: %s Entry reg %s\n",13161fieldUnresolved ? "unresolved" : "resolved",13162TR::Compiler->om.compressedReferenceShift(),13163raReg->getRegisterName(comp),13164cg->getEntryPointRealRegister()->getRegisterName(comp));13165}1316613167bool notInsideICF = (deps == NULL);13168if (notInsideICF)13169{13170deps = generateRegisterDependencyConditions(0, 6, cg);13171TR::LabelSymbol* startICFLabel = generateLabelSymbol(cg);1317213173generateS390LabelInstruction(cg, TR::InstOpCode::label, node, startICFLabel);13174startICFLabel->setStartInternalControlFlow();13175}1317613177TR::Register* dummyRegForRA = cg->allocateRegister();13178TR::Register* dummyRegForEntry = cg->allocateRegister();13179dummyRegForRA->setPlaceholderReg();13180dummyRegForEntry->setPlaceholderReg();1318113182deps->addPostCondition(resultReg, TR::RealRegister::AssignAny);13183deps->addPostCondition(fieldAddrReg, comp->target().isLinux() ? TR::RealRegister::GPR3 : TR::RealRegister::GPR2);13184deps->addPostCondition(dummyRegForRA, cg->getReturnAddressRegister());13185deps->addPostCondition(dummyRegForEntry, cg->getEntryPointRegister());1318613187cg->stopUsingRegister(dummyRegForRA);13188cg->stopUsingRegister(dummyRegForEntry);1318913190int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();13191bool shouldShift = (shiftAmount != 0) && !produceUnshiftedValue;13192TR::InstOpCode::Mnemonic loadOpCode = isCompressedRef ? TR::InstOpCode::LLGF: TR::InstOpCode::LG;1319313194if (fieldUnresolved)13195{13196generateRXInstruction(cg, TR::InstOpCode::LA, node, fieldAddrReg, loadMemRef);13197generateRXInstruction(cg, loadOpCode, node, resultReg, generateS390MemoryReference(fieldAddrReg, 0, cg));13198}13199else13200{13201generateRXInstruction(cg, loadOpCode, node, resultReg, loadMemRef);13202}1320313204deps->addAssignAnyPostCondOnMemRef(loadMemRef);1320513206TR::Register* vmReg = cg->getLinkage()->getMethodMetaDataRealRegister();1320713208TR::MemoryReference* baseMemRef = generateS390MemoryReference(vmReg, TR::Compiler->vm.thisThreadGetEvacuateBaseAddressOffset(comp), cg);13209TR::MemoryReference* topMemRef = generateS390MemoryReference(vmReg, TR::Compiler->vm.thisThreadGetEvacuateTopAddressOffset(comp), cg);1321013211// Range check with implicit software CS status check.13212TR::LabelSymbol* doneLabel = generateLabelSymbol(cg);13213generateRXInstruction(cg, comp->useCompressedPointers() ? TR::InstOpCode::CL : TR::InstOpCode::CLG, node, resultReg, baseMemRef);13214generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BL, node, doneLabel);13215generateRXInstruction(cg, comp->useCompressedPointers() ? TR::InstOpCode::CL : TR::InstOpCode::CLG, node, resultReg, topMemRef);13216generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BH, node, doneLabel);13217cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "readBar/helperCall"), 1, TR::DebugCounter::Cheap);13218if (!fieldUnresolved)13219{13220generateRXInstruction(cg, TR::InstOpCode::LA, node, fieldAddrReg, generateS390MemoryReference(*loadMemRef, 0, cg));13221}1322213223TR::LabelSymbol* callLabel = generateLabelSymbol(cg);13224TR::LabelSymbol* callEndLabel = generateLabelSymbol(cg);13225TR::Instruction *gcPoint = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, callLabel);13226gcPoint->setNeedsGCMap(0);13227auto readBarHelperSnippet = new (cg->trHeapMemory()) TR::S390HelperCallSnippet(cg, node, callLabel,13228cg->symRefTab()->findOrCreateRuntimeHelper(TR_softwareReadBarrier),13229callEndLabel);13230cg->addSnippet(readBarHelperSnippet);13231generateS390LabelInstruction(cg, TR::InstOpCode::label, node, callEndLabel);1323213233// Reload the object after helper call.13234generateRXInstruction(cg, loadOpCode, node, resultReg, generateS390MemoryReference(fieldAddrReg, 0, cg));13235TR::Instruction* cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);13236if (notInsideICF)13237{13238cursor->setDependencyConditions(deps);13239doneLabel->setEndInternalControlFlow();13240}1324113242// produce decompressed value in the end13243if (shouldShift)13244{13245generateRSInstruction(cg, TR::InstOpCode::SLLG, node, resultReg, resultReg, shiftAmount);13246}1324713248cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "readBar/total"), 1, TR::DebugCounter::Cheap);13249cg->stopUsingRegister(fieldAddrReg);1325013251return resultReg;13252}1325313254TR::Register *13255J9::Z::TreeEvaluator::arraycopyEvaluator(TR::Node * node, TR::CodeGenerator * cg)13256{13257if (node->isReferenceArrayCopy())13258{13259TR::TreeEvaluator::referenceArraycopyEvaluator(node, cg);13260}13261else13262{13263OMR::TreeEvaluatorConnector::arraycopyEvaluator(node, cg);13264}13265return NULL;13266}1326713268TR::Register *13269J9::Z::TreeEvaluator::referenceArraycopyEvaluator(TR::Node * node, TR::CodeGenerator * cg)13270{13271TR::Node* byteSrcObjNode = node->getChild(0);13272TR::Node* byteDstObjNode = node->getChild(1);13273TR::Node* byteSrcNode = node->getChild(2);13274TR::Node* byteDstNode = node->getChild(3);13275TR::Node* byteLenNode = node->getChild(4);1327613277TR::Register* byteSrcObjReg = cg->evaluate(byteSrcObjNode);13278TR::Register* byteDstObjReg = cg->evaluate(byteDstObjNode);1327913280if (!node->chkNoArrayStoreCheckArrayCopy())13281{13282TR::Register* byteSrcReg = cg->evaluate(byteSrcNode);13283TR::Register* byteDstReg = cg->evaluate(byteDstNode);13284TR::Register* byteLenReg = cg->evaluate(byteLenNode);1328513286genArrayCopyWithArrayStoreCHK(node, byteSrcObjReg, byteDstObjReg, byteSrcReg, byteDstReg, byteLenReg, cg);1328713288cg->decReferenceCount(byteSrcNode);13289cg->decReferenceCount(byteDstNode);13290cg->decReferenceCount(byteLenNode);13291}13292else13293{13294TR_ASSERT_FATAL(node->getArrayCopyElementType() == TR::Address, "Reference arraycopy element type should be TR::Address but was '%s'", node->getArrayCopyElementType().toString());13295primitiveArraycopyEvaluator(node, cg, byteSrcNode, byteDstNode, byteLenNode);13296genWrtbarForArrayCopy(node, byteSrcObjReg, byteDstObjReg, byteSrcNode->isNonNull(), cg);13297}1329813299cg->decReferenceCount(byteSrcObjNode);13300cg->decReferenceCount(byteDstObjNode);13301return NULL;13302}1330313304void13305J9::Z::TreeEvaluator::forwardArrayCopySequenceGenerator(TR::Node *node, TR::CodeGenerator *cg,13306TR::Register *byteSrcReg, TR::Register *byteDstReg,13307TR::Register *byteLenReg, TR::Node *byteLenNode,13308TR_S390ScratchRegisterManager *srm, TR::LabelSymbol *mergeLabel)13309{13310bool mustGenerateOOLGuardedLoadPath = TR::Compiler->om.readBarrierType() != gc_modron_readbar_none &&13311node->getArrayCopyElementType() == TR::Address;13312if (mustGenerateOOLGuardedLoadPath)13313{13314// It might be possible that we have constant byte length load and it is forward array copy.13315// In this case if we need to do guarded Load then need to evaluate byteLenNode.13316if (byteLenReg == NULL)13317byteLenReg = cg->gprClobberEvaluate(byteLenNode);13318TR::TreeEvaluator::genGuardedLoadOOL(node, cg, byteSrcReg, byteDstReg, byteLenReg, mergeLabel, srm, true);13319}1332013321OMR::TreeEvaluatorConnector::forwardArrayCopySequenceGenerator(node, cg, byteSrcReg, byteDstReg, byteLenReg, byteLenNode, srm, mergeLabel);13322}1332313324TR::RegisterDependencyConditions *13325J9::Z::TreeEvaluator::backwardArrayCopySequenceGenerator(TR::Node *node, TR::CodeGenerator *cg,13326TR::Register *byteSrcReg, TR::Register *byteDstReg,13327TR::Register *byteLenReg, TR::Node *byteLenNode,13328TR_S390ScratchRegisterManager *srm, TR::LabelSymbol *mergeLabel)13329{13330bool mustGenerateOOLGuardedLoadPath = TR::Compiler->om.readBarrierType() != gc_modron_readbar_none &&13331node->getArrayCopyElementType() == TR::Address;13332if (mustGenerateOOLGuardedLoadPath)13333{13334TR::TreeEvaluator::genGuardedLoadOOL(node, cg, byteSrcReg, byteDstReg, byteLenReg, mergeLabel, srm, false);13335}1333613337return OMR::TreeEvaluatorConnector::backwardArrayCopySequenceGenerator(node, cg, byteSrcReg, byteDstReg, byteLenReg, byteLenNode, srm, mergeLabel);13338}1333913340void13341J9::Z::TreeEvaluator::generateLoadAndStoreForArrayCopy(TR::Node *node, TR::CodeGenerator *cg,13342TR::MemoryReference *srcMemRef, TR::MemoryReference *dstMemRef,13343TR_S390ScratchRegisterManager *srm,13344TR::DataType elenmentType, bool needsGuardedLoad,13345TR::RegisterDependencyConditions* deps)1334613347{13348TR::Compilation *comp = cg->comp();1334913350if ((node->getArrayCopyElementType() == TR::Address)13351&& needsGuardedLoad13352&& (!comp->target().cpu.supportsFeature(OMR_FEATURE_S390_GUARDED_STORAGE)))13353{13354TR::Register* resultReg = srm->findOrCreateScratchRegister();13355TR::TreeEvaluator::generateSoftwareReadBarrier(node, cg, resultReg, srcMemRef, deps, true);13356TR::InstOpCode::Mnemonic storeOp = TR::InstOpCode::ST;13357if (comp->target().is64Bit() && !comp->useCompressedPointers())13358{13359storeOp = TR::InstOpCode::STG;13360}1336113362generateRXInstruction(cg, storeOp, node, resultReg, dstMemRef);13363srm->reclaimScratchRegister(resultReg);13364}13365else13366{13367OMR::TreeEvaluatorConnector::generateLoadAndStoreForArrayCopy(node, cg, srcMemRef, dstMemRef, srm, elenmentType, needsGuardedLoad, deps);13368}13369}1337013371TR::Register*13372J9::Z::TreeEvaluator::inlineIntegerToCharsForLatin1Strings(TR::Node *node, TR::CodeGenerator *cg)13373{13374TR::Compilation *comp = cg->comp();1337513376TR_ResolvedMethod *candidateToStringMethod = NULL;13377if (node->getInlinedSiteIndex() != -1)13378{13379candidateToStringMethod = comp->getInlinedResolvedMethod(node->getInlinedSiteIndex());13380}13381else13382{13383candidateToStringMethod = comp->getCurrentMethod();13384}13385// If method caller of Integer.stringSize or Long.stringSize is not Integer.toString(I) or Long.toString(J), then we don't inline13386if (candidateToStringMethod->getRecognizedMethod() != TR::java_lang_Long_toString &&13387candidateToStringMethod->getRecognizedMethod() != TR::java_lang_Integer_toString)13388{13389return NULL;13390}1339113392if (comp->getOption(TR_TraceCG))13393{13394traceMsg(comp, "inlineIntegerToCharsForLatin1Strings (compressed strings)\n");13395}13396TR::Node *inputValueNode = node->getChild(0);13397TR::Node *stringSizeNode = node->getChild(1);13398TR::Node *byteArrayNode = node->getChild(2);1339913400TR::Register *inputValueReg = cg->evaluate(inputValueNode);13401TR::Register *stringSizeReg = cg->gprClobberEvaluate(stringSizeNode, true);13402TR::Register *byteArrayReg = cg->gprClobberEvaluate(byteArrayNode, true);1340313404bool inputIs64Bit = inputValueNode->getDataType() == TR::Int64;1340513406TR::MemoryReference *destinationArrayMemRef = generateS390MemoryReference(byteArrayReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg);1340713408TR::LabelSymbol *cFlowRegionStart = generateLabelSymbol(cg);13409cFlowRegionStart->setStartInternalControlFlow();13410TR::LabelSymbol *cFlowRegionEnd = generateLabelSymbol(cg);13411cFlowRegionEnd->setEndInternalControlFlow();1341213413generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);1341413415// If input is 0, then do the work in GPRs and exit.13416// TODO: Measure performance of [1,9] here vs vanilla Java code to see what's faster. If vanilla java, then we should bail from here accordingly.13417// (See https://github.ibm.com/runtimes/openj9/pull/385#discussion_r5004355 for discussion)13418TR::Register *numCharsRemainingReg = cg->allocateRegister(); // this is also the index of the position of the first char after we have populated the buffer13419TR::LabelSymbol *nonZeroInputLabel = generateLabelSymbol(cg);13420generateS390CompareAndBranchInstruction(cg, inputIs64Bit ? TR::InstOpCode::CG : TR::InstOpCode::C, node, inputValueReg, 0, TR::InstOpCode::COND_BNE, nonZeroInputLabel, false);13421generateSIInstruction(cg, TR::InstOpCode::MVI, node, generateS390MemoryReference(*destinationArrayMemRef, 0, cg), 48);13422generateRILInstruction(cg, TR::InstOpCode::IILF, node, numCharsRemainingReg, 0);13423generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);1342413425generateS390LabelInstruction(cg, TR::InstOpCode::label, node, nonZeroInputLabel);1342613427TR::LabelSymbol *handleDigitsLabel = generateLabelSymbol(cg);13428// First handle negative sign if needed. Then proceed to handleDigitsLabel to process the digits.13429generateS390CompareAndBranchInstruction(cg, inputIs64Bit ? TR::InstOpCode::CG : TR::InstOpCode::C, node, inputValueReg, 0, TR::InstOpCode::COND_BNL, handleDigitsLabel, false);13430generateRILInstruction(cg, TR::InstOpCode::SLFI, node, stringSizeReg, 1);13431generateSIInstruction(cg, TR::InstOpCode::MVI, node, generateS390MemoryReference(*destinationArrayMemRef, 0, cg), 45);13432generateRILInstruction(cg, TR::InstOpCode::getAddImmOpCode(), node, byteArrayReg, 1);1343313434generateS390LabelInstruction(cg, TR::InstOpCode::label, node, handleDigitsLabel);13435TR::Register *intToPDReg = cg->allocateRegister(TR_VRF);13436// Load all digits into packed decimal format.13437generateVRIiInstruction(cg, inputIs64Bit ? TR::InstOpCode::VCVDG : TR::InstOpCode::VCVD, node, intToPDReg, inputValueReg, inputIs64Bit ? 19 : 10, 0x1);13438TR::Register *maskReg = cg->allocateRegister(TR_VRF);13439TR::Register *zonedDecimalReg1 = cg->allocateRegister(TR_VRF);13440TR::Register *zonedDecimalReg2 = NULL;1344113442TR::RegisterDependencyConditions *dependencies = NULL;1344313444if (inputIs64Bit)13445{13446// if the long input value is greater than 16 digits in length, then we need two vector registers to do the conversion. so jump to lengthgreaterthan16label13447// to handle that case.13448TR::LabelSymbol *lengthGreaterThan16Label = generateLabelSymbol(cg);13449generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, stringSizeReg, 16, TR::InstOpCode::COND_BH, lengthGreaterThan16Label, false);13450// this instruction unpacks the packed decimal in inttppdreg to zoned decimal format. it will do this for the rightmost 16 digits.13451// it populates the higher 4 bits of each byte with the "zone" bits and the bottom 4 bits with each digit from the packed decimal sequence.13452generateVRRkInstruction(cg, TR::InstOpCode::VUPKZL, node, zonedDecimalReg1, intToPDReg, 0 /*m3*/);13453// now we zero out the zone bits because we don't need them.13454generateVRIbInstruction(cg, TR::InstOpCode::VGM, node, maskReg, 4, 7, 0);13455generateVRRcInstruction(cg, TR::InstOpCode::VN, node, zonedDecimalReg1, zonedDecimalReg1, maskReg, 0, 0, 0);13456// now the rightmost 10 bytes should hold the entire integer in packed decimal format. so let's add 48 to each byte to convert each digit to ascii.13457generateVRIaInstruction(cg, TR::InstOpCode::VREPI, node, maskReg, 48, 0);13458generateVRRcInstruction(cg, TR::InstOpCode::VA, node, zonedDecimalReg1, zonedDecimalReg1, maskReg, 0);13459// for the purposes of this evaluator, stringsizereg contains the length of the resulting string. ex if input is 2147483647, stringsizereg will be 10.13460// when storing using vstrl, the index register specifying the first byte to store is 0 based. meanwhile13461// stringsizereg is 1 based. so we must first subtract 1 from stringsizereg so the calculation is done correctly by the instruction.13462// ex. if we specify 10 in vstrl, the instruction will do 15-10=5 to figure out that it needs to store bytes 5 to 15 instead of 6 to 15.13463generateRILInstruction(cg, TR::InstOpCode::SLFI, node, stringSizeReg, 1);13464// the memory reference should already be pointing to where the most significant digit is to be stored. so we just have to create the vstrl instruction now.13465generateVRSdInstruction(cg, TR::InstOpCode::VSTRLR, node, stringSizeReg, zonedDecimalReg1, generateS390MemoryReference(*destinationArrayMemRef, 0, cg));13466generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);1346713468// if we end up here, then there are more than 16 digits in the input value. this instruction sequence is similar to the one above, except that13469// we handle the 1 to 3 of the most significant digits in a separate register. we then store the value in this register before storing the remainder of the digits.13470generateS390LabelInstruction(cg, TR::InstOpCode::label, node, lengthGreaterThan16Label);13471zonedDecimalReg2 = cg->allocateRegister(TR_VRF); // holds the most significant digits. can be anywhere from 1-3 digits.13472generateVRRkInstruction(cg, TR::InstOpCode::VUPKZL, node, zonedDecimalReg1, intToPDReg, 0 /*m3*/);13473generateVRRkInstruction(cg, TR::InstOpCode::VUPKZH, node, zonedDecimalReg2, intToPDReg, 0 /*m3*/);13474// now we zero out the zone bits because we don't need them.13475generateVRIbInstruction(cg, TR::InstOpCode::VGM, node, maskReg, 4, 7, 0);13476generateVRRcInstruction(cg, TR::InstOpCode::VN, node, zonedDecimalReg1, zonedDecimalReg1, maskReg, 0, 0, 0);13477generateVRRcInstruction(cg, TR::InstOpCode::VN, node, zonedDecimalReg2, zonedDecimalReg2, maskReg, 0, 0, 0);13478// now add 48 to each byte.13479generateVRIaInstruction(cg, TR::InstOpCode::VREPI, node, maskReg, 48, 0);13480generateVRRcInstruction(cg, TR::InstOpCode::VA, node, zonedDecimalReg1, zonedDecimalReg1, maskReg, 0);13481generateVRRcInstruction(cg, TR::InstOpCode::VA, node, zonedDecimalReg2, zonedDecimalReg2, maskReg, 0);13482// now calculate how many digits are in the top half of the zoned decimal (i.e. zoneddecimalreg2) --> (stringsizereg - 16) - 1 = stringsizereg - 1713483generateRILInstruction(cg, TR::InstOpCode::SLFI, node, stringSizeReg, 17);13484// the memory reference should already be pointing to where the most significant digit is to be stored. so we just have to create the vstrl instruction now.13485generateVRSdInstruction(cg, TR::InstOpCode::VSTRLR, node, stringSizeReg, zonedDecimalReg2, generateS390MemoryReference(*destinationArrayMemRef, 0, cg));13486// increment bytearrayreg by stringsizereg+1 to move buffer pointer forward so we can write remaining bytes.13487generateRILInstruction(cg, TR::InstOpCode::AFI, node, stringSizeReg, 1);13488generateRRInstruction(cg, TR::InstOpCode::getAddRegWidenOpCode(), node, byteArrayReg, stringSizeReg);13489generateVSIInstruction(cg, TR::InstOpCode::VSTRL, node, zonedDecimalReg1, generateS390MemoryReference(*destinationArrayMemRef, 0, cg), 15);1349013491dependencies = generateRegisterDependencyConditions(0, 8, cg);13492dependencies->addPostCondition(zonedDecimalReg2, TR::RealRegister::AssignAny);13493}13494else13495{13496// This instruction unpacks the packed decimal in intTpPDReg to zoned decimal format. It will do this for the rightmost 16 digits.13497// It populates the higher 4 bits of each byte with the "zone" bits and the bottom 4 bits with each digit from the packed decimal sequence.13498generateVRRkInstruction(cg, TR::InstOpCode::VUPKZL, node, zonedDecimalReg1, intToPDReg, 0 /*M3*/);13499// Now we zero out the zone bits because we don't need them.13500generateVRIbInstruction(cg, TR::InstOpCode::VGM, node, maskReg, 4, 7, 0);13501generateVRRcInstruction(cg, TR::InstOpCode::VN, node, zonedDecimalReg1, zonedDecimalReg1, maskReg, 0, 0, 0);13502// Now the rightmost 10 bytes should hold the entire integer value in packed decimal form. So let's add 48 to each byte to convert each digit to ASCII.13503generateVRIaInstruction(cg, TR::InstOpCode::VREPI, node, maskReg, 48, 0);13504generateVRRcInstruction(cg, TR::InstOpCode::VA, node, zonedDecimalReg1, zonedDecimalReg1, maskReg, 0);1350513506// For the purposes of this evaluator, stringSizeReg contains the length of the resulting string. Ex if input is 2147483647, stringSizeReg will be 10.13507// When storing using VSTRL, the index register specifying the first byte to store is 0 based. Meanwhile13508// stringSizeReg is 1 based. So we must first subtract 1 from stringSizeReg so the calculation is done correctly by the instruction.13509// ex. if we specify 10 in VSTRL, the instruction will do 15-10=5 to figure out that it needs to store bytes 5 to 15 instead of 6 to 15.13510generateRILInstruction(cg, TR::InstOpCode::SLFI, node, stringSizeReg, 1);13511// The memory reference should already be pointing to where the most significant digit is to be stored. So we just have to create the VSTRL instruction now.13512generateVRSdInstruction(cg, TR::InstOpCode::VSTRLR, node, stringSizeReg, zonedDecimalReg1, generateS390MemoryReference(*destinationArrayMemRef, 0, cg));1351313514dependencies = generateRegisterDependencyConditions(0, 7, cg);13515}1351613517dependencies->addPostCondition(inputValueReg, TR::RealRegister::AssignAny);13518dependencies->addPostCondition(byteArrayReg, TR::RealRegister::AssignAny);13519dependencies->addPostCondition(stringSizeReg, TR::RealRegister::AssignAny);13520dependencies->addPostCondition(numCharsRemainingReg, TR::RealRegister::AssignAny);13521dependencies->addPostCondition(intToPDReg, TR::RealRegister::AssignAny);13522dependencies->addPostCondition(maskReg, TR::RealRegister::AssignAny);13523dependencies->addPostCondition(zonedDecimalReg1, TR::RealRegister::AssignAny);1352413525// For the purposes of inlining Integer.toString and Long.toString, the return value of the getChars API will always be 0. So we load it here manually.13526generateRILInstruction(cg, TR::InstOpCode::IILF, node, numCharsRemainingReg, 0);1352713528generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, dependencies);1352913530cg->decReferenceCount(inputValueNode);13531cg->decReferenceCount(stringSizeNode);13532cg->decReferenceCount(byteArrayNode);1353313534cg->stopUsingRegister(intToPDReg);13535cg->stopUsingRegister(maskReg);13536cg->stopUsingRegister(zonedDecimalReg1);1353713538cg->stopUsingRegister(byteArrayReg);13539cg->stopUsingRegister(stringSizeReg);13540cg->stopUsingRegister(zonedDecimalReg2);1354113542return node->setRegister(numCharsRemainingReg);13543}1354413545TR::Register*13546J9::Z::TreeEvaluator::inlineIntegerToCharsForUTF16Strings(TR::Node *node, TR::CodeGenerator *cg)13547{13548TR::Compilation *comp = cg->comp();1354913550TR_ResolvedMethod *candidateToStringMethod = NULL;13551if (node->getInlinedSiteIndex() != -1)13552{13553candidateToStringMethod = comp->getInlinedResolvedMethod(node->getInlinedSiteIndex());13554}13555else13556{13557candidateToStringMethod = comp->getCurrentMethod();13558}13559// If method caller of Integer.stringSize or Long.stringSize is not Integer.toString(I) or Long.toString(J), then we don't inline13560if (candidateToStringMethod->getRecognizedMethod() != TR::java_lang_Long_toString &&13561candidateToStringMethod->getRecognizedMethod() != TR::java_lang_Integer_toString)13562{13563return NULL;13564}1356513566if (comp->getOption(TR_TraceCG))13567{13568traceMsg(comp, "inlineIntegerToCharsForUTF16Strings (decompressed strings)\n");13569}13570TR::Node *inputValueNode = node->getChild(0);13571TR::Node *stringSizeNode = node->getChild(1);13572TR::Node *byteArrayNode = node->getChild(2);1357313574TR::Register *inputValueReg = cg->evaluate(inputValueNode);13575TR::Register *stringSizeReg = cg->gprClobberEvaluate(stringSizeNode, true);13576TR::Register *byteArrayReg = cg->gprClobberEvaluate(byteArrayNode, true);1357713578bool inputIs64Bit = inputValueNode->getDataType() == TR::Int64;1357913580TR::LabelSymbol *cFlowRegionStart = generateLabelSymbol(cg);13581cFlowRegionStart->setStartInternalControlFlow();13582TR::LabelSymbol *cFlowRegionEnd = generateLabelSymbol(cg);13583cFlowRegionEnd->setEndInternalControlFlow();1358413585generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);1358613587// If input is 0, just do the work in GPRs and exit.13588TR::Register *numCharsRemainingReg = cg->allocateRegister(); // this is also the index of the position of the first char after we have populated the buffer13589TR::LabelSymbol *nonZeroInputLabel = generateLabelSymbol(cg);13590generateS390CompareAndBranchInstruction(cg, inputIs64Bit ? TR::InstOpCode::CG : TR::InstOpCode::C, node, inputValueReg, 0, TR::InstOpCode::COND_BNE, nonZeroInputLabel, false);13591TR::MemoryReference *destinationArrayMemRef = generateS390MemoryReference(byteArrayReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg);13592generateSILInstruction(cg, TR::InstOpCode::MVHHI, node, destinationArrayMemRef, 48);13593generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);1359413595generateS390LabelInstruction(cg, TR::InstOpCode::label, node, nonZeroInputLabel);1359613597TR::LabelSymbol *handleDigitsLabel = generateLabelSymbol(cg);13598// Handle negative sign first.13599generateS390CompareAndBranchInstruction(cg, inputIs64Bit ? TR::InstOpCode::CG : TR::InstOpCode::C, node, inputValueReg, 0, TR::InstOpCode::COND_BNL, handleDigitsLabel, false);13600generateRILInstruction(cg, TR::InstOpCode::SLFI, node, stringSizeReg, 1);13601generateSILInstruction(cg, TR::InstOpCode::MVHHI, node, generateS390MemoryReference(*destinationArrayMemRef, 0, cg), 45);13602generateRILInstruction(cg, TR::InstOpCode::getAddImmOpCode(), node, byteArrayReg, 2);1360313604generateS390LabelInstruction(cg, TR::InstOpCode::label, node, handleDigitsLabel);1360513606TR::Register *intToPDReg = cg->allocateRegister(TR_VRF);13607// Load all digits into packed decimal format.13608generateVRIiInstruction(cg, inputIs64Bit ? TR::InstOpCode::VCVDG : TR::InstOpCode::VCVD, node, intToPDReg, inputValueReg, inputIs64Bit ? 19 : 10, 0x1);13609TR::Register *maskReg = cg->allocateRegister(TR_VRF);13610TR::Register *asciiOffset = cg->allocateRegister(TR_VRF);13611generateVRIbInstruction(cg, TR::InstOpCode::VGM, node, maskReg, 4, 7, 0);13612generateVRIaInstruction(cg, TR::InstOpCode::VREPI, node, asciiOffset, 48, 0);13613TR::Register *zonedDecimalRegLower = cg->allocateRegister(TR_VRF);1361413615TR::LabelSymbol *moreThan9DigitsLabel = generateLabelSymbol(cg);13616// Depending on the length of the resulting string, we will need different amounts of vector registers to do the conversion. We test for that13617// here and then branch to a handcrafted routine for each scenario. This creates some redundancy in the code generated (hence increasing footprint),13618// however it reduces checks/branches during runtime preventing bottlenecks.13619generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, stringSizeReg, 8, TR::InstOpCode::COND_BH, moreThan9DigitsLabel, false);1362013621// In this scenario we only need one vector register to do the conversion as there are less than 9 digits to process13622// If we are here, then 0 =< stringSizeReg <= 813623// Unpack packed decimal into zoned decimal. This should take a maximum of 8 bytes.13624generateVRRkInstruction(cg, TR::InstOpCode::VUPKZL, node, zonedDecimalRegLower, intToPDReg, 0 /*M3*/);13625// Remove the zone bits13626generateVRRcInstruction(cg, TR::InstOpCode::VN, node, zonedDecimalRegLower, zonedDecimalRegLower, maskReg, 0, 0, 0);13627// Now the rightmost 10 bytes should hold the entire integer we care about. So let's add 48 to each byte.13628generateVRRcInstruction(cg, TR::InstOpCode::VA, node, zonedDecimalRegLower, zonedDecimalRegLower, asciiOffset, 0);1362913630// For the purposes of this evaluator, stringSizeReg contains the length of the resulting string. Ex if input is 2147483647, stringSizeReg will be 10.13631// When storing using VSTRL, the index register specifying the first byte to store is 0 based. Meanwhile13632// stringSizeReg is 1 based. So we must first subtract 1 from stringSizeReg so the calculation is done correctly by the instruction.13633// ex. if we specify 10 in VSTRL, the instruction will do 15-10=5 to figure out that it needs to store bytes 5 to 15 instead of 6 to 15.13634// Since each character is 2 bytes in length, we must first multiply by 2.13635generateRSInstruction(cg, TR::InstOpCode::SLA, node, stringSizeReg, 1);13636generateRILInstruction(cg, TR::InstOpCode::SLFI, node, stringSizeReg, 1);13637// Finally, unpack the data in zonedDecimalReg1 using VUPL. The result should take no more than 16 bytes.13638generateVRRaInstruction(cg, TR::InstOpCode::VUPLL, node, zonedDecimalRegLower, zonedDecimalRegLower, 0, 0, 0);13639// The memory reference should already be pointing to where the most significant digit is to be stored. So we just have to create the VSTRL instruction now.13640generateVRSdInstruction(cg, TR::InstOpCode::VSTRLR, node, stringSizeReg, zonedDecimalRegLower, generateS390MemoryReference(*destinationArrayMemRef, 0, cg));13641generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);1364213643generateS390LabelInstruction(cg, TR::InstOpCode::label, node, moreThan9DigitsLabel);13644TR::LabelSymbol *moreThan16DigitsLabel = generateLabelSymbol(cg);13645generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::C, node, stringSizeReg, 16, TR::InstOpCode::COND_BH, moreThan16DigitsLabel, false);13646// Need two intermediate vector registers to process input values that are greater than 8 digits and less than 17.13647// For Integers between the length of 8 and 16, we must do as above but also use VUPLH to load the higher order digits. Note that the result13648// of converting packed decimal to zoned decimal will fit in 16 bytes, so we only need to use VUPKZL still.13649generateVRRkInstruction(cg, TR::InstOpCode::VUPKZL, node, zonedDecimalRegLower, intToPDReg, 0 /*M3*/);13650// Remove the zone bits13651generateVRRcInstruction(cg, TR::InstOpCode::VN, node, zonedDecimalRegLower, zonedDecimalRegLower, maskReg, 0, 0, 0);13652// Now the rightmost 16 bytes should hold the entire intege we care about. So let's add 48 to each byte.13653generateVRRcInstruction(cg, TR::InstOpCode::VA, node, zonedDecimalRegLower, zonedDecimalRegLower, asciiOffset, 0);13654// We know zonedDecimalRegLower will be full when we unpack. So we store all bytes in it. But we don't know if13655// zonedDecimalRegLowerUpperHalf will be full. So we must calculate "stringSize-8" to figure out how many extra digits remain.13656// ex if stringSize = 10, then 10-8 = 2 digits in upper half. 15 - 2*2-1 = 12 --> 12,13,14,15 are the bytes stored to memory.13657generateRILInstruction(cg, TR::InstOpCode::SLFI, node, stringSizeReg, 8);13658generateRSInstruction(cg, TR::InstOpCode::SLA, node, stringSizeReg, 1);13659generateRILInstruction(cg, TR::InstOpCode::SLFI, node, stringSizeReg, 1);13660// now stringSize will have position of byte in upper half.13661// Finally, unpack the higher 8 bytes in zonedDecimalReg1 using VUPLH.13662TR::Register *zonedDecimalRegLowerUpperHalf = cg->allocateRegister(TR_VRF);13663generateVRRaInstruction(cg, TR::InstOpCode::VUPLH, node, zonedDecimalRegLowerUpperHalf, zonedDecimalRegLower, 0, 0, 0);13664// And unpack the lower 8 bytes using VUPLL13665generateVRRaInstruction(cg, TR::InstOpCode::VUPLL, node, zonedDecimalRegLower, zonedDecimalRegLower, 0, 0, 0);13666// Store the higher half first as it holds the most significant digits.13667generateVRSdInstruction(cg, TR::InstOpCode::VSTRLR, node, stringSizeReg, zonedDecimalRegLowerUpperHalf, generateS390MemoryReference(*destinationArrayMemRef, 0, cg));1366813669// Advance the memoryReference pointer then store the bottom half13670generateRILInstruction(cg, TR::InstOpCode::AFI, node, stringSizeReg, 1);13671generateRRInstruction(cg, TR::InstOpCode::getAddRegWidenOpCode(), node, byteArrayReg, stringSizeReg);13672generateVSIInstruction(cg, TR::InstOpCode::VSTRL, node, zonedDecimalRegLower, generateS390MemoryReference(*destinationArrayMemRef, 0, cg), 15);13673generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);1367413675generateS390LabelInstruction(cg, TR::InstOpCode::label, node, moreThan16DigitsLabel);13676// In this scenario we have between 17 and 19 digits. The logic is similar to before, except we use VUPKZH to unpack the most significant digits (could be anywhere from 1 to 3 digits).13677// We first unpack into lower and upper zoned decimal halves.13678generateVRRkInstruction(cg, TR::InstOpCode::VUPKZL, node, zonedDecimalRegLower, intToPDReg, 0 /*M3*/);13679TR::Register *zonedDecimalRegHigher = cg->allocateRegister(TR_VRF);13680generateVRRkInstruction(cg, TR::InstOpCode::VUPKZH, node, zonedDecimalRegHigher, intToPDReg, 0 /*M3*/);13681// Now remove the zone bits in both13682generateVRRcInstruction(cg, TR::InstOpCode::VN, node, zonedDecimalRegLower, zonedDecimalRegLower, maskReg, 0, 0, 0);13683generateVRRcInstruction(cg, TR::InstOpCode::VN, node, zonedDecimalRegHigher, zonedDecimalRegHigher, maskReg, 0, 0, 0);13684// And add 0x30 to all13685generateVRRcInstruction(cg, TR::InstOpCode::VA, node, zonedDecimalRegLower, zonedDecimalRegLower, asciiOffset, 0);13686generateVRRcInstruction(cg, TR::InstOpCode::VA, node, zonedDecimalRegHigher, zonedDecimalRegHigher, asciiOffset, 0);13687// Now unpack the higher half --> i.e. process the most significant digits (anywhere from 1 to 3 digits)13688generateVRRaInstruction(cg, TR::InstOpCode::VUPLL, node, zonedDecimalRegHigher, zonedDecimalRegHigher, 0, 0, 0);13689// Calculate how many digits we need to store in this higher half.13690generateRILInstruction(cg, TR::InstOpCode::SLFI, node, stringSizeReg, 16);13691generateRSInstruction(cg, TR::InstOpCode::SLA, node, stringSizeReg, 1);13692generateRILInstruction(cg, TR::InstOpCode::SLFI, node, stringSizeReg, 1);13693// Store that many bytes from this register13694generateVRSdInstruction(cg, TR::InstOpCode::VSTRLR, node, stringSizeReg, zonedDecimalRegHigher, generateS390MemoryReference(*destinationArrayMemRef, 0, cg));13695// Advance buffer pointer13696generateRILInstruction(cg, TR::InstOpCode::AFI, node, stringSizeReg, 1);13697generateRRInstruction(cg, TR::InstOpCode::getAddRegWidenOpCode(), node, byteArrayReg, stringSizeReg);13698// unpack zonedDecimalRegLower into upper and lower halves --> i.e. we now process the least significant 16 digits.13699generateVRRaInstruction(cg, TR::InstOpCode::VUPLH, node, zonedDecimalRegLowerUpperHalf, zonedDecimalRegLower, 0, 0, 0);13700generateVRRaInstruction(cg, TR::InstOpCode::VUPLL, node, zonedDecimalRegLower, zonedDecimalRegLower, 0, 0, 0);13701generateVSIInstruction(cg, TR::InstOpCode::VSTRL, node, zonedDecimalRegLowerUpperHalf, generateS390MemoryReference(*destinationArrayMemRef, 0, cg), 15);13702// Advance Pointer then store again.13703generateRILInstruction(cg, TR::InstOpCode::getAddImmOpCode(), node, byteArrayReg, 16);13704generateVSIInstruction(cg, TR::InstOpCode::VSTRL, node, zonedDecimalRegLower, generateS390MemoryReference(*destinationArrayMemRef, 0, cg), 15);1370513706TR::RegisterDependencyConditions *dependencies = generateRegisterDependencyConditions(0, 10, cg);13707dependencies->addPostCondition(inputValueReg, TR::RealRegister::AssignAny);13708dependencies->addPostCondition(byteArrayReg, TR::RealRegister::AssignAny);13709dependencies->addPostCondition(stringSizeReg, TR::RealRegister::AssignAny);13710dependencies->addPostCondition(numCharsRemainingReg, TR::RealRegister::AssignAny);13711dependencies->addPostCondition(intToPDReg, TR::RealRegister::AssignAny);13712dependencies->addPostCondition(maskReg, TR::RealRegister::AssignAny);13713dependencies->addPostCondition(asciiOffset, TR::RealRegister::AssignAny);13714dependencies->addPostCondition(zonedDecimalRegLower, TR::RealRegister::AssignAny);13715dependencies->addPostCondition(zonedDecimalRegLowerUpperHalf, TR::RealRegister::AssignAny);13716dependencies->addPostCondition(zonedDecimalRegHigher, TR::RealRegister::AssignAny);1371713718generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, dependencies);1371913720// For the purposes of inlining Integer.toString and Long.toString, the return value of the getChars API will always be 0. So we load it here manually.13721generateRILInstruction(cg, TR::InstOpCode::IILF, node, numCharsRemainingReg, 0);1372213723cg->decReferenceCount(inputValueNode);13724cg->decReferenceCount(stringSizeNode);13725cg->decReferenceCount(byteArrayNode);1372613727cg->stopUsingRegister(intToPDReg);13728cg->stopUsingRegister(maskReg);13729cg->stopUsingRegister(asciiOffset);13730cg->stopUsingRegister(zonedDecimalRegLower);1373113732cg->stopUsingRegister(byteArrayReg);13733cg->stopUsingRegister(stringSizeReg);1373413735cg->stopUsingRegister(zonedDecimalRegLowerUpperHalf);13736cg->stopUsingRegister(zonedDecimalRegHigher);1373713738return node->setRegister(numCharsRemainingReg);13739}1374013741/*13742* This method inlines calls to Integer.stringSize and Long.stringSize using the VCLZDP instruction on zNext13743*/13744TR::Register*13745J9::Z::TreeEvaluator::inlineIntegerStringSize(TR::Node* node, TR::CodeGenerator* cg)13746{13747TR::Compilation *comp = cg->comp();13748static const bool disableIntegerStringSizeBranch = feGetEnv("TR_disableStringSizeBranch") != NULL;13749TR::Node *inputValueNode = node->getChild(0);13750bool inputIs64Bit = inputValueNode->getDataType() == TR::Int64;13751TR::Register *inputValueReg = cg->evaluate(inputValueNode);1375213753TR::LabelSymbol *cFlowRegionStart = generateLabelSymbol(cg);13754cFlowRegionStart->setStartInternalControlFlow();13755TR::LabelSymbol *cFlowRegionEnd = generateLabelSymbol(cg);13756cFlowRegionEnd->setEndInternalControlFlow();13757TR::LabelSymbol *inputValueZeroLabel = generateLabelSymbol(cg);13758TR::LabelSymbol *countNumDigitsLabel = generateLabelSymbol(cg);1375913760generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);13761TR::Register *lengthReg = cg->allocateRegister();13762// If value is 0, we branch to end as string is "0"13763generateRIInstruction(cg, TR::InstOpCode::LHI, node, lengthReg, 1);13764generateS390CompareAndBranchInstruction(cg, inputIs64Bit ? TR::InstOpCode::CG : TR::InstOpCode::C, node, inputValueReg, 0, TR::InstOpCode::COND_BE, cFlowRegionEnd, false);1376513766generateS390LabelInstruction(cg, TR::InstOpCode::label, node, countNumDigitsLabel);13767TR::Register *intToPDReg = cg->allocateRegister(TR_VRF);13768TR::Register *maxNumDigitsReg = cg->allocateRegister(TR_VRF);13769TR::Register *lengthVectorReg = cg->allocateRegister(TR_VRF);13770TR::Register *signBitConstant = disableIntegerStringSizeBranch ? cg->allocateRegister(TR_VRF) : NULL;13771if (disableIntegerStringSizeBranch)13772{13773generateVRIaInstruction(cg, TR::InstOpCode::VLEIB, node, signBitConstant, 1, 15);13774}13775generateVRIaInstruction(cg, TR::InstOpCode::VLEIB, node, maxNumDigitsReg, 31, 7);13776generateVRIiInstruction(cg, inputIs64Bit ? TR::InstOpCode::VCVDG : TR::InstOpCode::VCVD, node, intToPDReg, inputValueReg, inputIs64Bit ? 19 : 10, 0x1);13777TR::Register *leadingZerosReg = cg->allocateRegister(TR_VRF);13778generateVRRkInstruction(cg, TR::InstOpCode::VCLZDP, node, leadingZerosReg, intToPDReg, 0 /*M3*/);13779// Now subtract to get length of string13780generateVRRcInstruction(cg, TR::InstOpCode::VS, node, lengthVectorReg, maxNumDigitsReg, leadingZerosReg, 0);1378113782if (disableIntegerStringSizeBranch)13783{13784generateVRRcInstruction(cg, TR::InstOpCode::VN, node, intToPDReg, intToPDReg, signBitConstant, 0, 0, 0);13785generateVRRcInstruction(cg, TR::InstOpCode::VA, node, lengthVectorReg, lengthVectorReg, intToPDReg, 0);13786}13787else13788{13789generateVRScInstruction(cg, TR::InstOpCode::VLGV, node, lengthReg, lengthVectorReg, generateS390MemoryReference(7, cg), 0);13790// If value is greater than 0, we branch to end. Otherwise we add 1 to lengthReg to account for '-' sign.13791generateS390CompareAndBranchInstruction(cg, inputIs64Bit ? TR::InstOpCode::CG : TR::InstOpCode::C, node, inputValueReg, 0, TR::InstOpCode::COND_BNL, cFlowRegionEnd, false);13792generateRILInstruction(cg, TR::InstOpCode::AFI, node, lengthReg, 1);13793}1379413795TR::RegisterDependencyConditions *dependencies = generateRegisterDependencyConditions(0, disableIntegerStringSizeBranch ? 7 : 6, cg);13796dependencies->addPostCondition(inputValueReg, TR::RealRegister::AssignAny);13797dependencies->addPostCondition(intToPDReg, TR::RealRegister::AssignAny);13798dependencies->addPostCondition(leadingZerosReg, TR::RealRegister::AssignAny);13799dependencies->addPostCondition(lengthReg, TR::RealRegister::AssignAny);13800dependencies->addPostCondition(maxNumDigitsReg, TR::RealRegister::AssignAny);13801dependencies->addPostCondition(lengthVectorReg, TR::RealRegister::AssignAny);13802if (disableIntegerStringSizeBranch)13803{13804dependencies->addPostCondition(signBitConstant, TR::RealRegister::AssignAny);13805}1380613807generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, dependencies);1380813809cg->decReferenceCount(inputValueNode);13810cg->stopUsingRegister(intToPDReg);13811cg->stopUsingRegister(leadingZerosReg);13812cg->stopUsingRegister(maxNumDigitsReg);13813cg->stopUsingRegister(lengthVectorReg);13814if (disableIntegerStringSizeBranch)13815{13816cg->stopUsingRegister(signBitConstant);13817}1381813819return node->setRegister(lengthReg);13820}138211382213823