Path: blob/master/runtime/compiler/p/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#include <limits.h>23#include <math.h>24#include <stdint.h>25#include "j9.h"26#include "j9cfg.h"27#include "j9consts.h"28#include "omrmodroncore.h"29#include "thrdsup.h"30#include "thrtypes.h"31#include "codegen/AheadOfTimeCompile.hpp"32#include "codegen/BackingStore.hpp"33#include "codegen/CodeGenerator.hpp"34#include "codegen/CodeGeneratorUtils.hpp"35#include "codegen/CodeGenerator_inlines.hpp"36#include "codegen/Machine.hpp"37#include "codegen/Linkage.hpp"38#include "codegen/Linkage_inlines.hpp"39#include "codegen/LiveRegister.hpp"40#include "codegen/PPCJNILinkage.hpp"41#include "codegen/PPCPrivateLinkage.hpp"42#include "codegen/Relocation.hpp"43#include "codegen/Snippet.hpp"44#include "codegen/TreeEvaluator.hpp"45#include "compile/ResolvedMethod.hpp"46#include "control/Recompilation.hpp"47#include "control/RecompilationInfo.hpp"48#include "codegen/J9PPCWatchedInstanceFieldSnippet.hpp"49#include "codegen/J9PPCWatchedStaticFieldSnippet.hpp"50#include "env/CHTable.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/TreeTop.hpp"60#include "il/TreeTop_inlines.hpp"61#include "infra/Annotations.hpp"62#include "infra/Bit.hpp"63#include "optimizer/VectorAPIExpansion.hpp"64#include "p/codegen/ForceRecompilationSnippet.hpp"65#include "p/codegen/GenerateInstructions.hpp"66#include "p/codegen/InterfaceCastSnippet.hpp"67#include "p/codegen/J9PPCSnippet.hpp"68#include "p/codegen/LoadStoreHandler.hpp"69//#include "p/codegen/PPCAheadOfTimeCompile.hpp"70#include "p/codegen/PPCEvaluator.hpp"71#include "p/codegen/PPCInstruction.hpp"72#include "p/codegen/PPCTableOfConstants.hpp"73#include "runtime/CodeCache.hpp"74#include "runtime/Runtime.hpp"75#include "env/VMJ9.h"7677#define MAX_PPC_ARRAYCOPY_INLINE 25678#define AIX_NULL_ZERO_AREA_SIZE 25679#define NUM_PICS 38081#define LOCK_INC_DEC_VALUE OBJECT_HEADER_LOCK_FIRST_RECURSION_BIT82#define LOCK_RESERVATION_BIT OBJECT_HEADER_LOCK_RESERVED8384#define LOCK_RES_PRIMITIVE_ENTER_MASK (OBJECT_HEADER_LOCK_RECURSION_MASK | OBJECT_HEADER_LOCK_FLC)85#define LOCK_RES_PRIMITIVE_EXIT_MASK (OBJECT_HEADER_LOCK_BITS_MASK & ~OBJECT_HEADER_LOCK_RECURSION_MASK)86#define LOCK_RES_NON_PRIMITIVE_ENTER_MASK (OBJECT_HEADER_LOCK_RECURSION_MASK & ~OBJECT_HEADER_LOCK_LAST_RECURSION_BIT)87#define LOCK_RES_NON_PRIMITIVE_EXIT_MASK (OBJECT_HEADER_LOCK_RECURSION_MASK & ~OBJECT_HEADER_LOCK_FIRST_RECURSION_BIT)8889#define LOCK_RES_OWNING_COMPLEMENT (OBJECT_HEADER_LOCK_RECURSION_MASK | OBJECT_HEADER_LOCK_FLC)9091#define LOCK_NON_PRIMITIVE_ENTER_IGNORE_MASK ((OBJECT_HEADER_LOCK_RECURSION_MASK & ~OBJECT_HEADER_LOCK_LAST_RECURSION_BIT) | OBJECT_HEADER_LOCK_RESERVED | OBJECT_HEADER_LOCK_FLC)92#define LOCK_NON_PRIMITIVE_EXIT_IGNORE_MASK (OBJECT_HEADER_LOCK_RECURSION_MASK | OBJECT_HEADER_LOCK_RESERVED | OBJECT_HEADER_LOCK_FLC)9394extern TR::Register *addConstantToLong(TR::Node * node, TR::Register *srcReg, int64_t value, TR::Register *trgReg, TR::CodeGenerator *cg);95extern TR::Register *addConstantToInteger(TR::Node * node, TR::Register *trgReg, TR::Register *srcReg, int32_t value, TR::CodeGenerator *cg);9697static TR::InstOpCode::Mnemonic getLoadOrStoreFromDataType(TR::CodeGenerator *cg, TR::DataType dt, int32_t elementSize, bool isUnsigned, bool returnLoad);98void loadFieldWatchSnippet(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, TR::Register *snippetReg, TR::Register *scratchReg, bool isInstance);99static const char *ppcSupportsReadMonitors = feGetEnv("TR_ppcSupportReadMonitors");100101extern uint32_t getPPCCacheLineSize();102103static TR::RegisterDependencyConditions *createConditionsAndPopulateVSXDeps(TR::CodeGenerator *cg, int32_t nonVSXDepsCount)104{105TR::RegisterDependencyConditions *conditions;106TR_LiveRegisters *lrVector = cg->getLiveRegisters(TR_VSX_VECTOR);107bool liveVSXVectorReg = (!lrVector || (lrVector->getNumberOfLiveRegisters() > 0));108const TR::PPCLinkageProperties& properties = cg->getLinkage()->getProperties();109if (liveVSXVectorReg)110{111int32_t depsCount = 64 + nonVSXDepsCount;112conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(depsCount, depsCount, cg->trMemory());113for (int32_t i = TR::RealRegister::FirstFPR; i <= TR::RealRegister::LastFPR; i++)114{115if (!properties.getPreserved((TR::RealRegister::RegNum) i))116{117TR::addDependency(conditions, NULL, (TR::RealRegister::RegNum) i, TR_FPR, cg);118}119}120for (int32_t i = TR::RealRegister::FirstVRF; i <= TR::RealRegister::LastVRF; i++)121{122if (!properties.getPreserved((TR::RealRegister::RegNum) i))123{124TR::addDependency(conditions, NULL, (TR::RealRegister::RegNum) i, TR_VRF, cg);125}126}127}128else129{130TR_LiveRegisters *lrScalar = cg->getLiveRegisters(TR_VSX_SCALAR);131if (!lrScalar || (lrScalar->getNumberOfLiveRegisters() > 0))132{133int32_t depsCount = 32 + nonVSXDepsCount;134conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(depsCount, depsCount, cg->trMemory());135for (int32_t i = TR::RealRegister::FirstVRF; i <= TR::RealRegister::LastVRF; i++)136{137if (!properties.getPreserved((TR::RealRegister::RegNum) i))138{139TR::addDependency(conditions, NULL, (TR::RealRegister::RegNum) i, TR_VRF, cg);140}141}142}143else144{145conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(nonVSXDepsCount, nonVSXDepsCount, cg->trMemory());146}147}148return conditions;149}150151static TR::Instruction *genNullTest(TR::Node *node, TR::Register *objectReg, TR::Register *crReg, TR::CodeGenerator *cg, TR::Instruction *cursor = NULL)152{153cursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, crReg, objectReg, NULLVALUE, cursor);154return cursor;155}156157static inline TR::Instruction *genNullTest(TR::Node *node, TR::Register *objectReg, TR::Register *crReg, TR::Register *scratchReg, TR::Instruction *cursor, TR::CodeGenerator *cg)158{159TR::Instruction *iRet;160iRet = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, crReg, objectReg, NULLVALUE, cursor);161return (iRet);162}163164static void genInlineTest(TR::Node * node, TR_OpaqueClassBlock* castClassAddr, TR_OpaqueClassBlock** guessClassArray, uint8_t num_PICS, TR::Register * objClassReg,165TR::Register * resultReg, TR::Register * cndReg, TR::Register * scratch1Reg, TR::Register * scratch2Reg, bool checkCast, bool needsResult, TR::LabelSymbol * falseLabel,166TR::LabelSymbol * trueLabel, TR::LabelSymbol * doneLabel, TR::LabelSymbol * callLabel, bool testCastClassIsSuper, TR::Instruction *iCursor, TR::CodeGenerator * cg)167{168TR::Compilation * comp = cg->comp();169TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());170dumpOptDetails(comp, "inline test with %d guess classes\n", num_PICS);171TR_ASSERT(num_PICS != 0, "genInlineTest is called with at least 1 guess class\n");172173TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg);174175// TODO: we pass callLabel twice in TR::PPCInterfaceCastSnippet. However, this is because the first one is used as176// the restart point on TR::PPCInterfaceCastSnippet, and the second as the reference to the call to the helper function177// this lets us have a more generic Snippet. This can be simplified later on, should it be needed.178//179TR::PPCInterfaceCastSnippet * guessCacheSnippet = new (cg->trHeapMemory()) TR::PPCInterfaceCastSnippet(cg, node, callLabel, snippetLabel, trueLabel, falseLabel, doneLabel,180callLabel, testCastClassIsSuper, checkCast, TR::Compiler->om.offsetOfObjectVftField(), offsetof(J9Class, castClassCache), needsResult);181cg->addSnippet(guessCacheSnippet);182183uint8_t i;184bool result_bool;185int32_t result_value;186TR::LabelSymbol *result_label;187for (i = 0; i < num_PICS - 1; i++)188{189// Load the cached value in scratch1Reg190// HCR in genInlineTest for checkcast and instanceof191if (cg->wantToPatchClassPointer(guessClassArray[i], node))192{193iCursor = loadAddressConstantInSnippet(cg, node, (intptr_t) (guessClassArray[i]), scratch1Reg, scratch2Reg,TR::InstOpCode::Op_load, true, iCursor);194}195else if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager))196{197TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);198sym->setStaticAddress(guessClassArray[i]);199sym->setClassObject();200201iCursor = loadAddressConstant(cg, true, node, (intptr_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), scratch1Reg, iCursor, false, TR_ClassAddress);202}203else204{205iCursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t) (guessClassArray[i]), scratch1Reg, iCursor);206}207result_bool = fej9->instanceOfOrCheckCast((J9Class*) guessClassArray[i], (J9Class*) castClassAddr);208int32_t result_value = result_bool ? 1 : 0;209result_label = (falseLabel != trueLabel) ? (result_bool ? trueLabel : falseLabel) : doneLabel;210iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, objClassReg, scratch1Reg, iCursor);211if (needsResult)212iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, result_value, iCursor);213iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, result_label, cndReg, iCursor);214}215216// Load the cached value in scratch1Reg217if (cg->wantToPatchClassPointer(guessClassArray[num_PICS - 1], node))218{219iCursor = loadAddressConstantInSnippet(cg, node, (intptr_t) (guessClassArray[num_PICS - 1]), scratch1Reg, scratch2Reg,TR::InstOpCode::Op_load, true, iCursor);220}221else if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager))222{223TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);224sym->setStaticAddress(guessClassArray[num_PICS - 1]);225sym->setClassObject();226227iCursor = loadAddressConstant(cg, true, node, (intptr_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), scratch1Reg, iCursor, false, TR_ClassAddress);228}229else230{231iCursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t) (guessClassArray[num_PICS - 1]), scratch1Reg, iCursor);232}233iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, objClassReg, scratch1Reg, iCursor);234iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg, iCursor);235result_bool = fej9->instanceOfOrCheckCast((J9Class*) guessClassArray[num_PICS - 1], (J9Class*) castClassAddr);236result_value = result_bool ? 1 : 0;237result_label = (falseLabel != trueLabel) ? (result_bool ? trueLabel : falseLabel) : doneLabel;238if (needsResult)239{240iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, result_value, iCursor);241}242iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, result_label, iCursor);243return;244}245246static TR::Register *nonFixedDependency(TR::RegisterDependencyConditions *conditions, TR::Register *nonFixedReg, int32_t *depIndex, TR_RegisterKinds kind, bool excludeGR0,247TR::CodeGenerator *cg)248{249int32_t index = *depIndex;250251if (nonFixedReg == NULL)252nonFixedReg = cg->allocateRegister(kind);253254TR::addDependency(conditions, nonFixedReg, TR::RealRegister::NoReg, kind, cg);255256if (excludeGR0)257{258conditions->getPreConditions()->getRegisterDependency(index)->setExcludeGPR0();259conditions->getPostConditions()->getRegisterDependency(index)->setExcludeGPR0();260}261262*depIndex += 1;263return nonFixedReg;264}265266static void reviveResultRegister(TR::Register *realResult, TR::Register *deadRes, TR::CodeGenerator *cg)267{268TR_RegisterKinds kind = realResult->getKind();269TR_LiveRegisters *liveRegs = cg->getLiveRegisters(kind);270271if (deadRes->isLive())272deadRes->getLiveRegisterInfo()->decNodeCount();273cg->stopUsingRegister(deadRes);274275if (liveRegs != NULL)276{277liveRegs->addRegister(realResult);278}279}280281static int32_t numberOfRegisterCandidate(TR::CodeGenerator *cg, TR::Node *depNode, TR_RegisterKinds kind)282{283int32_t idx, result = 0;284285for (idx = 0; idx < depNode->getNumChildren(); idx++)286{287TR::Node *child = depNode->getChild(idx);288TR::Register *reg;289290if (child->getOpCodeValue() == TR::PassThrough)291child = child->getFirstChild();292reg = child->getRegister();293if (reg != NULL && reg->getKind() == kind)294{295result += 1;296if (kind == TR_GPR && cg->comp()->target().is32Bit() && child->getType().isInt64())297result += 1;298}299}300return (result);301}302303// ----------------------------------------------------------------------------304305306307/*308* J9 PPC specific tree evaluator table overrides309*/310extern void TEMPORARY_initJ9PPCTreeEvaluatorTable(TR::CodeGenerator *cg)311{312TR_TreeEvaluatorFunctionPointer *tet = cg->getTreeEvaluatorTable();313314tet[TR::awrtbar] = TR::TreeEvaluator::awrtbarEvaluator;315tet[TR::awrtbari] = TR::TreeEvaluator::awrtbariEvaluator;316tet[TR::monent] = TR::TreeEvaluator::monentEvaluator;317tet[TR::monexit] = TR::TreeEvaluator::monexitEvaluator;318tet[TR::monexitfence] = TR::TreeEvaluator::monexitfenceEvaluator;319tet[TR::asynccheck] = TR::TreeEvaluator::asynccheckEvaluator;320tet[TR::instanceof] = TR::TreeEvaluator::instanceofEvaluator;321tet[TR::checkcast] = TR::TreeEvaluator::checkcastEvaluator;322tet[TR::checkcastAndNULLCHK] = TR::TreeEvaluator::checkcastAndNULLCHKEvaluator;323tet[TR::New] = TR::TreeEvaluator::newObjectEvaluator;324tet[TR::variableNew] = TR::TreeEvaluator::newObjectEvaluator;325tet[TR::newarray] = TR::TreeEvaluator::newArrayEvaluator;326tet[TR::anewarray] = TR::TreeEvaluator::anewArrayEvaluator;327tet[TR::variableNewArray] = TR::TreeEvaluator::anewArrayEvaluator;328tet[TR::multianewarray] = TR::TreeEvaluator::multianewArrayEvaluator;329tet[TR::arraylength] = TR::TreeEvaluator::arraylengthEvaluator;330tet[TR::ResolveCHK] = TR::TreeEvaluator::resolveCHKEvaluator;331tet[TR::DIVCHK] = TR::TreeEvaluator::DIVCHKEvaluator;332tet[TR::BNDCHK] = TR::TreeEvaluator::BNDCHKEvaluator;333tet[TR::ArrayCopyBNDCHK] = TR::TreeEvaluator::ArrayCopyBNDCHKEvaluator;334tet[TR::BNDCHKwithSpineCHK] = TR::TreeEvaluator::BNDCHKwithSpineCHKEvaluator;335tet[TR::SpineCHK] = TR::TreeEvaluator::BNDCHKwithSpineCHKEvaluator;336tet[TR::ArrayStoreCHK] = TR::TreeEvaluator::ArrayStoreCHKEvaluator;337tet[TR::ArrayCHK] = TR::TreeEvaluator::ArrayCHKEvaluator;338tet[TR::MethodEnterHook] = TR::TreeEvaluator::conditionalHelperEvaluator;339tet[TR::MethodExitHook] = TR::TreeEvaluator::conditionalHelperEvaluator;340tet[TR::allocationFence] = TR::TreeEvaluator::flushEvaluator;341tet[TR::loadFence] = TR::TreeEvaluator::flushEvaluator;342tet[TR::storeFence] = TR::TreeEvaluator::flushEvaluator;343tet[TR::fullFence] = TR::TreeEvaluator::flushEvaluator;344345tet[TR::icall] = TR::TreeEvaluator::directCallEvaluator;346tet[TR::lcall] = TR::TreeEvaluator::directCallEvaluator;347tet[TR::fcall] = TR::TreeEvaluator::directCallEvaluator;348tet[TR::dcall] = TR::TreeEvaluator::directCallEvaluator;349tet[TR::acall] = TR::TreeEvaluator::directCallEvaluator;350tet[TR::call] = TR::TreeEvaluator::directCallEvaluator;351tet[TR::vcall] = TR::TreeEvaluator::directCallEvaluator;352353tet[TR::tstart] = TR::TreeEvaluator::tstartEvaluator;354tet[TR::tfinish] = TR::TreeEvaluator::tfinishEvaluator;355tet[TR::tabort] = TR::TreeEvaluator::tabortEvaluator;356357tet[TR::NULLCHK] = TR::TreeEvaluator::NULLCHKEvaluator;358tet[TR::ResolveAndNULLCHK] = TR::TreeEvaluator::resolveAndNULLCHKEvaluator;359}360361362static void363VMoutlinedHelperWrtbarEvaluator(364TR::Node *node,365TR::Register *srcObjectReg,366TR::Register *dstObjectReg,367bool srcIsNonNull,368TR::CodeGenerator *cg)369{370TR::Compilation * comp = cg->comp();371const auto gcMode = TR::Compiler->om.writeBarrierType();372373if (gcMode == gc_modron_wrtbar_none)374return;375376const bool doWrtbar = gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always377|| comp->getOptions()->realTimeGC();378379const bool doCardMark = !node->isNonHeapObjectWrtBar() && (gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental);380381TR::CodeCache *codeCache = cg->getCodeCache();382TR::LabelSymbol *doneWrtbarLabel = generateLabelSymbol(cg);383TR::Register *srcNullCondReg;384385TR_PPCScratchRegisterDependencyConditions deps;386387// Clobbered by the helper388deps.addDependency(cg, NULL, TR::RealRegister::cr0);389deps.addDependency(cg, NULL, TR::RealRegister::cr1);390391if (!srcIsNonNull)392{393srcNullCondReg = cg->allocateRegister(TR_CCR);394generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, srcNullCondReg, srcObjectReg, NULLVALUE);395generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneWrtbarLabel, srcNullCondReg);396}397398if (doWrtbar)399{400deps.addDependency(cg, dstObjectReg, TR::RealRegister::gr3);401deps.addDependency(cg, srcObjectReg, TR::RealRegister::gr4);402// Clobbered by the helper403deps.addDependency(cg, NULL, TR::RealRegister::gr5);404deps.addDependency(cg, NULL, TR::RealRegister::gr6);405deps.addDependency(cg, NULL, TR::RealRegister::gr11);406407TR_CCPreLoadedCode helper = doCardMark ? TR_writeBarrierAndCardMark : TR_writeBarrier;408uintptr_t helperAddr = (uintptr_t) codeCache->getCCPreLoadedCodeAddress(helper, cg);409TR::SymbolReference *symRef = comp->getSymRefTab()->findOrCreatePerCodeCacheHelperSymbolRef(helper, helperAddr);410411TR::Instruction *gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, helperAddr, new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 0, cg->trMemory()),412symRef);413gcPoint->PPCNeedsGCMap(0xFFFFFFFF);414}415else416{417TR_ASSERT(doCardMark, "Expecting at least one write barrier to be performed");418419deps.addDependency(cg, dstObjectReg, TR::RealRegister::gr3);420// Clobbered by the helper421deps.addDependency(cg, NULL, TR::RealRegister::gr4);422deps.addDependency(cg, NULL, TR::RealRegister::gr5);423deps.addDependency(cg, NULL, TR::RealRegister::gr11);424425uintptr_t helperAddr = (uintptr_t) codeCache->getCCPreLoadedCodeAddress(TR_cardMark, cg);426TR::SymbolReference *symRef = comp->getSymRefTab()->findOrCreatePerCodeCacheHelperSymbolRef(TR_cardMark, helperAddr);427generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, helperAddr, new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 0, cg->trMemory()), symRef);428}429430generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneWrtbarLabel, TR_PPCScratchRegisterDependencyConditions::createDependencyConditions(cg, NULL, &deps));431432if (!srcIsNonNull)433cg->stopUsingRegister(srcNullCondReg);434435cg->machine()->setLinkRegisterKilled(true);436cg->setHasCall();437}438439TR::Register *outlinedHelperWrtbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)440{441TR::Register *srcObjectReg = cg->gprClobberEvaluate(node->getFirstChild());442TR::Register *dstObjectReg = cg->gprClobberEvaluate(node->getSecondChild());443TR::Compilation* comp = cg->comp();444445TR::Symbol *storeSym = node->getSymbolReference()->getSymbol();446const bool isOrderedShadowStore = storeSym->isShadow() && storeSym->isOrdered();447const bool needSync = comp->target().isSMP() && (storeSym->isSyncVolatile() || isOrderedShadowStore);448const bool lazyVolatile = comp->target().isSMP() && isOrderedShadowStore;449450// Under real-time, store happens after the wrtbar451// For other GC modes, store happens before the wrtbar452if (comp->getOptions()->realTimeGC())453{454}455else456{457TR::LoadStoreHandler::generateStoreNodeSequence(cg, srcObjectReg, node, TR::InstOpCode::Op_st, TR::Compiler->om.sizeofReferenceAddress());458459if (!node->getFirstChild()->isNull())460VMoutlinedHelperWrtbarEvaluator(node, srcObjectReg, dstObjectReg, node->getFirstChild()->isNonNull(), cg);461}462463cg->decReferenceCount(node->getFirstChild());464cg->decReferenceCount(node->getSecondChild());465466if (srcObjectReg != node->getFirstChild()->getRegister())467cg->stopUsingRegister(srcObjectReg);468if (dstObjectReg != node->getSecondChild()->getRegister())469cg->stopUsingRegister(dstObjectReg);470471return NULL;472}473474static int32_t getOffsetOfJ9ObjectFlags()475{476#if defined(J9VM_INTERP_FLAGS_IN_CLASS_SLOT)477#if defined(TR_TARGET_64BIT)478if (!TR::Compiler->om.compressObjectReferences())479#if defined(__LITTLE_ENDIAN__)480return TMP_OFFSETOF_J9OBJECT_CLAZZ;481#else482return TMP_OFFSETOF_J9OBJECT_CLAZZ + 4;483#endif484#endif485return TMP_OFFSETOF_J9OBJECT_CLAZZ;486#else487#if defined(TMP_OFFSETOF_J9OBJECT_FLAGS)488return TMP_OFFSETOF_J9OBJECT_FLAGS;489#else490return 0;491#endif492#endif493}494495static void VMnonNullSrcWrtBarCardCheckEvaluator(TR::Node *node, TR::Register *srcReg, TR::Register *dstReg, TR::Register *condReg, TR::Register *temp1Reg, TR::Register *temp2Reg,496TR::Register *temp3Reg, TR::Register *temp4Reg, TR::LabelSymbol *doneLabel, TR::RegisterDependencyConditions *deps,497bool isCompressedRef, TR::CodeGenerator *cg, bool flagsInTemp1 = false)498{499// non-heap objects cannot be marked500// Make sure we really should be here501TR::Compilation *comp = cg->comp();502TR::Options *options = comp->getOptions();503TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());504auto gcMode = TR::Compiler->om.writeBarrierType();505TR::LabelSymbol *callLabel = generateLabelSymbol(cg);506TR::Node *wrtbarNode = NULL;507TR::SymbolReference *wbRef;508bool definitelyHeapObject = false, definitelyNonHeapObject = false;509bool doCrdMrk = (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck);510bool doWrtBar = (gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always511|| comp->getOptions()->realTimeGC());512bool temp3RegIsNull = (temp3Reg == NULL);513514//registers for old/new space boundaries515TR::Register *bound1 = cg->allocateRegister();516TR::Register *bound2 = cg->allocateRegister();517518deps->addPostCondition(bound1, TR::RealRegister::NoReg);519deps->addPostCondition(bound2, TR::RealRegister::NoReg);520521TR_ASSERT(doWrtBar == true, "VMnonNullSrcWrtBarCardCheckEvaluator: Invalid call to VMnonNullSrcWrtBarCardCheckEvaluator\n");522523if (temp3RegIsNull)524{525temp3Reg = cg->allocateRegister();526TR::addDependency(deps, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);527}528529if (node->getOpCodeValue() == TR::awrtbari || node->getOpCodeValue() == TR::awrtbar)530wrtbarNode = node;531else if (node->getOpCodeValue() == TR::ArrayStoreCHK)532wrtbarNode = node->getFirstChild();533534if (wrtbarNode != NULL)535{536definitelyHeapObject = wrtbarNode->isHeapObjectWrtBar();537definitelyNonHeapObject = wrtbarNode->isNonHeapObjectWrtBar();538}539540if (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck)541wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreGenerationalAndConcurrentMarkSymbolRef(comp->getMethodSymbol());542else if (gcMode == gc_modron_wrtbar_oldcheck)543wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreGenerationalSymbolRef(comp->getMethodSymbol());544else if (comp->getOptions()->realTimeGC())545{546if (wrtbarNode->getOpCodeValue() == TR::awrtbar || wrtbarNode->isUnsafeStaticWrtBar())547wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierClassStoreRealTimeGCSymbolRef(comp->getMethodSymbol());548else549wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreRealTimeGCSymbolRef(comp->getMethodSymbol());550}551else552wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreSymbolRef(comp->getMethodSymbol());553554if (gcMode != gc_modron_wrtbar_always && !comp->getOptions()->realTimeGC())555{556bool inlineCrdmrk = (doCrdMrk && !definitelyNonHeapObject);557// object header flags now occupy 4bytes (instead of 8) on 64-bit. Keep it in temp1Reg for following checks.558559TR::Register *metaReg = cg->getMethodMetaDataRegister();560561TR::LabelSymbol* startICF = generateLabelSymbol(cg);562startICF->setStartInternalControlFlow();563564// dstReg - heapBaseForBarrierRange0565generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, bound1,566TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapBaseForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));567generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp3Reg, bound1, dstReg);568569// if (temp3Reg >= heapSizeForBarrierRage0), object not in the tenured area570generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, bound2,571TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapSizeForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));572generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp3Reg, bound2);573generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, doneLabel, condReg);574575if (!flagsInTemp1)576generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, temp1Reg, TR::MemoryReference::createWithDisplacement(cg, dstReg, getOffsetOfJ9ObjectFlags(), 4));577578if (inlineCrdmrk)579{580TR::LabelSymbol *noChkLabel = NULL;581582// Balanced policy must always dirty the card table.583//584if (gcMode != gc_modron_wrtbar_cardmark_incremental)585{586noChkLabel = generateLabelSymbol(cg);587588generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg,589TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, privateFlags), TR::Compiler->om.sizeofReferenceAddress()));590591// The value for J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE is a generated value when VM code is created592// At the moment we are safe here, but it is better to be careful and avoid any unexpected behaviour593// Make sure this falls within the scope of andis594//595TR_ASSERT(J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE >= 0x00010000 && J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE <= 0x80000000,596"Concurrent mark active Value assumption broken.");597generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andis_r, node, temp2Reg, temp2Reg, condReg, J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE >> 16);598599//start of control flow600generateLabelInstruction(cg, TR::InstOpCode::label, node, startICF);601generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, noChkLabel, condReg);602}603604#if defined(TR_TARGET_64BIT)605uintptr_t card_size_shift = trailingZeroes((uint64_t)options->getGcCardSize());606#else607uintptr_t card_size_shift = trailingZeroes((uint32_t) options->getGcCardSize());608#endif609610// dirty(activeCardTableBase + temp3Reg >> card_size_shift)611generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg,612TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, activeCardTableBase), TR::Compiler->om.sizeofReferenceAddress()));613#if defined(TR_TARGET_64BIT)614generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicl, node, temp3Reg, temp3Reg, 64-card_size_shift, (CONSTANT64(1)<<(64-card_size_shift)) - CONSTANT64(1));615#else616generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, temp3Reg, temp3Reg, 32 - card_size_shift, ((uint32_t) 0xFFFFFFFF) >> card_size_shift);617#endif618generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, temp4Reg, CARD_DIRTY);619generateMemSrc1Instruction(cg, TR::InstOpCode::stb, node, TR::MemoryReference::createWithIndexReg(cg, temp2Reg, temp3Reg, 1), temp4Reg);620621if (noChkLabel)622{623//end of control flow624noChkLabel->setEndInternalControlFlow();625generateLabelInstruction(cg, TR::InstOpCode::label, node, noChkLabel);626}627628if (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck)629{630//check for src in new space631generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp2Reg, bound1, srcReg);632633generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp2Reg, bound2);634generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneLabel, condReg);635}636}637else638{639if (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_oldcheck)640{641//check for src in new space642generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp3Reg, bound1, srcReg);643generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp3Reg, bound2);644generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneLabel, condReg);645}646}647648TR::Instruction * i = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, temp2Reg, temp1Reg, condReg, J9_OBJECT_HEADER_REMEMBERED_MASK_FOR_TEST);649generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, doneLabel, condReg);650}651else if (comp->getOptions()->realTimeGC())652{653if (!comp->getOption(TR_DisableInlineWriteBarriersRT))654{655// check if barrier is enabled: if disabled then branch around the rest656657TR::MemoryReference *fragmentParentMR = TR::MemoryReference::createWithDisplacement(cg, cg->getMethodMetaDataRegister(),658fej9->thisThreadRememberedSetFragmentOffset() + fej9->getFragmentParentOffset(), TR::Compiler->om.sizeofReferenceAddress());659generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg, fragmentParentMR);660661TR::MemoryReference *globalFragmentIDMR = TR::MemoryReference::createWithDisplacement(cg, temp2Reg, fej9->getRememberedSetGlobalFragmentOffset(), TR::Compiler->om.sizeofReferenceAddress());662generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg, globalFragmentIDMR);663664// if barrier not enabled, nothing to do665generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, condReg, temp1Reg, NULLVALUE);666generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);667668// now check if barrier absolutely necessary, according to GC: if it is, then make sure we go out-of-line669// if the global fragment index and local fragment index don't match, go to the snippet670TR::MemoryReference *localFragmentIndexMR = TR::MemoryReference::createWithDisplacement(cg, cg->getMethodMetaDataRegister(),671fej9->thisThreadRememberedSetFragmentOffset() + fej9->getLocalFragmentOffset(), TR::Compiler->om.sizeofReferenceAddress());672generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg, localFragmentIndexMR);673generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, condReg, temp2Reg, NULLVALUE);674generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg);675676// null test on the reference we're about to store over: if it is null goto doneLabel677TR::InstOpCode::Mnemonic opCode = TR::InstOpCode::lwz;678int32_t size = 4;679if (comp->target().is64Bit() && !isCompressedRef)680{681opCode = TR::InstOpCode::ld;682size = 8;683}684generateTrg1MemInstruction(cg, opCode, node, temp1Reg, TR::MemoryReference::createWithDisplacement(cg, temp3Reg, 0, size));685generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, condReg, temp1Reg, NULLVALUE);686generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);687688generateLabelInstruction(cg, TR::InstOpCode::label, node, callLabel);689}690}691692generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t) wbRef->getSymbol()->castToMethodSymbol()->getMethodAddress(),693new (cg->trHeapMemory()) TR::RegisterDependencyConditions((uint8_t) 0, 0, cg->trMemory()), wbRef, NULL);694cg->machine()->setLinkRegisterKilled(true);695696cg->stopUsingRegister(bound1);697cg->stopUsingRegister(bound2);698699if (temp3RegIsNull && temp3Reg)700cg->stopUsingRegister(temp3Reg);701}702703static void VMCardCheckEvaluator(TR::Node *node, TR::Register *dstReg, TR::Register *condReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register *temp3Reg,704TR::RegisterDependencyConditions *deps, TR::CodeGenerator *cg)705{706TR::Compilation * comp = cg->comp();707// non-heap objects cannot be marked708// Make sure we really should be here709TR::Options *options = comp->getOptions();710TR::Node *wrtbarNode = NULL;711bool definitelyHeapObject = false, definitelyNonHeapObject = false;712auto gcMode = TR::Compiler->om.writeBarrierType();713714if (node->getOpCodeValue() == TR::awrtbari || node->getOpCodeValue() == TR::awrtbar)715wrtbarNode = node;716else if (node->getOpCodeValue() == TR::ArrayStoreCHK)717wrtbarNode = node->getFirstChild();718719if (wrtbarNode != NULL)720{721definitelyHeapObject = wrtbarNode->isHeapObjectWrtBar();722definitelyNonHeapObject = wrtbarNode->isNonHeapObjectWrtBar();723}724725TR_ASSERT((gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental) && !definitelyNonHeapObject,726"VMCardCheckEvaluator: Invalid call to cardCheckEvaluator\n");727728if (!definitelyNonHeapObject)729{730TR::Register *metaReg = cg->getMethodMetaDataRegister();731TR::LabelSymbol *noChkLabel = generateLabelSymbol(cg);732733// Balanced policy must always dirty the card table.734//735if (gcMode != gc_modron_wrtbar_cardmark_incremental)736{737generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,738TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, privateFlags), TR::Compiler->om.sizeofReferenceAddress()));739740// The value for J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE is a generated value when VM code is created741// At the moment we are safe here, but it is better to be careful and avoid any unexpected behaviour742// Make sure this falls within the scope of andis743//744TR_ASSERT(J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE >= 0x00010000 && J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE <= 0x80000000,745"Concurrent mark active Value assumption broken.");746generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andis_r, node, temp1Reg, temp1Reg, condReg, J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE >> 16);747generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, noChkLabel, condReg);748}749750#if defined(TR_TARGET_64BIT)751uintptr_t card_size_shift = trailingZeroes((uint64_t)options->getGcCardSize());752#else753uintptr_t card_size_shift = trailingZeroes((uint32_t) options->getGcCardSize());754#endif755756// temp3Reg = dstReg - heapBaseForBarrierRange0757generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp3Reg,758TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapBaseForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));759generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp3Reg, temp3Reg, dstReg);760761if (!definitelyHeapObject)762{763// if (temp3Reg >= heapSizeForBarrierRage0), object not in the heap764generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,765TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapSizeForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));766generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp3Reg, temp1Reg);767generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, noChkLabel, condReg);768}769770// dirty(activeCardTableBase + temp3Reg >> card_size_shift)771generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,772TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, activeCardTableBase), TR::Compiler->om.sizeofReferenceAddress()));773#if defined(TR_TARGET_64BIT)774generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicl, node, temp3Reg, temp3Reg, 64-card_size_shift, (CONSTANT64(1)<<(64-card_size_shift)) - CONSTANT64(1));775#else776generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, temp3Reg, temp3Reg, 32 - card_size_shift, ((uint32_t) 0xFFFFFFFF) >> card_size_shift);777#endif778generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, temp2Reg, CARD_DIRTY);779generateMemSrc1Instruction(cg, TR::InstOpCode::stb, node, TR::MemoryReference::createWithIndexReg(cg, temp1Reg, temp3Reg, 1), temp2Reg);780781generateLabelInstruction(cg, TR::InstOpCode::label, node, noChkLabel);782}783784}785786static void VMwrtbarEvaluator(TR::Node *node, TR::Register *srcReg, TR::Register *dstReg, TR::Register *dstAddrReg,787TR::RegisterDependencyConditions *conditions, bool srcNonNull, bool needDeps, bool isCompressedRef, TR::CodeGenerator *cg, TR::Register *flagsReg = NULL)788{789TR::Compilation *comp = cg->comp();790auto gcMode = TR::Compiler->om.writeBarrierType();791bool doWrtBar = (gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always792|| comp->getOptions()->realTimeGC());793bool doCrdMrk = ((gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental) && !node->isNonHeapObjectWrtBar());794TR::LabelSymbol *label;795TR::Register *cr0, *temp1Reg, *temp2Reg, *temp3Reg = NULL, *temp4Reg = NULL;796uint8_t numRegs = (doWrtBar && doCrdMrk) ? 7 : 5;797798//Also need to pass in destinationAddress to jitWriteBarrierStoreMetronome799if (comp->getOptions()->realTimeGC())800numRegs += 3;801802if (doWrtBar || doCrdMrk)803numRegs += 4; //two extra deps for space boundaries804805if ((!doWrtBar && !doCrdMrk) || (node->getOpCode().isWrtBar() && node->skipWrtBar()))806{807if (flagsReg)808cg->stopUsingRegister(flagsReg);809return;810}811if (flagsReg)812temp1Reg = flagsReg;813else814temp1Reg = cg->allocateRegister();815816temp2Reg = cg->allocateRegister();817label = generateLabelSymbol(cg);818819if (doWrtBar || doCrdMrk)820needDeps = true;821822if (needDeps)823{824cr0 = cg->allocateRegister(TR_CCR);825conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(numRegs, numRegs, cg->trMemory());826TR::addDependency(conditions, cr0, TR::RealRegister::cr0, TR_CCR, cg);827TR::addDependency(conditions, dstReg, TR::RealRegister::gr3, TR_GPR, cg);828TR::addDependency(conditions, temp1Reg, TR::RealRegister::gr11, TR_GPR, cg);829if (comp->getOptions()->realTimeGC())830{831TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);832conditions->getPostConditions()->getRegisterDependency(3)->setExcludeGPR0(); //3=temp2Reg833TR::addDependency(conditions, dstAddrReg, TR::RealRegister::gr4, TR_GPR, cg);834temp3Reg = dstAddrReg;835}836else837TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);838}839else840cr0 = conditions->getPostConditions()->getRegisterDependency(2)->getRegister();841842if (doWrtBar)843{844if (doCrdMrk)845{846temp3Reg = cg->allocateRegister();847temp4Reg = cg->allocateRegister();848if (needDeps)849{850TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);851TR::addDependency(conditions, temp4Reg, TR::RealRegister::NoReg, TR_GPR, cg);852conditions->getPostConditions()->getRegisterDependency(3)->setExcludeGPR0(); //3=temp2Reg853}854}855if (needDeps)856{857if (comp->getOptions()->realTimeGC())858TR::addDependency(conditions, srcReg, TR::RealRegister::gr5, TR_GPR, cg);859else860TR::addDependency(conditions, srcReg, TR::RealRegister::gr4, TR_GPR, cg);861}862if (!srcNonNull && !comp->getOptions()->realTimeGC())863{864generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cr0, srcReg, NULLVALUE);865generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, label, cr0);866}867868VMnonNullSrcWrtBarCardCheckEvaluator(node, srcReg, dstReg, cr0, temp1Reg, temp2Reg, temp3Reg, temp4Reg, label, conditions, isCompressedRef, cg,869flagsReg != NULL);870generateDepLabelInstruction(cg, TR::InstOpCode::label, node, label, conditions);871if (doCrdMrk)872{873cg->stopUsingRegister(temp3Reg);874cg->stopUsingRegister(temp4Reg);875}876else if (comp->getOptions()->realTimeGC())877cg->stopUsingRegister(temp3Reg);878}879else if (doCrdMrk)880{881temp3Reg = cg->allocateRegister();882if (needDeps)883{884TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);885conditions->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0(); //1=dstReg886conditions->getPostConditions()->getRegisterDependency(2)->setExcludeGPR0(); //2=temp1Reg887}888889VMCardCheckEvaluator(node, dstReg, cr0, temp1Reg, temp2Reg, temp3Reg, conditions, cg);890generateDepLabelInstruction(cg, TR::InstOpCode::label, node, label, conditions);891cg->stopUsingRegister(temp3Reg);892}893if (needDeps)894{895cg->stopUsingRegister(cr0);896}897cg->stopUsingRegister(temp1Reg);898cg->stopUsingRegister(temp2Reg);899}900901inline void generateLoadJ9Class(TR::Node* node, TR::Register* j9classReg, TR::Register *objReg, TR::CodeGenerator* cg)902{903if (TR::Compiler->om.compressObjectReferences())904generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, j9classReg,905TR::MemoryReference::createWithDisplacement(cg, objReg, static_cast<int32_t>(TR::Compiler->om.offsetOfObjectVftField()), 4));906else907generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, j9classReg,908TR::MemoryReference::createWithDisplacement(cg, objReg, static_cast<int32_t>(TR::Compiler->om.offsetOfObjectVftField()), TR::Compiler->om.sizeofReferenceAddress()));909TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, j9classReg);910}911912void913J9::Power::TreeEvaluator::generateFillInDataBlockSequenceForUnresolvedField(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *dataSnippetRegister)914{915TR::Compilation *comp = cg->comp();916TR::SymbolReference *symRef = node->getSymbolReference();917bool is64Bit = comp->target().is64Bit();918bool isStatic = symRef->getSymbol()->getKind() == TR::Symbol::IsStatic;919920TR_RuntimeHelper helperIndex = isWrite? (isStatic ? TR_jitResolveStaticFieldSetterDirect: TR_jitResolveFieldSetterDirect):921(isStatic ? TR_jitResolveStaticFieldDirect: TR_jitResolveFieldDirect);922923TR::Linkage *linkage = cg->getLinkage(runtimeHelperLinkage(helperIndex));924auto linkageProperties = linkage->getProperties();925intptr_t offsetInDataBlock = isStatic ? offsetof(J9JITWatchedStaticFieldData, fieldAddress): offsetof(J9JITWatchedInstanceFieldData, offset);926927928TR::LabelSymbol* startLabel = generateLabelSymbol(cg);929TR::LabelSymbol* endLabel = generateLabelSymbol(cg);930TR::LabelSymbol* unresolvedLabel = generateLabelSymbol(cg);931startLabel->setStartInternalControlFlow();932endLabel->setEndInternalControlFlow();933934TR::Register *cpIndexReg = cg->allocateRegister();935TR::Register *resultReg = cg->allocateRegister();936TR::Register *scratchReg = cg->allocateRegister();937TR::Register *jumpReg = cg->allocateRegister();938939// Check if snippet has been loaded940if (!isStatic && !static_cast<TR::J9PPCWatchedInstanceFieldSnippet *>(dataSnippet)->isSnippetLoaded() ||941(isStatic && !static_cast<TR::J9PPCWatchedStaticFieldSnippet *>(dataSnippet)->isSnippetLoaded()))942loadFieldWatchSnippet(cg, node, dataSnippet, dataSnippetRegister, scratchReg, !isStatic);943944945// Setup Dependencies946// dataSnippetRegister is always used during OOL sequence.947// Requires two argument registers: resultReg and cpIndexReg.948// Static requires an extra arugment fieldClassReg949// jumpReg used by trampoline950uint8_t numOfConditions = isStatic? 5 : 4;951TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(numOfConditions, numOfConditions, cg->trMemory());952953deps->addPreCondition(dataSnippetRegister, TR::RealRegister::NoReg);954deps->addPostCondition(dataSnippetRegister, TR::RealRegister::NoReg);955956TR_PPCOutOfLineCodeSection *generateReportOOL = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(unresolvedLabel, endLabel, cg);957cg->getPPCOutOfLineCodeSectionList().push_front(generateReportOOL);958959generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);960961// Compare J9JITWatchedInstanceFieldData.offset or J9JITWatchedStaticFieldData.fieldAddress (Depending on Instance of Static)962// Load value from dataSnippetRegister + offsetInDataBlock then compare and branch963TR::Register *cndReg = cg->allocateRegister(TR_CCR);964generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, scratchReg,965TR::MemoryReference::createWithDisplacement(cg, dataSnippetRegister, offsetInDataBlock, TR::Compiler->om.sizeofReferenceAddress()));966generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::Op_cmpi, node, cndReg, scratchReg, -1);967generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, unresolvedLabel, cndReg);968969generateReportOOL->swapInstructionListsWithCompilation();970971generateLabelInstruction(cg, TR::InstOpCode::label, node, unresolvedLabel);972973bool isSideEffectReg = false;974if (isStatic)975{976// Fill in J9JITWatchedStaticFieldData.fieldClass977TR::Register *fieldClassReg = NULL;978979if (isWrite)980{981fieldClassReg = cg->allocateRegister();982generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, fieldClassReg,983TR::MemoryReference::createWithDisplacement(cg, sideEffectRegister, comp->fej9()->getOffsetOfClassFromJavaLangClassField(), TR::Compiler->om.sizeofReferenceAddress()));984}985else986{987isSideEffectReg = true;988fieldClassReg = sideEffectRegister;989}990TR::MemoryReference *memRef = TR::MemoryReference::createWithDisplacement(cg, dataSnippetRegister, offsetof(J9JITWatchedStaticFieldData, fieldClass), TR::Compiler->om.sizeofReferenceAddress());991992// Store value to dataSnippetRegister + offset of fieldClass993generateMemSrc1Instruction(cg, TR::InstOpCode::Op_st, node, memRef, fieldClassReg);994deps->addPreCondition(fieldClassReg, TR::RealRegister::NoReg);995deps->addPostCondition(fieldClassReg, TR::RealRegister::NoReg);996if (!isSideEffectReg)997cg->stopUsingRegister(fieldClassReg);998}9991000TR::ResolvedMethodSymbol *methodSymbol = node->getByteCodeInfo().getCallerIndex() == -1 ? comp->getMethodSymbol(): comp->getInlinedResolvedMethodSymbol(node->getByteCodeInfo().getCallerIndex());10011002// Store cpAddressReg1003// TODO: Replace when AOT TR_ConstantPool Discontiguous support is enabled1004//loadAddressConstant(cg, node, (uintptr_t)methodSymbol->getResolvedMethod()->constantPool(), resultReg, NULL, false, TR_ConstantPool);1005loadAddressConstant(cg, comp->compileRelocatableCode(), node, reinterpret_cast<uintptr_t>(methodSymbol->getResolvedMethod()->constantPool()), resultReg);1006loadConstant(cg, node, symRef->getCPIndex(), cpIndexReg);10071008// cpAddress is the first argument of VMHelper1009deps->addPreCondition(resultReg, TR::RealRegister::gr3);1010deps->addPostCondition(resultReg, TR::RealRegister::gr3);1011// cpIndexReg is the second argument1012deps->addPreCondition(cpIndexReg, TR::RealRegister::gr4);1013deps->addPostCondition(cpIndexReg, TR::RealRegister::gr4);1014// jumpReg is used in trampoline to store callee address1015deps->addPreCondition(jumpReg, TR::RealRegister::gr11);1016deps->addPostCondition(jumpReg, TR::RealRegister::gr11);10171018// Generate helper address and branch1019TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(helperIndex);1020TR::Instruction *call = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, reinterpret_cast<uintptr_t>(helperSym->getMethodAddress()), deps, helperSym);1021call->PPCNeedsGCMap(linkageProperties.getPreservedRegisterMapForGC());10221023/*1024* For instance field offset, the result returned by the vmhelper includes header size.1025* subtract the header size to get the offset needed by field watch helpers1026*/1027if (!isStatic)1028addConstantToInteger(node, resultReg, resultReg , -TR::Compiler->om.objectHeaderSizeInBytes(), cg);10291030// store result into J9JITWatchedStaticFieldData.fieldAddress / J9JITWatchedInstanceFieldData.offset1031TR::MemoryReference* dataRef = TR::MemoryReference::createWithDisplacement(cg, dataSnippetRegister, offsetInDataBlock, TR::Compiler->om.sizeofReferenceAddress());1032generateMemSrc1Instruction(cg, TR::InstOpCode::Op_st, node, dataRef, resultReg);10331034generateLabelInstruction(cg, TR::InstOpCode::b, node, endLabel);10351036generateReportOOL->swapInstructionListsWithCompilation();10371038generateLabelInstruction(cg, TR::InstOpCode::label, node, endLabel);10391040cg->stopUsingRegister(scratchReg);1041cg->stopUsingRegister(cndReg);1042cg->stopUsingRegister(cpIndexReg);1043cg->stopUsingRegister(resultReg);1044cg->stopUsingRegister(jumpReg);10451046}10471048/*1049* Generate the reporting field access helper call with required arguments1050*1051* jitReportInstanceFieldRead1052* arg1 pointer to static data block1053* arg2 object being read1054*1055* jitReportInstanceFieldWrite1056* arg1 pointer to static data block1057* arg2 object being written to1058* arg3 pointer to value being written1059*1060* jitReportStaticFieldRead1061* arg1 pointer to static data block1062*1063* jitReportStaticFieldWrite1064* arg1 pointer to static data block1065* arg2 pointer to value being written1066*1067*/1068void generateReportFieldAccessOutlinedInstructions(TR::Node *node, TR::LabelSymbol *endLabel, TR::Register *dataBlockReg, bool isWrite, TR::CodeGenerator *cg, TR::Register *sideEffectRegister, TR::Register *valueReg)1069{1070TR::Compilation *comp = cg->comp();1071bool isInstanceField = node->getOpCode().isIndirect();10721073TR_RuntimeHelper helperIndex = isWrite ? (isInstanceField ? TR_jitReportInstanceFieldWrite: TR_jitReportStaticFieldWrite):1074(isInstanceField ? TR_jitReportInstanceFieldRead: TR_jitReportStaticFieldRead);10751076TR::Linkage *linkage = cg->getLinkage(runtimeHelperLinkage(helperIndex));1077auto linkageProperties = linkage->getProperties();1078TR::Register *valueReferenceReg = NULL;1079TR::Register *jumpReg = cg->allocateRegister();10801081// First argument is always the data block.1082// One register used by trampoline1083uint8_t numOfConditions = 2;1084// Instance field report needs the base object1085if (isInstanceField)1086numOfConditions++;1087// Field write report needs:1088// value being written1089// the reference to the value being written1090if (isWrite)1091numOfConditions += 2;1092// Register Pair may be needed1093if(comp->target().is32Bit())1094numOfConditions++;10951096TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory())TR::RegisterDependencyConditions(numOfConditions, numOfConditions, cg->trMemory());10971098/*1099* For reporting field write, reference to the valueNode is needed so we need to store1100* the value on to a stack location first and pass the stack location address as an arguement1101* to the VM helper1102*/1103if (isWrite)1104{1105TR::DataType dt = node->getDataType();1106int32_t elementSize = dt == TR::Address ? TR::Compiler->om.sizeofReferenceField() : TR::Symbol::convertTypeToSize(dt);1107TR::InstOpCode::Mnemonic storeOp = getLoadOrStoreFromDataType(cg, dt, elementSize, node->getOpCode().isUnsigned(), false);1108TR::SymbolReference *location = cg->allocateLocalTemp(dt);1109TR::MemoryReference *valueMR = TR::MemoryReference::createWithSymRef(cg, node, location, node->getSize());1110if (!valueReg->getRegisterPair())1111{1112generateMemSrc1Instruction(cg, storeOp, node, valueMR, valueReg);1113deps->addPreCondition(valueReg, TR::RealRegister::NoReg);1114deps->addPostCondition(valueReg, TR::RealRegister::NoReg);1115valueReferenceReg = cg->allocateRegister();1116}1117else1118{1119TR::MemoryReference *tempMR2 = TR::MemoryReference::createWithMemRef(cg, node, *valueMR, 4, 4);1120generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, valueMR, valueReg->getHighOrder());1121generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, tempMR2, valueReg->getLowOrder());1122deps->addPreCondition(valueReg->getHighOrder(), TR::RealRegister::NoReg);1123deps->addPostCondition(valueReg->getHighOrder(), TR::RealRegister::NoReg);1124valueReferenceReg = valueReg->getLowOrder();1125}11261127// store the stack location into a register1128generateTrg1MemInstruction(cg, TR::InstOpCode::addi2, node, valueReferenceReg, valueMR);1129}11301131// First Argument - DataBlock1132deps->addPreCondition(dataBlockReg, TR::RealRegister::gr3);1133deps->addPostCondition(dataBlockReg, TR::RealRegister::gr3);11341135// Second Argument1136if (isInstanceField)1137{1138deps->addPreCondition(sideEffectRegister, TR::RealRegister::gr4);1139deps->addPostCondition(sideEffectRegister, TR::RealRegister::gr4);1140}1141else if (isWrite)1142{1143deps->addPreCondition(valueReferenceReg, TR::RealRegister::gr4);1144deps->addPostCondition(valueReferenceReg, TR::RealRegister::gr4);1145}11461147// Third Argument1148if (isInstanceField && isWrite)1149{1150deps->addPreCondition(valueReferenceReg, TR::RealRegister::gr5);1151deps->addPostCondition(valueReferenceReg, TR::RealRegister::gr5);1152}11531154// Register ued by trampoline to store callee address1155deps->addPreCondition(jumpReg, TR::RealRegister::gr11);1156deps->addPostCondition(jumpReg, TR::RealRegister::gr11);11571158// Generate branch instruction to jump into helper1159TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(helperIndex);1160TR::Instruction *call = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, reinterpret_cast<uintptr_t>(helperSym->getMethodAddress()), deps, helperSym);1161call->PPCNeedsGCMap(linkageProperties.getPreservedRegisterMapForGC());11621163generateLabelInstruction(cg, TR::InstOpCode::b, node, endLabel);11641165cg->stopUsingRegister(valueReferenceReg);1166cg->stopUsingRegister(jumpReg);11671168}11691170void loadFieldWatchSnippet(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, TR::Register *snippetReg, TR::Register *scratchReg, bool isInstanceField)1171{1172TR::Compilation *comp = cg->comp();1173int32_t beginIndex = PTOC_FULL_INDEX;11741175cg->fixedLoadLabelAddressIntoReg(node, snippetReg, dataSnippet->getSnippetLabel());11761177// Loaded Snippet1178if (!isInstanceField)1179{1180static_cast<TR::J9PPCWatchedStaticFieldSnippet *>(dataSnippet)->setLoadSnippet();1181}1182else1183{1184static_cast<TR::J9PPCWatchedInstanceFieldSnippet *>(dataSnippet)->setLoadSnippet();1185}1186}11871188TR::Snippet *1189J9::Power::TreeEvaluator::getFieldWatchInstanceSnippet(TR::CodeGenerator *cg, TR::Node *node, J9Method *m, UDATA loc, UDATA os)1190{1191return new (cg->trHeapMemory()) TR::J9PPCWatchedInstanceFieldSnippet(cg, node, m, loc, os);1192}11931194TR::Snippet *1195J9::Power::TreeEvaluator::getFieldWatchStaticSnippet(TR::CodeGenerator *cg, TR::Node *node, J9Method *m, UDATA loc, void *fieldAddress, J9Class *fieldClass)1196{1197return new (cg->trHeapMemory()) TR::J9PPCWatchedStaticFieldSnippet(cg, node, m, loc, fieldAddress, fieldClass);1198}11991200void1201J9::Power::TreeEvaluator::generateTestAndReportFieldWatchInstructions(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *valueReg, TR::Register *dataSnippetRegister)1202{1203bool isInstanceField = node->getOpCode().isIndirect();1204TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());12051206TR::Register *scratchReg = cg->allocateRegister();12071208// Check if snippet has been loaded1209if (isInstanceField && !static_cast<TR::J9PPCWatchedInstanceFieldSnippet *>(dataSnippet)->isSnippetLoaded() ||1210(!isInstanceField && !static_cast<TR::J9PPCWatchedStaticFieldSnippet *>(dataSnippet)->isSnippetLoaded()))1211loadFieldWatchSnippet(cg, node, dataSnippet, dataSnippetRegister, scratchReg, isInstanceField);12121213TR::LabelSymbol* startLabel = generateLabelSymbol(cg);1214TR::LabelSymbol* endLabel = generateLabelSymbol(cg);1215TR::LabelSymbol* fieldReportLabel = generateLabelSymbol(cg);1216startLabel->setStartInternalControlFlow();1217endLabel->setEndInternalControlFlow();12181219generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);12201221TR_PPCOutOfLineCodeSection *generateReportOOL = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(fieldReportLabel, endLabel, cg);1222cg->getPPCOutOfLineCodeSectionList().push_front(generateReportOOL);12231224TR::Register *fieldClassReg = NULL;1225bool isSideEffectReg = false;1226// Load fieldClass1227if (isInstanceField)1228{1229fieldClassReg = cg->allocateRegister();1230generateLoadJ9Class(node, fieldClassReg, sideEffectRegister, cg);1231}1232else if (!(node->getSymbolReference()->isUnresolved()))1233{1234fieldClassReg = cg->allocateRegister();1235// During Non-AOT (JIT and JITServer) compilation the fieldClass has been populated inside the dataSnippet during compilation.1236// During AOT compilation the fieldClass must be loaded from the snippet. The fieldClass in an AOT body is invalid.1237if (cg->needClassAndMethodPointerRelocations())1238{1239// Load FieldClass from snippet1240generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, fieldClassReg,1241TR::MemoryReference::createWithDisplacement(cg, dataSnippetRegister, offsetof(J9JITWatchedStaticFieldData, fieldClass),1242TR::Compiler->om.sizeofReferenceAddress()));1243}1244else1245{1246J9Class * fieldClass = static_cast<TR::J9PPCWatchedStaticFieldSnippet *>(dataSnippet)->getFieldClass();1247loadAddressConstant(cg, false, node, reinterpret_cast<uintptr_t>(fieldClass), fieldClassReg);1248}1249}1250else1251{1252// Unresolved1253if (isWrite)1254{1255fieldClassReg = cg->allocateRegister();1256generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, fieldClassReg,1257TR::MemoryReference::createWithDisplacement(cg, sideEffectRegister, fej9->getOffsetOfClassFromJavaLangClassField(), TR::Compiler->om.sizeofReferenceAddress()));1258}1259else1260{1261isSideEffectReg = true;1262fieldClassReg = sideEffectRegister;1263}1264}12651266TR::MemoryReference *classFlagsMemRef = TR::MemoryReference::createWithDisplacement(cg, fieldClassReg, static_cast<uintptr_t>(fej9->getOffsetOfClassFlags()), 4);12671268TR::Register *cndReg = cg->allocateRegister(TR_CCR);1269generateTrg1MemInstruction(cg,TR::InstOpCode::lwz, node, scratchReg, classFlagsMemRef);1270generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, scratchReg, scratchReg, cndReg, J9ClassHasWatchedFields);1271generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, fieldReportLabel, cndReg);12721273generateReportOOL->swapInstructionListsWithCompilation();12741275generateLabelInstruction(cg, TR::InstOpCode::label, node, fieldReportLabel);1276generateReportFieldAccessOutlinedInstructions(node, endLabel, dataSnippetRegister, isWrite, cg, sideEffectRegister, valueReg);12771278generateReportOOL->swapInstructionListsWithCompilation();12791280generateLabelInstruction(cg, TR::InstOpCode::label, node, endLabel);12811282cg->stopUsingRegister(cndReg);1283cg->stopUsingRegister(scratchReg);1284if (!isSideEffectReg)1285cg->stopUsingRegister(fieldClassReg);1286cg->stopUsingRegister(valueReg);12871288cg->machine()->setLinkRegisterKilled(true);12891290}12911292TR::Register *J9::Power::TreeEvaluator::awrtbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)1293{1294TR::Compilation *comp = cg->comp();1295TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());1296TR::Register *valueReg = cg->evaluate(node->getFirstChild());1297TR::Register *sideEffectRegister = cg->evaluate(node->getSecondChild());1298if (comp->getOption(TR_EnableFieldWatch) && !node->getSymbolReference()->getSymbol()->isShadow())1299{1300TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);1301}13021303if (comp->isOptServer() && !comp->compileRelocatableCode() && !comp->getOptions()->realTimeGC())1304{1305if (!comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8))1306{1307static bool disableOutlinedWrtbar = feGetEnv("TR_ppcDisableOutlinedWriteBarrier") != NULL;1308if (!disableOutlinedWrtbar)1309{1310return outlinedHelperWrtbarEvaluator(node, cg);1311}1312}1313else1314{1315static bool enableOutlinedWrtbar = feGetEnv("TR_ppcEnableOutlinedWriteBarrier") != NULL;1316if (enableOutlinedWrtbar)1317{1318return outlinedHelperWrtbarEvaluator(node, cg);1319}1320}1321}13221323TR::Register *destinationRegister = cg->evaluate(node->getSecondChild());1324TR::Register *flagsReg = NULL;1325TR::Node *firstChild = node->getFirstChild();1326TR::Register *sourceRegister;1327bool killSource = false;13281329if (firstChild->getReferenceCount() > 1 && firstChild->getRegister() != NULL)1330{1331if (!firstChild->getRegister()->containsInternalPointer())1332sourceRegister = cg->allocateCollectedReferenceRegister();1333else1334{1335sourceRegister = cg->allocateRegister();1336sourceRegister->setPinningArrayPointer(firstChild->getRegister()->getPinningArrayPointer());1337sourceRegister->setContainsInternalPointer();1338}1339generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, sourceRegister, firstChild->getRegister());1340killSource = true;1341}1342else1343sourceRegister = cg->evaluate(firstChild);13441345if (!node->skipWrtBar() && !node->hasUnresolvedSymbolReference()1346&& (TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_oldcheck || TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_cardmark_and_oldcheck))1347{1348flagsReg = cg->allocateRegister();1349generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, flagsReg, TR::MemoryReference::createWithDisplacement(cg, destinationRegister, getOffsetOfJ9ObjectFlags(), 4));1350}13511352// RealTimeGC write barriers occur BEFORE the store1353if (comp->getOptions()->realTimeGC())1354{1355TR::Register *destinationAddressRegister = cg->allocateRegister();13561357TR::LoadStoreHandler::generateComputeAddressSequence(cg, destinationAddressRegister, node);1358VMwrtbarEvaluator(node, sourceRegister, destinationRegister, destinationAddressRegister, NULL, firstChild->isNonNull(), true, false, cg);1359TR::LoadStoreHandler::generateStoreAddressSequence(cg, sourceRegister, node, destinationAddressRegister, TR::InstOpCode::Op_st, TR::Compiler->om.sizeofReferenceAddress());13601361cg->stopUsingRegister(destinationAddressRegister);1362}1363else1364{1365TR::LoadStoreHandler::generateStoreNodeSequence(cg, sourceRegister, node, TR::InstOpCode::Op_st, TR::Compiler->om.sizeofReferenceAddress());1366VMwrtbarEvaluator(node, sourceRegister, destinationRegister, NULL, NULL, firstChild->isNonNull(), true, false, cg, flagsReg);1367}13681369if (killSource)1370cg->stopUsingRegister(sourceRegister);13711372cg->decReferenceCount(node->getFirstChild());1373cg->decReferenceCount(node->getSecondChild());13741375return NULL;1376}13771378TR::Register *J9::Power::TreeEvaluator::awrtbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)1379{1380TR::Compilation *comp = cg->comp();1381TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());13821383TR::Node *valueNode = NULL;1384TR::TreeEvaluator::getIndirectWrtbarValueNode(cg, node, valueNode, false);1385TR::Register *valueReg = cg->evaluate(valueNode);1386TR::Register *sideEffectRegister = cg->evaluate(node->getThirdChild());13871388TR::Register *destinationRegister = cg->evaluate(node->getChild(2));1389TR::Node *secondChild = node->getSecondChild();1390TR::Register *sourceRegister;1391TR::Register *flagsReg = NULL;1392bool killSource = false;13931394bool usingCompressedPointers = false;1395bool bumpedRefCount = false;13961397if (comp->getOption(TR_EnableFieldWatch) && !node->getSymbolReference()->getSymbol()->isArrayShadowSymbol())1398{1399// The Third child (sideEffectNode) and valueReg's node is also used by the store evaluator below.1400// The store evaluator will also evaluate+decrement it. In order to avoid double1401// decrementing the node we skip doing it here and let the store evaluator do it.1402TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);1403}14041405if (comp->useCompressedPointers() && (node->getSymbolReference()->getSymbol()->getDataType() == TR::Address) && (node->getSecondChild()->getDataType() != TR::Address))1406{1407usingCompressedPointers = true;1408while (secondChild->getNumChildren() && secondChild->getOpCodeValue() != TR::a2l)1409secondChild = secondChild->getFirstChild();1410if (secondChild->getNumChildren())1411secondChild = secondChild->getFirstChild();1412}14131414int32_t sizeofMR = TR::Compiler->om.sizeofReferenceAddress();1415if (usingCompressedPointers)1416sizeofMR = TR::Compiler->om.sizeofReferenceField();14171418TR::Register *compressedReg;1419if (secondChild->getReferenceCount() > 1 && secondChild->getRegister() != NULL)1420{1421if (!secondChild->getRegister()->containsInternalPointer())1422sourceRegister = cg->allocateCollectedReferenceRegister();1423else1424{1425sourceRegister = cg->allocateRegister();1426sourceRegister->setPinningArrayPointer(secondChild->getRegister()->getPinningArrayPointer());1427sourceRegister->setContainsInternalPointer();1428}1429generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, sourceRegister, secondChild->getRegister());1430killSource = true;1431compressedReg = sourceRegister;1432if (usingCompressedPointers)1433compressedReg = cg->evaluate(node->getSecondChild());1434}1435else1436{1437sourceRegister = cg->evaluate(secondChild);1438compressedReg = sourceRegister;1439if (usingCompressedPointers)1440compressedReg = cg->evaluate(node->getSecondChild());1441}14421443if (!node->skipWrtBar() && !node->hasUnresolvedSymbolReference()1444&& (TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_oldcheck || TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_cardmark_and_oldcheck))1445{1446flagsReg = cg->allocateRegister();1447generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, flagsReg, TR::MemoryReference::createWithDisplacement(cg, destinationRegister, getOffsetOfJ9ObjectFlags(), 4));1448}14491450TR::InstOpCode::Mnemonic storeOp = usingCompressedPointers ? TR::InstOpCode::stw : TR::InstOpCode::Op_st;1451TR::Register *storeRegister = usingCompressedPointers ? compressedReg : sourceRegister;14521453// RealTimeGC write barriers occur BEFORE the store1454if (comp->getOptions()->realTimeGC())1455{1456TR::Register *destinationAddressRegister = cg->allocateRegister();14571458TR::LoadStoreHandler::generateComputeAddressSequence(cg, destinationAddressRegister, node);1459VMwrtbarEvaluator(node, sourceRegister, destinationRegister, destinationAddressRegister, NULL, secondChild->isNonNull(), true, usingCompressedPointers, cg);1460TR::LoadStoreHandler::generateStoreAddressSequence(cg, storeRegister, node, destinationAddressRegister, storeOp, sizeofMR);14611462cg->stopUsingRegister(destinationAddressRegister);1463}1464else1465{1466TR::LoadStoreHandler::generateStoreNodeSequence(cg, storeRegister, node, storeOp, sizeofMR);1467VMwrtbarEvaluator(node, sourceRegister, destinationRegister, NULL, NULL, secondChild->isNonNull(), true, usingCompressedPointers, cg, flagsReg);1468}14691470if (killSource)1471cg->stopUsingRegister(sourceRegister);14721473cg->decReferenceCount(node->getSecondChild());1474cg->decReferenceCount(node->getChild(2));14751476if (comp->useCompressedPointers())1477node->setStoreAlreadyEvaluated(true);14781479return NULL;1480}14811482TR::Register *iGenerateSoftwareReadBarrier(TR::Node *node, TR::CodeGenerator *cg)1483{1484#ifndef OMR_GC_CONCURRENT_SCAVENGER1485TR_ASSERT_FATAL(false, "Concurrent Scavenger not supported.");1486#else1487TR::Compilation *comp = cg->comp();14881489TR::Register *objReg = cg->allocateRegister();1490TR::Register *locationReg = cg->allocateRegister();1491TR::Register *evacuateReg = cg->allocateRegister();1492TR::Register *r3Reg = cg->allocateRegister();1493TR::Register *r11Reg = cg->allocateRegister();1494TR::Register *metaReg = cg->getMethodMetaDataRegister();1495TR::Register *condReg = cg->allocateRegister(TR_CCR);14961497TR::LabelSymbol *startLabel = generateLabelSymbol(cg);1498TR::LabelSymbol *endLabel = generateLabelSymbol(cg);1499startLabel->setStartInternalControlFlow();1500endLabel->setEndInternalControlFlow();15011502TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 7, cg->trMemory());1503deps->addPostCondition(objReg, TR::RealRegister::NoReg);1504deps->addPostCondition(locationReg, TR::RealRegister::gr4); //TR_softwareReadBarrier helper needs this in gr4.1505deps->addPostCondition(evacuateReg, TR::RealRegister::NoReg);1506deps->addPostCondition(r3Reg, TR::RealRegister::gr3);1507deps->addPostCondition(r11Reg, TR::RealRegister::gr11);1508deps->addPostCondition(metaReg, TR::RealRegister::NoReg);1509deps->addPostCondition(condReg, TR::RealRegister::NoReg);15101511if (node->getSymbolReference()->getSymbol()->isInternalPointer())1512{1513objReg->setPinningArrayPointer(node->getSymbolReference()->getSymbol()->castToInternalPointerAutoSymbol()->getPinningArrayPointer());1514objReg->setContainsInternalPointer();1515}15161517node->setRegister(objReg);15181519TR::LoadStoreHandler::generateComputeAddressSequence(cg, locationReg, node);15201521generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, objReg, TR::MemoryReference::createWithDisplacement(cg, locationReg, 0, 4));15221523generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);1524generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, evacuateReg,1525TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateBaseAddressOffset(), 4));1526generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, condReg, objReg, evacuateReg);1527generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, endLabel, condReg);15281529generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, evacuateReg,1530TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateTopAddressOffset(), 4));1531generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, condReg, objReg, evacuateReg);1532generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, endLabel, condReg);15331534// TR_softwareReadBarrier helper expects the vmThread in r3.1535generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r3Reg, metaReg);15361537TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(TR_softwareReadBarrier);1538generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), deps, helperSym);15391540generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, objReg, TR::MemoryReference::createWithDisplacement(cg, locationReg, 0, 4));15411542generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);15431544// TODO: Allow this to be patched or skipped at runtime for unresolved symrefs1545if (node->getSymbol()->isSyncVolatile() && comp->target().isSMP())1546{1547generateInstruction(cg, comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P7) ? TR::InstOpCode::lwsync : TR::InstOpCode::isync, node);1548}15491550cg->insertPrefetchIfNecessary(node, objReg);15511552cg->stopUsingRegister(evacuateReg);1553cg->stopUsingRegister(locationReg);1554cg->stopUsingRegister(r3Reg);1555cg->stopUsingRegister(r11Reg);1556cg->stopUsingRegister(condReg);15571558cg->machine()->setLinkRegisterKilled(true);15591560return objReg;1561#endif1562}15631564TR::Register *aGenerateSoftwareReadBarrier(TR::Node *node, TR::CodeGenerator *cg)1565{1566#ifndef OMR_GC_CONCURRENT_SCAVENGER1567TR_ASSERT_FATAL(false, "Concurrent Scavenger not supported.");1568#else1569TR::Compilation *comp = cg->comp();15701571TR::Register *tempReg;1572TR::Register *locationReg = cg->allocateRegister();1573TR::Register *evacuateReg = cg->allocateRegister();1574TR::Register *r3Reg = cg->allocateRegister();1575TR::Register *r11Reg = cg->allocateRegister();1576TR::Register *metaReg = cg->getMethodMetaDataRegister();1577TR::Register *condReg = cg->allocateRegister(TR_CCR);15781579if (!node->getSymbolReference()->getSymbol()->isInternalPointer())1580{1581if (node->getSymbolReference()->getSymbol()->isNotCollected())1582tempReg = cg->allocateRegister();1583else1584tempReg = cg->allocateCollectedReferenceRegister();1585}1586else1587{1588tempReg = cg->allocateRegister();1589tempReg->setPinningArrayPointer(node->getSymbolReference()->getSymbol()->castToInternalPointerAutoSymbol()->getPinningArrayPointer());1590tempReg->setContainsInternalPointer();1591}15921593TR::LabelSymbol *startLabel = generateLabelSymbol(cg);1594TR::LabelSymbol *endLabel = generateLabelSymbol(cg);1595startLabel->setStartInternalControlFlow();1596endLabel->setEndInternalControlFlow();15971598TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 7, cg->trMemory());1599deps->addPostCondition(tempReg, TR::RealRegister::NoReg);1600deps->addPostCondition(locationReg, TR::RealRegister::gr4); //TR_softwareReadBarrier helper needs this in gr4.1601deps->addPostCondition(evacuateReg, TR::RealRegister::NoReg);1602deps->addPostCondition(r3Reg, TR::RealRegister::gr3);1603deps->addPostCondition(r11Reg, TR::RealRegister::gr11);1604deps->addPostCondition(metaReg, TR::RealRegister::NoReg);1605deps->addPostCondition(condReg, TR::RealRegister::NoReg);16061607node->setRegister(tempReg);16081609TR::LoadStoreHandler::generateComputeAddressSequence(cg, locationReg, node);16101611generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, tempReg, TR::MemoryReference::createWithDisplacement(cg, locationReg, 0, TR::Compiler->om.sizeofReferenceAddress()));16121613if (node->getSymbolReference() == comp->getSymRefTab()->findVftSymbolRef())1614TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, tempReg);16151616generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);16171618generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, evacuateReg,1619TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateBaseAddressOffset(), TR::Compiler->om.sizeofReferenceAddress()));1620generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, condReg, tempReg, evacuateReg);1621generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, endLabel, condReg);16221623generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, evacuateReg,1624TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateTopAddressOffset(), TR::Compiler->om.sizeofReferenceAddress()));1625generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, condReg, tempReg, evacuateReg);1626generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, endLabel, condReg);16271628// TR_softwareReadBarrier helper expects the vmThread in r3.1629generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r3Reg, metaReg);16301631TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(TR_softwareReadBarrier);1632generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), deps, helperSym);16331634generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, tempReg, TR::MemoryReference::createWithDisplacement(cg, locationReg, 0, TR::Compiler->om.sizeofReferenceAddress()));16351636if (node->getSymbolReference() == comp->getSymRefTab()->findVftSymbolRef())1637TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, tempReg);16381639generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);16401641// TODO: Allow this to be patched or skipped at runtime for unresolved symrefs1642if (node->getSymbol()->isSyncVolatile() && comp->target().isSMP())1643{1644generateInstruction(cg, comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P7) ? TR::InstOpCode::lwsync : TR::InstOpCode::isync, node);1645}16461647cg->stopUsingRegister(evacuateReg);1648cg->stopUsingRegister(locationReg);1649cg->stopUsingRegister(r3Reg);1650cg->stopUsingRegister(r11Reg);1651cg->stopUsingRegister(condReg);16521653cg->machine()->setLinkRegisterKilled(true);16541655return tempReg;1656#endif1657}16581659TR::Register *J9::Power::TreeEvaluator::fwrtbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)1660{1661// For rdbar and wrtbar nodes we first evaluate the children we need to1662// handle the side effects. Then we delegate the evaluation of the remaining1663// children and the load/store operation to the appropriate load/store evaluator.1664TR::Node *sideEffectNode = node->getSecondChild();1665TR::Register *valueReg = cg->evaluate(node->getFirstChild());1666TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);1667if (cg->comp()->getOption(TR_EnableFieldWatch))1668{1669TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);1670}1671// The Value Node, or the second child is not decremented here. The store evaluator also uses it, and decrements it.1672cg->decReferenceCount(sideEffectNode);1673return TR::TreeEvaluator::fstoreEvaluator(node, cg);1674}16751676TR::Register *J9::Power::TreeEvaluator::fwrtbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)1677{1678// For rdbar and wrtbar nodes we first evaluate the children we need to1679// handle the side effects. Then we delegate the evaluation of the remaining1680// children and the load/store operation to the appropriate load/store evaluator.1681TR::Node *sideEffectNode = node->getThirdChild();1682TR::Register *valueReg = cg->evaluate(node->getSecondChild());1683TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);1684if (cg->comp()->getOption(TR_EnableFieldWatch))1685{1686TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);1687}1688// The Value Node, or the second child is not decremented here. The store evaluator also uses it, and decrements it.1689cg->decReferenceCount(sideEffectNode);1690return TR::TreeEvaluator::fstoreEvaluator(node, cg);1691}16921693TR::Register *J9::Power::TreeEvaluator::dwrtbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)1694{1695// For rdbar and wrtbar nodes we first evaluate the children we need to1696// handle the side effects. Then we delegate the evaluation of the remaining1697// children and the load/store operation to the appropriate load/store evaluator.1698TR::Node *sideEffectNode = node->getSecondChild();1699TR::Register *valueReg = cg->evaluate(node->getFirstChild());1700TR::Register *sideEffectRegister = cg->evaluate(node->getSecondChild());1701if (cg->comp()->getOption(TR_EnableFieldWatch))1702{1703TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);1704}1705// The Value Node, or the second child is not decremented here. The store evaluator also uses it, and decrements it.1706cg->decReferenceCount(sideEffectNode);1707return TR::TreeEvaluator::dstoreEvaluator(node, cg);1708}17091710TR::Register *J9::Power::TreeEvaluator::dwrtbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)1711{1712// For rdbar and wrtbar nodes we first evaluate the children we need to1713// handle the side effects. Then we delegate the evaluation of the remaining1714// children and the load/store operation to the appropriate load/store evaluator.1715TR::Node *sideEffectNode = node->getThirdChild();1716TR::Register *valueReg = cg->evaluate(node->getSecondChild());1717TR::Register *sideEffectRegister = cg->evaluate(node->getThirdChild());1718if (cg->comp()->getOption(TR_EnableFieldWatch))1719{1720TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);1721}1722// The Value Node, or the second child is not decremented here. The store evaluator also uses it, and decrements it.1723cg->decReferenceCount(sideEffectNode);1724return TR::TreeEvaluator::dstoreEvaluator(node, cg);1725}17261727TR::Register *J9::Power::TreeEvaluator::irdbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)1728{1729// For rdbar and wrtbar nodes we first evaluate the children we need to1730// handle the side effects. Then we delegate the evaluation of the remaining1731// children and the load/store operation to the appropriate load/store evaluator.1732TR::Node *sideEffectNode = node->getFirstChild();1733TR::Register * sideEffectRegister = cg->evaluate(sideEffectNode);1734if (cg->comp()->getOption(TR_EnableFieldWatch))1735{1736TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);1737}1738cg->decReferenceCount(sideEffectNode);1739return TR::TreeEvaluator::iloadEvaluator(node, cg);1740}17411742TR::Register *J9::Power::TreeEvaluator::irdbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)1743{1744// For rdbar and wrtbar nodes we first evaluate the children we need to1745// handle the side effects. Then we delegate the evaluation of the remaining1746// children and the load/store operation to the appropriate load/store evaluator.1747TR::Node *sideEffectNode = node->getFirstChild();1748TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);1749if (cg->comp()->getOption(TR_EnableFieldWatch))1750{1751TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);1752}17531754// Note: For indirect rdbar nodes, the first child (sideEffectNode) is also used by the1755// load evaluator. The load evaluator will also evaluate+decrement it. In order to avoid double1756// decrementing the node we skip doing it here and let the load evaluator do it.1757if (TR::Compiler->om.readBarrierType() != gc_modron_readbar_none &&1758cg->comp()->useCompressedPointers() &&1759(node->getOpCode().hasSymbolReference() &&1760node->getSymbolReference()->getSymbol()->getDataType() == TR::Address))1761{1762return iGenerateSoftwareReadBarrier(node, cg);1763}1764else1765return TR::TreeEvaluator::iloadEvaluator(node, cg);1766}17671768TR::Register *J9::Power::TreeEvaluator::ardbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)1769{1770// For rdbar and wrtbar nodes we first evaluate the children we need to1771// handle the side effects. Then we delegate the evaluation of the remaining1772// children and the load/store operation to the appropriate load/store evaluator.1773TR::Node *sideEffectNode = node->getFirstChild();1774TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);1775if (cg->comp()->getOption(TR_EnableFieldWatch))1776{1777TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);1778}1779cg->decReferenceCount(sideEffectNode);1780return TR::TreeEvaluator::aloadEvaluator(node, cg);1781}17821783TR::Register *J9::Power::TreeEvaluator::ardbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)1784{1785// For rdbar and wrtbar nodes we first evaluate the children we need to1786// handle the side effects. Then we delegate the evaluation of the remaining1787// children and the load/store operation to the appropriate load/store evaluator.1788TR::Register *sideEffectRegister = cg->evaluate(node->getFirstChild());1789if (cg->comp()->getOption(TR_EnableFieldWatch))1790{1791TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);1792}1793// Note: For indirect rdbar nodes, the first child (sideEffectNode) is also used by the1794// load evaluator. The load evaluator will also evaluate+decrement it. In order to avoid double1795// decrementing the node we skip doing it here and let the load evaluator do it.1796if (TR::Compiler->om.readBarrierType() == gc_modron_readbar_none)1797return TR::TreeEvaluator::aloadEvaluator(node, cg);1798else1799return aGenerateSoftwareReadBarrier(node, cg);1800}18011802TR::Register *J9::Power::TreeEvaluator::monentEvaluator(TR::Node *node, TR::CodeGenerator *cg)1803{1804return TR::TreeEvaluator::VMmonentEvaluator(node, cg);1805}18061807TR::Register *J9::Power::TreeEvaluator::monexitEvaluator(TR::Node *node, TR::CodeGenerator *cg)1808{1809return TR::TreeEvaluator::VMmonexitEvaluator(node, cg);1810}18111812TR::Register *J9::Power::TreeEvaluator::asynccheckEvaluator(TR::Node *node, TR::CodeGenerator *cg)1813{1814// The child contains an inline test. If it succeeds, the helper is called1815// or (with TR_ASYNC_CHECK_TRAPS) trap handler is invoked.1816// The address of the helper is contained as an int in this node.1817//1818TR::Compilation *comp = cg->comp();1819TR::Node *testNode = node->getFirstChild();1820TR::Node *firstChild = testNode->getFirstChild();1821TR::Register *src1Reg = cg->evaluate(firstChild);1822TR::Node *secondChild = testNode->getSecondChild();18231824TR_ASSERT(testNode->getOpCodeValue() == (comp->target().is64Bit() ? TR::lcmpeq : TR::icmpeq), "asynccheck bad format");1825TR_ASSERT(secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL, "asynccheck bad format");18261827TR::Instruction *gcPoint;18281829#if defined(TR_ASYNC_CHECK_TRAPS)1830if (cg->getHasResumableTrapHandler())1831{1832if (comp->target().is64Bit())1833{1834TR_ASSERT(secondChild->getLongInt() == -1L, "asynccheck bad format");1835gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::tdeqi, node, src1Reg, secondChild->getLongInt());1836}1837else1838{1839TR_ASSERT(secondChild->getInt() == -1, "asynccheck bad format");1840gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::tweqi, node, src1Reg, secondChild->getInt());1841}1842cg->setCanExceptByTrap();1843}1844else1845#endif1846{1847TR::Register *condReg = cg->allocateRegister(TR_CCR);1848if (comp->target().is64Bit())1849{1850TR_ASSERT(secondChild->getLongInt() == -1L, "asynccheck bad format");1851generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi8, node, condReg, src1Reg, secondChild->getLongInt());1852}1853else1854{1855TR_ASSERT(secondChild->getInt() == -1, "asynccheck bad format");1856generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, src1Reg, secondChild->getInt());1857}18581859TR::LabelSymbol *snippetLabel;1860TR::Register *jumpRegister = cg->allocateRegister();1861TR::RegisterDependencyConditions *dependencies = createConditionsAndPopulateVSXDeps(cg, 2);18621863snippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());1864if (snippetLabel == NULL)1865{1866snippetLabel = generateLabelSymbol(cg);1867cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference()));1868}1869TR::addDependency(dependencies, jumpRegister, TR::RealRegister::gr11, TR_GPR, cg);1870TR::addDependency(dependencies, condReg, TR::RealRegister::cr7, TR_CCR, cg);1871gcPoint = generateDepConditionalBranchInstruction(cg, TR::InstOpCode::beql, PPCOpProp_BranchUnlikely, node, snippetLabel, condReg, dependencies);1872gcPoint->setAsyncBranch();1873cg->machine()->setLinkRegisterKilled(true);18741875dependencies->stopUsingDepRegs(cg);1876}18771878gcPoint->PPCNeedsGCMap(0xFFFFFFFF);1879cg->decReferenceCount(firstChild);1880cg->decReferenceCount(secondChild);1881cg->decReferenceCount(testNode);1882return NULL;1883}18841885TR::Register *J9::Power::TreeEvaluator::instanceofEvaluator(TR::Node *node, TR::CodeGenerator *cg)1886{1887return VMinstanceOfEvaluator(node, cg);1888}18891890TR::Register *J9::Power::TreeEvaluator::checkcastEvaluator(TR::Node *node, TR::CodeGenerator *cg)1891{1892return TR::TreeEvaluator::VMcheckcastEvaluator(node, cg);1893}18941895TR::Register *J9::Power::TreeEvaluator::checkcastAndNULLCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)1896{1897return checkcastEvaluator(node, cg);1898}18991900TR::Register *J9::Power::TreeEvaluator::newObjectEvaluator(TR::Node *node, TR::CodeGenerator *cg)1901{1902TR::Compilation* comp = cg->comp();1903if (comp->suppressAllocationInlining() ||1904TR::TreeEvaluator::requireHelperCallValueTypeAllocation(node, cg))1905{1906TR::ILOpCodes opCode = node->getOpCodeValue();1907TR::Node::recreate(node, TR::acall);1908TR::Register *targetRegister = directCallEvaluator(node, cg);1909TR::Node::recreate(node, opCode);1910return targetRegister;1911}1912else1913return TR::TreeEvaluator::VMnewEvaluator(node, cg);1914}19151916TR::Register *J9::Power::TreeEvaluator::newArrayEvaluator(TR::Node *node, TR::CodeGenerator *cg)1917{1918if (cg->comp()->suppressAllocationInlining())1919{1920TR::ILOpCodes opCode = node->getOpCodeValue();1921TR::Node::recreate(node, TR::acall);1922TR::Register *targetRegister = directCallEvaluator(node, cg);1923TR::Node::recreate(node, opCode);1924return targetRegister;1925}1926else1927return TR::TreeEvaluator::VMnewEvaluator(node, cg);1928}19291930TR::Register *J9::Power::TreeEvaluator::anewArrayEvaluator(TR::Node *node, TR::CodeGenerator *cg)1931{1932if (cg->comp()->suppressAllocationInlining())1933{1934TR::ILOpCodes opCode = node->getOpCodeValue();1935TR::Node::recreate(node, TR::acall);1936TR::Register *targetRegister = directCallEvaluator(node, cg);1937TR::Node::recreate(node, opCode);1938return targetRegister;1939}1940else1941return TR::TreeEvaluator::VMnewEvaluator(node, cg);1942}19431944TR::Register *J9::Power::TreeEvaluator::multianewArrayEvaluator(TR::Node *node, TR::CodeGenerator *cg)1945{1946TR::ILOpCodes opCode = node->getOpCodeValue();1947TR::Node::recreate(node, TR::acall);1948TR::Register *targetRegister = directCallEvaluator(node, cg);1949TR::Node::recreate(node, opCode);1950return targetRegister;1951}19521953TR::Register *J9::Power::TreeEvaluator::arraylengthEvaluator(TR::Node *node, TR::CodeGenerator *cg)1954{1955TR_ASSERT(cg->comp()->requiresSpineChecks(), "TR::arraylength should be lowered when hybrid arraylets are not in use");1956TR_ASSERT(node->getOpCodeValue() == TR::arraylength, "arraylengthEvaluator expecting TR::arraylength");19571958TR::Register *objectReg = cg->evaluate(node->getFirstChild());1959TR::Register *lengthReg = cg->allocateRegister();1960TR::Register *condReg = cg->allocateRegister(TR_CCR);1961TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);1962TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());19631964TR::MemoryReference *contiguousArraySizeMR = TR::MemoryReference::createWithDisplacement(cg, objectReg, fej9->getOffsetOfContiguousArraySizeField(), 4);1965TR::MemoryReference *discontiguousArraySizeMR = TR::MemoryReference::createWithDisplacement(cg, objectReg, fej9->getOffsetOfDiscontiguousArraySizeField(), 4);19661967TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 3, cg->trMemory());1968deps->addPostCondition(objectReg, TR::RealRegister::NoReg);1969deps->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();1970deps->addPostCondition(lengthReg, TR::RealRegister::NoReg);1971deps->addPostCondition(condReg, TR::RealRegister::NoReg);19721973// lwz R, [B + contiguousSize] ; Load contiguous array length1974// cmp R, 0 ; If 0, must be a discontiguous array1975// beq out-of-line1976// done:1977//1978// out-of-line:1979// lwz R, [B + discontiguousSize] ; Load discontiguous array length1980// b done19811982TR::LabelSymbol *discontiguousArrayLabel = generateLabelSymbol(cg);1983TR_PPCOutOfLineCodeSection *discontiguousArrayOOL = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(discontiguousArrayLabel, doneLabel, cg);1984cg->getPPCOutOfLineCodeSectionList().push_front(discontiguousArrayOOL);19851986generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, lengthReg, contiguousArraySizeMR);1987generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, lengthReg, 0);1988generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, PPCOpProp_BranchUnlikely, node, discontiguousArrayLabel, condReg);1989generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);19901991// OOL begin.1992//1993discontiguousArrayOOL->swapInstructionListsWithCompilation();1994{1995generateLabelInstruction(cg, TR::InstOpCode::label, node, discontiguousArrayLabel);1996generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, lengthReg, discontiguousArraySizeMR);1997generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);1998}1999discontiguousArrayOOL->swapInstructionListsWithCompilation();2000//2001// OOL end.20022003TR::LabelSymbol *depLabel = generateLabelSymbol(cg);2004generateDepLabelInstruction(cg, TR::InstOpCode::label, node, depLabel, deps);20052006cg->stopUsingRegister(condReg);2007cg->decReferenceCount(node->getFirstChild());2008node->setRegister(lengthReg);20092010return lengthReg;2011}20122013TR::Register *J9::Power::TreeEvaluator::DIVCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)2014{2015TR::Compilation *comp = cg->comp();2016TR::Node *secondChild = node->getFirstChild()->getSecondChild();2017TR::DataType type = secondChild->getType();2018TR::Register *srcReg;2019TR::Instruction *gcPoint;2020bool constDivisor = secondChild->getOpCode().isLoadConst();2021bool killSrc = false;20222023if (!constDivisor || (type.isInt32() && secondChild->getInt() == 0) || (type.isInt64() && secondChild->getLongInt() == 0))2024{2025if (!constDivisor || cg->getHasResumableTrapHandler())2026{2027srcReg = cg->evaluate(secondChild);2028if (type.isInt64() && comp->target().is32Bit())2029{2030TR::Register *trgReg = cg->allocateRegister();2031generateTrg1Src2Instruction(cg, TR::InstOpCode::OR, node, trgReg, srcReg->getHighOrder(), srcReg->getLowOrder());2032srcReg = trgReg;2033killSrc = true;2034}2035}20362037if (cg->getHasResumableTrapHandler())2038{2039if (type.isInt64() && comp->target().is64Bit())2040gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::tdllti, node, srcReg, 1);2041else2042gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twllti, node, srcReg, 1);2043cg->setCanExceptByTrap();2044}2045else2046{2047TR::LabelSymbol *snippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());2048TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg->trMemory());2049TR::Register *jumpReg = cg->allocateRegister();20502051if (snippetLabel == NULL)2052{2053snippetLabel = generateLabelSymbol(cg);2054cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference()));2055}20562057// trampoline kills gr112058TR::addDependency(conditions, jumpReg, TR::RealRegister::gr11, TR_GPR, cg);2059if (constDivisor)2060{2061// Can be improved to: call the helper directly.2062gcPoint = generateDepLabelInstruction(cg, TR::InstOpCode::bl, node, snippetLabel, conditions);2063}2064else2065{2066TR::Register *condReg = cg->allocateRegister(TR_CCR);2067if (type.isInt64() && comp->target().is64Bit())2068generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli8, node, condReg, srcReg, 0);2069else2070generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, srcReg, 0);2071gcPoint = generateDepConditionalBranchInstruction(cg, TR::InstOpCode::beql, PPCOpProp_BranchUnlikely, node, snippetLabel, condReg, conditions);2072cg->stopUsingRegister(condReg);2073}2074cg->stopUsingRegister(jumpReg);2075}20762077if (killSrc)2078cg->stopUsingRegister(srcReg);20792080gcPoint->PPCNeedsGCMap(0xFFFFFFFF);2081}20822083cg->evaluate(node->getFirstChild());2084cg->decReferenceCount(node->getFirstChild());2085return NULL;2086}20872088static void genBoundCheck(TR::CodeGenerator *cg, TR::Node *node, TR::Register *indexReg, int32_t indexVal, TR::Register *arrayLengthReg, int32_t arrayLengthVal,2089TR::Register *condReg, bool noTrap)2090{2091TR::Instruction *gcPoint;2092if (noTrap)2093{2094TR::LabelSymbol *boundCheckFailSnippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());2095if (!boundCheckFailSnippetLabel)2096{2097boundCheckFailSnippetLabel = generateLabelSymbol(cg);2098cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, boundCheckFailSnippetLabel, node->getSymbolReference()));2099}21002101if (indexReg)2102generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, condReg, arrayLengthReg, indexReg);2103else2104generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, arrayLengthReg, indexVal);21052106// NOTE: Trampoline kills gr112107gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::blel, PPCOpProp_BranchUnlikely, node, boundCheckFailSnippetLabel, condReg);2108}2109else2110{2111if (indexReg)2112{2113if (arrayLengthReg)2114gcPoint = generateSrc2Instruction(cg, TR::InstOpCode::twlle, node, arrayLengthReg, indexReg);2115else2116gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twlgei, node, indexReg, arrayLengthVal);2117}2118else2119{2120if (arrayLengthReg)2121gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twllei, node, arrayLengthReg, indexVal);2122else if (arrayLengthVal <= indexVal)2123gcPoint = generateInstruction(cg, TR::InstOpCode::trap, node);2124}21252126cg->setCanExceptByTrap();2127}21282129// Exception edges don't have any live regs2130gcPoint->PPCNeedsGCMap(0);2131}21322133TR::Register *J9::Power::TreeEvaluator::BNDCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)2134{2135static bool noReversedTrap = (feGetEnv("TR_noReversedTrap") != NULL);2136TR::Node *secondChild = node->getSecondChild();2137TR::Node *firstChild = node->getFirstChild();2138TR::Register *src1Reg;2139TR::Register *src2Reg = NULL;2140TR::Register *cndReg, *tmpReg = NULL;2141int32_t value;2142TR::RegisterDependencyConditions *conditions;2143TR::LabelSymbol *snippetLabel;2144TR::Instruction *gcPoint;2145bool noTrap = !cg->getHasResumableTrapHandler();2146bool reversed = false;21472148if (noTrap)2149{2150cndReg = cg->allocateRegister(TR_CCR);2151conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());2152}21532154if (firstChild->getOpCode().isLoadConst() && firstChild->getInt() >= 0 && firstChild->getInt() <= UPPER_IMMED && firstChild->getRegister() == NULL && !noReversedTrap)2155{2156src2Reg = cg->evaluate(secondChild);2157reversed = true;2158}2159else2160{2161src1Reg = cg->evaluate(firstChild);21622163if (secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL)2164{2165value = secondChild->getInt();2166if (value < 0 || value > UPPER_IMMED)2167{2168src2Reg = cg->evaluate(secondChild);2169}2170}2171else2172src2Reg = cg->evaluate(secondChild);2173}21742175if (!noTrap)2176{2177if (reversed)2178{2179gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twlgei, node, src2Reg, firstChild->getInt());2180}2181else2182{2183if (src2Reg == NULL)2184gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twllei, node, src1Reg, value);2185else2186gcPoint = generateSrc2Instruction(cg, TR::InstOpCode::twlle, node, src1Reg, src2Reg);2187}2188}2189else2190{2191if (reversed)2192{2193generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, cndReg, src2Reg, firstChild->getInt());2194}2195else2196{2197if (src2Reg == NULL)2198generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, cndReg, src1Reg, value);2199else2200generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, cndReg, src1Reg, src2Reg);2201}22022203snippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());2204if (snippetLabel == NULL)2205{2206snippetLabel = generateLabelSymbol(cg);2207cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference()));2208}22092210tmpReg = cg->allocateRegister();2211// trampoline kills gr112212TR::addDependency(conditions, tmpReg, TR::RealRegister::gr11, TR_GPR, cg);2213gcPoint = generateDepConditionalBranchInstruction(cg, reversed ? TR::InstOpCode::bgel : TR::InstOpCode::blel, PPCOpProp_BranchUnlikely, node, snippetLabel, cndReg, conditions);2214cg->stopUsingRegister(tmpReg);2215}22162217if (noTrap)2218cg->stopUsingRegister(cndReg);22192220gcPoint->PPCNeedsGCMap(0xFFFFFFFF);2221if (!noTrap)2222cg->setCanExceptByTrap();2223cg->decReferenceCount(firstChild);2224cg->decReferenceCount(secondChild);2225secondChild->setIsNonNegative(true);2226return (NULL);2227}22282229TR::Register *J9::Power::TreeEvaluator::ArrayCopyBNDCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)2230{2231TR::Node *firstChild = node->getFirstChild();2232TR::Node *secondChild = node->getSecondChild();2233TR::LabelSymbol *snippetLabel = NULL;2234TR::Instruction *gcPoint;2235bool noTrap = !cg->getHasResumableTrapHandler();2236bool directCase = firstChild->getOpCode().isLoadConst() && secondChild->getOpCode().isLoadConst() && firstChild->getInt() < secondChild->getInt();22372238if (directCase || noTrap)2239{2240snippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());2241if (snippetLabel == NULL)2242{2243snippetLabel = generateLabelSymbol(cg);2244cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference()));2245}2246}22472248// We are checking for firstChild>=secondChild. We don't need to copy registers.22492250if (directCase)2251{2252gcPoint = generateLabelInstruction(cg, TR::InstOpCode::bl, node, snippetLabel);2253}2254else if (firstChild->getOpCode().isLoadConst() && firstChild->getInt() >= LOWER_IMMED && firstChild->getInt() <= UPPER_IMMED && firstChild->getRegister() == NULL)2255{2256TR::Register *copyIndexReg = cg->evaluate(secondChild);2257if (noTrap)2258{2259TR::Register *cndReg = cg->allocateRegister(TR_CCR);2260generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cndReg, copyIndexReg, firstChild->getInt());2261gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgtl, PPCOpProp_BranchUnlikely, node, snippetLabel, cndReg);2262cg->stopUsingRegister(cndReg);2263}2264else2265{2266gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twgti, node, copyIndexReg, firstChild->getInt());2267cg->setCanExceptByTrap();2268}2269}2270else2271{2272TR::Register *boundReg = cg->evaluate(firstChild);2273if (secondChild->getOpCode().isLoadConst() && secondChild->getInt() >= LOWER_IMMED && secondChild->getInt() <= UPPER_IMMED)2274{2275if (noTrap)2276{2277TR::Register *cndReg = cg->allocateRegister(TR_CCR);2278generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cndReg, boundReg, secondChild->getInt());2279gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bltl, PPCOpProp_BranchUnlikely, node, snippetLabel, cndReg);2280cg->stopUsingRegister(cndReg);2281}2282else2283{2284gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twlti, node, boundReg, secondChild->getInt());2285cg->setCanExceptByTrap();2286}2287}2288else2289{2290TR::Register *copyIndexReg = cg->evaluate(secondChild);2291if (noTrap)2292{2293TR::Register *cndReg = cg->allocateRegister(TR_CCR);2294generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cndReg, boundReg, copyIndexReg);2295gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bltl, PPCOpProp_BranchUnlikely, node, snippetLabel, cndReg);2296cg->stopUsingRegister(cndReg);2297}2298else2299{2300gcPoint = generateSrc2Instruction(cg, TR::InstOpCode::twlt, node, boundReg, copyIndexReg);2301cg->setCanExceptByTrap();2302}2303}2304}23052306gcPoint->PPCNeedsGCMap(0xFFFFFFFF);2307cg->decReferenceCount(firstChild);2308cg->decReferenceCount(secondChild);2309if (secondChild->getOpCode().isLoadConst() && secondChild->getInt() >= 0)2310firstChild->setIsNonNegative(true);2311return (NULL);2312}23132314static TR::Instruction* genSpineCheck(TR::CodeGenerator *cg, TR::Node *node, TR::Register *arrayLengthReg, TR::Register *condReg, TR::LabelSymbol *discontiguousArrayLabel)2315{2316generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, arrayLengthReg, 0);2317return generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, discontiguousArrayLabel, condReg);2318}23192320static TR::Instruction* genSpineCheck(TR::CodeGenerator *cg, TR::Node *node, TR::Register *baseArrayReg, TR::Register *arrayLengthReg, TR::Register *condReg,2321TR::LabelSymbol *discontiguousArrayLabel)2322{2323TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());2324TR::MemoryReference *contiguousArraySizeMR = TR::MemoryReference::createWithDisplacement(cg, baseArrayReg, fej9->getOffsetOfContiguousArraySizeField(), 4);2325generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, arrayLengthReg, contiguousArraySizeMR);2326return genSpineCheck(cg, node, arrayLengthReg, condReg, discontiguousArrayLabel);2327}23282329static void genArrayletAccessAddr(TR::CodeGenerator *cg, TR::Node *node, int32_t elementSize,2330// Inputs:2331TR::Register *baseArrayReg, TR::Register *indexReg, int32_t indexVal,2332// Outputs:2333TR::Register *arrayletReg, TR::Register *offsetReg, int32_t& offsetVal)2334{2335TR::Compilation* comp = cg->comp();2336TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());2337TR_ASSERT(offsetReg || !indexReg, "Expecting valid offset reg when index reg is passed");23382339uintptr_t arrayHeaderSize = TR::Compiler->om.discontiguousArrayHeaderSizeInBytes();2340int32_t spinePointerSize = TR::Compiler->om.sizeofReferenceField();2341int32_t spinePointerSizeShift = spinePointerSize == 8 ? 3 : 2;23422343TR::MemoryReference *spineMR;23442345// Calculate the spine offset.2346//2347if (indexReg)2348{2349int32_t spineShift = fej9->getArraySpineShift(elementSize);23502351// spineOffset = (index >> spineShift) * spinePtrSize2352// = (index >> spineShift) << spinePtrSizeShift2353// = (index >> (spineShift - spinePtrSizeShift)) & ~(spinePtrSize - 1)2354// spineOffset += arrayHeaderSize2355//2356TR_ASSERT(spineShift >= spinePointerSizeShift, "Unexpected spine shift value");2357generateShiftRightLogicalImmediate(cg, node, arrayletReg, indexReg, spineShift - spinePointerSizeShift);2358generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, arrayletReg, arrayletReg, 0, ~(spinePointerSize - 1));2359generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, arrayletReg, arrayletReg, arrayHeaderSize);23602361spineMR = TR::MemoryReference::createWithIndexReg(cg, baseArrayReg, arrayletReg, spinePointerSize);2362}2363else2364{2365int32_t spineIndex = fej9->getArrayletLeafIndex(indexVal, elementSize);2366int32_t spineDisp32 = spineIndex * spinePointerSize + arrayHeaderSize;23672368spineMR = TR::MemoryReference::createWithDisplacement(cg, baseArrayReg, spineDisp32, spinePointerSize);2369}23702371// Load the arraylet from the spine.2372//2373generateTrg1MemInstruction(cg, spinePointerSize == 8 ? TR::InstOpCode::ld : TR::InstOpCode::lwz, node, arrayletReg, spineMR);23742375// Calculate the arraylet offset.2376//2377if (indexReg)2378{2379int32_t arrayletMask = fej9->getArrayletMask(elementSize);2380int32_t elementSizeShift = CHAR_BIT * sizeof(int32_t) - leadingZeroes(elementSize - 1);23812382generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, offsetReg, indexReg, elementSizeShift, arrayletMask << elementSizeShift);2383}2384else2385offsetVal = (fej9->getLeafElementIndex(indexVal, elementSize) * elementSize);2386}23872388static TR::InstOpCode::Mnemonic getLoadOrStoreFromDataType(TR::CodeGenerator *cg, TR::DataType dt, int32_t elementSize, bool isUnsigned, bool returnLoad)2389{2390switch (dt)2391{2392case TR::Int8:2393return returnLoad ? TR::InstOpCode::lbz : TR::InstOpCode::stb;2394case TR::Int16:2395if (returnLoad)2396return isUnsigned ? TR::InstOpCode::lhz : TR::InstOpCode::lha;2397else2398return TR::InstOpCode::sth;2399case TR::Int32:2400if (returnLoad)2401return TR::InstOpCode::lwz;2402else2403return TR::InstOpCode::stw;2404case TR::Int64:2405return returnLoad ? TR::InstOpCode::ld : TR::InstOpCode::std;2406case TR::Float:2407return returnLoad ? TR::InstOpCode::lfs : TR::InstOpCode::stfs;2408case TR::Double:2409return returnLoad ? TR::InstOpCode::lfd : TR::InstOpCode::stfd;2410case TR::Address:2411if (returnLoad)2412return elementSize == 8 ? TR::InstOpCode::ld : TR::InstOpCode::lwz;2413else2414return elementSize == 8 ? TR::InstOpCode::std : TR::InstOpCode::stw;2415default:2416TR_ASSERT(false, "Unexpected array data type");2417return TR::InstOpCode::bad;2418}2419}24202421static void genDecompressPointer(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *condReg = NULL, bool nullCheck = true)2422{2423TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());2424int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();24252426if (shiftAmount != 0)2427generateShiftLeftImmediateLong(cg, node, ptrReg, ptrReg, shiftAmount);2428}24292430static TR::Register *addConstantToLongWithTempReg(TR::Node * node, TR::Register *srcReg, int64_t value, TR::Register *trgReg, TR::Register *tempReg, TR::CodeGenerator *cg)2431{2432if (!trgReg)2433trgReg = cg->allocateRegister();24342435if ((int16_t) value == value)2436{2437generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, trgReg, srcReg, value);2438}2439// NOTE: the following only works if the second add's immediate is not sign extended2440else if (((int32_t) value == value) && ((value & 0x8000) == 0))2441{2442generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, trgReg, srcReg, value >> 16);2443if (value & 0xffff)2444generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, trgReg, trgReg, LO_VALUE(value));2445}2446else2447{2448loadConstant(cg, node, value, tempReg);2449generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, trgReg, srcReg, tempReg);2450}24512452return trgReg;2453}24542455static void genDecompressPointerWithTempReg(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *tempReg, TR::Register *condReg = NULL, bool nullCheck = true)2456{2457TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());2458int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();24592460if (shiftAmount != 0)2461generateShiftLeftImmediateLong(cg, node, ptrReg, ptrReg, shiftAmount);2462}24632464static TR::Register *genDecompressPointerNonNull2Regs(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *targetReg)2465{2466TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());2467int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();24682469if (shiftAmount != 0)2470{2471generateShiftLeftImmediateLong(cg, node, targetReg, ptrReg, shiftAmount);2472return targetReg;2473}2474else2475{2476return ptrReg;2477}2478}24792480static TR::Register *genDecompressPointerNonNull2RegsWithTempReg(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *targetReg, TR::Register *tempReg)2481{2482TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());2483int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();24842485if (shiftAmount != 0)2486{2487generateShiftLeftImmediateLong(cg, node, targetReg, ptrReg, shiftAmount);2488return targetReg;2489}2490else2491{2492return ptrReg;2493}2494}24952496static void genCompressPointerWithTempReg(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *tempReg, TR::Register *condReg = NULL, bool nullCheck = true)2497{2498TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());2499int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();25002501if (shiftAmount != 0)2502{2503generateShiftRightLogicalImmediateLong(cg, node, ptrReg, ptrReg, shiftAmount);2504}2505}25062507static void genCompressPointer(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *condReg = NULL, bool nullCheck = true)2508{2509TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());2510int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();25112512if (shiftAmount != 0)2513{2514generateShiftRightLogicalImmediateLong(cg, node, ptrReg, ptrReg, shiftAmount);2515}2516}25172518static TR::Register *genCompressPointerNonNull2RegsWithTempReg(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *targetReg, TR::Register *tempReg)2519{2520TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());2521int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();25222523if (shiftAmount != 0)2524{2525generateShiftRightLogicalImmediateLong(cg, node, targetReg, ptrReg, shiftAmount);2526return targetReg;2527}2528else2529return ptrReg;2530}25312532static TR::Register *genCompressPointerNonNull2Regs(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *targetReg)2533{2534TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());2535int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();25362537if (shiftAmount != 0)2538{2539generateShiftRightLogicalImmediateLong(cg, node, targetReg, ptrReg, shiftAmount);2540return targetReg;2541}2542else2543return ptrReg;2544}25452546// Handles both BNDCHKwithSpineCHK and SpineCHK nodes.2547//2548TR::Register *J9::Power::TreeEvaluator::BNDCHKwithSpineCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)2549{2550TR::Compilation *comp = cg->comp();2551TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());2552bool noTrap = !cg->getHasResumableTrapHandler();2553bool needsBoundCheck = node->getOpCodeValue() == TR::BNDCHKwithSpineCHK;2554bool needsBoundCheckOOL;25552556TR_PPCScratchRegisterManager *srm = cg->generateScratchRegisterManager();25572558TR::Node *loadOrStoreChild = node->getFirstChild();2559TR::Node *baseArrayChild = node->getSecondChild();2560TR::Node *arrayLengthChild;2561TR::Node *indexChild;25622563if (needsBoundCheck)2564{2565arrayLengthChild = node->getChild(2);2566indexChild = node->getChild(3);2567}2568else2569indexChild = node->getChild(2);25702571TR::Register *baseArrayReg = cg->evaluate(baseArrayChild);2572TR::Register *indexReg;2573TR::Register *loadOrStoreReg;2574TR::Register *arrayLengthReg;25752576// If the index is too large to be an immediate load it in a register2577if (!indexChild->getOpCode().isLoadConst() || (indexChild->getInt() > UPPER_IMMED || indexChild->getInt() < 0))2578indexReg = cg->evaluate(indexChild);2579else2580indexReg = NULL;25812582// For primitive stores anchored under the check node, we must evaluate the source node2583// before the bound check branch so that its available to the snippet.2584//2585if (loadOrStoreChild->getOpCode().isStore() && !loadOrStoreChild->getRegister())2586{2587TR::Node *valueChild = loadOrStoreChild->getSecondChild();2588cg->evaluate(valueChild);2589}25902591// Evaluate any escaping nodes before the OOL branch since they won't be evaluated in the OOL path.2592preEvaluateEscapingNodesForSpineCheck(node, cg);25932594// Label to the OOL code that will perform the load/store/agen for discontiguous arrays (and the bound check if needed).2595TR::LabelSymbol *discontiguousArrayLabel = generateLabelSymbol(cg);25962597// Label back to main-line that the OOL code will branch to when done.2598TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);2599doneLabel->setEndInternalControlFlow();26002601TR_PPCOutOfLineCodeSection *discontiguousArrayOOL = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(discontiguousArrayLabel, doneLabel, cg);2602cg->getPPCOutOfLineCodeSectionList().push_front(discontiguousArrayOOL);26032604TR::Instruction *OOLBranchInstr;26052606if (needsBoundCheck)2607{2608TR_ASSERT(arrayLengthChild, "Expecting to have an array length child for BNDCHKwithSpineCHK node");2609TR_ASSERT(2610arrayLengthChild->getOpCode().isConversion() || arrayLengthChild->getOpCodeValue() == TR::iloadi || arrayLengthChild->getOpCodeValue() == TR::iload2611|| arrayLengthChild->getOpCodeValue() == TR::iRegLoad || arrayLengthChild->getOpCode().isLoadConst(),2612"Expecting array length child under BNDCHKwithSpineCHK to be a conversion, iiload, iload, iRegLoad or iconst");26132614TR::Register *condReg = srm->findOrCreateScratchRegister(TR_CCR);26152616arrayLengthReg = arrayLengthChild->getRegister();26172618if (arrayLengthReg)2619{2620OOLBranchInstr = genSpineCheck(cg, node, baseArrayReg, arrayLengthReg, condReg, discontiguousArrayLabel);2621needsBoundCheckOOL = true;2622genBoundCheck(cg, node, indexReg, indexChild->getInt(), arrayLengthReg, arrayLengthChild->getInt(), condReg, noTrap);2623}2624else if (arrayLengthChild->getOpCode().isLoadConst())2625{2626// If the constant arraylength is non-zero then it will pass the spine check (hence its2627// a contiguous array) and the BNDCHK can be done inline with no OOL path.2628//2629// If the constant arraylength is zero then we will always go OOL.2630//2631// TODO: in the future there shouldn't be an OOL path because any valid access must be2632// on a discontiguous array.2633//2634if (arrayLengthChild->getInt() != 0)2635{2636// The array must be contiguous.2637//26382639// If the array length is too large to be an immediate load it in a register for the bound check2640if (arrayLengthChild->getInt() > UPPER_IMMED || arrayLengthChild->getInt() < 0)2641arrayLengthReg = cg->evaluate(arrayLengthChild);26422643// Do the bound check first.2644genBoundCheck(cg, node, indexReg, indexChild->getInt(), arrayLengthReg, arrayLengthChild->getInt(), condReg, noTrap);2645needsBoundCheckOOL = false;2646TR::Register *scratchArrayLengthReg = srm->findOrCreateScratchRegister();2647OOLBranchInstr = genSpineCheck(cg, node, baseArrayReg, scratchArrayLengthReg, condReg, discontiguousArrayLabel);2648srm->reclaimScratchRegister(scratchArrayLengthReg);2649}2650else2651{2652// Zero length array or discontiguous array. Unconditionally branch to the OOL path2653// to find out which.2654//2655OOLBranchInstr = generateLabelInstruction(cg, TR::InstOpCode::b, node, discontiguousArrayLabel);2656needsBoundCheckOOL = true;2657}2658}2659else2660{2661// Load the contiguous array length.2662arrayLengthReg = cg->evaluate(arrayLengthChild);2663// If the array length is 0, this is a discontiguous array and the bound check will be handled OOL.2664OOLBranchInstr = genSpineCheck(cg, node, arrayLengthReg, condReg, discontiguousArrayLabel);2665needsBoundCheckOOL = true;2666// Do the bound check using the contiguous array length.2667genBoundCheck(cg, node, indexReg, indexChild->getInt(), arrayLengthReg, arrayLengthChild->getInt(), condReg, noTrap);2668}26692670srm->reclaimScratchRegister(condReg);2671cg->decReferenceCount(arrayLengthChild);2672}2673else2674{2675// Spine check only; load the contiguous length, check for 0, branch OOL if discontiguous.2676needsBoundCheckOOL = false;26772678arrayLengthReg = srm->findOrCreateScratchRegister();26792680TR::Register *condReg = srm->findOrCreateScratchRegister(TR_CCR);26812682OOLBranchInstr = genSpineCheck(cg, node, baseArrayReg, arrayLengthReg, condReg, discontiguousArrayLabel);26832684srm->reclaimScratchRegister(arrayLengthReg);2685srm->reclaimScratchRegister(condReg);2686}26872688// For reference stores, only evaluate the array element address because the store cannot2689// happen here (it must be done via the array store check).2690//2691// For primitive stores, evaluate them now.2692// For loads, evaluate them now.2693// For address calculations (aladd/aiadd), evaluate them now.2694//2695bool doLoadOrStore;2696bool doLoadDecompress = false;2697bool doAddressComputation;26982699if (loadOrStoreChild->getOpCode().isStore() && loadOrStoreChild->getReferenceCount() > 1)2700{2701TR_ASSERT(loadOrStoreChild->getOpCode().isWrtBar(), "Opcode must be wrtbar");2702loadOrStoreReg = cg->evaluate(loadOrStoreChild->getFirstChild());2703cg->decReferenceCount(loadOrStoreChild->getFirstChild());2704doLoadOrStore = false;2705doAddressComputation = true;2706}2707else2708{2709// If it's a store and not commoned then it must be a primitive store.2710// If it's an address load it may need decompression in the OOL path.27112712// Top-level check whether a decompression sequence is necessary, because the first child2713// may have been created by a PRE temp.2714//2715if ((loadOrStoreChild->getOpCodeValue() == TR::aload || loadOrStoreChild->getOpCodeValue() == TR::aRegLoad) && node->isSpineCheckWithArrayElementChild() && comp->target().is64Bit()2716&& comp->useCompressedPointers())2717{2718doLoadDecompress = true;2719}27202721TR::Node *actualLoadOrStoreChild = loadOrStoreChild;2722while (actualLoadOrStoreChild->getOpCode().isConversion() || actualLoadOrStoreChild->containsCompressionSequence())2723{2724if (actualLoadOrStoreChild->containsCompressionSequence())2725doLoadDecompress = true;2726actualLoadOrStoreChild = actualLoadOrStoreChild->getFirstChild();2727}27282729doLoadOrStore = actualLoadOrStoreChild->getOpCode().hasSymbolReference()2730&& (actualLoadOrStoreChild->getSymbolReference()->getSymbol()->isArrayShadowSymbol()2731|| actualLoadOrStoreChild->getSymbolReference()->getSymbol()->isArrayletShadowSymbol()) && node->isSpineCheckWithArrayElementChild();27322733// If the 1st child is not a load/store/aladd/aiadd it's probably a nop (e.g. const) at this point due to commoning2734//2735doAddressComputation = !doLoadOrStore && actualLoadOrStoreChild->getOpCode().isArrayRef() && !node->isSpineCheckWithArrayElementChild();27362737if (doLoadOrStore || doAddressComputation || !loadOrStoreChild->getOpCode().isLoadConst())2738loadOrStoreReg = cg->evaluate(loadOrStoreChild);2739else2740loadOrStoreReg = NULL;2741}27422743if (noTrap)2744{2745TR::RegisterDependencyConditions *mainlineDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 1, cg->trMemory());2746// Trampoline to bound check fail kills gr112747// TODO: Try to use this as the arraylet reg2748TR::Register *gr11 = cg->allocateRegister();2749mainlineDeps->addPostCondition(gr11, TR::RealRegister::gr11);2750cg->stopUsingRegister(gr11);27512752generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);2753TR::LabelSymbol *doneMainlineLabel = generateLabelSymbol(cg);2754generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneMainlineLabel, mainlineDeps);2755}2756else2757generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);27582759// OOL begin.2760//2761discontiguousArrayOOL->swapInstructionListsWithCompilation();2762{2763TR::Instruction *OOLLabelInstr = generateLabelInstruction(cg, TR::InstOpCode::label, node, discontiguousArrayLabel);2764// XXX: Temporary fix, OOL instruction stream does not pick up live locals or monitors correctly.2765TR_ASSERT(!OOLLabelInstr->getLiveLocals() && !OOLLabelInstr->getLiveMonitors(), "Expecting first OOL instruction to not have live locals/monitors info");2766OOLLabelInstr->setLiveLocals(OOLBranchInstr->getLiveLocals());2767OOLLabelInstr->setLiveMonitors(OOLBranchInstr->getLiveMonitors());27682769if (needsBoundCheckOOL)2770{2771TR_ASSERT(needsBoundCheck, "Inconsistent state, needs bound check OOL but doesn't need bound check");27722773TR::MemoryReference *discontiguousArraySizeMR = TR::MemoryReference::createWithDisplacement(cg, baseArrayReg, fej9->getOffsetOfDiscontiguousArraySizeField(), 4);2774TR::Register *arrayLengthScratchReg = srm->findOrCreateScratchRegister();27752776generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, arrayLengthScratchReg, discontiguousArraySizeMR);27772778TR::Register *condReg = srm->findOrCreateScratchRegister(TR_CCR);27792780// Do the bound check using the discontiguous array length.2781genBoundCheck(cg, node, indexReg, indexChild->getInt(), arrayLengthScratchReg, arrayLengthChild->getInt(), condReg, noTrap);27822783srm->reclaimScratchRegister(condReg);2784srm->reclaimScratchRegister(arrayLengthScratchReg);2785}27862787TR_ASSERT(!(doLoadOrStore && doAddressComputation), "Unexpected condition");27882789TR::Register *arrayletReg;2790TR::DataType dt = loadOrStoreChild->getDataType();27912792if (doLoadOrStore || doAddressComputation)2793{2794arrayletReg = doAddressComputation ? loadOrStoreReg : /* Needs to be in !gr0 in this case */cg->allocateRegister();27952796// Generate the base+offset address pair into the arraylet.2797//2798int32_t elementSize = dt == TR::Address ? TR::Compiler->om.sizeofReferenceField() : TR::Symbol::convertTypeToSize(dt);2799TR::Register *arrayletOffsetReg;2800int32_t arrayletOffsetVal;28012802if (indexReg)2803arrayletOffsetReg = srm->findOrCreateScratchRegister();28042805genArrayletAccessAddr(cg, node, elementSize, baseArrayReg, indexReg, indexChild->getInt(), arrayletReg, arrayletOffsetReg, arrayletOffsetVal);28062807// Decompress the arraylet pointer if necessary.2808genDecompressPointer(cg, node, arrayletReg);28092810if (doLoadOrStore)2811{2812// Generate the load or store.2813//2814if (loadOrStoreChild->getOpCode().isStore())2815{2816bool isUnsigned = loadOrStoreChild->getOpCode().isUnsigned();2817TR::InstOpCode::Mnemonic storeOp = getLoadOrStoreFromDataType(cg, dt, elementSize, isUnsigned, false);28182819if (storeOp == TR::InstOpCode::std && comp->target().is32Bit())2820{2821// Store using consecutive stws.2822TR_ASSERT(elementSize == 8 && loadOrStoreChild->getSecondChild()->getRegister()->getRegisterPair(), "Expecting 64-bit store value to be in a register pair");2823if (indexReg)2824{2825TR::MemoryReference *arrayletMR = TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, 4);2826generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, arrayletMR, loadOrStoreChild->getSecondChild()->getRegister()->getHighOrder());28272828generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, arrayletOffsetReg, arrayletOffsetReg, 4);28292830TR::MemoryReference *arrayletMR2 = TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, 4);2831generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, arrayletMR2, loadOrStoreChild->getSecondChild()->getRegister()->getLowOrder());2832}2833else2834{2835TR::MemoryReference *arrayletMR = TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal, 4);2836TR::MemoryReference *arrayletMR2 = TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal + 4, 4);2837generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, arrayletMR, loadOrStoreChild->getSecondChild()->getRegister()->getHighOrder());2838generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, arrayletMR2, loadOrStoreChild->getSecondChild()->getRegister()->getLowOrder());2839}2840}2841else2842{2843TR::MemoryReference *arrayletMR =2844indexReg ? TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, elementSize) :2845TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal, elementSize);2846generateMemSrc1Instruction(cg, storeOp, node, arrayletMR, loadOrStoreChild->getSecondChild()->getRegister());2847}2848}2849else2850{2851TR_ASSERT(loadOrStoreChild->getOpCode().isConversion() || loadOrStoreChild->getOpCode().isLoad(), "Unexpected op");28522853bool isUnsigned = loadOrStoreChild->getOpCode().isUnsigned();2854TR::InstOpCode::Mnemonic loadOp = getLoadOrStoreFromDataType(cg, dt, elementSize, isUnsigned, true);28552856if (loadOp == TR::InstOpCode::ld && comp->target().is32Bit())2857{2858// Load using consecutive lwzs.2859TR_ASSERT(elementSize == 8 && loadOrStoreReg->getRegisterPair(), "Expecting 64-bit load value to be in a register pair");2860if (indexReg)2861{2862TR::MemoryReference *arrayletMR = TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, 4);2863generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, loadOrStoreReg->getHighOrder(), arrayletMR);28642865generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, arrayletOffsetReg, arrayletOffsetReg, 4);28662867TR::MemoryReference *arrayletMR2 = TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, 4);2868generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, loadOrStoreReg->getLowOrder(), arrayletMR2);2869}2870else2871{2872TR::MemoryReference *arrayletMR = TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal, 4);2873TR::MemoryReference *arrayletMR2 = TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal + 4, 4);2874generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, loadOrStoreReg->getHighOrder(), arrayletMR);2875generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, loadOrStoreReg->getLowOrder(), arrayletMR2);2876}2877}2878else2879{2880TR::MemoryReference *arrayletMR =2881indexReg ? TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, elementSize) :2882TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal, elementSize);2883generateTrg1MemInstruction(cg, loadOp, node, loadOrStoreReg, arrayletMR);2884}28852886if (doLoadDecompress)2887{2888TR_ASSERT(dt == TR::Address, "Expecting loads with decompression trees to have data type TR::Address");2889genDecompressPointer(cg, node, loadOrStoreReg);2890}2891}28922893cg->stopUsingRegister(arrayletReg);2894}2895else2896{2897if (indexReg)2898generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, loadOrStoreReg, loadOrStoreReg, arrayletOffsetReg);2899else2900addConstantToInteger(node, loadOrStoreReg, loadOrStoreReg, arrayletOffsetVal, cg);2901}29022903if (indexReg)2904srm->reclaimScratchRegister(arrayletOffsetReg);2905}29062907const uint32_t numOOLDeps = 1 + (doLoadOrStore ? 1 : 0) + (needsBoundCheck && arrayLengthReg ? 1 : 0) + (loadOrStoreReg ? (loadOrStoreReg->getRegisterPair() ? 2 : 1) : 0)2908+ (indexReg ? 1 : 0) + srm->numAvailableRegisters();2909TR::RegisterDependencyConditions *OOLDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numOOLDeps, cg->trMemory());2910OOLDeps->addPostCondition(baseArrayReg, TR::RealRegister::NoReg);2911TR_ASSERT(OOLDeps->getPostConditions()->getRegisterDependency(0)->getRegister() == baseArrayReg, "Unexpected register");2912OOLDeps->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();2913if (doLoadOrStore)2914{2915OOLDeps->addPostCondition(arrayletReg, TR::RealRegister::NoReg);2916TR_ASSERT(OOLDeps->getPostConditions()->getRegisterDependency(1)->getRegister() == arrayletReg, "Unexpected register");2917OOLDeps->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0();2918}2919if (indexReg)2920OOLDeps->addPostCondition(indexReg, TR::RealRegister::NoReg);2921if (loadOrStoreReg)2922{2923if (loadOrStoreReg->getRegisterPair())2924{2925TR_ASSERT(dt == TR::Int64 && comp->target().is32Bit(), "Unexpected register pair");2926OOLDeps->addPostCondition(loadOrStoreReg->getHighOrder(), TR::RealRegister::NoReg);2927OOLDeps->addPostCondition(loadOrStoreReg->getLowOrder(), TR::RealRegister::NoReg);2928}2929else2930OOLDeps->addPostCondition(loadOrStoreReg, TR::RealRegister::NoReg);2931}2932if (needsBoundCheck && arrayLengthReg)2933OOLDeps->addPostCondition(arrayLengthReg, TR::RealRegister::NoReg);2934srm->addScratchRegistersToDependencyList(OOLDeps);29352936srm->stopUsingRegisters();29372938TR::LabelSymbol *doneOOLLabel = generateLabelSymbol(cg);2939generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneOOLLabel, OOLDeps);2940generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);2941}2942discontiguousArrayOOL->swapInstructionListsWithCompilation();2943//2944// OOL end.29452946cg->decReferenceCount(loadOrStoreChild);2947cg->decReferenceCount(baseArrayChild);2948cg->decReferenceCount(indexChild);29492950return NULL;2951}29522953static void VMoutlinedHelperArrayStoreCHKEvaluator(TR::Node *node, TR::Register *srcReg, TR::Register *dstReg, bool srcIsNonNull, TR::CodeGenerator *cg)2954{2955TR::Compilation * comp = cg->comp();2956TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());2957TR::CodeCache *codeCache = cg->getCodeCache();2958TR::LabelSymbol *doneArrayStoreCHKLabel = generateLabelSymbol(cg);2959TR::Register *rootClassReg = cg->allocateRegister();2960TR::Register *scratchReg = cg->allocateRegister();2961TR::Register *srcNullCondReg;29622963TR_PPCScratchRegisterDependencyConditions deps;29642965if (!srcIsNonNull)2966{2967srcNullCondReg = cg->allocateRegister(TR_CCR);2968generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, srcNullCondReg, srcReg, NULLVALUE);2969generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneArrayStoreCHKLabel, srcNullCondReg);2970}29712972deps.addDependency(cg, dstReg, TR::RealRegister::gr3);2973deps.addDependency(cg, srcReg, TR::RealRegister::gr4);2974// Clobbered by the helper2975deps.addDependency(cg, NULL, TR::RealRegister::gr5);2976deps.addDependency(cg, NULL, TR::RealRegister::gr6);2977deps.addDependency(cg, scratchReg, TR::RealRegister::gr7);2978deps.addDependency(cg, rootClassReg, TR::RealRegister::gr11);29792980TR_OpaqueClassBlock *rootClass = fej9->getSystemClassFromClassName("java/lang/Object", 16);2981if (cg->wantToPatchClassPointer(rootClass, node))2982loadAddressConstantInSnippet(cg, node, (intptr_t) rootClass, rootClassReg, scratchReg,TR::InstOpCode::Op_load, false, NULL);2983else2984loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t) rootClass, rootClassReg);29852986TR_CCPreLoadedCode helper = TR_arrayStoreCHK;2987uintptr_t helperAddr = (uintptr_t) codeCache->getCCPreLoadedCodeAddress(helper, cg);2988TR::SymbolReference *symRef = comp->getSymRefTab()->findOrCreatePerCodeCacheHelperSymbolRef(helper, helperAddr);29892990TR::Instruction *gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, helperAddr, new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 0, cg->trMemory()),2991symRef);2992gcPoint->PPCNeedsGCMap(0xFFFFFFFF);29932994generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneArrayStoreCHKLabel, TR_PPCScratchRegisterDependencyConditions::createDependencyConditions(cg, NULL, &deps));29952996cg->stopUsingRegister(rootClassReg);2997cg->stopUsingRegister(scratchReg);29982999if (!srcIsNonNull)3000cg->stopUsingRegister(srcNullCondReg);3001}30023003TR::Register *outlinedHelperArrayStoreCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)3004{3005TR::Node *srcNode = node->getFirstChild()->getSecondChild();3006TR::Node *dstNode = node->getFirstChild()->getThirdChild();3007TR::Register *srcReg = cg->evaluate(srcNode);3008TR::Register *dstReg = cg->evaluate(dstNode);3009TR::Compilation* comp = cg->comp();30103011if (!srcNode->isNull())3012{3013VMoutlinedHelperArrayStoreCHKEvaluator(node, srcReg, dstReg, srcNode->isNonNull(), cg);3014}30153016cg->evaluate(node->getFirstChild());3017cg->decReferenceCount(node->getFirstChild());30183019return NULL;3020}30213022TR::Instruction *J9::Power::TreeEvaluator::generateVFTMaskInstruction(TR::CodeGenerator *cg, TR::Node *node, TR::Register *dstReg, TR::Register *srcReg, TR::Instruction *preced)3023{3024TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());3025uintptr_t mask = TR::Compiler->om.maskOfObjectVftField();3026bool isCompressed = TR::Compiler->om.compressObjectReferences();3027if (~mask == 0)3028{3029// no mask instruction required3030return preced;3031}3032else3033{3034TR::InstOpCode::Mnemonic op = (cg->comp()->target().is64Bit() && !isCompressed) ? TR::InstOpCode::rldicr : TR::InstOpCode::rlwinm;3035return generateTrg1Src1Imm2Instruction(cg, op, node, dstReg, srcReg, 0, mask, preced);3036}3037}30383039TR::Instruction *J9::Power::TreeEvaluator::generateVFTMaskInstruction(TR::CodeGenerator *cg, TR::Node *node, TR::Register *reg, TR::Instruction *preced)3040{3041return TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, reg, reg, preced);3042}30433044static TR::Instruction *genTestIsSuper(TR::Node *node, TR::Register *objClassReg, TR::Register *castClassReg, TR::Register *crReg, TR::Register *scratch1Reg,3045TR::Register *scratch2Reg, int32_t castClassDepth, TR::LabelSymbol *failLabel, TR::Instruction *cursor, TR::CodeGenerator *cg, bool depthInReg2 = false)3046{3047TR::Compilation *comp = cg->comp();3048int32_t superClassOffset = castClassDepth * TR::Compiler->om.sizeofReferenceAddress();3049bool outOfBound = (!depthInReg2 && (superClassOffset > UPPER_IMMED || superClassOffset < LOWER_IMMED)) ? true : false;3050#ifdef OMR_GC_COMPRESSED_POINTERS3051// objClassReg contains the class offset so we may need to generate code3052// to convert from class offset to real J9Class pointer3053#endif3054cursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, scratch1Reg,3055TR::MemoryReference::createWithDisplacement(cg, objClassReg, offsetof(J9Class, classDepthAndFlags), TR::Compiler->om.sizeofReferenceAddress()), cursor);3056if (outOfBound)3057{3058cursor = loadConstant(cg, node, castClassDepth, scratch2Reg, cursor);3059}3060cursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, scratch1Reg, scratch1Reg, 0, J9AccClassDepthMask, cursor);30613062if (outOfBound || depthInReg2)3063{3064cursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, crReg, scratch1Reg, scratch2Reg, cursor);3065}3066else3067{3068cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, crReg, scratch1Reg, castClassDepth, cursor);3069}3070cursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, failLabel, crReg, cursor);30713072if (outOfBound || depthInReg2)3073{3074if (comp->target().is64Bit())3075cursor = generateShiftLeftImmediateLong(cg, node, scratch2Reg, scratch2Reg, 3, cursor);3076else3077cursor = generateShiftLeftImmediate(cg, node, scratch2Reg, scratch2Reg, 2, cursor);3078}3079#ifdef OMR_GC_COMPRESSED_POINTERS3080// objClassReg contains the class offset so we may need to generate code3081// to convert from class offset to real J9Class pointer3082#endif3083cursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, scratch1Reg,3084TR::MemoryReference::createWithDisplacement(cg, objClassReg, offsetof(J9Class, superclasses), TR::Compiler->om.sizeofReferenceAddress()), cursor);30853086if (outOfBound || depthInReg2)3087{3088cursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_loadx, node, scratch1Reg, TR::MemoryReference::createWithIndexReg(cg, scratch1Reg, scratch2Reg, TR::Compiler->om.sizeofReferenceAddress()),3089cursor);3090}3091else3092{3093cursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, scratch1Reg,3094TR::MemoryReference::createWithDisplacement(cg, scratch1Reg, superClassOffset, TR::Compiler->om.sizeofReferenceAddress()), cursor);3095}3096#ifdef OMR_GC_COMPRESSED_POINTERS3097// castClassReg has a class offset and scratch1Reg contains a J9Class pointer3098// May need to convert the J9Class pointer to a class offset3099#endif3100cursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmp, node, crReg, scratch1Reg, castClassReg, cursor);3101return (cursor);3102}31033104static void VMarrayStoreCHKEvaluator(TR::Node *node, TR::Register *src, TR::Register *dst, TR::Register *t1Reg, TR::Register *t2Reg, TR::Register *t3Reg, TR::Register *t4Reg,3105TR::Register *cndReg, TR::LabelSymbol *toWB, TR::LabelSymbol *fLabel, TR::CodeGenerator *cg)3106{3107TR::Compilation *comp = cg->comp();3108TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());31093110generateLoadJ9Class(node, t1Reg, dst, cg);3111generateLoadJ9Class(node, t2Reg, src, cg);31123113generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t1Reg,3114TR::MemoryReference::createWithDisplacement(cg, t1Reg, (int32_t)offsetof(J9ArrayClass, componentType), TR::Compiler->om.sizeofReferenceAddress()));31153116if (!comp->compileRelocatableCode() || comp->getOption(TR_UseSymbolValidationManager))3117{3118TR_OpaqueClassBlock *rootClass = fej9->getSystemClassFromClassName("java/lang/Object", 16);31193120if (cg->wantToPatchClassPointer(rootClass, node))3121{3122loadAddressConstantInSnippet(cg, node, (intptr_t) rootClass, t3Reg, t4Reg, TR::InstOpCode::Op_load, false, NULL);3123}3124else if (comp->compileRelocatableCode())3125{3126TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);3127sym->setStaticAddress(rootClass);3128sym->setClassObject();31293130loadAddressConstant(cg, true, node, (intptr_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), t3Reg, NULL, false, TR_ClassAddress);3131}3132else3133{3134loadAddressConstant(cg, false, node, (intptr_t) rootClass, t3Reg);3135}31363137generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t3Reg);3138generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg);3139}31403141generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t4Reg,3142TR::MemoryReference::createWithDisplacement(cg, t2Reg, (int32_t) offsetof(J9Class, castClassCache), TR::Compiler->om.sizeofReferenceAddress()));31433144generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t2Reg);3145generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg);31463147generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t4Reg);3148generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg);31493150generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t3Reg);3151generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg);31523153if ((!comp->getOption(TR_DisableArrayStoreCheckOpts)) && node->getArrayComponentClassInNode())3154{3155TR_OpaqueClassBlock *castClass = (TR_OpaqueClassBlock *) node->getArrayComponentClassInNode();31563157if (cg->wantToPatchClassPointer(castClass, node))3158loadAddressConstantInSnippet(cg, node, (intptr_t) castClass, t3Reg, t4Reg,TR::InstOpCode::Op_load, false, NULL);3159else3160loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t) castClass, t3Reg);31613162generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t3Reg);3163generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg);3164}31653166#ifdef OMR_GC_COMPRESSED_POINTERS3167// For the following two instructions3168// we may need to convert the class offset from t1Reg into J9Class3169#endif3170generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t3Reg, TR::MemoryReference::createWithDisplacement(cg, t1Reg, (int32_t) offsetof(J9Class, romClass), TR::Compiler->om.sizeofReferenceAddress()));3171generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t4Reg,3172TR::MemoryReference::createWithDisplacement(cg, t1Reg, (int32_t) offsetof(J9Class, classDepthAndFlags), TR::Compiler->om.sizeofReferenceAddress()));3173generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, t3Reg, TR::MemoryReference::createWithDisplacement(cg, t3Reg, (int32_t) offsetof(J9ROMClass, modifiers), 4));3174generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, t4Reg, t4Reg, 0, J9AccClassDepthMask);3175generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, t3Reg, t3Reg, 31, 0xFFFFFFFF);3176TR_ASSERT(J9AccClassArray == (1 << 16) && J9AccInterface == (1 << 9), "Verify code sequence is still right ...");3177generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, t3Reg, t3Reg, cndReg, (J9AccClassArray | J9AccInterface) >> 1);3178generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, fLabel, cndReg);3179genTestIsSuper(node, t2Reg, t1Reg, cndReg, t3Reg, t4Reg, 0, fLabel, cg->getAppendInstruction(), cg, true);31803181generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, fLabel, cndReg);3182}31833184TR::Register *J9::Power::TreeEvaluator::ArrayStoreCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)3185{3186TR::Compilation *comp = cg->comp();3187TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());3188static bool oldArrayStoreCHK = feGetEnv("TR_newArrayStoreCheck") == NULL;3189if (!comp->compileRelocatableCode() && !comp->getOptions()->realTimeGC() && !comp->useCompressedPointers() && !oldArrayStoreCHK)3190return outlinedHelperArrayStoreCHKEvaluator(node, cg);31913192// Note: we take advantage of the register conventions of the helpers by limiting register usages on3193// the fast-path (most likely 4 registers; at most, 6 registers)31943195TR::Node * firstChild = node->getFirstChild();31963197TR::Node *sourceChild = firstChild->getSecondChild();3198TR::Node *destinationChild = firstChild->getChild(2);31993200if (comp->useCompressedPointers() && firstChild->getOpCode().isIndirect())3201{3202while ((sourceChild->getNumChildren() > 0) && (sourceChild->getOpCodeValue() != TR::a2l))3203sourceChild = sourceChild->getFirstChild();3204if (sourceChild->getOpCodeValue() == TR::a2l)3205sourceChild = sourceChild->getFirstChild();3206}32073208// Since ArrayStoreCHK doesn't have the shape of the corresponding helper call we have to create this tree3209// so we can have it evaluated out of line3210TR::Node *helperCallNode = TR::Node::createWithSymRef(node, TR::call, 2, node->getSymbolReference());3211helperCallNode->setAndIncChild(0, sourceChild);3212helperCallNode->setAndIncChild(1, destinationChild);3213if (comp->getOption(TR_TraceCG))3214{3215traceMsg(comp, "%s: Creating and evaluating the following tree to generate the necessary helper call for this node\n", node->getOpCode().getName());3216cg->getDebug()->print(comp->getOutFile(), helperCallNode);3217}32183219TR::Register *srcReg, *dstReg;3220TR::Register *condReg, *temp1Reg, *temp2Reg, *temp3Reg, *temp4Reg;3221TR::LabelSymbol *wbLabel, *startLabel;3222TR::RegisterDependencyConditions *conditions;32233224wbLabel = generateLabelSymbol(cg);32253226dstReg = cg->evaluate(destinationChild);3227srcReg = cg->evaluate(sourceChild);32283229conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(9, 9, cg->trMemory());3230temp1Reg = cg->allocateRegister();3231temp2Reg = cg->allocateRegister();3232temp3Reg = cg->allocateRegister();3233temp4Reg = cg->allocateRegister();3234condReg = cg->allocateRegister(TR_CCR);32353236TR::addDependency(conditions, dstReg, TR::RealRegister::NoReg, TR_GPR, cg);3237conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();3238conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();3239TR::addDependency(conditions, srcReg, TR::RealRegister::NoReg, TR_GPR, cg);3240conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();3241conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();3242TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);3243conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();3244conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();3245TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);3246conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();3247conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();3248TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);3249conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();3250conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();3251TR::addDependency(conditions, temp4Reg, TR::RealRegister::NoReg, TR_GPR, cg);3252conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();3253conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();3254TR::addDependency(conditions, condReg, TR::RealRegister::cr0, TR_CCR, cg);32553256//--Generate Test to see if 'sourceRegister' is NULL3257generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, srcReg, NULLVALUE);3258//--Generate Jump past ArrayStoreCHKEvaluator3259generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, wbLabel, condReg);32603261TR::LabelSymbol *helperCall = generateLabelSymbol(cg);3262VMarrayStoreCHKEvaluator(node, srcReg, dstReg, temp1Reg, temp2Reg, temp3Reg, temp4Reg, condReg, wbLabel, helperCall, cg);32633264TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(helperCallNode, TR::call, NULL, helperCall, wbLabel, cg);3265cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);3266cg->decReferenceCount(helperCallNode->getFirstChild());3267cg->decReferenceCount(helperCallNode->getSecondChild());32683269generateDepLabelInstruction(cg, TR::InstOpCode::label, node, wbLabel, conditions);3270cg->evaluate(firstChild);32713272cg->decReferenceCount(firstChild);32733274cg->stopUsingRegister(temp1Reg);3275cg->stopUsingRegister(temp2Reg);3276cg->stopUsingRegister(temp3Reg);3277cg->stopUsingRegister(temp4Reg);3278cg->stopUsingRegister(condReg);32793280return NULL;3281}32823283TR::Register *J9::Power::TreeEvaluator::ArrayCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)3284{3285return TR::TreeEvaluator::VMarrayCheckEvaluator(node, cg);3286}32873288TR::Register *J9::Power::TreeEvaluator::conditionalHelperEvaluator(TR::Node *node, TR::CodeGenerator *cg)3289{3290// There are two points which have to be considered for this evaluator:3291// 1) This conditional tree is of a special form which is lowered just3292// before instruction selection. This means the conditional is invisible3293// to the control flow analysis. As such, we have to treat it just as3294// part of a basic block;3295// 2) The two opCodes using this evaluator are intended as quick JVMPI3296// probes. They should not impact the normal code (in terms of performance).3297// As such, their call evaluation will be specially treated not to go3298// through the normal linkage. OTI will preserve all the registers as3299// needed.33003301TR::RegisterDependencyConditions *conditions;3302TR::Register *cndReg, *jumpReg, *valReg;3303TR::Node *testNode = node->getFirstChild(), *callNode = node->getSecondChild();3304TR::Node *firstChild = testNode->getFirstChild(), *secondChild = testNode->getSecondChild();3305int32_t value, i, numArgs = callNode->getNumChildren();33063307conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());33083309TR_ASSERT(numArgs <= 2, "Unexpected number of arguments for helper.");33103311// Helper arguments are in reversed order of the private linkage3312// Argument registers are not needed to be split since the helper will3313// preserve all of them.3314int32_t iArgIndex = 0, fArgIndex = 0;3315TR::Linkage *linkage = cg->createLinkage(TR_Private);3316for (i = numArgs - 1; i >= 0; i--)3317{3318TR::Register *argReg = cg->evaluate(callNode->getChild(i));3319TR::addDependency(conditions, argReg, (argReg->getKind() == TR_GPR) ? // Didn't consider Long here3320linkage->getProperties().getIntegerArgumentRegister(iArgIndex++) : linkage->getProperties().getFloatArgumentRegister(fArgIndex++), argReg->getKind(), cg);3321}33223323cndReg = cg->allocateRegister(TR_CCR);3324jumpReg = cg->evaluate(firstChild);3325TR::addDependency(conditions, cndReg, TR::RealRegister::NoReg, TR_CCR, cg);3326TR::addDependency(conditions, jumpReg, TR::RealRegister::gr11, TR_GPR, cg);33273328if (secondChild->getOpCode().isLoadConst() && (value = secondChild->getInt()) <= UPPER_IMMED && value >= LOWER_IMMED)3329{3330generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, testNode, cndReg, jumpReg, value);3331}3332else3333{3334valReg = cg->evaluate(secondChild);3335generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, testNode, cndReg, jumpReg, valReg);3336}33373338TR::Instruction *gcPoint;3339TR::LabelSymbol *snippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());3340if (snippetLabel == NULL)3341{3342snippetLabel = generateLabelSymbol(cg);3343cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference()));3344}3345gcPoint = generateDepConditionalBranchInstruction(cg, testNode->getOpCodeValue() == TR::icmpeq ? TR::InstOpCode::beql : TR::InstOpCode::bnel, node, snippetLabel, cndReg, conditions);3346gcPoint->PPCNeedsGCMap(0xFFFFFFFF);33473348cg->stopUsingRegister(cndReg);3349for (i = numArgs - 1; i >= 0; i--)3350cg->decReferenceCount(callNode->getChild(i));3351cg->decReferenceCount(firstChild);3352cg->decReferenceCount(secondChild);3353cg->decReferenceCount(testNode);3354cg->decReferenceCount(callNode);3355return NULL;3356}33573358TR::Register *J9::Power::TreeEvaluator::flushEvaluator(TR::Node *node, TR::CodeGenerator *cg)3359{3360TR::ILOpCodes opCode = node->getOpCodeValue();33613362if (opCode == TR::allocationFence)3363{3364if (!node->canOmitSync())3365generateInstruction(cg, TR::InstOpCode::lwsync, node);3366}3367else3368{3369if (opCode == TR::loadFence)3370{3371if (cg->comp()->target().cpu.is(OMR_PROCESSOR_PPC_P7))3372generateInstruction(cg, TR::InstOpCode::lwsync, node);3373else3374generateInstruction(cg, TR::InstOpCode::isync, node);3375}3376else if (opCode == TR::storeFence)3377generateInstruction(cg, TR::InstOpCode::lwsync, node);3378else if (opCode == TR::fullFence)3379{3380if (node->canOmitSync())3381generateLabelInstruction(cg, TR::InstOpCode::label, node, generateLabelSymbol(cg));3382else3383generateInstruction(cg, TR::InstOpCode::sync, node);3384}3385}33863387return NULL;3388}33893390static3391void genCheckCastTransitionToNextSequence(TR::Node *node, J9::TreeEvaluator::InstanceOfOrCheckCastSequences *iter, TR::LabelSymbol *nextSequenceLabel, TR::LabelSymbol *trueLabel, TR::Register *condReg, TR::CodeGenerator *cg)3392{3393J9::TreeEvaluator::InstanceOfOrCheckCastSequences current = *iter++;33943395if (current == J9::TreeEvaluator::EvaluateCastClass || current == J9::TreeEvaluator::LoadObjectClass)3396return;3397if (current == J9::TreeEvaluator::NullTest && node->getOpCodeValue() == TR::checkcastAndNULLCHK)3398return;33993400J9::TreeEvaluator::InstanceOfOrCheckCastSequences next = *iter;34013402while (next == J9::TreeEvaluator::EvaluateCastClass || next == J9::TreeEvaluator::LoadObjectClass)3403next = *++iter;34043405bool nextSequenceIsOutOfLine = next == J9::TreeEvaluator::HelperCall || next == J9::TreeEvaluator::GoToFalse;34063407if (nextSequenceIsOutOfLine)3408generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, nextSequenceLabel, condReg);3409else3410generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, trueLabel, condReg);3411}34123413static3414void genInstanceOfTransitionToNextSequence(TR::Node *node, J9::TreeEvaluator::InstanceOfOrCheckCastSequences *iter, TR::LabelSymbol *nextSequenceLabel, TR::LabelSymbol *doneLabel, TR::Register *condReg, TR::Register *resultReg, bool resultRegInitialValue, TR::LabelSymbol *oppositeResultLabel, bool profiledClassIsInstanceOf, TR::CodeGenerator *cg)3415{3416J9::TreeEvaluator::InstanceOfOrCheckCastSequences current = *iter++;34173418if (current == J9::TreeEvaluator::EvaluateCastClass || current == J9::TreeEvaluator::LoadObjectClass)3419return;3420if (current == J9::TreeEvaluator::NullTest && node->getOpCodeValue() == TR::checkcastAndNULLCHK)3421return;3422if (current == J9::TreeEvaluator::GoToFalse)3423return;34243425J9::TreeEvaluator::InstanceOfOrCheckCastSequences next = *iter;34263427while (next == J9::TreeEvaluator::EvaluateCastClass || next == J9::TreeEvaluator::LoadObjectClass)3428next = *++iter;34293430if (next == J9::TreeEvaluator::GoToFalse && resultRegInitialValue == false)3431nextSequenceLabel = doneLabel;34323433bool nextSequenceIsOutOfLine = next == J9::TreeEvaluator::HelperCall;34343435if (current == J9::TreeEvaluator::NullTest)3436{3437generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, resultRegInitialValue == false ? doneLabel : oppositeResultLabel, condReg);3438}3439else if (current == J9::TreeEvaluator::CastClassCacheTest)3440{3441if (resultRegInitialValue == true)3442{3443if (nextSequenceIsOutOfLine)3444{3445generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneLabel, condReg);3446generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, nextSequenceLabel, condReg);3447// Fall through to oppositeResultLabel3448}3449else3450{3451generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneLabel, condReg);3452generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, oppositeResultLabel, condReg);3453// Fall through to nextSequenceLabel3454}3455}3456else3457{3458if (nextSequenceIsOutOfLine)3459{3460generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);3461generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, nextSequenceLabel, condReg);3462// Fall through to oppositeResultLabel3463}3464else3465{3466generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);3467generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, oppositeResultLabel, condReg);3468// Fall through to nextSequenceLabel3469}3470}3471}3472else if (current == J9::TreeEvaluator::ProfiledClassTest)3473{3474if (resultRegInitialValue == true)3475{3476if (profiledClassIsInstanceOf)3477{3478if (nextSequenceIsOutOfLine)3479{3480generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);3481generateLabelInstruction(cg, TR::InstOpCode::b, node, nextSequenceLabel);3482}3483else3484{3485generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);3486}3487}3488else3489{3490if (nextSequenceIsOutOfLine)3491{3492generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, nextSequenceLabel, condReg);3493// Fall through to oppositeResultLabel3494}3495else3496{3497generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, oppositeResultLabel, condReg);3498}3499}3500}3501else3502{3503if (profiledClassIsInstanceOf)3504{3505if (nextSequenceIsOutOfLine)3506{3507generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, nextSequenceLabel, condReg);3508// Fall through to oppositeResultLabel3509}3510else3511{3512generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, oppositeResultLabel, condReg);3513}3514}3515else3516{3517if (nextSequenceIsOutOfLine)3518{3519generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);3520generateLabelInstruction(cg, TR::InstOpCode::b, node, nextSequenceLabel);3521}3522else3523{3524generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);3525}3526}3527}3528}3529else3530{3531if (nextSequenceIsOutOfLine)3532generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, nextSequenceLabel, condReg);3533else3534generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, resultRegInitialValue == true ? doneLabel : oppositeResultLabel, condReg);3535}3536}35373538static3539void genInstanceOfOrCheckCastClassEqualityTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR::Register *castClassReg, TR::CodeGenerator *cg)3540{3541generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, condReg, instanceClassReg, castClassReg);35423543// At this point condReg[eq] will be set if the cast class matches the instance class. Caller is responsible for acting on the result.3544}35453546static3547void genInstanceOfOrCheckCastSuperClassTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR::Register *castClassReg, int32_t castClassDepth, TR::LabelSymbol *falseLabel, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg)3548{3549TR::Compilation *comp = cg->comp();35503551// Compare the instance class depth to the cast class depth. If the instance class depth is less than or equal to3552// to the cast class depth then the cast class cannot be a superclass of the instance class.3553//3554TR::Register *instanceClassDepthReg = srm->findOrCreateScratchRegister();3555TR::Register *castClassDepthReg = NULL;3556generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, instanceClassDepthReg,3557TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9Class, classDepthAndFlags), TR::Compiler->om.sizeofReferenceAddress()));3558static_assert(J9AccClassDepthMask < UINT_MAX, "Class depth is not containable in 32 bits");3559generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, instanceClassDepthReg, instanceClassDepthReg, 0, J9AccClassDepthMask);3560if (castClassDepth <= UPPER_IMMED && castClassDepth >= LOWER_IMMED)3561generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, instanceClassDepthReg, castClassDepth);3562else3563{3564castClassDepthReg = srm->findOrCreateScratchRegister();3565loadConstant(cg, node, castClassDepth, castClassDepthReg);3566generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, condReg, instanceClassDepthReg, castClassDepthReg);3567}3568srm->reclaimScratchRegister(instanceClassDepthReg);35693570// At this point condReg[gt] will be set if the instance class depth is greater than the cast class depth.3571//3572generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, falseLabel, condReg);35733574// Load the superclasses array of the instance class and check if the superclass that appears at the depth of the cast class is in fact the cast class.3575// If not, the instance class and cast class are not in the same hierarchy.3576//3577TR::Register *instanceClassSuperClassesArrayReg = srm->findOrCreateScratchRegister();3578TR::Register *instanceClassSuperClassReg = srm->findOrCreateScratchRegister();35793580generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, instanceClassSuperClassesArrayReg,3581TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9Class, superclasses), TR::Compiler->om.sizeofReferenceAddress()));35823583int32_t castClassDepthOffset = castClassDepth * TR::Compiler->om.sizeofReferenceAddress();3584if (castClassDepthOffset <= UPPER_IMMED && castClassDepthOffset >= LOWER_IMMED)3585{3586generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, instanceClassSuperClassReg,3587TR::MemoryReference::createWithDisplacement(cg, instanceClassSuperClassesArrayReg, castClassDepthOffset, TR::Compiler->om.sizeofReferenceAddress()));3588}3589else3590{3591if (!castClassDepthReg)3592{3593castClassDepthReg = srm->findOrCreateScratchRegister();3594if (0x00008000 == HI_VALUE(castClassDepthOffset))3595{3596generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, castClassDepthReg, instanceClassSuperClassesArrayReg, 0x7FFF);3597generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, castClassDepthReg, castClassDepthReg, 0x1);3598}3599else3600{3601generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, castClassDepthReg, instanceClassSuperClassesArrayReg, HI_VALUE(castClassDepthOffset));3602}3603generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, instanceClassSuperClassReg,3604TR::MemoryReference::createWithDisplacement(cg, castClassDepthReg, LO_VALUE(castClassDepthOffset), TR::Compiler->om.sizeofReferenceAddress()));3605}3606else3607{3608if (comp->target().is64Bit())3609generateShiftLeftImmediateLong(cg, node, castClassDepthReg, castClassDepthReg, 3);3610else3611generateShiftLeftImmediate(cg, node, castClassDepthReg, castClassDepthReg, 2);3612generateTrg1MemInstruction(cg, TR::InstOpCode::Op_loadx, node, instanceClassSuperClassReg, TR::MemoryReference::createWithIndexReg(cg, instanceClassSuperClassesArrayReg, castClassDepthReg, TR::Compiler->om.sizeofReferenceAddress()));3613}3614}3615generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, condReg, instanceClassSuperClassReg, castClassReg);3616if (castClassDepthReg)3617srm->reclaimScratchRegister(castClassDepthReg);3618srm->reclaimScratchRegister(instanceClassSuperClassesArrayReg);3619srm->reclaimScratchRegister(instanceClassSuperClassReg);36203621// At this point condReg[eq] will be set if the cast class is a superclass of the instance class. Caller is responsible for acting on the result.3622}36233624static3625void genInstanceOfOrCheckCastArbitraryClassTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR_OpaqueClassBlock *arbitraryClass, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg)3626{3627TR::Compilation *comp = cg->comp();3628TR::Register *arbitraryClassReg = srm->findOrCreateScratchRegister();3629if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager))3630{3631TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);3632sym->setStaticAddress(arbitraryClass);3633sym->setClassObject();36343635loadAddressConstant(cg, true, node, (intptr_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), arbitraryClassReg, NULL, false, TR_ClassAddress);3636}3637else3638{3639loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t)arbitraryClass, arbitraryClassReg);3640}3641genInstanceOfOrCheckCastClassEqualityTest(node, condReg, instanceClassReg, arbitraryClassReg, cg);3642srm->reclaimScratchRegister(arbitraryClassReg);36433644// At this point condReg[eq] will be set if the cast class matches the arbitrary class. Caller is responsible for acting on the result.3645}36463647static3648void genInstanceOfCastClassCacheTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR::Register *castClassReg, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg)3649{3650TR::Compilation *comp = cg->comp();36513652// Compare the cast class against the cache on the instance class.3653// If they are the same the cast is successful.3654// If not it's either because the cache class does not match the cast class, or it does match except the cache class has the low bit set, which means the cast is not successful.3655//3656TR::Register *castClassCacheReg = srm->findOrCreateScratchRegister();3657generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, castClassCacheReg,3658TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9Class, castClassCache), TR::Compiler->om.sizeofReferenceAddress()));3659generateTrg1Src2Instruction(cg, TR::InstOpCode::XOR, node, castClassCacheReg, castClassCacheReg, castClassReg);3660generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::Op_cmpli, node, condReg, castClassCacheReg, 1);36613662// At this point condReg[lt] will be set if the cast is successful, condReg[eq] will be set if the cast is unsuccessful, and condReg[gt] will be set if the cache class did not match the cast class.3663// Caller is responsible for acting on the result.3664}36653666static3667void genCheckCastCastClassCacheTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR::Register *castClassReg, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg)3668{3669TR::Compilation *comp = cg->comp();36703671// Compare the cast class against the cache on the instance class.3672// If they are the same the cast is successful.3673// If not it's either because the cache class does not match the cast class, or it does match except the cache class has the low bit set, which means the cast is invalid.3674//3675TR::Register *castClassCacheReg = srm->findOrCreateScratchRegister();3676generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, castClassCacheReg,3677TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9Class, castClassCache), TR::Compiler->om.sizeofReferenceAddress()));3678generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, condReg, castClassReg, castClassCacheReg);3679srm->reclaimScratchRegister(castClassCacheReg);36803681// At this point condReg[eq] will be set if the cast is successful. Caller is responsible for acting on the result.3682}36833684static3685void genInstanceOfOrCheckCastObjectArrayTest(TR::Node *node, TR::Register *cr0Reg, TR::Register *instanceClassReg, TR::LabelSymbol *falseLabel, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg)3686{3687TR::Compilation *comp = cg->comp();36883689// Load the object ROM class and test the modifiers to see if this is an array.3690//3691TR::Register *scratchReg = srm->findOrCreateScratchRegister();3692generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9Class, romClass), TR::Compiler->om.sizeofReferenceAddress()));3693generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, scratchReg, offsetof(J9ROMClass, modifiers), 4));3694if (J9AccClassArray <= UPPER_IMMED && J9AccClassArray >= LOWER_IMMED)3695generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, scratchReg, scratchReg, cr0Reg, J9AccClassArray);3696else3697generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andis_r, node, scratchReg, scratchReg, cr0Reg, J9AccClassArray >> 16);36983699// At this point cr0[eq] will be set if this is not an array.3700//3701generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, falseLabel, cr0Reg);37023703// If it's an array, load the component ROM class and test the modifiers to see if this is a primitive array.3704//3705generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9ArrayClass, componentType), TR::Compiler->om.sizeofReferenceAddress()));3706generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, scratchReg, offsetof(J9Class, romClass), TR::Compiler->om.sizeofReferenceAddress()));3707generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, scratchReg, offsetof(J9ROMClass, modifiers), 4));3708if (J9AccClassInternalPrimitiveType <= UPPER_IMMED && J9AccClassInternalPrimitiveType >= LOWER_IMMED)3709generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, scratchReg, scratchReg, cr0Reg, J9AccClassInternalPrimitiveType);3710else3711generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andis_r, node, scratchReg, scratchReg, cr0Reg, J9AccClassInternalPrimitiveType >> 16);3712srm->reclaimScratchRegister(scratchReg);37133714// At this point cr0[eq] will be set if this is not a primitive array. Caller is responsible acting on the result.3715}37163717static3718void genInstanceOfOrCheckCastHelperCall(TR::Node *node, TR::Register *objectReg, TR::Register *castClassReg, TR::Register *resultReg, TR::CodeGenerator *cg)3719{3720TR_ASSERT((resultReg != NULL) == (node->getOpCodeValue() == TR::instanceof),3721"Expecting result reg for instanceof but not checkcast");37223723TR::Register *helperReturnReg = resultReg ? cg->allocateRegister() : NULL;37243725TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 4, cg->trMemory());37263727deps->addPreCondition(castClassReg, TR::RealRegister::gr3);3728deps->addPostCondition(resultReg ? helperReturnReg : castClassReg, TR::RealRegister::gr3);3729deps->addPostCondition(objectReg, TR::RealRegister::gr4);3730TR::Register *dummyReg, *dummyRegCCR;3731// gr11 is killed by the trampoline.3732deps->addPostCondition(dummyReg = cg->allocateRegister(), TR::RealRegister::gr11);3733dummyReg->setPlaceholderReg();3734// cr0 is not preserved by the helper.3735deps->addPostCondition(dummyRegCCR = cg->allocateRegister(TR_CCR), TR::RealRegister::cr0);3736dummyRegCCR->setPlaceholderReg();37373738TR::Instruction *gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)node->getSymbolReference()->getMethodAddress(), deps, node->getSymbolReference());3739gcPoint->PPCNeedsGCMap(0xFFFFFFFF);37403741if (resultReg)3742generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, resultReg, helperReturnReg);37433744cg->stopUsingRegister(dummyReg);3745cg->stopUsingRegister(dummyRegCCR);37463747cg->machine()->setLinkRegisterKilled(true);37483749TR::Register *nodeRegs[3] = {objectReg, castClassReg, resultReg};3750deps->stopUsingDepRegs(cg, 3, nodeRegs);3751}37523753TR::Register *J9::Power::TreeEvaluator::VMcheckcastEvaluator(TR::Node *node, TR::CodeGenerator *cg)3754{3755TR::Compilation *comp = cg->comp();3756TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(comp->fe());3757TR_OpaqueClassBlock *compileTimeGuessClass;3758InstanceOfOrCheckCastProfiledClasses profiledClassesList[1];3759InstanceOfOrCheckCastSequences sequences[InstanceOfOrCheckCastMaxSequences];3760uint32_t numberOfProfiledClass = 0;3761float topClassProbability = 0.0;3762bool topClassWasCastClass = false;3763uint32_t numSequencesRemaining = calculateInstanceOfOrCheckCastSequences(node, sequences, &compileTimeGuessClass, cg, profiledClassesList, &numberOfProfiledClass, 1, &topClassProbability, &topClassWasCastClass);37643765TR::Node *objectNode = node->getFirstChild();3766TR::Node *castClassNode = node->getSecondChild();3767TR::Register *objectReg = cg->evaluate(objectNode);3768TR::Register *castClassReg = NULL;37693770TR::LabelSymbol *depLabel = generateLabelSymbol(cg);3771TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);3772TR::LabelSymbol *helperReturnLabel = generateLabelSymbol(cg);3773TR::LabelSymbol *nextSequenceLabel = generateLabelSymbol(cg);37743775TR::Instruction *gcPoint;37763777TR_PPCScratchRegisterManager *srm = cg->generateScratchRegisterManager();3778TR::Register *objectClassReg = NULL;3779TR::Register *cr0Reg = cg->allocateRegister(TR_CCR);37803781InstanceOfOrCheckCastSequences *iter = &sequences[0];3782while (numSequencesRemaining > 1)3783{3784switch (*iter)3785{3786case EvaluateCastClass:3787TR_ASSERT(!castClassReg, "Cast class already evaluated");3788castClassReg = cg->evaluate(castClassNode);3789break;3790case LoadObjectClass:3791TR_ASSERT(!objectClassReg, "Object class already loaded");3792objectClassReg = srm->findOrCreateScratchRegister();3793generateLoadJ9Class(node, objectClassReg, objectReg, cg);3794break;3795case NullTest:3796if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting NullTest\n", node->getOpCode().getName());3797TR_ASSERT(!objectNode->isNonNull(), "Object is known to be non-null, no need for a null test");3798if (node->getOpCodeValue() == TR::checkcastAndNULLCHK)3799{3800TR::Node *nullChkInfo = comp->findNullChkInfo(node);3801gcPoint = generateNullTestInstructions(cg, objectReg, nullChkInfo, !cg->getHasResumableTrapHandler());3802gcPoint->PPCNeedsGCMap(0x0);3803}3804else3805{3806genNullTest(node, objectReg, cr0Reg, cg);3807}3808break;3809case GoToTrue:3810TR_ASSERT(false, "Doesn't make sense, GoToTrue should not be part of multiple sequences");3811break;3812case GoToFalse:3813TR_ASSERT(false, "Doesn't make sense, GoToFalse should be the terminal sequence");3814break;3815case ClassEqualityTest:3816if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ClassEqualityTest\n", node->getOpCode().getName());3817genInstanceOfOrCheckCastClassEqualityTest(node, cr0Reg, objectClassReg, castClassReg, cg);3818break;3819case SuperClassTest:3820{3821if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting SuperClassTest\n", node->getOpCode().getName());3822int32_t castClassDepth = castClassNode->getSymbolReference()->classDepth(comp);3823genInstanceOfOrCheckCastSuperClassTest(node, cr0Reg, objectClassReg, castClassReg, castClassDepth, nextSequenceLabel, srm, cg);3824break;3825}3826case ProfiledClassTest:3827if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ProfiledClassTest\n", node->getOpCode().getName());3828genInstanceOfOrCheckCastArbitraryClassTest(node, cr0Reg, objectClassReg, profiledClassesList[0].profiledClass, srm, cg);3829break;3830case CompileTimeGuessClassTest:3831if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting CompileTimeGuessClassTest\n", node->getOpCode().getName());3832genInstanceOfOrCheckCastArbitraryClassTest(node, cr0Reg, objectClassReg, compileTimeGuessClass, srm, cg);3833break;3834case CastClassCacheTest:3835if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting CastClassCacheTest\n", node->getOpCode().getName());3836genCheckCastCastClassCacheTest(node, cr0Reg, objectClassReg, castClassReg, srm, cg);3837break;3838case ArrayOfJavaLangObjectTest:3839if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ArrayOfJavaLangObjectTest\n", node->getOpCode().getName());3840genInstanceOfOrCheckCastObjectArrayTest(node, cr0Reg, objectClassReg, nextSequenceLabel, srm, cg);3841break;3842case HelperCall:3843TR_ASSERT(false, "Doesn't make sense, HelperCall should be the terminal sequence");3844break;3845}38463847genCheckCastTransitionToNextSequence(node, iter, nextSequenceLabel, doneLabel, cr0Reg, cg);38483849--numSequencesRemaining;3850++iter;38513852if (*iter != HelperCall && *iter != GoToFalse)3853{3854generateLabelInstruction(cg, TR::InstOpCode::label, node, nextSequenceLabel);3855nextSequenceLabel = generateLabelSymbol(cg);3856}3857}38583859if (objectClassReg)3860srm->reclaimScratchRegister(objectClassReg);38613862generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);38633864cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast/%s/fastPath",3865node->getOpCode().getName()),3866*srm);3867cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast.perMethod/%s/(%s)/%d/%d/fastPath",3868node->getOpCode().getName(), comp->signature(), node->getByteCodeInfo().getCallerIndex(), node->getByteCodeInfo().getByteCodeIndex()),3869*srm);38703871TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 3 + srm->numAvailableRegisters(), cg->trMemory());3872srm->addScratchRegistersToDependencyList(deps, true);3873deps->addPostCondition(cr0Reg, TR::RealRegister::cr0);3874deps->addPostCondition(objectReg, TR::RealRegister::NoReg);3875deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();3876if (castClassReg)3877{3878deps->addPostCondition(castClassReg, TR::RealRegister::NoReg);3879deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();3880}38813882generateDepLabelInstruction(cg, TR::InstOpCode::label, node, depLabel, deps);38833884generateLabelInstruction(cg, TR::InstOpCode::label, node, helperReturnLabel);38853886if (numSequencesRemaining > 0 && *iter != GoToTrue)3887{3888TR_ASSERT(*iter == HelperCall || *iter == GoToFalse, "Expecting helper call or fail here");3889bool helperCallForFailure = *iter != HelperCall;3890if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting HelperCall%s\n", node->getOpCode().getName(), helperCallForFailure ? " for failure" : "");3891TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, nextSequenceLabel, helperReturnLabel, cg);3892cg->generateDebugCounter(nextSequenceLabel->getInstruction(),3893TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast/%s/%s",3894node->getOpCode().getName(),3895helperCallForFailure ? "fail" : "helperCall"));3896cg->generateDebugCounter(nextSequenceLabel->getInstruction(),3897TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast.perMethod/%s/(%s)/%d/%d/%s",3898node->getOpCode().getName(), comp->signature(), node->getByteCodeInfo().getCallerIndex(), node->getByteCodeInfo().getByteCodeIndex(),3899helperCallForFailure ? "fail" : "helperCall"));39003901cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);3902}39033904deps->stopUsingDepRegs(cg, objectReg, castClassReg);3905cg->decReferenceCount(objectNode);3906cg->decReferenceCount(castClassNode);39073908return NULL;3909}39103911TR::Register *J9::Power::TreeEvaluator::VMinstanceOfEvaluator(TR::Node *node, TR::CodeGenerator *cg)3912{3913TR::Compilation *comp = cg->comp();3914TR_OpaqueClassBlock *compileTimeGuessClass;3915bool profiledClassIsInstanceOf;3916InstanceOfOrCheckCastProfiledClasses profiledClassesList[1];3917InstanceOfOrCheckCastSequences sequences[InstanceOfOrCheckCastMaxSequences];3918bool topClassWasCastClass = false;3919float topClassProbability = 0.0;3920uint32_t numberOfProfiledClass;3921uint32_t numSequencesRemaining = calculateInstanceOfOrCheckCastSequences(node, sequences, &compileTimeGuessClass, cg, profiledClassesList, &numberOfProfiledClass, 1, &topClassProbability, &topClassWasCastClass);39223923TR::Node *objectNode = node->getFirstChild();3924TR::Node *castClassNode = node->getSecondChild();3925TR::Register *objectReg = cg->evaluate(objectNode);3926TR::Register *castClassReg = NULL;3927TR::Register *resultReg = cg->allocateRegister();39283929TR::LabelSymbol *depLabel = generateLabelSymbol(cg);3930TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);3931TR::LabelSymbol *helperReturnLabel = generateLabelSymbol(cg);3932TR::LabelSymbol *nextSequenceLabel = generateLabelSymbol(cg);3933TR::LabelSymbol *oppositeResultLabel = generateLabelSymbol(cg);39343935TR::Instruction *gcPoint;39363937TR_PPCScratchRegisterManager *srm = cg->generateScratchRegisterManager();3938TR::Register *objectClassReg = NULL;3939TR::Register *cr0Reg = cg->allocateRegister(TR_CCR);39403941static bool initialResult = feGetEnv("TR_instanceOfInitialValue") != NULL;//true;3942generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, initialResult);39433944InstanceOfOrCheckCastSequences *iter = &sequences[0];3945while (numSequencesRemaining > 1 || (numSequencesRemaining == 1 && *iter != HelperCall))3946{3947switch (*iter)3948{3949case EvaluateCastClass:3950TR_ASSERT(!castClassReg, "Cast class already evaluated");3951castClassReg = cg->evaluate(castClassNode);3952break;3953case LoadObjectClass:3954TR_ASSERT(!objectClassReg, "Object class already loaded");3955objectClassReg = srm->findOrCreateScratchRegister();3956generateLoadJ9Class(node, objectClassReg, objectReg, cg);3957break;3958case NullTest:3959if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting NullTest\n", node->getOpCode().getName());3960TR_ASSERT(!objectNode->isNonNull(), "Object is known to be non-null, no need for a null test");3961if (node->getOpCodeValue() == TR::checkcastAndNULLCHK)3962{3963TR::Node *nullChkInfo = comp->findNullChkInfo(node);3964gcPoint = generateNullTestInstructions(cg, objectReg, nullChkInfo, !cg->getHasResumableTrapHandler());3965gcPoint->PPCNeedsGCMap(0x0);3966}3967else3968{3969genNullTest(node, objectReg, cr0Reg, cg);3970}3971break;3972case GoToTrue:3973if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting GoToTrue\n", node->getOpCode().getName());3974if (initialResult == true)3975generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);3976break;3977case GoToFalse:3978if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting GoToFalse\n", node->getOpCode().getName());3979if (initialResult == false)3980generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);3981break;3982case ClassEqualityTest:3983if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ClassEqualityTest\n", node->getOpCode().getName());3984genInstanceOfOrCheckCastClassEqualityTest(node, cr0Reg, objectClassReg, castClassReg, cg);3985break;3986case SuperClassTest:3987{3988if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting SuperClassTest\n", node->getOpCode().getName());3989int32_t castClassDepth = castClassNode->getSymbolReference()->classDepth(comp);3990genInstanceOfOrCheckCastSuperClassTest(node, cr0Reg, objectClassReg, castClassReg, castClassDepth, nextSequenceLabel, srm, cg);3991break;3992}3993case ProfiledClassTest:3994if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ProfiledClassTest\n", node->getOpCode().getName());3995profiledClassIsInstanceOf = profiledClassesList[0].isProfiledClassInstanceOfCastClass;3996genInstanceOfOrCheckCastArbitraryClassTest(node, cr0Reg, objectClassReg, profiledClassesList[0].profiledClass, srm, cg);3997break;3998case CompileTimeGuessClassTest:3999if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting CompileTimeGuessClassTest\n", node->getOpCode().getName());4000genInstanceOfOrCheckCastArbitraryClassTest(node, cr0Reg, objectClassReg, compileTimeGuessClass, srm, cg);4001break;4002case CastClassCacheTest:4003if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting CastClassCacheTest\n", node->getOpCode().getName());4004genInstanceOfCastClassCacheTest(node, cr0Reg, objectClassReg, castClassReg, srm, cg);4005break;4006case ArrayOfJavaLangObjectTest:4007if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ArrayOfJavaLangObjectTest\n", node->getOpCode().getName());4008genInstanceOfOrCheckCastObjectArrayTest(node, cr0Reg, objectClassReg, nextSequenceLabel, srm, cg);4009break;4010case DynamicCacheObjectClassTest:4011TR_ASSERT_FATAL(false, "%s: DynamicCacheObjectClassTest is not implemented on P\n", node->getOpCode().getName());4012break;4013case DynamicCacheDynamicCastClassTest:4014TR_ASSERT_FATAL(false, "%s: DynamicCacheDynamicCastClassTest is not implemented on P\n", node->getOpCode().getName());4015break;4016case HelperCall:4017TR_ASSERT(false, "Doesn't make sense, HelperCall should be the terminal sequence");4018break;4019}40204021genInstanceOfTransitionToNextSequence(node, iter, nextSequenceLabel, doneLabel, cr0Reg, resultReg, initialResult, oppositeResultLabel, profiledClassIsInstanceOf, cg);40224023--numSequencesRemaining;4024++iter;40254026if (*iter != HelperCall)4027{4028generateLabelInstruction(cg, TR::InstOpCode::label, node, nextSequenceLabel);4029nextSequenceLabel = generateLabelSymbol(cg);4030}4031}40324033if (objectClassReg)4034srm->reclaimScratchRegister(objectClassReg);40354036if (true)4037{4038generateLabelInstruction(cg, TR::InstOpCode::label, node, oppositeResultLabel);4039generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, !initialResult);4040}40414042generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);40434044cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast/%s/fastPath",4045node->getOpCode().getName()),4046*srm);4047cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast.perMethod/%s/(%s)/%d/%d/fastPath",4048node->getOpCode().getName(), comp->signature(), node->getByteCodeInfo().getCallerIndex(), node->getByteCodeInfo().getByteCodeIndex()),4049*srm);40504051TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 4 + srm->numAvailableRegisters(), cg->trMemory());4052srm->addScratchRegistersToDependencyList(deps, true);4053deps->addPostCondition(cr0Reg, TR::RealRegister::cr0);4054deps->addPostCondition(resultReg, TR::RealRegister::NoReg);4055deps->addPostCondition(objectReg, TR::RealRegister::NoReg);4056deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();4057if (castClassReg)4058{4059deps->addPostCondition(castClassReg, TR::RealRegister::NoReg);4060deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();4061}40624063generateDepLabelInstruction(cg, TR::InstOpCode::label, node, depLabel, deps);40644065generateLabelInstruction(cg, TR::InstOpCode::label, node, helperReturnLabel);40664067if (numSequencesRemaining > 0)4068{4069if (*iter == HelperCall)4070{4071if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting HelperCall\n", node->getOpCode().getName());4072TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::icall, resultReg, nextSequenceLabel, helperReturnLabel, cg);4073cg->generateDebugCounter(nextSequenceLabel->getInstruction(),4074TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast/%s/helperCall",4075node->getOpCode().getName()));4076cg->generateDebugCounter(nextSequenceLabel->getInstruction(),4077TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast.perMethod/%s/(%s)/%d/%d/helperCall",4078node->getOpCode().getName(), comp->signature(), node->getByteCodeInfo().getCallerIndex(), node->getByteCodeInfo().getByteCodeIndex()));40794080cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);4081}4082}40834084// Stop using every reg in the deps except these ones.4085//4086TR::Register *nodeRegs[3] = {objectReg, castClassReg, resultReg};4087deps->stopUsingDepRegs(cg, 3, nodeRegs);40884089cg->decReferenceCount(objectNode);4090cg->decReferenceCount(castClassNode);40914092node->setRegister(resultReg);40934094return resultReg;4095}40964097// ----------------------------------------------------------------------------40984099// only need a helper call if the class is not super and not final, otherwise4100// it can be determined without a call-out4101static bool needHelperCall(bool testCastClassIsSuper, bool isFinalClass)4102{4103return !testCastClassIsSuper && !isFinalClass;4104}41054106static bool needTestCache(bool cachingEnabled, bool needsHelperCall, bool superClassTest, TR_OpaqueClassBlock* castClassAddr, uint8_t num_PICS)4107{4108return cachingEnabled && needsHelperCall && !superClassTest && castClassAddr && num_PICS;4109}41104111TR::Register *J9::Power::TreeEvaluator::ifInstanceOfEvaluator(TR::Node *node, TR::CodeGenerator *cg)4112{4113return TR::TreeEvaluator::VMifInstanceOfEvaluator(node, cg);4114}411541164117TR::Register *J9::Power::TreeEvaluator::VMifInstanceOfEvaluator(TR::Node *node, TR::CodeGenerator *cg)4118{4119TR::Node *depNode;4120int32_t depIndex;4121int32_t numDep;4122TR::LabelSymbol *branchLabel;4123TR::Node *instanceOfNode;4124TR::Node *valueNode;4125int32_t value;4126TR::LabelSymbol *doneLabel, *res0Label, *res1Label;4127bool branchOn1;4128TR::Register *resultReg;4129TR::ILOpCodes opCode;4130TR::Compilation * comp = cg->comp();4131TR::SymbolReference *castClassSymRef;4132TR::Node *castClassNode;4133TR_OpaqueClassBlock *castClassAddr;4134TR_OpaqueClassBlock *guessClassArray[NUM_PICS];41354136depIndex = 0;4137numDep = 0;4138depNode = NULL;4139branchLabel = node->getBranchDestination()->getNode()->getLabel();4140instanceOfNode = node->getFirstChild();4141valueNode = node->getSecondChild();4142value = valueNode->getInt();4143opCode = node->getOpCodeValue();41444145castClassNode = instanceOfNode->getSecondChild();4146castClassSymRef = castClassNode->getSymbolReference();4147castClassAddr = TR::TreeEvaluator::getCastClassAddress(castClassNode);4148uint8_t num_PICS = TR::TreeEvaluator::interpreterProfilingInstanceOfOrCheckCastInfo(cg, instanceOfNode, guessClassArray);41494150bool testEqualClass = instanceOfOrCheckCastNeedEqualityTest(instanceOfNode, cg);4151// Testing castClassAddr to set testCastClassIsSuper only if cast class is known at compile time4152// When class is unknown, testCastClassIsSuper is false, and needsHelperCall is true to handle non-typical class types (e.g. interfaces)4153bool testCastClassIsSuper = castClassAddr && instanceOfOrCheckCastNeedSuperTest(instanceOfNode, cg);4154bool isFinalClass = (castClassSymRef == NULL) ? false : castClassSymRef->isNonArrayFinal(comp);4155bool needsHelperCall = needHelperCall(testCastClassIsSuper, isFinalClass);4156bool testCache = needTestCache(!comp->getOption(TR_DisableInlineCheckCast), needsHelperCall, testCastClassIsSuper, castClassAddr, num_PICS);41574158if (node->getNumChildren() == 3)4159{4160depNode = node->getChild(2);4161numDep = depNode->getNumChildren();4162}41634164// If the result itself is assigned to a global register, we still have to evaluate it4165int32_t needResult = (instanceOfNode->getReferenceCount() > 1);41664167if (depNode != NULL)4168{4169int32_t i1;41704171if (!needsHelperCall && numberOfRegisterCandidate(cg, depNode, TR_GPR) + 7 > cg->getMaximumNumberOfGPRsAllowedAcrossEdge(node))4172return ((TR::Register *) 1);41734174const TR::PPCLinkageProperties& properties = cg->getLinkage()->getProperties();4175TR::Node *objNode = instanceOfNode->getFirstChild();4176for (i1 = 0; i1 < depNode->getNumChildren(); i1++)4177{4178TR::Node *childNode = depNode->getChild(i1);4179int32_t regIndex = cg->getGlobalRegister(childNode->getGlobalRegisterNumber());41804181int32_t validHighRegNum = TR::TreeEvaluator::getHighGlobalRegisterNumberIfAny(childNode, cg);41824183if (needsHelperCall)4184{4185int32_t highIndex;41864187if (validHighRegNum != -1)4188highIndex = cg->getGlobalRegister(validHighRegNum);41894190if (!properties.getPreserved((TR::RealRegister::RegNum) regIndex)4191|| (validHighRegNum != -1 && !properties.getPreserved((TR::RealRegister::RegNum) highIndex)))4192return ((TR::Register *) 1);4193}4194else4195{4196if (childNode->getOpCodeValue() == TR::PassThrough)4197childNode = childNode->getFirstChild();4198if ((childNode == objNode || childNode == castClassNode) && regIndex == TR::RealRegister::gr0)4199return ((TR::Register *) 1);4200}4201}4202depIndex = numberOfRegisterCandidate(cg, depNode, TR_GPR) + numberOfRegisterCandidate(cg, depNode, TR_FPR) +4203numberOfRegisterCandidate(cg, depNode, TR_CCR) + numberOfRegisterCandidate(cg, depNode, TR_VRF) +4204numberOfRegisterCandidate(cg, depNode, TR_VSX_SCALAR) + numberOfRegisterCandidate(cg, depNode, TR_VSX_VECTOR);4205}42064207doneLabel = generateLabelSymbol(cg);42084209if ((opCode == TR::ificmpeq && value == 1) || (opCode != TR::ificmpeq && value == 0))4210{4211res0Label = doneLabel;4212res1Label = branchLabel;4213branchOn1 = true;4214}4215else4216{4217res0Label = branchLabel;4218res1Label = doneLabel;4219branchOn1 = false;4220}42214222resultReg = TR::TreeEvaluator::VMgenCoreInstanceofEvaluator(instanceOfNode, cg, true, depIndex, numDep, depNode, needResult, needsHelperCall, testEqualClass, testCache, testCastClassIsSuper,4223doneLabel, res0Label, res1Label, branchOn1);42244225if (resultReg != instanceOfNode->getRegister())4226instanceOfNode->setRegister(resultReg);4227cg->decReferenceCount(instanceOfNode);4228cg->decReferenceCount(valueNode);42294230node->setRegister(NULL);4231return NULL;4232}42334234// genCoreInstanceofEvaluator is used by if instanceof and instanceof routines.4235// The routine generates the 'core' code for instanceof evaluation. It requires a true and false label4236// (which are the same and are just fall-through labels if no branching is required) as well as4237// a boolean to indicate if the result should be calculated and returned in a register.4238// The code also needs to indicate if the fall-through case if for 'true' or 'false'.4239TR::Register * J9::Power::TreeEvaluator::VMgenCoreInstanceofEvaluator(TR::Node * node, TR::CodeGenerator * cg, bool isVMifInstanceOf, int32_t depIndex, int32_t numDep,4240TR::Node *depNode, bool needResult, bool needHelperCall, bool testEqualClass, bool testCache, bool testCastClassIsSuper, TR::LabelSymbol *doneLabel,4241TR::LabelSymbol *res0Label, TR::LabelSymbol *res1Label, bool branchOn1)4242{4243TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());4244TR::Register *objectReg, *castClassReg, *objClassReg;4245TR::Register *resultReg, *crReg, *scratch1Reg, *scratch2Reg, *scratch3Reg;4246TR::Instruction *iCursor;4247TR::SymbolReference *castClassSymRef;4248TR::RegisterDependencyConditions *conditions;4249TR::LabelSymbol *trueLabel, *callLabel, *nextTestLabel;4250TR::Node *objectNode, *castClassNode;4251int32_t castClassDepth;4252TR::ILOpCodes opCode;4253TR::RegisterDependencyConditions *deps;4254TR_OpaqueClassBlock *castClassAddr;4255TR_OpaqueClassBlock *guessClassArray[NUM_PICS];4256TR::Compilation * comp = cg->comp();4257castClassDepth = -1;4258trueLabel = NULL;4259resultReg = NULL;4260deps = NULL;4261iCursor = NULL;42624263castClassNode = node->getSecondChild();4264castClassSymRef = castClassNode->getSymbolReference();4265castClassAddr = TR::TreeEvaluator::getCastClassAddress(castClassNode);4266uint8_t num_PICS = TR::TreeEvaluator::interpreterProfilingInstanceOfOrCheckCastInfo(cg, node, guessClassArray);4267objectNode = node->getFirstChild();42684269bool stopUsingHelperCallCR = false;42704271if (needHelperCall)4272{4273callLabel = generateLabelSymbol(cg);42744275TR::ILOpCodes opCode = node->getOpCodeValue();42764277TR::Node::recreate(node, TR::icall);4278directCallEvaluator(node, cg);4279TR::Node::recreate(node, opCode);42804281iCursor = cg->getAppendInstruction();4282while (iCursor->getOpCodeValue() != TR::InstOpCode::bl)4283iCursor = iCursor->getPrev();4284conditions = ((TR::PPCDepImmSymInstruction *) iCursor)->getDependencyConditions();4285iCursor = iCursor->getPrev();4286iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, callLabel, iCursor);4287iCursor = iCursor->getPrev();42884289auto firstArgReg = node->getSymbol()->castToMethodSymbol()->getLinkageConvention() == TR_CHelper ? TR::RealRegister::gr4 : TR::RealRegister::gr3;4290objectReg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 1));4291castClassReg = conditions->searchPreConditionRegister(firstArgReg);4292scratch1Reg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 2));4293scratch2Reg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 4));4294scratch3Reg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 6));4295objClassReg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 3));4296crReg = conditions->searchPreConditionRegister(TR::RealRegister::cr0);4297if (!crReg)4298{4299// This is another hack to compensate for skipping the preserving of CCRs for helper calls in linkage code.4300// This hack wouldn't be necessary if this code wasn't being lazy and re-using the dependencies4301// set up by the direct call evaluator, but alas...4302// Since we are not preserving CCRs and this code previously expected to find a CCR in the call instruction's4303// dependency conditions we allocate a new virtual here and stick it in the dependencies, making sure to4304// repeat everything that is normally done for virtual regs when they are referenced by a generated instruction,4305// which just means we record two uses to correspond to the fact that we added them to the pre/post deps of the4306// call.4307crReg = nonFixedDependency(conditions, NULL, &depIndex, TR_CCR, false, cg);4308stopUsingHelperCallCR = true;4309TR::Instruction *callInstruction = scratch1Reg->getStartOfRange();4310callInstruction->useRegister(crReg);4311callInstruction->useRegister(crReg);4312}43134314if (depNode != NULL)4315{4316cg->evaluate(depNode);4317deps = generateRegisterDependencyConditions(cg, depNode, 0, &iCursor);4318}43194320if (testEqualClass || testCache || testCastClassIsSuper)4321{4322if (needResult)4323{4324resultReg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 5));4325iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0, iCursor);4326}4327if (!objectNode->isNonNull())4328{4329iCursor = genNullTest(objectNode, objectReg, crReg, scratch1Reg, iCursor, cg);4330iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res0Label, crReg, iCursor);4331}4332}4333}4334else4335{4336bool earlyEval = (castClassNode->getOpCodeValue() != TR::loadaddr || castClassNode->getReferenceCount() > 1) ? true : false;43374338bool objInDep = false, castClassInDep = false;4339if (depNode != NULL)4340{4341int32_t i1;43424343TR::Node *grNode;4344cg->evaluate(depNode);4345deps = generateRegisterDependencyConditions(cg, depNode, 7);43464347for (i1 = 0; i1 < numDep; i1++)4348{4349grNode = depNode->getChild(i1);4350if (grNode->getOpCodeValue() == TR::PassThrough)4351grNode = grNode->getFirstChild();4352if (grNode == objectNode)4353objInDep = true;4354if (grNode == castClassNode)4355castClassInDep = true;4356}4357}43584359if (deps == NULL)4360{4361conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(7, 7, cg->trMemory());4362}4363else4364{4365conditions = deps;4366}43674368crReg = nonFixedDependency(conditions, NULL, &depIndex, TR_CCR, false, cg);43694370if (needResult)4371resultReg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, false, cg);43724373objClassReg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, true, cg);43744375objectReg = cg->evaluate(objectNode);43764377if (!objInDep)4378objectReg = nonFixedDependency(conditions, objectReg, &depIndex, TR_GPR, true, cg);43794380if (earlyEval)4381{4382castClassReg = cg->evaluate(castClassNode);4383castClassReg = nonFixedDependency(conditions, castClassReg, &depIndex, TR_GPR, true, cg);4384}43854386if (needResult)4387generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0);43884389if (!objectNode->isNonNull())4390{4391genNullTest(objectNode, objectReg, crReg, objClassReg, NULL, cg);4392generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res0Label, crReg);4393}43944395if (!earlyEval)4396{4397castClassReg = cg->evaluate(castClassNode);4398castClassReg = nonFixedDependency(conditions, castClassReg, &depIndex, TR_GPR, true, cg);4399}44004401if (testCastClassIsSuper)4402{4403scratch1Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, true, cg);4404scratch2Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, true, cg);4405cg->stopUsingRegister(scratch1Reg);4406cg->stopUsingRegister(scratch2Reg);4407}44084409iCursor = cg->getAppendInstruction();44104411generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);44124413cg->decReferenceCount(objectNode);4414cg->decReferenceCount(castClassNode);4415cg->stopUsingRegister(crReg);4416cg->stopUsingRegister(objClassReg);4417}44184419if (testEqualClass || testCache || testCastClassIsSuper)4420{4421if (TR::Compiler->om.compressObjectReferences())4422// read only 32 bits4423iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, objClassReg,4424TR::MemoryReference::createWithDisplacement(cg, objectReg,4425(int32_t) TR::Compiler->om.offsetOfObjectVftField(), 4),4426iCursor);4427else4428iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, objClassReg,4429TR::MemoryReference::createWithDisplacement(cg, objectReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), TR::Compiler->om.sizeofReferenceAddress()), iCursor);4430iCursor = TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, objClassReg, iCursor);4431}44324433if (testEqualClass)4434{4435iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, crReg, objClassReg, castClassReg, iCursor);44364437if (testCache || testCastClassIsSuper)4438{4439if (needResult)4440{4441trueLabel = generateLabelSymbol(cg);4442iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, trueLabel, crReg, iCursor);4443}4444else4445{4446iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res1Label, crReg, iCursor);4447}4448}4449else if (needHelperCall)4450{4451if (needResult)4452{4453iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);4454}4455iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res1Label, crReg, iCursor);44564457bool castClassIsReferenceArray = (comp->isOptServer()) && (!castClassNode->getSymbolReference()->isUnresolved())4458&& (castClassNode->getSymbolReference() == comp->getSymRefTab()->findVftSymbolRef()) && (castClassNode->getNumChildren() == 1)4459&& (castClassNode->getFirstChild()->getOpCodeValue() == TR::anewarray);4460if (castClassIsReferenceArray)4461{4462TR_OpaqueClassBlock * jlobjectclassBlock = fej9->getSystemClassFromClassName("java/lang/Object", 16);4463J9Class* jlobjectarrayclassBlock = jlobjectclassBlock ? (J9Class*)fej9->getArrayClassFromComponentClass((TR_OpaqueClassBlock*)jlobjectclassBlock) : NULL;4464if (jlobjectarrayclassBlock != NULL)4465{4466iCursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t) (jlobjectarrayclassBlock), scratch1Reg, iCursor);4467iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, crReg, objClassReg, scratch1Reg, iCursor);4468if (needResult)4469{4470iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0, iCursor);4471}4472iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res0Label, crReg, iCursor);4473}4474}4475}4476else4477{4478iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, res0Label, crReg, iCursor);4479if (needResult)4480{4481iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);4482}44834484if (branchOn1)4485{4486iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, res1Label, iCursor);4487}4488}4489}44904491if (testCache)4492{4493// The cached value could have been from a previously successful checkcast or instanceof.4494// An answer of 0 in the low order bit indicates 'success' (the cast or instanceof was successful).4495// An answer of 1 in the lower order bit indicates 'failure' (the cast would have thrown an exception, instanceof would have been unsuccessful)4496// Because of this, we can just do a simple load and compare of the 2 class pointers. If it succeeds, the low order bit4497// must be off (success) from a previous checkcast or instanceof. If the low order bit is on, it is guaranteed not to4498// compare and we will take the slow path.4499// Generate inline test for instanceOf4500genInlineTest(node, castClassAddr, guessClassArray, num_PICS, objClassReg, resultReg, crReg, scratch1Reg, scratch2Reg, false, needResult, res0Label, res1Label, doneLabel,4501callLabel, testCastClassIsSuper, iCursor, cg);4502}45034504if (testCastClassIsSuper)4505{4506bool depthInReg2 = false;45074508TR::StaticSymbol *castClassSym = NULL;4509if (castClassSymRef && !castClassSymRef->isUnresolved())4510castClassSym = castClassSymRef->getSymbol()->getStaticSymbol();45114512TR_OpaqueClassBlock * clazz = NULL;4513if (castClassSym)4514clazz = (TR_OpaqueClassBlock *) castClassSym->getStaticAddress();45154516if(clazz)4517castClassDepth = (int32_t)TR::Compiler->cls.classDepthOf(clazz);45184519if (castClassDepth == -1)4520{4521iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, scratch2Reg,4522TR::MemoryReference::createWithDisplacement(cg, castClassReg, offsetof(J9Class, classDepthAndFlags), TR::Compiler->om.sizeofReferenceAddress()), iCursor);4523iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, scratch2Reg, scratch2Reg, 0, J9AccClassDepthMask, iCursor);4524depthInReg2 = true;4525}45264527iCursor = genTestIsSuper(node, objClassReg, castClassReg, crReg, scratch1Reg, scratch2Reg, castClassDepth, res0Label, iCursor, cg, depthInReg2);4528iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, res0Label, crReg, iCursor);45294530if (trueLabel == NULL)4531{4532if (needResult)4533{4534iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);4535}4536}4537else4538{4539iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, trueLabel, iCursor);4540iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);4541}45424543if (branchOn1)4544{4545iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, res1Label, iCursor);4546}4547}4548else if (testCache)4549{4550if (trueLabel == NULL)4551{4552if (needResult)4553{4554iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);4555}4556}4557else4558{4559iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, trueLabel, iCursor);4560iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);4561}4562}45634564if (needHelperCall)4565{4566TR::Register *callResult = node->getRegister();4567TR::RegisterDependencyConditions *newDeps;45684569if (resultReg == NULL)4570{4571resultReg = callResult;4572}4573else4574{4575generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, resultReg, callResult);4576}45774578if (isVMifInstanceOf)4579{4580generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, crReg, resultReg, 0);4581}45824583if (depNode != NULL)4584{4585newDeps = conditions->cloneAndFix(cg, deps);4586}4587else4588{4589newDeps = conditions->cloneAndFix(cg);4590}45914592if (isVMifInstanceOf)4593{4594if (branchOn1)4595{4596generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, res1Label, crReg);4597}4598else4599{4600generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res0Label, crReg);4601}4602}46034604// Just fall through4605// generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);46064607// Done4608generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, newDeps);46094610if (stopUsingHelperCallCR)4611cg->stopUsingRegister(crReg);46124613// We have to revive the resultReg here. Should revisit to see how to use registers better4614// (e.g., reducing the chance of moving around).4615if (resultReg != callResult)4616reviveResultRegister(resultReg, callResult, cg);4617}46184619if (depNode != NULL)4620cg->decReferenceCount(depNode);46214622return resultReg;4623}46244625static TR::Register *4626reservationLockEnter(TR::Node *node, int32_t lwOffset, TR::CodeGenerator *cg, TR::RegisterDependencyConditions *conditions, TR::Register *objReg, TR::Register *monitorReg, TR::Register *valReg, TR::Register *tempReg, TR::Register *cndReg, TR::LabelSymbol *callLabel)4627{4628TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());4629TR::LabelSymbol *resLabel, *doneLabel, *doneOOLLabel, *loopLabel, *reserved_checkLabel;4630int32_t lockSize;4631TR::Compilation * comp = cg->comp();46324633TR::Register *metaReg = cg->getMethodMetaDataRegister();46344635resLabel = generateLabelSymbol(cg);4636loopLabel = generateLabelSymbol(cg);4637reserved_checkLabel = generateLabelSymbol(cg);4638doneLabel = generateLabelSymbol(cg);4639doneOOLLabel = generateLabelSymbol(cg);46404641TR::TreeEvaluator::isPrimitiveMonitor(node, cg);4642bool isPrimitive = node->isPrimitiveLockedRegion();4643lockSize = comp->target().is64Bit() && !fej9->generateCompressedLockWord() ? 8 : 4;46444645/*4646* PRIMITIVE lockReservation enter sequence: Non-Primitive lockReservation enter sequence:4647* ld/lwz monitorReg, lwOffset(objReg) ld/lwz monitorReg, lwOffset(objReg)4648* ori valReg, metaReg, LOCK_RESERVATION_BIT ori valReg, metaReg, LOCK_RESERVATION_BIT4649* cmpl cr0, monitorReg, valReg cmpl cr0, monitorReg, valReg4650* beq doneLabel bne resLabel <--- Diff4651* addi tempReg, monitorReg, LOCK_INC_DEC_VALUE <--- Diff4652* st tempReg, lwOffset(objReg) <--- Diff4653* b doneLabel4654* resLabel(startOOLLabel):4655* cmpli cr0, monitorReg, 0 cmpli cr0, monitorReg, 04656* bne reserved_checkLabel bne reserved_checkLabel4657* li tempReg, lwOffset li tempReg, lwOffset4658* addi valReg, metaReg, RES+INC <--- Diff4659* loopLabel:4660* larx monitorReg, [objReg, tempReg] larx monitorReg, [objReg, tempReg]4661* cmpli cr0, monitorReg, 0 cmpli cr0, monitorReg, 04662* bne callLabel bne callLabel4663* stcx. valReg, [objReg, tempReg] stcx. valReg, [objReg, tempReg]4664* bne loopLabel bne loopLabel4665* isync isync4666* b doneLabel b doneLabel4667* reserved_checkLabel:4668* li tempReg, PRIMITIVE_ENTER_MASK li tempReg, NON_PRIMITIVE_ENTER_MASK <--- Diff4669* andc tempReg, monitorReg, tempReg andc tempReg, monitorReg, tempReg4670* addi valReg, metaReg, RES <--- Diff4671* cmpl cr0, tempReg, valReg cmpl cr0, tempReg, valReg4672* bne callLabel bne callLabel4673* addi monitorReg, monitorReg, INC <--- Diff4674* st monitorReg, [objReg, lwOffset] <--- Diff4675* doneLabel:4676* doneOOLLabel:4677* === OUT OF LINE ===4678* callLabel:4679* bl jitMonitorEntry4680* b doneOOLLabel4681*/46824683generateTrg1MemInstruction(cg, lockSize == 8 ? TR::InstOpCode::ld : TR::InstOpCode::lwz, node, monitorReg, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, lockSize));4684generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, valReg, metaReg, LOCK_RESERVATION_BIT);4685generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, monitorReg, valReg);46864687if (!isPrimitive)4688{4689generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, resLabel, cndReg);4690generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tempReg, monitorReg, LOCK_INC_DEC_VALUE);4691generateMemSrc1Instruction(cg, lockSize == 8 ? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, lockSize), tempReg);4692generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);4693}4694else4695generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, cndReg);46964697generateLabelInstruction(cg, TR::InstOpCode::label, node, resLabel);4698generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, monitorReg, 0);4699generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, reserved_checkLabel, cndReg);4700generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, lwOffset);4701if (!isPrimitive)4702generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valReg, metaReg, LOCK_RESERVATION_BIT | LOCK_INC_DEC_VALUE);4703generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);4704generateTrg1MemInstruction(cg, lockSize == 8 ? TR::InstOpCode::ldarx : TR::InstOpCode::lwarx,4705PPCOpProp_LoadReserveExclusiveAccess, node, monitorReg, TR::MemoryReference::createWithIndexReg(cg, objReg, tempReg, lockSize));4706generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, monitorReg, 0);4707generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, cndReg);4708generateMemSrc1Instruction(cg, lockSize == 8 ? TR::InstOpCode::stdcx_r : TR::InstOpCode::stwcx_r,4709node, TR::MemoryReference::createWithIndexReg(cg, objReg, tempReg, lockSize), valReg);4710generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, loopLabel, cndReg);4711generateInstruction(cg, TR::InstOpCode::isync, node);4712generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);4713generateLabelInstruction(cg, TR::InstOpCode::label, node, reserved_checkLabel);4714generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, isPrimitive ? LOCK_RES_PRIMITIVE_ENTER_MASK : LOCK_RES_NON_PRIMITIVE_ENTER_MASK);4715generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, tempReg, monitorReg, tempReg);4716if (!isPrimitive)4717generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valReg, metaReg, LOCK_RESERVATION_BIT);4718generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, tempReg, valReg);4719generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, cndReg);4720if (!isPrimitive)4721{4722generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, monitorReg, monitorReg, LOCK_INC_DEC_VALUE);4723generateMemSrc1Instruction(cg, lockSize == 8 ? TR::InstOpCode::std : TR::InstOpCode::stw,4724node, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset & 0x0000FFFF, lockSize), monitorReg);4725}47264727doneLabel->setEndInternalControlFlow();4728generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);47294730TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, doneOOLLabel, cg);4731cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);47324733generateLabelInstruction(cg, TR::InstOpCode::label, node, doneOOLLabel);47344735conditions->stopUsingDepRegs(cg, objReg);4736cg->decReferenceCount(node->getFirstChild());4737return NULL;4738}47394740static TR::Register *4741reservationLockExit(TR::Node *node, int32_t lwOffset, TR::CodeGenerator *cg, TR::RegisterDependencyConditions *conditions, TR::Register *objReg, TR::Register *monitorReg, TR::Register *valReg, TR::Register *tempReg, TR::Register *cndReg, TR::LabelSymbol *callLabel)4742{4743TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());4744TR::LabelSymbol *resLabel, *doneLabel, *doneOOLLabel;4745int32_t lockSize;4746TR::Compilation *comp = cg->comp();47474748TR::Register *metaReg = cg->getMethodMetaDataRegister();47494750resLabel = generateLabelSymbol(cg);4751doneLabel = generateLabelSymbol(cg);4752doneOOLLabel = generateLabelSymbol(cg);47534754bool isPrimitive = node->isPrimitiveLockedRegion();4755lockSize = comp->target().is64Bit() && !fej9->generateCompressedLockWord() ? 8 : 4;47564757/*4758* PRIMITIVE reservationLock exit sequence Non-PRIMITIVE reservationLock exit sequence4759* ld/lwz monitorReg, [objReg, lwOffset] ld/lwz monitorReg, [objReg, lwOffset]4760* andi_r tempReg, monitorReg, PRIMITIVE_EXIT_MASK ori tempReg, metaReg, RES+INC <-- Diff4761* cmpli cndReg, tempReg, LOCK_RESERVATION_BIT cmpl cndReg, monitorReg, tempReg <-- Diff4762* bne resLabel bne resLabel <-- Diff4763* addi valReg, metaReg, LOCK_RESERVATION_BIT <-- Diff4764* st valReg, [objReg, lwOffset] <-- Diff4765* b doneLabel <-- Diff4766* resLabel(startOOLLabel):4767* li tempReg, RES_OWNING_COMPLEMENT li tempReg, RES_OWNING_COMPLEMENT4768* andc tempReg, monitorReg, tempReg andc tempReg, monitorReg, tempReg4769* addi valReg, metaReg, RES_BIT addi valReg, metaReg, RES_BIT4770* cmpl cndReg, tempReg, valReg cmpl cndReg, tempReg, valReg4771* bne callLabel bne callLabel4772* andi_r tempReg, monitorReg, RECURSION_MASK andi_r tempReg, monitorReg, NON_PRIMITIVE_EXIT_MASK <-- Diff4773* bne doneLabel beq callLabel <-- Diff4774* addi monitorReg, monitorReg, INC addi monitorReg, monitorReg, -INC <-- Diff4775* st monitorReg, [objReg, lwOffset] st monitorReg, [objReg, lwOffset]4776* b doneLabel <-- Diff4777* doneLabel:4778* doneOOLLabel:4779* === OUT OF LINE ===4780* callLabel:4781* bl jitMonitorExit4782* b doneOOLLabel4783*/47844785generateTrg1MemInstruction(cg, lockSize == 8 ? TR::InstOpCode::ld : TR::InstOpCode::lwz, node, monitorReg, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, lockSize));4786if (!node->isPrimitiveLockedRegion())4787{4788generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, tempReg, metaReg, LOCK_RESERVATION_BIT + LOCK_INC_DEC_VALUE);4789generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, monitorReg, tempReg);4790}4791else4792{4793generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, tempReg, monitorReg, LOCK_RES_PRIMITIVE_EXIT_MASK);4794generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, tempReg, LOCK_RESERVATION_BIT);4795}47964797if (!isPrimitive)4798{4799generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, resLabel, cndReg);4800generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valReg, metaReg, LOCK_RESERVATION_BIT);4801generateMemSrc1Instruction(cg, lockSize == 8 ? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, lockSize), valReg);4802generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);4803}4804else4805generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, resLabel, cndReg);48064807generateLabelInstruction(cg, TR::InstOpCode::label, node, resLabel);4808generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, LOCK_RES_OWNING_COMPLEMENT);4809generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, tempReg, monitorReg, tempReg);4810generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valReg, metaReg, LOCK_RESERVATION_BIT);4811generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, tempReg, valReg);4812generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, cndReg);4813generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, tempReg, monitorReg, isPrimitive ? OBJECT_HEADER_LOCK_RECURSION_MASK : LOCK_RES_NON_PRIMITIVE_EXIT_MASK);4814if (isPrimitive)4815generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, doneLabel, cndReg);4816else4817generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, cndReg);4818generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, monitorReg, monitorReg, isPrimitive ? LOCK_INC_DEC_VALUE : -LOCK_INC_DEC_VALUE);4819generateMemSrc1Instruction(cg, lockSize == 8 ? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, lockSize), monitorReg);4820if (!isPrimitive)4821generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);48224823doneLabel->setEndInternalControlFlow();4824generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);48254826TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, doneOOLLabel, cg);4827cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);48284829generateLabelInstruction(cg, TR::InstOpCode::label, node, doneOOLLabel);48304831conditions->stopUsingDepRegs(cg, objReg);4832cg->decReferenceCount(node->getFirstChild());4833return NULL;4834}48354836TR::Register *J9::Power::TreeEvaluator::VMmonexitEvaluator(TR::Node *node, TR::CodeGenerator *cg)4837{4838TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());4839int32_t lwOffset = fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node));4840TR::Compilation *comp = cg->comp();4841TR_YesNoMaybe isMonitorValueBasedOrValueType = cg->isMonitorValueBasedOrValueType(node);48424843if (comp->getOption(TR_FullSpeedDebug) ||4844(isMonitorValueBasedOrValueType == TR_yes) ||4845comp->getOption(TR_DisableInlineMonExit))4846{4847TR::ILOpCodes opCode = node->getOpCodeValue();4848TR::Node::recreate(node, TR::call);4849TR::Register *targetRegister = directCallEvaluator(node, cg);4850TR::Node::recreate(node, opCode);4851return targetRegister;4852}48534854int32_t numDeps = 6;48554856TR::Node *objNode = node->getFirstChild();4857TR::Register *objReg = cg->evaluate(objNode);48584859TR::Register *monitorReg = cg->allocateRegister();4860TR::Register *tempReg = cg->allocateRegister();4861TR::Register *threadReg = cg->allocateRegister();48624863TR::Register *objectClassReg = cg->allocateRegister();4864TR::Register *lookupOffsetReg = NULL;48654866TR::Register *condReg = cg->allocateRegister(TR_CCR);4867TR::Register *metaReg = cg->getMethodMetaDataRegister();48684869TR::Register *baseReg = objReg;48704871if (lwOffset <= 0)4872{4873if (comp->getOption(TR_EnableMonitorCacheLookup))4874{4875lookupOffsetReg = cg->allocateRegister();4876numDeps++;4877}4878}48794880TR::RegisterDependencyConditions *conditions;4881conditions = createConditionsAndPopulateVSXDeps(cg, numDeps);48824883TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);4884conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();4885conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();48864887TR::addDependency(conditions, monitorReg, TR::RealRegister::NoReg, TR_GPR, cg);4888conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();4889conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();48904891TR::addDependency(conditions, tempReg, TR::RealRegister::NoReg, TR_GPR, cg);48924893TR::addDependency(conditions, threadReg, TR::RealRegister::NoReg, TR_GPR, cg);48944895TR::addDependency(conditions, objectClassReg, TR::RealRegister::NoReg, TR_GPR, cg);4896conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();4897conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();48984899if (lookupOffsetReg)4900{4901TR::addDependency(conditions, lookupOffsetReg, TR::RealRegister::NoReg, TR_GPR, cg);4902conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();4903conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();4904}49054906TR::addDependency(conditions, condReg, TR::RealRegister::cr0, TR_CCR, cg);49074908TR::LabelSymbol *callLabel = generateLabelSymbol(cg);4909TR::LabelSymbol *monitorLookupCacheLabel = generateLabelSymbol(cg);4910TR::LabelSymbol *fallThruFromMonitorLookupCacheLabel = generateLabelSymbol(cg);4911TR::LabelSymbol *startLabel = generateLabelSymbol(cg);49124913generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel, NULL);4914startLabel->setStartInternalControlFlow();49154916//If object is not known to be value type or value based class at compile time, check at run time4917if (isMonitorValueBasedOrValueType == TR_maybe)4918{4919generateCheckForValueMonitorEnterOrExit(node, callLabel, objReg, objectClassReg, tempReg, threadReg, condReg, cg, J9_CLASS_DISALLOWS_LOCKING_FLAGS);4920}49214922bool simpleLocking = false;49234924if (lwOffset <= 0)4925{4926generateLoadJ9Class(node, objectClassReg, objReg, cg);49274928int32_t offsetOfLockOffset = offsetof(J9Class, lockOffset);4929TR::MemoryReference *tempMR = TR::MemoryReference::createWithDisplacement(cg, objectClassReg, offsetOfLockOffset, TR::Compiler->om.sizeofReferenceAddress());4930generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, objectClassReg, tempMR);49314932generateTrg1Src1ImmInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, condReg, objectClassReg, 0);49334934if (comp->getOption(TR_EnableMonitorCacheLookup))4935{4936lwOffset = 0;4937generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, monitorLookupCacheLabel, condReg);4938generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, objectClassReg, objReg, objectClassReg);4939generateLabelInstruction(cg, TR::InstOpCode::b, node, fallThruFromMonitorLookupCacheLabel);49404941generateLabelInstruction(cg, TR::InstOpCode::label, node, monitorLookupCacheLabel);49424943int32_t offsetOfMonitorLookupCache = offsetof(J9VMThread, objectMonitorLookupCache);49444945generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, lookupOffsetReg, objReg);49464947int32_t t = trailingZeroes(TR::Compiler->om.getObjectAlignmentInBytes());49484949if (comp->target().is64Bit())4950generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sradi, node, lookupOffsetReg, lookupOffsetReg, t);4951else4952generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::srawi, node, lookupOffsetReg, lookupOffsetReg, t);49534954J9JavaVM * jvm = fej9->getJ9JITConfig()->javaVM;49554956if (comp->target().is64Bit())4957simplifyANDRegImm(node, lookupOffsetReg, lookupOffsetReg, (int64_t) J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, cg, objNode);4958else4959simplifyANDRegImm(node, lookupOffsetReg, lookupOffsetReg, J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, cg, objNode);49604961if (comp->target().is64Bit())4962generateShiftLeftImmediateLong(cg, node, lookupOffsetReg, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));4963else4964generateShiftLeftImmediate(cg, node, lookupOffsetReg, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));49654966generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, lookupOffsetReg, lookupOffsetReg, offsetOfMonitorLookupCache);49674968generateTrg1MemInstruction(cg, (comp->target().is64Bit() && fej9->generateCompressedLockWord()) ? TR::InstOpCode::lwz :TR::InstOpCode::Op_load, node, objectClassReg,4969TR::MemoryReference::createWithIndexReg(cg, metaReg, lookupOffsetReg, TR::Compiler->om.sizeofReferenceField()));49704971generateTrg1Src1ImmInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, condReg, objectClassReg, 0);4972generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg);49734974int32_t offsetOfMonitor = offsetof(J9ObjectMonitor, monitor);4975generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, lookupOffsetReg,4976TR::MemoryReference::createWithDisplacement(cg, objectClassReg, offsetOfMonitor, TR::Compiler->om.sizeofReferenceAddress()));49774978int32_t offsetOfUserData = offsetof(J9ThreadAbstractMonitor, userData);4979generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, lookupOffsetReg,4980TR::MemoryReference::createWithDisplacement(cg, lookupOffsetReg, offsetOfUserData, TR::Compiler->om.sizeofReferenceAddress()));49814982generateTrg1Src2Instruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmp8 : TR::InstOpCode::cmp4, node, condReg, lookupOffsetReg, objReg);4983generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);49844985int32_t offsetOfAlternateLockWord = offsetof(J9ObjectMonitor, alternateLockword);49864987generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, objectClassReg, objectClassReg, offsetOfAlternateLockWord);49884989generateLabelInstruction(cg, TR::InstOpCode::label, node, fallThruFromMonitorLookupCacheLabel);4990}4991else4992{4993generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, callLabel, condReg);4994generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, objectClassReg, objReg, objectClassReg);4995}49964997simpleLocking = true;4998lwOffset = 0;4999baseReg = objectClassReg;5000}50015002/* If the -XX:-GlobalLockReservation option is set, try to use the original aggressive reserved locking code path. */5003if (!fej9->isEnableGlobalLockReservationSet())5004{5005bool reserveLocking = false, normalLockWithReservationPreserving = false;50065007if (!simpleLocking && comp->getOption(TR_ReservingLocks))5008TR::TreeEvaluator::evaluateLockForReservation(node, &reserveLocking, &normalLockWithReservationPreserving, cg);50095010if (reserveLocking)5011return reservationLockExit(node, lwOffset, cg, conditions, baseReg, monitorReg, threadReg, tempReg, condReg, callLabel);5012}50135014int32_t lockSize;5015TR::InstOpCode::Mnemonic loadOpCode, storeOpCode, reservedLoadOpCode, conditionalStoreOpCode, compareLogicalOpCode, compareLogicalImmOpCode;50165017if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())5018{5019lockSize = 8;5020loadOpCode = TR::InstOpCode::ld;5021storeOpCode = TR::InstOpCode::std;5022reservedLoadOpCode = TR::InstOpCode::ldarx;5023conditionalStoreOpCode = TR::InstOpCode::stdcx_r;5024compareLogicalOpCode = TR::InstOpCode::cmpl8;5025compareLogicalImmOpCode = TR::InstOpCode::cmpli8;5026}5027else5028{5029lockSize = 4;5030loadOpCode = TR::InstOpCode::lwz;5031storeOpCode = TR::InstOpCode::stw;5032reservedLoadOpCode = TR::InstOpCode::lwarx;5033conditionalStoreOpCode = TR::InstOpCode::stwcx_r;5034compareLogicalOpCode = TR::InstOpCode::cmpl4;5035compareLogicalImmOpCode = TR::InstOpCode::cmpli4;5036}50375038/*5039* Read only locks do not support either the Reserved bit nor the Learning bit.5040* They are disabled until the code path is updated.5041*/5042if (true || !ppcSupportsReadMonitors || !node->isReadMonitor())5043{5044/*5045* JIT unlocking fast path checks:5046* 1. Check if lockword matches TID and the lower 8 bits are clear. If so, clear lockword to unlock the object.5047* 2. Check if TID matches, Learning bit is clear, and Inflated bit is clear. If not, call VM.5048* 3. Check if RC field is at least 1. If so, decrement RC.5049* 4. All fast path checks failed so go to VM.5050*5051* Check 1 catches Flat-Locked (non-nested, FLC bit clear).5052* Check 2 catches New-PreLearning, New-AutoReserve, Learning-Unlocked, Learning-Locked, Flat-Unlocked and Inflated and sends them to the VM.5053* Check 3 catches Flat-Locked (nested case) and Reserved-Locked.5054* Check 4 catches Reserved-Unlocked and Flat-Locked (non-nested case, FLC bit set) and sends it to the VM.5055*5056*5057* ld/lwz monitorReg, lwOffset(baseReg)5058* li tempReg, 05059* cmpl cr0, monitorReg, metaReg5060* bne decrementCheckLabel5061* lwsync5062* st tempReg, lwOffset(baseReg)5063* b doneLabel5064*5065* decrementCheckLabel:5066* li tempReg, LOCK_NON_PRIMITIVE_EXIT_IGNORE_MASK5067* andc tempReg, monitorReg, tempReg5068* cmpl cr0, tempReg, metaReg5069* bne callLabel5070* andi. tempReg, monitorReg, OBJECT_HEADER_LOCK_RECURSION_MASK5071* beq callLabel5072* addi monitorReg, monitorReg, -LOCK_INC_DEC_VALUE5073* st monitorReg, lwOffset(baseReg)5074*5075* doneLabel:5076* callReturnLabel:5077* === OUT OF LINE ===5078* callLabel:5079* bl jitMonitorExit5080* b callReturnLabel5081*/50825083TR::LabelSymbol *decrementCheckLabel, *doneLabel;50845085decrementCheckLabel = generateLabelSymbol(cg);5086doneLabel = generateLabelSymbol(cg);50875088generateTrg1MemInstruction(cg, loadOpCode, node, monitorReg, TR::MemoryReference::createWithDisplacement(cg, baseReg, lwOffset, lockSize));5089generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, 0);5090generateTrg1Src2Instruction(cg, compareLogicalOpCode, node, condReg, monitorReg, metaReg);5091generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, decrementCheckLabel, condReg);50925093// exiting from read monitors still needs lwsync5094// (ensures loads have completed before releasing lock)5095if (comp->target().isSMP())5096generateInstruction(cg, TR::InstOpCode::lwsync, node);50975098generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, baseReg, lwOffset, lockSize), tempReg);5099generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);51005101generateLabelInstruction(cg, TR::InstOpCode::label, node, decrementCheckLabel);5102generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, LOCK_NON_PRIMITIVE_EXIT_IGNORE_MASK);5103generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, tempReg, monitorReg, tempReg);5104generateTrg1Src2Instruction(cg, compareLogicalOpCode, node, condReg, tempReg, metaReg);5105generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);51065107generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, tempReg, monitorReg, OBJECT_HEADER_LOCK_RECURSION_MASK);5108generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg);51095110generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, monitorReg, monitorReg, -LOCK_INC_DEC_VALUE);5111generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, baseReg, lwOffset, lockSize), monitorReg);51125113generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);51145115doneLabel->setEndInternalControlFlow();51165117TR::LabelSymbol *callReturnLabel = generateLabelSymbol(cg);51185119TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, callReturnLabel, cg);5120cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);51215122generateLabelInstruction(cg, TR::InstOpCode::label, node, callReturnLabel);51235124conditions->stopUsingDepRegs(cg, objReg);5125cg->decReferenceCount(objNode);5126}5127else5128{5129// read-only locks, ReaderReg = 0x0000 00005130// li tempReg, offset5131// lwsync5132// loopLabel:5133// lwarx monitorReg, [baseReg, tempReg]5134// cmpi condReg, monitorReg, 0x6 // count == 1 (flc bit is set)5135// addi threadReg, monitorReg, -45136// beq decLabel5137// stwcx [baseReg, tempReg], threadReg5138// bne loopLabel5139// b doneLabel5140// decLabel: (a misleading name, really a RestoreAndCallLabel)5141// andi_r threadReg, monitorReg, 0x35142// or threadReg, threadReg, metaReg5143// stwcx [baseReg, tempReg], threadReg5144// beq callLabel5145// b loopLabel5146// doneLabel:5147// callReturnLabel:5148// === OUT OF LINE ===5149// callLabel:5150// bl jitMonitorExit5151// b callReturnLabel;51525153TR::LabelSymbol *loopLabel, *decLabel, *doneLabel;5154loopLabel = generateLabelSymbol(cg);5155decLabel = generateLabelSymbol(cg);5156doneLabel = generateLabelSymbol(cg);51575158generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, lwOffset);51595160// exiting from read monitors still needs lwsync5161// (ensures loads have completed before releasing lock)5162if (comp->target().isSMP())5163generateInstruction(cg, TR::InstOpCode::lwsync, node);51645165generateDepLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel, conditions);5166generateTrg1MemInstruction(cg, reservedLoadOpCode, node, monitorReg, TR::MemoryReference::createWithIndexReg(cg, baseReg, tempReg, lockSize));51675168generateTrg1Src1ImmInstruction(cg, compareLogicalImmOpCode, node, condReg, monitorReg, 0x6);5169generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, threadReg, monitorReg, -4);5170generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, decLabel, condReg);51715172generateMemSrc1Instruction(cg, conditionalStoreOpCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, tempReg, lockSize), threadReg);51735174generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, condReg);5175generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);51765177generateLabelInstruction(cg, TR::InstOpCode::label, node, decLabel);5178generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, threadReg, monitorReg, condReg, 0x3);5179generateTrg1Src2Instruction(cg, TR::InstOpCode::OR, node, threadReg, threadReg, metaReg);5180generateMemSrc1Instruction(cg, conditionalStoreOpCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, tempReg, lockSize), threadReg);5181generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg);5182generateLabelInstruction(cg, TR::InstOpCode::b, node, loopLabel);51835184generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);51855186doneLabel->setEndInternalControlFlow();51875188TR::LabelSymbol *callReturnLabel = generateLabelSymbol(cg);51895190TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, callReturnLabel, cg);5191cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);51925193generateLabelInstruction(cg, TR::InstOpCode::label, node, callReturnLabel);51945195conditions->stopUsingDepRegs(cg, objReg);5196cg->decReferenceCount(objNode);5197}51985199return (NULL);5200}52015202static void genInitObjectHeader(TR::Node *node, TR::Instruction *&iCursor, TR_OpaqueClassBlock *clazz, TR::Register *classReg, TR::Register *resReg, TR::Register *zeroReg,5203TR::Register *condReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register * packedClobberedOffset, TR::RegisterDependencyConditions *conditions, bool needZeroInit,5204TR::CodeGenerator *cg);52055206static void genHeapAlloc(TR::Node *node, TR::Instruction *&iCursor, TR_OpaqueClassBlock *clazz, bool isVariableLen, TR::Register *enumReg, TR::Register *classReg, TR::Register *resReg, TR::Register *zeroReg, TR::Register *condReg,5207TR::Register *dataSizeReg, TR::Register *heapTopReg, TR::Register *sizeReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register *temp3Reg, TR::LabelSymbol *callLabel, TR::LabelSymbol *doneLabel,5208int32_t allocSize, int32_t elementSize, bool usingTLH, bool needZeroInit, TR::RegisterDependencyConditions *dependencies, TR::CodeGenerator *cg)5209{5210TR::Compilation *comp = cg->comp();5211TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());5212TR::Register *metaReg = cg->getMethodMetaDataRegister();5213TR::ILOpCodes opCode = node->getOpCodeValue();52145215if (comp->getOptions()->realTimeGC())5216{5217#if defined(J9VM_GC_REALTIME)5218// Use temp3Reg to hold the javaVM.5219iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp3Reg,5220TR::MemoryReference::createWithDisplacement(cg, metaReg, fej9->thisThreadJavaVMOffset(), TR::Compiler->om.sizeofReferenceAddress()), iCursor);52215222// Realtime size classes are now a pointer in J9JavaVM rather than an inlined struct of arrays, so we can't use J9JavaVM as a base pointer anymore5223// Use temp3Reg to hold J9JavaVM->realTimeSizeClasses5224iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp3Reg,5225TR::MemoryReference::createWithDisplacement(cg, temp3Reg, fej9->getRealtimeSizeClassesOffset(), TR::Compiler->om.sizeofReferenceAddress()), iCursor);52265227// heap allocation, so proceed5228if (isVariableLen)5229{5230// make sure size isn't too big5231// convert max object size to num elements because computing an object size from num elements may overflow52325233uintptr_t maxSize = fej9->getMaxObjectSizeForSizeClass();5234TR_ASSERT(((int32_t)(maxSize)-allocSize)/elementSize <= USHRT_MAX, "MaxObjectSizeForSizeClass won't fit into 16-bits.");52355236iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, enumReg, ((int32_t)(maxSize)-allocSize)/elementSize, iCursor);5237iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, callLabel, condReg, iCursor);52385239if (TR::Compiler->om.useHybridArraylets())5240{5241// Zero length arrays are discontiguous (i.e. they also need the discontiguous length field to be 0) because5242// they are indistinguishable from non-zero length discontiguous arrays5243iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, enumReg, 0, iCursor);5244iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg, iCursor);5245}52465247// now compute size of object in bytes5248TR_ASSERT(elementSize == 1 || elementSize == 2 || elementSize == 4 || elementSize == 8 || elementSize == 16, "Illegal element size for genHeapAlloc()");52495250TR::Register *scaledSizeReg = enumReg;52515252if (elementSize > 1)5253{5254iCursor = generateShiftLeftImmediate(cg, node, dataSizeReg, enumReg, trailingZeroes(elementSize), iCursor);5255scaledSizeReg = dataSizeReg;5256}52575258// need to round up to sizeof(UDATA) so we can use it to index into size class index array5259// conservatively just add sizeof(UDATA) bytes and round5260if (elementSize < sizeof(UDATA))5261iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, scaledSizeReg, allocSize + sizeof(UDATA) - 1, iCursor);5262else5263iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, scaledSizeReg, allocSize, iCursor);52645265if (elementSize < sizeof(UDATA))5266{5267if (comp->target().is64Bit())5268iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, dataSizeReg, dataSizeReg, 0, int64_t(-sizeof(UDATA)), iCursor);5269else5270iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, dataSizeReg, dataSizeReg, 0, -sizeof(UDATA), iCursor);5271}52725273#ifdef J9VM_INTERP_FLAGS_IN_CLASS_SLOT5274iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, dataSizeReg, J9_GC_MINIMUM_OBJECT_SIZE, iCursor);5275TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);5276iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, PPCOpProp_BranchLikely, node, doneLabel, condReg, iCursor);5277iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, dataSizeReg, J9_GC_MINIMUM_OBJECT_SIZE, iCursor);5278iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, iCursor);5279#endif52805281// J9JavaVM (or realTimeSizeClasses when J9_CHANGES_PR95193 is defined) + rounded data size + SizeClassesIndexOffset is pointer to the size class5282iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, dataSizeReg, temp3Reg, iCursor);52835284//Now adjust dataSizeReg to only include the size of the array data in bytes, since this will be used in genInitArrayHeader();5285iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, dataSizeReg, -allocSize, iCursor);5286iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, heapTopReg,5287TR::MemoryReference::createWithDisplacement(cg, temp1Reg, fej9->getSizeClassesIndexOffset(), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5288// heapTopReg now holds size class52895290// get next cell for this size class at vmThread + thisThreadAllocationCacheCurrentOffset(0) + (size class)*sizeof(J9VMGCSegregatedAllocationCacheEntry)5291TR_ASSERT(sizeof(J9VMGCSegregatedAllocationCacheEntry) == sizeof(UDATA*) * 2,5292"J9VMGCSegregatedAllocationCacheEntry may need to be padded to avoid multiply in array access.");52935294if (comp->target().is64Bit())5295iCursor = generateShiftLeftImmediateLong(cg, node, temp1Reg, heapTopReg, trailingZeroes((int32_t)sizeof(J9VMGCSegregatedAllocationCacheEntry)), iCursor);5296else5297iCursor = generateShiftLeftImmediate(cg, node, temp1Reg, heapTopReg, trailingZeroes((int32_t)sizeof(J9VMGCSegregatedAllocationCacheEntry)), iCursor);52985299iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, sizeReg, temp1Reg, metaReg, iCursor);5300iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg,5301TR::MemoryReference::createWithDisplacement(cg, sizeReg, fej9->thisThreadAllocationCacheCurrentOffset(0), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5302iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,5303TR::MemoryReference::createWithDisplacement(cg, sizeReg, fej9->thisThreadAllocationCacheTopOffset(0), TR::Compiler->om.sizeofReferenceAddress()), iCursor);53045305// if we've reached the top, then no cell available, use slow path5306iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, resReg, temp1Reg, iCursor);5307iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, callLabel, condReg, iCursor);53085309// have a valid cell, need to update current cell pointer5310if (comp->target().is64Bit())5311iCursor = generateShiftLeftImmediateLong(cg, node, temp1Reg, heapTopReg, trailingZeroes((int32_t)sizeof(UDATA)), iCursor);5312else5313iCursor = generateShiftLeftImmediate(cg, node, temp1Reg, heapTopReg, trailingZeroes((int32_t)sizeof(UDATA)), iCursor);53145315iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, temp1Reg, temp3Reg, iCursor);53165317iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, temp1Reg,5318TR::MemoryReference::createWithDisplacement(cg, temp1Reg, fej9->getSmallCellSizesOffset(), TR::Compiler->om.sizeofReferenceAddress()), iCursor);53195320// temp1Reg now holds cell size5321iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, temp1Reg, resReg, iCursor);53225323//temp1Reg now holds new current cell pointer. Update it in memory:5324iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,5325TR::MemoryReference::createWithDisplacement(cg, sizeReg, fej9->thisThreadAllocationCacheCurrentOffset(0), TR::Compiler->om.sizeofReferenceAddress()), temp1Reg, iCursor);5326}5327else5328{5329// sizeClass will be bogus for variable length allocations because it only includes the header size (+ arraylet ptr for arrays)5330UDATA sizeClass = fej9->getObjectSizeClass(allocSize);53315332iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg, TR::MemoryReference::createWithDisplacement(cg, metaReg,5333fej9->thisThreadAllocationCacheCurrentOffset(sizeClass), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5334iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg, TR::MemoryReference::createWithDisplacement(cg, metaReg,5335fej9->thisThreadAllocationCacheTopOffset(sizeClass), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5336iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, resReg, temp2Reg, iCursor);5337iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, callLabel, condReg, iCursor);53385339//now bump the current updatepointer5340if (fej9->getCellSizeForSizeClass(sizeClass) <= UPPER_IMMED)5341iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp1Reg, resReg, fej9->getCellSizeForSizeClass(sizeClass), iCursor);5342else5343{5344iCursor = loadConstant(cg, node, (int32_t)fej9->getCellSizeForSizeClass(sizeClass), temp1Reg, iCursor);5345iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, temp1Reg, resReg, iCursor);5346}5347iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,5348TR::MemoryReference::createWithDisplacement(cg, metaReg, fej9->thisThreadAllocationCacheCurrentOffset(sizeClass), TR::Compiler->om.sizeofReferenceAddress()), temp1Reg, iCursor);5349}53505351iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, zeroReg, 0, iCursor);53525353//we're done5354return;5355#endif5356} // if (comp->getOptions()->realTimeGC())5357else5358{5359uint32_t maxSafeSize = cg->getMaxObjectSizeGuaranteedNotToOverflow();53605361bool generateArraylets = comp->generateArraylets();5362bool isArrayAlloc = (opCode == TR::newarray || opCode == TR::anewarray);53635364if (isArrayAlloc)5365{5366if (TR::Compiler->om.useHybridArraylets())5367{5368int32_t maxContiguousArraySize = TR::Compiler->om.maxContiguousArraySizeInBytes() / elementSize;5369TR_ASSERT(maxContiguousArraySize >= 0, "Unexpected negative size for max contiguous array size");5370if (maxContiguousArraySize > UPPER_IMMED)5371{5372iCursor = loadConstant(cg, node, maxContiguousArraySize, temp2Reg, iCursor);5373iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, condReg, enumReg, temp2Reg, iCursor);5374}5375else5376iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, enumReg, maxContiguousArraySize, iCursor);53775378iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, callLabel, condReg, iCursor);5379}53805381if (isVariableLen)5382{ // Inline runtime zero length non-packed array allocation5383// Zero length arrays are discontiguous (i.e. they also need the discontiguous length field to be 0) because5384// they are indistinguishable from non-zero length discontiguous arrays5385iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, enumReg, 0, iCursor);5386TR::LabelSymbol *nonZeroLengthLabel = generateLabelSymbol(cg);5387iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, nonZeroLengthLabel, condReg, iCursor);53885389int32_t zeroLenArraySize = (TR::Compiler->om.discontiguousArrayHeaderSizeInBytes() + TR::Compiler->om.getObjectAlignmentInBytes() - 1) & (-TR::Compiler->om.getObjectAlignmentInBytes());5390TR_ASSERT(zeroLenArraySize >= J9_GC_MINIMUM_OBJECT_SIZE, "Zero-length array size must be bigger than MIN_OBJECT_SIZE");5391TR_ASSERT(zeroLenArraySize <= maxSafeSize, "Zero-length array size must be smaller than maxSafeSize");5392// Load TLH heapAlloc and heapTop values.5393iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg,5394TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5395iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, heapTopReg,5396TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapTop), TR::Compiler->om.sizeofReferenceAddress()), iCursor);53975398iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp2Reg, resReg, zeroLenArraySize, iCursor);5399iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp2Reg, heapTopReg, iCursor);5400iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, callLabel, condReg, iCursor);54015402if (comp->compileRelocatableCode())5403genInitObjectHeader(node, iCursor, clazz, classReg, resReg, zeroReg, condReg, heapTopReg, sizeReg, NULL, dependencies, needZeroInit, cg);5404else5405genInitObjectHeader(node, iCursor, clazz, NULL, resReg, zeroReg, condReg, heapTopReg, sizeReg, NULL, dependencies, needZeroInit, cg);54065407UDATA offsetSizeFields = fej9->getOffsetOfDiscontiguousArraySizeField();5408iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,5409TR::MemoryReference::createWithDisplacement(cg, resReg, offsetSizeFields-4, 4), enumReg, iCursor);5410iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,5411TR::MemoryReference::createWithDisplacement(cg, resReg, offsetSizeFields, 4), enumReg, iCursor);54125413iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,5414TR::MemoryReference::createWithDisplacement(cg, metaReg,5415offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), temp2Reg, iCursor);5416iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);5417iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, nonZeroLengthLabel);5418}5419}54205421if (usingTLH)5422{5423bool sizeInReg = (isVariableLen || (allocSize > UPPER_IMMED));5424bool shouldAlignToCacheBoundary = false;5425int32_t instanceBoundaryForAlignment = 64;54265427static bool verboseDualTLH = feGetEnv("TR_verboseDualTLH") != NULL;54285429if (isVariableLen)5430{5431// Detect large or negative number of elements in case addr wrap-around54325433if (maxSafeSize < 0x00100000)5434{5435// NOTE: TR::InstOpCode::bge and the special shifts are used to cover every5436// possible corner cases, with 32byte maximum object header.5437iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, enumReg, (maxSafeSize >> 6) << 2, iCursor);5438iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, callLabel, condReg, iCursor);5439}5440else5441{5442uintptr_t mask;5443if (comp->target().is64Bit())5444{5445mask = 0xFFFFFFFF << (27 - leadingZeroes(maxSafeSize));5446iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm_r, node, temp2Reg, enumReg, condReg, 0, mask, iCursor);5447}5448else5449{5450mask = (0xFFFFFFFF << (11 - leadingZeroes(maxSafeSize))) & 0x0000FFFF;5451iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andis_r, node, temp2Reg, enumReg, condReg, mask, iCursor);5452}5453iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg, iCursor);5454}5455}54565457//TODO: This code is never executed, check if this can be deleted now.5458if (!cg->isDualTLH())5459{5460//All of this code never gets executed because of the 0 && in5461//the inside if statement. Candidate for deletion54625463if (!isVariableLen)5464{5465static char *disableAlign = feGetEnv("TR_DisableAlignAlloc");54665467if (0 && !disableAlign && (node->getOpCodeValue() == TR::New) && (comp->getMethodHotness() >= hot || node->shouldAlignTLHAlloc()))5468{5469TR_OpaqueMethodBlock *ownMethod = node->getOwningMethod();54705471TR::Node *classChild = node->getFirstChild();5472char * className = NULL;5473TR_OpaqueClassBlock *clazz = NULL;54745475if (classChild && classChild->getSymbolReference() && !classChild->getSymbolReference()->isUnresolved())5476{5477TR::SymbolReference *symRef = classChild->getSymbolReference();5478TR::Symbol *sym = symRef->getSymbol();54795480if (sym && sym->getKind() == TR::Symbol::IsStatic && sym->isClassObject())5481{5482TR::StaticSymbol * staticSym = symRef->getSymbol()->castToStaticSymbol();5483void * staticAddress = staticSym->getStaticAddress();5484if (symRef->getCPIndex() >= 0)5485{5486if (!staticSym->addressIsCPIndexOfStatic() && staticAddress)5487{5488int32_t len;5489className = TR::Compiler->cls.classNameChars(comp, symRef, len);5490clazz = (TR_OpaqueClassBlock *) staticAddress;5491}5492}5493}5494}54955496int32_t instanceSizeForAlignment = 56;5497static char *alignSize = feGetEnv("TR_AlignInstanceSize");5498static char *alignBoundary = feGetEnv("TR_AlignInstanceBoundary");54995500if (alignSize)5501instanceSizeForAlignment = atoi(alignSize);5502if (alignBoundary)5503instanceBoundaryForAlignment = atoi(alignBoundary);55045505if (clazz && !cg->getCurrentEvaluationBlock()->isCold() && TR::Compiler->cls.classInstanceSize(clazz) >= instanceSizeForAlignment)5506{5507shouldAlignToCacheBoundary = true;55085509iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,5510TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), iCursor);55115512iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, resReg, temp1Reg, instanceBoundaryForAlignment - 1, iCursor);5513if (comp->target().is64Bit())5514iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, resReg, resReg, 0, int64_t(-instanceBoundaryForAlignment), iCursor);5515else5516iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, resReg, resReg, 0, -instanceBoundaryForAlignment, iCursor);5517}5518}5519}55205521if (!shouldAlignToCacheBoundary)5522{5523iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg,5524TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5525}5526iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, heapTopReg,5527TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapTop), TR::Compiler->om.sizeofReferenceAddress()), iCursor);55285529if (needZeroInit)5530iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, zeroReg, 0, iCursor);55315532}5533else5534{5535//DualTLH support, use nonZeroTLH if optimizer says we can.55365537if (node->canSkipZeroInitialization())5538{55395540if (verboseDualTLH)5541fprintf(stderr, "DELETEME genHeapAlloc useNonZeroTLH [%d] isVariableLen [%d] node: [%p] %s [@%s]\n", 1, isVariableLen, node, comp->signature(),5542comp->getHotnessName(comp->getMethodHotness()));55435544//Load non-zeroed TLH heapAlloc and heapTop values.5545iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg,5546TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, nonZeroHeapAlloc), TR::Compiler->om.sizeofReferenceAddress()), iCursor);55475548iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, heapTopReg,5549TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, nonZeroHeapTop), TR::Compiler->om.sizeofReferenceAddress()), iCursor);55505551}5552else5553{5554if (verboseDualTLH)5555fprintf(stderr, "DELETEME genHeapAlloc useNonZeroTLH [%d] isVariableLen [%d] node: [%p] %s [@%s]\n", 0, isVariableLen, node, comp->signature(),5556comp->getHotnessName(comp->getMethodHotness()));55575558//Load zeroed TLH heapAlloc and heapTop values.5559iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg,5560TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), iCursor);55615562iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, heapTopReg,5563TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapTop), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5564}55655566} //if(!cg->isDualTLH()) == false55675568if (sizeInReg)5569{5570//Size will put into sizeReg5571//Get the size of the object5572//See if we can put into a single arraylet, if not call the helper.5573//Add enough padding to make it a multiple of OBJECT_ALIGNMENT5574if (isVariableLen)5575{5576int32_t elementSize;5577if (comp->useCompressedPointers() && node->getOpCodeValue() == TR::anewarray)5578elementSize = TR::Compiler->om.sizeofReferenceField();5579else5580elementSize = TR::Compiler->om.getSizeOfArrayElement(node);55815582// Check to see if the size of the array will fit in a single arraylet leaf.5583//5584if (generateArraylets && (node->getOpCodeValue() == TR::anewarray || node->getOpCodeValue() == TR::newarray))5585{5586int32_t arrayletLeafSize = TR::Compiler->om.arrayletLeafSize();5587int32_t maxContiguousArrayletLeafSizeInBytes = arrayletLeafSize - TR::Compiler->om.sizeofReferenceAddress(); //need to add definition5588int32_t maxArrayletSizeInElements = maxContiguousArrayletLeafSizeInBytes / elementSize;5589if (maxArrayletSizeInElements <= UPPER_IMMED)5590{5591iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, enumReg, maxArrayletSizeInElements, iCursor);5592}5593else5594{5595iCursor = loadConstant(cg, node, maxArrayletSizeInElements, temp1Reg, iCursor);5596iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, condReg, enumReg, temp1Reg, iCursor);5597}5598static const char *p = feGetEnv("TR_TarokPreLeafSizeCheckVarBreak");5599if (p)5600generateInstruction(cg, TR::InstOpCode::bad, node);56015602iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, callLabel, condReg, iCursor);5603}56045605int32_t round; // zero indicates no rounding is necessary5606round = (elementSize >= TR::Compiler->om.getObjectAlignmentInBytes()) ? 0 : TR::Compiler->om.getObjectAlignmentInBytes();5607bool headerAligned = allocSize % TR::Compiler->om.getObjectAlignmentInBytes() ? 0 : 1;56085609//TODO: The code below pads up the object allocation size so that zero init code later5610//will have multiples of wordsize to work with. For now leaving this code as is, but5611//check if its worthwhile to remove these extra instructions added here for padding as5612//zero init will be removed now.5613if (elementSize >= 2)5614{5615if (comp->target().is64Bit())5616iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldic, node, dataSizeReg, enumReg, trailingZeroes(elementSize), CONSTANT64(0x00000000FFFFFFFF) << trailingZeroes(elementSize));5617else5618iCursor = generateShiftLeftImmediate(cg, node, dataSizeReg, enumReg, trailingZeroes(elementSize), iCursor);56195620}5621if (needZeroInit && elementSize <= 2)5622{5623// the zero initialization code uses a loop of stwu's, and5624// so dataSizeReg must be rounded up to a multiple of 45625if (elementSize == 2)5626iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, dataSizeReg, 3, iCursor);5627else //elementSize == 15628iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, enumReg, 3, iCursor);56295630if (comp->target().is64Bit() && elementSize != 1)5631iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, dataSizeReg, dataSizeReg, 0, int64_t(-4), iCursor);5632else5633iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, dataSizeReg, dataSizeReg, 0, -4, iCursor);5634}56355636if ((round != 0 && (!needZeroInit || round != 4)) || !headerAligned)5637{5638// Round the total size to a multiple of OBJECT_ALIGNMENT5639if (elementSize == 1 && !needZeroInit)5640iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, enumReg, allocSize + round - 1, iCursor);5641else5642iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, dataSizeReg, allocSize + round - 1, iCursor);5643if (comp->target().is64Bit() && elementSize != 1)5644iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, sizeReg, sizeReg, 0, int64_t(-round), iCursor);5645else5646iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, sizeReg, sizeReg, 0, -round, iCursor);5647}5648else5649{5650if (elementSize == 1 && !needZeroInit)5651iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, enumReg, allocSize, iCursor);5652else5653iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, dataSizeReg, allocSize, iCursor);5654}56555656#ifdef J9VM_INTERP_FLAGS_IN_CLASS_SLOT5657if (!((node->getOpCodeValue() == TR::New) || (node->getOpCodeValue() == TR::anewarray) || (node->getOpCodeValue() == TR::newarray)))5658{5659iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, sizeReg, J9_GC_MINIMUM_OBJECT_SIZE, iCursor);5660TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);5661iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, PPCOpProp_BranchLikely, node, doneLabel, condReg, iCursor);56625663iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, sizeReg, J9_GC_MINIMUM_OBJECT_SIZE, iCursor);5664iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, iCursor);5665}5666#endif5667} //if (isVariableLen)5668else5669{5670// Check to see if the size of the array will fit in a single arraylet leaf.5671//5672if (generateArraylets && (node->getOpCodeValue() == TR::anewarray || node->getOpCodeValue() == TR::newarray))5673{5674int32_t arrayletLeafSize = TR::Compiler->om.arrayletLeafSize();56755676if (allocSize >= arrayletLeafSize + TR::Compiler->om.contiguousArrayHeaderSizeInBytes())5677{5678static const char *p = feGetEnv("TR_TarokPreLeafSizeCheckConstBreak");5679if (p)5680generateInstruction(cg, TR::InstOpCode::bad, node);56815682iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, callLabel, iCursor);5683}5684}56855686iCursor = loadConstant(cg, node, allocSize, sizeReg, iCursor);5687}5688} //if (sizeInReg)56895690// Calculate the after-allocation heapAlloc: if the size is huge,5691// we need to check address wrap-around also. This is unsigned5692// integer arithmetic, checking carry bit is enough to detect it.5693// For variable length array, we did an up-front check already.5694if (sizeInReg)5695iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp2Reg, resReg, sizeReg, iCursor);5696else5697iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp2Reg, resReg, allocSize, iCursor);56985699//TODO: shouldAlignToCacheBoundary is never true, check its effects here.5700int32_t padding = shouldAlignToCacheBoundary ? instanceBoundaryForAlignment : 0;57015702if (!isVariableLen && ((uint32_t) allocSize + padding) > maxSafeSize)5703{5704if (!shouldAlignToCacheBoundary)5705iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp2Reg, resReg, iCursor);5706else5707iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp2Reg, temp1Reg, iCursor);5708iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, callLabel, condReg, iCursor);5709}57105711// We need to make sure that the TLH pointer is bumped correctly to support the Arraylet header.5712//5713if (generateArraylets && (node->getOpCodeValue() == TR::anewarray || node->getOpCodeValue() == TR::newarray))5714{5715iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp2Reg, temp2Reg, TR::Compiler->om.getObjectAlignmentInBytes() - 1, iCursor);5716iCursor = generateTrg1Src1Imm2Instruction(cg, comp->target().is64Bit() ? TR::InstOpCode::rldicr : TR::InstOpCode::rlwinm, node, temp2Reg, temp2Reg, 0, int64_t(-TR::Compiler->om.getObjectAlignmentInBytes()), iCursor);5717static const char *p = feGetEnv("TR_TarokAlignHeapTopBreak");5718if (p)5719iCursor = generateInstruction(cg, TR::InstOpCode::bad, node, iCursor);5720}57215722// Ok, temp2Reg now points to where the object will end on the TLH.5723// resReg will contain the start of the object where we'll write out our5724// J9Class*. Should look like this in memory:5725// [heapAlloc == resReg] ... temp2Reg ...//... heapTopReg.57265727//Here we check if we overflow the TLH Heap Top (heapTop, or nonZeroHeapTop)5728//branch to regular heapAlloc Snippet if we overflow (ie callLabel).5729iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp2Reg, heapTopReg, iCursor);5730iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, callLabel, condReg, iCursor);57315732//TODO: this code is never executed, check if we can remove this now.5733if (!cg->isDualTLH())5734{5735//shouldAlignToCacheBoundary is false at definition at the top, and5736//the only codepoint where its set to true is never executed5737//so this looks like a candidate for deletion.5738if (shouldAlignToCacheBoundary)5739{5740TR::LabelSymbol *doneAlignLabel = generateLabelSymbol(cg);5741TR::LabelSymbol *multiSlotGapLabel = generateLabelSymbol(cg);5742;5743iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, dataSizeReg, temp1Reg, resReg, iCursor);57445745if (sizeInReg)5746iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, sizeReg, dataSizeReg, sizeReg, iCursor);5747else5748iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, dataSizeReg, allocSize, iCursor);57495750sizeInReg = true;57515752iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, dataSizeReg, sizeof(uintptr_t), iCursor);5753iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneAlignLabel, condReg, iCursor);5754iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, multiSlotGapLabel, condReg, iCursor);5755iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, dataSizeReg, J9_GC_SINGLE_SLOT_HOLE, iCursor);57565757if (comp->target().is64Bit() && fej9->generateCompressedLockWord())5758{5759iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, 0, 4), dataSizeReg, iCursor);5760iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, 4, 4), dataSizeReg, iCursor);5761}5762else5763{5764iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, 0, TR::Compiler->om.sizeofReferenceAddress()), dataSizeReg,5765iCursor);5766}57675768iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, doneAlignLabel, iCursor);5769iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, multiSlotGapLabel, iCursor);5770iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()),5771dataSizeReg, iCursor);5772iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, dataSizeReg, J9_GC_MULTI_SLOT_HOLE, iCursor);5773iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, 0, TR::Compiler->om.sizeofReferenceAddress()), dataSizeReg,5774iCursor);5775iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, doneAlignLabel, iCursor);5776}5777}57785779if (cg->enableTLHPrefetching())5780{5781//Decide between zeroed and non-zero TLH'es57825783if (cg->isDualTLH() && node->canSkipZeroInitialization())5784{57855786if (verboseDualTLH)5787fprintf(stderr, "DELETEME genHeapAlloc PREFETCH useNonZeroTLH [%d] isVariableLen [%d] node: [%p] %s [@%s]\n", 1, isVariableLen, node, comp->signature(),5788comp->getHotnessName(comp->getMethodHotness()));57895790iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,5791TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, nonZeroTlhPrefetchFTA), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5792}5793else5794{5795if (verboseDualTLH)5796fprintf(stderr, "DELETEME genHeapAlloc PREFETCH useNonZeroTLH [%d] isVariableLen [%d] node: [%p] %s [@%s]\n", 0, isVariableLen, node, comp->signature(),5797comp->getHotnessName(comp->getMethodHotness()));57985799iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,5800TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, tlhPrefetchFTA), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5801}58025803if (sizeInReg)5804iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::subf_r, node, temp1Reg, sizeReg, temp1Reg, condReg, iCursor);5805else5806iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addic_r, node, temp1Reg, temp1Reg, condReg, -allocSize, iCursor);58075808//Write back and allocate Snippet if needed.5809TR::LabelSymbol * callLabel = NULL;5810if (cg->isDualTLH() && node->canSkipZeroInitialization())5811{5812iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,5813TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, nonZeroTlhPrefetchFTA), TR::Compiler->om.sizeofReferenceAddress()), temp1Reg, iCursor);58145815callLabel = cg->lookUpSnippet(TR::Snippet::IsNonZeroAllocPrefetch, NULL);5816if (callLabel == NULL)5817{5818callLabel = generateLabelSymbol(cg);5819TR::Snippet *snippet = new (cg->trHeapMemory()) TR::PPCNonZeroAllocPrefetchSnippet(cg, node, callLabel);5820cg->addSnippet(snippet);5821}5822}5823else5824{5825iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,5826TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, tlhPrefetchFTA), TR::Compiler->om.sizeofReferenceAddress()), temp1Reg, iCursor);58275828callLabel = cg->lookUpSnippet(TR::Snippet::IsAllocPrefetch, NULL);5829if (callLabel == NULL)5830{5831callLabel = generateLabelSymbol(cg);5832TR::Snippet *snippet = new (cg->trHeapMemory()) TR::PPCAllocPrefetchSnippet(cg, node, callLabel);5833cg->addSnippet(snippet);5834}5835}58365837// kills temp1Reg and sizeReg5838iCursor = generateDepConditionalBranchInstruction(cg, TR::InstOpCode::blel, PPCOpProp_BranchUnlikely, node, callLabel, condReg, dependencies, iCursor);58395840cg->machine()->setLinkRegisterKilled(true);5841}58425843//Done, write back to heapAlloc (zero or nonZero TLH) here.5844if (cg->isDualTLH() && node->canSkipZeroInitialization())5845{5846iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,5847TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, nonZeroHeapAlloc), TR::Compiler->om.sizeofReferenceAddress()), temp2Reg, iCursor);5848}5849else5850{5851iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,5852TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), temp2Reg, iCursor);5853}5854}5855else5856{5857bool sizeInReg = (allocSize > UPPER_IMMED);5858TR::LabelSymbol *tryLabel = generateLabelSymbol(cg);58595860iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, heapTopReg,5861TR::MemoryReference::createWithDisplacement(cg, temp1Reg, offsetof(J9MemorySegment, heapTop), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5862iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, temp1Reg, offsetof(J9MemorySegment, heapAlloc), iCursor);5863iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, zeroReg, 0, iCursor);5864if (sizeInReg)5865{5866if (0x00008000 == HI_VALUE(allocSize))5867{5868iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, sizeReg, 0x7FFF, iCursor);5869iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, sizeReg, sizeReg, 0x1, iCursor);5870}5871else5872{5873iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, sizeReg, HI_VALUE(allocSize), iCursor);5874}5875iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, sizeReg, LO_VALUE(allocSize), iCursor);5876}58775878// Try to allocate5879iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, tryLabel, iCursor);5880iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg, TR::MemoryReference::createWithDisplacement(cg, dataSizeReg, 0, TR::Compiler->om.sizeofReferenceAddress()), iCursor);58815882// Calculate the after-allocation heapAlloc: if the size is huge,5883// we need to check address wrap-around also. This is unsigned5884// integer arithmetic, checking carry bit is enough to detect it.5885if ((uint32_t) allocSize > maxSafeSize)5886{5887if (sizeInReg)5888{5889iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, resReg, sizeReg, iCursor);5890}5891else5892{5893iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp1Reg, resReg, allocSize, iCursor);5894}58955896iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp1Reg, resReg, iCursor);58975898iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, callLabel, condReg, iCursor);5899}5900else5901{5902if (sizeInReg)5903{5904iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, resReg, sizeReg, iCursor);5905}5906else5907{5908iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp1Reg, resReg, allocSize, iCursor);5909}5910}59115912iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp1Reg, heapTopReg, iCursor);5913iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, callLabel, condReg, iCursor);59145915// todo64: I think these need to be ldarx/stdcx. in 64-bit mode5916iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::lwarx, node, temp2Reg, TR::MemoryReference::createWithIndexReg(cg, dataSizeReg, zeroReg, 4), iCursor);5917iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, condReg, temp2Reg, resReg, iCursor);5918iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, tryLabel, condReg, iCursor);5919iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stwcx_r, node, TR::MemoryReference::createWithIndexReg(cg, dataSizeReg, zeroReg, 4), temp1Reg, iCursor);59205921iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, tryLabel, condReg, iCursor);5922}5923}5924}592559265927static void genInitObjectHeader(TR::Node *node, TR::Instruction *&iCursor, TR_OpaqueClassBlock *clazz, TR::Register *classReg, TR::Register *resReg, TR::Register *zeroReg,5928TR::Register *condReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register * packedClobberedOffset, TR::RegisterDependencyConditions *conditions, bool needZeroInit,5929TR::CodeGenerator *cg)5930{5931TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());5932J9ROMClass *romClass = 0;5933uint32_t staticFlag = 0;5934uint32_t orFlag = 0;5935TR::Compilation *comp = cg->comp();59365937TR_ASSERT(clazz, "Cannot have a null OpaqueClassBlock\n");5938romClass = TR::Compiler->cls.romClassOf(clazz);5939staticFlag = romClass->instanceShape;5940TR::Register *metaReg = cg->getMethodMetaDataRegister();59415942TR::Register * clzReg = classReg;59435944if (comp->compileRelocatableCode() && !comp->getOption(TR_UseSymbolValidationManager))5945{5946if (node->getOpCodeValue() == TR::newarray)5947{5948iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,5949TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, javaVM), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5950iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,5951TR::MemoryReference::createWithDisplacement(cg, temp1Reg, ((TR_J9VM *) fej9)->getPrimitiveArrayOffsetInJavaVM(node->getSecondChild()->getInt()),5952TR::Compiler->om.sizeofReferenceAddress()), iCursor);5953clzReg = temp1Reg;5954}5955else if (node->getOpCodeValue() == TR::anewarray)5956{5957TR_ASSERT(classReg, "must have a classReg for TR::anewarray in AOT mode");5958iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,5959TR::MemoryReference::createWithDisplacement(cg, classReg, offsetof(J9Class, arrayClass), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5960clzReg = temp1Reg;5961}5962else5963{5964TR_ASSERT(node->getOpCodeValue() == TR::New && classReg, "must have a classReg for TR::New in AOT mode");5965clzReg = classReg;5966}5967}59685969// Store the class5970if (clzReg == NULL)5971{5972// HCR in genInitObjectHeader5973if (cg->wantToPatchClassPointer(clazz, node))5974{5975iCursor = loadAddressConstantInSnippet(cg, node, (int64_t) clazz, temp1Reg, temp2Reg,TR::InstOpCode::Op_load, false, iCursor);5976iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, temp1Reg, temp1Reg, orFlag, iCursor);5977}5978else5979{5980#ifdef TR_TARGET_64BIT5981int32_t offset;5982intptr_t classPtr = (intptr_t)clazz;59835984offset = TR_PPCTableOfConstants::lookUp((int8_t *)&classPtr, sizeof(intptr_t), true, 0, cg);59855986if (offset != PTOC_FULL_INDEX)5987{5988offset *= TR::Compiler->om.sizeofReferenceAddress();5989if (TR_PPCTableOfConstants::getTOCSlot(offset) == 0)5990TR_PPCTableOfConstants::setTOCSlot(offset, (int64_t)clazz);5991if (offset<LOWER_IMMED||offset>UPPER_IMMED)5992{5993TR_ASSERT_FATAL_WITH_NODE(node, 0x00008000 != HI_VALUE(offset), "TOC offset (0x%x) is unexpectedly high. Can not encode upper 16 bits into an addis instruction.", offset);5994iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, temp1Reg, cg->getTOCBaseRegister(), HI_VALUE(offset), iCursor);5995iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, LO_VALUE(offset), TR::Compiler->om.sizeofReferenceAddress()), iCursor);5996}5997else5998{5999iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg, TR::MemoryReference::createWithDisplacement(cg, cg->getTOCBaseRegister(), offset, TR::Compiler->om.sizeofReferenceAddress()), iCursor);6000}6001if (orFlag != 0)6002{6003iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, temp1Reg, temp1Reg, orFlag, iCursor);6004}6005}6006else6007{6008iCursor = loadConstant(cg, node, (int64_t)clazz|(int64_t)orFlag, temp1Reg, iCursor);6009}6010#else6011iCursor = loadConstant(cg, node, (int32_t) clazz | (int32_t) orFlag, temp1Reg, iCursor);6012#endif /* TR_TARGET_64BIT */6013}6014if (TR::Compiler->om.compressObjectReferences())6015// must store only 32 bits6016iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,6017TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4),6018temp1Reg, iCursor);6019else6020iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,6021TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), TR::Compiler->om.sizeofReferenceAddress()), temp1Reg, iCursor);6022}6023else6024{6025if (orFlag != 0)6026{6027iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, clzReg, clzReg, orFlag, iCursor);6028}6029if (TR::Compiler->om.compressObjectReferences())6030// must store only 32 bits6031iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,6032TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4),6033clzReg, iCursor);6034else6035iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,6036TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), TR::Compiler->om.sizeofReferenceAddress()), clzReg, iCursor);6037}603860396040#ifndef J9VM_INTERP_FLAGS_IN_CLASS_SLOT60416042bool isStaticFlag = fej9->isStaticObjectFlags();6043if (isStaticFlag)6044{6045// The object flags can be determined at compile time.6046staticFlag |= fej9->getStaticObjectFlags();6047if (staticFlag != 0 || needZeroInit)6048{6049iCursor = loadConstant(cg, node, (int32_t) staticFlag, temp2Reg, iCursor);6050// Store the flags6051iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t) TMP_OFFSETOF_J9OBJECT_FLAGS, 4, cg), temp2Reg,6052iCursor);6053}6054}6055else if (!comp->getOptions()->realTimeGC())6056{6057// If the object flags cannot be determined at compile time, we add a load for it.6058//6059iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg,6060TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, allocateThreadLocalHeap.objectFlags), TR::Compiler->om.sizeofReferenceAddress()), iCursor);60616062// OR staticFlag with temp2Reg.6063// For now, only the lower 16 bits are set in staticFlag. But check the higher 16 bits just in case.6064if (staticFlag != 0)6065{6066if ((staticFlag & 0xFFFF0000) != 0)6067{6068iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::oris, node, temp2Reg, temp2Reg, (staticFlag >> 16) & 0x0000FFFF, iCursor);6069}6070if ((staticFlag & 0x0000FFFF) != 0)6071{6072iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, temp2Reg, temp2Reg, staticFlag & 0x0000FFFF, iCursor);6073}6074}6075iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t) TMP_OFFSETOF_J9OBJECT_FLAGS, 4), temp2Reg,6076iCursor);6077}60786079#endif /*J9VM_INTERP_FLAGS_IN_CLASS_SLOT*/60806081TR::InstOpCode::Mnemonic storeOpCode;6082int32_t lockSize;60836084if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())6085{6086storeOpCode = TR::InstOpCode::std;6087lockSize = 8;6088}6089else6090{6091storeOpCode = TR::InstOpCode::stw;6092lockSize = 4;6093}60946095int32_t lwOffset = fej9->getByteOffsetToLockword(clazz);6096if (clazz && (lwOffset > 0))6097{6098int32_t lwInitialValue = fej9->getInitialLockword(clazz);60996100if (0 != lwInitialValue)6101{6102iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, temp1Reg, lwInitialValue, iCursor);6103iCursor = generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, resReg, lwOffset, lockSize), temp1Reg, iCursor);6104}6105}6106}61076108static void genAlignArray(TR::Node *node, TR::Instruction *&iCursor, bool isVariableLen, TR::Register *resReg, int32_t objectSize, int32_t dataBegin, TR::Register *dataSizeReg,6109TR::Register *condReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::CodeGenerator *cg)6110{6111TR::LabelSymbol *slotAtStart = generateLabelSymbol(cg);6112TR::LabelSymbol *doneAlign = generateLabelSymbol(cg);61136114iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, temp1Reg, resReg, condReg, 7, iCursor);6115iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, temp2Reg, 3, iCursor);6116iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, slotAtStart, condReg, iCursor);61176118// The slop bytes are at the end of the allocated object.6119if (isVariableLen)6120{6121iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, resReg, dataSizeReg, iCursor);6122iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, dataBegin, 4), temp2Reg, iCursor);6123}6124else if (objectSize > UPPER_IMMED)6125{6126iCursor = loadConstant(cg, node, objectSize, temp1Reg, iCursor);6127iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithIndexReg(cg, resReg, temp1Reg, 4), temp2Reg, iCursor);6128}6129else6130{6131iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, objectSize, 4), temp2Reg, iCursor);6132}6133iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, doneAlign, iCursor);61346135// the slop bytes are at the start of the allocation6136iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, slotAtStart, iCursor);6137iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t) 0, 4), temp2Reg, iCursor);6138iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, resReg, resReg, 4, iCursor);6139iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, doneAlign, iCursor);6140}61416142static void genInitArrayHeader(TR::Node *node, TR::Instruction *&iCursor, bool isVariableLen, TR_OpaqueClassBlock *clazz, TR::Register *classReg, TR::Register *resReg,6143TR::Register *zeroReg, TR::Register *condReg, TR::Register *eNumReg, TR::Register *dataSizeReg, TR::Register *temp1Reg, TR::Register *temp2Reg,6144TR::RegisterDependencyConditions *conditions, bool needZeroInit, TR::CodeGenerator *cg)6145{6146TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());6147TR::Register *instanceSizeReg;61486149genInitObjectHeader(node, iCursor, clazz, classReg, resReg, zeroReg, condReg, temp1Reg, temp2Reg, NULL, conditions, needZeroInit, cg);61506151instanceSizeReg = eNumReg;61526153if ((node->getOpCodeValue() == TR::newarray || node->getOpCodeValue() == TR::anewarray) && node->getFirstChild()->getOpCode().isLoadConst() && (node->getFirstChild()->getInt() == 0))6154{// constant zero length non-packed array6155// Zero length arrays are discontiguous (i.e. they also need the discontiguous length field to be 0) because6156// they are indistinguishable from non-zero length discontiguous arrays6157iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,6158TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getOffsetOfDiscontiguousArraySizeField()-4, 4),6159instanceSizeReg, iCursor);6160iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,6161TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getOffsetOfDiscontiguousArraySizeField(), 4),6162instanceSizeReg, iCursor);6163}6164else6165{6166// Store the array size6167iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,6168TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getOffsetOfContiguousArraySizeField(), 4),6169instanceSizeReg, iCursor);6170}6171}61726173static void genZeroInit(TR::CodeGenerator *cg, TR::Node *node, TR::Register *objectReg, int32_t headerSize, int32_t totalSize, bool useInitInfo)6174{6175TR_ASSERT((totalSize - headerSize > 0) && ((totalSize - headerSize) % 4 == 0), "Expecting non-zero word-aligned data size");61766177TR::Register *zeroReg = cg->allocateRegister();6178TR::Compilation* comp = cg->comp();61796180generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, zeroReg, 0);61816182// Perform initialization if it is needed:6183// 1) Initialize certain array elements individually. This depends on the optimizer6184// providing a "short" list of individual indices;6185// 2) Initialize the whole array:6186// a) If the object size is constant and small use straight line code;6187// b) For large objects and variable length arrays, do nothing, it was handled in the allocation helper.6188if (useInitInfo)6189{6190TR_ExtraInfoForNew *initInfo = node->getSymbolReference()->getExtraInfo();61916192TR_ASSERT(initInfo && initInfo->zeroInitSlots && initInfo->numZeroInitSlots > 0, "Expecting valid init info");61936194TR_BitVectorIterator bvi(*initInfo->zeroInitSlots);6195if (comp->target().is64Bit())6196{6197int32_t lastNotInit = -1;6198int32_t currElem = -1;61996200// Try to group set of words into smallest groupings using double-word stores (where possible)6201while (bvi.hasMoreElements())6202{6203currElem = bvi.getNextElement();62046205if (lastNotInit == -1)6206{6207// currently looking at only one slot (either just starting, or just emitted double-word store in last iter)6208lastNotInit = currElem;6209}6210else if (currElem == lastNotInit + 1)6211{6212// consecutive slots, can use std6213generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, headerSize + lastNotInit * 4, 8), zeroReg);6214lastNotInit = -1;6215}6216else6217{6218// Two non-consecutive slots, use stw for earlier slot and keep looking for slot6219// consecutive with the second slot currently held6220generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, headerSize + lastNotInit * 4, 4), zeroReg);6221lastNotInit = currElem;6222}6223}62246225if (lastNotInit != -1)6226{6227// Last slot is not consecutive with other slots, hasn't been initialized yet6228generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, headerSize + lastNotInit * 4, 4), zeroReg);6229}6230}6231else6232{6233while (bvi.hasMoreElements())6234{6235generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,6236TR::MemoryReference::createWithDisplacement(cg, objectReg, headerSize + bvi.getNextElement() * TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()), zeroReg);6237}6238}6239}6240else6241{6242int32_t ofs;6243for (ofs = headerSize; ofs < totalSize - TR::Compiler->om.sizeofReferenceAddress(); ofs += TR::Compiler->om.sizeofReferenceAddress())6244{6245generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, ofs, TR::Compiler->om.sizeofReferenceAddress()), zeroReg);6246}6247if (ofs + 4 == totalSize)6248generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, ofs, 4), zeroReg);6249else if (ofs + 8 == totalSize)6250generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, ofs, 8), zeroReg);6251}62526253// Scheduling barrier6254generateLabelInstruction(cg, TR::InstOpCode::label, node, generateLabelSymbol(cg));62556256cg->stopUsingRegister(zeroReg);6257}62586259TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeGenerator *cg)6260{6261TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());6262int32_t allocateSize, objectSize, dataBegin, idx;6263TR::ILOpCodes opCode;6264TR_OpaqueClassBlock *clazz;6265TR::Register *classReg, *resReg, *zeroReg = NULL;6266TR::RealRegister::RegNum resultRealReg = TR::RealRegister::gr8;6267TR::Register *condReg, *callResult, *enumReg, *dataSizeReg;6268TR::Register *tmp3Reg = NULL, *tmp4Reg, *tmp5Reg, *tmp6Reg, *tmp7Reg = NULL;6269TR::Register *packedRegAddr, *packedRegOffs, *packedRegLength;6270TR::LabelSymbol *callLabel, *callReturnLabel, *doneLabel;6271TR::RegisterDependencyConditions *conditions;6272TR::Instruction *iCursor = NULL;6273bool doInline = true, isArray = false, doublewordAlign = false;6274bool isVariableLen;6275bool insertType = false;6276static bool TR_noThreadLocalHeap = feGetEnv("TR_noThreadLocalHeap") ? 1 : 0;6277TR::Compilation * comp = cg->comp();6278bool generateArraylets = comp->generateArraylets();62796280if (comp->getOption(TR_DisableTarokInlineArrayletAllocation) && (node->getOpCodeValue() == TR::anewarray || node->getOpCodeValue() == TR::newarray))6281doInline = false;62826283bool usingTLH = !TR_noThreadLocalHeap;6284bool needZeroInit = (!usingTLH || !fej9->tlhHasBeenCleared()) || comp->getOptions()->realTimeGC();6285bool isDualTLH = cg->isDualTLH();62866287int32_t elementSize = 0;62886289opCode = node->getOpCodeValue();6290objectSize = comp->canAllocateInline(node, clazz);62916292bool isArrayAlloc = (opCode == TR::newarray || opCode == TR::anewarray);6293bool isConstantLenArrayAlloc = isArrayAlloc && node->getFirstChild()->getOpCode().isLoadConst();6294bool isConstantZeroLenArrayAlloc = isConstantLenArrayAlloc && (node->getFirstChild()->getInt() == 0);62956296TR_ASSERT(objectSize <= 0 || (objectSize & (TR::Compiler->om.sizeofReferenceAddress() - 1)) == 0, "object size causes an alignment problem");6297if (objectSize < 0 || (objectSize == 0 && !usingTLH))6298doInline = false;6299isVariableLen = (objectSize == 0);63006301allocateSize = objectSize;63026303if (opCode == TR::New)6304{6305if (comp->getOptions()->realTimeGC())6306{6307if (objectSize > fej9->getMaxObjectSizeForSizeClass())6308{6309doInline = false;6310}6311}6312}63136314if (!isVariableLen)6315{6316allocateSize = (allocateSize + TR::Compiler->om.getObjectAlignmentInBytes() - 1) & (-TR::Compiler->om.getObjectAlignmentInBytes());6317}63186319if (comp->compileRelocatableCode())6320{6321switch (opCode)6322{6323case TR::New: break;6324case TR::anewarray: break;6325case TR::newarray: break;6326default: doInline = false; break;6327}6328}63296330static int count = 0;6331doInline = doInline && performTransformation(comp, "O^O <%3d> Inlining Allocation of %s [0x%p].\n", count++, node->getOpCode().getName(), node);63326333if (doInline)6334{6335generateLabelInstruction(cg, TR::InstOpCode::label, node, generateLabelSymbol(cg));63366337callLabel = generateLabelSymbol(cg);6338callReturnLabel = generateLabelSymbol(cg);6339doneLabel = generateLabelSymbol(cg);6340conditions = createConditionsAndPopulateVSXDeps(cg, 14);63416342TR::Node *firstChild = node->getFirstChild();6343TR::Node *secondChild = NULL;63446345if (opCode == TR::New)6346{6347// classReg is passed to the VM helper on the slow path and subsequently clobbered; copy it for later nodes if necessary6348classReg = cg->gprClobberEvaluate(firstChild);6349dataBegin = TR::Compiler->om.objectHeaderSizeInBytes();6350}6351else6352{6353TR_ASSERT(opCode == TR::newarray || opCode == TR::anewarray, "Bad opCode for VMnewEvaluator");6354isArray = true;6355if (generateArraylets || TR::Compiler->om.useHybridArraylets())6356{6357if (node->getOpCodeValue() == TR::newarray)6358elementSize = TR::Compiler->om.getSizeOfArrayElement(node);6359else if (comp->useCompressedPointers())6360elementSize = TR::Compiler->om.sizeofReferenceField();6361else6362elementSize = TR::Compiler->om.sizeofReferenceAddress();63636364if (generateArraylets)6365dataBegin = fej9->getArrayletFirstElementOffset(elementSize, comp);6366else6367dataBegin = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();6368static const char *p = feGetEnv("TR_TarokDataBeginBreak");6369if (p)6370TR_ASSERT(false, "Hitting Arraylet Data Begin Break");6371}6372else6373{6374dataBegin = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();6375}6376secondChild = node->getSecondChild();6377enumReg = cg->evaluate(firstChild);63786379insertType = (opCode == TR::newarray && secondChild->getDataType() == TR::Int32 && secondChild->getReferenceCount() == 1 && secondChild->getOpCode().isLoadConst());63806381if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager))6382{6383// IMPORTANT: secondChild actually references the J9Class of the array *elements* rather6384// than the J9Class of the array itself; the new AOT infrastructure requires that6385// classReg contain the J9Class of the array, so we have to actually construct a new6386// loadaddr for that and then evaluate it instead of evaluating secondChild directly.6387// Note that the original secondChild *must still be evaluated* as it will be used in6388// the out-of-line code section.6389TR::StaticSymbol *classSymbol = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);6390classSymbol->setStaticAddress(clazz);6391classSymbol->setClassObject();63926393cg->evaluate(secondChild);6394secondChild = TR::Node::createWithSymRef(TR::loadaddr, 0,6395new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), classSymbol));6396secondChild->incReferenceCount();63976398classReg = cg->evaluate(secondChild);6399}6400else if (insertType)6401{6402classReg = cg->allocateRegister();6403}6404else6405{6406// classReg is passed to the VM helper on the slow path and subsequently clobbered; copy it for later nodes if necessary6407classReg = cg->gprClobberEvaluate(secondChild);6408}6409}6410TR::addDependency(conditions, classReg, TR::RealRegister::NoReg, TR_GPR, cg);6411conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();64126413if (secondChild == NULL)6414enumReg = cg->allocateRegister();6415TR::addDependency(conditions, enumReg, TR::RealRegister::NoReg, TR_GPR, cg);6416conditions->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0();64176418condReg = cg->allocateRegister(TR_CCR);6419TR::addDependency(conditions, condReg, TR::RealRegister::cr0, TR_CCR, cg);6420tmp6Reg = cg->allocateRegister();6421TR::addDependency(conditions, tmp6Reg, TR::RealRegister::NoReg, TR_GPR, cg);6422tmp4Reg = cg->allocateRegister();6423TR::addDependency(conditions, tmp4Reg, TR::RealRegister::gr11, TR_GPR, cg); // used by TR::PPCAllocPrefetchSnippet6424tmp5Reg = cg->allocateRegister();6425TR::addDependency(conditions, tmp5Reg, TR::RealRegister::NoReg, TR_GPR, cg);6426conditions->getPostConditions()->getRegisterDependency(5)->setExcludeGPR0();6427resReg = cg->allocateRegister();6428TR::addDependency(conditions, resReg, resultRealReg, TR_GPR, cg); // used by TR::PPCAllocPrefetchSnippet6429conditions->getPostConditions()->getRegisterDependency(6)->setExcludeGPR0();6430dataSizeReg = cg->allocateRegister();6431TR::addDependency(conditions, dataSizeReg, TR::RealRegister::NoReg, TR_GPR, cg);6432conditions->getPostConditions()->getRegisterDependency(7)->setExcludeGPR0();6433tmp7Reg = cg->allocateRegister();6434TR::addDependency(conditions, tmp7Reg, TR::RealRegister::NoReg, TR_GPR, cg);6435conditions->getPostConditions()->getRegisterDependency(8)->setExcludeGPR0();6436tmp3Reg = cg->allocateRegister();6437TR::addDependency(conditions, tmp3Reg, TR::RealRegister::gr10, TR_GPR, cg); // used by TR::PPCAllocPrefetchSnippet64386439TR::Instruction *firstInstruction = cg->getAppendInstruction();64406441if (!isDualTLH && needZeroInit)6442{6443zeroReg = cg->allocateRegister();6444TR::addDependency(conditions, zeroReg, TR::RealRegister::NoReg, TR_GPR, cg);6445}64466447if (isVariableLen)6448allocateSize += dataBegin;64496450//Here we set up backout paths if we overflow nonZeroTLH in genHeapAlloc.6451//If we overflow the nonZeroTLH, set the destination to the right VM runtime helper (eg jitNewObjectNoZeroInit, etc...)6452//The zeroed-TLH versions have their correct destinations already setup in TR_ByteCodeIlGenerator::genNew, TR_ByteCodeIlGenerator::genNewArray, TR_ByteCodeIlGenerator::genANewArray6453//To retrieve the destination node->getSymbolReference() is used below after genHeapAlloc.6454if (isDualTLH && node->canSkipZeroInitialization())6455{6456// For value types, the backout path should call jitNewValue helper call which is set up before code gen6457if ((node->getOpCodeValue() == TR::New)6458&& (!TR::Compiler->om.areValueTypesEnabled() || (node->getSymbolReference() != comp->getSymRefTab()->findOrCreateNewValueSymbolRef(comp->getMethodSymbol()))))6459node->setSymbolReference(comp->getSymRefTab()->findOrCreateNewObjectNoZeroInitSymbolRef(comp->getMethodSymbol()));6460else if (node->getOpCodeValue() == TR::newarray)6461node->setSymbolReference(comp->getSymRefTab()->findOrCreateNewArrayNoZeroInitSymbolRef(comp->getMethodSymbol()));6462else if (node->getOpCodeValue() == TR::anewarray)6463node->setSymbolReference(comp->getSymRefTab()->findOrCreateANewArrayNoZeroInitSymbolRef(comp->getMethodSymbol()));6464}64656466// On return, zeroReg is set to 0 if needZeroInit is true, and6467// dataSizeReg is set to the size of data area if isVariableLen6468// is true, and either elementSize != 1 or needZeroInit is true6469// (and we only ever use dataSizeReg below in those cases).6470genHeapAlloc(node, iCursor, clazz, isVariableLen, enumReg, classReg, resReg, zeroReg, condReg, dataSizeReg, tmp5Reg, tmp4Reg, tmp3Reg, tmp6Reg, tmp7Reg, callLabel, doneLabel, allocateSize, elementSize,6471usingTLH, needZeroInit, conditions, cg);64726473// Call out to VM runtime helper if needed.6474TR::Register *objReg = cg->allocateCollectedReferenceRegister();6475TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::acall, objReg, callLabel, callReturnLabel, cg);6476cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);64776478if (isArray)6479{6480// Align the array if necessary.6481if (doublewordAlign && !comp->getOptions()->realTimeGC())6482genAlignArray(node, iCursor, isVariableLen, resReg, objectSize, dataBegin, dataSizeReg, condReg, tmp5Reg, tmp4Reg, cg);6483if (comp->compileRelocatableCode() && (opCode == TR::anewarray || comp->getOption(TR_UseSymbolValidationManager)))6484genInitArrayHeader(node, iCursor, isVariableLen, clazz, classReg, resReg, zeroReg, condReg, enumReg, dataSizeReg, tmp5Reg, tmp4Reg, conditions, needZeroInit, cg);6485else6486genInitArrayHeader(node, iCursor, isVariableLen, clazz, NULL, resReg, zeroReg, condReg, enumReg, dataSizeReg,6487tmp5Reg, tmp4Reg, conditions, needZeroInit, cg);64886489#ifdef TR_TARGET_64BIT6490/* Here we'll update dataAddr slot for both fixed and variable length arrays. Fixed length arrays are6491* simple as we just need to check first child of the node for array size. For variable length arrays6492* runtime size checks are needed to determine whether to use contiguous or discontiguous header layout.6493*6494* In both scenarios, arrays of non-zero size use contiguous header layout while zero size arrays use6495* discontiguous header layout.6496*/6497TR::Register *offsetReg = tmp5Reg;6498TR::Register *firstDataElementReg = tmp4Reg;6499TR::MemoryReference *dataAddrSlotMR = NULL;65006501if (isVariableLen && TR::Compiler->om.compressObjectReferences())6502{6503/* We need to check enumReg at runtime to determine correct offset of dataAddr field.6504* Here we deal only with compressed refs because dataAddr offset for discontiguous6505* and contiguous arrays is the same in full refs.6506*/6507if (comp->getOption(TR_TraceCG))6508traceMsg(comp, "Node (%p): Dealing with compressed refs variable length array.\n", node);65096510TR_ASSERT_FATAL_WITH_NODE(node, (fej9->getOffsetOfDiscontiguousDataAddrField() - fej9->getOffsetOfContiguousDataAddrField()) == 8,6511"Offset of dataAddr field in discontiguous array is expected to be 8 bytes more than contiguous array. But was %d bytes for discontigous and %d bytes for contiguous array.\n", fej9->getOffsetOfDiscontiguousDataAddrField(), fej9->getOffsetOfContiguousDataAddrField());65126513iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::cntlzd, node, offsetReg, enumReg, iCursor);6514iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, offsetReg, offsetReg, 29, 8, iCursor);6515// offsetReg should either be 0 (if enumReg > 0) or 8 (if enumReg == 0)6516iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, offsetReg, resReg, offsetReg, iCursor);65176518iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, firstDataElementReg, offsetReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), iCursor);6519dataAddrSlotMR = TR::MemoryReference::createWithDisplacement(cg, offsetReg, fej9->getOffsetOfContiguousDataAddrField(), TR::Compiler->om.sizeofReferenceAddress());6520}6521else if (!isVariableLen && node->getFirstChild()->getOpCode().isLoadConst() && node->getFirstChild()->getInt() == 0)6522{6523if (comp->getOption(TR_TraceCG))6524traceMsg(comp, "Node (%p): Dealing with full/compressed refs fixed length zero size array.\n", node);65256526iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, firstDataElementReg, resReg, TR::Compiler->om.discontiguousArrayHeaderSizeInBytes(), iCursor);6527dataAddrSlotMR = TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getOffsetOfDiscontiguousDataAddrField(), TR::Compiler->om.sizeofReferenceAddress());6528}6529else6530{6531if (comp->getOption(TR_TraceCG))6532traceMsg(comp, "Node (%p): Dealing with either full/compressed refs fixed length non-zero size array or full refs variable length array.\n", node);65336534if (!TR::Compiler->om.compressObjectReferences())6535TR_ASSERT_FATAL_WITH_NODE(node, fej9->getOffsetOfDiscontiguousDataAddrField() == fej9->getOffsetOfContiguousDataAddrField(), "dataAddr field offset is expected to be same for both contiguous and discontiguous arrays in full refs. But was %d bytes for discontiguous and %d bytes for contiguous array.\n", fej9->getOffsetOfDiscontiguousDataAddrField(), fej9->getOffsetOfContiguousDataAddrField());65366537iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, firstDataElementReg, resReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), iCursor);6538dataAddrSlotMR = TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getOffsetOfContiguousDataAddrField(), TR::Compiler->om.sizeofReferenceAddress());6539}65406541// store the first data element address to dataAddr slot6542iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, dataAddrSlotMR, firstDataElementReg, iCursor);6543#endif /* TR_TARGET_64BIT */65446545if (generateArraylets)6546{6547//write arraylet pointer to object header6548static const char *p = feGetEnv("TR_TarokPreWritePointerBreak");6549if (p)6550generateInstruction(cg, TR::InstOpCode::bad, node);65516552iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, resReg, dataBegin, iCursor);6553if (TR::Compiler->om.compressedReferenceShiftOffset() > 0)6554iCursor = generateShiftRightLogicalImmediateLong(cg, node, tmp4Reg, tmp4Reg, TR::Compiler->om.compressedReferenceShiftOffset(), iCursor);6555iCursor = generateMemSrc1Instruction(cg, (comp->target().is64Bit() && !comp->useCompressedPointers()) ? TR::InstOpCode::std : TR::InstOpCode::stw, node,6556TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getFirstArrayletPointerOffset(comp), comp->useCompressedPointers() ? 4 : TR::Compiler->om.sizeofReferenceAddress()), tmp4Reg, iCursor);6557static const char *p1 = feGetEnv("TR_TarokPostWritePointerBreak");6558if (p1)6559generateInstruction(cg, TR::InstOpCode::bad, node);6560}6561}6562else6563{6564genInitObjectHeader(node, iCursor, clazz, classReg, resReg, zeroReg, condReg, tmp5Reg, tmp4Reg, packedRegOffs, conditions, needZeroInit, cg);6565}65666567//Do not need zero init if using dualTLH now.6568if (!isDualTLH && needZeroInit && (!isConstantZeroLenArrayAlloc))6569{6570// Perform initialization if it is needed:6571// 1) Initialize certain array elements individually. This depends on the optimizer6572// providing a "short" list of individual indices;6573// 2) Initialize the whole array:6574// a) If the object size is constant, we can choose strategy depending on the6575// size of the array. Using straight line of code, or unrolled loop;6576// b) For variable length of array, do a counted loop;65776578TR_ExtraInfoForNew *initInfo = node->getSymbolReference()->getExtraInfo();65796580static bool disableFastArrayZeroInit = (feGetEnv("TR_DisableFastArrayZeroInit") != NULL);65816582if (!node->canSkipZeroInitialization() && (initInfo == NULL || initInfo->numZeroInitSlots > 0))6583{6584if (!isVariableLen)6585{6586if (initInfo != NULL && initInfo->zeroInitSlots != NULL && initInfo->numZeroInitSlots <= 9 && objectSize <= UPPER_IMMED)6587{6588TR_BitVectorIterator bvi(*initInfo->zeroInitSlots);65896590if (comp->target().is64Bit())6591{6592int32_t lastNotInit = -1;6593int32_t currElem = -1;65946595// Try to group set of words into smallest groupings using double-word stores (where possible)6596while (bvi.hasMoreElements())6597{6598currElem = bvi.getNextElement();65996600if (lastNotInit == -1)6601{6602// currently looking at only one slot (either just starting, or just emitted double-word store in last iter)6603lastNotInit = currElem;6604}6605else if (currElem == lastNotInit + 1)6606{6607// consecutive slots, can use std6608iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, TR::MemoryReference::createWithDisplacement(cg, resReg, lastNotInit * 4 + dataBegin, 8),6609zeroReg, iCursor);66106611lastNotInit = -1;6612}6613else6614{6615// Two non-consecutive slots, use stw for earlier slot and keep looking for slot6616// consecutive with the second slot currently held6617iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, lastNotInit * 4 + dataBegin, 4),6618zeroReg, iCursor);66196620lastNotInit = currElem;6621}6622}66236624if (lastNotInit != -1)6625{6626// Last slot is not consecutive with other slots, hasn't been initialized yet6627iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, lastNotInit * 4 + dataBegin, 4),6628zeroReg, iCursor);6629}6630}6631else6632{6633while (bvi.hasMoreElements())6634{6635iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,6636TR::MemoryReference::createWithDisplacement(cg, resReg, bvi.getNextElement() * 4 + dataBegin, 4), zeroReg, iCursor);6637}6638}6639}6640else if (objectSize <= (TR::Compiler->om.sizeofReferenceAddress() * 12))6641{6642for (idx = dataBegin; idx < (objectSize - TR::Compiler->om.sizeofReferenceAddress()); idx += TR::Compiler->om.sizeofReferenceAddress())6643{6644iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, resReg, idx, TR::Compiler->om.sizeofReferenceAddress()), zeroReg,6645iCursor);6646}6647if (idx + 4 == objectSize)6648iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, idx, 4), zeroReg, iCursor);6649else if (idx + 8 == objectSize)6650iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, TR::MemoryReference::createWithDisplacement(cg, resReg, idx, 8), zeroReg, iCursor);6651}6652else6653{6654static bool disableUnrollNewInitLoop1 = (feGetEnv("TR_DisableUnrollNewInitLoop1") != NULL);6655if (!disableUnrollNewInitLoop1)6656{6657int32_t unrollFactor = 8;6658int32_t width = comp->target().is64Bit() ? 8 : 4;6659int32_t loopCount = (objectSize - dataBegin) / (unrollFactor * width);6660int32_t res1 = (objectSize - dataBegin) % (unrollFactor * width);6661int32_t residueCount = res1 / width;6662int32_t res2 = res1 % width;6663TR::LabelSymbol *loopStart = generateLabelSymbol(cg);66646665iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, resReg, dataBegin, iCursor);6666if (loopCount > 0)6667{6668if (loopCount > 1)6669{6670iCursor = loadConstant(cg, node, loopCount, tmp5Reg, iCursor);6671iCursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, tmp5Reg, 0, iCursor);6672iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, loopStart, iCursor);6673}66746675for (int32_t i = 0; i < unrollFactor; i++)6676iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, i * width, width), zeroReg, iCursor);66776678iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, tmp4Reg, tmp4Reg, (unrollFactor * width), iCursor);6679if (loopCount > 1)6680iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, loopStart, condReg, iCursor);6681}66826683for (int32_t i = 0; i < residueCount; i++)6684iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, i * width, width), zeroReg, iCursor);66856686if (res2 && residueCount != 0)6687iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, tmp4Reg, tmp4Reg, residueCount * width, iCursor);66886689if (comp->target().is64Bit() && res2 >= 4) // Should only be 0 or 4 here6690iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 0, 4), zeroReg, iCursor);6691}6692else6693{6694int32_t loopCnt = (objectSize - dataBegin) >> 4;6695int32_t residue = ((objectSize - dataBegin) >> 2) & 0x03;6696TR::LabelSymbol *initLoop = generateLabelSymbol(cg);66976698iCursor = loadConstant(cg, node, loopCnt, tmp5Reg, iCursor);6699iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, resReg, dataBegin, iCursor);6700iCursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, tmp5Reg, 0, iCursor);6701iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, initLoop, iCursor);6702iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 0, TR::Compiler->om.sizeofReferenceAddress()), zeroReg,6703iCursor);6704iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,6705TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()), zeroReg, iCursor);6706if (comp->target().is32Bit())6707{6708iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 8, 4), zeroReg, iCursor);6709iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 12, 4), zeroReg, iCursor);6710}6711iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, tmp4Reg, 16, iCursor);6712iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, initLoop, condReg, iCursor);67136714idx = 0;6715if (residue & 0x2)6716{6717iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 0, TR::Compiler->om.sizeofReferenceAddress()), zeroReg,6718iCursor);67196720if (comp->target().is32Bit())6721iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 4, 4), zeroReg, iCursor);67226723idx = 8;6724}6725if (residue & 0x1)6726{6727iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, idx, 4), zeroReg, iCursor);6728}6729}6730}6731}6732else // Init variable length array6733{6734static bool disableUnrollNewInitLoop2 = (feGetEnv("TR_DisableUnrollNewInitLoop2") != NULL);6735static bool disableNewZeroInit = (feGetEnv("TR_DisableNewZeroInit") != NULL);6736if (!disableUnrollNewInitLoop2)6737{6738int32_t unrollFactor = 8, i = 1;6739int32_t width = comp->target().is64Bit() ? 8 : 4;6740TR::LabelSymbol *loopLabel = generateLabelSymbol(cg);6741TR::LabelSymbol *resLabel = generateLabelSymbol(cg);6742TR::LabelSymbol *left4Label = generateLabelSymbol(cg);6743TR::LabelSymbol *resLoopLabel = NULL;67446745if (!disableNewZeroInit)6746resLoopLabel = generateLabelSymbol(cg);67476748iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp5Reg, resReg, (dataBegin - width), iCursor);6749iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tmp4Reg, tmp5Reg, dataSizeReg, iCursor);6750iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp4Reg, tmp5Reg, iCursor);6751iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg, iCursor);67526753iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp6Reg, tmp4Reg, (int32_t)(-unrollFactor * width), iCursor);67546755// Switch order of compare to avoid FXU reject in P6 for later store instruction6756iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp6Reg, tmp5Reg, iCursor);6757iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, resLabel, condReg, iCursor);67586759iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel, iCursor);6760for (; i <= unrollFactor; i++)6761iCursor = generateMemSrc1Instruction(cg, (width == 8) ? TR::InstOpCode::std : TR::InstOpCode::stw, node,6762TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, i * width, width), zeroReg, iCursor);6763iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp5Reg, tmp5Reg, (int32_t)(unrollFactor * width), iCursor);67646765iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp6Reg, tmp5Reg, iCursor);6766iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, loopLabel, condReg, iCursor);67676768iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp4Reg, tmp5Reg, iCursor);6769iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg, iCursor);67706771iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, resLabel, iCursor);67726773if (!disableNewZeroInit)6774{6775// End pointer-46776iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp6Reg, tmp4Reg, -4, iCursor);67776778// Residue loop start6779iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, resLoopLabel, iCursor);67806781// If current pointer == end pointer - 4, there is 4 bytes left to write6782// If current pointer > end pointer - 4, data is 8-byte divisible and we are done6783iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp6Reg, tmp5Reg, iCursor);6784iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, left4Label, condReg, iCursor);6785iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneLabel, condReg, iCursor);67866787// Do 8-byte zero init and restart loop6788iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, width, width), zeroReg, iCursor);67896790if (comp->target().is32Bit())6791{6792iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, 8, 4), zeroReg, iCursor);6793}67946795iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp5Reg, tmp5Reg, 8, iCursor);6796iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, resLoopLabel);67976798// Finish last 4 bytes if necessary6799iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, left4Label, iCursor);6800iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, width, 4), zeroReg, iCursor);6801}6802else6803{6804/* Need this in 64-bit as well */6805iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, tmp6Reg, tmp5Reg, tmp4Reg, iCursor);6806iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, tmp6Reg, 4, iCursor);6807iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, left4Label, condReg, iCursor);68086809iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, 8, width), zeroReg, iCursor);68106811if (comp->target().is32Bit())6812{6813iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, 12, 4), zeroReg, iCursor);6814}68156816iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp5Reg, tmp5Reg, 8, iCursor);6817iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp4Reg, tmp5Reg, iCursor);6818iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg, iCursor);6819iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, resLabel);68206821/* Need this in 64-bit as well */6822iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, left4Label, iCursor);6823iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, 8, 4), zeroReg, iCursor);6824}6825}6826else6827{6828// Test for zero length array: the following two instructions will be combined6829// to the record form by later pass.6830iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, tmp5Reg, dataSizeReg, 30, 0x3FFFFFFF, iCursor);6831iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, tmp5Reg, 0, iCursor);6832iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg, iCursor);6833iCursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, tmp5Reg, 0, iCursor);6834iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, resReg, dataBegin - 4, iCursor);68356836TR::LabelSymbol *initLoop = generateLabelSymbol(cg);6837iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, initLoop, iCursor);6838iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 4, 4), zeroReg, iCursor);6839iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, tmp4Reg, 4, iCursor);6840iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, initLoop, condReg, iCursor);6841}6842}6843}6844}68456846if (comp->compileRelocatableCode() && (opCode == TR::New || opCode == TR::anewarray))6847{6848firstInstruction = firstInstruction->getNext();6849TR_OpaqueClassBlock *classToValidate = clazz;68506851TR_RelocationRecordInformation *recordInfo = (TR_RelocationRecordInformation *) comp->trMemory()->allocateMemory(sizeof(TR_RelocationRecordInformation), heapAlloc);6852recordInfo->data1 = allocateSize;6853recordInfo->data2 = node->getInlinedSiteIndex();6854recordInfo->data3 = (uintptr_t) callLabel;6855recordInfo->data4 = (uintptr_t) firstInstruction;68566857TR::SymbolReference * classSymRef;6858TR_ExternalRelocationTargetKind reloKind;68596860if (opCode == TR::New)6861{6862classSymRef = node->getFirstChild()->getSymbolReference();6863reloKind = TR_VerifyClassObjectForAlloc;6864}6865else6866{6867classSymRef = node->getSecondChild()->getSymbolReference();6868reloKind = TR_VerifyRefArrayForAlloc;68696870if (comp->getOption(TR_UseSymbolValidationManager))6871classToValidate = comp->fej9()->getComponentClassFromArrayClass(classToValidate);6872}68736874if (comp->getOption(TR_UseSymbolValidationManager))6875{6876TR_ASSERT_FATAL(classToValidate, "classToValidate should not be NULL, clazz=%p\n", clazz);6877recordInfo->data5 = (uintptr_t)classToValidate;6878}68796880cg->addExternalRelocation(new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(firstInstruction, (uint8_t *) classSymRef, (uint8_t *) recordInfo, reloKind, cg),6881__FILE__, __LINE__, node);6882}68836884generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);68856886// At this point the object is initialized and we can move it to a collected register.6887// The out of line path will do the same. Since the live ranges of resReg and objReg6888// do not overlap we want them to occupy the same real register so that this instruction6889// becomes a nop and can be optimized away.6890generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, objReg, resReg);6891conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg->trMemory());6892TR::addDependency(conditions, objReg, resultRealReg, TR_GPR, cg);68936894generateDepLabelInstruction(cg, TR::InstOpCode::label, node, callReturnLabel, conditions);68956896cg->stopUsingRegister(condReg);6897cg->stopUsingRegister(tmp3Reg);6898cg->stopUsingRegister(tmp4Reg);6899cg->stopUsingRegister(tmp5Reg);6900cg->stopUsingRegister(tmp6Reg);6901cg->stopUsingRegister(tmp7Reg);6902cg->stopUsingRegister(resReg);6903cg->stopUsingRegister(dataSizeReg);6904if (!isDualTLH && needZeroInit)6905cg->stopUsingRegister(zeroReg);6906cg->decReferenceCount(firstChild);6907if (opCode == TR::New)6908{6909if (classReg != firstChild->getRegister())6910cg->stopUsingRegister(classReg);6911cg->stopUsingRegister(enumReg);6912}6913else6914{6915cg->decReferenceCount(secondChild);6916if (node->getSecondChild() != secondChild)6917cg->decReferenceCount(node->getSecondChild());6918if (classReg != secondChild->getRegister())6919cg->stopUsingRegister(classReg);6920}69216922node->setRegister(objReg);6923return objReg;6924}6925else6926{6927TR::Node::recreate(node, TR::acall);6928callResult = directCallEvaluator(node, cg);6929TR::Node::recreate(node, opCode);6930return (callResult);6931}6932}69336934// Special case evaluator for simple read monitors.6935static bool simpleReadMonitor(TR::Node *node, TR::CodeGenerator *cg, TR::Node *objNode, TR::Register *objReg, TR::Register *objectClassReg, TR::Register *condReg,6936TR::Register *lookupOffsetReg)6937{6938#if defined(J9VM_JIT_NEW_DUAL_HELPERS)6939// This needs to be updated to work with dual-mode helpers by not using snippets6940return false;6941#endif6942TR::Compilation *comp = cg->comp();6943TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());6944static char *disableSRM = feGetEnv("TR_disableSimpleReadMonitors");6945static char *nolwsync = feGetEnv("TR_noSRMlwsync");69466947if (disableSRM)6948return false;69496950// look for the special case of a read monitor sequence that protects6951// a single fixed-point load, ie:6952// monenter (object)6953// a simple form of iaload or iiload6954// monexit (object)69556956// note: before we make the following checks it is important that the6957// object on the monenter has been evaluated (currently done before the6958// call to this routine, and the result passed in as objReg)69596960if (!node->isReadMonitor())6961return false;69626963TR::TreeTop *nextTreeTop = cg->getCurrentEvaluationTreeTop()->getNextTreeTop();6964if (!nextTreeTop)6965return false;69666967TR::TreeTop *liveMonitorExitStore = NULL;6968TR::TreeTop *liveMonitorEnterStore = NULL;69696970if (nextTreeTop->getNode()->getOpCode().isStore() && nextTreeTop->getNode()->getSymbol()->holdsMonitoredObject())6971{6972liveMonitorEnterStore = nextTreeTop;6973nextTreeTop = nextTreeTop->getNextTreeTop();6974}69756976if (nextTreeTop->getNode()->getOpCode().getOpCodeValue() == TR::monexitfence)6977{6978liveMonitorExitStore = nextTreeTop;6979nextTreeTop = nextTreeTop->getNextTreeTop();6980}69816982TR::TreeTop *secondNextTreeTop = nextTreeTop->getNextTreeTop();6983if (!secondNextTreeTop)6984return false;69856986if (secondNextTreeTop->getNode()->getOpCode().getOpCodeValue() == TR::monexitfence)6987{6988liveMonitorExitStore = secondNextTreeTop;6989secondNextTreeTop = secondNextTreeTop->getNextTreeTop();6990}69916992// check that the second node after the monent is the matching monexit6993TR::Node *secondNextTopNode = secondNextTreeTop->getNode();6994if (!secondNextTopNode)6995return false;6996if (secondNextTopNode->getOpCodeValue() == TR::treetop)6997secondNextTopNode = secondNextTopNode->getFirstChild();6998if (secondNextTopNode->getOpCodeValue() != TR::monexit || secondNextTopNode->getFirstChild() != objNode)6999return false;70007001// check that the first node after the monent is a simple load7002TR::Node *nextTopNode = nextTreeTop->getNode();7003if (!nextTopNode)7004return false;7005if (nextTopNode->getOpCodeValue() == TR::treetop || nextTopNode->getOpCodeValue() == TR::iRegStore)7006nextTopNode = nextTopNode->getFirstChild();7007if (!TR::LoadStoreHandler::isSimpleLoad(cg, nextTopNode))7008return false;7009// possible TODO: expand the set of load types we can handle7010if (nextTopNode->getOpCodeValue() != TR::aloadi && nextTopNode->getOpCodeValue() != TR::iloadi)7011{7012// printf("Rejecting read-only monitor on load type in %s\n", comp->getCurrentMethod()->signature());7013return false;7014}7015// possible TODO: expand the complexity of loads we can handle7016// iaload and iiload are indirect and have a child7017// if we don't need to evaluate that child then the iaload or iiload7018// consists of a single hardware instruction and satisfies our current7019// constraint of simple7020if (!nextTopNode->getFirstChild()->getRegister())7021{7022// printf("Rejecting read-only monitor on complex load in %s\n", comp->getCurrentMethod()->signature());7023return false;7024}70257026// end of checks, we can handle this case7027// printf("Success on read-only monitor optimization in %s\n", comp->getCurrentMethod()->signature());70287029// RAS: dump out the load and monexit trees, since we are effectively7030// evaluating them here7031if (comp->getOption(TR_TraceCG) || debug("traceGRA"))7032{7033trfprintf(comp->getOutFile(), "\n");7034comp->getDebug()->dumpSingleTreeWithInstrs(nextTreeTop, NULL, true, false, true, comp->getOption(TR_TraceRegisterPressureDetails));7035trfprintf(comp->getOutFile(), "\n");7036comp->getDebug()->dumpSingleTreeWithInstrs(secondNextTreeTop, NULL, true, false, true, comp->getOption(TR_TraceRegisterPressureDetails));7037trfflush(comp->getOutFile());7038}70397040if (liveMonitorEnterStore)7041{7042TR::TreeTop *oldCur = cg->getCurrentEvaluationTreeTop();7043cg->setCurrentEvaluationTreeTop(liveMonitorEnterStore);7044cg->evaluate(liveMonitorEnterStore->getNode());7045cg->setCurrentEvaluationTreeTop(oldCur);7046}7047// check the TR::monexit to see if an lwsync is required7048// or whether to suppress the lwsync for performance analysis purposes7049bool needlwsync = comp->target().isSMP() && !secondNextTopNode->canSkipSync() && nolwsync == NULL;70507051// generate code for the combined monenter, load and monexit:7052// <monitor object evaluation code>7053// <TR_MemoryReference evaluation code for load>7054// (see design 908 for more information on the code sequences used)7055// if running on a POWER4/5 and the load is from the monitor object:7056// (altsequence)7057// if an lwsync is needed:7058// li offsetReg, offset_of_monitor_word7059// loopLabel:7060// lwarx monitorReg, [objReg, offsetReg]7061// cmpli cndReg, monitorReg, 07062// bne cndReg, recurCheckLabel7063// stwcx [objReg, offsetReg], metaReg7064// bne- loopLabel7065// or loadBaseReg,loadBaseReg,monitorReg7066// <load>7067// lwsync7068// stw offsetReg(objReg), monitorReg7069// restartLabel:7070// else (no lwsync):7071// li offsetReg, offset_of_monitor_word7072// loopLabel:7073// lwarx monitorReg, [objReg, offsetReg]7074// cmpli cndReg, monitorReg, 07075// bne cndReg, recurCheckLabel7076// stwcx [objReg, offsetReg], metaReg7077// bne- loopLabel7078// or loadBaseReg,loadBaseReg,monitorReg7079// <load>7080// xor monitorReg,loadResultReg,loadResultReg7081// stw offsetReg(objReg), monitorReg7082// restartLabel:7083// else:7084// if an lwsync is needed:7085// li offsetReg, offset_of_monitor_word7086// loopLabel:7087// lwarx monitorReg, [objReg, offsetReg]7088// cmpli cndReg, monitorReg, 07089// bne cndReg, recurCheckLabel7090// or loadBaseReg,loadBaseReg,monitorReg7091// <load>7092// lwsync7093// stwcx [objReg, offsetReg], monitorReg7094// bne- loopLabel7095// restartLabel:7096// else (no lwsync):7097// li offsetReg, offset_of_monitor_word7098// loopLabel:7099// lwarx monitorReg, [objReg, offsetReg]7100// cmpli cndReg, monitorReg, 07101// bne cndReg, recurCheckLabel7102// or loadBaseReg,loadBaseReg,monitorReg7103// <load>7104// xor monitorReg,loadResultReg,loadResultReg7105// stwcx [objReg, offsetReg], monitorReg7106// bne- loopLabel7107// restartLabel:7108// === SNIPPET === (generated later)7109// recurCheckLabel:7110// rlwinm monitorReg, monitorReg, 0, THREAD_MASK_CONST7111// cmp cndReg, metaReg, monitorReg7112// bne cndReg, slowPath7113// <load>7114// b restartLabel7115// slowPath:7116// bl monitorEnterHelper7117// <load>7118// bl monitorExitHelper7119// b restartLabel71207121TR::RegisterDependencyConditions *conditions;7122TR::Register *metaReg, *monitorReg, *cndReg, *offsetReg;7123TR::InstOpCode::Mnemonic opCode;7124int32_t lockSize;71257126int32_t numDeps = 6;7127if (objectClassReg)7128numDeps = numDeps + 2;71297130if (lookupOffsetReg)7131numDeps = numDeps + 1;71327133conditions = createConditionsAndPopulateVSXDeps(cg, numDeps);71347135monitorReg = cg->allocateRegister();7136offsetReg = cg->allocateRegister();7137cndReg = cg->allocateRegister(TR_CCR);7138TR::addDependency(conditions, monitorReg, TR::RealRegister::gr11, TR_GPR, cg);7139TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);7140TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);71417142// the following code is derived from the iaload and iiload evaluators7143TR::Register *loadResultReg;7144OMR::Power::NodeMemoryReference tempMR;7145if (nextTopNode->getOpCodeValue() == TR::aloadi)7146loadResultReg = cg->allocateCollectedReferenceRegister();7147else7148loadResultReg = cg->allocateRegister();7149if (nextTopNode->getSymbolReference()->getSymbol()->isInternalPointer())7150{7151loadResultReg->setPinningArrayPointer(nextTopNode->getSymbolReference()->getSymbol()->castToInternalPointerAutoSymbol()->getPinningArrayPointer());7152loadResultReg->setContainsInternalPointer();7153}7154nextTopNode->setRegister(loadResultReg);7155TR::InstOpCode::Mnemonic loadOpCode;7156if (nextTopNode->getOpCodeValue() == TR::aloadi && comp->target().is64Bit())7157{7158if (TR::Compiler->om.compressObjectReferences() && nextTopNode->getSymbol()->isClassObject())7159{7160tempMR = TR::LoadStoreHandler::generateSimpleLoadMemoryReference(cg, nextTopNode, 4);7161loadOpCode = TR::InstOpCode::lwz;7162}7163else7164{7165tempMR = TR::LoadStoreHandler::generateSimpleLoadMemoryReference(cg, nextTopNode, 8);7166loadOpCode = TR::InstOpCode::ld;7167}7168}7169else7170{7171tempMR = TR::LoadStoreHandler::generateSimpleLoadMemoryReference(cg, nextTopNode, 4);7172loadOpCode = TR::InstOpCode::lwz;7173}7174// end of code derived from the iaload and iiload evaluators71757176TR::addDependency(conditions, loadResultReg, TR::RealRegister::NoReg, TR_GPR, cg);7177if (tempMR.getMemoryReference()->getBaseRegister() != objReg)7178{7179TR::addDependency(conditions, tempMR.getMemoryReference()->getBaseRegister(), TR::RealRegister::NoReg, TR_GPR, cg);7180conditions->getPreConditions()->getRegisterDependency(4)->setExcludeGPR0();7181conditions->getPostConditions()->getRegisterDependency(4)->setExcludeGPR0();7182}7183TR::addDependency(conditions, objReg, TR::RealRegister::gr3, TR_GPR, cg);71847185TR::Register *baseReg = objReg;7186if (objectClassReg)7187baseReg = objectClassReg;71887189bool altsequence = (comp->target().cpu.is(OMR_PROCESSOR_PPC_GP) || comp->target().cpu.is(OMR_PROCESSOR_PPC_GR)) && tempMR.getMemoryReference()->getBaseRegister() == objReg;71907191TR::LabelSymbol *loopLabel, *restartLabel, *recurCheckLabel, *monExitCallLabel;7192loopLabel = generateLabelSymbol(cg);7193restartLabel = generateLabelSymbol(cg);7194recurCheckLabel = generateLabelSymbol(cg);7195monExitCallLabel = generateLabelSymbol(cg);71967197metaReg = cg->getMethodMetaDataRegister();71987199if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())7200{7201opCode = TR::InstOpCode::ldarx;7202lockSize = 8;7203}7204else7205{7206opCode = TR::InstOpCode::lwarx;7207lockSize = 4;7208}72097210if (objectClassReg)7211generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, offsetReg, 0);7212else7213generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, offsetReg, fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node)));7214generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);7215generateTrg1MemInstruction(cg, opCode, node, monitorReg, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize));7216generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, monitorReg, 0);7217TR::Instruction *gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, recurCheckLabel, cndReg);7218gcPoint->PPCNeedsGCMap(0xFFFFFFFF);72197220if (altsequence)7221{7222if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())7223opCode = TR::InstOpCode::stdcx_r;7224else7225opCode = TR::InstOpCode::stwcx_r;7226generateMemSrc1Instruction(cg, opCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize), metaReg);7227generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, cndReg);7228generateTrg1Src2Instruction(cg, TR::InstOpCode::OR, node, tempMR.getMemoryReference()->getBaseRegister(), tempMR.getMemoryReference()->getBaseRegister(), monitorReg);7229generateTrg1MemInstruction(cg, loadOpCode, node, loadResultReg, tempMR.getMemoryReference());7230if (needlwsync)7231generateInstruction(cg, TR::InstOpCode::lwsync, node);7232else7233generateTrg1Src2Instruction(cg, TR::InstOpCode::XOR, node, monitorReg, loadResultReg, loadResultReg);7234if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())7235opCode = TR::InstOpCode::std;7236else7237opCode = TR::InstOpCode::stw;7238generateMemSrc1Instruction(cg, opCode, node,7239TR::MemoryReference::createWithDisplacement(cg, baseReg, objectClassReg ? 0 : fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node)), lockSize), monitorReg);7240}7241else7242{7243generateTrg1Src2Instruction(cg, TR::InstOpCode::OR, node, tempMR.getMemoryReference()->getBaseRegister(), tempMR.getMemoryReference()->getBaseRegister(), monitorReg);7244generateTrg1MemInstruction(cg, loadOpCode, node, loadResultReg, tempMR.getMemoryReference());7245if (needlwsync)7246generateInstruction(cg, TR::InstOpCode::lwsync, node);7247else7248generateTrg1Src2Instruction(cg, TR::InstOpCode::XOR, node, monitorReg, loadResultReg, loadResultReg);7249if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())7250opCode = TR::InstOpCode::stdcx_r;7251else7252opCode = TR::InstOpCode::stwcx_r;7253generateMemSrc1Instruction(cg, opCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize), monitorReg);7254generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, cndReg);7255}72567257if (objectClassReg)7258TR::addDependency(conditions, objectClassReg, TR::RealRegister::NoReg, TR_GPR, cg);72597260if (lookupOffsetReg)7261TR::addDependency(conditions, lookupOffsetReg, TR::RealRegister::NoReg, TR_GPR, cg);72627263if (condReg)7264TR::addDependency(conditions, condReg, TR::RealRegister::cr1, TR_CCR, cg);72657266generateDepLabelInstruction(cg, TR::InstOpCode::label, node, restartLabel, conditions);72677268conditions->stopUsingDepRegs(cg, objReg, loadResultReg);7269cg->decReferenceCount(objNode);72707271TR::Snippet *snippet = new (cg->trHeapMemory()) TR::PPCReadMonitorSnippet(cg, node, secondNextTopNode, recurCheckLabel, monExitCallLabel, restartLabel, loadOpCode,7272tempMR.getMemoryReference()->getOffset(), objectClassReg);7273cg->addSnippet(snippet);72747275// the load and monexit trees need reference count adjustments and7276// must not be evaluated7277tempMR.decReferenceCounts(cg);7278cg->decReferenceCount(nextTopNode);7279if (secondNextTopNode == secondNextTreeTop->getNode())7280cg->recursivelyDecReferenceCount(secondNextTopNode->getFirstChild());7281else7282cg->recursivelyDecReferenceCount(secondNextTopNode);72837284if (liveMonitorExitStore)7285{7286TR::TreeTop *prev = liveMonitorExitStore->getPrevTreeTop();7287TR::TreeTop *next = liveMonitorExitStore->getNextTreeTop();7288prev->join(next);72897290next = secondNextTreeTop->getNextTreeTop();7291secondNextTreeTop->join(liveMonitorExitStore);7292liveMonitorExitStore->join(next);7293}72947295cg->setCurrentEvaluationTreeTop(secondNextTreeTop);72967297return true;7298}72997300void J9::Power::TreeEvaluator::generateCheckForValueMonitorEnterOrExit(TR::Node *node, TR::LabelSymbol *helperCallLabel, TR::Register *objReg, TR::Register *objectClassReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register *condReg, TR::CodeGenerator *cg, int32_t classFlag)7301{7302//get class of object7303generateLoadJ9Class(node, objectClassReg, objReg, cg);73047305//get memory reference to class flags7306TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());7307TR::MemoryReference *classFlagsMemRef = TR::MemoryReference::createWithDisplacement(cg, objectClassReg, static_cast<uintptr_t>(fej9->getOffsetOfClassFlags()), 4);73087309generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, temp1Reg, classFlagsMemRef);73107311loadConstant(cg, node, classFlag, temp2Reg);7312generateTrg1Src2Instruction(cg, TR::InstOpCode::and_r, node, temp1Reg, temp1Reg, temp2Reg);73137314//If obj is value type or value based class instance, call VM helper and throw IllegalMonitorState exception, else continue as usual7315generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, helperCallLabel, condReg);7316}73177318TR::Register *J9::Power::TreeEvaluator::VMmonentEvaluator(TR::Node *node, TR::CodeGenerator *cg)7319{7320TR::Compilation *comp = cg->comp();7321TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());7322int32_t lwOffset = fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node));7323TR_ASSERT(lwOffset>=LOWER_IMMED && lwOffset<=UPPER_IMMED, "Need re-work on using lwOffset.");7324TR_YesNoMaybe isMonitorValueBasedOrValueType = cg->isMonitorValueBasedOrValueType(node);73257326if (comp->getOption(TR_MimicInterpreterFrameShape) ||7327(comp->getOption(TR_FullSpeedDebug) && node->isSyncMethodMonitor()) ||7328(isMonitorValueBasedOrValueType == TR_yes) ||7329comp->getOption(TR_DisableInlineMonEnt))7330{7331TR::ILOpCodes opCode = node->getOpCodeValue();7332TR::Node::recreate(node, TR::call);7333TR::Register *targetRegister = directCallEvaluator(node, cg);7334TR::Node::recreate(node, opCode);7335return targetRegister;7336}73377338int32_t numDeps = 6;73397340TR::Node *objNode = node->getFirstChild();7341TR::Register *objReg = cg->evaluate(objNode);73427343TR::Register *monitorReg = cg->allocateRegister();7344TR::Register *offsetReg = cg->allocateRegister();7345TR::Register *tempReg = cg->allocateRegister();73467347TR::Register *objectClassReg = cg->allocateRegister();7348TR::Register *lookupOffsetReg = NULL;73497350TR::Register *condReg = cg->allocateRegister(TR_CCR);7351TR::Register *metaReg = cg->getMethodMetaDataRegister();73527353TR::Register *baseReg = objReg;73547355if (lwOffset <= 0)7356{7357if (comp->getOption(TR_EnableMonitorCacheLookup))7358{7359lookupOffsetReg = cg->allocateRegister();7360numDeps++;7361}7362}73637364TR::RegisterDependencyConditions *conditions;7365conditions = createConditionsAndPopulateVSXDeps(cg, numDeps);73667367TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);7368conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();7369conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();73707371TR::addDependency(conditions, monitorReg, TR::RealRegister::NoReg, TR_GPR, cg);7372conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();7373conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();73747375TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);73767377TR::addDependency(conditions, tempReg, TR::RealRegister::NoReg, TR_GPR, cg);73787379TR::addDependency(conditions, objectClassReg, TR::RealRegister::NoReg, TR_GPR, cg);7380conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();7381conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();73827383if (lookupOffsetReg)7384{7385TR::addDependency(conditions, lookupOffsetReg, TR::RealRegister::NoReg, TR_GPR, cg);7386conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();7387conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();7388}73897390TR::addDependency(conditions, condReg, TR::RealRegister::cr0, TR_CCR, cg);73917392TR::LabelSymbol *callLabel = generateLabelSymbol(cg);7393TR::LabelSymbol *monitorLookupCacheLabel = generateLabelSymbol(cg);7394TR::LabelSymbol *fallThruFromMonitorLookupCacheLabel = generateLabelSymbol(cg);7395TR::LabelSymbol *startLabel = generateLabelSymbol(cg);73967397generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel, NULL);7398startLabel->setStartInternalControlFlow();73997400//If object is not known to be value type or value based class at compile time, check at run time7401if (isMonitorValueBasedOrValueType == TR_maybe)7402{7403generateCheckForValueMonitorEnterOrExit(node, callLabel, objReg, objectClassReg, tempReg, offsetReg, condReg, cg, J9_CLASS_DISALLOWS_LOCKING_FLAGS);7404}74057406bool simpleLocking = false;74077408if (lwOffset <= 0)7409{7410generateLoadJ9Class(node, objectClassReg, objReg, cg);74117412int32_t offsetOfLockOffset = offsetof(J9Class, lockOffset);7413TR::MemoryReference *tempMR = TR::MemoryReference::createWithDisplacement(cg, objectClassReg, offsetOfLockOffset, TR::Compiler->om.sizeofReferenceAddress());7414generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, objectClassReg, tempMR);74157416generateTrg1Src1ImmInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, condReg, objectClassReg, 0);74177418if (comp->getOption(TR_EnableMonitorCacheLookup))7419{7420lwOffset = 0;7421generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, monitorLookupCacheLabel, condReg);7422generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, objectClassReg, objReg, objectClassReg);7423generateLabelInstruction(cg, TR::InstOpCode::b, node, fallThruFromMonitorLookupCacheLabel);74247425generateLabelInstruction(cg, TR::InstOpCode::label, node, monitorLookupCacheLabel);74267427int32_t offsetOfMonitorLookupCache = offsetof(J9VMThread, objectMonitorLookupCache);74287429generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, lookupOffsetReg, objReg);74307431int32_t t = trailingZeroes(TR::Compiler->om.getObjectAlignmentInBytes());74327433if (comp->target().is64Bit())7434generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sradi, node, lookupOffsetReg, lookupOffsetReg, t);7435else7436generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::srawi, node, lookupOffsetReg, lookupOffsetReg, t);74377438J9JavaVM * jvm = fej9->getJ9JITConfig()->javaVM;7439if (comp->target().is64Bit())7440simplifyANDRegImm(node, lookupOffsetReg, lookupOffsetReg, (int64_t) J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, cg, objNode);7441else7442simplifyANDRegImm(node, lookupOffsetReg, lookupOffsetReg, J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, cg, objNode);74437444if (comp->target().is64Bit())7445generateShiftLeftImmediateLong(cg, node, lookupOffsetReg, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));7446else7447generateShiftLeftImmediate(cg, node, lookupOffsetReg, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));74487449generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, lookupOffsetReg, lookupOffsetReg, offsetOfMonitorLookupCache);74507451generateTrg1MemInstruction(cg, (comp->target().is64Bit() && fej9->generateCompressedLockWord()) ? TR::InstOpCode::lwz :TR::InstOpCode::Op_load, node, objectClassReg,7452TR::MemoryReference::createWithIndexReg(cg, metaReg, lookupOffsetReg, TR::Compiler->om.sizeofReferenceField()));74537454generateTrg1Src1ImmInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, condReg, objectClassReg, 0);7455generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg);74567457int32_t offsetOfMonitor = offsetof(J9ObjectMonitor, monitor);7458generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, lookupOffsetReg,7459TR::MemoryReference::createWithDisplacement(cg, objectClassReg, offsetOfMonitor, TR::Compiler->om.sizeofReferenceAddress()));74607461int32_t offsetOfUserData = offsetof(J9ThreadAbstractMonitor, userData);7462generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, lookupOffsetReg,7463TR::MemoryReference::createWithDisplacement(cg, lookupOffsetReg, offsetOfUserData, TR::Compiler->om.sizeofReferenceAddress()));74647465generateTrg1Src2Instruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmp8 : TR::InstOpCode::cmp4, node, condReg, lookupOffsetReg, objReg);7466generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);74677468int32_t offsetOfAlternateLockWord = offsetof(J9ObjectMonitor, alternateLockword);74697470generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, objectClassReg, objectClassReg, offsetOfAlternateLockWord);74717472generateLabelInstruction(cg, TR::InstOpCode::label, node, fallThruFromMonitorLookupCacheLabel);7473}7474else7475{7476generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, callLabel, condReg);7477generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, objectClassReg, objReg, objectClassReg);7478}74797480simpleLocking = true;7481lwOffset = 0;7482baseReg = objectClassReg;7483}74847485/* If the -XX:-GlobalLockReservation option is set, try to use the original aggressive reserved locking code path. */7486if (!fej9->isEnableGlobalLockReservationSet())7487{7488bool reserveLocking = false, normalLockWithReservationPreserving = false;74897490if (!simpleLocking && comp->getOption(TR_ReservingLocks))7491TR::TreeEvaluator::evaluateLockForReservation(node, &reserveLocking, &normalLockWithReservationPreserving, cg);74927493if (reserveLocking)7494return reservationLockEnter(node, lwOffset, cg, conditions, baseReg, monitorReg, offsetReg, tempReg, condReg, callLabel);74957496if (!simpleLocking && !reserveLocking && !normalLockWithReservationPreserving && simpleReadMonitor(node, cg, objNode, objReg, objectClassReg, condReg, lookupOffsetReg))7497return NULL;7498}74997500int32_t lockSize;7501TR::InstOpCode::Mnemonic loadOpCode, storeOpCode, reservedLoadOpCode, conditionalStoreOpCode, compareLogicalOpCode, compareLogicalImmOpCode;75027503if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())7504{7505lockSize = 8;7506loadOpCode = TR::InstOpCode::ld;7507storeOpCode = TR::InstOpCode::std;7508reservedLoadOpCode = TR::InstOpCode::ldarx;7509conditionalStoreOpCode = TR::InstOpCode::stdcx_r;7510compareLogicalOpCode = TR::InstOpCode::cmpl8;7511compareLogicalImmOpCode = TR::InstOpCode::cmpli8;7512}7513else7514{7515lockSize = 4;7516loadOpCode = TR::InstOpCode::lwz;7517storeOpCode = TR::InstOpCode::stw;7518reservedLoadOpCode = TR::InstOpCode::lwarx;7519conditionalStoreOpCode = TR::InstOpCode::stwcx_r;7520compareLogicalOpCode = TR::InstOpCode::cmpl4;7521compareLogicalImmOpCode = TR::InstOpCode::cmpli4;7522}75237524// full codegen support for read monitors is not enabled, pending performance tuning7525/*7526* Read only locks do not support either the Reserved bit nor the Learning bit.7527* They are disabled until the code path is updated.7528*/7529if (true || !ppcSupportsReadMonitors || !node->isReadMonitor())7530{7531/*7532* JIT locking fast path checks:7533* 1. Compare lockword to 0. If equal, use CAS to set TID in lockword.7534* 2. Check if TID matches, highest RC bit is 0, Learning bit is clear and Inflated bit is clear. If so, increment RC.7535* 3. All fast path checks failed so go to VM.7536*7537* Check 1 catches Flat-Unlocked.7538* Check 2 catches Reserved-Unlocked, Reserved-Locked and Flat-Locked.7539* Check 3 catches New-PreLearning, New-AutoReserve, Learning-Unlocked, Learning-Locked and Inflated and sends them to the VM.7540*7541*7542* ld/lwz monitorReg, lwOffset(baseReg)7543* cmpli cr0, monitorReg, 07544* bne incrementCheckLabel7545* li offsetReg, lwOffset7546*7547* loopLabel:7548* larx monitorReg, [baseReg, offsetReg]7549* cmpli cr0, monitorReg, 07550* bne callLabel7551* stcx. metaReg, [baseReg, offsetReg]7552* bne loopLabel7553* isync7554* b doneLabel7555*7556* incrementCheckLabel:7557* li tempReg, LOCK_NON_PRIMITIVE_ENTER_IGNORE_MASK7558* andc tempReg, monitorReg, tempReg7559* cmpl cr0, tempReg, metaReg7560* bne callLabel7561* addi monitorReg, monitorReg, LOCK_INC_DEC_VALUE7562* st monitorReg, lwOffset(baseReg)7563*7564* doneLabel:7565* callReturnLabel:7566* === OUT OF LINE ===7567* callLabel:7568* bl jitMonitorEntry7569* b callReturnLabel7570*/75717572TR::LabelSymbol *loopLabel, *incrementCheckLabel, *doneLabel;7573loopLabel = generateLabelSymbol(cg);7574incrementCheckLabel = generateLabelSymbol(cg);7575doneLabel = generateLabelSymbol(cg);75767577generateTrg1MemInstruction(cg, loadOpCode, node, monitorReg, TR::MemoryReference::createWithDisplacement(cg, baseReg, lwOffset, lockSize));75787579generateTrg1Src1ImmInstruction(cg, compareLogicalImmOpCode, node, condReg, monitorReg, 0);7580generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, incrementCheckLabel, condReg);7581generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, offsetReg, lwOffset);75827583generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);7584generateTrg1MemInstruction(cg, reservedLoadOpCode, PPCOpProp_LoadReserveExclusiveAccess, node, monitorReg, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize));7585generateTrg1Src1ImmInstruction(cg, compareLogicalImmOpCode, node, condReg, monitorReg, 0);7586generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);7587generateMemSrc1Instruction(cg, conditionalStoreOpCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize), metaReg);75887589generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, condReg);75907591if (comp->target().isSMP())7592{7593// either an isync or a sync can be used here to prevent any7594// following loads from executing out-of-order7595// on nstar and pulsar a sync is cheaper, while an isync is7596// cheaper on other processors7597if (comp->target().cpu.is(OMR_PROCESSOR_PPC_NSTAR) || comp->target().cpu.is(OMR_PROCESSOR_PPC_PULSAR))7598generateInstruction(cg, TR::InstOpCode::sync, node);7599else7600generateInstruction(cg, TR::InstOpCode::isync, node);7601}7602generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);76037604generateLabelInstruction(cg, TR::InstOpCode::label, node, incrementCheckLabel);7605generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, LOCK_NON_PRIMITIVE_ENTER_IGNORE_MASK);7606generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, tempReg, monitorReg, tempReg);7607generateTrg1Src2Instruction(cg, compareLogicalOpCode, node, condReg, tempReg, metaReg);7608generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);7609generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, monitorReg, monitorReg, LOCK_INC_DEC_VALUE);7610generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, baseReg, lwOffset, lockSize), monitorReg);76117612generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);76137614doneLabel->setEndInternalControlFlow();76157616TR::LabelSymbol *callReturnLabel = generateLabelSymbol(cg);76177618TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, callReturnLabel, cg);7619cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);76207621generateLabelInstruction(cg, TR::InstOpCode::label, node, callReturnLabel);76227623conditions->stopUsingDepRegs(cg, objReg);7624cg->decReferenceCount(objNode);7625}7626else7627{7628// read-only locks, readerReg = 0x0000 00007629// li offsetReg, offset_of_monitor_word7630// loopLabel:7631// larx monitorReg, [baseReg, offsetReg]7632// rlwinm tempReg, monitorReg, 0, 0xFFFFFF837633// cmpi cr0, tempReg, 0x07634// bne callLabel7635// addi monitorReg, monitorReg, 47636// stcx. [baseReg, offsetReg], monitorReg7637// bne loopLabel7638// isync7639// doneLabel:7640// callReturnLabel:7641// === OUT OF LINE ===7642// callLabel:7643// bl jitMonitorEntry7644// b callReturnLabel76457646TR::LabelSymbol *doneLabel, *loopLabel;7647doneLabel = generateLabelSymbol(cg);7648loopLabel = generateLabelSymbol(cg);76497650generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, offsetReg, lwOffset);7651generateDepLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel, conditions);7652generateTrg1MemInstruction(cg, reservedLoadOpCode, PPCOpProp_LoadReserveExclusiveAccess, node, monitorReg,7653TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize));7654generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, tempReg, monitorReg, 0, 0xFFFFFF80);7655generateTrg1Src1ImmInstruction(cg, compareLogicalImmOpCode, node, condReg, tempReg, 0);7656generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);7657generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, monitorReg, monitorReg, 4);7658generateMemSrc1Instruction(cg, conditionalStoreOpCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize), monitorReg);76597660generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, condReg);76617662if (comp->target().isSMP())7663{7664// either an isync or a sync can be used here to prevent any7665// following loads from executing out-of-order7666// on nstar and pulsar a sync is cheaper, while an isync is7667// cheaper on other processors7668if (comp->target().cpu.is(OMR_PROCESSOR_PPC_NSTAR) || comp->target().cpu.is(OMR_PROCESSOR_PPC_PULSAR))7669generateInstruction(cg, TR::InstOpCode::sync, node);7670else7671generateInstruction(cg, TR::InstOpCode::isync, node);7672}7673generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);76747675doneLabel->setEndInternalControlFlow();76767677TR::LabelSymbol *callReturnLabel = generateLabelSymbol(cg);76787679TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, callReturnLabel, cg);7680cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);76817682generateLabelInstruction(cg, TR::InstOpCode::label, node, callReturnLabel);76837684conditions->stopUsingDepRegs(cg, objReg);7685cg->decReferenceCount(objNode);7686}76877688return (NULL);7689}76907691TR::Register *J9::Power::TreeEvaluator::VMarrayCheckEvaluator(TR::Node *node, TR::CodeGenerator *cg)7692{7693TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());7694TR::Register *obj1Reg, *obj2Reg, *tmp1Reg, *tmp2Reg, *cndReg;7695TR::LabelSymbol *doneLabel, *snippetLabel;7696TR::Instruction *gcPoint;7697TR::Snippet *snippet;7698TR::RegisterDependencyConditions *conditions;7699int32_t depIndex;7700TR::Compilation* comp = cg->comp();77017702obj1Reg = cg->evaluate(node->getFirstChild());7703obj2Reg = cg->evaluate(node->getSecondChild());7704doneLabel = generateLabelSymbol(cg);7705conditions = createConditionsAndPopulateVSXDeps(cg, 5);7706depIndex = 0;7707nonFixedDependency(conditions, obj1Reg, &depIndex, TR_GPR, true, cg);7708nonFixedDependency(conditions, obj2Reg, &depIndex, TR_GPR, true, cg);7709tmp1Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, true, cg);7710tmp2Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, false, cg);7711cndReg = cg->allocateRegister(TR_CCR);7712TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);77137714// We have a unique snippet sharing arrangement in this code sequence.7715// It is not generally applicable for other situations.7716snippetLabel = NULL;77177718// Same array, we are done.7719//7720generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, obj1Reg, obj2Reg);7721generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, cndReg);77227723// If we know nothing about either object, test object1 first. It has to be an array.7724//7725if (!node->isArrayChkPrimitiveArray1() && !node->isArrayChkReferenceArray1() && !node->isArrayChkPrimitiveArray2() && !node->isArrayChkReferenceArray2())7726{77277728generateLoadJ9Class(node, tmp1Reg, obj1Reg, cg);77297730generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, tmp1Reg, (int32_t) offsetof(J9Class, classDepthAndFlags), 4));77317732loadConstant(cg, node, (int32_t) J9AccClassRAMArray, tmp2Reg);7733generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, tmp2Reg, tmp1Reg, tmp2Reg);77347735generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cndReg, tmp2Reg, NULLVALUE);77367737snippetLabel = generateLabelSymbol(cg);7738gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, snippetLabel, cndReg);7739snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference(), doneLabel);7740cg->addSnippet(snippet);7741}77427743// One of the object is array. Test equality of two objects' classes.7744//7745generateLoadJ9Class(node, tmp2Reg, obj2Reg, cg);7746generateLoadJ9Class(node, tmp1Reg, obj1Reg, cg);77477748generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, tmp1Reg, tmp2Reg);77497750// If either object is known to be of primitive component type,7751// we are done: since both of them have to be of equal class.7752if (node->isArrayChkPrimitiveArray1() || node->isArrayChkPrimitiveArray2())7753{7754if (snippetLabel == NULL)7755{7756snippetLabel = generateLabelSymbol(cg);7757gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg);7758snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference(), doneLabel);7759cg->addSnippet(snippet);7760}7761else7762generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg);7763}7764// We have to take care of the un-equal class situation: both of them must be of reference array7765else7766{7767generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, cndReg);77687769// Object1 must be of reference component type, otherwise throw exception7770if (!node->isArrayChkReferenceArray1())7771{77727773// Loading the Class Pointer -> classDepthAndFlags7774generateLoadJ9Class(node, tmp1Reg, obj1Reg, cg);77757776generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, tmp1Reg, (int32_t) offsetof(J9Class, classDepthAndFlags), 4));77777778// We already have classDepth&Flags in tmp1Reg. X = (ramclass->ClassDepthAndFlags)>>J9AccClassRAMShapeShift7779generateShiftRightLogicalImmediate(cg, node, tmp1Reg, tmp1Reg, J9AccClassRAMShapeShift);77807781// We need to perform a X & OBJECT_HEADER_SHAPE_MASK77827783generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, tmp2Reg, tmp1Reg, 0, OBJECT_HEADER_SHAPE_MASK);7784generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cndReg, tmp2Reg, OBJECT_HEADER_SHAPE_POINTERS);77857786if (snippetLabel == NULL)7787{7788snippetLabel = generateLabelSymbol(cg);7789gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg);7790snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference(), doneLabel);7791cg->addSnippet(snippet);7792}7793else7794generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg);7795}77967797// Object2 must be of reference component type array, otherwise throw exception7798if (!node->isArrayChkReferenceArray2())7799{78007801generateLoadJ9Class(node, tmp1Reg, obj2Reg, cg);7802generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, tmp1Reg, (int32_t) offsetof(J9Class, classDepthAndFlags), 4));78037804loadConstant(cg, node, (int32_t) J9AccClassRAMArray, tmp2Reg);7805generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, tmp2Reg, tmp1Reg, tmp2Reg);78067807TR::Instruction * i = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cndReg, tmp2Reg, NULLVALUE);78087809if (snippetLabel == NULL)7810{7811snippetLabel = generateLabelSymbol(cg);7812gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, snippetLabel, cndReg);7813snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference(), doneLabel);7814cg->addSnippet(snippet);7815}7816else7817generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, snippetLabel, cndReg);78187819// We already have classDepth&Flags in tmp1Reg. X = (ramclass->ClassDepthAndFlags)>>J9AccClassRAMShapeShift7820generateShiftRightLogicalImmediate(cg, node, tmp1Reg, tmp1Reg, J9AccClassRAMShapeShift);78217822// We need to perform a X & OBJECT_HEADER_SHAPE_MASK78237824generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, tmp2Reg, tmp1Reg, 0, OBJECT_HEADER_SHAPE_MASK);7825generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cndReg, tmp2Reg, OBJECT_HEADER_SHAPE_POINTERS);7826generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg);7827}7828}78297830generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);7831if (snippetLabel != NULL)7832{7833gcPoint->PPCNeedsGCMap(0x0);7834snippet->gcMap().setGCRegisterMask(0x0);7835}78367837conditions->stopUsingDepRegs(cg, obj1Reg, obj2Reg);78387839cg->decReferenceCount(node->getFirstChild());7840cg->decReferenceCount(node->getSecondChild());7841return (NULL);7842}78437844void J9::Power::TreeEvaluator::genArrayCopyWithArrayStoreCHK(TR::Node* node, TR::CodeGenerator *cg)7845{7846TR::Compilation *comp = cg->comp();7847TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());7848TR::Register *metaReg = cg->getMethodMetaDataRegister();7849TR::Register *gr3Reg, *gr2Reg, *lengthReg, *temp1Reg;78507851// child 0 ------ Source array object;7852// child 1 ------ Destination array object;7853// child 2 ------ Source byte address;7854// child 3 ------ Destination byte address;7855// child 4 ------ Copy length in byte;78567857bool aix_style_linkage = (comp->target().isAIX() || (comp->target().is64Bit() && comp->target().isLinux()));7858J9::Power::JNILinkage *jniLinkage = (J9::Power::JNILinkage*) cg->getLinkage(TR_J9JNILinkage);7859const TR::PPCLinkageProperties &pp = jniLinkage->getProperties();7860TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(pp.getNumberOfDependencyGPRegisters(),7861pp.getNumberOfDependencyGPRegisters(), cg->trMemory());78627863// I_32 referenceArrayCopy(7864// J9VMThread *vmThread,7865// J9IndexableObjectContiguous *srcObject,7866// J9IndexableObjectContiguous *destObject,7867// U_8 *srcAddress,7868// U_8 *destAddress,7869// I_32 lengthInSlots)7870intptr_t *funcdescrptr = (intptr_t*) fej9->getReferenceArrayCopyHelperAddress();78717872TR::Instruction *iCursor;7873if (aix_style_linkage)7874{7875gr2Reg = cg->allocateRegister();7876TR::addDependency(conditions, gr2Reg, TR::RealRegister::gr2, TR_GPR, cg);7877}7878// set up the arguments and dependencies7879int32_t argSize = jniLinkage->buildJNIArgs(node, conditions, pp, true);7880temp1Reg = conditions->searchPreConditionRegister(TR::RealRegister::gr12);7881if (aix_style_linkage &&7882!(comp->target().is64Bit() && comp->target().isLinux() && comp->target().cpu.isLittleEndian()))7883{7884intptr_t target_ip = funcdescrptr[0];7885intptr_t target_toc = funcdescrptr[1];7886iCursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, target_ip, temp1Reg, NULL, false, TR_ArrayCopyHelper);7887iCursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, target_toc, gr2Reg, iCursor, false, TR_ArrayCopyToc);7888}7889else7890{7891bool doRelocation = comp->compileRelocatableCode();7892#ifdef J9VM_OPT_JITSERVER7893doRelocation = doRelocation || comp->isOutOfProcessCompilation();7894#endif7895iCursor = loadAddressConstant(cg, doRelocation, node, (intptr_t) funcdescrptr, temp1Reg, NULL, false, TR_ArrayCopyHelper);7896}78977898iCursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, temp1Reg, NULL, iCursor);7899// the C routine expects length measured by slots7900lengthReg = conditions->searchPreConditionRegister(TR::RealRegister::gr8);7901int32_t elementSize;7902if (comp->useCompressedPointers())7903elementSize = TR::Compiler->om.sizeofReferenceField();7904else7905elementSize = (int32_t) TR::Compiler->om.sizeofReferenceAddress();7906generateShiftRightLogicalImmediate(cg, node, lengthReg, lengthReg, trailingZeroes(elementSize));7907// pass vmThread as the first parameter7908gr3Reg = cg->allocateRegister();7909TR::addDependency(conditions, gr3Reg, TR::RealRegister::gr3, TR_GPR, cg);7910iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, gr3Reg, metaReg, iCursor);7911// call the C routine7912TR::Instruction *gcPoint = generateDepInstruction(cg, TR::InstOpCode::bctrl, node, conditions);7913gcPoint->PPCNeedsGCMap(pp.getPreservedRegisterMapForGC());7914// check return value7915TR::Register *cr0Reg = conditions->searchPreConditionRegister(TR::RealRegister::cr0);7916generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cr0Reg, gr3Reg, -1);7917// throw exception if needed7918TR::SymbolReference *throwSymRef = comp->getSymRefTab()->findOrCreateArrayStoreExceptionSymbolRef(comp->getJittedMethodSymbol());7919TR::LabelSymbol *exceptionSnippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, throwSymRef);7920if (exceptionSnippetLabel == NULL)7921{7922exceptionSnippetLabel = generateLabelSymbol(cg);7923cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, exceptionSnippetLabel, throwSymRef));7924}79257926gcPoint = generateDepConditionalBranchInstruction(cg, TR::InstOpCode::bnel, node, exceptionSnippetLabel, cr0Reg, conditions->cloneAndFix(cg));7927// somewhere to hang the dependencies7928TR::LabelSymbol *depLabel = generateLabelSymbol(cg);7929generateDepLabelInstruction(cg, TR::InstOpCode::label, node, depLabel, conditions);7930gcPoint->PPCNeedsGCMap(pp.getPreservedRegisterMapForGC());7931cg->machine()->setLinkRegisterKilled(true);7932conditions->stopUsingDepRegs(cg);7933cg->setHasCall();7934return;7935}79367937void J9::Power::TreeEvaluator::genWrtbarForArrayCopy(TR::Node *node, TR::Register *srcObjReg, TR::Register *dstObjReg, TR::CodeGenerator *cg)7938{7939TR::Compilation *comp = cg->comp();7940bool ageCheckIsNeeded = false;7941bool cardMarkIsNeeded = false;7942auto gcMode = TR::Compiler->om.writeBarrierType();7943TR::RegisterDependencyConditions *conditions = NULL;79447945ageCheckIsNeeded = (gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always);7946cardMarkIsNeeded = (gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_incremental);79477948if (!ageCheckIsNeeded && !cardMarkIsNeeded)7949return;79507951if (ageCheckIsNeeded)7952{7953TR::Register *temp1Reg;7954TR::Register *temp2Reg;7955TR::Register *condReg = cg->allocateRegister(TR_CCR);7956TR::Instruction *gcPoint;79577958if (gcMode != gc_modron_wrtbar_always)7959{7960temp1Reg = cg->allocateRegister();7961temp2Reg = cg->allocateRegister();7962conditions = createConditionsAndPopulateVSXDeps(cg, 4);7963TR::addDependency(conditions, temp1Reg, TR::RealRegister::gr11, TR_GPR, cg);7964TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);7965}7966else7967{7968conditions = createConditionsAndPopulateVSXDeps(cg, 2);7969}79707971TR::addDependency(conditions, dstObjReg, TR::RealRegister::gr3, TR_GPR, cg);7972TR::addDependency(conditions, condReg, TR::RealRegister::cr0, TR_CCR, cg);79737974TR::LabelSymbol *doneLabel;7975TR::SymbolReference *wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierBatchStoreSymbolRef(comp->getMethodSymbol());79767977if (gcMode != gc_modron_wrtbar_always)7978{7979doneLabel = generateLabelSymbol(cg);79807981TR::Register *metaReg = cg->getMethodMetaDataRegister();79827983// temp1Reg = dstObjReg - heapBaseForBarrierRange07984generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,7985TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapBaseForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));7986generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp1Reg, temp1Reg, dstObjReg);79877988// if (temp1Reg >= heapSizeForBarrierRage0), object not in the tenured area7989generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg,7990TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapSizeForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));7991generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp1Reg, temp2Reg);7992generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, doneLabel, condReg);7993}79947995gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t) wbRef->getSymbol()->castToMethodSymbol()->getMethodAddress(),7996new (cg->trHeapMemory()) TR::RegisterDependencyConditions((uint8_t) 0, 0, cg->trMemory()), wbRef, NULL);79977998if (gcMode != gc_modron_wrtbar_always)7999generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);80008001cg->machine()->setLinkRegisterKilled(true);8002cg->setHasCall();80038004// This GC point can only happen when there is an exception. As a result, we can ditch8005// all registers.8006gcPoint->PPCNeedsGCMap(0xFFFFFFFF);8007}80088009if (!ageCheckIsNeeded && cardMarkIsNeeded)8010{8011if (!comp->getOptions()->realTimeGC())80128013{8014TR::Register *cndReg = cg->allocateRegister(TR_CCR);8015TR::Register *temp1Reg = cg->allocateRegister();8016TR::Register *temp2Reg = cg->allocateRegister();8017TR::Register *temp3Reg = cg->allocateRegister();8018conditions = createConditionsAndPopulateVSXDeps(cg, 7);80198020TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);8021TR::addDependency(conditions, dstObjReg, TR::RealRegister::NoReg, TR_GPR, cg);8022TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);8023conditions->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0();8024conditions->getPostConditions()->getRegisterDependency(2)->setExcludeGPR0();8025TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);8026TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);80278028VMCardCheckEvaluator(node, dstObjReg, cndReg, temp1Reg, temp2Reg, temp3Reg, conditions, cg);8029generateDepLabelInstruction(cg, TR::InstOpCode::label, node, generateLabelSymbol(cg), conditions);80308031}8032else8033TR_ASSERT(0, "genWrtbarForArrayCopy card marking not supported for RT");8034}8035if (conditions)8036{8037conditions->stopUsingDepRegs(cg, dstObjReg);8038}8039}80408041static TR::Register *genCAS(TR::Node *node, TR::CodeGenerator *cg, TR::Register *objReg, TR::Register *offsetReg, TR::Register *oldVReg, TR::Register *newVReg, TR::Register *cndReg,8042TR::LabelSymbol *doneLabel, TR::Node *objNode, int32_t oldValue, bool oldValueInReg, bool isLong, bool casWithoutSync = false)8043{8044TR::Register *resultReg = cg->allocateRegister();8045TR::Instruction *gcPoint;80468047// Memory barrier --- NOTE: we should be able to do a test upfront to save this barrier,8048// but Hursley advised to be conservative due to lack of specification.8049generateInstruction(cg, TR::InstOpCode::lwsync, node);80508051TR::LabelSymbol *loopLabel = generateLabelSymbol(cg);8052generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);80538054generateTrg1MemInstruction(cg, isLong ? TR::InstOpCode::ldarx : TR::InstOpCode::lwarx, node, resultReg, TR::MemoryReference::createWithIndexReg(cg, objReg, offsetReg, isLong ? 8 : 4));8055if (oldValueInReg)8056generateTrg1Src2Instruction(cg, isLong ? TR::InstOpCode::cmp8 : TR::InstOpCode::cmp4, node, cndReg, resultReg, oldVReg);8057else8058generateTrg1Src1ImmInstruction(cg, isLong ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, cndReg, resultReg, oldValue);8059generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0);80608061// We don't know how the compare will fare such that we don't dictate the prediction8062generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, doneLabel, cndReg);80638064generateMemSrc1Instruction(cg, isLong ? TR::InstOpCode::stdcx_r : TR::InstOpCode::stwcx_r, node, TR::MemoryReference::createWithIndexReg(cg, objReg, offsetReg, isLong ? 8 : 4), newVReg);8065// We expect this store is usually successful, i.e., the following branch will not be taken8066generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, cndReg);80678068// We deviate from the VM helper here: no-store-no-barrier instead of always-barrier8069if (!casWithoutSync)8070generateInstruction(cg, TR::InstOpCode::sync, node);8071generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1);80728073node->setRegister(resultReg);8074return resultReg;8075}80768077static TR::Register *VMinlineCompareAndSwap(TR::Node *node, TR::CodeGenerator *cg, bool isLong)8078{8079TR::Compilation * comp = cg->comp();8080TR::Register *objReg, *offsetReg, *oldVReg, *newVReg, *resultReg, *cndReg;8081TR::Node *firstChild, *secondChild, *thirdChild, *fourthChild, *fifthChild;8082TR::RegisterDependencyConditions *conditions;8083TR::LabelSymbol *doneLabel;8084intptr_t offsetValue, oldValue;8085bool oldValueInReg = true, freeOffsetReg = false;8086TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());80878088firstChild = node->getFirstChild();8089secondChild = node->getSecondChild();8090thirdChild = node->getChild(2);8091fourthChild = node->getChild(3);8092fifthChild = node->getChild(4);8093objReg = cg->evaluate(secondChild);80948095// VM helper chops off the value in 32bit, and we don't want the whole long value either8096if (thirdChild->getOpCode().isLoadConst() && thirdChild->getRegister() == NULL && comp->target().is32Bit())8097{8098offsetValue = thirdChild->getLongInt();8099offsetReg = cg->allocateRegister();8100loadConstant(cg, node, (int32_t) offsetValue, offsetReg);8101freeOffsetReg = true;8102}8103else8104{8105offsetReg = cg->evaluate(thirdChild);8106if (comp->target().is32Bit())8107offsetReg = offsetReg->getLowOrder();8108}81098110if (fourthChild->getOpCode().isLoadConst() && fourthChild->getRegister() == NULL)8111{8112if (isLong)8113oldValue = fourthChild->getLongInt();8114else8115oldValue = fourthChild->getInt();8116if (oldValue >= LOWER_IMMED && oldValue <= UPPER_IMMED)8117oldValueInReg = false;8118}8119if (oldValueInReg)8120oldVReg = cg->evaluate(fourthChild);8121newVReg = cg->evaluate(fifthChild);8122cndReg = cg->allocateRegister(TR_CCR);8123doneLabel = generateLabelSymbol(cg);81248125bool casWithoutSync = false;8126TR_OpaqueMethodBlock *caller = node->getOwningMethod();8127if (caller)8128{8129TR_ResolvedMethod *m = fej9->createResolvedMethod(cg->trMemory(), caller, node->getSymbolReference()->getOwningMethod(comp));8130if ((m->getRecognizedMethod() == TR::java_util_concurrent_atomic_AtomicInteger_weakCompareAndSet)8131|| (m->getRecognizedMethod() == TR::java_util_concurrent_atomic_AtomicLong_weakCompareAndSet)8132|| (m->getRecognizedMethod() == TR::java_util_concurrent_atomic_AtomicReference_weakCompareAndSet))8133{8134casWithoutSync = true;8135}8136}81378138resultReg = genCAS(node, cg, objReg, offsetReg, oldVReg, newVReg, cndReg, doneLabel, secondChild, oldValue, oldValueInReg, isLong, casWithoutSync);81398140conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(6, 6, cg->trMemory());8141TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);8142conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();8143TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);8144TR::addDependency(conditions, resultReg, TR::RealRegister::NoReg, TR_GPR, cg);8145TR::addDependency(conditions, newVReg, TR::RealRegister::NoReg, TR_GPR, cg);8146if (oldValueInReg)8147TR::addDependency(conditions, oldVReg, TR::RealRegister::NoReg, TR_GPR, cg);8148TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);81498150generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);81518152cg->stopUsingRegister(cndReg);8153cg->recursivelyDecReferenceCount(firstChild);8154cg->decReferenceCount(secondChild);8155if (freeOffsetReg)8156{8157cg->stopUsingRegister(offsetReg);8158cg->recursivelyDecReferenceCount(thirdChild);8159}8160else8161cg->decReferenceCount(thirdChild);8162if (oldValueInReg)8163cg->decReferenceCount(fourthChild);8164else8165cg->recursivelyDecReferenceCount(fourthChild);8166cg->decReferenceCount(fifthChild);8167return resultReg;8168}81698170static TR::Register *VMinlineCompareAndSwapObject(TR::Node *node, TR::CodeGenerator *cg)8171{8172TR::Compilation *comp = cg->comp();8173TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());8174TR::Register *objReg, *offsetReg, *oldVReg, *newVReg, *resultReg, *cndReg;8175TR::Node *firstChild, *secondChild, *thirdChild, *fourthChild, *fifthChild;8176TR::RegisterDependencyConditions *conditions;8177TR::LabelSymbol *doneLabel, *storeLabel, *wrtBarEndLabel;8178intptr_t offsetValue;8179bool freeOffsetReg = false;8180bool needDup = false;81818182auto gcMode = TR::Compiler->om.writeBarrierType();8183bool doWrtBar = (gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always8184|| comp->getOptions()->realTimeGC());8185bool doCrdMrk = (gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental);81868187firstChild = node->getFirstChild();8188secondChild = node->getSecondChild();8189thirdChild = node->getChild(2);8190fourthChild = node->getChild(3);8191fifthChild = node->getChild(4);8192objReg = cg->evaluate(secondChild);81938194// VM helper chops off the value in 32bit, and we don't want the whole long value either8195if (thirdChild->getOpCode().isLoadConst() && thirdChild->getRegister() == NULL && comp->target().is32Bit())8196{8197offsetValue = thirdChild->getLongInt();8198offsetReg = cg->allocateRegister();8199loadConstant(cg, node, (int32_t) offsetValue, offsetReg);8200freeOffsetReg = true;8201}8202else8203{8204offsetReg = cg->evaluate(thirdChild);8205if (comp->target().is32Bit())8206offsetReg = offsetReg->getLowOrder();8207}82088209oldVReg = cg->evaluate(fourthChild);82108211TR::Node *translatedNode = fifthChild;8212bool bumpedRefCount = false;8213if (comp->useCompressedPointers() && (fifthChild->getDataType() != TR::Address))8214{8215bool useShiftedOffsets = (TR::Compiler->om.compressedReferenceShiftOffset() != 0);82168217translatedNode = fifthChild;8218if (translatedNode->getOpCode().isConversion())8219translatedNode = translatedNode->getFirstChild();8220if (translatedNode->getOpCode().isRightShift()) // optional8221translatedNode = translatedNode->getFirstChild();82228223translatedNode = fifthChild;8224if (useShiftedOffsets)8225{8226while ((translatedNode->getNumChildren() > 0) && (translatedNode->getOpCodeValue() != TR::a2l))8227translatedNode = translatedNode->getFirstChild();82288229if (translatedNode->getOpCodeValue() == TR::a2l)8230translatedNode = translatedNode->getFirstChild();82318232// this is required so that different registers are8233// allocated for the actual store and translated values8234translatedNode->incReferenceCount();8235bumpedRefCount = true;8236}8237}82388239newVReg = cg->evaluate(fifthChild);8240if (objReg == newVReg)8241{8242newVReg = cg->allocateCollectedReferenceRegister();8243generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, newVReg, objReg);8244needDup = true;8245}8246cndReg = cg->allocateRegister(TR_CCR);8247doneLabel = generateLabelSymbol(cg);8248storeLabel = generateLabelSymbol(cg);82498250if (comp->getOptions()->realTimeGC())8251wrtBarEndLabel = storeLabel;8252else8253wrtBarEndLabel = doneLabel;82548255#ifdef OMR_GC_CONCURRENT_SCAVENGER8256if (TR::Compiler->om.readBarrierType() != gc_modron_readbar_none)8257{8258TR::Register *tmpReg = cg->allocateRegister();8259TR::Register *locationReg = cg->allocateRegister();8260TR::Register *evacuateReg = cg->allocateRegister();8261TR::Register *r3Reg = cg->allocateRegister();8262TR::Register *r11Reg = cg->allocateRegister();8263TR::Register *metaReg = cg->getMethodMetaDataRegister();82648265TR::LabelSymbol *startReadBarrierLabel = generateLabelSymbol(cg);8266TR::LabelSymbol *endReadBarrierLabel = generateLabelSymbol(cg);82678268TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 9, cg->trMemory());8269deps->addPostCondition(objReg, TR::RealRegister::NoReg);8270deps->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();8271deps->addPostCondition(offsetReg, TR::RealRegister::NoReg);8272deps->addPostCondition(tmpReg, TR::RealRegister::NoReg);8273deps->addPostCondition(locationReg, TR::RealRegister::gr4); //TR_softwareReadBarrier helper needs this in gr4.8274deps->addPostCondition(evacuateReg, TR::RealRegister::NoReg);8275deps->addPostCondition(r3Reg, TR::RealRegister::gr3);8276deps->addPostCondition(r11Reg, TR::RealRegister::gr11);8277deps->addPostCondition(metaReg, TR::RealRegister::NoReg);8278deps->addPostCondition(cndReg, TR::RealRegister::NoReg);82798280startReadBarrierLabel->setStartInternalControlFlow();8281endReadBarrierLabel->setEndInternalControlFlow();82828283TR::InstOpCode::Mnemonic loadOpCode = TR::InstOpCode::lwz;8284TR::InstOpCode::Mnemonic cmpOpCode = TR::InstOpCode::cmpl4;8285int32_t loadWidth = 4;82868287if (comp->target().is64Bit() && !comp->useCompressedPointers())8288{8289loadOpCode = TR::InstOpCode::ld;8290cmpOpCode = TR::InstOpCode::cmpl8;8291loadWidth = 8;8292}82938294generateTrg1MemInstruction(cg, loadOpCode, node, tmpReg, TR::MemoryReference::createWithIndexReg(cg, objReg, offsetReg, loadWidth));82958296generateLabelInstruction(cg, TR::InstOpCode::label, node, startReadBarrierLabel);82978298generateTrg1MemInstruction(cg, loadOpCode, node, evacuateReg,8299TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateBaseAddressOffset(), loadWidth));8300generateTrg1Src2Instruction(cg, cmpOpCode, node, cndReg, tmpReg, evacuateReg);8301generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, endReadBarrierLabel, cndReg);83028303generateTrg1MemInstruction(cg, loadOpCode, node, evacuateReg,8304TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateTopAddressOffset(), loadWidth));8305generateTrg1Src2Instruction(cg, cmpOpCode, node, cndReg, tmpReg, evacuateReg);8306generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, endReadBarrierLabel, cndReg);83078308generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, locationReg, objReg, offsetReg);83098310// TR_softwareReadBarrier helper expects the vmThread in r3.8311generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r3Reg, metaReg);83128313TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(TR_softwareReadBarrier);8314generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), deps, helperSym);83158316generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endReadBarrierLabel, deps);83178318cg->stopUsingRegister(tmpReg);8319cg->stopUsingRegister(locationReg);8320cg->stopUsingRegister(evacuateReg);8321cg->stopUsingRegister(r11Reg);8322cg->stopUsingRegister(r3Reg);83238324cg->machine()->setLinkRegisterKilled(true);8325}8326#endif //OMR_GC_CONCURRENT_SCAVENGER83278328if (!comp->getOptions()->realTimeGC())8329resultReg = genCAS(node, cg, objReg, offsetReg, oldVReg, newVReg, cndReg, doneLabel, secondChild, 0, true, (comp->target().is64Bit() && !comp->useCompressedPointers()));83308331uint32_t numDeps = (doWrtBar || doCrdMrk) ? 13 : 11;83328333if (doWrtBar) //two extra deps for space boundaries8334numDeps += 2;83358336conditions = createConditionsAndPopulateVSXDeps(cg, numDeps);83378338if (doWrtBar && doCrdMrk)8339{8340TR::Register *temp1Reg = cg->allocateRegister(), *temp2Reg = cg->allocateRegister(), *temp3Reg, *temp4Reg = cg->allocateRegister();8341TR::addDependency(conditions, objReg, TR::RealRegister::gr3, TR_GPR, cg);8342TR::Register *wrtbarSrcReg;8343if (translatedNode != fifthChild)8344{8345TR::addDependency(conditions, newVReg, TR::RealRegister::NoReg, TR_GPR, cg);8346TR::addDependency(conditions, translatedNode->getRegister(), TR::RealRegister::gr4, TR_GPR, cg);8347wrtbarSrcReg = translatedNode->getRegister();8348}8349else8350{8351TR::addDependency(conditions, newVReg, TR::RealRegister::gr4, TR_GPR, cg);8352wrtbarSrcReg = newVReg;8353}83548355TR::addDependency(conditions, temp1Reg, TR::RealRegister::gr11, TR_GPR, cg);8356TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);8357TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);8358TR::addDependency(conditions, temp4Reg, TR::RealRegister::NoReg, TR_GPR, cg);83598360if (freeOffsetReg)8361{8362temp3Reg = offsetReg;8363}8364else8365{8366temp3Reg = cg->allocateRegister();8367TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);8368}83698370if (!fifthChild->isNonNull())8371{8372generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cndReg, newVReg, NULLVALUE);8373generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, cndReg);8374}83758376VMnonNullSrcWrtBarCardCheckEvaluator(node, comp->useCompressedPointers() ? wrtbarSrcReg : newVReg, objReg, cndReg, temp1Reg, temp2Reg, temp3Reg, temp4Reg, doneLabel,8377conditions, comp->useCompressedPointers(), cg);83788379cg->stopUsingRegister(temp1Reg);8380cg->stopUsingRegister(temp2Reg);8381if (!freeOffsetReg)8382cg->stopUsingRegister(temp3Reg);8383cg->stopUsingRegister(temp4Reg);8384}8385else if (doWrtBar && !doCrdMrk)8386{8387TR::Register *temp1Reg = cg->allocateRegister(), *temp2Reg;8388TR::addDependency(conditions, objReg, TR::RealRegister::gr3, TR_GPR, cg);83898390if (newVReg != translatedNode->getRegister())8391{8392TR::addDependency(conditions, newVReg, TR::RealRegister::NoReg, TR_GPR, cg);8393if (comp->getOptions()->realTimeGC())8394TR::addDependency(conditions, translatedNode->getRegister(), TR::RealRegister::gr5, TR_GPR, cg);8395else8396TR::addDependency(conditions, translatedNode->getRegister(), TR::RealRegister::gr4, TR_GPR, cg);8397}8398else8399{8400if (comp->getOptions()->realTimeGC())8401TR::addDependency(conditions, newVReg, TR::RealRegister::gr5, TR_GPR, cg);8402else8403TR::addDependency(conditions, newVReg, TR::RealRegister::gr4, TR_GPR, cg);8404}84058406TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);84078408//Realtime needs the offsetReg to be preserved after the wrtbar to do the store in genCAS()8409if (freeOffsetReg && !comp->getOptions()->realTimeGC())8410{8411TR::addDependency(conditions, offsetReg, TR::RealRegister::gr11, TR_GPR, cg);8412temp2Reg = offsetReg;8413}8414else8415{8416temp2Reg = cg->allocateRegister();8417TR::addDependency(conditions, temp2Reg, TR::RealRegister::gr11, TR_GPR, cg);8418TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);8419}84208421if (!fifthChild->isNonNull())8422{8423generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cndReg, newVReg, NULLVALUE);8424generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, wrtBarEndLabel, cndReg);8425}84268427TR::Register *dstAddrReg = NULL;84288429if (comp->getOptions()->realTimeGC())8430{8431dstAddrReg = cg->allocateRegister();8432TR::addDependency(conditions, dstAddrReg, TR::RealRegister::gr4, TR_GPR, cg);8433generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, dstAddrReg, objReg, offsetReg);8434}84358436VMnonNullSrcWrtBarCardCheckEvaluator(node, comp->useCompressedPointers() ? translatedNode->getRegister() : newVReg, objReg, cndReg, temp1Reg, temp2Reg, dstAddrReg, NULL,8437wrtBarEndLabel, conditions, comp->useCompressedPointers(), cg);84388439if (comp->getOptions()->realTimeGC())8440cg->stopUsingRegister(dstAddrReg);84418442cg->stopUsingRegister(temp1Reg);8443if (!freeOffsetReg || comp->getOptions()->realTimeGC())8444cg->stopUsingRegister(temp2Reg);8445}8446else if (!doWrtBar && doCrdMrk)8447{8448TR::Register *temp1Reg = cg->allocateRegister(), *temp2Reg = cg->allocateRegister(), *temp3Reg;8449TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);8450conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();8451TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);8452conditions->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0();8453if (newVReg != translatedNode->getRegister())8454TR::addDependency(conditions, newVReg, TR::RealRegister::NoReg, TR_GPR, cg);8455TR::addDependency(conditions, translatedNode->getRegister(), TR::RealRegister::NoReg, TR_GPR, cg);84568457TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);8458TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);8459if (freeOffsetReg)8460{8461temp3Reg = offsetReg;8462}8463else8464{8465temp3Reg = cg->allocateRegister();8466TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);8467}84688469VMCardCheckEvaluator(node, objReg, cndReg, temp1Reg, temp2Reg, temp3Reg, conditions, cg);84708471cg->stopUsingRegister(temp1Reg);8472cg->stopUsingRegister(temp2Reg);8473if (!freeOffsetReg)8474cg->stopUsingRegister(temp3Reg);8475}8476else8477{8478TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);8479conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();8480TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);8481if (newVReg != translatedNode->getRegister())8482TR::addDependency(conditions, newVReg, TR::RealRegister::NoReg, TR_GPR, cg);8483TR::addDependency(conditions, translatedNode->getRegister(), TR::RealRegister::NoReg, TR_GPR, cg);8484}84858486generateLabelInstruction(cg, TR::InstOpCode::label, node, storeLabel);84878488if (comp->getOptions()->realTimeGC())8489resultReg = genCAS(node, cg, objReg, offsetReg, oldVReg, newVReg, cndReg, doneLabel, secondChild, 0, true, (comp->target().is64Bit() && !comp->useCompressedPointers()));84908491TR::addDependency(conditions, resultReg, TR::RealRegister::NoReg, TR_GPR, cg);8492if (oldVReg != newVReg && oldVReg != objReg)8493TR::addDependency(conditions, oldVReg, TR::RealRegister::NoReg, TR_GPR, cg);8494TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);84958496generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);84978498if (needDup)8499cg->stopUsingRegister(newVReg);8500cg->stopUsingRegister(cndReg);8501cg->recursivelyDecReferenceCount(firstChild);8502cg->decReferenceCount(secondChild);8503if (freeOffsetReg)8504{8505cg->stopUsingRegister(offsetReg);8506cg->recursivelyDecReferenceCount(thirdChild);8507}8508else8509cg->decReferenceCount(thirdChild);8510cg->decReferenceCount(fourthChild);8511cg->decReferenceCount(fifthChild);8512if (bumpedRefCount)8513cg->decReferenceCount(translatedNode);85148515return resultReg;8516}851785188519void J9::Power::TreeEvaluator::restoreTOCRegister(TR::Node *node, TR::CodeGenerator *cg, TR::RegisterDependencyConditions *dependencies)8520{8521#if defined(TR_HOST_POWER)8522TR::Compilation *comp = cg->comp();8523TR::Register *tocReg = dependencies->searchPreConditionRegister(TR::RealRegister::gr2);8524generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, tocReg,8525TR::MemoryReference::createWithDisplacement(cg, cg->getMethodMetaDataRegister(), offsetof(J9VMThread, jitTOC), TR::Compiler->om.sizeofReferenceAddress()));8526#else8527TR_ASSERT(0, "direct C calls directly are not supported on this platform.\n");8528#endif8529}85308531void J9::Power::TreeEvaluator::buildArgsProcessFEDependencies(TR::Node *node, TR::CodeGenerator *cg, TR::RegisterDependencyConditions *dependencies)8532{8533TR::Compilation *comp = cg->comp();8534//Java uses gr2 as a volatile for targets except for 32-bit Linux.8535bool aix_style_linkage = (comp->target().isAIX() || (comp->target().is64Bit() && comp->target().isLinux()));85368537if(aix_style_linkage)8538TR::addDependency(dependencies, NULL, TR::RealRegister::gr2, TR_GPR, cg);8539}85408541TR::Register *J9::Power::TreeEvaluator::retrieveTOCRegister(TR::Node *node, TR::CodeGenerator *cg, TR::RegisterDependencyConditions *dependencies)8542{8543#if defined(DEBUG)8544TR::Compilation *comp = cg->comp();8545//We should not land here if we're compiling for 32-bit Linux.8546bool aix_style_linkage = (comp->target().isAIX() || (comp->target().is64Bit() && comp->target().isLinux()));8547TR_ASSERT(aix_style_linkage, "Landed to restore gr2 for TOC with 32bit Linux as target\n");8548#endif85498550TR::Register *grTOCReg=dependencies->searchPreConditionRegister(TR::RealRegister::gr2);8551TR_ASSERT(grTOCReg != NULL, "Dependency not set in J9 Java on gr2 for TOC.\n");8552return grTOCReg;8553}855485558556static TR::Register *inlineAtomicOps(TR::Node *node, TR::CodeGenerator *cg, int8_t size, TR::MethodSymbol *method, bool isArray)8557{8558TR::Node *valueChild = node->getFirstChild();8559TR::Node *deltaChild = NULL;8560TR::Register *valueReg = cg->evaluate(valueChild);8561TR::Register *deltaReg = NULL;8562TR::Register *resultReg = cg->allocateRegister();8563TR::Register *cndReg = cg->allocateRegister(TR_CCR);8564TR::Register *fieldOffsetReg = cg->allocateRegister();8565TR::Register *tempReg = NULL;8566int32_t delta = 0;8567int32_t numDeps = 5;8568TR::Compilation *comp = cg->comp();8569TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());85708571bool isAddOp = true;8572bool isGetAndOp = true;8573bool isLong = false;8574bool isArgConstant = false;8575bool isArgImmediate = false;8576bool isArgImmediateShifted = false;8577TR::RecognizedMethod currentMethod = method->getRecognizedMethod();85788579switch (currentMethod)8580{8581case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:8582case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:8583case TR::java_util_concurrent_atomic_AtomicLong_getAndSet:8584case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:8585case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:8586case TR::java_util_concurrent_atomic_AtomicLongArray_getAndSet:8587case TR::java_util_concurrent_atomic_AtomicReferenceArray_getAndSet:8588{8589isAddOp = false;8590break;8591}8592case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:8593case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:8594{8595isGetAndOp = false;8596}8597case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:8598case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:8599{8600break;8601}86028603case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:8604case TR::java_util_concurrent_atomic_AtomicIntegerArray_incrementAndGet:8605{8606isGetAndOp = false;8607}8608case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:8609case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:8610{8611delta = (int32_t) 1;8612isArgConstant = true;8613isArgImmediate = true;8614break;8615}8616case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:8617case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:8618{8619isGetAndOp = false;8620}8621case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:8622case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:8623{8624delta = (int32_t) - 1;8625isArgConstant = true;8626isArgImmediate = true;8627break;8628}8629}86308631if (node->getNumChildren() > 1)8632deltaChild = node->getSecondChild();86338634//determine if the delta is a constant.8635if (deltaChild && deltaChild->getOpCode().isLoadConst() && !deltaChild->getRegister() && deltaChild->getDataType() == TR::Int32)8636{8637delta = (int32_t)(deltaChild->getInt());8638isArgConstant = true;86398640//determine if the constant can be represented as an immediate8641if (delta <= UPPER_IMMED && delta >= LOWER_IMMED)8642{8643// avoid evaluating immediates for add operations8644isArgImmediate = true;8645}8646else if (delta & 0xFFFF == 0 && (delta & 0xFFFF0000) >> 16 <= UPPER_IMMED && (delta & 0xFFFF0000) >> 16 >= LOWER_IMMED)8647{8648// avoid evaluating shifted immediates for add operations8649isArgImmediate = true;8650isArgImmediateShifted = true;8651}8652else8653{8654// evaluate non-immediate constants since there may be reuse8655// and they have to go into a reg anyway8656tempReg = cg->evaluate(deltaChild);8657}8658}8659else if (deltaChild)8660tempReg = cg->evaluate(deltaChild);86618662//determine the offset of the value field8663int32_t fieldOffset = 0;8664int32_t shiftAmount = 0;8665TR::Node *indexChild = NULL;8666TR::Register *indexRegister = NULL;86678668TR::Register *scratchRegister = NULL;86698670if (!isArray)8671{8672TR_OpaqueClassBlock * bdClass;8673char *className, *fieldSig;8674int32_t classNameLen, fieldSigLen;86758676fieldSigLen = 1;86778678switch (currentMethod)8679{8680case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:8681className = "Ljava/util/concurrent/atomic/AtomicBoolean;";8682classNameLen = 43;8683fieldSig = "I"; // not a typo, the field is int8684break;8685case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:8686case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:8687case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:8688case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:8689case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:8690case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:8691case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:8692className = "Ljava/util/concurrent/atomic/AtomicInteger;";8693classNameLen = 43;8694fieldSig = "I";8695break;8696case TR::java_util_concurrent_atomic_AtomicLong_getAndSet:8697case TR::java_util_concurrent_atomic_AtomicLong_addAndGet:8698case TR::java_util_concurrent_atomic_AtomicLong_getAndAdd:8699case TR::java_util_concurrent_atomic_AtomicLong_incrementAndGet:8700case TR::java_util_concurrent_atomic_AtomicLong_getAndIncrement:8701case TR::java_util_concurrent_atomic_AtomicLong_decrementAndGet:8702case TR::java_util_concurrent_atomic_AtomicLong_getAndDecrement:8703className = "Ljava/util/concurrent/atomic/AtomicLong;";8704classNameLen = 40;8705fieldSig = "J";8706break;8707case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:8708className = "Ljava/util/concurrent/atomic/AtomicReference;";8709classNameLen = 45;8710fieldSig = "Ljava/lang/Object;";8711fieldSigLen = 18;8712break;8713default:8714TR_ASSERT(0, "Unknown atomic operation method\n");8715return NULL;8716}87178718TR_ResolvedMethod *owningMethod = node->getSymbolReference()->getOwningMethod(comp);8719TR_OpaqueClassBlock *containingClass = fej9->getClassFromSignature(className, classNameLen, owningMethod, true);8720fieldOffset = fej9->getInstanceFieldOffset(containingClass, "value", 5, fieldSig, fieldSigLen, true) + fej9->getObjectHeaderSizeInBytes(); // size of a J9 object header8721}8722else8723{8724if (isArray)8725{8726indexChild = node->getChild(1);8727indexRegister = cg->evaluate(indexChild);8728fieldOffset = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();8729if (size == 4)8730shiftAmount = 2;8731else if (size == 8)8732shiftAmount = 3;87338734TR_OpaqueClassBlock * bdClass;8735char *className, *fieldSig;8736int32_t classNameLen, fieldSigLen;87378738fieldSigLen = 1;87398740switch (currentMethod)8741{8742case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:8743case TR::java_util_concurrent_atomic_AtomicIntegerArray_incrementAndGet:8744case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:8745case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:8746case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:8747case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:8748case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:8749className = "Ljava/util/concurrent/atomic/AtomicIntegerArray;";8750classNameLen = 48;8751fieldSig = "[I";8752fieldSigLen = 2;8753break;87548755case TR::java_util_concurrent_atomic_AtomicLongArray_getAndSet:8756case TR::java_util_concurrent_atomic_AtomicLongArray_incrementAndGet:8757case TR::java_util_concurrent_atomic_AtomicLongArray_getAndIncrement:8758case TR::java_util_concurrent_atomic_AtomicLongArray_decrementAndGet:8759case TR::java_util_concurrent_atomic_AtomicLongArray_getAndDecrement:8760case TR::java_util_concurrent_atomic_AtomicLongArray_addAndGet:8761case TR::java_util_concurrent_atomic_AtomicLongArray_getAndAdd:8762className = "Ljava/util/concurrent/atomic/AtomicLongArray;";8763classNameLen = 45;8764fieldSig = "[J";8765fieldSigLen = 2;8766break;87678768case TR::java_util_concurrent_atomic_AtomicReferenceArray_getAndSet:8769className = "Ljava/util/concurrent/atomic/AtomicReferenceArray;";8770classNameLen = 50;8771fieldSig = "Ljava/lang/Object;";8772fieldSigLen = 18;8773break;8774}87758776TR_ResolvedMethod *owningMethod = node->getSymbolReference()->getOwningMethod(comp);8777TR_OpaqueClassBlock *containingClass = fej9->getClassFromSignature(className, classNameLen, owningMethod, true);8778int32_t arrayFieldOffset = fej9->getInstanceFieldOffset(containingClass, "array", 5, fieldSig, fieldSigLen) + fej9->getObjectHeaderSizeInBytes(); // size of a J9 object header87798780TR::MemoryReference *tempMR = TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, isLong ? 8 : 4);87818782numDeps++;8783scratchRegister = cg->allocateCollectedReferenceRegister();8784TR::Register *memRefRegister = scratchRegister;87858786if (TR::Compiler->om.compressObjectReferences())8787// read only 32 bits8788generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, memRefRegister,8789TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, 4));8790else8791generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, memRefRegister, TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, TR::Compiler->om.sizeofReferenceAddress()));87928793valueReg = memRefRegister;87948795generateShiftLeftImmediate(cg, node, fieldOffsetReg, indexRegister, shiftAmount);8796generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, fieldOffsetReg, fieldOffsetReg, fieldOffset);8797}8798}87998800// Memory barrier --- NOTE: we should be able to do a test upfront to save this barrier,8801// but Hursley advised to be conservative due to lack of specification.8802generateInstruction(cg, TR::InstOpCode::lwsync, node);88038804TR::LabelSymbol *doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);8805TR::LabelSymbol *loopLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);88068807loopLabel->setStartInternalControlFlow();8808if (!isArray)8809generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, fieldOffsetReg, fieldOffset);88108811deltaReg = cg->allocateRegister();8812if (isArgImmediate && isAddOp)8813{8814// If argument is an immediate value and operation is an add,8815// it will be used as an immediate operand in an add immediate instruction8816generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);8817}8818else if (isArgImmediate)8819{8820// If argument is immediate, but the operation is not an add,8821// the value must still be loaded into a register8822generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);8823loadConstant(cg, node, delta, deltaReg);8824}8825else8826{8827// For non-constant arguments, use evaluated register8828// For non-immediate constants, evaluate since they may be re-used8829numDeps++;8830generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);8831generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, deltaReg, tempReg);8832}88338834generateTrg1MemInstruction(cg, isLong ? TR::InstOpCode::ldarx : TR::InstOpCode::lwarx, node, resultReg,8835TR::MemoryReference::createWithIndexReg(cg, valueReg, fieldOffsetReg, isLong ? 8 : 4));88368837if (isAddOp)8838{8839if (isArgImmediateShifted)8840generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, deltaReg, resultReg, ((delta & 0xFFFF0000) >> 16));8841else if (isArgImmediate)8842generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, deltaReg, resultReg, delta);8843else8844generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, deltaReg, resultReg, deltaReg);8845}88468847generateMemSrc1Instruction(cg, isLong ? TR::InstOpCode::stdcx_r : TR::InstOpCode::stwcx_r, node, TR::MemoryReference::createWithIndexReg(cg, valueReg, fieldOffsetReg, isLong ? 8 : 4),8848deltaReg);88498850// We expect this store is usually successful, i.e., the following branch will not be taken8851generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, cndReg);88528853// We deviate from the VM helper here: no-store-no-barrier instead of always-barrier8854generateInstruction(cg, TR::InstOpCode::sync, node);88558856TR::RegisterDependencyConditions *conditions;88578858//Set the conditions and dependencies8859conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, (uint16_t) numDeps, cg->trMemory());8860conditions->addPostCondition(valueReg, TR::RealRegister::NoReg);8861conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();8862conditions->addPostCondition(resultReg, TR::RealRegister::NoReg);8863conditions->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0();8864conditions->addPostCondition(deltaReg, TR::RealRegister::NoReg);8865conditions->addPostCondition(cndReg, TR::RealRegister::cr0);8866conditions->addPostCondition(fieldOffsetReg, TR::RealRegister::NoReg);8867if (tempReg)8868conditions->addPostCondition(tempReg, TR::RealRegister::NoReg);8869if (scratchRegister)8870conditions->addPostCondition(scratchRegister, TR::RealRegister::NoReg);88718872doneLabel->setEndInternalControlFlow();8873generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);88748875cg->decReferenceCount(valueChild);8876cg->stopUsingRegister(cndReg);8877cg->stopUsingRegister(fieldOffsetReg);88788879if (tempReg)8880cg->stopUsingRegister(tempReg);88818882if (scratchRegister)8883cg->stopUsingRegister(scratchRegister);88848885if (deltaChild)8886cg->decReferenceCount(deltaChild);88878888if (isGetAndOp)8889{8890//for Get And Op, we will store the result in the result register8891cg->stopUsingRegister(deltaReg);8892node->setRegister(resultReg);8893return resultReg;8894}8895else8896{8897//for Op And Get, we will store the return value in the delta register8898//we no longer need the result register8899cg->stopUsingRegister(resultReg);8900node->setRegister(deltaReg);8901return deltaReg;8902}8903}89048905static TR::Register *inlineSinglePrecisionFP(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)8906{8907TR_ASSERT(node->getNumChildren() == 1, "Wrong number of children in inlineSinglePrecisionFP");89088909TR::Node *firstChild = node->getFirstChild();8910TR::Register *srcRegister = cg->evaluate(firstChild);8911TR::Register *targetRegister = cg->allocateSinglePrecisionRegister();89128913generateTrg1Src1Instruction(cg, op, node, targetRegister, srcRegister);89148915node->setRegister(targetRegister);8916cg->decReferenceCount(firstChild);89178918return targetRegister;8919}89208921static TR::Register *inlineSinglePrecisionFPTrg1Src2(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)8922{8923TR_ASSERT(node->getNumChildren() == 2, "Wrong number of children in inlineSinglePrecisionFPTrg1Src2");89248925TR::Node *firstChild = node->getFirstChild();8926TR::Node *secondChild = node->getSecondChild();8927TR::Register *src1Register = cg->evaluate(firstChild);8928TR::Register *src2Register = cg->evaluate(secondChild);8929TR::Register *targetRegister = cg->allocateSinglePrecisionRegister();89308931if (op == TR::InstOpCode::fcpsgn) // fcpsgn orders operands opposite of Math.copySign8932generateTrg1Src2Instruction(cg, op, node, targetRegister, src2Register, src1Register);8933else8934generateTrg1Src2Instruction(cg, op, node, targetRegister, src1Register, src2Register);89358936node->setRegister(targetRegister);8937cg->decReferenceCount(firstChild);8938cg->decReferenceCount(secondChild);8939return targetRegister;8940}89418942static TR::Register *inlineFPTrg1Src3(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)8943{8944TR_ASSERT_FATAL(node->getNumChildren() == 3, "In function inlineFPTrg1Src3, the node at address %p should have exactly 3 children, but got %u instead", node, node->getNumChildren());89458946TR::DataType type = node->getDataType();8947TR_ASSERT_FATAL(type == TR::Float || type == TR::Double, "In function inlineFPTrg1Src3, the node at address %p should be either TR::Float or TR::Double", node);89488949TR::Node *firstChild = node->getFirstChild();8950TR::Node *secondChild = node->getSecondChild();8951TR::Node *thirdChild = node->getThirdChild();8952TR::Register *src1Register = cg->evaluate(firstChild);8953TR::Register *src2Register = cg->evaluate(secondChild);8954TR::Register *src3Register = cg->evaluate(thirdChild);8955TR::Register *targetRegister;89568957if(type == TR::Float)8958targetRegister = cg->allocateSinglePrecisionRegister();8959else8960targetRegister = cg->allocateRegister(TR_FPR);89618962generateTrg1Src3Instruction(cg, op, node, targetRegister, src1Register, src2Register, src3Register);89638964node->setRegister(targetRegister);8965cg->decReferenceCount(firstChild);8966cg->decReferenceCount(secondChild);8967cg->decReferenceCount(thirdChild);8968return targetRegister;8969}89708971static TR::Register *inlineDoublePrecisionFP(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)8972{8973TR_ASSERT(node->getNumChildren() == 1, "Wrong number of children in inlineDoublePrecisionFP");89748975TR::Node *firstChild = node->getFirstChild();8976TR::Register *srcRegister = cg->evaluate(firstChild);8977TR::Register *targetRegister = cg->allocateRegister(TR_FPR);89788979generateTrg1Src1Instruction(cg, op, node, targetRegister, srcRegister);89808981node->setRegister(targetRegister);8982cg->decReferenceCount(firstChild);89838984return targetRegister;8985}89868987static TR::Register *inlineDoublePrecisionFPTrg1Src2(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)8988{8989TR_ASSERT(node->getNumChildren() == 2, "Wrong number of children in inlineDoublePrecisionFPTrg1Src2");89908991TR::Node *firstChild = node->getFirstChild();8992TR::Node *secondChild = node->getSecondChild();8993TR::Register *src1Register = cg->evaluate(firstChild);8994TR::Register *src2Register = cg->evaluate(secondChild);8995TR::Register *targetRegister = cg->allocateRegister(TR_FPR);89968997if (op == TR::InstOpCode::fcpsgn) // fcpsgn orders operands opposite of Math.copySign8998generateTrg1Src2Instruction(cg, op, node, targetRegister, src2Register, src1Register);8999else9000generateTrg1Src2Instruction(cg, op, node, targetRegister, src1Register, src2Register);90019002node->setRegister(targetRegister);9003cg->decReferenceCount(firstChild);9004cg->decReferenceCount(secondChild);9005return targetRegister;9006}90079008static TR::Register *inlineAtomicOperation(TR::Node *node, TR::CodeGenerator *cg, TR::MethodSymbol *method)9009{9010TR::Node *firstChild = NULL;9011TR::Node *valueChild = NULL;9012TR::Node *indexChild = NULL;9013TR::Node *deltaChild = NULL;9014TR::Node *newValChild = NULL;9015TR::Node *expValChild = NULL;9016TR::Node *newRefChild = NULL;9017TR::Node *expRefChild = NULL;9018TR::Node *overNewNode = NULL;9019TR::Node *overExpNode = NULL;90209021TR::LabelSymbol *startLabel = NULL;9022TR::LabelSymbol *failLabel = NULL;9023TR::LabelSymbol *doneLabel = NULL;90249025TR::Register *valueReg = NULL;9026TR::Register *scratchReg = NULL;9027TR::Register *fieldOffsetReg = NULL;9028TR::Register *cndReg = NULL;9029TR::Register *currentReg = NULL;9030TR::Register *newComposedReg = NULL;9031TR::Register *expComposedReg = NULL;9032TR::Register *expRefReg = NULL;9033TR::Register *newRefReg = NULL;9034TR::Register *expValReg = NULL;9035TR::Register *newValReg = NULL;9036TR::Register *resultReg = NULL;9037TR::Register *objReg = NULL;9038TR::Compilation *comp = cg->comp();9039TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());90409041bool isArray = false;9042bool isAddOp = true;9043bool isDeltaImplied = false;9044bool isDelta = false;9045bool isGetAndOp = false;9046bool isCAS = false;9047bool isSetOnly = false;9048bool isWeak = false;9049bool isRefFirst = false;9050bool isUnsafe = false;90519052bool isArgImm = false;9053bool isArgImmShifted = false;90549055bool fieldOffsetRegIsEval = false;9056bool isRefWrite = false;90579058bool newPair = false;9059bool expPair = false;90609061bool stopNewComposedCopy = false;90629063int64_t expValImm;9064int32_t delta;9065uint8_t size = 4;9066int32_t fieldOffset = 0;9067int32_t idx;9068uint8_t numDeps = 1;90699070TR::RecognizedMethod currentMethod = method->getRecognizedMethod();90719072switch (currentMethod)9073{9074case TR::sun_misc_Unsafe_compareAndSwapLong_jlObjectJJJ_Z:9075size = 8;9076isUnsafe = true;9077isCAS = true;9078isAddOp = false;9079break;9080case TR::sun_misc_Unsafe_compareAndSwapObject_jlObjectJjlObjectjlObject_Z:9081size = TR::Compiler->om.sizeofReferenceAddress();9082isRefWrite = true;9083case TR::sun_misc_Unsafe_compareAndSwapInt_jlObjectJII_Z:9084isUnsafe = true;9085isCAS = true;9086isAddOp = false;9087break;9088case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:9089case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:9090case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:9091case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:9092case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:9093case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:9094case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:9095case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:9096case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:9097case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:9098case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:9099case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:9100case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:9101case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:9102case TR::java_util_concurrent_atomic_AtomicIntegerArray_incrementAndGet:9103size = 4;9104break;9105case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:9106case TR::java_util_concurrent_atomic_AtomicReferenceArray_getAndSet:9107size = TR::Compiler->om.sizeofReferenceAddress();9108break;9109default:9110size = 8;9111}91129113switch (currentMethod)9114{9115case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:9116case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:9117case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:9118case TR::java_util_concurrent_atomic_AtomicLong_getAndSet:9119case TR::java_util_concurrent_atomic_AtomicLongArray_getAndSet:9120case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:9121case TR::java_util_concurrent_atomic_AtomicReferenceArray_getAndSet:9122isAddOp = false;9123case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:9124case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:9125case TR::java_util_concurrent_atomic_AtomicLong_getAndAdd:9126case TR::java_util_concurrent_atomic_AtomicLongArray_getAndAdd:9127isDelta = true;9128case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:9129case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:9130case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:9131case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:9132case TR::java_util_concurrent_atomic_AtomicLong_getAndDecrement:9133case TR::java_util_concurrent_atomic_AtomicLong_getAndIncrement:9134case TR::java_util_concurrent_atomic_AtomicLongArray_getAndDecrement:9135case TR::java_util_concurrent_atomic_AtomicLongArray_getAndIncrement:9136isGetAndOp = true;9137break;9138case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:9139case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:9140case TR::java_util_concurrent_atomic_AtomicLong_addAndGet:9141case TR::java_util_concurrent_atomic_AtomicLongArray_addAndGet:9142isDelta = true;9143break;9144}91459146isDeltaImplied = isAddOp && !isDelta;91479148if (isDeltaImplied)9149{9150switch (currentMethod)9151{9152case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:9153case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:9154case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:9155case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:9156case TR::java_util_concurrent_atomic_AtomicLong_decrementAndGet:9157case TR::java_util_concurrent_atomic_AtomicLong_getAndDecrement:9158case TR::java_util_concurrent_atomic_AtomicLongArray_decrementAndGet:9159case TR::java_util_concurrent_atomic_AtomicLongArray_getAndDecrement:9160delta = (int32_t) - 1;9161default:9162delta = (int32_t) 1;9163}9164}91659166if (isUnsafe && isCAS)9167{9168firstChild = node->getChild(0);9169valueChild = node->getChild(1);9170indexChild = node->getChild(2);9171if (isRefWrite)9172{9173expRefChild = node->getChild(3);9174newRefChild = node->getChild(4);9175}9176else9177{9178expValChild = node->getChild(3);9179newValChild = node->getChild(4);9180}9181}9182else9183{9184valueChild = node->getChild(0);9185idx = 1;9186if (isArray)9187{9188indexChild = node->getChild(idx++);9189}9190if (isDelta)9191{9192deltaChild = node->getChild(idx++);9193}9194else if (isCAS)9195{9196expValChild = node->getChild(idx);9197newValChild = node->getChild(idx + 1);9198idx += 2;9199}9200if (idx != node->getNumChildren())9201{9202TR_ASSERT(0, "Wrong number of children for JUC Atomic node\n");9203return NULL;9204}9205}92069207valueReg = cg->evaluate(valueChild);9208objReg = valueReg;92099210if (isUnsafe)9211{9212if (indexChild->getOpCode().isLoadConst() && indexChild->getRegister() == NULL && comp->target().is32Bit())9213{9214fieldOffset = (int32_t) indexChild->getLongInt();9215//traceMsg(comp,"Allocate fieldOffsetReg\n");9216fieldOffsetReg = cg->allocateRegister();9217numDeps++;9218loadConstant(cg, node, fieldOffset, fieldOffsetReg);9219}9220else9221{9222fieldOffsetReg = cg->evaluate(indexChild);9223resultReg = cg->allocateRegister();9224numDeps += 2;9225if (comp->target().is32Bit())9226fieldOffsetReg = fieldOffsetReg->getLowOrder();9227}9228}9229else if (!isArray)9230{9231TR_OpaqueClassBlock *classBlock;9232char *className, *fieldSig;9233int32_t classNameLen, fieldSigLen;9234fieldSigLen = 1;92359236switch (currentMethod)9237{9238case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:9239className = "Ljava/util/concurrent/atomic/AtomicBoolean;";9240classNameLen = 43;9241fieldSig = "I"; // not a type, the field is int9242case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:9243case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:9244case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:9245case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:9246case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:9247case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:9248case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:9249className = "Ljava/util/concurrent/atomic/AtomicInteger;";9250classNameLen = 43;9251fieldSig = "I";9252break;9253case TR::java_util_concurrent_atomic_AtomicLong_addAndGet:9254case TR::java_util_concurrent_atomic_AtomicLong_decrementAndGet:9255case TR::java_util_concurrent_atomic_AtomicLong_getAndAdd:9256case TR::java_util_concurrent_atomic_AtomicLong_getAndDecrement:9257case TR::java_util_concurrent_atomic_AtomicLong_getAndIncrement:9258case TR::java_util_concurrent_atomic_AtomicLong_getAndSet:9259case TR::java_util_concurrent_atomic_AtomicLong_incrementAndGet:9260className = "Ljava/util/concurrent/atomic/AtomicLong;";9261classNameLen = 40;9262fieldSig = "J";9263break;9264case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:9265className = "Ljava/util/concurrent/atomic/AtomicReference;";9266classNameLen = 45;9267fieldSig = "Ljava/lang/Object;";9268fieldSigLen = 18;9269break;9270default:9271TR_ASSERT(0, "Unknown atomic operation method\n");9272return NULL;9273}9274classBlock = fej9->getClassFromSignature(className, classNameLen, comp->getCurrentMethod(), true);9275fieldOffset = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "value", 5, fieldSig, fieldSigLen);9276}9277else // isArray9278{9279TR::Register *indexReg = cg->evaluate(indexChild);9280int32_t shiftAmount = size == 8 ? 3 : 2;9281fieldOffset = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();92829283TR_OpaqueClassBlock *classBlock;9284char *className, *fieldSig;9285int32_t classNameLen, fieldSigLen;9286fieldSigLen = 1;92879288switch (currentMethod)9289{9290case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:9291case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:9292case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:9293case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:9294case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:9295case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:9296case TR::java_util_concurrent_atomic_AtomicIntegerArray_incrementAndGet:9297className = "Ljava/util/concurrent/atomic/AtomicIntegerArray;";9298classNameLen = 48;9299fieldSig = "[I";9300fieldSigLen = 2;9301break;9302case TR::java_util_concurrent_atomic_AtomicLongArray_addAndGet:9303case TR::java_util_concurrent_atomic_AtomicLongArray_decrementAndGet:9304case TR::java_util_concurrent_atomic_AtomicLongArray_getAndAdd:9305case TR::java_util_concurrent_atomic_AtomicLongArray_getAndDecrement:9306case TR::java_util_concurrent_atomic_AtomicLongArray_getAndIncrement:9307case TR::java_util_concurrent_atomic_AtomicLongArray_getAndSet:9308case TR::java_util_concurrent_atomic_AtomicLongArray_incrementAndGet:9309className = "Ljava/util/concurrent/atomic/AtomicLongArray;";9310classNameLen = 45;9311fieldSig = "[J";9312fieldSigLen = 2;9313break;9314case TR::java_util_concurrent_atomic_AtomicReferenceArray_getAndSet:9315className = "Ljava/util/concurrent/atomic/AtomicReferenceArray;";9316classNameLen = 50;9317fieldSig = "[Ljava/lang/Object;";9318fieldSigLen = 19;9319break;9320default:9321TR_ASSERT(0, "Unknown atomic operation method\n");9322return NULL;9323}9324classBlock = fej9->getClassFromSignature(className, classNameLen, comp->getCurrentMethod(), true);9325int32_t arrayFieldOffset = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "array", 5, fieldSig, fieldSigLen);93269327TR::MemoryReference *tempMR = TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, size);9328scratchReg = cg->allocateCollectedReferenceRegister();93299330if (TR::Compiler->om.compressObjectReferences())9331// read only 32 bits9332generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, scratchReg,9333TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, 4));9334else9335generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, TR::Compiler->om.sizeofReferenceAddress()));93369337valueReg = scratchReg;9338fieldOffsetReg = cg->allocateRegister();9339numDeps += 2;9340generateShiftLeftImmediate(cg, node, fieldOffsetReg, indexReg, shiftAmount);9341generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, fieldOffsetReg, fieldOffsetReg, fieldOffset);9342}93439344if (isUnsafe)9345{9346//right now not checking for ref, just doing long!9347if (isRefWrite)9348{9349}9350else9351{9352if (expValChild->getOpCode().isLoadConst() && expValChild->getRegister() == NULL)9353{9354if (size == 8)9355expValImm = expValChild->getLongInt();9356else9357expValImm = expValChild->getInt();9358if (expValImm >= LOWER_IMMED && expValImm <= UPPER_IMMED)9359isArgImm = true;9360}93619362if (!isArgImm)9363{9364expValReg = cg->evaluate(expValChild);9365numDeps++;9366}93679368newValReg = cg->evaluate(newValChild);9369numDeps++;9370}9371}93729373if (isCAS)9374{9375TR::LabelSymbol *rsvFailLabel;9376cndReg = cg->allocateRegister(TR_CCR);9377currentReg = cg->allocateRegister();9378numDeps += 2;9379startLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);9380failLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);9381doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);93829383//allow spurious failures9384rsvFailLabel = isWeak ? failLabel : startLabel;93859386startLabel->setStartInternalControlFlow();93879388if (fieldOffsetReg == NULL)9389{9390numDeps++;9391fieldOffsetReg = cg->allocateRegister();9392loadConstant(cg, node, fieldOffset, fieldOffsetReg);9393}9394if (resultReg == NULL)9395{9396resultReg = fieldOffsetReg;9397}93989399if (!isWeak)9400generateInstruction(cg, TR::InstOpCode::lwsync, node);94019402generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);94039404generateTrg1MemInstruction(cg, size == 8 ? TR::InstOpCode::ldarx : TR::InstOpCode::lwarx, node, currentReg,9405TR::MemoryReference::createWithIndexReg(cg, valueReg, (fieldOffsetReg->getRegisterPair() ? fieldOffsetReg->getLowOrder() : fieldOffsetReg), size));94069407if (size == 8 && comp->target().is32Bit())9408{9409if (!isArgImm && expValReg->getRegisterPair())9410{9411generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldimi, node, expValReg->getLowOrder(), expValReg->getHighOrder(), 32, CONSTANT64(0xFFFFFFFF00000000));9412expPair = true;9413numDeps++;9414}9415if (newValReg->getRegisterPair())9416{9417if (newValReg != expValReg)9418{9419generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldimi, node, newValReg->getLowOrder(), newValReg->getHighOrder(), 32, CONSTANT64(0xFFFFFFFF00000000));9420}9421numDeps++;9422newPair = true;9423}9424}94259426if (!isArgImm && expComposedReg == NULL)9427{9428if (expPair)9429expComposedReg = expValReg->getLowOrder();9430else9431expComposedReg = expValReg != NULL ? expValReg : expRefReg;9432}9433if (newComposedReg == NULL)9434{9435if (newPair)9436newComposedReg = newValReg->getLowOrder();9437else9438newComposedReg = newValReg != NULL ? newValReg : newRefReg;9439}94409441if (isArgImm)9442{9443generateTrg1Src1ImmInstruction(cg, size == 8 ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, cndReg, currentReg, expValImm);9444}9445else9446{9447generateTrg1Src2Instruction(cg, size == 8 ? TR::InstOpCode::cmp8 : TR::InstOpCode::cmp4, node, cndReg, currentReg, expComposedReg);9448}94499450generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, failLabel, cndReg);9451generateMemSrc1Instruction(cg, size == 8 ? TR::InstOpCode::stdcx_r : TR::InstOpCode::stwcx_r, node,9452TR::MemoryReference::createWithIndexReg(cg, valueReg, (fieldOffsetReg->getRegisterPair() ? fieldOffsetReg->getLowOrder() : fieldOffsetReg), size),9453newComposedReg);94549455/* Expect store to be successful, so this branch is usually not taken */9456generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, rsvFailLabel, cndReg);94579458if (!isWeak)9459generateInstruction(cg, TR::InstOpCode::sync, node);94609461generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1);9462generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);9463generateLabelInstruction(cg, TR::InstOpCode::label, node, failLabel);94649465if (!isWeak && size == 8 && comp->target().is32Bit())9466{9467/* store original current value conditionally9468* if it succeeds, then this was a true failure, if it9469* does not, it could have been corruption messing up the compare9470*/9471generateMemSrc1Instruction(cg, size == 8 ? TR::InstOpCode::stdcx_r : TR::InstOpCode::stwcx_r, node,9472TR::MemoryReference::createWithIndexReg(cg, valueReg, (fieldOffsetReg->getRegisterPair() ? fieldOffsetReg->getLowOrder() : fieldOffsetReg), size),9473currentReg);9474/* Expect store to be successful, so this branch is usually not taken */9475generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, startLabel, cndReg);9476}94779478generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0);94799480}94819482TR::RegisterDependencyConditions *conditions;9483conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numDeps, cg->trMemory());9484conditions->addPostCondition(valueReg, TR::RealRegister::NoReg);9485conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();9486conditions->addPostCondition(currentReg, TR::RealRegister::NoReg);94879488numDeps -= 2;9489if (fieldOffsetReg != NULL)9490{9491conditions->addPostCondition(fieldOffsetReg, TR::RealRegister::NoReg);9492numDeps--;9493}9494if (resultReg != fieldOffsetReg)9495{9496conditions->addPostCondition(resultReg, TR::RealRegister::NoReg);9497numDeps--;9498}9499if (objReg != valueReg)9500{9501conditions->addPostCondition(objReg, TR::RealRegister::NoReg);9502numDeps--;9503}9504if (isUnsafe)9505{9506if (isRefWrite)9507{9508conditions->addPostCondition(newRefReg, TR::RealRegister::NoReg);9509conditions->addPostCondition(expRefReg, TR::RealRegister::NoReg);9510numDeps -= 2;9511}9512else9513{9514if (newPair)9515{9516conditions->addPostCondition(newValReg->getHighOrder(), TR::RealRegister::NoReg);9517conditions->addPostCondition(newValReg->getLowOrder(), TR::RealRegister::NoReg);9518numDeps--;9519}9520else9521{9522conditions->addPostCondition(newValReg, TR::RealRegister::NoReg);9523}9524numDeps--;9525if (!isArgImm)9526{9527if (expPair)9528{9529conditions->addPostCondition(expValReg->getHighOrder(), TR::RealRegister::NoReg);9530conditions->addPostCondition(expValReg->getLowOrder(), TR::RealRegister::NoReg);9531numDeps--;9532}9533else9534{9535conditions->addPostCondition(expValReg, TR::RealRegister::NoReg);9536}9537numDeps--;9538}9539}9540}95419542conditions->addPostCondition(cndReg, TR::RealRegister::cr0);9543numDeps--;95449545doneLabel->setEndInternalControlFlow();9546generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);95479548if (firstChild)9549cg->decReferenceCount(firstChild);9550cg->decReferenceCount(valueChild);9551cg->decReferenceCount(indexChild);9552cg->decReferenceCount(expValChild);9553cg->decReferenceCount(newValChild);9554cg->stopUsingRegister(cndReg);9555cg->stopUsingRegister(currentReg);9556node->setRegister(resultReg);95579558return resultReg;9559}95609561static TR::Register *compressStringEvaluator(TR::Node *node, TR::CodeGenerator *cg, bool japaneseMethod)9562{9563TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());9564TR::Node *srcObjNode, *dstObjNode, *startNode, *lengthNode;9565TR::Register *srcObjReg = NULL, *dstObjReg = NULL, *lengthReg = NULL, *startReg = NULL;95669567srcObjNode = node->getChild(0);9568dstObjNode = node->getChild(1);9569startNode = node->getChild(2);9570lengthNode = node->getChild(3);95719572bool stopUsingCopyReg1, stopUsingCopyReg2, stopUsingCopyReg3, stopUsingCopyReg4;95739574stopUsingCopyReg1 = TR::TreeEvaluator::stopUsingCopyReg(srcObjNode, srcObjReg, cg);9575stopUsingCopyReg2 = TR::TreeEvaluator::stopUsingCopyReg(dstObjNode, dstObjReg, cg);9576stopUsingCopyReg3 = TR::TreeEvaluator::stopUsingCopyReg(startNode, startReg, cg);9577stopUsingCopyReg4 = TR::TreeEvaluator::stopUsingCopyReg(lengthNode, lengthReg, cg);95789579uintptr_t hdrSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();9580generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, srcObjReg, srcObjReg, hdrSize);9581generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dstObjReg, dstObjReg, hdrSize);95829583TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(12, 12, cg->trMemory());9584TR::Register *cndRegister = cg->allocateRegister(TR_CCR);9585TR::Register *resultReg = cg->allocateRegister(TR_GPR);9586TR::addDependency(conditions, cndRegister, TR::RealRegister::cr0, TR_CCR, cg);9587TR::addDependency(conditions, lengthReg, TR::RealRegister::gr8, TR_GPR, cg);9588TR::addDependency(conditions, startReg, TR::RealRegister::gr7, TR_GPR, cg);9589TR::addDependency(conditions, srcObjReg, TR::RealRegister::gr9, TR_GPR, cg);9590TR::addDependency(conditions, dstObjReg, TR::RealRegister::gr10, TR_GPR, cg);95919592TR::addDependency(conditions, NULL, TR::RealRegister::gr0, TR_GPR, cg);9593TR::addDependency(conditions, NULL, TR::RealRegister::gr11, TR_GPR, cg);9594TR::addDependency(conditions, NULL, TR::RealRegister::gr6, TR_GPR, cg);9595TR::addDependency(conditions, NULL, TR::RealRegister::gr4, TR_GPR, cg);9596TR::addDependency(conditions, NULL, TR::RealRegister::gr5, TR_GPR, cg);9597TR::addDependency(conditions, NULL, TR::RealRegister::gr12, TR_GPR, cg);9598TR::addDependency(conditions, resultReg, TR::RealRegister::gr3, TR_GPR, cg);95999600if (japaneseMethod)9601TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(TR_PPCcompressStringJ, node, conditions, cg);9602else9603TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(TR_PPCcompressString, node, conditions, cg);96049605TR::Register* regs[5] =9606{9607lengthReg, startReg, srcObjReg, dstObjReg, resultReg9608};9609conditions->stopUsingDepRegs(cg, 5, regs);9610for (uint16_t i = 0; i < node->getNumChildren(); i++)9611cg->decReferenceCount(node->getChild(i));9612if (stopUsingCopyReg1)9613cg->stopUsingRegister(srcObjReg);9614if (stopUsingCopyReg2)9615cg->stopUsingRegister(dstObjReg);9616if (stopUsingCopyReg3)9617cg->stopUsingRegister(startReg);9618if (stopUsingCopyReg4)9619cg->stopUsingRegister(lengthReg);96209621node->setRegister(resultReg);96229623cg->machine()->setLinkRegisterKilled(true);9624cg->setHasCall();9625return (resultReg);9626}96279628static TR::Register *compressStringNoCheckEvaluator(TR::Node *node, TR::CodeGenerator *cg, bool japaneseMethod)9629{9630TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());9631TR::Node *srcObjNode, *dstObjNode, *startNode, *lengthNode;9632TR::Register *srcObjReg = NULL, *dstObjReg = NULL, *lengthReg = NULL, *startReg = NULL;96339634srcObjNode = node->getChild(0);9635dstObjNode = node->getChild(1);9636startNode = node->getChild(2);9637lengthNode = node->getChild(3);96389639bool stopUsingCopyReg1, stopUsingCopyReg2, stopUsingCopyReg3, stopUsingCopyReg4;96409641stopUsingCopyReg1 = TR::TreeEvaluator::stopUsingCopyReg(srcObjNode, srcObjReg, cg);9642stopUsingCopyReg2 = TR::TreeEvaluator::stopUsingCopyReg(dstObjNode, dstObjReg, cg);9643stopUsingCopyReg3 = TR::TreeEvaluator::stopUsingCopyReg(startNode, startReg, cg);9644stopUsingCopyReg4 = TR::TreeEvaluator::stopUsingCopyReg(lengthNode, lengthReg, cg);96459646uintptr_t hdrSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();9647generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, srcObjReg, srcObjReg, hdrSize);9648generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dstObjReg, dstObjReg, hdrSize);96499650int numOfRegs = japaneseMethod ? 11 : 12;9651TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(numOfRegs, numOfRegs, cg->trMemory());9652TR::Register *cndRegister = cg->allocateRegister(TR_CCR);9653TR::addDependency(conditions, cndRegister, TR::RealRegister::cr0, TR_CCR, cg);9654TR::addDependency(conditions, lengthReg, TR::RealRegister::gr8, TR_GPR, cg);9655TR::addDependency(conditions, startReg, TR::RealRegister::gr7, TR_GPR, cg);9656TR::addDependency(conditions, srcObjReg, TR::RealRegister::gr9, TR_GPR, cg);9657TR::addDependency(conditions, dstObjReg, TR::RealRegister::gr10, TR_GPR, cg);96589659TR::addDependency(conditions, NULL, TR::RealRegister::gr0, TR_GPR, cg);9660TR::addDependency(conditions, NULL, TR::RealRegister::gr11, TR_GPR, cg);9661TR::addDependency(conditions, NULL, TR::RealRegister::gr6, TR_GPR, cg);9662TR::addDependency(conditions, NULL, TR::RealRegister::gr4, TR_GPR, cg);9663TR::addDependency(conditions, NULL, TR::RealRegister::gr5, TR_GPR, cg);9664TR::addDependency(conditions, NULL, TR::RealRegister::gr3, TR_GPR, cg);9665if (!japaneseMethod)9666TR::addDependency(conditions, NULL, TR::RealRegister::gr12, TR_GPR, cg);96679668if (japaneseMethod)9669TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(TR_PPCcompressStringNoCheckJ, node, conditions, cg);9670else9671TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(TR_PPCcompressStringNoCheck, node, conditions, cg);96729673TR::Register* regs[4] =9674{9675lengthReg, startReg, srcObjReg, dstObjReg9676};9677conditions->stopUsingDepRegs(cg, 4, regs);9678for (uint16_t i = 0; i < node->getNumChildren(); i++)9679cg->decReferenceCount(node->getChild(i));9680if (stopUsingCopyReg1)9681cg->stopUsingRegister(srcObjReg);9682if (stopUsingCopyReg2)9683cg->stopUsingRegister(dstObjReg);9684if (stopUsingCopyReg3)9685cg->stopUsingRegister(startReg);9686if (stopUsingCopyReg4)9687cg->stopUsingRegister(lengthReg);96889689cg->machine()->setLinkRegisterKilled(true);9690cg->setHasCall();9691return NULL;9692}96939694static TR::Register *andORStringEvaluator(TR::Node *node, TR::CodeGenerator *cg)9695{9696TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());9697TR::Node *srcObjNode, *startNode, *lengthNode;9698TR::Register *srcObjReg = NULL, *lengthReg = NULL, *startReg = NULL;96999700srcObjNode = node->getChild(0);9701startNode = node->getChild(1);9702lengthNode = node->getChild(2);97039704bool stopUsingCopyReg1, stopUsingCopyReg2, stopUsingCopyReg3;97059706stopUsingCopyReg1 = TR::TreeEvaluator::stopUsingCopyReg(srcObjNode, srcObjReg, cg);9707stopUsingCopyReg2 = TR::TreeEvaluator::stopUsingCopyReg(startNode, startReg, cg);9708stopUsingCopyReg3 = TR::TreeEvaluator::stopUsingCopyReg(lengthNode, lengthReg, cg);97099710uintptr_t hdrSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();9711generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, srcObjReg, srcObjReg, hdrSize);97129713TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(8, 8, cg->trMemory());9714TR::Register *cndRegister = cg->allocateRegister(TR_CCR);9715TR::Register *resultReg = cg->allocateRegister(TR_GPR);9716TR::addDependency(conditions, cndRegister, TR::RealRegister::cr0, TR_CCR, cg);9717TR::addDependency(conditions, lengthReg, TR::RealRegister::gr8, TR_GPR, cg);9718TR::addDependency(conditions, startReg, TR::RealRegister::gr7, TR_GPR, cg);9719TR::addDependency(conditions, srcObjReg, TR::RealRegister::gr9, TR_GPR, cg);97209721TR::addDependency(conditions, NULL, TR::RealRegister::gr0, TR_GPR, cg);9722TR::addDependency(conditions, NULL, TR::RealRegister::gr4, TR_GPR, cg);9723TR::addDependency(conditions, NULL, TR::RealRegister::gr5, TR_GPR, cg);9724TR::addDependency(conditions, resultReg, TR::RealRegister::gr3, TR_GPR, cg);97259726TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(TR_PPCandORString, node, conditions, cg);97279728TR::Register* regs[4] =9729{9730lengthReg, startReg, srcObjReg, resultReg9731};9732conditions->stopUsingDepRegs(cg, 4, regs);97339734for (uint16_t i = 0; i < node->getNumChildren(); i++)9735cg->decReferenceCount(node->getChild(i));9736if (stopUsingCopyReg1)9737cg->stopUsingRegister(srcObjReg);9738if (stopUsingCopyReg2)9739cg->stopUsingRegister(startReg);9740if (stopUsingCopyReg3)9741cg->stopUsingRegister(lengthReg);97429743node->setRegister(resultReg);97449745cg->machine()->setLinkRegisterKilled(true);9746cg->setHasCall();9747return (resultReg);9748}97499750static TR::Register *inlineConcurrentLinkedQueueTMOffer(TR::Node *node, TR::CodeGenerator *cg)9751{9752TR::Compilation *comp = cg->comp();9753TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());9754int32_t addressFieldSize = TR::Compiler->om.sizeofReferenceField();9755TR::InstOpCode::Mnemonic loadOpCode = (addressFieldSize == 8) ? TR::InstOpCode::ld : TR::InstOpCode::lwz;9756TR::InstOpCode::Mnemonic storeOpCode = (addressFieldSize == 8) ? TR::InstOpCode::std : TR::InstOpCode::stw;9757bool usesCompressedrefs = comp->useCompressedPointers();97589759// wrt bar9760auto gcMode = TR::Compiler->om.writeBarrierType();9761bool doWrtBar = (gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always9762|| TR::Options::getCmdLineOptions()->realTimeGC());9763bool doCrdMrk = ((gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental) && (!node->getOpCode().isWrtBar() || !node->isNonHeapObjectWrtBar()));97649765TR_OpaqueClassBlock * classBlock = NULL;9766classBlock = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49, comp->getCurrentMethod(), true);9767int32_t offsetNext = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "next", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);9768classBlock = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue;", 44, comp->getCurrentMethod(), true);9769int32_t offsetTail = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "tail", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);97709771TR::Register * cndReg = cg->allocateRegister(TR_CCR);9772TR::Register * resultReg = cg->allocateRegister();9773TR::Register * objReg = cg->evaluate(node->getFirstChild());9774TR::Register * nReg = cg->evaluate(node->getSecondChild());9775TR::Register * pReg = cg->allocateRegister();9776TR::Register * qReg = cg->allocateRegister();9777TR::Register * retryCountReg = cg->allocateRegister();9778TR::Register * temp3Reg = NULL;9779TR::Register * temp4Reg = NULL;97809781TR::LabelSymbol * loopLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);9782TR::LabelSymbol * insertLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);9783TR::LabelSymbol * failureLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);9784TR::LabelSymbol * returnLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);9785TR::LabelSymbol * wrtbar1Donelabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);97869787int numDeps = doWrtBar? 11 : 9; //two extra deps for space boundaries (used in wrtbar)97889789TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(numDeps, numDeps, cg->trMemory());97909791TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);9792TR::addDependency(conditions, resultReg, TR::RealRegister::NoReg, TR_GPR, cg);9793TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);9794TR::addDependency(conditions, pReg, TR::RealRegister::gr3, TR_GPR, cg); // dstReg for wrtbar9795TR::addDependency(conditions, qReg, TR::RealRegister::gr11, TR_GPR, cg); // temp1Reg for wrtbar9796TR::addDependency(conditions, retryCountReg, TR::RealRegister::NoReg, TR_GPR, cg); // temp2Reg for wrtbar9797TR::addDependency(conditions, nReg, TR::RealRegister::gr4, TR_GPR, cg); // srcReg for wrtbar97989799static char * disableTMOffer = feGetEnv("TR_DisableTMOffer");9800static char * debugTM = feGetEnv("TR_DebugTM");98019802/*9803* TM is not compatible with read barriers. If read barriers are required, TM is disabled.9804*/9805if (disableTMOffer || TR::Compiler->om.readBarrierType() != gc_modron_readbar_none)9806{9807generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 3); // TM offer disabled9808generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);9809}98109811if (debugTM)9812{9813printf("\nTM: use TM CLQ.Offer in %s (%s)", comp->signature(), comp->getHotnessName(comp->getMethodHotness()));9814fflush (stdout);9815}98169817static const char *s = feGetEnv("TR_TMOfferRetry");9818static uint16_t TMOfferRetry = s ? atoi(s) : 7;98199820//#define CLQ_OFFER_RETRY 79821generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, retryCountReg, TMOfferRetry);98229823generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);98249825generateInstruction(cg, TR::InstOpCode::tbegin_r, node);98269827generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, failureLabel, cndReg);98289829// ALG: p := this.tail9830generateTrg1MemInstruction(cg, loadOpCode, node, pReg, TR::MemoryReference::createWithDisplacement(cg, objReg, offsetTail, addressFieldSize));9831if (usesCompressedrefs)9832{9833genDecompressPointerWithTempReg(cg, node, pReg, resultReg, NULL, false); // p is not null9834}98359836// ALG: q := p.next9837generateTrg1MemInstruction(cg, loadOpCode, node, qReg, TR::MemoryReference::createWithDisplacement(cg, pReg, offsetNext, addressFieldSize));98389839// ALG: if q == null goto insertLabel9840generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, qReg, 0);9841generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, insertLabel, cndReg);98429843if (usesCompressedrefs)9844{9845genDecompressPointerWithTempReg(cg, node, qReg, resultReg, NULL, false); // q has been checked not null9846}98479848// ALG: p := q9849generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, pReg, qReg);98509851// ALG: q := p.next9852generateTrg1MemInstruction(cg, loadOpCode, node, qReg, TR::MemoryReference::createWithDisplacement(cg, pReg, offsetNext, addressFieldSize));98539854// ALG: if q == null goto insertLabel9855generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, qReg, 0);9856generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, PPCOpProp_BranchLikely, node, insertLabel, cndReg);98579858// ALG: tend.9859generateInstruction(cg, TR::InstOpCode::tend_r, node);98609861// ALG: res := 19862// cannot find tail9863generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1);98649865// ALG: goto returnLabel9866generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);98679868// ALG: *** insert:9869generateLabelInstruction(cg, TR::InstOpCode::label, node, insertLabel);98709871// need uncompressed nReg for the wrtbar9872TR::Register *compressedReg = nReg;9873if (usesCompressedrefs)9874{9875compressedReg = genCompressPointerNonNull2RegsWithTempReg(cg, node, nReg, qReg, resultReg); //In Java code checkNotNull() already ensures n != null9876}9877// ALG: p.next := n9878generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, pReg, offsetNext, addressFieldSize), compressedReg);98799880// ALG: this.tail = n9881generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, objReg, offsetTail, addressFieldSize), compressedReg);98829883// ALG: tend9884generateInstruction(cg, TR::InstOpCode::tend_r, node);98859886// ALG: res := 09887// TM success9888generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0);98899890if (doWrtBar)9891{9892if (doCrdMrk)9893{9894temp3Reg = cg->allocateRegister();9895temp4Reg = cg->allocateRegister();9896TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);9897TR::addDependency(conditions, temp4Reg, TR::RealRegister::NoReg, TR_GPR, cg);9898conditions->getPostConditions()->getRegisterDependency(5)->setExcludeGPR0(); //5=temp2Reg9899}99009901VMnonNullSrcWrtBarCardCheckEvaluator(node, nReg, pReg, cndReg, qReg, retryCountReg, temp3Reg, temp4Reg, wrtbar1Donelabel, conditions, false, cg, false);9902// ALG: *** wrtbar1Donelabel9903generateDepLabelInstruction(cg, TR::InstOpCode::label, node, wrtbar1Donelabel, conditions);99049905generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, pReg, objReg);99069907VMnonNullSrcWrtBarCardCheckEvaluator(node, nReg, pReg, cndReg, qReg, retryCountReg, temp3Reg, temp4Reg, returnLabel, conditions, false, cg, false);99089909}9910else if (doCrdMrk)9911{9912temp3Reg = cg->allocateRegister();9913TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);9914conditions->getPostConditions()->getRegisterDependency(3)->setExcludeGPR0(); //3=dstReg9915conditions->getPostConditions()->getRegisterDependency(4)->setExcludeGPR0(); //4=temp1Reg99169917VMCardCheckEvaluator(node, pReg, cndReg, qReg, retryCountReg, temp3Reg, conditions, cg);99189919generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, pReg, objReg);99209921VMCardCheckEvaluator(node, pReg, cndReg, qReg, retryCountReg, temp3Reg, conditions, cg);9922}99239924// ALG: goto returnLabel9925generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);99269927// ALG: *** failureLabel9928generateLabelInstruction(cg, TR::InstOpCode::label, node, failureLabel);9929//generateDepLabelInstruction(cg, TR::InstOpCode::label, node, failureLabel, conditions);99309931// retryCount-=19932generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addic_r, node, retryCountReg, retryCountReg, -1);99339934// ALG: goto loopLabel9935generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, loopLabel, cndReg);99369937// ALG: res := 29938// exceeds retry count9939generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 2);99409941// ALG: *** return9942generateDepLabelInstruction(cg, TR::InstOpCode::label, node, returnLabel, conditions);99439944// wrtbar or after TM success earlier99459946cg->decReferenceCount(node->getFirstChild());9947cg->decReferenceCount(node->getSecondChild());9948cg->stopUsingRegister(pReg);9949cg->stopUsingRegister(qReg);9950cg->stopUsingRegister(retryCountReg);9951cg->stopUsingRegister(cndReg);9952if (temp3Reg != NULL)9953cg->stopUsingRegister(temp3Reg);9954if (temp4Reg != NULL)9955cg->stopUsingRegister(temp4Reg);99569957node->setRegister(resultReg);9958resultReg->setContainsCollectedReference();9959return resultReg;9960}99619962static TR::Register *inlineConcurrentLinkedQueueTMPoll(TR::Node *node, TR::CodeGenerator *cg)9963{9964TR::Compilation *comp = cg->comp();9965TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());9966int32_t addressFieldSize = TR::Compiler->om.sizeofReferenceField();9967TR::InstOpCode::Mnemonic loadOpCode = (addressFieldSize == 8) ? TR::InstOpCode::ld : TR::InstOpCode::lwz;9968TR::InstOpCode::Mnemonic storeOpCode = (addressFieldSize == 8) ? TR::InstOpCode::std : TR::InstOpCode::stw;9969bool usesCompressedrefs = comp->useCompressedPointers();99709971TR_OpaqueClassBlock *classBlock = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue;", 44, comp->getCurrentMethod(), true);9972int32_t offsetHead = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "head", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);9973classBlock = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49, comp->getCurrentMethod(), true);9974int32_t offsetNext = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "next", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);9975int32_t offsetItem = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "item", 4, "Ljava/lang/Object;", 18);99769977TR::Register * objReg = cg->evaluate(node->getFirstChild());9978TR::Register * cndReg = cg->allocateRegister(TR_CCR);9979TR::Register * resultReg = cg->allocateRegister();9980TR::Register * nullReg = cg->allocateRegister();9981TR::Register * pReg = cg->allocateRegister();9982TR::Register * qReg = cg->allocateRegister();9983TR::Register * temp3Reg = cg->allocateRegister();9984TR::Register * temp4Reg = NULL;99859986TR::LabelSymbol * tendLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);9987TR::LabelSymbol * returnLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);9988TR::LabelSymbol * failureLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);99899990TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(8, 8, cg->trMemory());99919992TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);9993TR::addDependency(conditions, resultReg, TR::RealRegister::NoReg, TR_GPR, cg);9994TR::addDependency(conditions, objReg, TR::RealRegister::gr3, TR_GPR, cg); // dstReg for wrtbar9995TR::addDependency(conditions, nullReg, TR::RealRegister::gr11, TR_GPR, cg); // temp1Reg for wrtbar9996TR::addDependency(conditions, pReg, TR::RealRegister::NoReg, TR_GPR, cg); // temp2Reg for wrtbar9997TR::addDependency(conditions, qReg, TR::RealRegister::gr4, TR_GPR, cg); // srcReg for wrtbar9998TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);999910000static char * disableTMPoll = feGetEnv("TR_DisableTMPoll");10001static char * debugTM = feGetEnv("TR_DebugTM");1000210003/*10004* TM is not compatible with read barriers. If read barriers are required, TM is disabled.10005*/10006if (disableTMPoll || TR::Compiler->om.readBarrierType() != gc_modron_readbar_none)10007{10008generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0); // BEFORE WAS 010009generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);10010}1001110012if (debugTM)10013{10014printf("\nTM: use TM CLQ.Poll in %s (%s)", comp->signature(), comp->getHotnessName(comp->getMethodHotness()));10015fflush (stdout);10016}1001710018generateInstruction(cg, TR::InstOpCode::tbegin_r, node);10019generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, failureLabel, cndReg);1002010021// ALG: p := this.head10022generateTrg1MemInstruction(cg, loadOpCode, node, temp3Reg, TR::MemoryReference::createWithDisplacement(cg, objReg, offsetHead, addressFieldSize));10023TR::Register *decompressedP = temp3Reg;10024if (usesCompressedrefs)10025{10026decompressedP = genDecompressPointerNonNull2RegsWithTempReg(cg, node, temp3Reg, pReg, qReg);10027}1002810029// ALG: res := p.item10030generateTrg1MemInstruction(cg, loadOpCode, node, resultReg, TR::MemoryReference::createWithDisplacement(cg, decompressedP, offsetItem, addressFieldSize));10031if (usesCompressedrefs)10032{10033genDecompressPointerWithTempReg(cg, node, resultReg, qReg, cndReg); // NOTE: res could be null10034}1003510036// ALG: q := p.next10037generateTrg1MemInstruction(cg, loadOpCode, node, qReg, TR::MemoryReference::createWithDisplacement(cg, decompressedP, offsetNext, addressFieldSize));1003810039// ALG: p.item := null10040generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, nullReg, 0);1004110042generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, decompressedP, offsetItem, addressFieldSize), nullReg);1004310044// ALG: if q == null goto tendLabel10045generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, qReg, 0);1004610047generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, tendLabel, cndReg);1004810049// ALG: this.head = q10050// qReg is still compressed, use it to store10051generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, objReg, offsetHead, addressFieldSize), qReg);1005210053if (usesCompressedrefs)10054{10055genDecompressPointerWithTempReg(cg, node, qReg, nullReg, NULL, false); // qReg is not null10056}1005710058// ALG: p.next := p10059generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, decompressedP, offsetNext, addressFieldSize), temp3Reg);1006010061// ALG: tend10062generateInstruction(cg, TR::InstOpCode::tend_r, node);1006310064// WrtBar for this.head = q10065auto gcMode = TR::Compiler->om.writeBarrierType();10066bool doWrtBar = (gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always10067|| comp->getOptions()->realTimeGC());10068bool doCrdMrk = ((gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental) && (!node->getOpCode().isWrtBar() || !node->isNonHeapObjectWrtBar()));10069if (doWrtBar)10070{10071if (doCrdMrk)10072{10073temp4Reg = cg->allocateRegister();10074TR::addDependency(conditions, temp4Reg, TR::RealRegister::NoReg, TR_GPR, cg);10075conditions->getPostConditions()->getRegisterDependency(4)->setExcludeGPR0(); //4=temp2Reg10076}1007710078VMnonNullSrcWrtBarCardCheckEvaluator(node, qReg, objReg, cndReg, nullReg, pReg, temp3Reg, temp4Reg, returnLabel, conditions, false, cg, false);10079}10080else if (doCrdMrk)10081{10082conditions->getPostConditions()->getRegisterDependency(2)->setExcludeGPR0(); //2=dstReg10083conditions->getPostConditions()->getRegisterDependency(3)->setExcludeGPR0(); //3=temp1Reg1008410085VMCardCheckEvaluator(node, objReg, cndReg, nullReg, pReg, temp3Reg, conditions, cg);10086}1008710088// ALG: goto returnLabel10089generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);1009010091// ALG:**** tendLabel:10092generateLabelInstruction(cg, TR::InstOpCode::label, node, tendLabel);1009310094// ALG: tend10095generateInstruction(cg, TR::InstOpCode::tend_r, node);1009610097// ALG: goto returnLabel10098generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);1009910100// ALG: *** failureLabel10101generateLabelInstruction(cg, TR::InstOpCode::label, node, failureLabel);10102// resultReg := 010103generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0);1010410105// ALG: *** returnLabel10106generateDepLabelInstruction(cg, TR::InstOpCode::label, node, returnLabel, conditions);1010710108// wrtbar if result is non-null1010910110cg->decReferenceCount(node->getFirstChild());10111cg->stopUsingRegister(nullReg);10112cg->stopUsingRegister(pReg);10113cg->stopUsingRegister(qReg);10114cg->stopUsingRegister(cndReg);10115if (temp3Reg != NULL)10116cg->stopUsingRegister(temp3Reg);10117if (temp4Reg != NULL)10118cg->stopUsingRegister(temp4Reg);1011910120node->setRegister(resultReg);10121resultReg->setContainsCollectedReference();10122return resultReg;10123}1012410125#if defined(AIXPPC)10126static TR::Register *dangerousGetCPU(10127TR::Node *node,10128TR::CodeGenerator *cg)10129{10130// This is a bad idea that works most of the time.10131// We don't bother with ANY of the usual native method protocol(!)10132// But we do adjust r1 to be way out of the way and then call10133// "mycpu" which is buried deep in the kernel1013410135TR::Register *retReg = cg->allocateRegister();10136TR::Register *gr1 = cg->allocateRegister();10137TR::Register *gr2 = cg->allocateRegister();10138TR::Register *tmpReg = cg->allocateRegister();10139TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());10140TR::Compilation *comp = cg->comp();10141TR::addDependency(dependencies, retReg, TR::RealRegister::gr3, TR_GPR, cg);10142TR::addDependency(dependencies, gr1, TR::RealRegister::gr1, TR_GPR, cg);10143TR::addDependency(dependencies, gr2, TR::RealRegister::gr2, TR_GPR, cg);10144generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, gr1, gr1, -256);10145generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,10146TR::MemoryReference::createWithDisplacement(cg, gr1, 0x14, TR::Compiler->om.sizeofReferenceAddress()),10147gr2);10148intptr_t xx[3];10149xx[0] = ((intptr_t *)(void *)&mycpu)[0];10150xx[1] = ((intptr_t *)(void *)&mycpu)[1];10151xx[2] = ((intptr_t *)(void *)&mycpu)[2];10152loadAddressConstant(cg, comp->compileRelocatableCode(), node, xx[0], tmpReg);10153loadAddressConstant(cg, comp->compileRelocatableCode(), node, xx[1], gr2);10154generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, tmpReg);10155generateInstruction(cg, TR::InstOpCode::bctrl, node);1015610157generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, gr2,10158TR::MemoryReference::createWithDisplacement(cg, gr1, 0x14, TR::Compiler->om.sizeofReferenceAddress()));10159generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, gr1, gr1, 256);10160generateDepLabelInstruction(cg, TR::InstOpCode::label, node, TR::LabelSymbol::create(cg->trHeapMemory(),cg), dependencies);10161cg->stopUsingRegister(gr1);10162cg->stopUsingRegister(gr2);10163cg->stopUsingRegister(tmpReg);10164node->setRegister(retReg);10165cg->machine()->setLinkRegisterKilled(true);10166return retReg;10167}10168#else10169static TR::Register *dangerousGetCPU(TR::Node *node, TR::CodeGenerator *cg)10170{10171return NULL;10172}10173#endif1017410175static TR::Register *inlineFixedTrg1Src1(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)10176{10177TR_ASSERT(node->getNumChildren() == 1, "Wrong number of children in inlineFixedTrg1Src1");1017810179TR::Node *firstChild = node->getFirstChild();10180TR::Register *srcRegister = cg->evaluate(firstChild);10181TR::Register *targetRegister = cg->allocateRegister();1018210183generateTrg1Src1Instruction(cg, op, node, targetRegister, srcRegister);1018410185node->setRegister(targetRegister);10186cg->decReferenceCount(firstChild);1018710188return targetRegister;10189}1019010191static TR::Register *inlineLongNumberOfTrailingZeros(TR::Node *node, TR::CodeGenerator *cg)10192{10193TR_ASSERT(node->getNumChildren() == 1, "Wrong number of children in inlineLongNumberOfTrailingZeros");1019410195TR::Node *firstChild = node->getFirstChild();10196TR::Register *srcRegister = cg->evaluate(firstChild);10197TR::Register *targetRegister = cg->allocateRegister();10198TR::Register *tempRegister = cg->allocateRegister();10199TR::Register *maskRegister = cg->allocateRegister();1020010201generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addic, node, tempRegister, srcRegister->getLowOrder(), -1);10202generateTrg1Src1Instruction(cg, TR::InstOpCode::addme, node, targetRegister, srcRegister->getHighOrder());10203generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, tempRegister, tempRegister, srcRegister->getLowOrder());10204generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, targetRegister, targetRegister, srcRegister->getHighOrder());10205generateTrg1Src1Instruction(cg, TR::InstOpCode::cntlzw, node, targetRegister, targetRegister);10206generateTrg1Src1Instruction(cg, TR::InstOpCode::cntlzw, node, tempRegister, tempRegister);10207generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, maskRegister, targetRegister, 27, 0x1);10208generateTrg1Src1Instruction(cg, TR::InstOpCode::neg, node, maskRegister, maskRegister);10209generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, tempRegister, tempRegister, maskRegister);10210generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, targetRegister, targetRegister, tempRegister);10211generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::subfic, node, targetRegister, targetRegister, 64);1021210213cg->stopUsingRegister(tempRegister);10214cg->stopUsingRegister(maskRegister);1021510216node->setRegister(targetRegister);10217cg->decReferenceCount(firstChild);1021810219return targetRegister;10220}1022110222static TR::Register *inlineIsAssignableFrom(TR::Node *node, TR::CodeGenerator *cg)10223{10224TR::Compilation *comp = cg->comp();10225TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());10226TR::Node *receiverNode = node->getFirstChild();10227TR::Node *parmNode = node->getSecondChild();1022810229// If the receiver class is known at compile-time and the receiver and parm classes aren't the same,10230// we can check if the receiver is a super class of the parm class10231// Look for:10232// icall java/lang/Class.isAssignableFrom(Ljava/lang/Class;)Z10233// aloadi <javaLangClassFromClass>10234// loadaddr receiverj9class10235int32_t receiverClassDepth = -1;10236if (receiverNode->getOpCodeValue() == TR::aloadi &&10237receiverNode->getSymbolReference() == comp->getSymRefTab()->findJavaLangClassFromClassSymbolRef() &&10238receiverNode->getFirstChild()->getOpCodeValue() == TR::loadaddr)10239{10240TR::Node *receiverJ9ClassNode = receiverNode->getFirstChild();10241TR::SymbolReference *receiverJ9ClassSymRef = receiverJ9ClassNode->getSymbolReference();10242if (receiverJ9ClassSymRef && !receiverJ9ClassSymRef->isUnresolved())10243{10244TR::StaticSymbol *receiverJ9ClassSym = receiverJ9ClassSymRef->getSymbol()->getStaticSymbol();10245if (receiverJ9ClassSym)10246{10247TR_OpaqueClassBlock *receiverJ9ClassPtr = (TR_OpaqueClassBlock *)receiverJ9ClassSym->getStaticAddress();10248if (receiverJ9ClassPtr)10249{10250receiverClassDepth = (int32_t)TR::Compiler->cls.classDepthOf(receiverJ9ClassPtr);10251if (receiverClassDepth >= 0)10252{10253static bool disable = feGetEnv("TR_disableInlineIsAssignableFromSuperTest") != NULL;10254if (disable)10255receiverClassDepth = -1;10256}10257}10258}10259}10260}1026110262TR_PPCScratchRegisterManager *srm = cg->generateScratchRegisterManager();10263TR::Register *receiverReg = cg->evaluate(node->getFirstChild());10264TR::Register *parmReg = cg->evaluate(node->getSecondChild());10265TR::Register *resultReg = cg->allocateRegister();10266TR::LabelSymbol *outlinedCallLabel = generateLabelSymbol(cg);10267TR::LabelSymbol *returnTrueLabel = generateLabelSymbol(cg);10268TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);1026910270doneLabel->setEndInternalControlFlow();1027110272// We don't want this guy to be live across the call to isAssignableFrom in the outlined section10273// because the CR reg will have to be spilled/restored.10274// Instead, we allocate it outside the srm and don't bother putting it in the dependencies on doneLabel.10275// For correctness we could free all CRs in the post conditions of doneLabel, but currently CRs are10276// never live outside of the evaluator they were created in so it's not a concern.10277TR::Register *condReg = cg->allocateRegister(TR_CCR);1027810279// This is fine since we don't use any scratch regs after writing to the result reg10280srm->donateScratchRegister(resultReg);1028110282// If either the receiver or the parm is null, bail out10283TR::Register *nullTestReg = srm->findOrCreateScratchRegister();10284if (!receiverNode->isNonNull())10285{10286genNullTest(node, receiverReg, condReg, nullTestReg, NULL, cg);10287generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, outlinedCallLabel, condReg);10288}10289if (!parmNode->isNonNull())10290{10291genNullTest(node, parmReg, condReg, nullTestReg, NULL, cg);10292generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, outlinedCallLabel, condReg);10293}10294srm->reclaimScratchRegister(nullTestReg);1029510296// Compare receiver and parm10297generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, receiverReg, parmReg);10298generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, returnTrueLabel, condReg);1029910300// Compare receiver and parm classes10301TR::Register *receiverJ9ClassReg = srm->findOrCreateScratchRegister();10302TR::Register *parmJ9ClassReg = srm->findOrCreateScratchRegister();10303generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, receiverJ9ClassReg,10304TR::MemoryReference::createWithDisplacement(cg, receiverReg, fej9->getOffsetOfClassFromJavaLangClassField(), TR::Compiler->om.sizeofReferenceAddress()));10305generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, parmJ9ClassReg,10306TR::MemoryReference::createWithDisplacement(cg, parmReg, fej9->getOffsetOfClassFromJavaLangClassField(), TR::Compiler->om.sizeofReferenceAddress()));10307generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, receiverJ9ClassReg, parmJ9ClassReg);1030810309TR::Register *scratch1Reg = NULL;10310if (receiverClassDepth >= 0)10311{10312generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, returnTrueLabel, condReg);1031310314scratch1Reg = srm->findOrCreateScratchRegister();10315TR::Register *scratch2Reg = srm->findOrCreateScratchRegister();1031610317genTestIsSuper(node, parmJ9ClassReg, receiverJ9ClassReg, condReg, scratch1Reg, scratch2Reg, receiverClassDepth, outlinedCallLabel, NULL, cg);10318generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, outlinedCallLabel, condReg);1031910320srm->reclaimScratchRegister(scratch1Reg);10321srm->reclaimScratchRegister(scratch2Reg);10322}10323else10324{10325generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, outlinedCallLabel, condReg);10326}1032710328srm->reclaimScratchRegister(receiverJ9ClassReg);10329srm->reclaimScratchRegister(parmJ9ClassReg);10330generateLabelInstruction(cg, TR::InstOpCode::label, node, returnTrueLabel);10331generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1);1033210333TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 2 + srm->numAvailableRegisters(), cg->trMemory());10334deps->addPostCondition(receiverReg, TR::RealRegister::NoReg, UsesDependentRegister | ExcludeGPR0InAssigner);10335deps->addPostCondition(parmReg, TR::RealRegister::NoReg, UsesDependentRegister | ExcludeGPR0InAssigner);10336srm->addScratchRegistersToDependencyList(deps);10337// Make sure these two (added to the deps by the srm) have !gr0, since we use them as base regs10338deps->setPostDependencyExcludeGPR0(receiverJ9ClassReg);10339if (scratch1Reg)10340deps->setPostDependencyExcludeGPR0(scratch1Reg);10341generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);1034210343TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::icall, resultReg, outlinedCallLabel, doneLabel, cg);10344cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);1034510346node->setRegister(resultReg);10347cg->decReferenceCount(node->getFirstChild());10348cg->decReferenceCount(node->getSecondChild());10349srm->stopUsingRegisters();10350cg->stopUsingRegister(condReg);1035110352return resultReg;10353}1035410355static TR::Register *inlineStringHashcode(TR::Node *node, TR::CodeGenerator *cg)10356{10357TR::Compilation *comp = cg->comp();10358TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());10359bool isLE = comp->target().cpu.isLittleEndian();1036010361TR::Node *valueNode = node->getFirstChild();10362TR::Node *offsetNode = node->getSecondChild();10363TR::Node *countNode = node->getThirdChild();1036410365TR::Register *valueReg = cg->gprClobberEvaluate(valueNode);10366TR::Register *endReg = cg->gprClobberEvaluate(offsetNode);10367TR::Register *vendReg = cg->gprClobberEvaluate(countNode);10368TR::Register *hashReg = cg->allocateRegister();10369TR::Register *tempReg = cg->allocateRegister();10370TR::Register *constant0Reg = cg->allocateRegister();10371TR::Register *multiplierAddrReg = cg->allocateRegister();10372TR::Register *condReg = cg->allocateRegister(TR_CCR);1037310374TR::Register *multiplierReg = cg->allocateRegister(TR_VRF);10375TR::Register *high4Reg = cg->allocateRegister(TR_VRF);10376TR::Register *low4Reg = cg->allocateRegister(TR_VRF);10377TR::Register *vtmp1Reg = cg->allocateRegister(TR_VRF);10378TR::Register *vtmp2Reg = cg->allocateRegister(TR_VRF);10379TR::Register *vconstant0Reg = cg->allocateRegister(TR_VRF);10380TR::Register *vconstantNegReg = cg->allocateRegister(TR_VRF);10381TR::Register *vunpackMaskReg = cg->allocateRegister(TR_VRF);1038210383TR::LabelSymbol *serialLabel = generateLabelSymbol(cg);10384TR::LabelSymbol *VSXLabel = generateLabelSymbol(cg);10385TR::LabelSymbol *POSTVSXLabel = generateLabelSymbol(cg);10386TR::LabelSymbol *endLabel = generateLabelSymbol(cg);1038710388// Skip header of the array10389// v = v + offset<<110390// end = v + count<<110391// hash = 010392// temp = 010393intptr_t hdrSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();10394generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valueReg, valueReg, hdrSize);10395generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, endReg, endReg, endReg);10396generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, valueReg, valueReg, endReg);10397generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, vendReg, vendReg, vendReg);10398generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, endReg, valueReg, vendReg);10399generateTrg1Src2Instruction(cg, TR::InstOpCode::XOR, node, hashReg, hashReg, hashReg);10400generateTrg1Src2Instruction(cg, TR::InstOpCode::XOR, node, tempReg, tempReg, tempReg);10401loadConstant(cg, node, 0x0, constant0Reg);1040210403// if count<<1 < 16 goto serial10404generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, vendReg, 0x10);10405generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, serialLabel, condReg);1040610407// load multiplier, clear high4 low410408static uint32_t multiplierVectors_be[12] = {0x94446F01, 0x94446F01, 0x94446F01, 0x94446F01, 0x67E12CDF, 887503681, 28629151, 923521, 29791, 961, 31, 1};10409static uint32_t multiplierVectors_le[12] = {0x94446F01, 0x94446F01, 0x94446F01, 0x94446F01, 1, 31, 961, 29791, 923521, 28629151, 887503681, 0x67E12CDF};1041010411if (isLE){10412loadAddressConstant(cg, false, node, (intptr_t)multiplierVectors_le, multiplierAddrReg);10413}else{10414loadAddressConstant(cg, false, node, (intptr_t)multiplierVectors_be, multiplierAddrReg);10415}10416generateTrg1MemInstruction(cg, TR::InstOpCode::lxvw4x, node, multiplierReg, TR::MemoryReference::createWithIndexReg(cg, multiplierAddrReg, constant0Reg, 16));10417generateTrg1Src2Instruction(cg, TR::InstOpCode::vxor, node, high4Reg, high4Reg, high4Reg);10418generateTrg1Src2Instruction(cg, TR::InstOpCode::vxor, node, low4Reg, low4Reg, low4Reg);10419generateTrg1Src2Instruction(cg, TR::InstOpCode::vxor, node, vconstant0Reg, vconstant0Reg, vconstant0Reg);10420generateTrg1Src2Instruction(cg, TR::InstOpCode::vnor, node, vconstantNegReg, vconstant0Reg, vconstant0Reg);10421generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::vsldoi, node, vunpackMaskReg, vconstant0Reg, vconstantNegReg, 2);10422generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::vspltw, node, vunpackMaskReg, vunpackMaskReg, 3);1042310424// vend = end & (~0xf)10425// if v is 16byte aligned goto VSX_LOOP10426generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, 0xFFFFFFFFFFFFFFF0);10427generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, vendReg, endReg, tempReg);10428loadConstant(cg, node, 0xF, tempReg);10429generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, tempReg, valueReg, tempReg);10430generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, tempReg, 0x0);10431generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, VSXLabel, condReg);1043210433// The reason we don't do VSX loop directly is we want to avoid loading unaligned data and deal it with vperm.10434// Instead, we load the first unaligned part, let VSX handle the rest aligned part.10435// load unaligned v, mask out unwanted part10436// for example, if value = 0x12345, we mask out 0x12340~0x12344, keep 0x12345~0x1234F10437generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, vtmp1Reg, TR::MemoryReference::createWithIndexReg(cg, valueReg, constant0Reg, 16));10438loadConstant(cg, node, 0xF, tempReg);10439generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, tempReg, valueReg, tempReg);10440generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, tempReg, tempReg, 3, 0xFFFFFFFFFFFFFFF8);10441generateTrg1Src1Instruction(cg, TR::InstOpCode::mtvsrd, node, vtmp2Reg, tempReg);10442generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::vsldoi, node, vtmp2Reg, vconstant0Reg, vtmp2Reg, 8);10443if (isLE) {10444generateTrg1Src2Instruction(cg, TR::InstOpCode::vslo, node, vtmp2Reg, vconstantNegReg, vtmp2Reg);10445} else {10446generateTrg1Src2Instruction(cg, TR::InstOpCode::vsro, node, vtmp2Reg, vconstantNegReg, vtmp2Reg);10447}10448generateTrg1Src2Instruction(cg, TR::InstOpCode::vand, node, vtmp1Reg, vtmp1Reg, vtmp2Reg);1044910450// unpack masked v to high4 low410451generateTrg1Src1Instruction(cg, TR::InstOpCode::vupkhsh, node, high4Reg, vtmp1Reg);10452generateTrg1Src2Instruction(cg, TR::InstOpCode::vand, node, high4Reg, high4Reg, vunpackMaskReg);10453generateTrg1Src1Instruction(cg, TR::InstOpCode::vupklsh, node, low4Reg, vtmp1Reg);10454generateTrg1Src2Instruction(cg, TR::InstOpCode::vand, node, low4Reg, low4Reg, vunpackMaskReg);1045510456// advance v to next aligned pointer10457// if v >= vend goto POST_VSX10458generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valueReg, valueReg, 0xF);10459generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, 0xFFFFFFFFFFFFFFF0);10460generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, valueReg, valueReg, tempReg);10461generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, condReg, valueReg, vendReg);10462generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, POSTVSXLabel, condReg);1046310464//VSX_LOOP:10465//load v (here v must be aligned)10466//unpack v to temphigh4 templow410467//high4 = high4 * multiplier10468//low4 = low4 * multiplier10469//high4 = high4 + temphigh410470//low4 = low4 + templow410471//v = v + 0x1010472//if v < vend goto VSX_LOOP10473generateLabelInstruction(cg, TR::InstOpCode::label, node, VSXLabel);10474generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, vtmp1Reg, TR::MemoryReference::createWithIndexReg(cg, valueReg, constant0Reg, 16));10475generateTrg1Src1Instruction(cg, TR::InstOpCode::vupkhsh, node, vtmp2Reg, vtmp1Reg);10476generateTrg1Src2Instruction(cg, TR::InstOpCode::vand, node, vtmp2Reg, vtmp2Reg, vunpackMaskReg);10477generateTrg1Src2Instruction(cg, TR::InstOpCode::vmuluwm, node, high4Reg, high4Reg, multiplierReg);10478generateTrg1Src2Instruction(cg, TR::InstOpCode::vadduwm, node, high4Reg, high4Reg, vtmp2Reg);10479generateTrg1Src1Instruction(cg, TR::InstOpCode::vupklsh, node, vtmp2Reg, vtmp1Reg);10480generateTrg1Src2Instruction(cg, TR::InstOpCode::vand, node, vtmp2Reg, vtmp2Reg, vunpackMaskReg);10481generateTrg1Src2Instruction(cg, TR::InstOpCode::vmuluwm, node, low4Reg, low4Reg, multiplierReg);10482generateTrg1Src2Instruction(cg, TR::InstOpCode::vadduwm, node, low4Reg, low4Reg, vtmp2Reg);10483generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valueReg, valueReg, 0x10);10484generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, condReg, valueReg, vendReg);10485generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, VSXLabel, condReg);1048610487// POST_VSX:10488// shift and sum low4 and high410489// move result to hashReg10490generateLabelInstruction(cg, TR::InstOpCode::label, node, POSTVSXLabel);1049110492generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, multiplierAddrReg, multiplierAddrReg, 0x10);10493generateTrg1MemInstruction(cg, TR::InstOpCode::lxvw4x, node, multiplierReg, TR::MemoryReference::createWithIndexReg(cg, multiplierAddrReg, constant0Reg, 16));10494generateTrg1Src2Instruction(cg, TR::InstOpCode::vmuluwm, node, high4Reg, high4Reg, multiplierReg);10495generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, multiplierAddrReg, multiplierAddrReg, 0x10);10496generateTrg1MemInstruction(cg, TR::InstOpCode::lxvw4x, node, multiplierReg, TR::MemoryReference::createWithIndexReg(cg, multiplierAddrReg, constant0Reg, 16));10497generateTrg1Src2Instruction(cg, TR::InstOpCode::vmuluwm, node, low4Reg, low4Reg, multiplierReg);1049810499generateTrg1Src2Instruction(cg, TR::InstOpCode::vadduwm, node, high4Reg, high4Reg, low4Reg);10500generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::vsldoi, node, vtmp1Reg, vconstant0Reg, high4Reg, 8);10501generateTrg1Src2Instruction(cg, TR::InstOpCode::vadduwm, node, high4Reg, high4Reg, vtmp1Reg);10502generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::vsldoi, node, vtmp1Reg, vconstant0Reg, high4Reg, 12);10503generateTrg1Src2Instruction(cg, TR::InstOpCode::vadduwm, node, high4Reg, high4Reg, vtmp1Reg);1050410505generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::vsldoi, node, vtmp1Reg, high4Reg, vconstant0Reg, 8);10506generateTrg1Src1Instruction(cg, TR::InstOpCode::mfvsrwz, node, hashReg, vtmp1Reg);1050710508// Head of the serial loop10509generateLabelInstruction(cg, TR::InstOpCode::label, node, serialLabel);1051010511// temp = hash10512// hash = hash << 510513// hash = hash - temp10514// temp = v[i]10515// hash = hash + temp1051610517generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, condReg, valueReg, endReg);10518generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, endLabel, condReg);10519generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, tempReg, hashReg);10520generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, hashReg, hashReg, 5, 0xFFFFFFFFFFFFFFE0);10521generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, hashReg, tempReg, hashReg);10522generateTrg1MemInstruction(cg, TR::InstOpCode::lhzx, node, tempReg, TR::MemoryReference::createWithIndexReg(cg, valueReg, constant0Reg, 2));10523generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, hashReg, hashReg, tempReg);10524generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valueReg, valueReg, 0x2);10525generateLabelInstruction(cg, TR::InstOpCode::b, node, serialLabel);1052610527// End of this method10528TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 16, cg->trMemory());10529dependencies->addPostCondition(valueReg, TR::RealRegister::NoReg);10530dependencies->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0(); // valueReg1053110532dependencies->addPostCondition(endReg, TR::RealRegister::NoReg);10533dependencies->addPostCondition(vendReg, TR::RealRegister::NoReg);10534dependencies->addPostCondition(hashReg, TR::RealRegister::NoReg);10535dependencies->addPostCondition(tempReg, TR::RealRegister::NoReg);10536dependencies->addPostCondition(constant0Reg, TR::RealRegister::NoReg);10537dependencies->addPostCondition(condReg, TR::RealRegister::NoReg);1053810539dependencies->addPostCondition(multiplierAddrReg, TR::RealRegister::NoReg);10540dependencies->getPostConditions()->getRegisterDependency(7)->setExcludeGPR0(); // multiplierAddrReg1054110542dependencies->addPostCondition(multiplierReg, TR::RealRegister::NoReg);10543dependencies->addPostCondition(high4Reg, TR::RealRegister::NoReg);10544dependencies->addPostCondition(low4Reg, TR::RealRegister::NoReg);10545dependencies->addPostCondition(vtmp1Reg, TR::RealRegister::NoReg);10546dependencies->addPostCondition(vtmp2Reg, TR::RealRegister::NoReg);10547dependencies->addPostCondition(vconstant0Reg, TR::RealRegister::NoReg);10548dependencies->addPostCondition(vconstantNegReg, TR::RealRegister::NoReg);10549dependencies->addPostCondition(vunpackMaskReg, TR::RealRegister::NoReg);1055010551generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, dependencies);1055210553node->setRegister(hashReg);10554cg->decReferenceCount(valueNode);10555cg->decReferenceCount(offsetNode);10556cg->decReferenceCount(countNode);1055710558cg->stopUsingRegister(valueReg);10559cg->stopUsingRegister(endReg);10560cg->stopUsingRegister(vendReg);10561cg->stopUsingRegister(tempReg);10562cg->stopUsingRegister(constant0Reg);10563cg->stopUsingRegister(condReg);10564cg->stopUsingRegister(multiplierAddrReg);1056510566cg->stopUsingRegister(multiplierReg);10567cg->stopUsingRegister(high4Reg);10568cg->stopUsingRegister(low4Reg);10569cg->stopUsingRegister(vtmp1Reg);10570cg->stopUsingRegister(vtmp2Reg);10571cg->stopUsingRegister(vconstant0Reg);10572cg->stopUsingRegister(vconstantNegReg);10573cg->stopUsingRegister(vunpackMaskReg);10574return hashReg;10575}1057610577static TR::Register *inlineEncodeUTF16(TR::Node *node, TR::CodeGenerator *cg)10578{10579// tree looks like:10580// icall com.ibm.jit.JITHelpers.encodeUtf16{Big,Little}()10581// input ptr10582// output ptr10583// input length (in elements)10584// Number of elements converted returned1058510586TR::MethodSymbol *symbol = node->getSymbol()->castToMethodSymbol();10587bool bigEndian = symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_transformedEncodeUTF16Big;1058810589// Set up register dependencies10590const int gprClobberCount = 5;10591const int fprClobberCount = 4;10592const int vrClobberCount = 6;10593const int crClobberCount = 2;10594const int totalDeps = crClobberCount + gprClobberCount + fprClobberCount + vrClobberCount + 3;10595TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, totalDeps, cg->trMemory());1059610597TR::Register *inputReg = cg->gprClobberEvaluate(node->getChild(0));10598TR::Register *outputReg = cg->gprClobberEvaluate(node->getChild(1));10599TR::Register *inputLenReg = cg->gprClobberEvaluate(node->getChild(2));10600TR::Register *outputLenReg = cg->allocateRegister();1060110602// Allocate clobbered registers10603TR::Register *gprClobbers[gprClobberCount], *fprClobbers[fprClobberCount], *vrClobbers[vrClobberCount], *crClobbers[crClobberCount];10604for (int i = 0; i < gprClobberCount; ++i) gprClobbers[i] = cg->allocateRegister(TR_GPR);10605for (int i = 0; i < fprClobberCount; ++i) fprClobbers[i] = cg->allocateRegister(TR_FPR);10606for (int i = 0; i < vrClobberCount; ++i) vrClobbers[i] = cg->allocateRegister(TR_VRF);10607for (int i = 0; i < crClobberCount; ++i) crClobbers[i] = cg->allocateRegister(TR_CCR);1060810609// Add the pre and post conditions10610// Input and output registers10611deps->addPreCondition(inputReg, TR::RealRegister::gr3);1061210613deps->addPostCondition(outputLenReg, TR::RealRegister::gr3);10614deps->addPostCondition(outputReg, TR::RealRegister::gr4);10615deps->addPostCondition(inputLenReg, TR::RealRegister::gr5);1061610617//CCR.10618deps->addPostCondition(crClobbers[0], TR::RealRegister::cr0);10619deps->addPostCondition(crClobbers[1], TR::RealRegister::cr6);1062010621//GPRs + Trampoline10622deps->addPostCondition(gprClobbers[0], TR::RealRegister::gr6);10623deps->addPostCondition(gprClobbers[1], TR::RealRegister::gr7);10624deps->addPostCondition(gprClobbers[2], TR::RealRegister::gr8);10625deps->addPostCondition(gprClobbers[3], TR::RealRegister::gr9);10626deps->addPostCondition(gprClobbers[4], TR::RealRegister::gr11);1062710628//VR's10629deps->addPostCondition(vrClobbers[0], TR::RealRegister::vr0);10630deps->addPostCondition(vrClobbers[1], TR::RealRegister::vr1);10631deps->addPostCondition(vrClobbers[2], TR::RealRegister::vr2);10632deps->addPostCondition(vrClobbers[3], TR::RealRegister::vr3);10633deps->addPostCondition(vrClobbers[4], TR::RealRegister::vr4);10634deps->addPostCondition(vrClobbers[5], TR::RealRegister::vr5);1063510636//FP/VSR10637deps->addPostCondition(fprClobbers[0], TR::RealRegister::fp0);10638deps->addPostCondition(fprClobbers[1], TR::RealRegister::fp1);10639deps->addPostCondition(fprClobbers[2], TR::RealRegister::fp2);10640deps->addPostCondition(fprClobbers[3], TR::RealRegister::fp3);1064110642// Generate helper call10643TR_RuntimeHelper helper;10644helper = bigEndian ? TR_PPCencodeUTF16Big : TR_PPCencodeUTF16Little;10645TR::SymbolReference *helperSym = cg->comp()->getSymRefTab()->findOrCreateRuntimeHelper(helper);10646generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), deps, helperSym);1064710648for (uint32_t i = 0; i < node->getNumChildren(); ++i) cg->decReferenceCount(node->getChild(i));1064910650// Spill the clobbered registers10651if (inputReg != node->getChild(0)->getRegister()) cg->stopUsingRegister(inputReg);10652if (outputReg != node->getChild(1)->getRegister()) cg->stopUsingRegister(outputReg);10653if (inputLenReg != node->getChild(2)->getRegister()) cg->stopUsingRegister(inputLenReg);10654for (int i = 0; i < gprClobberCount; ++i) cg->stopUsingRegister(gprClobbers[i]);10655for (int i = 0; i < vrClobberCount; ++i) cg->stopUsingRegister(vrClobbers[i]);10656for (int i = 0; i < fprClobberCount; ++i) cg->stopUsingRegister(fprClobbers[i]);10657for (int i = 0; i < crClobberCount; ++i) cg->stopUsingRegister(crClobbers[i]);1065810659cg->machine()->setLinkRegisterKilled(true);10660cg->setHasCall();10661node->setRegister(outputLenReg);1066210663return outputLenReg;10664}1066510666static TR::Register *inlineIntrinsicIndexOf_P10(TR::Node *node, TR::CodeGenerator *cg, bool isLatin1)10667{10668static bool disableIndexOfStringIntrinsic = feGetEnv("TR_DisableIndexOfStringIntrinsic") != NULL;10669if (disableIndexOfStringIntrinsic)10670return nullptr;10671TR::Compilation *comp = cg->comp();10672auto vectorCompareOp = isLatin1 ? TR::InstOpCode::vcmpequb_r : TR::InstOpCode::vcmpequh_r;10673TR::InstOpCode::Mnemonic scalarLoadOp = isLatin1 ? TR::InstOpCode::lbzx : TR::InstOpCode::lhzx;106741067510676TR::Register *array = cg->evaluate(node->getChild(1));10677TR::Register *ch = cg->evaluate(node->getChild(2));10678TR::Register *offset = cg->evaluate(node->getChild(3));10679TR::Register *length = cg->evaluate(node->getChild(4));1068010681TR::LabelSymbol *startLabel = generateLabelSymbol(cg);10682TR::LabelSymbol *mainLoop = generateLabelSymbol(cg);10683TR::LabelSymbol *residueLabel = generateLabelSymbol(cg);10684TR::LabelSymbol *resultLabel = generateLabelSymbol(cg);10685TR::LabelSymbol *endLabel = generateLabelSymbol(cg);1068610687TR::Register *cr6 = cg->allocateRegister(TR_CCR);1068810689TR::Register *position = cg->allocateRegister();10690TR::Register *endPos = cg->allocateRegister();10691TR::Register *arrAddress = cg->allocateRegister();10692TR::Register *result = cg->allocateRegister();10693TR::Register *temp = cg->allocateRegister();10694TR::Register *vec0 = cg->allocateRegister(TR_VRF);10695TR::Register *vec1 = cg->allocateRegister(TR_VRF);10696TR::Register *vec2 = cg->allocateRegister(TR_VRF);1069710698startLabel->setStartInternalControlFlow();10699endLabel->setEndInternalControlFlow();1070010701generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);1070210703generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, result, -1);10704// check empty10705generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr6, offset, length);10706generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, endLabel, cr6);1070710708generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, position, offset);10709generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, endPos, length);1071010711// sanity check : if str isLatin1, then ch should be isLatin1 too.10712if (isLatin1)10713{10714generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, temp, ch, 24, 0xFF);10715generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cr6, temp, 0);10716generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, endLabel, cr6);10717}107181071910720if (!isLatin1)10721{10722generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, position, position, position);10723generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, endPos, endPos, endPos);10724}1072510726generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, arrAddress, array, TR::Compiler->om.contiguousArrayHeaderSizeInBytes());1072710728// match first byte10729generateTrg1MemInstruction(cg, scalarLoadOp, node, temp, TR::MemoryReference::createWithIndexReg(cg, position, arrAddress, isLatin1 ? 1 : 2));10730generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr6, temp, ch);10731generateTrg1Src3Instruction(cg, TR::InstOpCode::iseleq, node, result, offset, result, cr6);10732generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, endLabel, cr6);1073310734generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, position, position, isLatin1 ? 1 : 2);10735generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr6, position, endPos);10736generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, endLabel, cr6);1073710738generateTrg1Src1Instruction(cg, TR::InstOpCode::mtvsrwz, node, vec1, ch);10739if (isLatin1)10740generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::vspltb, node, vec1, vec1, 7);10741else10742generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::vsplth, node, vec1, vec1, 3);107431074410745generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp, position, endPos);10746generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, endPos, temp, 0, 0xF);10747generateShiftRightLogicalImmediate(cg, node, temp, temp, 4);1074810749generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cr6, temp, 0);10750generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, residueLabel, cr6);1075110752generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, temp);1075310754generateLabelInstruction(cg, TR::InstOpCode::label, node, mainLoop); // mainloop10755if (!isLatin1)10756{10757generateTrg1Src2Instruction(cg, TR::InstOpCode::lxvh8x, node, vec0, arrAddress, position);10758generateTrg1Src2Instruction(cg, TR::InstOpCode::vcmpequh_r, node, vec0, vec0, vec1);10759}10760else10761{10762generateTrg1Src2Instruction(cg, TR::InstOpCode::lxvb16x, node, vec0, arrAddress, position);10763generateTrg1Src2Instruction(cg, TR::InstOpCode::vcmpequb_r, node, vec0, vec0, vec1);10764}10765generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, resultLabel, cr6);10766generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, position, position, 16);10767generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, mainLoop, cr6);1076810769generateLabelInstruction(cg, TR::InstOpCode::label, node, residueLabel);1077010771generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cr6, endPos, 0);10772generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, endLabel, cr6);1077310774generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, arrAddress, arrAddress, position);10775generateShiftLeftImmediateLong(cg, node, endPos, endPos, 56);1077610777generateTrg1Src2Instruction(cg, TR::InstOpCode::lxvll, node, vec0, arrAddress, endPos);107781077910780if (comp->target().cpu.isLittleEndian() && !isLatin1)10781{10782generateTrg1ImmInstruction(cg, TR::InstOpCode::vspltisb, node, vec2, 8);10783generateTrg1Src2Instruction(cg, TR::InstOpCode::vrlq, node, vec1, vec1, vec2);10784}1078510786if (isLatin1)10787generateTrg1Src2Instruction(cg, TR::InstOpCode::vcmpequb, node, vec0, vec0, vec1);10788else10789generateTrg1Src2Instruction(cg, TR::InstOpCode::vcmpequh, node, vec0, vec0, vec1);1079010791generateLabelInstruction(cg, TR::InstOpCode::label, node, resultLabel); // resultLabel10792generateTrg1Src1Instruction(cg, TR::InstOpCode::vclzlsbb, node, temp, vec0);10793generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp, temp, position);1079410795if (!isLatin1)10796{10797generateShiftRightLogicalImmediate(cg, node, temp, temp, 1);10798}10799generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr6, temp, length);1080010801generateTrg1Src3Instruction(cg, TR::InstOpCode::isellt, node, result, temp, result, cr6);10802// end1080310804TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 13, cg->trMemory());1080510806deps->addPostCondition(array, TR::RealRegister::NoReg);10807deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();10808deps->addPostCondition(ch, TR::RealRegister::NoReg);10809deps->addPostCondition(offset, TR::RealRegister::NoReg);10810deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();10811deps->addPostCondition(length, TR::RealRegister::NoReg);1081210813deps->addPostCondition(cr6, TR::RealRegister::cr6);1081410815deps->addPostCondition(position, TR::RealRegister::NoReg);10816deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();10817deps->addPostCondition(endPos, TR::RealRegister::NoReg);10818deps->addPostCondition(arrAddress, TR::RealRegister::NoReg);10819deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();10820deps->addPostCondition(result, TR::RealRegister::NoReg);10821deps->addPostCondition(temp, TR::RealRegister::NoReg);10822deps->addPostCondition(vec0, TR::RealRegister::NoReg);10823deps->addPostCondition(vec1, TR::RealRegister::NoReg);10824deps->addPostCondition(vec2, TR::RealRegister::NoReg);1082510826generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);1082710828deps->stopUsingDepRegs(cg, result);1082910830node->setRegister(result);1083110832cg->decReferenceCount(node->getChild(0));10833cg->decReferenceCount(node->getChild(1));10834cg->decReferenceCount(node->getChild(2));10835cg->decReferenceCount(node->getChild(3));10836cg->decReferenceCount(node->getChild(4));1083710838return result;10839}1084010841static TR::Register *inlineIntrinsicIndexOf(TR::Node *node, TR::CodeGenerator *cg, bool isLatin1)10842{10843static bool disableIndexOfStringIntrinsic = feGetEnv("TR_DisableIndexOfStringIntrinsic") != NULL;10844if (disableIndexOfStringIntrinsic)10845return nullptr;10846TR::Compilation *comp = cg->comp();10847auto vectorCompareOp = isLatin1 ? TR::InstOpCode::vcmpequb_r : TR::InstOpCode::vcmpequh_r;10848auto scalarLoadOp = isLatin1 ? TR::InstOpCode::lbzx : TR::InstOpCode::lhzx;1084910850TR::Register *array = cg->evaluate(node->getChild(1));10851TR::Register *ch = cg->evaluate(node->getChild(2));10852TR::Register *offset = cg->evaluate(node->getChild(3));10853TR::Register *length = cg->evaluate(node->getChild(4));1085410855TR::Register *cr0 = cg->allocateRegister(TR_CCR);10856TR::Register *cr6 = cg->allocateRegister(TR_CCR);1085710858TR::Register *zeroRegister = cg->allocateRegister();10859TR::Register *result = cg->allocateRegister();10860TR::Register *arrAddress = cg->allocateRegister();10861TR::Register *currentAddress = cg->allocateRegister();10862TR::Register *endAddress = cg->allocateRegister();1086310864TR::Register *targetVector = cg->allocateRegister(TR_VRF);10865TR::Register *targetVectorNot = cg->allocateRegister(TR_VRF);10866TR::Register *searchVector = cg->allocateRegister(TR_VRF);10867TR::Register *permuteVector = cg->allocateRegister(TR_VRF);1086810869TR_PPCScratchRegisterManager *srm = cg->generateScratchRegisterManager();1087010871TR::LabelSymbol *startLabel = generateLabelSymbol(cg);10872TR::LabelSymbol *notSmallLabel = generateLabelSymbol(cg);10873TR::LabelSymbol *vectorLoopLabel = generateLabelSymbol(cg);10874TR::LabelSymbol *residueLabel = generateLabelSymbol(cg);10875TR::LabelSymbol *notFoundLabel = generateLabelSymbol(cg);10876TR::LabelSymbol *foundLabel = generateLabelSymbol(cg);10877TR::LabelSymbol *foundExactLabel = generateLabelSymbol(cg);10878TR::LabelSymbol *endLabel = generateLabelSymbol(cg);1087910880startLabel->setStartInternalControlFlow();10881endLabel->setEndInternalControlFlow();1088210883generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);1088410885// Special case for empty strings, which always return -110886generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr0, offset, length);10887generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, notFoundLabel, cr0);1088810889// IMPORTANT: The upper 32 bits of a 64-bit register containing an int are undefined. Since the10890// indices are being passed in as ints, we must ensure that their upper 32 bits are not garbage.10891generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, result, offset);10892generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, endAddress, length);1089310894if (!isLatin1)10895{10896generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, result, result, result);10897generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, endAddress, endAddress, endAddress);10898}1089910900if (node->getChild(3)->getReferenceCount() == 1)10901srm->donateScratchRegister(offset);10902if (node->getChild(4)->getReferenceCount() == 1)10903srm->donateScratchRegister(length);1090410905generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, arrAddress, array, TR::Compiler->om.contiguousArrayHeaderSizeInBytes());10906if (node->getChild(1)->getReferenceCount() == 1)10907srm->donateScratchRegister(array);1090810909// Handle the first character using a simple scalar compare. Otherwise, first character matches10910// would be slower than the old scalar comparison loop. This is a problem since first character10911// matches are common in certain contexts, e.g. StringTokenizer where the default first character10912// to each String.indexOf call is ' ', which is the most common whitespace character.10913{10914TR::Register *value = srm->findOrCreateScratchRegister();10915TR::Register *zxTargetScalar = srm->findOrCreateScratchRegister();1091610917// Since we're going to do a load followed immediately by a comparison, we need to ensure that10918// the target scalar is zero-extended and *not* sign-extended.10919generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, zxTargetScalar, ch, 0, isLatin1 ? 0xff : 0xffff);1092010921generateTrg1MemInstruction(cg, scalarLoadOp, node, value, TR::MemoryReference::createWithIndexReg(cg, result, arrAddress, isLatin1 ? 1 : 2));10922generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr0, value, zxTargetScalar);10923generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, foundExactLabel, cr0);1092410925generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, result, result, isLatin1 ? 1 : 2);10926generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, result, endAddress);10927generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, notFoundLabel, cr0);1092810929srm->reclaimScratchRegister(zxTargetScalar);10930srm->reclaimScratchRegister(value);10931}1093210933generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, zeroRegister, 0);1093410935// Calculate the actual addresses of the start and end points10936generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, endAddress, arrAddress, endAddress);10937generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, currentAddress, arrAddress, result);1093810939// Splat the value to be compared against and its bitwise complement into two vector registers10940// for later use10941generateTrg1Src1Instruction(cg, TR::InstOpCode::mtvsrwz, node, targetVector, ch);10942if (node->getChild(2)->getReferenceCount() == 1)10943srm->donateScratchRegister(ch);10944if (isLatin1)10945generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::vspltb, node, targetVector, targetVector, 7);10946else10947generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::vsplth, node, targetVector, targetVector, 3);10948generateTrg1Src2Instruction(cg, TR::InstOpCode::vnor, node, targetVectorNot, targetVector, targetVector);1094910950TR::Register *endVectorAddress = srm->findOrCreateScratchRegister();10951TR::Register *startVectorAddress = srm->findOrCreateScratchRegister();1095210953// Calculate the end address for what can be compared using full vector compares. After reaching10954// this address, the remaining comparisons (if required) will need special handling.10955generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, endVectorAddress, endAddress, 0, CONSTANT64(0xfffffffffffffff0));1095610957// Check if the entire string is contained within a single 16-byte aligned section. If this10958// happens, we need to handle that case specially.10959generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, startVectorAddress, currentAddress, 0, CONSTANT64(0xfffffffffffffff0));10960generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, startVectorAddress, endVectorAddress);10961generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, notSmallLabel, cr0);1096210963// If we got here, then the entire string to search is contained within a single 16-byte aligned10964// vector and the end of the string is not aligned to the end of the vector. We don't know10965// whether the start of the string is aligned, but we'll assume it isn't since that just results10966// in a few unnecessary operations producing the correct answer regardless.1096710968// First, we read in an entire 16-byte aligned vector containing the entire string. Since this10969// load is done with 16-byte natural alignment, this load can't cross a page boundary and cause10970// an unexpected page fault. However, this will read some garbage at the start and end of the10971// vector. Assume that we read n bytes of garbage before the string and m bytes of garbage after10972// the string.10973generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, searchVector, TR::MemoryReference::createWithIndexReg(cg, zeroRegister, currentAddress, 16));1097410975{10976TR::Register *scratchRegister = srm->findOrCreateScratchRegister();1097710978// We need to ensure that the garbage we read can't compare as equal to the target value for10979// obvious reasons. In order to accomplish this, we first rotate forwards by m bytes. This10980// places all garbage at the beginning of the vector.10981generateTrg1Src1Instruction(cg, TR::InstOpCode::neg, node, scratchRegister, endAddress);10982generateTrg1Src2Instruction(cg, comp->target().cpu.isLittleEndian() ? TR::InstOpCode::lvsl : TR::InstOpCode::lvsr, node, permuteVector, zeroRegister, scratchRegister);10983generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, searchVector, permuteVector);1098410985// Next, we shift the vector backwards by (n + m) bytes shifting in the bitwise complement of10986// the target value. This causes the garbage to end up at the vector register, having been10987// replaced with a bit pattern that can never compare as equal to the target value.10988generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, scratchRegister, scratchRegister, currentAddress);10989if (comp->target().cpu.isLittleEndian())10990{10991generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsr, node, permuteVector, zeroRegister, scratchRegister);10992generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, targetVectorNot, searchVector, permuteVector);10993}10994else10995{10996generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsl, node, permuteVector, zeroRegister, scratchRegister);10997generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, targetVectorNot, permuteVector);10998}1099911000srm->reclaimScratchRegister(scratchRegister);1100111002// Now the search vector is ready for comparison: none of the garbage can compare as equal to11003// our target value and the start of the vector is now aligned to the start of the string. So11004// we can now perform the comparison as normal.11005generateTrg1Src2Instruction(cg, vectorCompareOp, node, searchVector, searchVector, targetVector);11006generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, foundLabel, cr6);11007generateLabelInstruction(cg, TR::InstOpCode::b, node, notFoundLabel);11008}1100911010generateLabelInstruction(cg, TR::InstOpCode::label, node, notSmallLabel);1101111012// Check if we already have 16-byte alignment. Vector loads require 16-byte alignment, so if we11013// aren't properly aligned, we'll need to handle comparisons specially until we achieve 16-byte11014// alignment.11015generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, currentAddress, startVectorAddress);11016generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, vectorLoopLabel, cr0);1101711018// We are not on a 16-byte boundary, so we cannot directly load the first 16 bytes of the string11019// for comparison. Instead, we load the 16 byte vector starting from the 16-byte aligned section11020// containing the start of the string. Since we have 16-byte natural alignment, this can't cause11021// an unexpected page fault.11022generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, searchVector, TR::MemoryReference::createWithIndexReg(cg, zeroRegister, currentAddress, 16));1102311024// However, before we can run any comparisons on the loaded vector, we must ensure that the extra11025// garbage read before the start of the string can't match the target character. To do this, we11026// shift the loaded vector backwards by n bytes shifting in the bitwise complement of the target11027// character.11028if (comp->target().cpu.isLittleEndian())11029{11030generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsr, node, permuteVector, zeroRegister, currentAddress);11031generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, targetVectorNot, searchVector, permuteVector);11032}11033else11034{11035generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsl, node, permuteVector, zeroRegister, currentAddress);11036generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, targetVectorNot, permuteVector);11037}1103811039// Now our vector is ready for comparison: no garbage can match the target value and the start of11040// the vector is now aligned to the start of the string.11041generateTrg1Src2Instruction(cg, vectorCompareOp, node, searchVector, searchVector, targetVector);11042generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, foundLabel, cr6);1104311044// If the first vector didn't match, then we can slide right into the standard vectorized loop.11045generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, currentAddress, startVectorAddress, 0x10);11046generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, currentAddress, endVectorAddress);11047generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, residueLabel, cr0);1104811049srm->reclaimScratchRegister(startVectorAddress);1105011051// This is the heart of the vectorized loop, working just like any standard vectorized loop.11052generateLabelInstruction(cg, TR::InstOpCode::label, node, vectorLoopLabel);11053generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, searchVector, TR::MemoryReference::createWithIndexReg(cg, zeroRegister, currentAddress, 16));11054generateTrg1Src2Instruction(cg, vectorCompareOp, node, searchVector, searchVector, targetVector);11055generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, foundLabel, cr6);1105611057generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, currentAddress, currentAddress, 0x10);11058generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, currentAddress, endVectorAddress);11059generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, vectorLoopLabel, cr0);1106011061srm->reclaimScratchRegister(endVectorAddress);1106211063// Now we're done with the part of the loop which can be handled as a normal vectorized loop. If11064// there are no more elements to compare, we're done. Otherwise, we need to handle the residue.11065generateLabelInstruction(cg, TR::InstOpCode::label, node, residueLabel);11066generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, currentAddress, endAddress);11067generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, notFoundLabel, cr0);1106811069// Usually, we would need a residue loop here, but it's safe to read beyond the end of the string11070// here. Since our load will have 16-byte natural alignment, it can't cross a page boundary and11071// cause an unexpected page fault.11072generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, searchVector, TR::MemoryReference::createWithIndexReg(cg, zeroRegister, currentAddress, 16));1107311074TR::Register *shiftAmount = srm->findOrCreateScratchRegister();1107511076// Before we can run our comparison, we need to ensure that the garbage from beyond the end of11077// the string cannot compare as equal to our target value. To do this, we first rotate the vector11078// forwards by n bytes then shift back by n bytes, shifting in the bitwise complement of the11079// target value.11080generateTrg1Src1Instruction(cg, TR::InstOpCode::neg, node, shiftAmount, endAddress);11081if (comp->target().cpu.isLittleEndian())11082{11083generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsl, node, permuteVector, zeroRegister, shiftAmount);11084generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, searchVector, permuteVector);11085generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsr, node, permuteVector, zeroRegister, shiftAmount);11086generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, targetVectorNot, searchVector, permuteVector);11087}11088else11089{11090generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsr, node, permuteVector, zeroRegister, shiftAmount);11091generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, searchVector, permuteVector);11092generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsl, node, permuteVector, zeroRegister, shiftAmount);11093generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, targetVectorNot, permuteVector);11094}1109511096srm->reclaimScratchRegister(shiftAmount);1109711098// Now we run our comparison as normal11099generateTrg1Src2Instruction(cg, vectorCompareOp, node, searchVector, searchVector, targetVector);11100generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, foundLabel, cr6);1110111102generateLabelInstruction(cg, TR::InstOpCode::label, node, notFoundLabel);1110311104// We've looked through the entire string and didn't find our target character, so return the11105// sentinel value -111106generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, result, -1);11107generateLabelInstruction(cg, TR::InstOpCode::b, node, endLabel);1110811109generateLabelInstruction(cg, TR::InstOpCode::label, node, foundLabel);1111011111// We've managed to find a match for the target value in the loaded vector, but we don't yet know11112// which element of the loaded vector is the first match. The comparison will have set matching11113// elements in the vector to -1 and non-matching elements to 0. We can find the first matching11114// element by gathering the first bit of every byte in the vector register...1111511116// Set permuteVector = 0x000102030405060708090a0b0c0d0e0f11117generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsl, node, permuteVector, zeroRegister, zeroRegister);1111811119// For little-endian, reverse permuteVector so that we can find the first set bit using a count11120// leading zeroes test instead of a count trailing zeroes test. This is necessary since cnttzw11121// wasn't introduced until Power 9.11122if (comp->target().cpu.isLittleEndian())11123{11124generateTrg1ImmInstruction(cg, TR::InstOpCode::vspltisb, node, targetVector, 0x0f);11125generateTrg1Src2Instruction(cg, TR::InstOpCode::vsububm, node, permuteVector, targetVector, permuteVector);11126}1112711128// Set permuteVector = 0x00081018202830384048505860687078 (reversed for LE)11129generateTrg1ImmInstruction(cg, TR::InstOpCode::vspltisb, node, targetVector, 3);11130generateTrg1Src2Instruction(cg, TR::InstOpCode::vslb, node, permuteVector, permuteVector, targetVector);1113111132generateTrg1Src2Instruction(cg, TR::InstOpCode::vbpermq, node, searchVector, searchVector, permuteVector);11133generateTrg1Src1Instruction(cg, TR::InstOpCode::mfvsrwz, node, result, searchVector);1113411135// Then count the number of leading zeroes from the obtained result. This tells us the index (in11136// bytes) of the first matching element in the vector. Note that there is no way to count leading11137// zeroes of a half-word, so we count leading zeroes of a word and subtract 16 since the value11138// we're interested in is in the least significant half-word.11139generateTrg1Src1Instruction(cg, TR::InstOpCode::cntlzw, node, result, result);11140generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, result, result, -16);1114111142// Finally, combine this with the address of the last vector load to find the address of the11143// first matching element in the string. Finally, use this to calculate the corresponding index.11144generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, result, result, currentAddress);11145generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, result, arrAddress, result);1114611147generateLabelInstruction(cg, TR::InstOpCode::label, node, foundExactLabel);11148if (!isLatin1)11149generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::srawi, node, result, result, 1);1115011151TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 15 + srm->numAvailableRegisters(), cg->trMemory());1115211153if (node->getChild(1)->getReferenceCount() != 1)11154{11155deps->addPostCondition(array, TR::RealRegister::NoReg);11156deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();11157}11158if (node->getChild(2)->getReferenceCount() != 1)11159deps->addPostCondition(ch, TR::RealRegister::NoReg);11160if (node->getChild(3)->getReferenceCount() != 1)11161deps->addPostCondition(offset, TR::RealRegister::NoReg);11162if (node->getChild(4)->getReferenceCount() != 1)11163deps->addPostCondition(length, TR::RealRegister::NoReg);1116411165deps->addPostCondition(cr0, TR::RealRegister::cr0);11166deps->addPostCondition(cr6, TR::RealRegister::cr6);1116711168deps->addPostCondition(zeroRegister, TR::RealRegister::NoReg);11169deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();11170deps->addPostCondition(result, TR::RealRegister::NoReg);11171deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();11172deps->addPostCondition(arrAddress, TR::RealRegister::NoReg);11173deps->addPostCondition(currentAddress, TR::RealRegister::NoReg);11174deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();11175deps->addPostCondition(endAddress, TR::RealRegister::NoReg);1117611177deps->addPostCondition(targetVector, TR::RealRegister::NoReg);11178deps->addPostCondition(targetVectorNot, TR::RealRegister::NoReg);11179deps->addPostCondition(searchVector, TR::RealRegister::NoReg);11180deps->addPostCondition(permuteVector, TR::RealRegister::NoReg);1118111182srm->addScratchRegistersToDependencyList(deps, true);1118311184generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);1118511186deps->stopUsingDepRegs(cg, result);1118711188node->setRegister(result);1118911190cg->decReferenceCount(node->getChild(0));11191cg->decReferenceCount(node->getChild(1));11192cg->decReferenceCount(node->getChild(2));11193cg->decReferenceCount(node->getChild(3));11194cg->decReferenceCount(node->getChild(4));1119511196return result;11197}1119811199/*11200* Arraycopy evaluator needs a version of inlineArrayCopy that can be used inside internal control flow. For this version of inlineArrayCopy, registers must11201* be allocated outside of this function so the dependency at the end of the control flow knows about them.11202*/11203static void inlineArrayCopy_ICF(TR::Node *node, int64_t byteLen, TR::Register *src, TR::Register *dst, TR::CodeGenerator *cg, TR::Register *cndReg,11204TR::Register *tmp1Reg, TR::Register *tmp2Reg, TR::Register *tmp3Reg, TR::Register *tmp4Reg,11205TR::Register *fp1Reg, TR::Register *fp2Reg, TR::Register *fp3Reg, TR::Register *fp4Reg)11206{11207if (byteLen == 0)11208return;1120911210bool postP10CopyInline = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10) &&11211cg->comp()->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX);1121211213if (postP10CopyInline)11214{11215// tmp1Reg and fp1Reg can be used: fp1Reg is a VSX_VECTOR1121611217int32_t iteration64 = byteLen >> 6, residue64 = byteLen & 0x3F, standingOffset = 0;1121811219if (iteration64 > 0)11220{11221TR::LabelSymbol *loopStart;1122211223if (iteration64 > 1)11224{11225generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tmp1Reg, iteration64);11226generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, tmp1Reg);1122711228loopStart = generateLabelSymbol(cg);11229generateLabelInstruction(cg, TR::InstOpCode::label, node, loopStart);11230}1123111232generateTrg1MemInstruction(cg, TR::InstOpCode::lxv, node, fp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, 0, 16));11233generateMemSrc1Instruction(cg, TR::InstOpCode::stxv, node, TR::MemoryReference::createWithDisplacement(cg, dst, 0, 16), fp1Reg);11234generateTrg1MemInstruction(cg, TR::InstOpCode::lxv, node, fp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, 16, 16));11235generateMemSrc1Instruction(cg, TR::InstOpCode::stxv, node, TR::MemoryReference::createWithDisplacement(cg, dst, 16, 16), fp1Reg);11236generateTrg1MemInstruction(cg, TR::InstOpCode::lxv, node, fp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, 32, 16));11237generateMemSrc1Instruction(cg, TR::InstOpCode::stxv, node, TR::MemoryReference::createWithDisplacement(cg, dst, 32, 16), fp1Reg);11238generateTrg1MemInstruction(cg, TR::InstOpCode::lxv, node, fp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, 48, 16));11239generateMemSrc1Instruction(cg, TR::InstOpCode::stxv, node, TR::MemoryReference::createWithDisplacement(cg, dst, 48, 16), fp1Reg);1124011241if (iteration64 > 1)11242{11243generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, src, src, 64);11244generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, dst, dst, 64);11245generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, loopStart, cndReg);11246}11247else11248standingOffset = 64;11249}1125011251for (int32_t i = 0; i < (residue64>>4); i++)11252{11253generateTrg1MemInstruction(cg, TR::InstOpCode::lxv, node, fp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, standingOffset+i*16, 16));11254generateMemSrc1Instruction(cg, TR::InstOpCode::stxv, node, TR::MemoryReference::createWithDisplacement(cg, dst, standingOffset+i*16, 16), fp1Reg);11255}1125611257if ((residue64 & 0xF) != 0)11258{11259standingOffset += residue64 & 0x30;11260switch (residue64 & 0xF)11261{11262case 1:11263generateTrg1MemInstruction(cg, TR::InstOpCode::lbz, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, standingOffset, 1));11264generateMemSrc1Instruction(cg, TR::InstOpCode::stb, node, TR::MemoryReference::createWithDisplacement(cg, dst, standingOffset, 1), tmp1Reg);11265break;11266case 2:11267generateTrg1MemInstruction(cg, TR::InstOpCode::lhz, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, standingOffset, 2));11268generateMemSrc1Instruction(cg, TR::InstOpCode::sth, node, TR::MemoryReference::createWithDisplacement(cg, dst, standingOffset, 2), tmp1Reg);11269break;11270case 4:11271generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, standingOffset, 4));11272generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, dst, standingOffset, 4), tmp1Reg);11273break;11274case 8:11275generateTrg1MemInstruction(cg, TR::InstOpCode::ld, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, standingOffset, 8));11276generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, TR::MemoryReference::createWithDisplacement(cg, dst, standingOffset, 8), tmp1Reg);11277break;11278default:11279generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tmp1Reg, residue64 & 0xF);11280generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, tmp1Reg, tmp1Reg,1128156, CONSTANT64(0xff00000000000000));11282if (standingOffset != 0)11283{11284generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, src, src, standingOffset);11285generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, dst, dst, standingOffset);11286}11287generateTrg1Src2Instruction(cg, TR::InstOpCode::lxvl, node, fp1Reg, src, tmp1Reg);11288generateSrc3Instruction(cg, TR::InstOpCode::stxvl, node, fp1Reg, dst, tmp1Reg);11289break;11290}11291}11292}11293else11294{11295TR::Register *regs[4] = {tmp1Reg, tmp2Reg, tmp3Reg, tmp4Reg};11296TR::Register *fpRegs[4] = {fp1Reg, fp2Reg, fp3Reg, fp4Reg};11297int32_t groups, residual;1129811299static bool disableLEArrayCopyInline = (feGetEnv("TR_disableLEArrayCopyInline") != NULL);11300bool supportsLEArrayCopyInline = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) && !disableLEArrayCopyInline && cg->comp()->target().cpu.isLittleEndian() && cg->comp()->target().cpu.hasFPU() && cg->comp()->target().is64Bit();1130111302if (cg->comp()->target().is64Bit())11303{11304groups = byteLen >> 5;11305residual = byteLen & 0x0000001F;11306}11307else11308{11309groups = byteLen >> 4;11310residual = byteLen & 0x0000000F;11311}1131211313int32_t regIx = 0, ix = 0, fpRegIx = 0;11314int32_t memRefSize;11315TR::InstOpCode::Mnemonic load, store;11316TR::Compilation* comp = cg->comp();1131711318/* Some machines have issues with 64bit loads/stores in 32bit mode, ie. sicily, do not check for is64BitProcessor() */11319memRefSize = TR::Compiler->om.sizeofReferenceAddress();11320load = TR::InstOpCode::Op_load;11321store = TR::InstOpCode::Op_st;1132211323if (groups != 0)11324{11325TR::LabelSymbol *loopStart;1132611327if (groups != 1)11328{11329if (groups <= UPPER_IMMED)11330generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, regs[0], groups);11331else11332loadConstant(cg, node, groups, regs[0]);11333generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, regs[0]);1133411335loopStart = generateLabelSymbol(cg);11336generateLabelInstruction(cg, TR::InstOpCode::label, node, loopStart);11337}1133811339if (supportsLEArrayCopyInline)11340{11341generateTrg1MemInstruction(cg, TR::InstOpCode::lfd, node, fpRegs[3], TR::MemoryReference::createWithDisplacement(cg, src, 0, memRefSize));11342generateTrg1MemInstruction(cg, TR::InstOpCode::lfd, node, fpRegs[2], TR::MemoryReference::createWithDisplacement(cg, src, memRefSize, memRefSize));11343generateTrg1MemInstruction(cg, TR::InstOpCode::lfd, node, fpRegs[1], TR::MemoryReference::createWithDisplacement(cg, src, 2*memRefSize, memRefSize));11344generateTrg1MemInstruction(cg, TR::InstOpCode::lfd, node, fpRegs[0], TR::MemoryReference::createWithDisplacement(cg, src, 3*memRefSize, memRefSize));11345}11346else11347{11348generateTrg1MemInstruction(cg, load, node, regs[3], TR::MemoryReference::createWithDisplacement(cg, src, 0, memRefSize));11349generateTrg1MemInstruction(cg, load, node, regs[2], TR::MemoryReference::createWithDisplacement(cg, src, memRefSize, memRefSize));11350generateTrg1MemInstruction(cg, load, node, regs[1], TR::MemoryReference::createWithDisplacement(cg, src, 2*memRefSize, memRefSize));11351generateTrg1MemInstruction(cg, load, node, regs[0], TR::MemoryReference::createWithDisplacement(cg, src, 3*memRefSize, memRefSize));11352}1135311354if (groups != 1)11355generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, src, src, 4*memRefSize);1135611357if (supportsLEArrayCopyInline)11358{11359generateMemSrc1Instruction(cg, TR::InstOpCode::stfd, node, TR::MemoryReference::createWithDisplacement(cg, dst, 0, memRefSize), fpRegs[3]);11360generateMemSrc1Instruction(cg, TR::InstOpCode::stfd, node, TR::MemoryReference::createWithDisplacement(cg, dst, memRefSize, memRefSize), fpRegs[2]);11361generateMemSrc1Instruction(cg, TR::InstOpCode::stfd, node, TR::MemoryReference::createWithDisplacement(cg, dst, 2*memRefSize, memRefSize), fpRegs[1]);11362generateMemSrc1Instruction(cg, TR::InstOpCode::stfd, node, TR::MemoryReference::createWithDisplacement(cg, dst, 3*memRefSize, memRefSize), fpRegs[0]);11363}11364else11365{11366generateMemSrc1Instruction(cg, store, node, TR::MemoryReference::createWithDisplacement(cg, dst, 0, memRefSize), regs[3]);11367generateMemSrc1Instruction(cg, store, node, TR::MemoryReference::createWithDisplacement(cg, dst, memRefSize, memRefSize), regs[2]);11368generateMemSrc1Instruction(cg, store, node, TR::MemoryReference::createWithDisplacement(cg, dst, 2*memRefSize, memRefSize), regs[1]);11369generateMemSrc1Instruction(cg, store, node, TR::MemoryReference::createWithDisplacement(cg, dst, 3*memRefSize, memRefSize), regs[0]);11370}1137111372if (groups != 1)11373{11374generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, dst, dst, 4*memRefSize);11375generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, loopStart, cndReg);11376}11377else11378{11379ix = 4*memRefSize;11380}11381}1138211383for (; residual>=memRefSize; residual-=memRefSize, ix+=memRefSize)11384{11385if (supportsLEArrayCopyInline)11386{11387TR::Register *oneReg = fpRegs[fpRegIx++];11388if (fpRegIx>3 || fpRegs[fpRegIx]==NULL)11389fpRegIx = 0;11390generateTrg1MemInstruction(cg, TR::InstOpCode::lfd, node, oneReg, TR::MemoryReference::createWithDisplacement(cg, src, ix, memRefSize));11391generateMemSrc1Instruction(cg, TR::InstOpCode::stfd, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, memRefSize), oneReg);11392}11393else11394{11395TR::Register *oneReg = regs[regIx++];11396if (regIx>3 || regs[regIx]==NULL)11397regIx = 0;11398generateTrg1MemInstruction(cg, load, node, oneReg, TR::MemoryReference::createWithDisplacement(cg, src, ix, memRefSize));11399generateMemSrc1Instruction(cg, store, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, memRefSize), oneReg);11400}11401}1140211403if (residual != 0)11404{11405if (residual & 4)11406{11407if (supportsLEArrayCopyInline)11408{11409TR::Register *oneReg = fpRegs[fpRegIx++];11410if (fpRegIx>3 || fpRegs[fpRegIx]==NULL)11411fpRegIx = 0;11412generateTrg1MemInstruction(cg, TR::InstOpCode::lfs, node, oneReg, TR::MemoryReference::createWithDisplacement(cg, src, ix, 4));11413generateMemSrc1Instruction(cg, TR::InstOpCode::stfs, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, 4), oneReg);11414}11415else11416{11417TR::Register *oneReg = regs[regIx++];11418if (regIx>3 || regs[regIx]==NULL)11419regIx = 0;11420generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, oneReg, TR::MemoryReference::createWithDisplacement(cg, src, ix, 4));11421generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, 4), oneReg);11422}11423ix += 4;11424}11425if (residual & 2)11426{11427TR::Register *oneReg = regs[regIx++];11428if (regIx>3 || regs[regIx]==NULL)11429regIx = 0;11430generateTrg1MemInstruction(cg, TR::InstOpCode::lhz, node, oneReg, TR::MemoryReference::createWithDisplacement(cg, src, ix, 2));11431generateMemSrc1Instruction(cg, TR::InstOpCode::sth, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, 2), oneReg);11432ix += 2;11433}11434if (residual & 1)11435{11436generateTrg1MemInstruction(cg, TR::InstOpCode::lbz, node, regs[regIx], TR::MemoryReference::createWithDisplacement(cg, src, ix, 1));11437generateMemSrc1Instruction(cg, TR::InstOpCode::stb, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, 1), regs[regIx]);11438}11439}11440}1144111442return;11443}1144411445bool11446J9::Power::CodeGenerator::inlineDirectCall(TR::Node *node, TR::Register *&resultReg)11447{11448TR::CodeGenerator *cg = self();11449TR::Compilation *comp = cg->comp();11450TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());11451TR::MethodSymbol * methodSymbol = node->getSymbol()->getMethodSymbol();1145211453static bool disableDCAS = (feGetEnv("TR_DisablePPCDCAS") != NULL);11454static bool useJapaneseCompression = (feGetEnv("TR_JapaneseComp") != NULL);1145511456if (comp->getSymRefTab()->isNonHelper(node->getSymbolReference(), TR::SymbolReferenceTable::singlePrecisionSQRTSymbol))11457{11458resultReg = inlineSinglePrecisionFP(node, TR::InstOpCode::fsqrts, cg);11459return true;11460}11461else if (OMR::CodeGeneratorConnector::inlineDirectCall(node, resultReg))11462{11463return true;11464}11465else if (methodSymbol)11466{11467switch (methodSymbol->getRecognizedMethod())11468{11469case TR::java_util_concurrent_ConcurrentLinkedQueue_tmOffer:11470{11471if (cg->getSupportsInlineConcurrentLinkedQueue())11472{11473resultReg = inlineConcurrentLinkedQueueTMOffer(node, cg);11474return true;11475}11476break;11477}1147811479case TR::java_util_concurrent_ConcurrentLinkedQueue_tmPoll:11480{11481if (cg->getSupportsInlineConcurrentLinkedQueue())11482{11483resultReg = inlineConcurrentLinkedQueueTMPoll(node, cg);11484return true;11485}11486break;11487}11488case TR::jdk_internal_misc_Unsafe_copyMemory0:11489case TR::sun_misc_Unsafe_copyMemory:11490if (comp->canTransformUnsafeCopyToArrayCopy()11491&& methodSymbol->isNative()11492&& performTransformation(comp,11493"O^O Call arraycopy instead of Unsafe.copyMemory: %s\n", cg->getDebug()->getName(node)))11494{11495TR::Node *src = node->getChild(1);11496TR::Node *srcOffset = node->getChild(2);11497TR::Node *dest = node->getChild(3);11498TR::Node *destOffset = node->getChild(4);11499TR::Node *len = node->getChild(5);1150011501if (comp->target().is32Bit())11502{11503srcOffset = TR::Node::create(TR::l2i, 1, srcOffset);11504destOffset = TR::Node::create(TR::l2i, 1, destOffset);11505len = TR::Node::create(TR::l2i, 1, len);11506src = TR::Node::create(TR::aiadd, 2, src, srcOffset);11507dest = TR::Node::create(TR::aiadd, 2, dest, destOffset);11508}11509else11510{11511src = TR::Node::create(TR::aladd, 2, src, srcOffset);11512dest = TR::Node::create(TR::aladd, 2, dest, destOffset);11513}1151411515TR::Node *arraycopyNode = TR::Node::createArraycopy(src, dest, len);11516TR::TreeEvaluator::arraycopyEvaluator(arraycopyNode,cg);1151711518if (node->getChild(0)->getRegister())11519cg->decReferenceCount(node->getChild(0));11520else11521node->getChild(0)->recursivelyDecReferenceCount();1152211523cg->decReferenceCount(node->getChild(1));11524cg->decReferenceCount(node->getChild(2));11525cg->decReferenceCount(node->getChild(3));11526cg->decReferenceCount(node->getChild(4));11527cg->decReferenceCount(node->getChild(5));1152811529return true;11530}11531break;1153211533case TR::sun_misc_Unsafe_setMemory:11534if (comp->canTransformUnsafeSetMemory())11535{11536TR::Node *dest = node->getChild(1);11537TR::Node *destOffset = node->getChild(2);11538TR::Node *len = node->getChild(3);11539TR::Node *byteValue = node->getChild(4);11540dest = TR::Node::create(TR::aladd, 2, dest, destOffset);1154111542TR::Node * copyMemNode = TR::Node::createWithSymRef(TR::arrayset, 3, 3, dest, len, byteValue, node->getSymbolReference());11543copyMemNode->setByteCodeInfo(node->getByteCodeInfo());1154411545TR::TreeEvaluator::setmemoryEvaluator(copyMemNode,cg);1154611547if (node->getChild(0)->getRegister())11548cg->decReferenceCount(node->getChild(0));11549else11550node->getChild(0)->recursivelyDecReferenceCount();1155111552cg->decReferenceCount(node->getChild(1));11553cg->decReferenceCount(node->getChild(2));11554cg->decReferenceCount(node->getChild(3));11555cg->decReferenceCount(node->getChild(4));11556return true;11557}11558break;1155911560case TR::java_lang_String_compress:11561resultReg = compressStringEvaluator(node, cg, useJapaneseCompression);11562return true;11563break;1156411565case TR::java_lang_String_compressNoCheck:11566resultReg = compressStringNoCheckEvaluator(node, cg, useJapaneseCompression);11567return true;1156811569case TR::java_lang_String_andOR:11570resultReg = andORStringEvaluator(node, cg);11571return true;11572break;1157311574case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:11575case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:11576case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:11577case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:11578case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:11579case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:11580case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:11581case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:11582{11583resultReg = inlineAtomicOps(node, cg, 4, methodSymbol, false);11584return true;11585break;11586}1158711588case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:11589case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:11590case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:11591case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:11592case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:11593case TR::java_util_concurrent_atomic_AtomicIntegerArray_incrementAndGet:11594case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:11595{11596resultReg = inlineAtomicOps(node, cg, 4, methodSymbol, true);11597return true;11598break;11599}1160011601case TR::java_lang_Math_ceil:11602case TR::java_lang_StrictMath_ceil:11603if (methodSymbol->getResolvedMethodSymbol()->canReplaceWithHWInstr())11604{11605resultReg = inlineDoublePrecisionFP(node, TR::InstOpCode::frip, cg);11606return true;11607}11608break;1160911610case TR::java_lang_Math_floor:11611case TR::java_lang_StrictMath_floor:11612if (methodSymbol->getResolvedMethodSymbol()->canReplaceWithHWInstr())11613{11614resultReg = inlineDoublePrecisionFP(node, TR::InstOpCode::frim, cg);11615return true;11616}11617break;1161811619case TR::java_lang_Math_copySign_F:11620// StrictMath copySign spec not guaranteed by fcpsgn instruction11621if (methodSymbol->getResolvedMethodSymbol()->canReplaceWithHWInstr())11622{11623resultReg = inlineSinglePrecisionFPTrg1Src2(node, TR::InstOpCode::fcpsgn, cg);11624return true;11625}11626break;1162711628case TR::java_lang_Math_copySign_D:11629// StrictMath copySign spec not guaranteed by fcpsgn instruction11630if (methodSymbol->getResolvedMethodSymbol()->canReplaceWithHWInstr())11631{11632resultReg = inlineDoublePrecisionFPTrg1Src2(node, TR::InstOpCode::fcpsgn, cg);11633return true;11634}11635break;1163611637case TR::java_lang_Math_fma_D:11638case TR::java_lang_StrictMath_fma_D:11639resultReg = inlineFPTrg1Src3(node, TR::InstOpCode::fmadd, cg);11640return true;1164111642case TR::java_lang_Math_fma_F:11643case TR::java_lang_StrictMath_fma_F:11644resultReg = inlineFPTrg1Src3(node, TR::InstOpCode::fmadds, cg);11645return true;1164611647case TR::java_lang_String_hashCodeImplDecompressed:11648if (!TR::Compiler->om.canGenerateArraylets() && comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) && comp->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX) && !comp->compileRelocatableCode()11649#ifdef J9VM_OPT_JITSERVER11650&& !comp->isOutOfProcessCompilation()11651#endif11652)11653{11654resultReg = inlineStringHashcode(node, cg);11655return true;11656}11657break;1165811659case TR::com_ibm_jit_JITHelpers_transformedEncodeUTF16Big:11660case TR::com_ibm_jit_JITHelpers_transformedEncodeUTF16Little:11661if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P7) && comp->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX))11662{11663resultReg = inlineEncodeUTF16(node, cg);11664return true;11665}11666break;1166711668case TR::com_ibm_jit_JITHelpers_intrinsicIndexOfLatin1:11669case TR::com_ibm_jit_JITHelpers_intrinsicIndexOfUTF16:11670if (cg->getSupportsInlineStringIndexOf())11671{11672bool isLatin1 = methodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_intrinsicIndexOfLatin1;11673if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))11674resultReg = inlineIntrinsicIndexOf_P10(node, cg, isLatin1);11675else11676resultReg = inlineIntrinsicIndexOf(node, cg, isLatin1);11677return resultReg != nullptr;11678}11679break;1168011681case TR::sun_misc_Unsafe_compareAndSwapInt_jlObjectJII_Z:11682// In Java9 this can be either the jdk.internal JNI method or the sun.misc Java wrapper.11683// In Java8 it will be sun.misc which will contain the JNI directly.11684// We only want to inline the JNI methods, so add an explicit test for isNative().11685if (!methodSymbol->isNative())11686break;1168711688if ((node->isUnsafeGetPutCASCallOnNonArray() || !TR::Compiler->om.canGenerateArraylets()) && node->isSafeForCGToFastPathUnsafeCall())11689{11690resultReg = VMinlineCompareAndSwap(node, cg, false);11691return true;11692}11693break;1169411695case TR::sun_misc_Unsafe_compareAndSwapLong_jlObjectJJJ_Z:11696if (comp->getOption(TR_TraceCG))11697traceMsg(comp, "In evaluator for compareAndSwapLong. node = %p node->isSafeForCGToFastPathUnsafeCall = %p\n", node, node->isSafeForCGToFastPathUnsafeCall());11698// As above, we only want to inline the JNI methods, so add an explicit test for isNative()11699if (!methodSymbol->isNative())11700break;1170111702if (comp->target().is64Bit() && (node->isUnsafeGetPutCASCallOnNonArray() || !TR::Compiler->om.canGenerateArraylets()) && node->isSafeForCGToFastPathUnsafeCall())11703{11704resultReg = VMinlineCompareAndSwap(node, cg, true);11705return true;11706}11707else if ((node->isUnsafeGetPutCASCallOnNonArray() || !TR::Compiler->om.canGenerateArraylets()) && node->isSafeForCGToFastPathUnsafeCall())11708{11709resultReg = inlineAtomicOperation(node, cg, methodSymbol);11710return true;11711}11712break;1171311714case TR::sun_misc_Unsafe_compareAndSwapObject_jlObjectJjlObjectjlObject_Z:11715// As above, we only want to inline the JNI methods, so add an explicit test for isNative()11716if (!methodSymbol->isNative())11717break;1171811719if ((node->isUnsafeGetPutCASCallOnNonArray() || !TR::Compiler->om.canGenerateArraylets()) && node->isSafeForCGToFastPathUnsafeCall())11720{11721resultReg = VMinlineCompareAndSwapObject(node, cg);11722return true;11723}11724break;1172511726case TR::java_nio_Bits_keepAlive:11727case TR::java_lang_ref_Reference_reachabilityFence:11728{11729TR::Node *paramNode = node->getFirstChild();11730TR::Register *paramReg = cg->evaluate(paramNode);11731TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg->trMemory());11732TR::addDependency(conditions, paramReg, TR::RealRegister::NoReg, TR_GPR, cg);11733TR::LabelSymbol *label = TR::LabelSymbol::create(cg->trHeapMemory(),cg);11734generateDepLabelInstruction(cg, TR::InstOpCode::label, node, label, conditions);11735cg->decReferenceCount(paramNode);11736resultReg = NULL;11737return true;11738}1173911740case TR::x10JITHelpers_getCPU:11741break;1174211743case TR::java_util_concurrent_atomic_Fences_reachabilityFence:11744{11745cg->decReferenceCount(node->getChild(0));11746resultReg = NULL;11747return true;11748}1174911750case TR::java_util_concurrent_atomic_Fences_orderReads:11751if (performTransformation(comp, "O^O PPC Evaluator: Replacing read/read Fence with an lwsync [%p].\n", node))11752{11753// mark as seen and then just don't bother generating instructions11754TR::Node *callNode = node;11755int32_t numArgs = callNode->getNumChildren();11756for (int32_t i = numArgs - 1; i >= 0; i--)11757cg->decReferenceCount(callNode->getChild(i));11758cg->decReferenceCount(callNode);11759generateInstruction(cg, TR::InstOpCode::isync, node);11760resultReg = NULL;11761return true;11762}11763break;1176411765// for now all preStores simply emit lwsync See JIT design 159811766case TR::java_util_concurrent_atomic_Fences_preStoreFence:11767case TR::java_util_concurrent_atomic_Fences_preStoreFence_jlObject:11768case TR::java_util_concurrent_atomic_Fences_preStoreFence_jlObjectI:11769case TR::java_util_concurrent_atomic_Fences_preStoreFence_jlObjectjlrField:11770case TR::java_util_concurrent_atomic_Fences_postLoadFence:11771case TR::java_util_concurrent_atomic_Fences_postLoadFence_jlObjectjlrField:11772case TR::java_util_concurrent_atomic_Fences_postLoadFence_jlObject:11773case TR::java_util_concurrent_atomic_Fences_postLoadFence_jlObjectI:11774case TR::java_util_concurrent_atomic_Fences_orderWrites:11775if (performTransformation(comp, "O^O PPC Evaluator: Replacing store/store Fence with an lwsync [%p].\n", node))11776{11777// mark as seen and then just don't bother generating instructions11778TR::Node *callNode = node;11779int32_t numArgs = callNode->getNumChildren();11780for (int32_t i = numArgs - 1; i >= 0; i--)11781cg->decReferenceCount(callNode->getChild(i));11782cg->decReferenceCount(callNode);11783generateInstruction(cg, TR::InstOpCode::lwsync, node);11784resultReg = NULL;11785return true;11786}11787break;1178811789// for now just emit a sync. See design 159811790case TR::java_util_concurrent_atomic_Fences_postStorePreLoadFence_jlObject:11791case TR::java_util_concurrent_atomic_Fences_postStorePreLoadFence_jlObjectjlrField:11792case TR::java_util_concurrent_atomic_Fences_postStorePreLoadFence:11793case TR::java_util_concurrent_atomic_Fences_postStorePreLoadFence_jlObjectI:11794case TR::java_util_concurrent_atomic_Fences_orderAccesses:11795if (performTransformation(comp, "O^O PPC Evaluator: Replacing store/load Fence with a sync [%p].\n", node))11796{11797TR::Node *callNode = node;11798int32_t numArgs = callNode->getNumChildren();11799for (int32_t i = numArgs - 1; i >= 0; i--)11800cg->decReferenceCount(callNode->getChild(i));11801cg->decReferenceCount(callNode);11802generateInstruction(cg, TR::InstOpCode::sync, node);11803resultReg = NULL;11804return true;11805}11806break;1180711808case TR::java_lang_Class_isAssignableFrom:11809{11810// Do not use an inline class check if the 'this' Class object is known to be an11811// abstract class or an interface at compile-time (the check will always fail11812// and go out of line).11813//11814TR::Node *receiverNode = node->getFirstChild();11815if (receiverNode->getOpCodeValue() == TR::aloadi &&11816receiverNode->getSymbolReference() == comp->getSymRefTab()->findJavaLangClassFromClassSymbolRef() &&11817receiverNode->getFirstChild()->getOpCodeValue() == TR::loadaddr)11818{11819TR::SymbolReference *receiverClassSymRef = receiverNode->getFirstChild()->getSymbolReference();11820if (receiverClassSymRef->isClassInterface(comp) ||11821receiverClassSymRef->isClassAbstract(comp))11822break;11823}1182411825static bool disable = feGetEnv("TR_disableInlineIsAssignableFrom") != NULL;11826if (!disable &&11827performTransformation(comp, "O^O PPC Evaluator: Specialize call to java/lang/Class.isAssignableFrom [%p].\n", node))11828{11829resultReg = inlineIsAssignableFrom(node, cg);11830return true;11831}1183211833break;11834}1183511836default:11837break;11838}11839}1184011841#ifdef J9VM_OPT_JAVA_CRYPTO_ACCELERATION11842if (self()->inlineCryptoMethod(node, resultReg))11843{11844return true;11845}11846#endif1184711848// No method specialization was done.11849//11850resultReg = NULL;11851return false;11852}1185311854void VMgenerateCatchBlockBBStartPrologue(TR::Node *node, TR::Instruction *fenceInstruction, TR::CodeGenerator *cg)11855{11856TR::Compilation *comp = cg->comp();11857TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());1185811859TR::Block *block = node->getBlock();1186011861if (fej9->shouldPerformEDO(block, comp))11862{11863TR::Register *biAddrReg = cg->allocateRegister();11864TR::Register *recompCounterReg = cg->allocateRegister();11865intptr_t addr = (intptr_t) (comp->getRecompilationInfo()->getCounterAddress());11866TR::Instruction *cursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, addr, biAddrReg);11867TR::MemoryReference *loadbiMR = TR::MemoryReference::createWithDisplacement(cg, biAddrReg, 0, TR::Compiler->om.sizeofReferenceAddress());11868TR::MemoryReference *storebiMR = TR::MemoryReference::createWithDisplacement(cg, biAddrReg, 0, TR::Compiler->om.sizeofReferenceAddress());11869cursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, recompCounterReg, loadbiMR);11870TR::Register *cndRegister = cg->allocateRegister(TR_CCR);11871cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2_r, node, recompCounterReg, recompCounterReg, cndRegister, -1, cursor);11872cursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, storebiMR, recompCounterReg, cursor);11873cg->stopUsingRegister(biAddrReg);11874cg->stopUsingRegister(recompCounterReg);1187511876TR::LabelSymbol *snippetLabel = NULL;11877TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);11878// snippet call chain through jitCallCFunction kills 3 parameter11879// registers that we will reserve here11880TR::Register *arg1Reg, *arg2Reg, *arg3Reg;11881arg1Reg = cg->allocateRegister();11882arg2Reg = cg->allocateRegister();11883arg3Reg = cg->allocateRegister();1188411885snippetLabel = cg->lookUpSnippet(TR::Snippet::IsForceRecompilation, NULL);11886if (snippetLabel == NULL)11887{11888TR::Snippet *snippet;11889snippetLabel = generateLabelSymbol(cg);11890snippet = new (cg->trHeapMemory()) TR::PPCForceRecompilationSnippet(snippetLabel, doneLabel, cursor, cg);11891cg->addSnippet(snippet);11892}1189311894TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());11895TR::addDependency(conditions, arg1Reg, TR::RealRegister::gr3, TR_GPR, cg);11896TR::addDependency(conditions, arg2Reg, TR::RealRegister::gr4, TR_GPR, cg);11897TR::addDependency(conditions, arg3Reg, TR::RealRegister::gr5, TR_GPR, cg);11898TR::addDependency(conditions, cndRegister, TR::RealRegister::cr0, TR_CCR, cg);1189911900// used to be blel11901// only need to call snippet once, so using beql instead11902cursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beql, node, snippetLabel, cndRegister);11903generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);1190411905cg->machine()->setLinkRegisterKilled(true);11906conditions->stopUsingDepRegs(cg);11907}11908}1190911910TR::Instruction *loadAddressRAM32(TR::CodeGenerator *cg, TR::Node * node, int32_t value, TR::Register *trgReg)11911{11912// load a 32-bit constant into a register with a fixed 2 instruction sequence11913TR::Compilation *comp = cg->comp();11914TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());1191511916bool isAOT = comp->compileRelocatableCode();1191711918TR::Instruction *cursor = cg->getAppendInstruction();1191911920cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, trgReg, isAOT ? 0 : value>>16, cursor);1192111922if (value != 0x0)11923{11924TR_ExternalRelocationTargetKind reloType;11925if (node->getSymbol()->castToResolvedMethodSymbol()->isSpecial())11926reloType = TR_SpecialRamMethodConst;11927else if (node->getSymbol()->castToResolvedMethodSymbol()->isStatic())11928reloType = TR_StaticRamMethodConst;11929else if (node->getSymbol()->castToResolvedMethodSymbol()->isVirtual())11930reloType = TR_VirtualRamMethodConst;11931else11932{11933reloType = TR_NoRelocation;11934TR_ASSERT(0,"JNI relocation not supported.");11935}11936if(isAOT)11937cg->addExternalRelocation(new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(cursor, (uint8_t *) node->getSymbolReference(),11938node ? (uint8_t *)(intptr_t)node->getInlinedSiteIndex() : (uint8_t *)-1,11939reloType, cg),11940__FILE__, __LINE__, node);11941}1194211943cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : value&0x0000ffff, cursor);1194411945cg->setAppendInstruction(cursor);11946return(cursor);11947}1194811949TR::Instruction *loadAddressRAM(TR::CodeGenerator *cg, TR::Node * node, intptr_t value, TR::Register *trgReg)11950{11951TR::Compilation *comp = cg->comp();11952TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());11953bool isAOT = comp->compileRelocatableCode();11954if (comp->target().is32Bit())11955{11956return loadAddressRAM32(cg, node, (int32_t)value, trgReg);11957}1195811959// load a 64-bit constant into a register with a fixed 5 instruction sequence11960TR::Instruction *cursor = cg->getAppendInstruction();1196111962// lis trgReg, upper 16-bits11963cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, trgReg, isAOT? 0: (value>>48) , cursor);11964if (value != 0x0)11965{11966TR_ExternalRelocationTargetKind reloType;11967if (node->getSymbol()->castToResolvedMethodSymbol()->isSpecial())11968reloType = TR_SpecialRamMethodConst;11969else if (node->getSymbol()->castToResolvedMethodSymbol()->isStatic())11970reloType = TR_StaticRamMethodConst;11971else if (node->getSymbol()->castToResolvedMethodSymbol()->isVirtual())11972reloType = TR_VirtualRamMethodConst;11973else11974{11975reloType = TR_NoRelocation;11976TR_ASSERT(0,"JNI relocation not supported.");11977}11978if(isAOT)11979cg->addExternalRelocation(new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(cursor, (uint8_t *) node->getSymbolReference(),11980node ? (uint8_t *)(intptr_t)node->getInlinedSiteIndex() : (uint8_t *)-1,11981reloType, cg),11982__FILE__,__LINE__, node);11983}11984// ori trgReg, trgReg, next 16-bits11985cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : ((value>>32) & 0x0000ffff), cursor);11986// shiftli trgReg, trgReg, 3211987cursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, trgReg, trgReg, 32, CONSTANT64(0xFFFFFFFF00000000), cursor);11988// oris trgReg, trgReg, next 16-bits11989cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::oris, node, trgReg, trgReg, isAOT ? 0 : ((value>>16) & 0x0000ffff), cursor);11990// ori trgReg, trgReg, last 16-bits11991cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : (value & 0x0000ffff), cursor);1199211993cg->setAppendInstruction(cursor);1199411995return(cursor);11996}1199711998TR::Instruction *loadAddressJNI32(TR::CodeGenerator *cg, TR::Node * node, int32_t value, TR::Register *trgReg)11999{12000// load a 32-bit constant into a register with a fixed 2 instruction sequence12001TR::Compilation *comp = cg->comp();12002TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());1200312004bool isAOT = comp->compileRelocatableCode();1200512006TR::Instruction *cursor = cg->getAppendInstruction();1200712008cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, trgReg, isAOT ? 0 : value>>16, cursor);1200912010if (isAOT && value != 0x0)12011{12012TR_ExternalRelocationTargetKind reloType;12013if (node->getSymbol()->castToResolvedMethodSymbol()->isSpecial())12014reloType = TR_JNISpecialTargetAddress;12015else if (node->getSymbol()->castToResolvedMethodSymbol()->isStatic())12016reloType = TR_JNIStaticTargetAddress;12017else if (node->getSymbol()->castToResolvedMethodSymbol()->isVirtual())12018reloType = TR_JNIVirtualTargetAddress;12019else12020{12021reloType = TR_NoRelocation;12022TR_ASSERT(0,"JNI relocation not supported.");12023}1202412025TR_RelocationRecordInformation *info = new (comp->trHeapMemory()) TR_RelocationRecordInformation();12026info->data1 = 0;12027info->data2 = reinterpret_cast<uintptr_t>(node->getSymbolReference());12028int16_t inlinedSiteIndex = node ? node->getInlinedSiteIndex() : -1;12029info->data3 = static_cast<uintptr_t>(inlinedSiteIndex);1203012031cg->addExternalRelocation(12032new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(12033cursor,12034reinterpret_cast<uint8_t *>(info),12035reloType,12036cg),12037__FILE__, __LINE__, node);12038}1203912040cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : value&0x0000ffff, cursor);1204112042cg->setAppendInstruction(cursor);12043return(cursor);12044}1204512046TR::Instruction *loadAddressJNI(TR::CodeGenerator *cg, TR::Node * node, intptr_t value, TR::Register *trgReg)12047{12048TR::Compilation *comp = cg->comp();12049TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());12050bool isAOT = comp->compileRelocatableCode();12051if (comp->target().is32Bit())12052{12053return loadAddressJNI32(cg, node, (int32_t)value, trgReg);12054}1205512056// load a 64-bit constant into a register with a fixed 5 instruction sequence12057TR::Instruction *cursor = cg->getAppendInstruction();1205812059// lis trgReg, upper 16-bits12060cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, trgReg, isAOT? 0: (value>>48) , cursor);12061if (isAOT && value != 0x0)12062{12063TR_ExternalRelocationTargetKind reloType;12064if (node->getSymbol()->castToResolvedMethodSymbol()->isSpecial())12065reloType = TR_JNISpecialTargetAddress;12066else if (node->getSymbol()->castToResolvedMethodSymbol()->isStatic())12067reloType = TR_JNIStaticTargetAddress;12068else if (node->getSymbol()->castToResolvedMethodSymbol()->isVirtual())12069reloType = TR_JNIVirtualTargetAddress;12070else12071{12072reloType = TR_NoRelocation;12073TR_ASSERT(0,"JNI relocation not supported.");12074}1207512076TR_RelocationRecordInformation *info = new (comp->trHeapMemory()) TR_RelocationRecordInformation();12077info->data1 = 0;12078info->data2 = reinterpret_cast<uintptr_t>(node->getSymbolReference());12079int16_t inlinedSiteIndex = node ? node->getInlinedSiteIndex() : -1;12080info->data3 = static_cast<uintptr_t>(inlinedSiteIndex);1208112082cg->addExternalRelocation(12083new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(12084cursor,12085reinterpret_cast<uint8_t *>(info),12086reloType,12087cg),12088__FILE__, __LINE__, node);12089}12090// ori trgReg, trgReg, next 16-bits12091cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : ((value>>32) & 0x0000ffff), cursor);12092// shiftli trgReg, trgReg, 3212093cursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, trgReg, trgReg, 32, CONSTANT64(0xFFFFFFFF00000000), cursor);12094// oris trgReg, trgReg, next 16-bits12095cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::oris, node, trgReg, trgReg, isAOT ? 0 : ((value>>16) & 0x0000ffff), cursor);12096// ori trgReg, trgReg, last 16-bits12097cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : (value & 0x0000ffff), cursor);1209812099cg->setAppendInstruction(cursor);1210012101return(cursor);12102}1210312104TR::Register *J9::Power::TreeEvaluator::directCallEvaluator(TR::Node *node, TR::CodeGenerator *cg)12105{12106TR::SymbolReference *symRef = node->getSymbolReference();12107TR::MethodSymbol *callee = symRef->getSymbol()->castToMethodSymbol();12108TR::Linkage *linkage;12109TR::Register *returnRegister;1211012111if (callee->getRecognizedMethod() == TR::jdk_incubator_vector_FloatVector_add &&12112node->getOpCodeValue() == TR::vcall) // was vectorized12113{12114TR::Node::recreate(node, TR::vadd);12115return vaddEvaluator(node, cg);12116}12117else if (callee->getRecognizedMethod() == TR::jdk_internal_vm_vector_VectorSupport_binaryOp &&12118node->getOpCodeValue() == TR::vcall) // was vectorized12119{12120// The following code is temporary and can only be enabled for specific opcodes in VectorAPIExpansion.12121// It's an example of how development of vector evaluators can proceed until vector IL opcodes12122// are implemented. Eventually, all recognition of Vector API methods will be removed from this12123// evaluator12124//12125int firstOperandIndex = 5;12126int secondOperandIndex = 6;12127TR::Node *opcodeNode = node->getChild(0);12128TR::Node *dataTypeNode = node->getChild(3);12129TR::Node *numLanesNode = node->getChild(4);12130TR::Node *firstOperandNode = node->getChild(firstOperandIndex);12131TR::Node *secondOperandNode = node->getChild(secondOperandIndex);1213212133TR::DataType dataType = TR_VectorAPIExpansion::getDataTypeFromClassNode(cg->comp(), dataTypeNode);12134bool supported = true;12135if (dataType != TR::Float)12136supported = false;12137if (!opcodeNode->getOpCode().isLoadConst() ||12138opcodeNode->getInt() != TR_VectorAPIExpansion::VECTOR_OP_ADD)12139supported = false;12140if (!numLanesNode->getOpCode().isLoadConst() ||12141numLanesNode->getInt() != 4)12142supported = false;1214312144TR_ASSERT_FATAL_WITH_NODE(node, supported, "Vector API opcode, type, and number of lanes should be supported\n");1214512146// evaluate unused children12147for (int i = 0; i < node->getNumChildren(); i++)12148{12149TR::Node *child = node->getChild(i);12150if (i != firstOperandIndex && i != secondOperandIndex)12151{12152cg->evaluate(child);12153cg->recursivelyDecReferenceCount(child);12154}12155}1215612157node->setChild(0, firstOperandNode);12158node->setChild(1, secondOperandNode);12159node->setNumChildren(2);12160TR::Node::recreate(node, TR::vadd);12161return vaddEvaluator(node, cg);12162}12163else if (callee->getRecognizedMethod() >= TR::FirstVectorMethod &&12164callee->getRecognizedMethod() <= TR::LastVectorMethod &&12165node->getOpCodeValue() == TR::vcall) // was vectorized12166{12167TR_ASSERT_FATAL_WITH_NODE(node, false, "vcall is not supported for this Vector API method yet\n");12168}121691217012171if (!cg->inlineDirectCall(node, returnRegister))12172{12173TR::SymbolReferenceTable *symRefTab = cg->comp()->getSymRefTab();1217412175// Non-helpers supported by code gen. are expected to be inlined12176if (symRefTab->isNonHelper(symRef))12177{12178TR_ASSERT(!cg->supportsNonHelper(symRefTab->getNonHelperSymbol(symRef)),12179"Non-helper %d was not inlined, but was expected to be.\n",12180symRefTab->getNonHelperSymbol(symRef));12181}1218212183linkage = cg->deriveCallingLinkage(node, false);12184returnRegister = linkage->buildDirectDispatch(node);12185}1218612187return returnRegister;12188}121891219012191TR::Register *J9::Power::TreeEvaluator::tstartEvaluator(TR::Node *node, TR::CodeGenerator *cg)12192{12193// tstart12194// - persistentFailNode12195// - transientFailNode12196// - fallThroughNode (next block)12197// - monitorObject12198//fprintf(stderr,"tstart Start\n");12199TR::Node *persistentFailureNode = node->getFirstChild();12200TR::Node *transientFailureNode = node->getSecondChild();12201TR::Node *fallThrough = node->getThirdChild();12202TR::Node *objNode = node->getChild(3);12203TR::Node *GRANode = NULL;12204TR::Compilation *comp = cg->comp();1220512206TR::LabelSymbol *labelPersistentFailure = persistentFailureNode->getBranchDestination()->getNode()->getLabel();12207TR::LabelSymbol *labelTransientFailure = transientFailureNode->getBranchDestination()->getNode()->getLabel();12208TR::LabelSymbol *labelfallThrough = fallThrough->getBranchDestination()->getNode()->getLabel();12209TR::LabelSymbol *startLabel = generateLabelSymbol(cg);12210TR::LabelSymbol *lockwordLabel = generateLabelSymbol(cg);12211TR::LabelSymbol *noTexStatsLabel = generateLabelSymbol(cg);1221212213TR::Register *objReg = cg->evaluate(objNode);12214TR::Register *monReg = cg->allocateRegister();12215TR::Register *cndReg = cg->allocateRegister(TR_CCR);12216TR::Register *tempReg = cg->allocateRegister();12217//TR::Register *temp2Reg = cg->allocateRegister();12218//TR::Register *temp3Reg = cg->allocateRegister();1221912220// Dependency conditions for this evaluator's internal control flow12221TR::RegisterDependencyConditions *conditions = NULL;12222// Dependency conditions for GRA12223TR::RegisterDependencyConditions *fallThroughConditions = NULL;12224TR::RegisterDependencyConditions *persistentConditions = NULL;12225TR::RegisterDependencyConditions *transientConditions = NULL;1222612227conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());1222812229if (fallThrough->getNumChildren() != 0)12230{12231GRANode = fallThrough->getFirstChild();12232cg->evaluate(GRANode);12233fallThroughConditions = generateRegisterDependencyConditions(cg, GRANode, 0);12234cg->decReferenceCount(GRANode);12235}1223612237if (persistentFailureNode->getNumChildren() != 0)12238{12239GRANode = persistentFailureNode->getFirstChild();12240cg->evaluate(GRANode);12241persistentConditions = generateRegisterDependencyConditions(cg, GRANode, 0);12242cg->decReferenceCount(GRANode);12243}1224412245if (transientFailureNode->getNumChildren() != 0)12246{12247GRANode = transientFailureNode->getFirstChild();12248cg->evaluate(GRANode);12249transientConditions = generateRegisterDependencyConditions(cg, GRANode, 0);12250cg->decReferenceCount(GRANode);12251}1225212253uint32_t conditionCursor = conditions->getAddCursorForPre();12254TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);12255conditions->getPreConditions()->getRegisterDependency(conditionCursor)->setExcludeGPR0();12256conditions->getPostConditions()->getRegisterDependency(conditionCursor++)->setExcludeGPR0();12257TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);12258TR::addDependency(conditions, monReg, TR::RealRegister::NoReg, TR_GPR, cg);12259TR::addDependency(conditions, tempReg, TR::RealRegister::NoReg, TR_GPR, cg);1226012261static char * debugTMTLE = feGetEnv("debugTMTLE");1226212263if (debugTMTLE)12264printf ("\nTM: use TM TLE in %s (%s) %p", comp->signature(), comp->getHotnessName(comp->getMethodHotness()), node);1226512266if (debugTMTLE )12267{12268if (persistentConditions)12269{12270generateDepLabelInstruction(cg, TR::InstOpCode::b, node, labelPersistentFailure, persistentConditions);12271}12272else12273{12274generateLabelInstruction(cg, TR::InstOpCode::b, node, labelPersistentFailure);12275}12276}12277else12278{12279generateInstruction(cg, TR::InstOpCode::tbegin_r, node);12280}1228112282generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node,12283lockwordLabel, cndReg);1228412285generateTrg1Instruction(cg, TR::InstOpCode::mftexasru, node, monReg);1228612287// This mask *should* correspond to the TEXASR failure persistent bit (8)12288// NOT the abort bit (31, indicates an explicit abort)12289//loadConstant(cg, node, 0x01000001, tempReg);12290loadConstant(cg, node, 0x01000000, tempReg);12291generateTrg1Src2Instruction(cg, TR::InstOpCode::and_r, node, tempReg, tempReg, monReg);12292if (transientConditions)12293{12294generateDepConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, labelTransientFailure, cndReg, transientConditions);12295}12296else12297{12298generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, labelTransientFailure, cndReg);12299}12300if (persistentConditions)12301{12302generateDepLabelInstruction(cg, TR::InstOpCode::b, node, labelPersistentFailure, persistentConditions);12303}12304else12305{12306generateLabelInstruction(cg, TR::InstOpCode::b, node, labelPersistentFailure);12307}1230812309generateDepLabelInstruction(cg, TR::InstOpCode::label, node, lockwordLabel, conditions);1231012311int32_t lwOffset = cg->fej9()->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node));1231212313if (comp->target().is64Bit() && cg->fej9()->generateCompressedLockWord())12314{12315generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, monReg,12316TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, 4));12317}12318else12319{12320generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, monReg,12321TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, TR::Compiler->om.sizeofReferenceAddress()));12322}1232312324// abort if lock is held12325if (comp->target().is32Bit() || cg->fej9()->generateCompressedLockWord())12326{12327generateSrc1Instruction(cg, TR::InstOpCode::tabortwneqi_r, node, monReg, 0);12328}12329else12330{12331generateSrc1Instruction(cg, TR::InstOpCode::tabortdneqi_r, node, monReg, 0);12332}1233312334TR::TreeTop *BBendTreeTop = cg->getCurrentEvaluationTreeTop()->getNextTreeTop();12335TR::TreeTop *BBstartTreeTop = NULL;12336if (BBendTreeTop)12337BBstartTreeTop = BBendTreeTop->getNextTreeTop();12338TR::TreeTop *fallThruTarget = fallThrough->getBranchDestination();1233912340if (BBstartTreeTop && (fallThruTarget == BBstartTreeTop))12341{12342if (fallThroughConditions)12343generateDepLabelInstruction(cg, TR::InstOpCode::label, node, startLabel, fallThroughConditions);12344else12345generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);12346}12347else12348{12349if (fallThroughConditions)12350generateDepLabelInstruction(cg, TR::InstOpCode::b, node, labelfallThrough, fallThroughConditions);12351else12352generateLabelInstruction(cg, TR::InstOpCode::b, node, labelfallThrough);12353}1235412355cg->stopUsingRegister(monReg);12356cg->stopUsingRegister(cndReg);12357cg->stopUsingRegister(tempReg);1235812359cg->decReferenceCount(objNode);12360cg->decReferenceCount(persistentFailureNode);12361cg->decReferenceCount(transientFailureNode);12362cg->decReferenceCount(fallThrough);1236312364return NULL;12365}1236612367TR::Register *J9::Power::TreeEvaluator::tfinishEvaluator(TR::Node *node, TR::CodeGenerator *cg)12368{12369generateInstruction(cg, TR::InstOpCode::tend_r, node);12370return NULL;12371}1237212373TR::Register *J9::Power::TreeEvaluator::tabortEvaluator(TR::Node *node, TR::CodeGenerator *cg)12374{12375generateInstruction(cg, TR::InstOpCode::tabort_r, node);12376return NULL;12377}1237812379TR::Register *J9::Power::TreeEvaluator::arraycopyEvaluator(TR::Node *node, TR::CodeGenerator *cg)12380{12381#ifdef OMR_GC_CONCURRENT_SCAVENGER12382/*12383* This version of arraycopyEvaluator is designed to handle the special case where read barriers are12384* needed for field loads. At the time of writing, read barriers are used for Concurrent Scavenge GC.12385* If there are no read barriers then the original implementation of arraycopyEvaluator can be used.12386*/12387if (TR::Compiler->om.readBarrierType() == gc_modron_readbar_none ||12388!node->chkNoArrayStoreCheckArrayCopy() ||12389!node->isReferenceArrayCopy() ||12390debug("noArrayCopy")12391)12392{12393return OMR::TreeEvaluatorConnector::arraycopyEvaluator(node, cg);12394}1239512396TR::Compilation *comp = cg->comp();12397TR::Instruction *gcPoint;12398TR::Node *srcObjNode, *dstObjNode, *srcAddrNode, *dstAddrNode, *lengthNode;12399TR::Register *srcObjReg, *dstObjReg, *srcAddrReg, *dstAddrReg, *lengthReg;12400bool stopUsingCopyReg1, stopUsingCopyReg2, stopUsingCopyReg3, stopUsingCopyReg4, stopUsingCopyReg5 = false;1240112402srcObjNode = node->getChild(0);12403dstObjNode = node->getChild(1);12404srcAddrNode = node->getChild(2);12405dstAddrNode = node->getChild(3);12406lengthNode = node->getChild(4);1240712408// These calls evaluate the nodes and give back registers that can be clobbered if needed.12409stopUsingCopyReg1 = TR::TreeEvaluator::stopUsingCopyReg(srcObjNode, srcObjReg, cg);12410stopUsingCopyReg2 = TR::TreeEvaluator::stopUsingCopyReg(dstObjNode, dstObjReg, cg);12411stopUsingCopyReg3 = TR::TreeEvaluator::stopUsingCopyReg(srcAddrNode, srcAddrReg, cg);12412stopUsingCopyReg4 = TR::TreeEvaluator::stopUsingCopyReg(dstAddrNode, dstAddrReg, cg);1241312414lengthReg = cg->evaluate(lengthNode);12415if (!cg->canClobberNodesRegister(lengthNode))12416{12417TR::Register *lenCopyReg = cg->allocateRegister();12418generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, lengthNode, lenCopyReg, lengthReg);12419lengthReg = lenCopyReg;12420stopUsingCopyReg5 = true;12421}1242212423// Inline forward arrayCopy with constant length.12424int64_t len = -1;12425if (node->isForwardArrayCopy() && lengthNode->getOpCode().isLoadConst())12426{12427len = (lengthNode->getType().isInt32() ? lengthNode->getInt() : lengthNode->getLongInt());1242812429// inlineArrayCopy_ICF is not currently capable of handling very long lengths correctly. Under some circumstances,12430// it will generate an li instruction with an out-of-bounds immediate, which triggers an assert in the binary12431// encoder.12432if (len >= 0 && len < MAX_PPC_ARRAYCOPY_INLINE)12433{12434/*12435* This path generates code to perform a runtime check on whether concurrent GC is done moving objects or not.12436* If it isn't, a call to referenceArrayCopy helper should be made.12437* If it is, using the inlined array copy code path is okay.12438*/12439int32_t groups;1244012441// Our hands are tied somewhat due to the potential ReferenceArrayCopy call12442// We can really work with less registers in P10 case. For readability and12443// maintainability, we are simplifying the logic but using more registers.1244412445bool postP10CopyInline = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10) &&12446cg->comp()->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX);1244712448static bool disableLEArrayCopyInline = (feGetEnv("TR_disableLEArrayCopyInline") != NULL);12449bool supportsLEArrayCopyInline = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) &&12450!disableLEArrayCopyInline &&12451comp->target().cpu.isLittleEndian() &&12452comp->target().cpu.hasFPU() &&12453comp->target().is64Bit();1245412455// There are a minimum of 9 dependencies.12456uint8_t numDeps = 9;1245712458if (comp->target().is64Bit())12459{12460groups = len >> 5;12461}12462else12463{12464groups = len >> 4;12465}1246612467TR::Register *condReg = cg->allocateRegister(TR_CCR);1246812469// These registers are used when taking the inlineArrayCopy_ICF path.12470TR::Register *tmp1Reg = cg->allocateRegister(TR_GPR);12471TR::Register *tmp2Reg = NULL;12472TR::Register *tmp3Reg = NULL;12473TR::Register *tmp4Reg = NULL;12474TR::Register *fp1Reg = NULL;12475TR::Register *fp2Reg = NULL;12476TR::Register *fp3Reg = NULL;12477TR::Register *fp4Reg = NULL;1247812479// These registers are used when taking the referenceArrayCopy helper call path.12480TR::Register *r3Reg = cg->allocateRegister();12481TR::Register *metaReg = cg->getMethodMetaDataRegister();1248212483if (postP10CopyInline)12484{12485numDeps += 1;12486fp1Reg = cg->allocateRegister(TR_VSX_VECTOR);12487}12488else12489{12490if (groups != 0)12491{12492numDeps += 3;12493tmp2Reg = cg->allocateRegister(TR_GPR);12494tmp3Reg = cg->allocateRegister(TR_GPR);12495tmp4Reg = cg->allocateRegister(TR_GPR);12496}1249712498if (supportsLEArrayCopyInline)12499{12500numDeps += 4;12501fp1Reg = cg->allocateRegister(TR_FPR);12502fp2Reg = cg->allocateRegister(TR_FPR);12503fp3Reg = cg->allocateRegister(TR_FPR);12504fp4Reg = cg->allocateRegister(TR_FPR);12505}12506}1250712508/*12509* r3-r8 are used to pass parameters to the referenceArrayCopy helper.12510* r11 is used for the tmp1Reg since r11 gets killed by the trampoline and values put into tmp1Reg are not needed after the trampoline.12511*/12512TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numDeps, cg->trMemory());12513deps->addPostCondition(condReg, TR::RealRegister::cr0);12514deps->addPostCondition(metaReg, TR::RealRegister::NoReg);1251512516deps->addPostCondition(r3Reg, TR::RealRegister::gr3);12517deps->addPostCondition(srcObjReg, TR::RealRegister::gr4);12518deps->addPostCondition(dstObjReg, TR::RealRegister::gr5);12519deps->addPostCondition(srcAddrReg, TR::RealRegister::gr6);12520deps->addPostCondition(dstAddrReg, TR::RealRegister::gr7);12521deps->addPostCondition(lengthReg, TR::RealRegister::gr8);1252212523deps->addPostCondition( tmp1Reg, TR::RealRegister::gr11);1252412525if (postP10CopyInline)12526{12527deps->addPostCondition(fp1Reg, TR::RealRegister::NoReg);12528}12529else12530{12531if (groups != 0)12532{12533deps->addPostCondition(tmp2Reg, TR::RealRegister::NoReg);12534deps->addPostCondition(tmp3Reg, TR::RealRegister::NoReg);12535deps->addPostCondition(tmp4Reg, TR::RealRegister::NoReg);12536}1253712538if (supportsLEArrayCopyInline)12539{12540deps->addPostCondition(fp1Reg, TR::RealRegister::NoReg);12541deps->addPostCondition(fp2Reg, TR::RealRegister::NoReg);12542deps->addPostCondition(fp3Reg, TR::RealRegister::NoReg);12543deps->addPostCondition(fp4Reg, TR::RealRegister::NoReg);12544}12545}1254612547TR::LabelSymbol *startLabel = generateLabelSymbol(cg);12548TR::LabelSymbol *helperLabel = generateLabelSymbol(cg);12549TR::LabelSymbol *endLabel = generateLabelSymbol(cg);12550startLabel->setStartInternalControlFlow();12551endLabel->setEndInternalControlFlow();1255212553generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);1255412555// Runtime check for concurrent scavenger.12556generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, tmp1Reg,12557TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, readBarrierRangeCheckTop), TR::Compiler->om.sizeofReferenceAddress()));12558generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::Op_cmpli, node, condReg, tmp1Reg, 0);12559generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, helperLabel, condReg);1256012561// Generate assembly for inlined version of array copy.12562inlineArrayCopy_ICF(node, len, srcAddrReg, dstAddrReg, cg, condReg,12563tmp1Reg, tmp2Reg, tmp3Reg, tmp4Reg,12564fp1Reg, fp2Reg, fp3Reg, fp4Reg);1256512566generateLabelInstruction(cg, TR::InstOpCode::b, node, endLabel);1256712568// Start of referenceArrayCopy helper path.12569generateLabelInstruction(cg, TR::InstOpCode::label, node, helperLabel);1257012571J9::Power::JNILinkage *jniLinkage = (J9::Power::JNILinkage*) cg->getLinkage(TR_J9JNILinkage);12572const TR::PPCLinkageProperties &pp = jniLinkage->getProperties();1257312574int32_t elementSize;12575if (comp->useCompressedPointers())12576elementSize = TR::Compiler->om.sizeofReferenceField();12577else12578elementSize = (int32_t) TR::Compiler->om.sizeofReferenceAddress();1257912580// Sign extend non-64bit Integers on LinuxPPC64 as required by the ABI12581if (comp->target().isLinux() && comp->target().is64Bit())12582{12583generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, lengthReg, lengthReg);12584}1258512586// The C routine expects length measured by slots.12587generateShiftRightLogicalImmediate(cg, node, lengthReg, lengthReg, trailingZeroes(elementSize));1258812589generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r3Reg, metaReg);1259012591TR::RegisterDependencyConditions *helperDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 0, cg->trMemory());12592TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(TR_referenceArrayCopy);1259312594gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), helperDeps, helperSym);12595gcPoint->PPCNeedsGCMap(pp.getPreservedRegisterMapForGC());1259612597generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);1259812599TR::TreeEvaluator::genWrtbarForArrayCopy(node, srcObjReg, dstObjReg, cg);1260012601TR::Register *retRegisters[5];12602int retRegCount = 0;12603cg->decReferenceCount(srcObjNode);12604cg->decReferenceCount(dstObjNode);12605cg->decReferenceCount(srcAddrNode);12606cg->decReferenceCount(dstAddrNode);12607cg->decReferenceCount(lengthNode);1260812609// Don't kill the registers that should not be clobbered12610if (!stopUsingCopyReg1)12611retRegisters[retRegCount++] = srcObjReg;12612if (!stopUsingCopyReg2)12613retRegisters[retRegCount++] = dstObjReg;12614if (!stopUsingCopyReg3)12615retRegisters[retRegCount++] = srcAddrReg;12616if (!stopUsingCopyReg4)12617retRegisters[retRegCount++] = dstAddrReg;12618if (!stopUsingCopyReg5)12619retRegisters[retRegCount++] = lengthReg;1262012621deps->stopUsingDepRegs(cg, retRegCount, retRegisters);12622cg->machine()->setLinkRegisterKilled(true);12623cg->setHasCall();1262412625return NULL;12626}12627}1262812629/*12630* This path also generates code to perform a runtime check on whether concurrent GC is done moving objects or not.12631* If it isn't done, once again a call to referenceArrayCopy helper should be made.12632* If it is done, using the assembly helpers code path is okay.12633*/1263412635TR::Register *condReg = cg->allocateRegister(TR_CCR);1263612637// These registers are used when taking the assembly helpers path12638TR::Register *tmp1Reg = cg->allocateRegister(TR_GPR);12639TR::Register *tmp2Reg = cg->allocateRegister(TR_GPR);12640TR::Register *tmp3Reg = cg->allocateRegister(TR_GPR);12641TR::Register *tmp4Reg = cg->allocateRegister(TR_GPR);12642TR::Register *fp1Reg = NULL;12643TR::Register *fp2Reg = NULL;12644TR::Register *vec0Reg = NULL;12645TR::Register *vec1Reg = NULL;1264612647// These registers are used when taking the referenceArrayCopy helper call path.12648TR::Register *r3Reg = cg->allocateRegister();12649TR::Register *r4Reg = cg->allocateRegister();12650TR::Register *metaReg = cg->getMethodMetaDataRegister();1265112652// This section calculates the number of dependencies needed by the assembly helpers path.12653bool postP10Copy = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10) &&12654cg->comp()->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX);1265512656static bool disableVSXArrayCopy = (feGetEnv("TR_disableVSXArrayCopy") != NULL);12657bool useVSXForCopy = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) &&12658!disableVSXArrayCopy && cg->comp()->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX);1265912660// VSX supercedes FPU. No reason to offering disable option on this.12661// POWER8 potentially micro-coded unaligned integer accesses in LE mode,12662// breaking the guarantee of data atomicity. So, we use floating point12663// accesses instead.12664bool extraLERequirement = cg->comp()->target().cpu.isLittleEndian();1266512666#if defined(DEBUG) || defined(PROD_WITH_ASSUMES)12667static bool verboseArrayCopy = (feGetEnv("TR_verboseArrayCopy") != NULL); //Check which helper is getting used.12668if (verboseArrayCopy)12669fprintf(stderr, "arraycopy [0x%p] isReferenceArrayCopy:[%d] isForwardArrayCopy:[%d] isHalfWordElementArrayCopy:[%d] isWordElementArrayCopy:[%d] %s @ %s\n",12670node,126710,12672node->isForwardArrayCopy(),12673node->isHalfWordElementArrayCopy(),12674node->isWordElementArrayCopy(),12675comp->signature(),12676comp->getHotnessName(comp->getMethodHotness())12677);12678#endif1267912680/*12681* The minimum number of dependencies used by the assembly helpers path is 8.12682* The number of dependencies added by the referenceArrayCopy helper call path is 5.12683*/12684int32_t numDeps = 8 + 5;1268512686if (postP10Copy)12687{12688// Due to the potential ReferenceArrayCopy call, our hands are tied somewhat.12689// Strictly for arrayCopy call, we don't need that many registers at all.1269012691numDeps += 4;12692}12693else if (useVSXForCopy)12694{12695vec0Reg = cg->allocateRegister(TR_VRF);12696vec1Reg = cg->allocateRegister(TR_VRF);12697numDeps += 2;12698if (comp->target().is32Bit())12699{12700numDeps += 1;12701}12702if (extraLERequirement)12703{12704fp1Reg = cg->allocateSinglePrecisionRegister();12705fp2Reg = cg->allocateSinglePrecisionRegister();12706numDeps += 4;12707}12708}12709else if (comp->target().is32Bit())12710{12711numDeps += 1;12712if (comp->target().cpu.hasFPU())12713{12714numDeps += 4;12715}12716}12717else if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))12718{12719numDeps += 4;12720}1272112722TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(numDeps, numDeps, cg->trMemory());1272312724/*12725* Build up the dependency conditions for assembly helper path.12726* Unfortunately, the two different paths have a conflict regarding which real register they want srcAddrReg, dstAddrReg and lengthReg in.12727* Dependencies are set up to favour the fast assembly path. Register moves are used in the slow helper path to move the values to the12728* real registers they are expected to be in.12729*/12730TR::addDependency(deps, condReg, TR::RealRegister::cr0, TR_CCR, cg);1273112732TR::addDependency(deps, lengthReg, TR::RealRegister::gr7, TR_GPR, cg);12733TR::addDependency(deps, srcAddrReg, TR::RealRegister::gr8, TR_GPR, cg);12734TR::addDependency(deps, dstAddrReg, TR::RealRegister::gr9, TR_GPR, cg);1273512736TR::addDependency(deps, tmp1Reg, TR::RealRegister::gr5, TR_GPR, cg);12737TR::addDependency(deps, tmp2Reg, TR::RealRegister::gr6, TR_GPR, cg);12738TR::addDependency(deps, tmp3Reg, TR::RealRegister::gr0, TR_GPR, cg);12739TR::addDependency(deps, tmp4Reg, TR::RealRegister::gr11, TR_GPR, cg); // Trampoline kills gr11.1274012741if (postP10Copy)12742{12743TR::addDependency(deps, NULL, TR::RealRegister::vsr8, TR_VSX_VECTOR, cg);12744TR::addDependency(deps, NULL, TR::RealRegister::vsr9, TR_VSX_VECTOR, cg);12745TR::addDependency(deps, NULL, TR::RealRegister::vsr32, TR_VSX_VECTOR, cg);12746TR::addDependency(deps, NULL, TR::RealRegister::vsr33, TR_VSX_VECTOR, cg);12747}12748else if (useVSXForCopy)12749{12750TR::addDependency(deps, vec0Reg, TR::RealRegister::vr0, TR_VRF, cg);12751TR::addDependency(deps, vec1Reg, TR::RealRegister::vr1, TR_VRF, cg);12752if (comp->target().is32Bit())12753{12754TR::addDependency(deps, NULL, TR::RealRegister::gr10, TR_GPR, cg);12755}12756if (extraLERequirement)12757{12758TR::addDependency(deps, fp1Reg, TR::RealRegister::fp8, TR_FPR, cg);12759TR::addDependency(deps, fp2Reg, TR::RealRegister::fp9, TR_FPR, cg);12760TR::addDependency(deps, NULL, TR::RealRegister::fp10, TR_FPR, cg);12761TR::addDependency(deps, NULL, TR::RealRegister::fp11, TR_FPR, cg);12762}12763}12764else if (comp->target().is32Bit())12765{12766TR::addDependency(deps, NULL, TR::RealRegister::gr10, TR_GPR, cg);12767if (comp->target().cpu.hasFPU())12768{12769TR::addDependency(deps, NULL, TR::RealRegister::fp8, TR_FPR, cg);12770TR::addDependency(deps, NULL, TR::RealRegister::fp9, TR_FPR, cg);12771TR::addDependency(deps, NULL, TR::RealRegister::fp10, TR_FPR, cg);12772TR::addDependency(deps, NULL, TR::RealRegister::fp11, TR_FPR, cg);12773}12774}12775else if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))12776{12777// stfdp arrayCopy used12778TR::addDependency(deps, NULL, TR::RealRegister::fp8, TR_FPR, cg);12779TR::addDependency(deps, NULL, TR::RealRegister::fp9, TR_FPR, cg);12780TR::addDependency(deps, NULL, TR::RealRegister::fp10, TR_FPR, cg);12781TR::addDependency(deps, NULL, TR::RealRegister::fp11, TR_FPR, cg);12782}1278312784// Add dependencies for the referenceArrayCopy helper call path.12785TR::addDependency(deps, r3Reg, TR::RealRegister::gr3, TR_GPR, cg);12786TR::addDependency(deps, r4Reg, TR::RealRegister::gr4, TR_GPR, cg);1278712788TR::addDependency(deps, srcObjReg, TR::RealRegister::NoReg, TR_GPR, cg);12789TR::addDependency(deps, dstObjReg, TR::RealRegister::NoReg, TR_GPR, cg);12790TR::addDependency(deps, metaReg, TR::RealRegister::NoReg, TR_GPR, cg);1279112792TR::LabelSymbol *startLabel = generateLabelSymbol(cg);12793TR::LabelSymbol *helperLabel = generateLabelSymbol(cg);12794TR::LabelSymbol *endLabel = generateLabelSymbol(cg);12795startLabel->setStartInternalControlFlow();12796endLabel->setEndInternalControlFlow();1279712798generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);1279912800// Runtime check for concurrent scavenger.12801generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, tmp1Reg,12802TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, readBarrierRangeCheckTop), TR::Compiler->om.sizeofReferenceAddress()));12803generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::Op_cmpli, node, condReg, tmp1Reg, 0);12804generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, helperLabel, condReg);1280512806// Start of assembly helper path.12807TR_RuntimeHelper helper;1280812809if (node->isForwardArrayCopy())12810{12811if (postP10Copy)12812{12813helper = TR_PPCpostP10ForwardCopy;12814}12815else if (useVSXForCopy)12816{12817helper = TR_PPCforwardQuadWordArrayCopy_vsx;12818}12819else if (node->isWordElementArrayCopy())12820{12821if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))12822helper = TR_PPCforwardWordArrayCopy_dp;12823else12824helper = TR_PPCforwardWordArrayCopy;12825}12826else if (node->isHalfWordElementArrayCopy())12827{12828if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))12829helper = TR_PPCforwardHalfWordArrayCopy_dp;12830else12831helper = TR_PPCforwardHalfWordArrayCopy;12832}12833else12834{12835if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))12836helper = TR_PPCforwardArrayCopy_dp;12837else12838helper = TR_PPCforwardArrayCopy;12839}12840}12841else // We are not sure it is forward or we have to do backward.12842{12843if (postP10Copy)12844{12845helper = TR_PPCpostP10GenericCopy;12846}12847else if (useVSXForCopy)12848{12849helper = TR_PPCquadWordArrayCopy_vsx;12850}12851else if (node->isWordElementArrayCopy())12852{12853if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))12854helper = TR_PPCwordArrayCopy_dp;12855else12856helper = TR_PPCwordArrayCopy;12857}12858else if (node->isHalfWordElementArrayCopy())12859{12860if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))12861helper = TR_PPChalfWordArrayCopy_dp;12862else12863helper = TR_PPChalfWordArrayCopy;12864}12865else12866{12867if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))12868helper = TR_PPCarrayCopy_dp;12869else12870helper = TR_PPCarrayCopy;12871}12872}12873TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(helper, node, deps, cg);1287412875generateLabelInstruction(cg, TR::InstOpCode::b, node, endLabel);1287612877// Start of referenceArrayCopy helper path.12878generateLabelInstruction(cg, TR::InstOpCode::label, node, helperLabel);1287912880J9::Power::JNILinkage *jniLinkage = (J9::Power::JNILinkage*) cg->getLinkage(TR_J9JNILinkage);12881const TR::PPCLinkageProperties &pp = jniLinkage->getProperties();1288212883int32_t elementSize;12884if (comp->useCompressedPointers())12885elementSize = TR::Compiler->om.sizeofReferenceField();12886else12887elementSize = (int32_t) TR::Compiler->om.sizeofReferenceAddress();1288812889// Sign extend non-64bit Integers on LinuxPPC64 as required by the ABI12890if (comp->target().isLinux() && comp->target().is64Bit())12891{12892generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, lengthReg, lengthReg);12893}1289412895// The C routine expects length measured by slots.12896generateShiftRightLogicalImmediate(cg, node, lengthReg, lengthReg, trailingZeroes(elementSize));1289712898/*12899* Parameters are set up here12900* r3 = vmThread12901* r4 = srcObj12902* r5 = dstObj12903* r6 = srcAddr12904* r7 = dstAddr12905* r8 = length12906*12907* CAUTION: Virtual register names are based on their use during the non-helper path so they are misleading after this point.12908* Due to register reuse, pay attention to copying order so that a register is not clobbered too early.12909*/12910generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r3Reg, metaReg);12911generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r4Reg, srcObjReg);12912generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, tmp1Reg, dstObjReg); //tmp1Reg is tied to r5.12913generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, tmp2Reg, srcAddrReg); //tmp2Reg is tied to r6.12914generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, srcAddrReg, lengthReg); //srcAddrReg is tied to r8. Need to copy srcAddrReg first.12915generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, lengthReg, dstAddrReg); //lengthReg is tied to r7. Need to copy lengthReg first.1291612917TR::RegisterDependencyConditions *helperDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 0, cg->trMemory());12918TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(TR_referenceArrayCopy);1291912920gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), helperDeps, helperSym);12921gcPoint->PPCNeedsGCMap(pp.getPreservedRegisterMapForGC());1292212923generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);1292412925TR::TreeEvaluator::genWrtbarForArrayCopy(node, srcObjReg, dstObjReg, cg);1292612927cg->decReferenceCount(srcObjNode);12928cg->decReferenceCount(dstObjNode);12929cg->decReferenceCount(srcAddrNode);12930cg->decReferenceCount(dstAddrNode);12931cg->decReferenceCount(lengthNode);1293212933TR::Register *retRegisters[5];12934int retRegCount = 0;1293512936// Don't kill the registers that should not be clobbered12937if (!stopUsingCopyReg1)12938retRegisters[retRegCount++] = srcObjReg;12939if (!stopUsingCopyReg2)12940retRegisters[retRegCount++] = dstObjReg;12941if (!stopUsingCopyReg3)12942retRegisters[retRegCount++] = srcAddrReg;12943if (!stopUsingCopyReg4)12944retRegisters[retRegCount++] = dstAddrReg;12945if (!stopUsingCopyReg5)12946retRegisters[retRegCount++] = lengthReg;1294712948deps->stopUsingDepRegs(cg, retRegCount, retRegisters);12949cg->machine()->setLinkRegisterKilled(true);12950cg->setHasCall();1295112952return NULL;12953#else /* OMR_GC_CONCURRENT_SCAVENGER */12954return OMR::TreeEvaluatorConnector::arraycopyEvaluator(node, cg);12955#endif /* OMR_GC_CONCURRENT_SCAVENGER */12956}1295712958TR::Register *12959J9::Power::TreeEvaluator::NULLCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)12960{12961return TR::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(node, false, cg);12962}1296312964TR::Register *12965J9::Power::TreeEvaluator::resolveAndNULLCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)12966{12967return TR::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(node, true, cg);12968}1296912970TR::Register *12971J9::Power::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(TR::Node *node, bool needsResolve, TR::CodeGenerator *cg)12972{12973// NOTE:12974// If in the future no code is generated for the null check, just evaluate the12975// child and decrement its use count UNLESS the child is a pass-through node12976// in which case some kind of explicit test or indirect load must be generated12977// to force the null check at this point.1297812979TR::Node *firstChild = node->getFirstChild();12980TR::ILOpCode &opCode = firstChild->getOpCode();12981TR::Node *reference = NULL;12982TR::Compilation *comp = cg->comp();1298312984bool hasCompressedPointers = false;12985if (comp->useCompressedPointers()12986&& firstChild->getOpCodeValue() == TR::l2a)12987{12988hasCompressedPointers = true;12989TR::ILOpCodes loadOp = comp->il.opCodeForIndirectLoad(TR::Int32);12990TR::ILOpCodes rdbarOp = comp->il.opCodeForIndirectReadBarrier(TR::Int32);12991TR::Node *n = firstChild;12992while ((n->getOpCodeValue() != loadOp) && (n->getOpCodeValue() != rdbarOp))12993n = n->getFirstChild();12994reference = n->getFirstChild();12995}12996else12997reference = node->getNullCheckReference();1299812999// TODO - If a resolve check is needed as well, the resolve must be done13000// before the null check, so that exceptions are handled in the correct13001// order.13002//13003///// if (needsResolve)13004///// {13005///// ...13006///// }1300713008TR::Register *trgReg = cg->evaluate(reference);13009TR::Instruction *gcPoint;1301013011gcPoint = TR::TreeEvaluator::generateNullTestInstructions(cg, trgReg, node);1301213013gcPoint->PPCNeedsGCMap(0xFFFFFFFF);1301413015TR::Node *n = NULL;13016if (comp->useCompressedPointers()13017&& reference->getOpCodeValue() == TR::l2a)13018{13019reference->setIsNonNull(true);13020n = reference->getFirstChild();13021TR::ILOpCodes loadOp = comp->il.opCodeForIndirectLoad(TR::Int32);13022TR::ILOpCodes rdbarOp = comp->il.opCodeForIndirectReadBarrier(TR::Int32);13023while ((n->getOpCodeValue() != loadOp) && (n->getOpCodeValue() != rdbarOp))13024{13025n->setIsNonZero(true);13026n = n->getFirstChild();13027}13028n->setIsNonZero(true);13029}1303013031reference->setIsNonNull(true);1303213033cg->evaluate(firstChild);13034cg->decReferenceCount(firstChild);1303513036return NULL;13037}130381303913040