Path: blob/master/runtime/compiler/env/J9VMEnv.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#define J9_EXTERNAL_TO_VM2324#include "compile/Compilation.hpp"25#include "control/Options.hpp"26#include "control/CompilationRuntime.hpp"27#include "control/CompilationThread.hpp"28#include "env/VMEnv.hpp"29#include "env/CompilerEnv.hpp"30#include "env/VMJ9.h"31#include "exceptions/JITShutDown.hpp"32#include "infra/Assert.hpp"33#include "infra/Monitor.hpp"34#include "infra/MonitorTable.hpp"35#include "runtime/J9VMAccess.hpp"36#include "j9.h"37#include "j9cfg.h"38#include "jilconsts.h"39#include "vmaccess.h"40#if defined(J9VM_OPT_JITSERVER)41#include "runtime/JITClientSession.hpp"42#endif /* defined(J9VM_OPT_JITSERVER) */4344int64_t45J9::VMEnv::maxHeapSizeInBytes()46{47#if defined(J9VM_OPT_JITSERVER)48if (auto stream = TR::CompilationInfo::getStream())49{50auto *vmInfo = TR::compInfoPT->getClientData()->getOrCacheVMInfo(stream);51return vmInfo->_maxHeapSizeInBytes;52}53#endif /* defined(J9VM_OPT_JITSERVER) */54J9JavaVM *jvm = TR::Compiler->javaVM;5556if (!jvm)57return -1;5859J9MemoryManagerFunctions * mmf = jvm->memoryManagerFunctions;60return (int64_t) mmf->j9gc_get_maximum_heap_size(jvm);61}6263bool64J9::VMEnv::hasAccess(OMR_VMThread *omrVMThread)65{66return TR::Compiler->vm.hasAccess(self()->J9VMThreadFromOMRVMThread(omrVMThread));67}686970bool71J9::VMEnv::hasAccess(J9VMThread *j9VMThread)72{73return (j9VMThread->publicFlags & J9_PUBLIC_FLAGS_VM_ACCESS) ? true : false;74}757677bool78J9::VMEnv::hasAccess(TR::Compilation *comp)79{80return comp->fej9()->haveAccess(comp);81}828384// Points to address: what if vmThread is not the compilation thread?85// What if the compilation thread does not have the classUnloadMonitor?86// What if jitConfig does not exist?87// What if we already have the compilationShouldBeInterrupted flag set?88// How do we set the error code when we throw an exception?8990// IMPORTANT: acquireVMAccessIfNeeded could throw an exception,91// hence it is important to call this within a try block.92//93static bool94acquireVMaccessIfNeededInner(J9VMThread *vmThread, TR_YesNoMaybe isCompThread)95{96bool haveAcquiredVMAccess = false;9798if (TR::Options::getCmdLineOptions() == 0 || // if options haven't been created yet, there is no danger99TR::Options::getCmdLineOptions()->getOption(TR_DisableNoVMAccess))100{101return false; // don't need to acquire VM access102}103104// we need to test if the thread has VM access105TR_ASSERT(vmThread, "vmThread must be not null");106107// We need to acquire VMaccess only for the compilation thread108if (isCompThread == TR_no)109{110TR_ASSERT((vmThread->publicFlags & J9_PUBLIC_FLAGS_VM_ACCESS), "Must have vm access if this is not a compilation thread");111return false;112}113114// scan all compilation threads115J9JITConfig *jitConfig = vmThread->javaVM->jitConfig;116TR::CompilationInfo *compInfo = TR::CompilationInfo::get(jitConfig);117TR::CompilationInfoPerThread *compInfoPT = compInfo->getCompInfoForThread(vmThread);118119// We need to acquire VMaccess only for the compilation thread120if (isCompThread == TR_maybe)121{122if (!compInfoPT)123{124TR_ASSERT((vmThread->publicFlags & J9_PUBLIC_FLAGS_VM_ACCESS), "Must have vm access if this is not a compilation thread");125return false;126}127}128129// At this point we know we deal with a compilation thread130//131TR_ASSERT(compInfoPT, "A compilation thread must have an associated compilationInfo");132133if (!(vmThread->publicFlags & J9_PUBLIC_FLAGS_VM_ACCESS)) // I don't already have VM access134{135if (0 == vmThread->javaVM->internalVMFunctions->internalTryAcquireVMAccessWithMask(vmThread, J9_PUBLIC_FLAGS_HALT_THREAD_ANY_NO_JAVA_SUSPEND))136{137haveAcquiredVMAccess = true;138}139else // the GC is having exclusive VM access140{141// compilationShouldBeInterrupted flag is reset by the compilation142// thread when a new compilation starts.143144// must test if we have the class unload monitor145//vmThread->osThread == classUnloadMonitor->owner()146147bool hadClassUnloadMonitor = false;148#if !defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)149if (TR::Options::getCmdLineOptions()->getOption(TR_EnableHCR) || TR::Options::getCmdLineOptions()->getOption(TR_FullSpeedDebug))150#endif151hadClassUnloadMonitor = TR::MonitorTable::get()->readReleaseClassUnloadMonitor(compInfoPT->getCompThreadId()) >= 0;152153#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)154// We must have had classUnloadMonitor by the way we architected the application155TR_ASSERT(hadClassUnloadMonitor, "Comp thread must hold classUnloadMonitor when compiling without VMaccess");156#endif157158//--- GC CAN INTERVENE HERE ---159160// fprintf(stderr, "Have released class unload monitor temporarily\n"); fflush(stderr);161162// At this point we must not hold any JIT monitors that can also be accessed by the GC163// As we don't know how the GC code will be modified in the future we will164// scan the entire list of known monitors165#if defined(DEBUG) || defined(PROD_WITH_ASSUMES)166TR::Monitor * heldMonitor = TR::MonitorTable::get()->monitorHeldByCurrentThread();167TR_ASSERT(!heldMonitor, "Current thread must not hold TR::Monitor %p called %s when trying to acquire VM access\n",168heldMonitor, TR_J9VMBase::get(jitConfig, NULL)->getJ9MonitorName((J9ThreadMonitor*)heldMonitor->getVMMonitor()));169#endif // #if defined(DEBUG) || defined(PROD_WITH_ASSUMES)170171TR::Compilation *comp = compInfoPT->getCompilation();172if ((comp && comp->getOptions()->realTimeGC()) ||173TR::Options::getCmdLineOptions()->realTimeGC())174compInfoPT->waitForGCCycleMonitor(false); // used only for real-time175176acquireVMAccessNoSuspend(vmThread); // blocking. Will wait for the entire GC177178if (hadClassUnloadMonitor)179{180TR::MonitorTable::get()->readAcquireClassUnloadMonitor(compInfoPT->getCompThreadId());181//fprintf(stderr, "Have acquired class unload monitor again\n"); fflush(stderr);182}183184// Now we can check if the GC has done some unloading or redefinition happened185if (compInfoPT->compilationShouldBeInterrupted())186{187// bail out188// fprintf(stderr, "Released classUnloadMonitor and will throw an exception because GC unloaded classes\n"); fflush(stderr);189//TR::MonitorTable::get()->readReleaseClassUnloadMonitor(0); // Main code should do it.190// releaseVMAccess(vmThread);191192if (comp)193{194comp->failCompilation<TR::CompilationInterrupted>("Compilation interrupted by GC unloading classes");195}196else // I am not sure we are in a compilation; better release the monitor197{198if (hadClassUnloadMonitor)199TR::MonitorTable::get()->readReleaseClassUnloadMonitor(compInfoPT->getCompThreadId()); // Main code should do it.200throw TR::CompilationInterrupted();201}202}203else // GC did not do any unloading204{205haveAcquiredVMAccess = true;206}207}208}209210/*211* At shutdown time the compilation thread executes Java code and it may receive a sample (see D174900)212* Only abort the compilation if we're explicitly prepared to handle it.213*/214if (compInfoPT->compilationShouldBeInterrupted())215{216TR_ASSERT(compInfoPT->compilationShouldBeInterrupted() != GC_COMP_INTERRUPT, "GC should not have cut in _compInfoPT=%p\n", compInfoPT);217218// in prod builds take some corrective action219throw J9::JITShutdown();220}221222return haveAcquiredVMAccess;223}224225226bool227J9::VMEnv::acquireVMAccessIfNeeded(OMR_VMThread *omrVMThread)228{229TR_ASSERT(0, "not implemented"); return false;230}231232233bool234J9::VMEnv::acquireVMAccessIfNeeded(TR_J9VMBase *fej9)235{236// This interface should be deprecated when the FrontEnd is redesigned and237// eliminated. The trouble with the CompilerEnv interface is that it doesn't238// yet understand compilation contexts (i.e., a 'regular' compile, an AOT239// compile, etc.). While this can be sorted out, the safest thing to do until240// that happens is to simply call the equivalent J9 FrontEnd virtual function to241// ensure the correct call is being made.242//243// return acquireVMaccessIfNeededInner(fej9->vmThread(), fej9->vmThreadIsCompilationThread());244245return fej9->acquireVMAccessIfNeeded();246}247248249bool250J9::VMEnv::acquireVMAccessIfNeeded(TR::Compilation *comp)251{252return TR::Compiler->vm.acquireVMAccessIfNeeded(comp->fej9());253}254255256bool257J9::VMEnv::tryToAcquireAccess(TR::Compilation *comp, bool *haveAcquiredVMAccess)258{259return comp->fej9()->tryToAcquireAccess(comp, haveAcquiredVMAccess);260}261262263bool264J9::VMEnv::tryToAcquireAccess(OMR_VMThread *omrVMThread, bool *haveAcquiredVMAccess)265{266TR_ASSERT(0, "not implemented"); return false;267}268269270static void271releaseVMaccessIfNeededInner(J9VMThread *vmThread, bool haveAcquiredVMAccess)272{273if (haveAcquiredVMAccess)274{275TR_ASSERT((vmThread->publicFlags & J9_PUBLIC_FLAGS_VM_ACCESS), "Must have VM access");276releaseVMAccess(vmThread);277}278}279280281void282J9::VMEnv::releaseVMAccessIfNeeded(TR::Compilation *comp, bool haveAcquiredVMAccess)283{284comp->fej9()->releaseVMAccessIfNeeded(haveAcquiredVMAccess);285}286287288void289J9::VMEnv::releaseVMAccessIfNeeded(OMR_VMThread *omrVMThread, bool haveAcquiredVMAccess)290{291releaseVMaccessIfNeededInner(self()->J9VMThreadFromOMRVMThread(omrVMThread), haveAcquiredVMAccess);292}293294295void296J9::VMEnv::releaseVMAccessIfNeeded(TR_J9VMBase *fej9, bool haveAcquiredVMAccess)297{298fej9->releaseVMAccessIfNeeded(haveAcquiredVMAccess);299}300301302void303J9::VMEnv::releaseAccess(TR::Compilation *comp)304{305comp->fej9()->releaseAccess(comp);306}307308309void310J9::VMEnv::releaseAccess(OMR_VMThread *omrVMThread)311{312TR_ASSERT(0, "not implemented");313}314315316void317J9::VMEnv::releaseAccess(TR_J9VMBase *fej9)318{319if (fej9->vmThread()->publicFlags & J9_PUBLIC_FLAGS_VM_ACCESS)320{321releaseVMAccess(fej9->vmThread());322}323}324325uintptr_t326J9::VMEnv::thisThreadGetPendingExceptionOffset()327{328return offsetof(J9VMThread, jitException);329}330331bool332J9::VMEnv::hasResumableTrapHandler(TR::Compilation *comp)333{334return comp->fej9()->hasResumableTrapHandler();335}336337bool338J9::VMEnv::hasResumableTrapHandler(OMR_VMThread *omrVMThread)339{340TR_ASSERT(0, "not implemented"); return false;341}342343uint64_t344J9::VMEnv::getUSecClock(TR::Compilation *comp)345{346return comp->fej9()->getUSecClock();347}348349uint64_t350J9::VMEnv::getUSecClock(OMR_VMThread *omrVMThread)351{352TR_ASSERT(0, "not implemented"); return 0;353}354355uint64_t356J9::VMEnv::getHighResClock(TR::Compilation *comp)357{358return comp->fej9()->getHighResClock();359}360361uint64_t362J9::VMEnv::getHighResClock(OMR_VMThread *omrVMThread)363{364TR_ASSERT(0, "not implemented"); return 0;365}366367uint64_t368J9::VMEnv::getHighResClockResolution(TR::Compilation *comp)369{370return comp->fej9()->getHighResClockResolution();371}372373uint64_t374J9::VMEnv::getHighResClockResolution(OMR_VMThread *omrVMThread)375{376TR_ASSERT(0, "not implemented"); return 0;377}378379uint64_t380J9::VMEnv::getHighResClockResolution(TR_FrontEnd *fej9)381{382return ((TR_J9VMBase*)fej9)->getHighResClockResolution();383}384385uint64_t386J9::VMEnv::getHighResClockResolution()387{388PORT_ACCESS_FROM_PORT(TR::Compiler->portLib);389return j9time_hires_frequency();390}391392bool393J9::VMEnv::canMethodEnterEventBeHooked(TR::Compilation *comp)394{395return comp->fej9()->canMethodEnterEventBeHooked();396}397398bool399J9::VMEnv::canMethodExitEventBeHooked(TR::Compilation *comp)400{401return comp->fej9()->canMethodExitEventBeHooked();402}403404uintptr_t405J9::VMEnv::getOverflowSafeAllocSize(TR::Compilation *comp)406{407return comp->fej9()->getOverflowSafeAllocSize();408}409410411int64_t412J9::VMEnv::cpuTimeSpentInCompilationThread(TR::Compilation *comp)413{414return comp->fej9()->getCpuTimeSpentInCompThread(comp);415}416417418uintptr_t419J9::VMEnv::OSRFrameHeaderSizeInBytes(TR::Compilation *comp)420{421return comp->fej9()->getOSRFrameHeaderSizeInBytes();422}423424425uintptr_t426J9::VMEnv::OSRFrameSizeInBytes(TR::Compilation *comp, TR_OpaqueMethodBlock* method)427{428return comp->fej9()->getOSRFrameSizeInBytes(method);429}430431432bool433J9::VMEnv::ensureOSRBufferSize(TR::Compilation *comp, uintptr_t osrFrameSizeInBytes, uintptr_t osrScratchBufferSizeInBytes, uintptr_t osrStackFrameSizeInBytes)434{435return comp->fej9()->ensureOSRBufferSize(comp, osrFrameSizeInBytes, osrScratchBufferSizeInBytes, osrStackFrameSizeInBytes);436}437438uintptr_t439J9::VMEnv::thisThreadGetOSRReturnAddressOffset(TR::Compilation *comp)440{441return comp->fej9()->thisThreadGetOSRReturnAddressOffset();442}443444uintptr_t445J9::VMEnv::thisThreadGetGSIntermediateResultOffset(TR::Compilation *comp)446{447return comp->fej9()->thisThreadGetGSIntermediateResultOffset();448}449450uintptr_t451J9::VMEnv::thisThreadGetConcurrentScavengeActiveByteAddressOffset(TR::Compilation *comp)452{453return comp->fej9()->thisThreadGetConcurrentScavengeActiveByteAddressOffset();454}455456uintptr_t457J9::VMEnv::thisThreadGetEvacuateBaseAddressOffset(TR::Compilation *comp)458{459return comp->fej9()->thisThreadGetEvacuateBaseAddressOffset();460}461462uintptr_t463J9::VMEnv::thisThreadGetEvacuateTopAddressOffset(TR::Compilation *comp)464{465return comp->fej9()->thisThreadGetEvacuateTopAddressOffset();466}467468uintptr_t469J9::VMEnv::thisThreadGetGSOperandAddressOffset(TR::Compilation *comp)470{471return comp->fej9()->thisThreadGetGSOperandAddressOffset();472}473474uintptr_t475J9::VMEnv::thisThreadGetGSHandlerAddressOffset(TR::Compilation *comp)476{477return comp->fej9()->thisThreadGetGSHandlerAddressOffset();478}479480/*481* Method enter/exit hooks are only enabled for some specific methods482*/483bool484J9::VMEnv::isSelectiveMethodEnterExitEnabled(TR::Compilation *comp)485{486return comp->fej9()->isSelectiveMethodEnterExitEnabled();487}488489size_t490J9::VMEnv::getInterpreterVTableOffset()491{492#if defined(J9VM_OPT_JITSERVER)493if (auto stream = TR::CompilationInfo::getStream())494{495auto *vmInfo = TR::compInfoPT->getClientData()->getOrCacheVMInfo(stream);496return vmInfo->_interpreterVTableOffset;497}498#endif /* defined(J9VM_OPT_JITSERVER) */499return sizeof(J9Class);500}501502bool503J9::VMEnv::isVMInStartupPhase(J9JITConfig *jitConfig)504{505#if defined(J9VM_OPT_JITSERVER)506if (auto stream = TR::CompilationInfo::getStream())507{508return TR::compInfoPT->getClientData()->isInStartupPhase();509}510#endif /* defined(J9VM_OPT_JITSERVER) */511return jitConfig->javaVM->phase != J9VM_PHASE_NOT_STARTUP;512}513514515