Path: blob/master/runtime/compiler/env/CHTable.cpp
6000 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 "env/CHTable.hpp"2324#include "codegen/CodeGenerator.hpp"25#include "env/FrontEnd.hpp"26#include "env/CompilerEnv.hpp"27#include "env/KnownObjectTable.hpp"28#include "compile/CompilationTypes.hpp"29#include "compile/ResolvedMethod.hpp"30#include "compile/VirtualGuard.hpp"31#include "control/Options.hpp"32#include "control/Options_inlines.hpp"33#include "control/Recompilation.hpp"34#include "control/RecompilationInfo.hpp"35#include "env/CompilerEnv.hpp"36#include "env/PersistentCHTable.hpp"37#include "env/PersistentInfo.hpp"38#include "env/jittypes.h"39#include "env/j9method.h"40#include "env/ClassTableCriticalSection.hpp"41#include "env/VMAccessCriticalSection.hpp"42#include "env/VMJ9.h"43#include "env/VerboseLog.hpp"44#include "il/MethodSymbol.hpp"45#include "il/ResolvedMethodSymbol.hpp"46#include "il/Symbol.hpp"47#include "il/SymbolReference.hpp"48#include "infra/Array.hpp"49#include "infra/Assert.hpp"50#include "infra/List.hpp"51#include "optimizer/PreExistence.hpp"52#if defined(J9VM_OPT_JITSERVER)53#include "env/j9methodServer.hpp"54#include "control/JITServerCompilationThread.hpp"55#endif /* defined(J9VM_OPT_JITSERVER) */5657void58TR_PreXRecompile::dumpInfo()59{60OMR::RuntimeAssumption::dumpInfo("TR_PreXRecompile");61TR_VerboseLog::write(" startPC=%p", _startPC);62}6364void65TR::PatchNOPedGuardSite::dumpInfo()66{67OMR::RuntimeAssumption::dumpInfo("TR::PatchNOPedGuardSite");68TR_VerboseLog::write(" location=%p destination=%p", _location, _destination);69}7071void72TR::PatchMultipleNOPedGuardSites::dumpInfo()73{74OMR::RuntimeAssumption::dumpInfo("TR::PatchMultipleNOPedGuardSites");75for (int i = 0; i < _patchSites->getSize(); ++i)76TR_VerboseLog::write(" %d location=%p destination=%p", i, _patchSites->getLocation(i), _patchSites->getDestination(i));77}7879void80TR_PatchJNICallSite::dumpInfo()81{82OMR::RuntimeAssumption::dumpInfo("TR_PatchJNICallSite");83TR_VerboseLog::write(" pc=%p", _pc );84}8586TR_PatchNOPedGuardSiteOnClassExtend *TR_PatchNOPedGuardSiteOnClassExtend::make(87TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, uint8_t *loc, uint8_t *dest, OMR::RuntimeAssumption **sentinel)88{89TR_PatchNOPedGuardSiteOnClassExtend *result = new (pm) TR_PatchNOPedGuardSiteOnClassExtend(pm, clazz, loc, dest);90result->addToRAT(pm, RuntimeAssumptionOnClassExtend, fe, sentinel);91return result;92}9394TR_PatchNOPedGuardSiteOnMethodOverride *TR_PatchNOPedGuardSiteOnMethodOverride::make(95TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueMethodBlock *method, uint8_t *loc, uint8_t *dest, OMR::RuntimeAssumption **sentinel)96{97TR_PatchNOPedGuardSiteOnMethodOverride *result = new (pm) TR_PatchNOPedGuardSiteOnMethodOverride(pm, method, loc, dest);98result->addToRAT(pm, RuntimeAssumptionOnMethodOverride, fe, sentinel);99return result;100}101102TR_PatchNOPedGuardSiteOnClassRedefinition *TR_PatchNOPedGuardSiteOnClassRedefinition::make(103TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, uint8_t *loc, uint8_t *dest, OMR::RuntimeAssumption **sentinel)104{105TR_PatchNOPedGuardSiteOnClassRedefinition *result = new (pm) TR_PatchNOPedGuardSiteOnClassRedefinition(pm, clazz, loc, dest);106result->addToRAT(pm, RuntimeAssumptionOnClassRedefinitionNOP, fe, sentinel);107return result;108}109110TR_PatchMultipleNOPedGuardSitesOnClassRedefinition *TR_PatchMultipleNOPedGuardSitesOnClassRedefinition::make(111TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, TR::PatchSites *sites, OMR::RuntimeAssumption **sentinel)112{113TR_PatchMultipleNOPedGuardSitesOnClassRedefinition *result = new (pm) TR_PatchMultipleNOPedGuardSitesOnClassRedefinition(pm, clazz, sites);114sites->addReference();115result->addToRAT(pm, RuntimeAssumptionOnClassRedefinitionNOP, fe, sentinel);116return result;117}118119TR_PatchNOPedGuardSiteOnStaticFinalFieldModification *TR_PatchNOPedGuardSiteOnStaticFinalFieldModification::make(120TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, uint8_t *loc, uint8_t *dest, OMR::RuntimeAssumption **sentinel)121{122TR_PatchNOPedGuardSiteOnStaticFinalFieldModification *result = new (pm) TR_PatchNOPedGuardSiteOnStaticFinalFieldModification(pm, clazz, loc, dest);123result->addToRAT(pm, RuntimeAssumptionOnStaticFinalFieldModification, fe, sentinel);124return result;125}126127TR_PatchMultipleNOPedGuardSitesOnStaticFinalFieldModification *TR_PatchMultipleNOPedGuardSitesOnStaticFinalFieldModification::make(128TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, TR::PatchSites *sites, OMR::RuntimeAssumption **sentinel)129{130TR_PatchMultipleNOPedGuardSitesOnStaticFinalFieldModification *result = new (pm) TR_PatchMultipleNOPedGuardSitesOnStaticFinalFieldModification(pm, clazz, sites);131sites->addReference();132result->addToRAT(pm, RuntimeAssumptionOnStaticFinalFieldModification, fe, sentinel);133return result;134}135136TR_PatchJNICallSite *TR_PatchJNICallSite::make(137TR_FrontEnd *fe, TR_PersistentMemory * pm, uintptr_t key, uint8_t *pc, OMR::RuntimeAssumption **sentinel)138{139TR_PatchJNICallSite *result = new (pm) TR_PatchJNICallSite(pm, key, pc);140result->addToRAT(pm, RuntimeAssumptionOnRegisterNative, fe, sentinel);141return result;142}143144TR_PreXRecompileOnClassExtend *TR_PreXRecompileOnClassExtend::make(145TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, uint8_t *startPC, OMR::RuntimeAssumption **sentinel)146{147TR_PreXRecompileOnClassExtend *result = new (pm) TR_PreXRecompileOnClassExtend(pm, clazz, startPC);148result->addToRAT(pm, RuntimeAssumptionOnClassExtend, fe, sentinel);149return result;150}151152TR_PreXRecompileOnMethodOverride *TR_PreXRecompileOnMethodOverride::make(153TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueMethodBlock *method, uint8_t *startPC, OMR::RuntimeAssumption **sentinel)154{155TR_PreXRecompileOnMethodOverride *result = new (pm) TR_PreXRecompileOnMethodOverride(pm, method, startPC);156result->addToRAT(pm, RuntimeAssumptionOnMethodOverride, fe, sentinel);157return result;158}159160TR_PatchNOPedGuardSiteOnMutableCallSiteChange *TR_PatchNOPedGuardSiteOnMutableCallSiteChange::make(161TR_FrontEnd *fe, TR_PersistentMemory *pm, uintptr_t key, uint8_t *location, uint8_t *destination, OMR::RuntimeAssumption **sentinel)162{163TR_PatchNOPedGuardSiteOnMutableCallSiteChange *result = new (pm) TR_PatchNOPedGuardSiteOnMutableCallSiteChange(pm, key, location, destination);164result->addToRAT(pm, RuntimeAssumptionOnMutableCallSiteChange, fe, sentinel);165return result;166}167168bool TR_CHTable::recompileOnClassExtend(TR::Compilation *c, TR_OpaqueClassBlock * classId)169{170// return true or false171// depending on whether the class was added to the list172//173c->setUsesPreexistence(true);174if (!_classes)175_classes = new (c->trHeapMemory()) TR_Array<TR_OpaqueClassBlock *>(c->trMemory(), 8);176if (!_classes->contains(classId))177_classes->add(classId);178else return false;179return true;180}181182183bool TR_CHTable::recompileOnNewClassExtend(TR::Compilation *c, TR_OpaqueClassBlock * classId)184{185// return true or false186// depending on whether the class was added to the list187//188c->setUsesPreexistence(true);189if (!_classesThatShouldNotBeNewlyExtended)190_classesThatShouldNotBeNewlyExtended = new (c->trHeapMemory()) TR_Array<TR_OpaqueClassBlock *>(c->trMemory(), 8);191if (!_classesThatShouldNotBeNewlyExtended->contains(classId))192_classesThatShouldNotBeNewlyExtended->add(classId);193else return false;194return true;195}196197198199bool TR_CHTable::recompileOnMethodOverride(TR::Compilation *c, TR_ResolvedMethod *method)200{201// return true or false202// depending on whether the method was added to the list203//204c->setUsesPreexistence(true);205if (!_preXMethods)206_preXMethods = new (c->trHeapMemory()) TR_Array<TR_ResolvedMethod*>(c->trMemory(), 16);207208int32_t last = _preXMethods->lastIndex();209bool addIt = true;210for (int32_t i = 0; i <= last; ++i)211{212if (_preXMethods->element(i)->getPersistentIdentifier() == method->getPersistentIdentifier())213{214addIt = false;215break;216}217}218219if (addIt)220_preXMethods->add(method);221else222return false;223224return true;225}226227228// Must hold classTableMonitor when calling this method229void TR_CHTable::cleanupNewlyExtendedInfo(TR::Compilation *comp)230{231if (_classesThatShouldNotBeNewlyExtended)232{233TR_PersistentCHTable *table = comp->getPersistentInfo()->getPersistentCHTable();234int32_t last = _classesThatShouldNotBeNewlyExtended->lastIndex();235for (int32_t i = 0; i <= last; ++i)236{237TR_OpaqueClassBlock * classId = _classesThatShouldNotBeNewlyExtended->element(i);238TR_PersistentClassInfo * cl = table->findClassInfo(classId);239// The class may have been unloaded during this compilation and the search may return NULL240// This method is called even if we abort the compilation. Hence, killing the241// compilation after a class unload (which we already do) is not enough242// If we get really unlucky a new class could be unloaded exactly in the place of the243// unloaded one (the window of time is very small for this to occur). However, resetting244// the flag for the newly loaded class is not going to create any problems (it's245// supposed to be reset to start with)246if (cl)247cl->resetShouldNotBeNewlyExtended(comp->getCompThreadID());248}249}250}251252253bool TR_CHTable::canSkipCommit(TR::Compilation *comp)254{255return comp->compileRelocatableCode() ||256(comp->getVirtualGuards().empty() &&257comp->getSideEffectGuardPatchSites()->empty() &&258!_preXMethods && !_classes && !_classesThatShouldNotBeNewlyExtended);259}260261262// Returning false here will fail this compilation!263//264bool TR_CHTable::commit(TR::Compilation *comp)265{266#if defined(J9VM_OPT_JITSERVER)267if (comp->isOutOfProcessCompilation())268{269return true; // Handled in outOfProcessCompilationEnd instead270}271#endif /* defined(J9VM_OPT_JITSERVER) */272if (canSkipCommit(comp))273return true;274275TR::list<TR_VirtualGuard*> &vguards = comp->getVirtualGuards();276TR::list<TR_VirtualGuardSite*> *sideEffectPatchSites = comp->getSideEffectGuardPatchSites();277278cleanupNewlyExtendedInfo(comp);279if (comp->getFailCHTableCommit())280return false;281282TR_PersistentCHTable *table = comp->getPersistentInfo()->getPersistentCHTable();283TR_ResolvedMethod *currentMethod = comp->getCurrentMethod();284uint8_t *startPC = comp->cg()->getCodeStart();285TR_Hotness hotness = comp->getMethodHotness();286287if (_preXMethods)288{289int32_t last = _preXMethods->lastIndex(), i;290for (i = 0; i <= last; ++i)291if (_preXMethods->element(i)->virtualMethodIsOverridden())292return false;293294for (i = 0; i <= last; ++i)295{296TR_ResolvedMethod *resolvedMethod = _preXMethods->element(i);297TR_OpaqueMethodBlock *method = resolvedMethod->getPersistentIdentifier();298TR_PreXRecompileOnMethodOverride::make(comp->fe(), comp->trPersistentMemory(), method, startPC, comp->getMetadataAssumptionList());299comp->setHasMethodOverrideAssumptions();300}301}302303if (_classes)304{305int32_t last = _classes->lastIndex();306for (int32_t i = 0; i <= last; ++i)307{308TR_OpaqueClassBlock * classId = _classes->element(i);309310// check if we may have already added this class to the persistent table311//312bool alreadyAdded = false;313for (int32_t j = 0; j < i && !alreadyAdded; ++j)314{315TR_OpaqueClassBlock * other = _classes->element(j);316if (other == classId)317alreadyAdded = true;318}319320if (!alreadyAdded)321{322if (comp->fe()->classHasBeenExtended(classId))323return false;324325TR_PreXRecompileOnClassExtend::make(comp->fe(), comp->trPersistentMemory(), classId, startPC, comp->getMetadataAssumptionList());326comp->setHasClassExtendAssumptions();327}328}329}330331if (_classesThatShouldNotBeNewlyExtended)332{333int32_t last = _classesThatShouldNotBeNewlyExtended->lastIndex();334335// keep a list of classes that were set visited so that we can336// easily reset the visited flag later-on337VisitTracker tracker(comp->trMemory());338for (int32_t i = 0; i <= last; ++i)339{340TR_OpaqueClassBlock * classId = _classesThatShouldNotBeNewlyExtended->element(i);341TR_PersistentClassInfo * cl = table->findClassInfo(classId);342if (cl && !cl->hasBeenVisited()) // is it possible to have cl==0343{344tracker.visit(cl);345}346}347348bool invalidAssumption = false;349auto it = tracker.iterator();350for (auto cl = it.getFirst(); cl; cl = it.getNext())351{352// If the class has been extended verify that was included in the original list353// Otherwise it means that the extension happened afterwards and we should fail this compilation354if (comp->fe()->classHasBeenExtended(cl->getClassId()))355{356for (TR_SubClass *subClass = cl->getFirstSubclass(); subClass; subClass = subClass->getNext())357{358TR_PersistentClassInfo *subClassInfo = subClass->getClassInfo();359if (!subClassInfo->hasBeenVisited())360{361invalidAssumption = true;362break;363}364}365}366367if (invalidAssumption)368break;369370TR_PreXRecompileOnClassExtend::make(comp->fe(), comp->trPersistentMemory(), cl->getClassId(), startPC, comp->getMetadataAssumptionList());371comp->setHasClassExtendAssumptions();372}373374if (invalidAssumption) return false;375} // if (_classesThatShouldNotBeNewlyExtended)376377// Check if the assumptions for static final field are still valid378// Returning false will cause CHTable opts to be disabled in the next compilation of this method,379// thus we abort the compilation here to avoid causing performance issues380TR_Array<TR_OpaqueClassBlock*> *clazzesOnStaticFinalFieldModification = comp->getClassesForStaticFinalFieldModification();381for (int i = 0; i < clazzesOnStaticFinalFieldModification->size(); ++i)382{383TR_OpaqueClassBlock* clazz = (*clazzesOnStaticFinalFieldModification)[i];384if (TR::Compiler->cls.classHasIllegalStaticFinalFieldModification(clazz))385{386if (TR::Options::isAnyVerboseOptionSet(TR_VerboseRuntimeAssumptions, TR_VerboseCompileEnd, TR_VerbosePerformance, TR_VerboseCompFailure))387{388TR_VerboseLog::writeLineLocked(TR_Vlog_FAILURE, "Failure while commiting static final field assumption for class %p for %s", clazz, comp->signature());389}390comp->failCompilation<TR::CompilationInterrupted>("Compilation interrupted: Static final field of a class has been modified");391}392}393394if (!vguards.empty())395{396static bool dontGroupOSRAssumptions = (feGetEnv("TR_DontGroupOSRAssumptions") != NULL);397if (!dontGroupOSRAssumptions)398commitOSRVirtualGuards(comp, vguards);399400for (auto info = vguards.begin(); info != vguards.end(); ++info)401{402List<TR_VirtualGuardSite> &sites = (*info)->getNOPSites();403if (sites.isEmpty())404continue;405406// Commit the virtual guard itself407//408commitVirtualGuard(*info, sites, table, comp);409410// Commit any inner guards that are assuming on this guard411//412ListIterator<TR_InnerAssumption> it(&((*info)->getInnerAssumptions()));413for (TR_InnerAssumption *inner = it.getFirst(); inner; inner = it.getNext())414commitVirtualGuard(inner->_guard, sites, table, comp);415}416}417418if (!sideEffectPatchSites->empty())419table->commitSideEffectGuards(comp);420421return true;422}423424void425TR_CHTable::commitOSRVirtualGuards(TR::Compilation *comp, TR::list<TR_VirtualGuard*> &vguards)426{427// Count patch sites with OSR assumptions428int osrSites = 0;429TR_VirtualGuardSite *onlySite = NULL;430for (auto info = vguards.begin(); info != vguards.end(); ++info)431{432if ((*info)->getKind() == TR_OSRGuard || (*info)->mergedWithOSRGuard())433{434List<TR_VirtualGuardSite> &sites = (*info)->getNOPSites();435if (sites.getSize() > 0)436onlySite = sites.getListHead()->getData();437osrSites += sites.getSize();438}439}440441TR_Array<TR_OpaqueClassBlock*> *clazzesForOSRRedefinition = comp->getClassesForOSRRedefinition();442TR_Array<TR_OpaqueClassBlock*> *clazzesForStaticFinalFieldModification = comp->getClassesForStaticFinalFieldModification();443if (osrSites == 0444|| (clazzesForOSRRedefinition->size() == 0445&& clazzesForStaticFinalFieldModification->size() == 0))446{447return;448}449else if (osrSites == 1)450{451// Only one patch point, create an assumption for each class452for (int i = 0; i < clazzesForOSRRedefinition->size(); ++i)453TR_PatchNOPedGuardSiteOnClassRedefinition454::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForOSRRedefinition)[i], onlySite->getLocation(), onlySite->getDestination(), comp->getMetadataAssumptionList());455456for (int i = 0; i < clazzesForStaticFinalFieldModification->size(); ++i)457TR_PatchNOPedGuardSiteOnStaticFinalFieldModification458::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForStaticFinalFieldModification)[i], onlySite->getLocation(), onlySite->getDestination(), comp->getMetadataAssumptionList());459}460else if (osrSites > 1)461{462// Several points to patch, create collection463TR::PatchSites *points = new (comp->trPersistentMemory()) TR::PatchSites(comp->trPersistentMemory(), osrSites);464for (auto info = vguards.begin(); info != vguards.end(); ++info)465{466if ((*info)->getKind() == TR_OSRGuard || (*info)->mergedWithOSRGuard())467{468List<TR_VirtualGuardSite> &sites = (*info)->getNOPSites();469ListIterator<TR_VirtualGuardSite> it(&sites);470for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())471points->add(site->getLocation(), site->getDestination());472}473}474475for (int i = 0; i < clazzesForOSRRedefinition->size(); ++i)476TR_PatchMultipleNOPedGuardSitesOnClassRedefinition477::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForOSRRedefinition)[i], points, comp->getMetadataAssumptionList());478479for (int i = 0; i < clazzesForStaticFinalFieldModification->size(); ++i)480TR_PatchMultipleNOPedGuardSitesOnStaticFinalFieldModification481::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForStaticFinalFieldModification)[i], points, comp->getMetadataAssumptionList());482}483484if (clazzesForOSRRedefinition->size() > 0)485comp->setHasClassRedefinitionAssumptions();486return;487}488489void490TR_CHTable::commitVirtualGuard(TR_VirtualGuard *info, List<TR_VirtualGuardSite> &sites,491TR_PersistentCHTable *table, TR::Compilation *comp)492{493// If this is an OSR guard or another kind that has been marked as necessary to patch494// in OSR, add a runtime assumption for every class that generated fear495//496if (info->getKind() == TR_OSRGuard || info->mergedWithOSRGuard())497{498static bool dontGroupOSRAssumptions = (feGetEnv("TR_DontGroupOSRAssumptions") != NULL);499if (dontGroupOSRAssumptions)500{501TR_Array<TR_OpaqueClassBlock*> *clazzesForRedefinition = comp->getClassesForOSRRedefinition();502TR_Array<TR_OpaqueClassBlock*> *clazzesForStaticFinalFieldModification = comp->getClassesForStaticFinalFieldModification();503504if (clazzesForRedefinition || clazzesForStaticFinalFieldModification)505{506ListIterator<TR_VirtualGuardSite> it(&sites);507for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())508{509for (uint32_t i = 0; i < clazzesForRedefinition->size(); ++i)510TR_PatchNOPedGuardSiteOnClassRedefinition511::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForRedefinition)[i], site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());512513if (clazzesForRedefinition->size() > 0)514comp->setHasClassRedefinitionAssumptions();515516// Add assumption for static final field folding517for (uint32_t i = 0; i < clazzesForStaticFinalFieldModification->size(); ++i)518TR_PatchNOPedGuardSiteOnStaticFinalFieldModification519::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForStaticFinalFieldModification)[i], site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());520}521}522}523524// if it's not real OSR guard then we need to register525// both the OSR site and the guard526if (!info->mergedWithOSRGuard())527return;528if (!info->isNopable())529return;530}531532TR::SymbolReference *symRef = info->getSymbolReference();533TR::MethodSymbol *methodSymbol = symRef->getSymbol()->castToMethodSymbol();534TR::ResolvedMethodSymbol *resolvedMethodSymbol = methodSymbol->getResolvedMethodSymbol();535TR_ResolvedMethod *guardedMethod = 0;536TR_OpaqueClassBlock *guardedClass = 0;537bool nopAssumptionIsValid = true;538int32_t cpIndex = symRef->getCPIndex();539TR_ResolvedMethod *owningMethod = symRef->getOwningMethod(comp);540541if ((info->getKind() == TR_HCRGuard) || info->mergedWithHCRGuard())542{543guardedClass = info->getThisClass();544ListIterator<TR_VirtualGuardSite> it(&sites);545for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())546{547TR_ASSERT(site->getLocation(), "assertion failure");548TR_PatchNOPedGuardSiteOnClassRedefinition549::make(comp->fe(), comp->trPersistentMemory(), guardedClass, site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());550comp->setHasClassRedefinitionAssumptions();551}552// if it's not real HCR guard then we need to register553// both the HCR site and the guard554if (!info->mergedWithHCRGuard())555return;556if (!info->isNopable())557return;558}559560if (info->getKind() == TR_DummyGuard)561{562/* nothing to do */563}564else if (info->getKind() == TR_MutableCallSiteTargetGuard)565{566static char *dontInvalidateMCSTargetGuards = feGetEnv("TR_dontInvalidateMCSTargetGuards");567if (!dontInvalidateMCSTargetGuards)568{569#if defined(J9VM_OPT_JITSERVER)570// JITServer KOT: At the moment this method is called only by TR_CHTable::commit().571// TR_CHTable::commit() already checks comp->isOutOfProcessCompilation().572// Adding the following check as a precaution in case commitVirtualGuard() is called573// outside TR_CHTable::commit() in the future.574TR_ASSERT(!comp->isOutOfProcessCompilation(), "TR_CHTable::commitVirtualGuard() should not be called at the server\n");575#endif /* defined(J9VM_OPT_JITSERVER) */576uintptr_t *mcsReferenceLocation = info->mutableCallSiteObject();577TR::KnownObjectTable *knot = comp->getKnownObjectTable();578TR_ASSERT(knot, "MutableCallSiteTargetGuard requires the Known Object Table");579void *cookiePointer = comp->trPersistentMemory()->allocatePersistentMemory(1);580uintptr_t potentialCookie = (uintptr_t)(uintptr_t)cookiePointer;581uintptr_t cookie = 0;582583TR::KnownObjectTable::Index currentIndex;584585{586TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());587TR::VMAccessCriticalSection invalidateMCSTargetGuards(fej9);588currentIndex = fej9->mutableCallSiteEpoch(comp, *mcsReferenceLocation);589if (info->mutableCallSiteEpoch() == currentIndex)590cookie = fej9->mutableCallSiteCookie(*mcsReferenceLocation, potentialCookie);591else592nopAssumptionIsValid = false;593}594595if (cookie != potentialCookie)596comp->trPersistentMemory()->freePersistentMemory(cookiePointer);597598if (nopAssumptionIsValid)599{600ListIterator<TR_VirtualGuardSite> it(&sites);601for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())602{603TR_ASSERT(site->getLocation(), "assertion failure");604TR_PatchNOPedGuardSiteOnMutableCallSiteChange605::make(comp->fe(), comp->trPersistentMemory(), cookie, site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());606}607}608else if (comp->getOption(TR_TraceCG))609traceMsg(comp, "MutableCallSiteTargetGuard is already invalid. Expected epoch: obj%d Found: obj%d\n", info->mutableCallSiteEpoch(), currentIndex);610}611}612else if ((info->getKind() == TR_MethodEnterExitGuard) || (info->getKind() == TR_DirectMethodGuard))613{614/* nothing to do */615}616else if (info->getKind() == TR_BreakpointGuard)617{618if (comp->getOption(TR_DisableNopBreakpointGuard))619return;620TR_ResolvedMethod *breakpointedMethod = comp->getInlinedResolvedMethod(info->getCalleeIndex());621TR_OpaqueMethodBlock *method = breakpointedMethod->getPersistentIdentifier();622if (comp->fej9()->isMethodBreakpointed(method))623{624nopAssumptionIsValid = false;625}626else627{628ListIterator<TR_VirtualGuardSite> it(&sites);629for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())630{631TR_PatchNOPedGuardSiteOnMethodBreakPoint632::make(comp->fe(), comp->trPersistentMemory(), method, site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());633}634}635}636else if (info->getKind() == TR_ArrayStoreCheckGuard)637{638guardedClass = info->getThisClass();639if (comp->fe()->classHasBeenExtended(guardedClass))640nopAssumptionIsValid = false;641}642else if (!resolvedMethodSymbol)643{644TR_ASSERT(methodSymbol->isInterface() && info->getKind() == TR_InterfaceGuard, "assertion failure");645TR_OpaqueClassBlock *thisClass = info->getThisClass();646TR_ASSERT(thisClass, "assertion failure");647648TR_ResolvedMethod *implementer = table->findSingleImplementer(thisClass, cpIndex, owningMethod, comp, true, TR_yes);649if (!implementer ||650(info->getTestType() == TR_VftTest && comp->fe()->classHasBeenExtended(implementer->containingClass())))651nopAssumptionIsValid = false;652else653TR_ClassQueries::addAnAssumptionForEachSubClass(table, table->findClassInfo(thisClass), sites, comp);654}655else if (info->getKind() == TR_NonoverriddenGuard && info->getTestType() != TR_VftTest)656{657TR_ASSERT(info->getTestType() == TR_NonoverriddenTest, "unexpected test type for a non-overridden guard.");658659guardedMethod = resolvedMethodSymbol->getResolvedMethod();660if (guardedMethod->virtualMethodIsOverridden())661nopAssumptionIsValid = false;662}663else if ((!info->isInlineGuard() &&664!TR::Compiler->cls.isAbstractClass(comp, resolvedMethodSymbol->getResolvedMethod()->containingClass())) ||665(info->isInlineGuard() && info->getKind() == TR_HierarchyGuard && info->getTestType() == TR_MethodTest))666{667guardedMethod = resolvedMethodSymbol->getResolvedMethod();668TR_ASSERT(guardedMethod, "Method must have been found when creating assumption\n");669670TR_DevirtualizedCallInfo *dc;671TR_OpaqueClassBlock *thisClass = info->isInlineGuard() ? info->getThisClass()672: ((dc = comp->findDevirtualizedCall(info->getCallNode())) ? dc->_thisType :673guardedMethod->classOfMethod());674675//temp fix for defect 57599 until we find root cause676if (table->isOverriddenInThisHierarchy(guardedMethod, thisClass, symRef->getOffset(), comp))677nopAssumptionIsValid = false;678}679else if (info->isInlineGuard() &&680info->getTestType() == TR_VftTest &&681(info->getKind() == TR_NonoverriddenGuard || info->getKind() == TR_HierarchyGuard))682{683guardedClass = info->getThisClass();684if (comp->fe()->classHasBeenExtended(guardedClass))685nopAssumptionIsValid = false;686}687else if ((!info->isInlineGuard() &&688TR::Compiler->cls.isAbstractClass(comp, resolvedMethodSymbol->getResolvedMethod()->containingClass())) ||689(info->isInlineGuard() && info->getKind() == TR_AbstractGuard && info->getTestType() == TR_MethodTest))690{691TR_OpaqueClassBlock *thisClass = info->isInlineGuard() ? thisClass = info->getThisClass()692: resolvedMethodSymbol->getResolvedMethod()->containingClass();693if (table->findSingleAbstractImplementer(thisClass, symRef->getOffset(), owningMethod, comp, true))694TR_ClassQueries::addAnAssumptionForEachSubClass(table, table->findClassInfo(thisClass), sites, comp);695else696nopAssumptionIsValid = false;697}698else699{700TR_ASSERT(false, "should be unreachable");701nopAssumptionIsValid = false;702}703704if (nopAssumptionIsValid)705{706ListIterator<TR_VirtualGuardSite> it(&sites);707for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())708{709TR_ASSERT(site->getLocation(), "assertion failure");710if (guardedClass)711{712TR_PatchNOPedGuardSiteOnClassExtend713::make(comp->fe(), comp->trPersistentMemory(), guardedClass, site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());714comp->setHasClassExtendAssumptions();715}716if (guardedMethod)717{718TR_PatchNOPedGuardSiteOnMethodOverride719::make(comp->fe(), comp->trPersistentMemory(), guardedMethod->getPersistentIdentifier(),720site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());721comp->setHasMethodOverrideAssumptions();722}723}724}725else // assumption is invalid726{727ListIterator<TR_VirtualGuardSite> it(&sites);728for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())729{730if (comp->getOption(TR_TraceCG))731traceMsg(comp, " Patching %p to %p\n", site->getLocation(), site->getDestination());732TR::PatchNOPedGuardSite::compensate(0, site->getLocation(), site->getDestination());733}734}735}736737#if defined(J9VM_OPT_JITSERVER)738VirtualGuardInfoForCHTable getImportantVGuardInfo(TR::Compilation *comp, TR_VirtualGuard *vguard)739{740VirtualGuardInfoForCHTable info;741info._testType = vguard->getTestType();742info._kind = vguard->getKind();743info._calleeIndex = vguard->getCalleeIndex();744info._byteCodeIndex = vguard->getByteCodeIndex();745746// info below is not used if there are no nop sites747if (vguard->getNOPSites().isEmpty())748return info;749750TR::SymbolReference *symRef = vguard->getSymbolReference();751if (symRef)752{753TR::MethodSymbol *methodSymbol = symRef->getSymbol()->castToMethodSymbol();754TR::ResolvedMethodSymbol *resolvedMethodSymbol = methodSymbol->getResolvedMethodSymbol();755info._hasResolvedMethodSymbol = resolvedMethodSymbol != NULL;756info._cpIndex = symRef->getCPIndex();757info._owningMethod = static_cast<TR_ResolvedJ9JITServerMethod*>(symRef->getOwningMethod(comp))->getRemoteMirror();758info._isInterface = methodSymbol->isInterface();759info._guardedMethod = resolvedMethodSymbol ? static_cast<TR_ResolvedJ9JITServerMethod*>(resolvedMethodSymbol->getResolvedMethod())->getRemoteMirror() : NULL;760info._offset = symRef->getOffset();761762info._isInlineGuard = vguard->isInlineGuard();763TR_DevirtualizedCallInfo *dc;764765if (resolvedMethodSymbol)766info._guardedMethodThisClass = vguard->isInlineGuard()767? vguard->getThisClass()768: ((dc = comp->findDevirtualizedCall(vguard->getCallNode()))769? dc->_thisType770: resolvedMethodSymbol->getResolvedMethod()->classOfMethod());771}772773info._thisClass = vguard->getThisClass();774info._mergedWithHCRGuard = vguard->mergedWithHCRGuard();775info._mergedWithOSRGuard = vguard->mergedWithOSRGuard();776777info._mutableCallSiteObject = info._kind == TR_MutableCallSiteTargetGuard ? vguard->mutableCallSiteObject() : NULL;778info._mutableCallSiteEpoch = info._kind == TR_MutableCallSiteTargetGuard ? vguard->mutableCallSiteEpoch() : -1;779780info._inlinedResolvedMethod = info._kind == TR_BreakpointGuard781? static_cast<TR_ResolvedJ9JITServerMethod *>(comp->getInlinedResolvedMethod(info._calleeIndex))->getRemoteMirror()782: NULL;783784return info;785}786787CHTableCommitData788TR_CHTable::computeDataForCHTableCommit(TR::Compilation *comp)789{790// collect info from TR_CHTable791std::vector<TR_OpaqueClassBlock*> classes = _classes792? std::vector<TR_OpaqueClassBlock*>(&(_classes->element(0)), (&(_classes->element(_classes->lastIndex()))) + 1)793: std::vector<TR_OpaqueClassBlock*>();794std::vector<TR_OpaqueClassBlock*> classesThatShouldNotBeNewlyExtended = _classesThatShouldNotBeNewlyExtended795? std::vector<TR_OpaqueClassBlock*>(&_classesThatShouldNotBeNewlyExtended->element(0), &_classesThatShouldNotBeNewlyExtended->element(_classesThatShouldNotBeNewlyExtended->lastIndex()) + 1)796: std::vector<TR_OpaqueClassBlock*>();797std::vector<TR_ResolvedMethod*> preXMethods(_preXMethods ? _preXMethods->size() : 0);798for (size_t i = 0; i < preXMethods.size(); i++)799{800TR_ResolvedMethod *method = _preXMethods->element(i);801TR_ResolvedJ9JITServerMethod *JITServerMethod = static_cast<TR_ResolvedJ9JITServerMethod*>(method);802preXMethods[i] = JITServerMethod->getRemoteMirror();803}804805cleanupNewlyExtendedInfo(comp);806807// collect virtual guard info808TR::list<TR_VirtualGuard*> &vguards = comp->getVirtualGuards();809std::vector<VirtualGuardForCHTable> serialVGuards;810serialVGuards.reserve(vguards.size());811812for (TR_VirtualGuard* vguard : vguards)813{814VirtualGuardInfoForCHTable info = getImportantVGuardInfo(comp, vguard);815816std::vector<TR_VirtualGuardSite> nopSites;817818{819List<TR_VirtualGuardSite> &sites = vguard->getNOPSites();820ListIterator<TR_VirtualGuardSite> it(&sites);821for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())822nopSites.push_back(*site);823}824825std::vector<VirtualGuardInfoForCHTable> innerAssumptions;826{827ListIterator<TR_InnerAssumption> it(&vguard->getInnerAssumptions());828for (TR_InnerAssumption *inner = it.getFirst(); inner; inner = it.getNext())829{830VirtualGuardInfoForCHTable innerInfo = getImportantVGuardInfo(comp, vguard);831innerAssumptions.push_back(innerInfo);832}833}834835serialVGuards.push_back(std::make_tuple(info, nopSites, innerAssumptions));836}837838TR::list<TR_VirtualGuardSite*> &sideEffectPatchSites = *comp->getSideEffectGuardPatchSites();839std::vector<TR_VirtualGuardSite> sideEffectPatchSitesVec;840for (TR_VirtualGuardSite *site : sideEffectPatchSites)841sideEffectPatchSitesVec.push_back(*site);842843FlatClassLoadCheck compClassesThatShouldNotBeLoaded;844for (TR_ClassLoadCheck * clc = comp->getClassesThatShouldNotBeLoaded()->getFirst(); clc; clc = clc->getNext())845compClassesThatShouldNotBeLoaded.emplace_back(std::string(clc->_name, clc->_length));846847FlatClassExtendCheck compClassesThatShouldNotBeNewlyExtended;848for (TR_ClassExtendCheck * cec = comp->getClassesThatShouldNotBeNewlyExtended()->getFirst(); cec; cec = cec->getNext())849compClassesThatShouldNotBeNewlyExtended.emplace_back(cec->_clazz);850851auto *compClassesForOSRRedefinition = comp->getClassesForOSRRedefinition();852std::vector<TR_OpaqueClassBlock*> classesForOSRRedefinition(compClassesForOSRRedefinition->size());853for (int i = 0; i < compClassesForOSRRedefinition->size(); ++i)854classesForOSRRedefinition[i] = (*compClassesForOSRRedefinition)[i];855856auto *compClassesForStaticFinalFieldModification = comp->getClassesForStaticFinalFieldModification();857std::vector<TR_OpaqueClassBlock*> classesForStaticFinalFieldModification(compClassesForStaticFinalFieldModification->size());858for (int i = 0; i < compClassesForStaticFinalFieldModification->size(); ++i)859classesForStaticFinalFieldModification[i] = (*compClassesForStaticFinalFieldModification)[i];860861uint8_t *startPC = comp->cg()->getCodeStart();862863return std::make_tuple(classes,864classesThatShouldNotBeNewlyExtended,865preXMethods,866sideEffectPatchSitesVec,867serialVGuards,868compClassesThatShouldNotBeLoaded,869compClassesThatShouldNotBeNewlyExtended,870classesForOSRRedefinition,871classesForStaticFinalFieldModification,872startPC);873}874#endif /* defined(J9VM_OPT_JITSERVER) */875876// class used to collect all different implementations of a method877class CollectImplementors : public TR_SubclassVisitor878{879public:880CollectImplementors(TR::Compilation * comp, TR_OpaqueClassBlock *topClassId, TR_ResolvedMethod **implArray, int32_t maxCount,881TR_ResolvedMethod *callerMethod, int32_t slotOrIndex, TR_YesNoMaybe useGetResolvedInterfaceMethod = TR_maybe) : TR_SubclassVisitor(comp)882{883_comp = comp;884_topClassId = topClassId;885_implArray = implArray;886_callerMethod = callerMethod;887_maxCount = maxCount;888_slotOrIndex = slotOrIndex;889_count = 0;890_topClassIsInterface = TR::Compiler->cls.isInterfaceClass(comp, topClassId);891_maxNumVisitedSubClasses = comp->getOptions()->getMaxNumVisitedSubclasses();892_numVisitedSubClasses = 0;893_useGetResolvedInterfaceMethod = useGetResolvedInterfaceMethod;894}895896virtual bool visitSubclass(TR_PersistentClassInfo *cl);897int32_t getCount() const { return _count;}898bool isInterface();899900protected:901bool addImplementor(TR_ResolvedMethod *implementor);902903TR_OpaqueClassBlock * _topClassId;904TR_ResolvedMethod ** _implArray;905TR_ResolvedMethod * _callerMethod;906int32_t _maxCount;907int32_t _slotOrIndex;908int32_t _count;909bool _topClassIsInterface;910int32_t _maxNumVisitedSubClasses;911int32_t _numVisitedSubClasses;912TR_YesNoMaybe _useGetResolvedInterfaceMethod;913};// end of class CollectImplementors914915bool916CollectImplementors::isInterface()917{918bool useGetResolvedInterfaceMethod = _topClassIsInterface;919920// refine if requested by a caller921if (_useGetResolvedInterfaceMethod != TR_maybe)922useGetResolvedInterfaceMethod = _useGetResolvedInterfaceMethod == TR_yes ? true : false;923return useGetResolvedInterfaceMethod;924}925926bool927CollectImplementors::visitSubclass(TR_PersistentClassInfo *cl)928{929TR_OpaqueClassBlock *classId = cl->getClassId();930// verify that our subclass meets all conditions931if (TR::Compiler->cls.isConcreteClass(comp(), classId))932{933int32_t length;934char *clazzName = TR::Compiler->cls.classNameChars(comp(), classId, length);935TR_ResolvedMethod *method;936937if (isInterface())938{939method = _callerMethod->getResolvedInterfaceMethod(comp(), classId, _slotOrIndex);940}941else942{943method = _callerMethod->getResolvedVirtualMethod(comp(), classId, _slotOrIndex);944}945946++_numVisitedSubClasses;947if ((_numVisitedSubClasses > _maxNumVisitedSubClasses) || !method)948{949// set count greater than maxCount, to indicate failure and force exit950_count = _maxCount + 1;951stopTheWalk();952return false;953}954955bool added = addImplementor(method);956if (added && _count >= _maxCount)957stopTheWalk();958}959return true;960}961962bool963CollectImplementors::addImplementor(TR_ResolvedMethod *implementor)964{965TR_ASSERT_FATAL(_count < _maxCount, "Max implementor count exceeded: _maxCount = %d, _count = %d", _maxCount, _count);966967// cannot add an unresolved implementor968if (!implementor)969return false;970// check to see if there are any duplicates971int32_t i;972for (i = 0; i < _count; ++i)973if (implementor->isSameMethod(_implArray[i]))974return false; // we already listed this method975// brand new implementor976_implArray[_count++] = implementor;977return true;978}979980class CollectCompiledImplementors : public CollectImplementors981{982public:983CollectCompiledImplementors(TR::Compilation * comp, TR_OpaqueClassBlock *topClassId, TR_ResolvedMethod **implArray, int32_t maxCount,984TR_ResolvedMethod *callerMethod, int32_t slotOrIndex, TR_Hotness hotness, TR_YesNoMaybe useGetResolvedInterfaceMethod = TR_maybe) : CollectImplementors(comp, topClassId, implArray, maxCount+1, callerMethod, slotOrIndex, useGetResolvedInterfaceMethod)985{986_hotness = hotness;987}988virtual bool visitSubclass(TR_PersistentClassInfo *cl);989private:990TR_Hotness _hotness;991};992993bool CollectCompiledImplementors::visitSubclass(TR_PersistentClassInfo *cl)994{995int32_t currentCount = _count;996if (CollectImplementors::visitSubclass(cl))997{998if (currentCount < _count)999{1000if (!TR::Compiler->mtd.isCompiledMethod((_implArray[_count-1])->getPersistentIdentifier()))1001{1002_count -= 1;1003}1004else1005{1006TR_PersistentJittedBodyInfo * bodyInfo = ((TR_ResolvedJ9Method*) _implArray[_count - 1])->getExistingJittedBodyInfo();1007if (!bodyInfo || bodyInfo->getHotness() < _hotness)1008{1009_count -= 1;1010}1011if (_count >= _maxCount - 1)1012{1013stopTheWalk();1014}1015}1016}1017return true;1018}1019return false;1020}10211022void1023TR_ClassQueries::getSubClasses(TR_PersistentClassInfo *clazz,1024TR_ScratchList<TR_PersistentClassInfo> &list, TR_FrontEnd *fe, bool locked)1025{1026TR::ClassTableCriticalSection getSubClasses(fe, locked);10271028for (TR_SubClass * subClass = clazz->_subClasses.getFirst(); subClass; subClass = subClass->getNext())1029list.add(subClass->getClassInfo());1030}103110321033// this method will return the number of implementers stored in the given implArray1034// NOTE: if the number is larger than maxCount, it means that the collection failed1035// and we should not check the content of the implArray as it may contain bogus data1036int32_t1037TR_ClassQueries::collectImplementorsCapped(TR_PersistentClassInfo *clazz,1038TR_ResolvedMethod **implArray,1039int32_t maxCount, int32_t slotOrIndex,1040TR_ResolvedMethod *callerMethod,1041TR::Compilation *comp, bool locked,1042TR_YesNoMaybe useGetResolvedInterfaceMethod)1043{1044if (comp->getOption(TR_DisableCHOpts))1045return maxCount+1; // fail the collection10461047#if defined(J9VM_OPT_JITSERVER)1048if (comp->isOutOfProcessCompilation())1049{1050return static_cast<TR_ResolvedJ9JITServerMethod *>(callerMethod)->collectImplementorsCapped(1051clazz->getClassId(),1052maxCount,1053slotOrIndex,1054useGetResolvedInterfaceMethod,1055implArray);1056}1057#endif1058CollectImplementors collector(comp, clazz->getClassId(), implArray, maxCount, callerMethod, slotOrIndex, useGetResolvedInterfaceMethod);1059collector.visitSubclass(clazz);1060collector.visit(clazz->getClassId(), locked);1061return collector.getCount(); // return the number of implementers in the implArray1062}10631064int32_t1065TR_ClassQueries::collectCompiledImplementorsCapped(TR_PersistentClassInfo *clazz,1066TR_ResolvedMethod **implArray,1067int32_t maxCount, int32_t slotOrIndex,1068TR_ResolvedMethod *callerMethod,1069TR::Compilation *comp,1070TR_Hotness hotness, bool locked,1071TR_YesNoMaybe useGetResolvedInterfaceMethod)1072{1073if (comp->getOption(TR_DisableCHOpts))1074return maxCount+1; // fail the collection1075CollectCompiledImplementors collector(comp, clazz->getClassId(), implArray, maxCount, callerMethod, slotOrIndex, hotness, useGetResolvedInterfaceMethod);1076collector.visitSubclass(clazz);1077collector.visit(clazz->getClassId(), locked);1078return collector.getCount();1079}10801081void1082TR_ClassQueries::collectLeafs(TR_PersistentClassInfo *clazz,1083TR_ScratchList<TR_PersistentClassInfo> &leafs, TR::Compilation *comp, bool locked)1084{1085TR::ClassTableCriticalSection collectLeafs(comp->fe(), locked);10861087// keep a list of classes that were set visited so that we can1088// easily reset the visited flag later-on1089TR_CHTable::VisitTracker marked(comp->trMemory());10901091for (TR_SubClass *subClass = clazz->_subClasses.getFirst(); subClass; subClass = subClass->getNext())1092if (!subClass->getClassInfo()->hasBeenVisited())1093TR_ClassQueries::collectLeafsLocked(subClass->getClassInfo(), leafs, marked);1094}10951096void1097TR_ClassQueries::collectLeafsLocked(TR_PersistentClassInfo* clazz,1098TR_ScratchList<TR_PersistentClassInfo>& leafs,1099TR_CHTable::VisitTracker& marked)1100{1101marked.visit(clazz);1102TR_SubClass* subClass = clazz->_subClasses.getFirst();1103if (!subClass)1104leafs.add(clazz);1105else // visit all non-visited classes1106for (; subClass; subClass = subClass->getNext())1107if (!subClass->getClassInfo()->hasBeenVisited())1108TR_ClassQueries::collectLeafsLocked(subClass->getClassInfo(), leafs, marked);1109}11101111void1112TR_ClassQueries::collectAllSubClasses(TR_PersistentClassInfo *clazz,1113TR_ScratchList<TR_PersistentClassInfo> *leafs,1114TR::Compilation *comp, bool locked)1115{1116TR::ClassTableCriticalSection collectAllSubClasses(comp->fe(), locked);11171118// Defect 180426 We used to use the same 'leafs' list for both the result set and to track the list1119// of classes on which to call resetVisited(). This raises concerns about possible interactions1120// between invocations now that the reset list is held in TR::Compilation. To avoid problems1121// we're separating the two issues and using two lists.1122TR_CHTable::VisitTracker marked(comp->trMemory());11231124TR_ClassQueries::collectAllSubClassesLocked(clazz, leafs, marked); // walk1125}11261127/*1128* Recursively walk the class tree to find subclasses.1129*1130* clazz - the current class to find subclasses of.1131* leafs - the result set1132* marked - list of visited classes (used to clear the visited flags)1133*/1134void1135TR_ClassQueries::collectAllSubClassesLocked(TR_PersistentClassInfo* clazz,1136TR_ScratchList<TR_PersistentClassInfo>* leafs,1137TR_CHTable::VisitTracker& marked)1138{1139TR_SubClass * subClass = clazz->_subClasses.getFirst();11401141for (; subClass; subClass = subClass->getNext())1142{1143if (!subClass->getClassInfo()->hasBeenVisited())1144{1145TR_PersistentClassInfo *sc = subClass->getClassInfo();1146leafs->add(sc);1147marked.visit(sc);1148TR_ClassQueries::collectAllSubClassesLocked(sc, leafs, marked);1149}1150}1151}11521153// class used to collect first layer of non-interface subclasses1154class CollectNonIFSubClasses : public TR_SubclassVisitor1155{1156public:1157CollectNonIFSubClasses(TR::Compilation * comp, TR_ScratchList<TR_PersistentClassInfo> &leafs) :1158TR_SubclassVisitor(comp), _collection(leafs) {}1159virtual bool visitSubclass(TR_PersistentClassInfo *cl)1160{1161return (TR::Compiler->cls.isInterfaceClass(comp(), cl->getClassId()) ? true : (_collection.add(cl), false));1162}1163private:1164TR_ScratchList<TR_PersistentClassInfo> &_collection;1165};// end of class CollectNonIFSubClasses11661167void1168TR_ClassQueries::collectAllNonIFSubClasses(TR_PersistentClassInfo *clazz,1169TR_ScratchList<TR_PersistentClassInfo> &leafs, TR::Compilation *comp, bool locked)1170{1171CollectNonIFSubClasses collector(comp, leafs);1172collector.visit(clazz->getClassId(), locked);1173}11741175void1176TR_ClassQueries::addAnAssumptionForEachSubClass(TR_PersistentCHTable *table,1177TR_PersistentClassInfo *clazz,1178List<TR_VirtualGuardSite> &list,1179TR::Compilation *comp)1180{1181// Gather the subtree of classes rooted at clazz1182TR_ScratchList<TR_PersistentClassInfo> subTree(comp->trMemory());1183collectAllSubClasses(clazz, &subTree, comp);11841185// Add the root to the list1186subTree.add(clazz);11871188ListIterator<TR_VirtualGuardSite> it(&list);1189for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())1190{1191ListIterator<TR_PersistentClassInfo> classIt(&subTree);1192for (TR_PersistentClassInfo *sc = classIt.getFirst(); sc; sc = classIt.getNext())1193{1194TR_ASSERT(sc == table->findClassInfo(sc->getClassId()), "Class ID mismatch");1195TR_PatchNOPedGuardSiteOnClassExtend::make(comp->fe(), comp->trPersistentMemory(), sc->getClassId(),1196site->getLocation(),1197site->getDestination(),1198comp->getMetadataAssumptionList());1199comp->setHasClassExtendAssumptions();1200}1201}1202}12031204// class used to count all non-interface subclasses up to a maximum1205class CountNonIFSubClasses : public TR_SubclassVisitor1206{1207public:1208CountNonIFSubClasses(TR::Compilation * comp, int32_t maxCount) :1209TR_SubclassVisitor(comp), _maxCount(maxCount), _count(0) {}1210virtual bool visitSubclass(TR_PersistentClassInfo *cl)1211{1212if (!TR::Compiler->cls.isInterfaceClass(comp(), cl->getClassId()))1213if (++_count >= _maxCount)1214stopTheWalk();1215return true;1216}1217int32_t getCount() const { return _count; }1218private:1219int32_t _maxCount, _count;1220};// end of class CountNonIFSubClasses12211222int32_t1223TR_ClassQueries::countAllNonIFSubClassesWithDepth(TR_PersistentClassInfo *clazz,1224TR::Compilation *comp, int32_t maxcount, bool locked)1225{1226CountNonIFSubClasses collector(comp, maxcount);1227collector.visit(clazz->getClassId(), locked);1228return collector.getCount();1229}123012311232TR_SubclassVisitor::TR_SubclassVisitor(TR::Compilation * comp)1233: _comp(comp),1234_stopTheWalk(false),1235_depth(0)1236{1237static char * trace = feGetEnv("TR_TraceSubclassVisitor");1238_trace = (trace != 0);1239}12401241void1242TR_SubclassVisitor::visit(TR_OpaqueClassBlock * clazz, bool locked)1243{1244TR::ClassTableCriticalSection visit(fe(), locked);12451246TR_PersistentClassInfo * classInfo = comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfo(clazz);1247if (!classInfo)1248return;12491250// A class can be visited more than once if we're starting from an interface class or if we're starting from1251// java/lang/Object. The latter is because all interfaces extend java/lang/Object.1252// java/lang/Object has the property that it doesn't have a super class (classdepth == 0).1253//1254_mightVisitAClassMoreThanOnce = TR::Compiler->cls.isInterfaceClass(comp(), clazz) || TR::Compiler->cls.classDepthOf(clazz) == 0;12551256if (_trace && classInfo->getFirstSubclass())1257{1258int32_t len; char * s = TR::Compiler->cls.classNameChars(comp(), clazz, len);1259TR_VerboseLog::writeLine(TR_Vlog_INFO,"visiting subclasses for %.*s", len, s);1260}12611262TR_CHTable::VisitTracker visited(comp()->trMemory());1263visitSubclasses(classInfo, visited);1264}12651266void1267TR_SubclassVisitor::visitSubclasses(TR_PersistentClassInfo * classInfo, TR_CHTable::VisitTracker& visited)1268{1269++_depth;1270for (TR_SubClass * subclass = classInfo->getFirstSubclass(); subclass; subclass = subclass->getNext())1271{1272TR_PersistentClassInfo * subclassInfo = subclass->getClassInfo();1273if (!subclassInfo->hasBeenVisited())1274{1275if (_trace)1276{1277int32_t len; char * s = TR::Compiler->cls.classNameChars(comp(), subclassInfo->getClassId(), len);1278TR_VerboseLog::writeLine(TR_Vlog_INFO,"%*s%.*s", _depth, " ", len, s);1279}12801281if (_mightVisitAClassMoreThanOnce)1282{1283visited.visit(subclassInfo);1284}12851286bool recurse = visitSubclass(subclassInfo);1287if (recurse && !_stopTheWalk)1288visitSubclasses(subclassInfo, visited);12891290if (_stopTheWalk)1291break;1292}1293}1294--_depth;1295}129612971298