From 5691e16a0ecab9a1e23ae3cb311dd362fb4dd3bf Mon Sep 17 00:00:00 2001 From: Ben Thomas Date: Fri, 1 Feb 2019 19:39:44 +0000 Subject: [PATCH 1/4] Fix direct calls on Power under SVM AOT Previously, it was generally assumed that any method calls generated under AOT would be unresolved calls. While this was historically true, it is no longer true when the Symbol Validation Manager is enabled. The Power codegen will now no longer force unresolved dispatch in these cases, instead using the new functionality to allow resolved dispatch. Signed-off-by: Ben Thomas --- runtime/compiler/p/codegen/CallSnippet.cpp | 38 ++++++++++++++----- runtime/compiler/p/codegen/CallSnippet.hpp | 4 +- .../compiler/p/codegen/PPCPrivateLinkage.cpp | 10 +++-- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/runtime/compiler/p/codegen/CallSnippet.cpp b/runtime/compiler/p/codegen/CallSnippet.cpp index 3c09ca243bb..36bfa362725 100644 --- a/runtime/compiler/p/codegen/CallSnippet.cpp +++ b/runtime/compiler/p/codegen/CallSnippet.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corp. and others + * Copyright (c) 2000, 2019 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -282,9 +282,13 @@ TR_RuntimeHelper TR::PPCCallSnippet::getInterpretedDispatchHelper( isJitInduceOSRCall = true; } - if (methodSymRef->isUnresolved() || comp->compileRelocatableCode()) // KEN + bool forceUnresolvedDispatch = fej9->forceUnresolvedDispatch(); + if (comp->getOption(TR_UseSymbolValidationManager)) + forceUnresolvedDispatch = false; + + if (methodSymRef->isUnresolved() || forceUnresolvedDispatch) { - TR_ASSERT(!isJitInduceOSRCall || !comp->compileRelocatableCode(), "calling jitInduceOSR is not supported yet under AOT\n"); + TR_ASSERT(!isJitInduceOSRCall || !forceUnresolvedDispatch, "calling jitInduceOSR is not supported yet under AOT\n"); if (methodSymbol->isSpecial()) return TR_PPCinterpreterUnresolvedSpecialGlue; @@ -396,8 +400,12 @@ uint8_t *TR::PPCCallSnippet::emitSnippetBody() //continue execution in interpreted mode. Therefore, it doesn't need the method pointer. if (!glueRef->isOSRInductionHelper()) { + bool forceUnresolvedDispatch = fej9->forceUnresolvedDispatch(); + if (comp->getOption(TR_UseSymbolValidationManager)) + forceUnresolvedDispatch = false; + // Store the method pointer: it is NULL for unresolved - if (methodSymRef->isUnresolved() || comp->compileRelocatableCode()) + if (methodSymRef->isUnresolved() || forceUnresolvedDispatch) { *(intptrj_t *)cursor = 0; if (comp->getOption(TR_EnableHCR)) @@ -414,10 +422,18 @@ uint8_t *TR::PPCCallSnippet::emitSnippetBody() if (comp->getOption(TR_EnableHCR)) cg()->jitAddPicToPatchOnClassRedefinition((void *)methodSymbol->getMethodAddress(), (void *)cursor); - cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, (uint8_t *)methodSymRef, - getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1, - TR_MethodObject, cg()), - __FILE__, __LINE__, callNode); + if (comp->compileRelocatableCode()) + { + cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, + (uint8_t *)methodSymbol->getMethodAddress(), + (uint8_t *)TR::SymbolType::typeMethod, + TR_SymbolFromManager, + cg()), __FILE__, __LINE__, getNode()); + cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, + (uint8_t *)methodSymbol->getMethodAddress(), + TR_ResolvedTrampolines, + cg()), __FILE__, __LINE__, getNode()); + } } } cursor += TR::Compiler->om.sizeofReferenceAddress(); @@ -1276,13 +1292,17 @@ TR_Debug::print(TR::FILE *pOutFile, TR::PPCCallSnippet * snippet) const char *labelString = NULL; bool isNativeStatic = false; + bool forceUnresolvedDispatch = fej9->forceUnresolvedDispatch(); + if (comp->getOption(TR_UseSymbolValidationManager)) + forceUnresolvedDispatch = false; + if (methodSymbol->isHelper() && methodSymRef->isOSRInductionHelper()) { labelString = "Induce OSR Call Snippet"; glueRef = methodSymRef; } - else if (methodSymRef->isUnresolved() || comp->compileRelocatableCode()) + else if (methodSymRef->isUnresolved() || forceUnresolvedDispatch) { labelString = "Unresolved Direct Call Snippet"; if (methodSymbol->isSpecial()) diff --git a/runtime/compiler/p/codegen/CallSnippet.hpp b/runtime/compiler/p/codegen/CallSnippet.hpp index b9cc573cdde..3d661f97edf 100644 --- a/runtime/compiler/p/codegen/CallSnippet.hpp +++ b/runtime/compiler/p/codegen/CallSnippet.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corp. and others + * Copyright (c) 2000, 2019 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -43,7 +43,7 @@ class PPCCallSnippet : public TR::Snippet bool needsGCMap(TR::CodeGenerator *cg, TR::SymbolReference *methodSymRef) { TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe()); - if (OMR_UNLIKELY(cg->comp()->compileRelocatableCode())) + if (OMR_UNLIKELY(cg->comp()->compileRelocatableCode() && !cg->comp()->getOption(TR_UseSymbolValidationManager))) return false; TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol(); return !methodSymRef->isUnresolved() && diff --git a/runtime/compiler/p/codegen/PPCPrivateLinkage.cpp b/runtime/compiler/p/codegen/PPCPrivateLinkage.cpp index d8125f06009..ada275f8482 100644 --- a/runtime/compiler/p/codegen/PPCPrivateLinkage.cpp +++ b/runtime/compiler/p/codegen/PPCPrivateLinkage.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corp. and others + * Copyright (c) 2000, 2019 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -2675,8 +2675,12 @@ void TR::PPCPrivateLinkage::buildDirectCall(TR::Node *callNode, if (callSymRef->getReferenceNumber() >= TR_PPCnumRuntimeHelpers) fej9->reserveTrampolineIfNecessary(comp(), callSymRef, false); + bool forceUnresolvedDispatch = fej9->forceUnresolvedDispatch(); + if (comp()->getOption(TR_UseSymbolValidationManager)) + forceUnresolvedDispatch = false; + if ((callSymbol->isJITInternalNative() || - (!callSymRef->isUnresolved() && !callSymbol->isInterpreted() && ((comp()->compileRelocatableCode() && callSymbol->isHelper()) || !comp()->compileRelocatableCode())))) + (!callSymRef->isUnresolved() && !callSymbol->isInterpreted() && ((forceUnresolvedDispatch && callSymbol->isHelper()) || !forceUnresolvedDispatch)))) { gcPoint = generateDepImmSymInstruction(cg(), TR::InstOpCode::bl, callNode, myself?0:(uintptrj_t)callSymbol->getMethodAddress(), @@ -2687,7 +2691,7 @@ void TR::PPCPrivateLinkage::buildDirectCall(TR::Node *callNode, TR::LabelSymbol *label = generateLabelSymbol(cg()); TR::Snippet *snippet; - if (callSymRef->isUnresolved() || comp()->compileRelocatableCode()) + if (callSymRef->isUnresolved() || forceUnresolvedDispatch) { snippet = new (trHeapMemory()) TR::PPCUnresolvedCallSnippet(cg(), callNode, label, argSize); } From a1fb824bf258cb50af4de819bc47887dc629f24d Mon Sep 17 00:00:00 2001 From: Ben Thomas Date: Fri, 1 Feb 2019 19:44:37 +0000 Subject: [PATCH 2/4] Fix instanceof and checkcast inlining on Power under SVM AOT Inlining of instanceof and checkcast tests in the Power codegen when running with the Symbol Validation Manager enabled has now been fixed to work correctly. This includes adding the correct validation records for profiled classes and single-implementer classes. Signed-off-by: Ben Thomas --- .../compiler/p/codegen/J9TreeEvaluator.cpp | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/runtime/compiler/p/codegen/J9TreeEvaluator.cpp b/runtime/compiler/p/codegen/J9TreeEvaluator.cpp index d427346ff8f..d9c7854eef3 100644 --- a/runtime/compiler/p/codegen/J9TreeEvaluator.cpp +++ b/runtime/compiler/p/codegen/J9TreeEvaluator.cpp @@ -179,9 +179,21 @@ static void genInlineTest(TR::Node * node, TR_OpaqueClassBlock* castClassAddr, T // Load the cached value in scratch1Reg // HCR in genInlineTest for checkcast and instanceof if (cg->wantToPatchClassPointer(guessClassArray[i], node)) + { iCursor = loadAddressConstantInSnippet(cg, node, (intptrj_t) (guessClassArray[i]), scratch1Reg, scratch2Reg,TR::InstOpCode::Op_load, true, iCursor); + } + else if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager)) + { + TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address); + sym->setStaticAddress(guessClassArray[i]); + sym->setClassObject(); + + iCursor = loadAddressConstant(cg, node, (intptrj_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), scratch1Reg, iCursor, false, TR_ClassAddress); + } else + { iCursor = loadAddressConstant(cg, node, (intptrj_t) (guessClassArray[i]), scratch1Reg, iCursor); + } result_bool = instanceOfOrCheckCast((J9Class*) guessClassArray[i], (J9Class*) castClassAddr); int32_t result_value = result_bool ? 1 : 0; result_label = (falseLabel != trueLabel) ? (result_bool ? trueLabel : falseLabel) : doneLabel; @@ -193,9 +205,21 @@ static void genInlineTest(TR::Node * node, TR_OpaqueClassBlock* castClassAddr, T // Load the cached value in scratch1Reg if (cg->wantToPatchClassPointer(guessClassArray[num_PICS - 1], node)) + { iCursor = loadAddressConstantInSnippet(cg, node, (intptrj_t) (guessClassArray[num_PICS - 1]), scratch1Reg, scratch2Reg,TR::InstOpCode::Op_load, true, iCursor); + } + else if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager)) + { + TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address); + sym->setStaticAddress(guessClassArray[num_PICS - 1]); + sym->setClassObject(); + + iCursor = loadAddressConstant(cg, node, (intptrj_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), scratch1Reg, iCursor, false, TR_ClassAddress); + } else + { iCursor = loadAddressConstant(cg, node, (intptrj_t) (guessClassArray[num_PICS - 1]), scratch1Reg, iCursor); + } iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, objClassReg, scratch1Reg, iCursor); iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg, iCursor); result_bool = instanceOfOrCheckCast((J9Class*) guessClassArray[num_PICS - 1], (J9Class*) castClassAddr); @@ -3672,7 +3696,18 @@ static void genInstanceOfOrCheckCastArbitraryClassTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR_OpaqueClassBlock *arbitraryClass, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg) { TR::Register *arbitraryClassReg = srm->findOrCreateScratchRegister(); - loadAddressConstant(cg, node, (intptr_t)arbitraryClass, arbitraryClassReg); + if (cg->comp()->compileRelocatableCode() && cg->comp()->getOption(TR_UseSymbolValidationManager)) + { + TR::StaticSymbol *sym = TR::StaticSymbol::create(cg->comp()->trHeapMemory(), TR::Address); + sym->setStaticAddress(arbitraryClass); + sym->setClassObject(); + + loadAddressConstant(cg, node, (intptr_t) new (cg->comp()->trHeapMemory()) TR::SymbolReference(cg->comp()->getSymRefTab(), sym), arbitraryClassReg, NULL, false, TR_ClassAddress); + } + else + { + loadAddressConstant(cg, node, (intptr_t)arbitraryClass, arbitraryClassReg); + } genInstanceOfOrCheckCastClassEqualityTest(node, condReg, instanceClassReg, arbitraryClassReg, cg); srm->reclaimScratchRegister(arbitraryClassReg); @@ -4163,6 +4198,9 @@ TR::Register *J9::Power::TreeEvaluator::VMcheckcastEvaluator(TR::Node *node, TR: if (newCheckCast) return VMcheckcastEvaluator2(node, cg); + TR_ASSERT_FATAL(!cg->comp()->compileRelocatableCode() || !cg->comp()->getOption(TR_UseSymbolValidationManager), + "Old checkcast and instanceof evaluators are not supported under AOT"); + TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe()); TR::Register *objReg, *castClassReg, *objClassReg, *scratch1Reg, *scratch2Reg, *cndReg; TR::LabelSymbol *doneLabel, *callLabel, *callForInlineLabel, *nextTestLabel; @@ -4568,6 +4606,9 @@ TR::Register *J9::Power::TreeEvaluator::VMinstanceOfEvaluator(TR::Node *node, TR if (newInstanceOf) return VMinstanceOfEvaluator2(node, cg); + TR_ASSERT_FATAL(!cg->comp()->compileRelocatableCode() || !cg->comp()->getOption(TR_UseSymbolValidationManager), + "Old checkcast and instanceof evaluators are not supported under AOT"); + TR::Compilation *comp = cg->comp(); TR::Node *depNode; int32_t depIndex; @@ -4846,7 +4887,7 @@ TR::Register * J9::Power::TreeEvaluator::VMgenCoreInstanceofEvaluator(TR::Node * if (castClassIsReferenceArray) { TR_OpaqueClassBlock * jlobjectclassBlock = fej9->getSystemClassFromClassName("java/lang/Object", 16); - J9Class* jlobjectarrayclassBlock = jlobjectclassBlock ? ((J9Class*) jlobjectclassBlock)->arrayClass : NULL; + J9Class* jlobjectarrayclassBlock = jlobjectclassBlock ? (J9Class*)fej9->getArrayClassFromComponentClass((TR_OpaqueClassBlock*)jlobjectclassBlock) : NULL; if (jlobjectarrayclassBlock != NULL) { iCursor = loadAddressConstant(cg, node, (intptrj_t) (jlobjectarrayclassBlock), scratch1Reg, iCursor); From 9a88f0a6256480c08357de6e1255e94ece796569 Mon Sep 17 00:00:00 2001 From: Ben Thomas Date: Fri, 1 Feb 2019 19:47:22 +0000 Subject: [PATCH 3/4] Fix fast ArrayStoreCHK test on Power under AOT When evaluating an ArrayStoreCHK node, we add a test to see if the array being stored into is an Object[]. When storing to an Object[], there's no need to check the element's class, as all objects can be stored in an Object[]. However, the address for the Object class was being loaded without adding any relocations under AOT, which could cause incorrect behaviour. This has been fixed under SVM AOT, while the fast path is no longer generated under old AOT. Signed-off-by: Ben Thomas --- .../compiler/p/codegen/J9TreeEvaluator.cpp | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/runtime/compiler/p/codegen/J9TreeEvaluator.cpp b/runtime/compiler/p/codegen/J9TreeEvaluator.cpp index d9c7854eef3..5aa47d0470e 100644 --- a/runtime/compiler/p/codegen/J9TreeEvaluator.cpp +++ b/runtime/compiler/p/codegen/J9TreeEvaluator.cpp @@ -3030,31 +3030,42 @@ static void VMarrayStoreCHKEvaluator(TR::Node *node, TR::Register *src, TR::Regi new (cg->trHeapMemory()) TR::MemoryReference(dst, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4, cg)); generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, t2Reg, new (cg->trHeapMemory()) TR::MemoryReference(src, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4, cg)); - TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, t1Reg); - TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, t2Reg); - // here we may need to convert from class offset contained in t1Reg to - // J9Class pointer - generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t1Reg, - new (cg->trHeapMemory()) TR::MemoryReference(t1Reg, (int32_t)offsetof(J9ArrayClass, componentType), TR::Compiler->om.sizeofReferenceAddress(), cg)); - // here we may need to convert from J9Class pointer contained in t1Reg - // into class offset (so that we can compare two classes) #else generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t1Reg, new (cg->trHeapMemory()) TR::MemoryReference(dst, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), TR::Compiler->om.sizeofReferenceAddress(), cg)); generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t2Reg, new (cg->trHeapMemory()) TR::MemoryReference(src, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), TR::Compiler->om.sizeofReferenceAddress(), cg)); +#endif TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, t1Reg); TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, t2Reg); + generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t1Reg, - new (cg->trHeapMemory()) TR::MemoryReference(t1Reg, (int32_t) offsetof(J9ArrayClass, componentType), TR::Compiler->om.sizeofReferenceAddress(), cg)); -#endif + new (cg->trHeapMemory()) TR::MemoryReference(t1Reg, (int32_t)offsetof(J9ArrayClass, componentType), TR::Compiler->om.sizeofReferenceAddress(), cg)); - TR_OpaqueClassBlock *rootClass = fej9->getSystemClassFromClassName("java/lang/Object", 16); + if (!comp->compileRelocatableCode() || comp->getOption(TR_UseSymbolValidationManager)) + { + TR_OpaqueClassBlock *rootClass = fej9->getSystemClassFromClassName("java/lang/Object", 16); - if (cg->wantToPatchClassPointer(rootClass, node)) - loadAddressConstantInSnippet(cg, node, (intptrj_t) rootClass, t3Reg, t4Reg,TR::InstOpCode::Op_load, false, NULL); - else - loadAddressConstant(cg, node, (intptrj_t) rootClass, t3Reg); + if (cg->wantToPatchClassPointer(rootClass, node)) + { + loadAddressConstantInSnippet(cg, node, (intptrj_t) rootClass, t3Reg, t4Reg, TR::InstOpCode::Op_load, false, NULL); + } + else if (comp->compileRelocatableCode()) + { + TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address); + sym->setStaticAddress(rootClass); + sym->setClassObject(); + + loadAddressConstant(cg, node, (intptrj_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), t3Reg, NULL, false, TR_ClassAddress); + } + else + { + loadAddressConstant(cg, node, (intptrj_t) rootClass, t3Reg); + } + + generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t3Reg); + generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg); + } generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t4Reg, new (cg->trHeapMemory()) TR::MemoryReference(t2Reg, (int32_t) offsetof(J9Class, castClassCache), TR::Compiler->om.sizeofReferenceAddress(), cg)); From 715b9d327dd9e2b3db61c7aa782aeff88aac3663 Mon Sep 17 00:00:00 2001 From: Ben Thomas Date: Fri, 1 Feb 2019 19:56:14 +0000 Subject: [PATCH 4/4] Fix object allocation inlining on Power under SVM AOT Object allocation inlining in the Power codegen now works correctly when the Symbol Validation Manager is enabled. The previous code was making a number of incorrect assumptions about what would happen under AOT, which have now been corrected. Specifically, when allocating an array, the old AOT infrastructure would put the address of the component class in classReg and the array class would be retrieved from that at runtime. Under SVM AOT, it is now possible to directly load the address of the array class, so classReg will now contain the address of the array class and the runtime retrieval of the array class from the component class is no longer necessary. Signed-off-by: Ben Thomas --- .../compiler/p/codegen/J9TreeEvaluator.cpp | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/runtime/compiler/p/codegen/J9TreeEvaluator.cpp b/runtime/compiler/p/codegen/J9TreeEvaluator.cpp index 5aa47d0470e..5579fe2e89f 100644 --- a/runtime/compiler/p/codegen/J9TreeEvaluator.cpp +++ b/runtime/compiler/p/codegen/J9TreeEvaluator.cpp @@ -6381,7 +6381,7 @@ static void genInitObjectHeader(TR::Node *node, TR::Instruction *&iCursor, TR_Op TR::Register * clzReg = classReg; - if (comp->compileRelocatableCode()) + if (comp->compileRelocatableCode() && !comp->getOption(TR_UseSymbolValidationManager)) { if (node->getOpCodeValue() == TR::newarray) { @@ -6981,6 +6981,17 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG allocateSize = (allocateSize + fej9->getObjectAlignmentInBytes() - 1) & (-fej9->getObjectAlignmentInBytes()); } + if (comp->compileRelocatableCode()) + { + switch (opCode) + { + case TR::New: break; + case TR::anewarray: break; + case TR::newarray: break; + default: doInline = false; break; + } + } + static int count = 0; doInline = doInline && performTransformation(comp, "O^O <%3d> Inlining Allocation of %s [0x%p].\n", count++, node->getOpCode().getName(), node); @@ -7032,7 +7043,26 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG insertType = (opCode == TR::newarray && secondChild->getDataType() == TR::Int32 && secondChild->getReferenceCount() == 1 && secondChild->getOpCode().isLoadConst()); - if (insertType) + if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager)) + { + // IMPORTANT: secondChild actually references the J9Class of the array *elements* rather + // than the J9Class of the array itself; the new AOT infrastructure requires that + // classReg contain the J9Class of the array, so we have to actually construct a new + // loadaddr for that and then evaluate it instead of evaluating secondChild directly. + // Note that the original secondChild *must still be evaluated* as it will be used in + // the out-of-line code section. + TR::StaticSymbol *classSymbol = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address); + classSymbol->setStaticAddress(clazz); + classSymbol->setClassObject(); + + cg->evaluate(secondChild); + secondChild = TR::Node::createWithSymRef(TR::loadaddr, 0, + new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), classSymbol)); + secondChild->incReferenceCount(); + + classReg = cg->evaluate(secondChild); + } + else if (insertType) { classReg = cg->allocateRegister(); } @@ -7113,7 +7143,7 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG // Align the array if necessary. if (doublewordAlign && !comp->getOptions()->realTimeGC()) genAlignArray(node, iCursor, isVariableLen, resReg, objectSize, dataBegin, dataSizeReg, condReg, tmp5Reg, tmp4Reg, cg); - if (cg->comp()->compileRelocatableCode() && opCode == TR::anewarray) + if (cg->comp()->compileRelocatableCode() && (opCode == TR::anewarray || comp->getOption(TR_UseSymbolValidationManager))) genInitArrayHeader(node, iCursor, isVariableLen, clazz, classReg, resReg, zeroReg, condReg, enumReg, dataSizeReg, tmp5Reg, tmp4Reg, conditions, needZeroInit, cg); else genInitArrayHeader(node, iCursor, isVariableLen, clazz, NULL, resReg, zeroReg, condReg, enumReg, dataSizeReg, @@ -7426,11 +7456,14 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG if (cg->comp()->compileRelocatableCode() && (opCode == TR::New || opCode == TR::anewarray)) { firstInstruction = firstInstruction->getNext(); + TR_OpaqueClassBlock *classToValidate = clazz; + TR_RelocationRecordInformation *recordInfo = (TR_RelocationRecordInformation *) comp->trMemory()->allocateMemory(sizeof(TR_RelocationRecordInformation), heapAlloc); recordInfo->data1 = allocateSize; recordInfo->data2 = node->getInlinedSiteIndex(); recordInfo->data3 = (uintptr_t) callLabel; recordInfo->data4 = (uintptr_t) firstInstruction; + TR::SymbolReference * classSymRef; TR_ExternalRelocationTargetKind reloKind; @@ -7443,6 +7476,15 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG { classSymRef = node->getSecondChild()->getSymbolReference(); reloKind = TR_VerifyRefArrayForAlloc; + + if (comp->getOption(TR_UseSymbolValidationManager)) + classToValidate = comp->fej9()->getComponentClassFromArrayClass(classToValidate); + } + + if (comp->getOption(TR_UseSymbolValidationManager)) + { + TR_ASSERT_FATAL(classToValidate, "classToValidate should not be NULL, clazz=%p\n", clazz); + recordInfo->data5 = (uintptr_t)classToValidate; } cg->addExternalRelocation(new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(firstInstruction, (uint8_t *) classSymRef, (uint8_t *) recordInfo, reloKind, cg), @@ -7481,6 +7523,8 @@ TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeG else { cg->decReferenceCount(secondChild); + if (node->getSecondChild() != secondChild) + cg->decReferenceCount(node->getSecondChild()); if (classReg != secondChild->getRegister()) cg->stopUsingRegister(classReg); }