Path: blob/master/runtime/compiler/arm/codegen/J9ARMEvaluator.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2000, 2021 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 <stdint.h>23#include "j9.h"24#include "j9cfg.h"25#include "j9consts.h"26#include "thrdsup.h"27#include "thrtypes.h"28#include "arm/codegen/ARMInstruction.hpp"29#include "arm/codegen/ARMOperand2.hpp"30#include "arm/codegen/J9ARMSnippet.hpp"31#include "codegen/CodeGenerator.hpp"32#include "codegen/CodeGeneratorUtils.hpp"33#include "codegen/GenerateInstructions.hpp"34#include "codegen/Machine.hpp"35#include "codegen/Linkage.hpp"36#include "codegen/Linkage_inlines.hpp"37#include "codegen/Snippet.hpp"38#include "codegen/TreeEvaluator.hpp"39#include "control/Recompilation.hpp"40#include "control/RecompilationInfo.hpp"41#include "env/jittypes.h"42#include "env/CompilerEnv.hpp"43#include "il/Node.hpp"44#include "il/Node_inlines.hpp"45#include "il/TreeTop.hpp"46#include "il/TreeTop_inlines.hpp"47#include "infra/Bit.hpp"48#include "env/VMJ9.h"4950#ifdef J9VM_GC_ALIGN_OBJECTS51#define OBJECT_ALIGNMENT 852#else53#define OBJECT_ALIGNMENT (TR::Compiler->om.sizeofReferenceAddress())54#endif5556static inline TR::Instruction *genNullTest(TR::CodeGenerator *cg,57TR::Node *node,58TR::Register *objectReg,59TR::Register *scratchReg,60TR::Instruction *cursor)61{62TR::Instruction *instr;63uint32_t base, rotate;64if (constantIsImmed8r(NULLVALUE, &base, &rotate))65{66instr = generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, objectReg, base, rotate, cursor);67}68else69{70instr = armLoadConstant(node, NULLVALUE, scratchReg, cg, cursor);71instr = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, objectReg, scratchReg, instr);72}7374return instr;75}767778static TR::Register *nonFixedDependency(TR::CodeGenerator *cg,79TR::RegisterDependencyConditions *conditions,80TR::Register *nonFixedReg,81TR_RegisterKinds kind)82{83if (nonFixedReg == NULL)84nonFixedReg = cg->allocateRegister(kind);8586TR::addDependency(conditions, nonFixedReg, TR::RealRegister::NoReg, kind, cg);87return nonFixedReg;88}8990static int32_t numberOfRegisterCandidate(TR::Node *depNode, TR_RegisterKinds kind)91{92int32_t idx, result = 0;9394for (idx = 0; idx < depNode->getNumChildren(); idx++)95{96TR::Node *child = depNode->getChild(idx);97TR::Register *reg;98/*99* The direct child node has HighGlobalRegisterNumber even if it is PassThrough100* The child of PassThrough node has garbage data for HighGlobalRegisterNumber.101*/102TR_GlobalRegisterNumber highNumber = child->getHighGlobalRegisterNumber();103104if (child->getOpCodeValue() == TR::PassThrough)105child = child->getFirstChild();106reg = child->getRegister();107if (reg != NULL && reg->getKind() == kind)108{109result += 1;110if (kind == TR_GPR && highNumber > -1)111result += 1;112}113}114return (result);115}116117TR::Instruction *OMR::ARM::TreeEvaluator::generateVFTMaskInstruction(TR::CodeGenerator *cg, TR::Node *node, TR::Register *dstReg, TR::Register *srcReg, TR::Instruction *prev)118{119TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());120uintptr_t mask = TR::Compiler->om.maskOfObjectVftField();121122if (~mask == 0)123{124// no mask instruction required125return prev;126}127else128{129return generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::bic, node, dstReg, srcReg, ~mask, 0, prev);130}131}132133TR::Instruction *OMR::ARM::TreeEvaluator::generateVFTMaskInstruction(TR::CodeGenerator *cg, TR::Node *node, TR::Register *reg, TR::Instruction *prev)134{135return generateVFTMaskInstruction(cg, node, reg, reg, prev);136}137138static TR::Instruction *genTestIsSuper(TR::CodeGenerator *cg,139TR::Node *node,140TR::Register *objClassReg,141TR::Register *castClassReg,142TR::Register *scratch1Reg,143TR::Register *scratch2Reg,144int32_t castClassDepth,145TR::LabelSymbol *failLabel,146TR::Instruction *cursor,147TR::LabelSymbol *doneLabel)148{149uint32_t base, rotate;150uint32_t shiftAmount = leadingZeroes(J9AccClassDepthMask);151int32_t superClassOffset = castClassDepth << 2;152bool outOfBound = (superClassOffset > UPPER_IMMED12 || superClassOffset < LOWER_IMMED12);153bool regDepth = !constantIsImmed8r(castClassDepth, &base, &rotate);154155TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objClassReg, offsetof(J9Class, classDepthAndFlags), cg);156cursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, scratch1Reg, tempMR, cursor);157158cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mvn, node, scratch2Reg, 0, 0, cursor);159160TR_ARMOperand2 *operand2 = new (cg->trHeapMemory()) TR_ARMOperand2(ARMOp2RegLSRImmed, scratch2Reg, shiftAmount);161cursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::and_, node, scratch1Reg, scratch1Reg, operand2, cursor);162163if (outOfBound || regDepth)164{165cursor = armLoadConstant(node, castClassDepth, scratch2Reg, cg, cursor);166cursor = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, scratch1Reg, scratch2Reg, cursor);167}168else169{170cursor = generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, scratch1Reg, base, rotate, cursor);171}172173if (failLabel)174{175cursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeLE, failLabel, cursor);176}177else178{179TR::SymbolReference *symRef = node->getSymbolReference();180cursor = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)symRef->getMethodAddress(), NULL, symRef, NULL, NULL, ARMConditionCodeLE);181cursor->ARMNeedsGCMap(0xFFFFFFFF);182cg->machine()->setLinkRegisterKilled(true);183}184185186tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objClassReg, offsetof(J9Class,superclasses), cg);187cursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, scratch1Reg, tempMR, cursor);188189if (outOfBound || regDepth)190{191tempMR = new (cg->trHeapMemory()) TR::MemoryReference(scratch1Reg, scratch2Reg, 4, cg);192cursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, scratch1Reg, tempMR, cursor);193}194else195{196tempMR = new (cg->trHeapMemory()) TR::MemoryReference(scratch1Reg, superClassOffset, cg);197cursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, scratch1Reg, tempMR, cursor);198}199200cursor = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, scratch1Reg, castClassReg, cursor);201return cursor;202}203204205TR::Register *OMR::ARM::TreeEvaluator::VMcheckcastEvaluator(TR::Node *node, TR::CodeGenerator *cg)206{207TR::Node *objNode = node->getFirstChild();208TR::Node *castClassNode = node->getSecondChild();209TR::SymbolReference *castClassSymRef = castClassNode->getSymbolReference();210TR::Compilation *comp = TR::comp();211TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());212213TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(6, 6, cg->trMemory());214215int32_t castClassDepth = -1;216bool testEqualClass = instanceOfOrCheckCastNeedEqualityTest(node, cg);217bool testCastClassIsSuper = instanceOfOrCheckCastNeedSuperTest(node, cg);218TR::StaticSymbol *castClassSym;219TR_OpaqueClassBlock *clazz;220221bool isCheckCastOrNullCheck = (node->getOpCodeValue() == TR::checkcastAndNULLCHK);222223if (testCastClassIsSuper)224{225castClassSym = castClassSymRef->getSymbol()->getStaticSymbol();226clazz = (TR_OpaqueClassBlock *) castClassSym->getStaticAddress();227if (fej9->classHasBeenExtended(clazz) || comp->getMethodHotness() < warm || !comp->isRecompilationEnabled() )228{229castClassDepth = TR::Compiler->cls.classDepthOf(clazz);230}231else232{233testCastClassIsSuper = false;234}235}236237TR::Register *objReg = cg->evaluate(objNode);238TR::Register *castClassReg = cg->evaluate(castClassNode);239TR::Register *objClassReg = cg->allocateRegister();240241TR::addDependency(deps, objReg, TR::RealRegister::gr1, TR_GPR, cg);242TR::addDependency(deps, castClassReg, TR::RealRegister::gr0, TR_GPR, cg);243244cg->machine()->setLinkRegisterKilled(true);245246if (!testEqualClass && !testCastClassIsSuper)247{248TR::SymbolReference *symRef = node->getSymbolReference();249TR::Instruction *gcPoint = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uint32_t)symRef->getMethodAddress(), deps, symRef);250gcPoint->ARMNeedsGCMap(0xFFFFFFFF);251deps->stopAddingConditions();252cg->decReferenceCount(objNode);253cg->decReferenceCount(castClassNode);254return NULL;255}256257TR::LabelSymbol *doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);258259TR::Instruction *gcPoint;260261TR::addDependency(deps, objClassReg, TR::RealRegister::NoReg, TR_GPR, cg);262263TR::Instruction *implicitExceptionPointInstr = NULL;264if (!objNode->isNonNull())265{266if (!isCheckCastOrNullCheck)267{268genNullTest(cg, node, objReg, objClassReg, NULL);269generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel);270}271}272273implicitExceptionPointInstr = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, objClassReg,274new (cg->trHeapMemory()) TR::MemoryReference(objReg, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), cg));275generateVFTMaskInstruction(cg, node, objClassReg);276277TR::SymbolReference *symRef = node->getSymbolReference();278279if (testEqualClass)280{281generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, objClassReg, castClassReg);282if (testCastClassIsSuper)283generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel);284else285{286gcPoint = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)symRef->getMethodAddress(), NULL, symRef, NULL, NULL, ARMConditionCodeNE);287gcPoint->ARMNeedsGCMap(0xFFFFFFFF);288}289}290291if (testCastClassIsSuper)292{293TR::Register *scratch1Reg = cg->allocateRegister();294TR::Register *scratch2Reg = cg->allocateRegister();295TR::addDependency(deps, scratch1Reg, TR::RealRegister::NoReg, TR_GPR, cg);296TR::addDependency(deps, scratch2Reg, TR::RealRegister::NoReg, TR_GPR, cg);297298genTestIsSuper(cg, node, objClassReg, castClassReg, scratch1Reg,299scratch2Reg, castClassDepth, NULL, NULL, doneLabel);300gcPoint = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)symRef->getMethodAddress(), NULL, symRef, NULL, NULL, ARMConditionCodeNE);301gcPoint->ARMNeedsGCMap(0xFFFFFFFF);302}303304if (isCheckCastOrNullCheck &&305implicitExceptionPointInstr &&306!objNode->isNonNull())307{308cg->setImplicitExceptionPoint(implicitExceptionPointInstr);309implicitExceptionPointInstr->setNeedsGCMap();310// find the bytecodeinfo of the311// NULLCHK that was compacted312TR::Node *implicitExceptionPointNode = comp->findNullChkInfo(node);313implicitExceptionPointInstr->setNode(implicitExceptionPointNode);314}315316generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);317deps->stopAddingConditions();318319cg->decReferenceCount(objNode);320cg->decReferenceCount(castClassNode);321return NULL;322}323324325TR::Register *OMR::ARM::TreeEvaluator::VMifInstanceOfEvaluator(TR::Node *node, TR::CodeGenerator *cg)326{327TR::Compilation *comp = TR::comp();328TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());329bool branchOn1 = false;330331TR::Register *resultReg = NULL;332TR::LabelSymbol *doneLabel = NULL;333TR::LabelSymbol *trueLabel = NULL;334TR::LabelSymbol *res0Label = NULL;335TR::LabelSymbol *res1Label = NULL;336337TR::RegisterDependencyConditions *conditions = NULL;338TR::RegisterDependencyConditions *deps = NULL;339340TR::ILOpCodes opCode = node->getOpCodeValue();341TR::Node *instanceOfNode = node->getFirstChild();342TR::Node *valueNode = node->getSecondChild();343TR::Node *depNode = node->getNumChildren() == 3 ? node->getChild(2) : NULL;344TR::Node *objectNode = instanceOfNode->getFirstChild();345TR::Node *castClassNode = instanceOfNode->getSecondChild();346int32_t value = valueNode->getInt();347int32_t numDeps = depNode ? depNode->getNumChildren() : 0;348int32_t castClassDepth = -1;349TR::SymbolReference *castClassSymRef = castClassNode->getSymbolReference();350TR::LabelSymbol *branchLabel = node->getBranchDestination()->getNode()->getLabel();351bool testEqualClass = instanceOfOrCheckCastNeedEqualityTest(instanceOfNode, cg);352bool testCastClassIsSuper = instanceOfOrCheckCastNeedSuperTest(instanceOfNode, cg);353bool isFinalClass = (castClassSymRef == NULL) ? false : castClassSymRef->isNonArrayFinal(comp);354bool needsHelperCall = TR::TreeEvaluator::instanceOfNeedHelperCall(testCastClassIsSuper, isFinalClass);355356// If the result itself is assigned to a global register, we still have to do357// something special...358bool needResult = (instanceOfNode->getReferenceCount() > 1);359360int32_t i;361if (depNode != NULL)362{363if (!needsHelperCall && numberOfRegisterCandidate(depNode, TR_GPR) + 6 > cg->getMaximumNumberOfGPRsAllowedAcrossEdge(node))364return (TR::Register *)1;365366TR::ARMLinkageProperties properties = cg->getLinkage()->getProperties();367for (i = 0; i < depNode->getNumChildren(); i++)368{369TR::Node *childNode = depNode->getChild(i);370int32_t regIndex = cg->getGlobalRegister(depNode->getChild(i)->getGlobalRegisterNumber());371int32_t highIndex = childNode->getHighGlobalRegisterNumber();372373if (needsHelperCall)374{375if (highIndex > -1)376highIndex = cg->getGlobalRegister(highIndex);377if (!properties.getPreserved((TR::RealRegister::RegNum) regIndex) || (highIndex > -1 && !properties.getPreserved((TR::RealRegister::RegNum) highIndex)))378return (TR::Register *)1;379}380else381{382// Below check code taken from PPC.383if (childNode->getOpCodeValue() == TR::PassThrough)384childNode = childNode->getFirstChild();385if ((childNode == instanceOfNode || childNode == castClassNode) && regIndex == TR::RealRegister::gr0)386return ((TR::Register *) 1);387}388}389}390391if (testEqualClass || testCastClassIsSuper)392{393doneLabel = generateLabelSymbol(cg);394}395396if ((opCode == TR::ificmpeq && value == 1) ||397(opCode != TR::ificmpeq && value == 0))398{399res0Label = doneLabel;400res1Label = branchLabel;401branchOn1 = true;402}403else404{405res0Label = branchLabel;406res1Label = doneLabel;407branchOn1 = false;408}409410TR::Register *objectReg;411TR::Register *objClassReg;412TR::Register *castClassReg;413TR::Register *scratch1Reg;414TR::Register *scratch2Reg;415TR::Instruction *iCursor;416417if (needsHelperCall)418{419TR::ILOpCodes childOpCode = instanceOfNode->getOpCodeValue();420421TR::Node::recreate(instanceOfNode, TR::icall);422directCallEvaluator(instanceOfNode, cg);423TR::Node::recreate(instanceOfNode, childOpCode);424425iCursor = cg->getAppendInstruction();426while (iCursor->getOpCodeValue() != TR::InstOpCode::bl)427iCursor = iCursor->getPrev();428conditions = iCursor->getDependencyConditions();429iCursor = iCursor->getPrev();430objectReg= conditions->searchPreConditionRegister(TR::RealRegister::gr1);431castClassReg = conditions->searchPreConditionRegister(TR::RealRegister::gr0);432scratch1Reg = conditions->searchPreConditionRegister(TR::RealRegister::gr2);433scratch2Reg = conditions->searchPreConditionRegister(TR::RealRegister::gr3);434objClassReg = conditions->searchPreConditionRegister(TR::RealRegister::gr4);435436if (depNode !=NULL)437{438cg->evaluate(depNode);439deps = generateRegisterDependencyConditions(cg, depNode, 0, &iCursor);440}441442if (testEqualClass || testCastClassIsSuper)443{444if (needResult)445{446resultReg = conditions->searchPreConditionRegister(TR::RealRegister::gr5);447iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 0, 0, iCursor);448}449if (!objectNode->isNonNull())450{451iCursor = genNullTest(cg, objectNode, objectReg, scratch1Reg, iCursor);452iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res0Label, iCursor);453}454}455}456else457{458bool earlyEval = (castClassNode->getOpCodeValue() != TR::loadaddr ||459castClassNode->getReferenceCount() > 1)?true:false;460bool objInDep = false, castClassInDep = false;461if (depNode != NULL)462{463cg->evaluate(depNode);464deps = generateRegisterDependencyConditions(cg, depNode, 6);465for (i = 0; i < numDeps; i++)466{467TR::Node *grNode = depNode->getChild(i);468if (grNode->getOpCodeValue() == TR::PassThrough)469grNode = grNode->getFirstChild();470if (grNode == objectNode)471objInDep = true;472if (grNode == castClassNode)473castClassInDep = true;474}475}476if (deps == NULL)477{478conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(6, 6, cg->trMemory());479}480else481{482conditions = deps;483}484485if (needResult)486{487resultReg = nonFixedDependency(cg, conditions, NULL, TR_GPR);488}489490objClassReg = nonFixedDependency(cg, conditions, NULL, TR_GPR);491492objectReg = cg->evaluate(objectNode);493if (!objInDep)494objectReg = nonFixedDependency(cg, conditions, objectReg, TR_GPR);495496if (earlyEval)497{498castClassReg = cg->evaluate(castClassNode);499if (!castClassInDep)500castClassReg = nonFixedDependency(cg, conditions, castClassReg, TR_GPR);501}502503if (needResult)504{505generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 0, 0);506}507508if (!objectNode->isNonNull())509{510genNullTest(cg, objectNode, objectReg, objClassReg, NULL);511generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res0Label);512}513514if (!earlyEval)515{516castClassReg = cg->evaluate(castClassNode);517if (!castClassInDep)518castClassReg = nonFixedDependency(cg, conditions, castClassReg, TR_GPR);519}520521if (testCastClassIsSuper)522{523scratch1Reg = nonFixedDependency(cg, conditions, NULL, TR_GPR);524scratch2Reg = nonFixedDependency(cg, conditions, NULL, TR_GPR);525cg->stopUsingRegister(scratch1Reg);526cg->stopUsingRegister(scratch2Reg);527}528529iCursor = cg->getAppendInstruction();530generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);531conditions->stopAddingConditions();532cg->decReferenceCount(objectNode);533cg->decReferenceCount(castClassNode);534}535536if (testEqualClass || testCastClassIsSuper)537{538TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objectReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), cg);539iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, objClassReg, tempMR, iCursor);540iCursor = generateVFTMaskInstruction(cg, node, objClassReg, iCursor);541}542543if (testEqualClass)544{545iCursor = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, objClassReg, castClassReg, iCursor);546547if (testCastClassIsSuper)548{549if (needResult)550{551trueLabel = generateLabelSymbol(cg);552iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, trueLabel, iCursor);553}554else555{556iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res1Label, iCursor);557}558}559else if (needsHelperCall)560{561if (needResult)562{563iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);564}565iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res1Label, iCursor);566}567else568{569if (needResult)570{571iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);572iCursor->setConditionCode(ARMConditionCodeEQ);573}574575if (branchOn1)576{577iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res1Label, iCursor);578}579else580{581iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, res0Label, iCursor);582}583}584}585586if (testCastClassIsSuper)587{588TR::StaticSymbol *castClassSym;589590castClassSym = castClassSymRef->getSymbol()->getStaticSymbol();591void * clazz = castClassSym->getStaticAddress();592castClassDepth = TR::Compiler->cls.classDepthOf((TR_OpaqueClassBlock *) clazz);593594iCursor = genTestIsSuper(cg, node, objClassReg, castClassReg, scratch1Reg, scratch2Reg, castClassDepth, res0Label, iCursor, NULL);595iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, res0Label, iCursor);596if (trueLabel == NULL)597{598if (needResult)599{600iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);601}602}603else604{605iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, trueLabel, iCursor);606iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);607}608609if (branchOn1)610{611iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, res1Label, iCursor);612}613}614615if (needsHelperCall)616{617TR::Register *callResult = instanceOfNode->getRegister();618TR::RegisterDependencyConditions *newDeps;619620if (resultReg == NULL)621{622resultReg = callResult;623}624else625{626generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, resultReg, callResult);627}628629generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, resultReg, 0, 0);630631if (depNode != NULL)632{633newDeps = conditions->cloneAndFix(cg, deps);634}635else636{637newDeps = conditions->cloneAndFix(cg);638}639640if (branchOn1)641{642if (doneLabel == NULL)643generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, res1Label, newDeps);644else645generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, res1Label);646}647else648{649if (doneLabel == NULL)650generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res0Label, newDeps);651else652generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res0Label);653}654655if (doneLabel != NULL)656{657generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, newDeps);658newDeps->stopAddingConditions();659}660661#if 0 // TODO:PPC has this fixup. It maybe a fix to something so keeping here as note. See J9PPCEvaluator.cpp for reviveResultRegister() imple.662// We have to revive the resultReg here. Should revisit to see how to use registers better663// (e.g., reducing the chance of moving around).664if (resultReg != callResult)665reviveResultRegister(resultReg, callResult, cg);666#endif667}668669if (resultReg != instanceOfNode->getRegister())670instanceOfNode->setRegister(resultReg);671cg->decReferenceCount(instanceOfNode);672cg->decReferenceCount(valueNode);673if (depNode != NULL)674cg->decReferenceCount(depNode);675node->setRegister(NULL);676return NULL;677}678679680TR::Register *OMR::ARM::TreeEvaluator::VMinstanceOfEvaluator(TR::Node *node, TR::CodeGenerator *cg)681{682TR::Compilation *comp = TR::comp();683TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());684TR::Register *objectReg, *castClassReg, *objClassReg;685TR::Register *resultReg, *scratch1Reg, *scratch2Reg;686TR::Instruction *iCursor;687TR::RegisterDependencyConditions *conditions;688TR::LabelSymbol *doneLabel, *trueLabel;689TR::Node *objectNode, *castClassNode;690int32_t castClassDepth = -1;691692trueLabel = doneLabel = NULL;693resultReg = NULL;694objectNode = node->getFirstChild();695castClassNode = node->getSecondChild();696TR::SymbolReference * castClassSymRef = castClassNode->getSymbolReference();697bool testEqualClass = instanceOfOrCheckCastNeedEqualityTest(node, cg);698bool testCastClassIsSuper = instanceOfOrCheckCastNeedSuperTest(node, cg);699bool isFinalClass = (castClassSymRef == NULL) ? false : castClassSymRef->isNonArrayFinal(comp);700bool needsHelperCall = TR::TreeEvaluator::instanceOfNeedHelperCall(testCastClassIsSuper, isFinalClass);701702if (needsHelperCall)703{704TR::ILOpCodes opCode = node->getOpCodeValue();705706TR::Node::recreate(node, TR::icall);707directCallEvaluator(node, cg);708TR::Node::recreate(node, opCode);709710iCursor = cg->getAppendInstruction();711while (iCursor->getOpCodeValue() != TR::InstOpCode::bl)712iCursor = iCursor->getPrev();713conditions = iCursor->getDependencyConditions();714iCursor = iCursor->getPrev();715objectReg= conditions->searchPreConditionRegister(716TR::RealRegister::gr1);717castClassReg = conditions->searchPreConditionRegister(718TR::RealRegister::gr0);719scratch1Reg = conditions->searchPreConditionRegister(720TR::RealRegister::gr2);721scratch2Reg = conditions->searchPreConditionRegister(722TR::RealRegister::gr3);723objClassReg = conditions->searchPreConditionRegister(724TR::RealRegister::gr4);725726if (testEqualClass || testCastClassIsSuper)727{728doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);729730resultReg = conditions->searchPreConditionRegister(731TR::RealRegister::gr5);732733iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 0, 0, iCursor);734if (!objectNode->isNonNull())735{736iCursor = genNullTest(cg, objectNode, objectReg, scratch1Reg, iCursor);737iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel, iCursor);738}739}740}741else742{743bool earlyEval = (castClassNode->getOpCodeValue() != TR::loadaddr ||744castClassNode->getReferenceCount() > 1)?true:false;745746conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(6, 6, cg->trMemory());747748resultReg = nonFixedDependency(cg, conditions, NULL, TR_GPR);749objClassReg = nonFixedDependency(cg, conditions, NULL, TR_GPR);750751objectReg = cg->evaluate(objectNode);752objectReg = nonFixedDependency(cg, conditions, objectReg, TR_GPR);753if (earlyEval)754{755castClassReg = cg->evaluate(castClassNode);756castClassReg = nonFixedDependency(cg, conditions, castClassReg, TR_GPR);757}758759doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);760generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 0, 0);761if (!objectNode->isNonNull())762{763genNullTest(cg, objectNode, objectReg, objClassReg, NULL);764generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel);765}766767if (!earlyEval)768{769castClassReg = cg->evaluate(castClassNode);770castClassReg = nonFixedDependency(cg, conditions, castClassReg, TR_GPR);771}772773if (testCastClassIsSuper)774{775scratch1Reg = nonFixedDependency(cg, conditions, NULL, TR_GPR);776scratch2Reg = nonFixedDependency(cg, conditions, NULL, TR_GPR);777}778779iCursor = cg->getAppendInstruction();780generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);781cg->decReferenceCount(objectNode);782cg->decReferenceCount(castClassNode);783}784785if (testEqualClass || testCastClassIsSuper)786{787TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objectReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), cg);788iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, objClassReg, tempMR, iCursor);789iCursor = generateVFTMaskInstruction(cg, node, objClassReg, iCursor);790}791792if (testEqualClass)793{794iCursor = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, objClassReg, castClassReg, iCursor);795796if (testCastClassIsSuper)797{798trueLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);799iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, trueLabel, iCursor);800}801else if (needsHelperCall)802{803iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);804iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel, iCursor);805}806else807{808iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);809iCursor->setConditionCode(ARMConditionCodeEQ);810}811}812813if (testCastClassIsSuper)814{815TR::StaticSymbol *castClassSym;816817castClassSym = castClassSymRef->getSymbol()->getStaticSymbol();818void * clazz = castClassSym->getStaticAddress();819castClassDepth = TR::Compiler->cls.classDepthOf((TR_OpaqueClassBlock *) clazz);820821iCursor = genTestIsSuper(cg, node, objClassReg, castClassReg, scratch1Reg, scratch2Reg, castClassDepth, doneLabel, iCursor, NULL);822823// needHelperCall must be false, and the only consumer of "trueLabel" is a branch instruction824// with the exact same condition as required below. We can take advantage of this situation.825826if (trueLabel != NULL)827{828iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, trueLabel, iCursor);829}830iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);831iCursor->setConditionCode(ARMConditionCodeEQ);832}833834if (needsHelperCall)835{836TR::Register *callResult = node->getRegister();837if (resultReg == NULL)838{839resultReg = callResult;840}841else842{843generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, resultReg, callResult);844generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions->cloneAndFix(cg));845}846}847if (resultReg != node->getRegister())848node->setRegister(resultReg);849return resultReg;850}851852853TR::Register *OMR::ARM::TreeEvaluator::VMmonexitEvaluator(TR::Node *node, TR::CodeGenerator *cg)854{855TR::Compilation *comp = TR::comp();856TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());857int32_t lwOffset = fej9->getByteOffsetToLockword(cg->getMonClass(node));858859if ((comp->getOption(TR_FullSpeedDebug) /*&& !comp->getOption(TR_EnableLiveMonitorMetadata)*/) ||860comp->getOption(TR_DisableInlineMonExit) ||861lwOffset <= 0)862{863TR::ILOpCodes opCode = node->getOpCodeValue();864TR::Node::recreate(node, TR::call);865TR::Register *targetRegister = directCallEvaluator(node, cg);866TR::Node::recreate(node, opCode);867return targetRegister;868}869870TR::Node *objNode = node->getFirstChild();871TR::Register *objReg = cg->evaluate(objNode);872TR::Register *monitorReg = cg->allocateRegister();873TR::Register *flagReg = cg->allocateRegister();874TR::Register *metaReg = cg->getMethodMetaDataRegister();875876TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(3, 3, cg->trMemory());877TR::addDependency(deps, objReg, TR::RealRegister::gr0, TR_GPR, cg);878TR::addDependency(deps, monitorReg, TR::RealRegister::NoReg, TR_GPR, cg);879TR::addDependency(deps, flagReg, TR::RealRegister::NoReg, TR_GPR, cg);880881TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objReg, lwOffset, cg);882generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, monitorReg, tempMR);883generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, monitorReg, metaReg);884885TR::Instruction *instr = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, flagReg, 0, 0);886instr->setConditionCode(ARMConditionCodeEQ);887888if (cg->comp()->target().isSMP() && cg->comp()->target().cpu.id() != TR_DefaultARMProcessor)889{890//instr = generateInstruction(cg, (cg->comp()->target().cpu.id() == TR_ARMv6) ? TR::InstOpCode::dmb_v6 : TR::InstOpCode::dmb, node);891instr = generateInstruction(cg, TR::InstOpCode::dmb_v6 , node); // v7 version is unconditional892instr->setConditionCode(ARMConditionCodeEQ);893}894895tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objReg, lwOffset, cg);896instr = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, flagReg);897instr->setConditionCode(ARMConditionCodeEQ);898899// Branch to decLabel in snippet first900TR::LabelSymbol *decLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);901TR::LabelSymbol *callLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);902TR::LabelSymbol *doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);903TR::Snippet *snippet = new (cg->trHeapMemory()) TR::ARMMonitorExitSnippet(cg, node, lwOffset, decLabel, callLabel, doneLabel);904905generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, decLabel);906907generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);908cg->addSnippet(snippet);909doneLabel->setEndInternalControlFlow();910911cg->decReferenceCount(objNode);912return NULL;913}914915916static void genHeapAlloc(TR::CodeGenerator *cg,917TR::Node *node,918TR::Instruction * &iCursor,919bool isVariableLen,920TR::Register *enumReg,921TR::Register *resReg,922TR::Register *zeroReg,923TR::Register *dataSizeReg,924TR::Register *heapTopReg,925TR::Register *sizeReg,926TR::LabelSymbol *callLabel,927int32_t allocSize)928{929if (cg->comp()->getOptions()->realTimeGC())930{931TR_ASSERT(0, "genHeapAlloc() not supported for RT");932return;933}934935TR::Register *metaReg = cg->getMethodMetaDataRegister();936uint32_t base, rotate;937bool sizeInReg = (isVariableLen || !constantIsImmed8r(allocSize, &base, &rotate));938939TR::ILOpCodes opCode = node->getOpCodeValue();940bool isArrayAlloc = (opCode == TR::newarray || opCode == TR::anewarray);941942if (isVariableLen)943{944// This is coming from the cg setting: less than 0x10000000 will not wrap around945iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::and_r, node, zeroReg, enumReg, 0x000000FF, 24, iCursor);946iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, callLabel, iCursor);947948if (isArrayAlloc)949{950// Zero length arrays are discontiguous951iCursor = generateSrc2Instruction(cg, TR::InstOpCode::tst, node, enumReg, enumReg, iCursor);952iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, callLabel, iCursor);953}954}955956TR::MemoryReference *tempMR;957tempMR = new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapAlloc), cg);958iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, resReg, tempMR, iCursor);959//tempMR = new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapTop), cg);960//iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, heapTopReg, tempMR, iCursor);961962if (sizeInReg)963{964if (isVariableLen)965{966int32_t elementSize = TR::Compiler->om.getSizeOfArrayElement(node);967int32_t round = (elementSize >= OBJECT_ALIGNMENT) ? 0 : OBJECT_ALIGNMENT; // zero indicates no rounding is necessary968bool headerAligned = allocSize % OBJECT_ALIGNMENT ? 0 : 1;969970if (elementSize >= 4)971{972TR_ARMOperand2 *operand2 = new (cg->trHeapMemory()) TR_ARMOperand2(ARMOp2RegLSLImmed, enumReg, trailingZeroes(elementSize));973iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, dataSizeReg, operand2, iCursor);974}975else976{977// Round the data area to a multiple of 4978iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, dataSizeReg, enumReg, 3, 0, iCursor);979if (elementSize == 2)980{981iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, dataSizeReg, dataSizeReg, enumReg, iCursor);982}983iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::bic, node, dataSizeReg, dataSizeReg, 3, 0, iCursor);984}985if ((round != 0 && round != 4) || !headerAligned)986{987iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, sizeReg, dataSizeReg, allocSize+round-1, 0, iCursor);988iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::bic, node, sizeReg, sizeReg, round-1, 0, iCursor);989}990else991iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, sizeReg, dataSizeReg, allocSize, 0, iCursor);992}993else994iCursor = armLoadConstant(node, allocSize, sizeReg, cg, iCursor);995}996997// Borrowing heapTopReg998tempMR = new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapTop), cg);999iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, heapTopReg, tempMR, iCursor);10001001// Calculate the after-allocation heapAlloc: if the size is huge,1002// we need to check address wrap-around also. This is unsigned1003// integer arithmetic, checking carry bit is enough to detect it.1004// For variable length array, we did an up-front check already.10051006if (allocSize > cg->getMaxObjectSizeGuaranteedNotToOverflow())1007{1008if (sizeInReg)1009{1010iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add_r, node, sizeReg, resReg, sizeReg, iCursor);1011}1012else1013{1014iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add_r, node, sizeReg, resReg, base, rotate, iCursor);1015}1016iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeCS, callLabel, iCursor);1017}1018else1019{1020if (sizeInReg)1021{1022iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, sizeReg, resReg, sizeReg, iCursor);1023}1024else1025{1026iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, sizeReg, resReg, base, rotate, iCursor);1027}1028}10291030iCursor = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, sizeReg, heapTopReg, iCursor);1031iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeHI, callLabel, iCursor);1032tempMR = new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapAlloc), cg);1033iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, sizeReg, iCursor);1034iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, zeroReg, 0, 0, iCursor);1035}103610371038static void genInitObjectHeader(TR::CodeGenerator *cg,1039TR::Node *node,1040TR::Instruction * &iCursor,1041J9Class *clazz,1042TR::Register *classReg,1043TR::Register *resReg,1044TR::Register *zeroReg,1045TR::Register *temp1Reg,1046TR::Register *temp2Reg)1047{1048TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());1049uint32_t staticFlag = clazz->romClass->instanceShape;1050TR::Register *metaReg = cg->getMethodMetaDataRegister();1051TR::MemoryReference *tempMR;10521053// Store the class1054if (classReg == NULL)1055{1056iCursor = armLoadConstant(node, (int32_t)clazz, temp1Reg, cg, iCursor);10571058tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), cg);1059iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp1Reg, iCursor);1060}1061else1062{1063tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), cg);1064iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, classReg, iCursor);1065}10661067// If the object flags cannot be determined at compile time, we have to add a load1068// for it. And then, OR it with temp1Reg.1069// todo: if MODRON_GC is used, staticFlag could be obtained dynamically, and using isStaticObjectFlags and1070// getStaticObjectFlags interfaces10711072#ifndef J9VM_INTERP_FLAGS_IN_CLASS_SLOT1073bool isStaticFlag = fej9->isStaticObjectFlags();10741075#if defined(J9VM_OPT_NEW_OBJECT_HASH)1076// TODO: need to handle the !isStaticFlag case as mentioned above.1077// TODO: only one temp register is needed. Fix later1078if (isStaticFlag != 0)1079{1080staticFlag |= fej9->getStaticObjectFlags();1081iCursor = armLoadConstant(node, staticFlag, temp1Reg, cg, iCursor);1082}1083#else10841085// Calculate: (resReg << 14) & 0x7FFF00001086// I can only think of 4 instructions sequence which takes advantage of the fact1087// that resReg itself is at least dword-aligned. Need to revisit whether there is1088// better sequence.1089iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, temp1Reg, 2, 16, iCursor);1090iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sub, node, temp1Reg, temp1Reg, 1, 0, iCursor);1091iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::and_, node, temp1Reg, resReg, temp1Reg, iCursor);1092iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, temp1Reg,1093new (cg->trHeapMemory()) TR_ARMOperand2(ARMOp2RegLSLImmed, temp1Reg, 14), iCursor);10941095if (isStaticFlag != 0)1096{1097staticFlag |= fej9->getStaticObjectFlags();1098uint32_t val1, val2;1099if (constantIsImmed8r(staticFlag, &val1, &val2))1100{1101iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::orr, node, temp1Reg, temp1Reg, val1, val2, iCursor);1102}1103else1104{1105iCursor = armLoadConstant(node, staticFlag, temp2Reg, cg, iCursor);1106iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::orr, node, temp1Reg, temp1Reg, temp2Reg, iCursor);1107}1108}1109#endif /* J9VM_OPT_NEW_OBJECT_HASH */11101111// Store the flags1112tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t)TR::Compiler->om.offsetOfHeaderFlags(), cg);1113iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp1Reg, iCursor);1114#endif /* J9VM_INTERP_FLAGS_IN_CLASS_SLOT */1115}111611171118static void genAlignDoubleArray(TR::CodeGenerator *cg,1119TR::Node *node,1120TR::Instruction *&iCursor,1121bool isVariableLen,1122TR::Register *resReg,1123int32_t objectSize,1124int32_t dataBegin,1125TR::Register *dataSizeReg,1126TR::Register *temp1Reg,1127TR::Register *temp2Reg)1128{1129TR::LabelSymbol *slotAtStart = TR::LabelSymbol::create(cg->trHeapMemory(),cg);1130TR::LabelSymbol *doneAlign = TR::LabelSymbol::create(cg->trHeapMemory(),cg);11311132iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::and_r, node, temp1Reg, resReg, 7, 0, iCursor);1133iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, temp2Reg, 3, 0, iCursor);1134iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, slotAtStart, iCursor);11351136// Should be able to have branch-less sequence here ... but we need to change armLoadConstant for that.1137// TODO: consider this for the future.11381139// The slop bytes are at the end of the allocated object.1140TR::MemoryReference *tempMR;1141if (isVariableLen)1142{1143tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp1Reg, dataBegin, cg);1144iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, resReg, dataSizeReg, iCursor);1145iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp2Reg, iCursor);1146}1147else if (objectSize > UPPER_IMMED12)1148{1149tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, temp1Reg, cg);1150iCursor = armLoadConstant(node, objectSize, temp1Reg, cg, iCursor);1151iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp2Reg, iCursor);1152}1153else1154{1155tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, objectSize, cg);1156iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp2Reg, iCursor);1157}1158iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, doneAlign, iCursor);11591160// the slop bytes are at the start of the allocation1161tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t)0, cg);1162iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, slotAtStart, iCursor);1163iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp2Reg, iCursor);1164iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, resReg, resReg, 4, 0, iCursor);1165iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, doneAlign, iCursor);1166}116711681169static void genInitArrayHeader(TR::CodeGenerator *cg,1170TR::Node *node,1171TR::Instruction *&iCursor,1172bool isVariableLen,1173J9Class *clazz,1174TR::Register *resReg,1175TR::Register *zeroReg,1176TR::Register *eNumReg,1177TR::Register *dataSizeReg,1178TR::Register *temp1Reg,1179TR::Register *temp2Reg)1180{1181TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());1182int32_t elementSize = TR::Compiler->om.getSizeOfArrayElement(node);1183TR::Register *instanceSizeReg;11841185genInitObjectHeader(cg, node, iCursor, clazz, NULL, resReg, zeroReg, temp1Reg, temp2Reg);11861187instanceSizeReg = eNumReg;11881189// Store the array size1190TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t)(fej9->getOffsetOfContiguousArraySizeField()), cg);1191iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, instanceSizeReg, iCursor);1192}119311941195TR::Register *OMR::ARM::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeGenerator *cg)1196{1197TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());1198int32_t dataBegin, idx;1199J9Class *clazz;1200TR::Register *callResult;1201TR::LabelSymbol *callLabel, *doneLabel;1202TR::RegisterDependencyConditions *deps;1203TR::Instruction *iCursor = NULL;1204bool isArray = false, isDoubleArray = false;1205TR::Compilation *comp = TR::comp();12061207// AOT does not support inline allocates - cannot currently guarantee totalInstanceSize12081209// If the helper symbol set on the node is TR_newValue, we are (expecting to be)1210// dealing with a value type. Since we do not fully support value types yet, always1211// call the JIT helper to do the allocation.12121213TR::ILOpCodes opCode = node->getOpCodeValue();1214int32_t objectSize = cg->comp()->canAllocateInlineOnStack(node, (TR_OpaqueClassBlock *&) clazz);1215bool isVariableLen = (objectSize == 0);1216if (objectSize < 0 || comp->compileRelocatableCode() || comp->suppressAllocationInlining() ||1217TR::TreeEvaluator::requireHelperCallValueTypeAllocation(node, cg))1218{1219TR::Node::recreate(node, TR::acall);1220callResult = directCallEvaluator(node, cg);1221TR::Node::recreate(node, opCode);1222return callResult;1223}12241225TR::Register *enumReg;1226TR::Register *classReg;1227int32_t allocateSize = objectSize;1228callLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);1229doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);1230deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(10, 10, cg->trMemory());12311232TR::Node *firstChild = node->getFirstChild();1233TR::Node *secondChild = NULL;12341235if (opCode == TR::New)1236{1237classReg = cg->evaluate(firstChild);1238if (firstChild->getReferenceCount() > 1)1239{1240TR::Register *copyReg = cg->allocateRegister();1241iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, copyReg, classReg, iCursor);1242classReg = copyReg;1243}1244dataBegin = TR::Compiler->om.objectHeaderSizeInBytes();1245}1246else1247{1248isArray = true;1249dataBegin = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();1250secondChild = node->getSecondChild();1251#ifndef J9VM_GC_ALIGN_OBJECTS1252if (opCode == TR::newarray)1253{1254if (secondChild->getInt() == 7 || secondChild->getInt() == 11)1255{1256// To ensure 8-byte alignment on the array, we need 4-byte slop.1257allocateSize += 4;1258isDoubleArray = true;1259}1260}1261else1262{1263TR_ASSERT(opCode == TR::anewarray, "Bad opCode for VMnewEvaluator");1264}1265#endif1266// Potential helper call requires us to evaluate the arguments always.1267// For TR::newarray, classReg refers to the primitive type, not a class.1268enumReg = cg->evaluate(firstChild);1269classReg = cg->evaluate(secondChild);1270if (secondChild->getReferenceCount() > 1)1271{1272TR::Register *copyReg = cg->allocateRegister();1273iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, copyReg, classReg, iCursor);1274classReg = copyReg;1275}1276}12771278TR::addDependency(deps, classReg, TR::RealRegister::NoReg, TR_GPR, cg);1279if (secondChild == NULL)1280enumReg = cg->allocateRegister();1281TR::addDependency(deps, enumReg, TR::RealRegister::NoReg, TR_GPR, cg);12821283// We have two paths through this code, each of which calls a different helper:1284// one calls jitNewObject, the other performs a write barrier (when multimidlets are enabled).1285// Each helper has different register allocation requirements so we'll set the deps here for1286// the write barrier (which should be the common case), and fix up the registers in the call1287// to jitNewObject.12881289TR::Register *resReg = cg->allocateRegister();1290TR::Register *zeroReg = cg->allocateRegister();1291TR::Register *dataSizeReg = cg->allocateRegister();1292TR::Register *temp1Reg = cg->allocateRegister();1293TR::Register *temp2Reg = cg->allocateRegister();1294TR::addDependency(deps, resReg, TR::RealRegister::gr0, TR_GPR, cg);1295TR::addDependency(deps, zeroReg, TR::RealRegister::NoReg, TR_GPR, cg);1296TR::addDependency(deps, dataSizeReg, TR::RealRegister::NoReg, TR_GPR, cg);1297TR::addDependency(deps, temp1Reg, TR::RealRegister::gr2, TR_GPR, cg);1298TR::addDependency(deps, temp2Reg, TR::RealRegister::gr1, TR_GPR, cg);129913001301if (isVariableLen)1302allocateSize += dataBegin;1303else1304allocateSize = (allocateSize + OBJECT_ALIGNMENT - 1) & (-OBJECT_ALIGNMENT);13051306// classReg and enumReg have to be intact still, in case we have to call the helper.1307// On return, zeroReg is set to 0, and dataSizeReg is set to the size of data area if1308// isVariableLen is true.1309genHeapAlloc(cg, node, iCursor, isVariableLen, enumReg, resReg, zeroReg, dataSizeReg, temp1Reg, temp2Reg, callLabel, allocateSize);13101311if (isArray)1312{1313// Align the array if necessary.1314if (isDoubleArray)1315genAlignDoubleArray(cg, node, iCursor, isVariableLen, resReg, objectSize, dataBegin, dataSizeReg, temp1Reg, temp2Reg);1316genInitArrayHeader(cg, node, iCursor, isVariableLen, clazz, resReg, zeroReg, enumReg, dataSizeReg, temp1Reg, temp2Reg);1317}1318else1319{1320genInitObjectHeader(cg, node, iCursor, clazz, classReg, resReg, zeroReg, temp1Reg, temp2Reg);1321}13221323// Perform initialization if it is needed:1324// 1) Initialize certain array elements individually. This depends on the optimizer1325// providing a "short" list of individual indices;1326// 2) Initialize the whole array:1327// a) If the object size is constant, we can choose strategy depending on the1328// size of the array. Using straight line of code, or unrolled loop;1329// b) For variable length of array, do a counted loop;13301331TR_ExtraInfoForNew *initInfo = node->getSymbolReference()->getExtraInfo();1332TR::MemoryReference *tempMR;13331334if (!node->canSkipZeroInitialization() && (initInfo == NULL || initInfo->numZeroInitSlots > 0))1335{1336if (!isVariableLen)1337{1338if (initInfo!=NULL && initInfo->zeroInitSlots!=NULL &&1339initInfo->numZeroInitSlots<=9 && objectSize<=UPPER_IMMED12)1340{1341TR_BitVectorIterator bvi(*initInfo->zeroInitSlots);13421343while (bvi.hasMoreElements())1344{1345tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, bvi.getNextElement() * 4 + dataBegin, cg);1346iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);1347}1348}1349else if (objectSize > 48)1350{1351// maybe worth of exploring the possibility of using dcbz, but the alignment1352// would require a little more cost of setup.13531354int32_t loopCnt = (objectSize - dataBegin) >> 4;1355int32_t residue = ((objectSize - dataBegin) >> 2) & 0x03;1356TR::LabelSymbol *initLoop = TR::LabelSymbol::create(cg->trHeapMemory(),cg);13571358iCursor = armLoadConstant(node, loopCnt, temp1Reg, cg, iCursor);1359iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, temp2Reg, resReg, dataBegin, 0, iCursor);1360iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, initLoop, iCursor);1361tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, 0, cg);1362iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);1363tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, 4, cg);1364iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);1365tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, 8, cg);1366iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);1367tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, 12, cg);1368iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);13691370// TODO: add the update form instruction, we will not need the following instruction1371iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, temp2Reg, temp2Reg, 16, 0, iCursor);13721373iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sub_r, node, temp1Reg, temp1Reg, 1, 0, iCursor);1374iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, initLoop, iCursor);1375for (idx = 0; idx < residue; idx++)1376{1377tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, idx << 2, cg);1378iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);1379}1380}1381else1382{1383for (idx = dataBegin; idx < objectSize; idx += 4)1384{1385tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, idx, cg);1386iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);1387}1388}1389}1390else // Init variable length array1391{1392// Test for zero length array: also set up loop count13931394iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mov_r, node, temp1Reg, new (cg->trHeapMemory()) TR_ARMOperand2(ARMOp2RegLSRImmed, dataSizeReg, 2), iCursor);1395iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel, iCursor);1396iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, temp2Reg, resReg, dataBegin - 4, 0, iCursor);13971398TR::LabelSymbol *initLoop = TR::LabelSymbol::create(cg->trHeapMemory(),cg);1399iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, initLoop, iCursor);1400tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, temp1Reg, 4, cg);1401iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);1402iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sub_r, node, temp1Reg, temp1Reg, 1, 0, iCursor);1403iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, initLoop, iCursor);1404}1405}1406generateConditionalBranchInstruction(cg, node, ARMConditionCodeAL, doneLabel);14071408// TODO: using snippet to better use of branch prediction facility1409generateLabelInstruction(cg, TR::InstOpCode::label, node, callLabel);1410generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, resReg, classReg);1411if (secondChild != NULL)1412generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, temp2Reg, enumReg);1413iCursor = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uint32_t)node->getSymbolReference()->getMethodAddress(), deps, node->getSymbolReference());1414iCursor->ARMNeedsGCMap(0xFFFFFFFE); // mask off gr01415cg->machine()->setLinkRegisterKilled(true);1416generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);1417deps->stopAddingConditions();14181419cg->decReferenceCount(firstChild);1420if (secondChild != NULL)1421cg->decReferenceCount(secondChild);14221423node->setRegister(resReg);1424resReg->setContainsCollectedReference();1425return resReg;1426}14271428TR::Register *1429OMR::ARM::TreeEvaluator::VMmonentEvaluator(TR::Node *node, TR::CodeGenerator *cg)1430{1431TR::Compilation *comp = TR::comp();1432TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());1433int32_t lwOffset = fej9->getByteOffsetToLockword(cg->getMonClass(node));14341435if ((comp->getOption(TR_FullSpeedDebug) /*&& !comp->getOption(TR_EnableLiveMonitorMetadata)*/) ||1436comp->getOption(TR_DisableInlineMonEnt) ||1437lwOffset <= 0)1438{1439TR::ILOpCodes opCode = node->getOpCodeValue();1440TR::Node::recreate(node, TR::call);1441TR::Register *targetRegister = directCallEvaluator(node, cg);1442TR::Node::recreate(node, opCode);1443return targetRegister;1444}14451446TR::Node *objNode = node->getFirstChild();1447TR::Register *objReg = cg->evaluate(objNode);1448TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());1449TR::Register *metaReg, *dataReg, *addrReg;1450TR::LabelSymbol *callLabel;1451TR::Instruction *iCursor;14521453metaReg = cg->getMethodMetaDataRegister();1454dataReg = cg->allocateRegister();1455addrReg = cg->allocateRegister();1456TR::addDependency(deps, objReg, TR::RealRegister::gr0, TR_GPR, cg);1457TR::addDependency(deps, dataReg, TR::RealRegister::NoReg, TR_GPR, cg);1458TR::addDependency(deps, addrReg, TR::RealRegister::NoReg, TR_GPR, cg);14591460TR::Register *tempReg = cg->allocateRegister();1461TR::addDependency(deps, tempReg, TR::RealRegister::NoReg, TR_GPR, cg);14621463callLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);14641465// This is spinning on the object itself and not on the global objectFlagSpinLock1466TR::LabelSymbol *incLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);1467TR::LabelSymbol *loopLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);1468TR::LabelSymbol *doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);14691470generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, addrReg, objReg, lwOffset, 0);1471generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);1472generateTrg1MemInstruction(cg, TR::InstOpCode::ldrex, node, dataReg, new (cg->trHeapMemory()) TR::MemoryReference(addrReg, (int32_t)0, cg));1473generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, dataReg, 0, 0);1474TR::Instruction *cursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, incLabel);14751476generateTrg1MemSrc1Instruction(cg, TR::InstOpCode::strex, node, tempReg, new (cg->trHeapMemory()) TR::MemoryReference(addrReg, (int32_t)0, cg), metaReg);1477generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, tempReg, 0, 0);1478generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, loopLabel);14791480if (cg->comp()->target().isSMP() && cg->comp()->target().cpu.id() != TR_DefaultARMProcessor)1481{1482generateInstruction(cg, (cg->comp()->target().cpu.id() == TR_ARMv6) ? TR::InstOpCode::dmb_v6 : TR::InstOpCode::dmb, node);1483}14841485generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);14861487TR::Snippet *snippet = new (cg->trHeapMemory()) TR::ARMMonitorEnterSnippet(cg, node, lwOffset, incLabel, callLabel, doneLabel);1488cg->addSnippet(snippet);1489doneLabel->setEndInternalControlFlow();14901491deps->stopAddingConditions();14921493cg->decReferenceCount(objNode);1494return NULL;1495}14961497/*1498TR::Register *OMR::Power::TreeEvaluator::VMarrayCheckEvaluator(TR::Node *node)1499{1500TR::Register *obj1Reg, *obj2Reg, *tmp1Reg, *tmp2Reg, *cndReg;1501TR::LabelSymbol *doneLabel, *snippetLabel;1502TR_Instruction *gcPoint;1503TR::Snippet *snippet;1504TR::RegisterDependencyConditions *conditions;1505int32_t depIndex;15061507obj1Reg = ppcCodeGen->evaluate(node->getFirstChild());1508obj2Reg = ppcCodeGen->evaluate(node->getSecondChild());1509doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),ppcCodeGen);1510conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(5, 5, cg->trMemory());1511depIndex = 0;1512nonFixedDependency(conditions, obj1Reg, &depIndex, TR_GPR, true);1513nonFixedDependency(conditions, obj2Reg, &depIndex, TR_GPR, true);1514tmp1Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, false);1515tmp2Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, false);1516cndReg = ppcCodeGen->allocateRegister(TR_CCR);1517TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);15181519// We have a unique snippet sharing arrangement in this code sequence.1520// It is not generally applicable for other situations.1521snippetLabel = NULL;15221523// Same array, we are done.1524//1525generateTrg1Src2Instruction(TR::InstOpCode::cmpl4, node, cndReg, obj1Reg, obj2Reg);1526generateConditionalBranchInstruction(TR::InstOpCode::beq, node, doneLabel, cndReg);15271528// If we know nothing about either object, test object1 first. It has to be an array.1529//1530if (!node->isArrayChkPrimitiveArray1() &&1531!node->isArrayChkReferenceArray1() &&1532!node->isArrayChkPrimitiveArray2() &&1533!node->isArrayChkReferenceArray2())1534{1535generateTrg1MemInstruction(TR::InstOpCode::lwz, node, tmp1Reg,1536new (cg->trHeapMemory()) TR::MemoryReference(obj1Reg, (int32_t)TR::Compiler->om.offsetOfHeaderFlags(), 4));1537generateTrg1Src1ImmInstruction(TR::InstOpCode::andi_r, node, tmp1Reg, tmp1Reg, OBJECT_HEADER_INDEXABLE);1538snippetLabel = TR::LabelSymbol::create(cg->trHeapMemory(),ppcCodeGen);1539gcPoint = generateConditionalBranchInstruction(TR::InstOpCode::beql, node, snippetLabel, cndReg);1540snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(snippetLabel, node->getSymbolReference());1541ppcCodeGen->addSnippet(snippet);1542}15431544// One of the object is array. Test equality of two objects' classes.1545//1546generateTrg1MemInstruction(TR::InstOpCode::lwz, node, tmp2Reg,1547new (cg->trHeapMemory()) TR::MemoryReference(obj2Reg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), 4));1548generateTrg1MemInstruction(TR::InstOpCode::lwz, node, tmp1Reg,1549new (cg->trHeapMemory()) TR::MemoryReference(obj1Reg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), 4));1550generateTrg1Src2Instruction(TR::InstOpCode::cmpl4, node, cndReg, tmp1Reg, tmp2Reg);15511552// If either object is known to be of primitive component type,1553// we are done: since both of them have to be of equal class.1554if (node->isArrayChkPrimitiveArray1() || node->isArrayChkPrimitiveArray2())1555{1556if (snippetLabel == NULL)1557{1558snippetLabel = TR::LabelSymbol::create(cg->trHeapMemory(),ppcCodeGen);1559gcPoint = generateConditionalBranchInstruction(TR::InstOpCode::bnel, node, snippetLabel, cndReg);1560snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(snippetLabel, node->getSymbolReference());1561ppcCodeGen->addSnippet(snippet);1562}1563else1564generateConditionalBranchInstruction(TR::InstOpCode::bne, node, snippetLabel, cndReg);1565}1566// We have to take care of the un-equal class situation: both of them must be of reference array1567else1568{1569generateConditionalBranchInstruction(TR::InstOpCode::beq, node, doneLabel, cndReg);15701571// Object1 must be of reference component type, otherwise throw exception1572if (!node->isArrayChkReferenceArray1())1573{1574generateTrg1MemInstruction(TR::InstOpCode::lwz, node, tmp1Reg,1575new (cg->trHeapMemory()) TR::MemoryReference(obj1Reg, (int32_t)TR::Compiler->om.offsetOfHeaderFlags(), 4));1576generateTrg1Src1ImmInstruction(TR::InstOpCode::andi_r, node, tmp1Reg, tmp1Reg, OBJECT_HEADER_SHAPE_MASK);1577if (snippetLabel == NULL)1578{1579snippetLabel = TR::LabelSymbol::create(cg->trHeapMemory(),ppcCodeGen);1580gcPoint = generateConditionalBranchInstruction(TR::InstOpCode::bnel, node, snippetLabel, cndReg);1581snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(snippetLabel, node->getSymbolReference());1582ppcCodeGen->addSnippet(snippet);1583}1584else1585generateConditionalBranchInstruction(TR::InstOpCode::bne, node, snippetLabel, cndReg);1586}15871588// Object2 must be of reference component type array, otherwise throw exception1589if (!node->isArrayChkReferenceArray2())1590{1591generateTrg1MemInstruction(TR::InstOpCode::lwz, node, tmp2Reg,1592new (cg->trHeapMemory()) TR::MemoryReference(obj2Reg, (int32_t)TR::Compiler->om.offsetOfHeaderFlags(), 4));1593generateTrg1Src1ImmInstruction(TR::InstOpCode::andi_r, node, tmp1Reg, tmp2Reg, OBJECT_HEADER_INDEXABLE);1594if (snippetLabel == NULL)1595{1596snippetLabel = TR::LabelSymbol::create(cg->trHeapMemory(),ppcCodeGen);1597gcPoint = generateConditionalBranchInstruction(TR::InstOpCode::beql, node, snippetLabel, cndReg);1598snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(snippetLabel, node->getSymbolReference());1599ppcCodeGen->addSnippet(snippet);1600}1601else1602generateConditionalBranchInstruction(TR::InstOpCode::beq, node, snippetLabel, cndReg);16031604generateTrg1Src1ImmInstruction(TR::InstOpCode::andi_r, node, tmp1Reg, tmp2Reg, OBJECT_HEADER_SHAPE_MASK);1605generateConditionalBranchInstruction(TR::InstOpCode::bne, node, snippetLabel, cndReg);1606}1607}16081609generateDepLabelInstruction(TR::InstOpCode::label, node, doneLabel, conditions);16101611conditions->stopUsingDepRegs(obj1Reg, obj2Reg);16121613ppcCodeGen->decReferenceCount(node->getFirstChild());1614ppcCodeGen->decReferenceCount(node->getSecondChild());1615return NULL;1616}161716181619void OMR::Power::TreeEvaluator::VMarrayStoreCHKEvaluator(TR::Node *node, TR::Register *src, TR::Register *dst, TR::Register *t1Reg, TR::Register *t2Reg, TR::Register *cndReg, TR::LabelSymbol *toWB, TR_Instruction *iPtr)1620{1621int32_t objectClass = (int32_t)getSystemClassFromClassName("java/lang/Object", 16);1622int32_t upper = ((objectClass>>16) + ((objectClass & 0x00008000)>>15)) & 0x0000FFFF;1623int32_t lower = objectClass & 0x0000FFFF;16241625iPtr = generateTrg1MemInstruction(TR::InstOpCode::lwz, node, t1Reg,1626new (cg->trHeapMemory()) TR::MemoryReference(dst, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4), iPtr);1627iPtr = generateTrg1MemInstruction(TR::InstOpCode::lwz, node, t2Reg,1628new (cg->trHeapMemory()) TR::MemoryReference(src, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4), iPtr);1629iPtr = generateTrg1MemInstruction(TR::InstOpCode::lwz, node, t1Reg,1630new (cg->trHeapMemory()) TR::MemoryReference(t1Reg, (int32_t)offsetof(J9ArrayClass, componentType), 4),1631iPtr);1632iPtr = generateTrg1Src2Instruction(TR::InstOpCode::cmpl4, node, cndReg, t1Reg, t2Reg, iPtr);1633iPtr = generateConditionalBranchInstruction(TR::InstOpCode::beq, node, toWB, cndReg, iPtr);1634if (upper == 0)1635{1636iPtr = generateTrg1ImmInstruction(TR::InstOpCode::li, node, t2Reg, lower, iPtr);1637}1638else1639{1640iPtr = generateTrg1ImmInstruction(TR::InstOpCode::lis, node, t2Reg, upper, iPtr);1641if (lower != 0)1642{1643iPtr = generateTrg1Src1ImmInstruction(TR::InstOpCode::addi, node, t2Reg, t2Reg, lower, iPtr);1644}1645}1646iPtr = generateTrg1Src2Instruction(TR::InstOpCode::cmpl4, node, cndReg, t1Reg, t2Reg, iPtr);1647iPtr = generateConditionalBranchInstruction(TR::InstOpCode::beq, node, toWB, cndReg, iPtr);1648}1649*/165016511652void OMR::ARM::TreeEvaluator::VMwrtbarEvaluator(TR::Node *node, TR::Register *srcReg, TR::Register *dstReg, TR::Register *flagReg, bool needDeps, TR::CodeGenerator *cg)1653{1654TR::Compilation *comp = TR::comp();1655TR::LabelSymbol *doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);1656TR::SymbolReference *wbref = comp->getSymRefTab()->findOrCreateWriteBarrierStoreSymbolRef(comp->getMethodSymbol());1657auto gcMode = TR::Compiler->om.writeBarrierType();16581659TR::Register *tempReg = NULL;1660TR::RegisterDependencyConditions *deps = NULL;16611662if (flagReg == NULL)1663tempReg = cg->allocateRegister();1664else1665tempReg = flagReg;16661667if (needDeps)1668{1669deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(3, 3, cg->trMemory());1670TR::addDependency(deps, srcReg, TR::RealRegister::gr1, TR_GPR, cg);1671TR::addDependency(deps, dstReg, TR::RealRegister::gr0, TR_GPR, cg);1672TR::addDependency(deps, tempReg, TR::RealRegister::gr2, TR_GPR, cg);1673}16741675// todo check for _isSourceNonNull in PPC gen to see possible opt?1676// nullcheck store - skip write barrier if null being written in1677generateSrc2Instruction(cg, TR::InstOpCode::tst, node, srcReg, srcReg);1678generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel);16791680if (gcMode != gc_modron_wrtbar_always)1681{1682// check to see if colour bits give hint (read FLAGS field of J9Object).1683// @@ getWordOffsetToGCFlags() and getWriteBarrierGCFlagMaskAsByte() are missing in TR_FrontEnd1684// @@ if (flagReg == NULL)1685// @@ generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, tempReg, new (cg->trHeapMemory()) TR::MemoryReference(dstReg, fej9->getWordOffsetToGCFlags(), cg));1686// @@ generateTrg1Src2Instruction(cg, TR::InstOpCode::and_r, node, tempReg, tempReg, new (cg->trHeapMemory()) TR_ARMOperand2(fej9->getWriteBarrierGCFlagMaskAsByte(), 8));1687}16881689TR::Instruction *cursor = generateImmSymInstruction(cg, TR::InstOpCode::bl,1690node, (uintptr_t)wbref->getMethodAddress(),1691new (cg->trHeapMemory()) TR::RegisterDependencyConditions((uint8_t)0, 0, cg->trMemory()),1692wbref, NULL);16931694if (gcMode != gc_modron_wrtbar_always)1695{1696// conditional call to the write barrier1697cursor->setConditionCode(ARMConditionCodeNE);1698}16991700// place label that marks work was done.1701generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);17021703if (flagReg == NULL)1704cg->stopUsingRegister(tempReg);1705}17061707void VMgenerateCatchBlockBBStartPrologue(TR::Node *node, TR::Instruction *fenceInstruction, TR::CodeGenerator *cg)1708{1709/* @@ not implemented @@ */1710}171117121713