Path: blob/master/runtime/compiler/arm/codegen/J9TreeEvaluator.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 "j9.h"23#include "j9cfg.h"24#include "j9consts.h"25#include "omrmodroncore.h"26#include "thrdsup.h"27#include "thrtypes.h"28#include "codegen/CodeGenerator.hpp"29#include "codegen/CodeGeneratorUtils.hpp"30#include "codegen/Machine.hpp"31#include "codegen/Linkage.hpp"32#include "codegen/Linkage_inlines.hpp"33#include "codegen/TreeEvaluator.hpp"34#include "env/jittypes.h"35#include "il/DataTypes.hpp"36#include "il/LabelSymbol.hpp"37#include "il/Node.hpp"38#include "il/Node_inlines.hpp"39#include "arm/codegen/ARMInstruction.hpp"40#include "arm/codegen/GenerateInstructions.hpp"4142/*43* J9 ARM specific tree evaluator table overrides44*/45extern void TEMPORARY_initJ9ARMTreeEvaluatorTable(TR::CodeGenerator *cg)46{47TR_TreeEvaluatorFunctionPointer *tet = cg->getTreeEvaluatorTable();4849tet[TR::ResolveCHK] = TR::TreeEvaluator::resolveCHKEvaluator;50tet[TR::monexitfence] = TR::TreeEvaluator::monexitfenceEvaluator;51tet[TR::NULLCHK] = TR::TreeEvaluator::NULLCHKEvaluator;52tet[TR::ResolveAndNULLCHK] = TR::TreeEvaluator::resolveAndNULLCHKEvaluator;53}5455TR::Register *56J9::ARM::TreeEvaluator::NULLCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)57{58return TR::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(node, false, cg);59}6061TR::Register *62J9::ARM::TreeEvaluator::resolveAndNULLCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)63{64return TR::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(node, true, cg);65}6667TR::Register *68J9::ARM::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(TR::Node *node, bool needsResolve, TR::CodeGenerator *cg)69{70// NOTE:71// If no code is generated for the null check, just evaluate the72// child and decrement its use count UNLESS the child is a pass-through node73// in which case some kind of explicit test or indirect load must be generated74// to force the null check at this point.7576// Generate the code for the null check77//78TR::Node *firstChild = node->getFirstChild();79TR::ILOpCode &opCode = firstChild->getOpCode();80TR::Node *reference = node->getNullCheckReference();8182// Skip the NULLCHK for TR::loadaddr nodes.83//84if (reference->getOpCodeValue() == TR::loadaddr)85{86cg->evaluate(firstChild);87firstChild->decReferenceCount();88return NULL;89}9091bool needCode = !(cg->canNullChkBeImplicit(node, true));9293// nullchk is not implicit94//95if (needCode)96{97// TODO - If a resolve check is needed as well, the resolve must be done98// before the null check, so that exceptions are handled in the correct99// order.100//101///// if (needsResolve)102///// {103///// ...104///// }105106TR::Register *targetRegister = cg->evaluate(reference);107108generateSrc2Instruction(cg, TR::InstOpCode::tst, node, targetRegister, targetRegister);109110TR::SymbolReference *NULLCHKException = node->getSymbolReference();111TR::Instruction *instr1 = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)NULLCHKException->getMethodAddress(), NULL, NULLCHKException, NULL, NULL, ARMConditionCodeEQ);112instr1->ARMNeedsGCMap(0xFFFFFFFF);113cg->machine()->setLinkRegisterKilled(true);114}115116// For a load, if this is the only use decrement the use count on the117// grandchild since it has already been evaluated.118// Otherwise just evaluate the child.119//120if (needCode && opCode.isLoad()121&& firstChild->getReferenceCount() == 1122&& firstChild->getSymbolReference()123&& !firstChild->getSymbolReference()->isUnresolved())124{125firstChild->decReferenceCount();126reference->decReferenceCount();127}128else129{130cg->evaluate(firstChild);131firstChild->decReferenceCount();132}133134// If an explicit check has not been generated for the null check, there is135// an instruction that will cause a hardware trap if the exception is to be136// taken. If this method may catch the exception, a GC stack map must be137// created for this instruction. All registers are valid at this GC point138// TODO - if the method may not catch the exception we still need to note139// that the GC point exists, since maps before this point and after it cannot140// be merged.141//142/////if (!needCode && comp->getMethodSymbol()->isEHAwareMethod())143if (!needCode)144{145TR::Instruction *faultingInstruction = cg->getImplicitExceptionPoint();146if (faultingInstruction)147faultingInstruction->setNeedsGCMap();148}149150reference->setIsNonNull(true);151152return NULL;153}154155/**156* \brief157* Generates code for card marking checks158*159* \parm dstReg160* Register for destination object161*162* \parm temp1Reg163* Temporary register164*165* \parm temp2Reg166* Temporary register167*168* \parm temp3Reg169* Temporary register170*171* \parm deps172* Register dependencies to be satisfied at the end of code173*/174static void VMCardCheckEvaluator(TR::Node *node, TR::Register *dstReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register *temp3Reg,175TR::RegisterDependencyConditions *deps, TR::CodeGenerator *cg)176{177TR::Compilation * comp = cg->comp();178// non-heap objects cannot be marked179// Make sure we really should be here180TR::Options *options = comp->getOptions();181TR::Node *wrtbarNode = NULL;182bool definitelyHeapObject = false, definitelyNonHeapObject = false;183auto gcMode = TR::Compiler->om.writeBarrierType();184185if (node->getOpCodeValue() == TR::awrtbari || node->getOpCodeValue() == TR::awrtbar)186wrtbarNode = node;187else if (node->getOpCodeValue() == TR::ArrayStoreCHK)188wrtbarNode = node->getFirstChild();189190if (wrtbarNode != NULL)191{192definitelyHeapObject = wrtbarNode->isHeapObjectWrtBar();193definitelyNonHeapObject = wrtbarNode->isNonHeapObjectWrtBar();194}195196TR_ASSERT((gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental) && !definitelyNonHeapObject,197"VMCardCheckEvaluator: Invalid call to cardCheckEvaluator\n");198199if (!definitelyNonHeapObject)200{201TR::Register *metaReg = cg->getMethodMetaDataRegister();202TR::LabelSymbol *noChkLabel = generateLabelSymbol(cg);203204// Balanced policy must always dirty the card table.205//206if (gcMode != gc_modron_wrtbar_cardmark_incremental)207{208uint32_t base, rotate;209210generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp1Reg,211new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, privateFlags), cg));212213// The value for J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE is a generated value when VM code is created214// At the moment we are safe here, but it is better to be careful and avoid any unexpected behaviour215// Make sure this falls within the scope of tst216//217TR_ASSERT(J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE >= 0x00010000 && J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE <= 0x80000000,218"Concurrent mark active Value assumption broken.");219constantIsImmed8r(J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE, &base, &rotate);220generateSrc1ImmInstruction(cg, TR::InstOpCode::tst, node, temp1Reg, base, rotate);221generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, noChkLabel);222}223224uintptr_t card_size_shift = trailingZeroes((uint32_t) options->getGcCardSize());225226// temp3Reg = dstReg - heapBaseForBarrierRange0227generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp3Reg,228new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapBaseForBarrierRange0), cg));229generateTrg1Src2Instruction(cg, TR::InstOpCode::sub, node, temp3Reg, dstReg, temp3Reg);230231if (!definitelyHeapObject)232{233// if (temp3Reg >= heapSizeForBarrierRange0), object not in the heap234generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp1Reg,235new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapSizeForBarrierRange0), cg));236generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, temp3Reg, temp1Reg);237generateConditionalBranchInstruction(cg, node, ARMConditionCodeCS, noChkLabel);238}239240// dirty(activeCardTableBase + temp3Reg >> card_size_shift)241generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp1Reg,242new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, activeCardTableBase), cg));243generateShiftRightImmediate(cg, node, temp3Reg, temp3Reg, card_size_shift, true);244armLoadConstant(node, CARD_DIRTY, temp2Reg, cg);245generateMemSrc1Instruction(cg, TR::InstOpCode::strb, node, new (cg->trHeapMemory()) TR::MemoryReference(temp1Reg, temp3Reg, 1, cg), temp2Reg);246247generateLabelInstruction(cg, TR::InstOpCode::label, node, noChkLabel, deps);248}249250}251252253void254J9::ARM::TreeEvaluator::generateTestAndReportFieldWatchInstructions(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *valueReg, TR::Register *dataSnippetRegister)255{256TR_ASSERT_FATAL(false, "This helper implements platform specific code for Fieldwatch, which is currently not supported on ARM platforms.\n");257}258259void260J9::ARM::TreeEvaluator::generateFillInDataBlockSequenceForUnresolvedField(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *dataSnippetRegister)261{262TR_ASSERT_FATAL(false, "This helper implements platform specific code for Fieldwatch, which is currently not supported on ARM platforms.\n");263}264265/**266* \brief267* Generates write barrier for non-simple arraycopy node268*269* \parm srcObjReg270* Register for source object271*272* \parm dstObjReg273* Register for destination object274*/275void J9::ARM::TreeEvaluator::genWrtbarForArrayCopy(TR::Node *node, TR::Register *srcObjReg, TR::Register *dstObjReg, TR::CodeGenerator *cg)276{277TR::Compilation * comp = cg->comp();278bool ageCheckIsNeeded = false;279bool cardMarkIsNeeded = false;280auto gcMode = TR::Compiler->om.writeBarrierType();281282ageCheckIsNeeded = (gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always);283cardMarkIsNeeded = (gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_incremental);284285if (!ageCheckIsNeeded && !cardMarkIsNeeded)286{287return;288}289290if (ageCheckIsNeeded)291{292TR::Register *temp1Reg;293TR::Register *temp2Reg;294TR::RegisterDependencyConditions *conditions;295296TR::LabelSymbol *doneLabel;297TR::SymbolReference *wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierBatchStoreSymbolRef(comp->getMethodSymbol());298299if (gcMode != gc_modron_wrtbar_always)300{301temp1Reg = cg->allocateRegister();302temp2Reg = cg->allocateRegister();303doneLabel = generateLabelSymbol(cg);304305conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(3, 3, cg->trMemory());306TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);307TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);308309TR::Register *metaReg = cg->getMethodMetaDataRegister();310311// temp1Reg = dstObjReg - heapBaseForBarrierRange0312generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp1Reg,313new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapBaseForBarrierRange0), cg));314generateTrg1Src2Instruction(cg, TR::InstOpCode::sub, node, temp1Reg, dstObjReg, temp1Reg);315316// if (temp1Reg >= heapSizeForBarrierRange0), object not in the tenured area317generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp2Reg,318new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapSizeForBarrierRange0), cg));319generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, temp1Reg, temp2Reg);320generateConditionalBranchInstruction(cg, node, ARMConditionCodeCS, doneLabel);321}322else323{324conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg->trMemory());325}326327TR::addDependency(conditions, dstObjReg, TR::RealRegister::gr0, TR_GPR, cg);328329TR::Instruction *gcPoint = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)wbRef->getSymbol()->castToMethodSymbol()->getMethodAddress(), NULL, wbRef);330gcPoint->ARMNeedsGCMap(0xFFFFFFFF);331332if (gcMode != gc_modron_wrtbar_always)333{334generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);335}336337cg->machine()->setLinkRegisterKilled(true);338cg->setHasCall();339340if (gcMode != gc_modron_wrtbar_always)341{342cg->stopUsingRegister(temp1Reg);343cg->stopUsingRegister(temp2Reg);344}345}346else if (cardMarkIsNeeded)347{348if (!comp->getOptions()->realTimeGC())349{350TR::Register *temp1Reg = cg->allocateRegister();351TR::Register *temp2Reg = cg->allocateRegister();352TR::Register *temp3Reg = cg->allocateRegister();353TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());354355TR::addDependency(conditions, dstObjReg, TR::RealRegister::NoReg, TR_GPR, cg);356TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);357TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);358TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);359360VMCardCheckEvaluator(node, dstObjReg, temp1Reg, temp2Reg, temp3Reg, conditions, cg);361362cg->stopUsingRegister(temp1Reg);363cg->stopUsingRegister(temp2Reg);364cg->stopUsingRegister(temp3Reg);365}366else367TR_ASSERT(0, "genWrtbarForArrayCopy card marking not supported for RT");368}369}370371372