Path: blob/master/runtime/gc_check/CheckCycle.cpp
5990 views
1/*******************************************************************************2* Copyright (c) 1991, 2021 IBM Corp. and others3*4* This program and the accompanying materials are made available under5* the terms of the Eclipse Public License 2.0 which accompanies this6* distribution and is available at https://www.eclipse.org/legal/epl-2.0/7* or the Apache License, Version 2.0 which accompanies this distribution and8* is available at https://www.apache.org/licenses/LICENSE-2.0.9*10* This Source Code may also be made available under the following11* Secondary Licenses when the conditions for such availability set12* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU13* General Public License, version 2 with the GNU Classpath14* Exception [1] and GNU General Public License, version 2 with the15* OpenJDK Assembly Exception [2].16*17* [1] https://www.gnu.org/software/classpath/license.html18* [2] http://openjdk.java.net/legal/assembly-exception.html19*20* 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-exception21*******************************************************************************/2223#include <string.h>2425#include "vendor_version.h"26#include "CheckCycle.hpp"27#include "CheckClassHeap.hpp"28#include "CheckClassLoaders.hpp"29#include "CheckEngine.hpp"30#include "CheckFinalizableList.hpp"31#include "CheckJNIGlobalReferences.hpp"32#include "CheckJNIWeakGlobalReferences.hpp"33#include "CheckJVMTIObjectTagTables.hpp"34#include "CheckMonitorTable.hpp"35#include "CheckObjectHeap.hpp"36#include "CheckOwnableSynchronizerList.hpp"37#include "CheckRememberedSet.hpp"38#include "CheckStringTable.hpp"39#include "CheckUnfinalizedList.hpp"40#include "CheckVMClassSlots.hpp"41#include "CheckVMThreads.hpp"42#include "CheckVMThreadStacks.hpp"43#include "FixDeadObjects.hpp"44#include "GCExtensionsBase.hpp"4546#define TOTAL_NUM_CHECKS (sizeof(GC_CheckCycle::funcArray) / sizeof(GC_CheckCycle::funcStruct))47const GC_CheckCycle::funcStruct GC_CheckCycle::funcArray[] = {48/* move ownablesynchronizer check before objectheap check in order to ownablesynchronizer check runs after objectheap check(the checks in stack, last in first out)49* for ownablesynchronizer consistency check, which defends on both ownablesynchronizer check before objectheap check. the verify consistency only at the end of ownablesynchronizer check.50*/51{"ownablesynchronizer", J9MODRON_GCCHK_SCAN_OWNABLE_SYNCHRONIZER, GC_CheckOwnableSynchronizerList::newInstance},52{"objectheap", J9MODRON_GCCHK_SCAN_OBJECT_HEAP, GC_CheckObjectHeap::newInstance},53{"classheap", J9MODRON_GCCHK_SCAN_CLASS_HEAP, GC_CheckClassHeap::newInstance},54#if defined(J9VM_GC_GENERATIONAL)55{"rememberedset", J9MODRON_GCCHK_SCAN_REMEMBERED_SET, GC_CheckRememberedSet::newInstance},56#endif57#if defined(J9VM_GC_FINALIZATION)58{"unfinalized", J9MODRON_GCCHK_SCAN_UNFINALIZED, GC_CheckUnfinalizedList::newInstance},59{"finalizable", J9MODRON_GCCHK_SCAN_FINALIZABLE, GC_CheckFinalizableList::newInstance},60#endif61{"stringtable", J9MODRON_GCCHK_SCAN_STRING_TABLE, GC_CheckStringTable::newInstance},62{"classloaders", J9MODRON_GCCHK_SCAN_CLASS_LOADERS, GC_CheckClassLoaders::newInstance},63{"jniglobalrefs", J9MODRON_GCCHK_SCAN_JNI_GLOBAL_REFERENCES, GC_CheckJNIGlobalReferences::newInstance},64{"jniweakglobalrefs", J9MODRON_GCCHK_SCAN_JNI_WEAK_GLOBAL_REFERENCES, GC_CheckJNIWeakGlobalReferences::newInstance},65#if defined(J9VM_OPT_JVMTI)66{"jvmtiobjecttagtables", J9MODRON_GCCHK_SCAN_JVMTI_OBJECT_TAG_TABLES, GC_CheckJVMTIObjectTagTables::newInstance},67#endif68{"vmclassslots", J9MODRON_GCCHK_SCAN_VM_CLASS_SLOTS, GC_CheckVMClassSlots::newInstance},69{"monitortable", J9MODRON_GCCHK_SCAN_MONITOR_TABLE, GC_CheckMonitorTable::newInstance},70{"vmthreads", J9MODRON_GCCHK_SCAN_VMTHREADS, GC_CheckVMThreads::newInstance},71{"threadstacks", J9MODRON_GCCHK_SCAN_THREADSTACKS, GC_CheckVMThreadStacks::newInstance}72};7374/**75* Provide user help.76* Display GC_Check command line option help.77*/78void79GC_CheckCycle::printHelp(J9PortLibrary *portLib)80{81PORT_ACCESS_FROM_PORT(portLib);8283j9tty_printf(PORTLIB, "gcchk for J9, Version " J9JVM_VERSION_STRING "\n");84j9tty_printf(PORTLIB, J9_COPYRIGHT_STRING "\n\n");85j9tty_printf(PORTLIB, "Usage: -Xcheck:gc[:scanOption,...][:verifyOption,...][:miscOption,...]\n");86j9tty_printf(PORTLIB, "scan options (default is all):\n");87j9tty_printf(PORTLIB, " all all object and VM slots\n");88j9tty_printf(PORTLIB, " none\n");8990/* print the name of each check supported */91for(UDATA i = 0; i < TOTAL_NUM_CHECKS; i++) {92j9tty_printf(PORTLIB, " %s\n", funcArray[i].name);93}9495j9tty_printf(PORTLIB, " heap object and class heaps\n");96j9tty_printf(PORTLIB, " novmthreads\n");97j9tty_printf(PORTLIB, " help print this screen\n");9899j9tty_printf(PORTLIB, "\nverify options (default is all):\n");100j9tty_printf(PORTLIB, " all\n");101j9tty_printf(PORTLIB, " none\n");102j9tty_printf(PORTLIB, " classslot\n");103j9tty_printf(PORTLIB, " range\n");104j9tty_printf(PORTLIB, " flags\n");105106j9tty_printf(PORTLIB, "\nmisc options (default is verbose,check):\n");107j9tty_printf(PORTLIB, " verbose\n");108j9tty_printf(PORTLIB, " quiet\n");109j9tty_printf(PORTLIB, " scan\n");110j9tty_printf(PORTLIB, " noscan\n");111j9tty_printf(PORTLIB, " check\n");112j9tty_printf(PORTLIB, " nocheck\n");113j9tty_printf(PORTLIB, " maxErrors=X\n");114115j9tty_printf(PORTLIB, " abort\n");116j9tty_printf(PORTLIB, " noabort\n");117j9tty_printf(PORTLIB, " dumpstack\n");118j9tty_printf(PORTLIB, " nodumpstack\n");119j9tty_printf(PORTLIB, " interval=X\n");120j9tty_printf(PORTLIB, " globalinterval=X\n");121#if defined(J9VM_GC_MODRON_SCAVENGER)122j9tty_printf(PORTLIB, " localinterval=X\n");123#endif /* J9VM_GC_MODRON_SCAVENGER */124j9tty_printf(PORTLIB, " startindex=x\n");125#if defined(J9VM_GC_MODRON_SCAVENGER)126j9tty_printf(PORTLIB, " scavengerbackout\n");127j9tty_printf(PORTLIB, " suppresslocal\n");128#endif /* J9VM_GC_MODRON_SCAVENGER */129j9tty_printf(PORTLIB, " suppressglobal\n");130#if defined(J9VM_GC_GENERATIONAL)131j9tty_printf(PORTLIB, " rememberedsetoverflow\n");132#endif /* J9VM_GC_GENERATIONAL */133j9tty_printf(PORTLIB, "\n");134}135136/**137* Generate the list of checks to perform in this cycle138* Iterates over the scanFlags UDATA, instantiating a GC_Check subtype for139* each bit turned on and adding it to the list.140*141* @param scanFlags Bit vector containing a bit for each type of check we're142* going to run.143*/144void145GC_CheckCycle::generateCheckList(UDATA scanFlags)146{147/* Iterate over funcArray dereferencing the function pointer of the checks we want to instantiate */148for(UDATA i = 0; i < TOTAL_NUM_CHECKS; i++) {149if(scanFlags & funcArray[i].bitmask) {150/* we've found a check we need to instantiate */151GC_Check *check = (funcArray[i].function)(_javaVM, _engine);152/* add it to the list of checks */153if(check) {154check->setNext(_checks);155check->setBitId(funcArray[i].bitmask);156_checks = check;157}158}159}160}161162/**163* Parse command line.164* Parse the command line for GCCheck options.165*166* @param options a string containing the user-supplied options167*/168bool169GC_CheckCycle::initialize(const char *options)170{171GCCHK_Extensions *extensions = (GCCHK_Extensions *)((MM_GCExtensions*)_javaVM->gcExtensions)->gcchkExtensions;172UDATA scanFlags = 0, checkFlags = 0, miscFlags;173char *scan_start = (char *)options;174const char *scan_limit = options + strlen(options);175176/* set the default miscFlags */177miscFlags = J9MODRON_GCCHK_VERBOSE | J9MODRON_GCCHK_MISC_CHECK;178179/* parse supplied options */180top:181while (scan_start < scan_limit) {182183/* ignore separators */184try_scan(&scan_start, ",");185186if (try_scan(&scan_start, "all")) {187scanFlags |= J9MODRON_GCCHK_SCAN_ALL_SLOTS;188continue;189}190191if (try_scan(&scan_start, "none")) {192scanFlags &= ~J9MODRON_GCCHK_SCAN_ALL_SLOTS;193continue;194}195196/* search for a supported check */197for(UDATA i = 0; i < TOTAL_NUM_CHECKS; i++) {198if (try_scan(&scan_start, funcArray[i].name)) {199scanFlags |= funcArray[i].bitmask;200goto top; /* we want to 'break' from the for-loop and 'continue' the while, so a goto is needed */201}202}203204/* now do the special compound options (that affect more than one check) */205if (try_scan(&scan_start, "heap")) {206scanFlags |= J9MODRON_GCCHK_SCAN_OBJECT_HEAP | J9MODRON_GCCHK_SCAN_CLASS_HEAP;207continue;208}209210if (try_scan(&scan_start, "novmthreads")) {211scanFlags &= ~J9MODRON_GCCHK_SCAN_VMTHREADS;212continue;213}214215/* When ':' is encountered, everything that follows is a check option */216if (try_scan(&scan_start, ":")) {217while (scan_start < scan_limit) {218/* ignore separators */219try_scan(&scan_start, ",");220221if (try_scan(&scan_start, "all")) {222checkFlags |= J9MODRON_GCCHK_VERIFY_ALL;223continue;224}225226if (try_scan(&scan_start, "none")) {227checkFlags &= ~J9MODRON_GCCHK_VERIFY_ALL;228continue;229}230231if (try_scan(&scan_start, "classslot")) {232checkFlags |= J9MODRON_GCCHK_VERIFY_CLASS_SLOT;233continue;234}235236if (try_scan(&scan_start, "range")) {237checkFlags |= J9MODRON_GCCHK_VERIFY_RANGE;238continue;239}240241if (try_scan(&scan_start, "flags")) {242checkFlags |= J9MODRON_GCCHK_VERIFY_FLAGS;243continue;244}245246/* Another ':' signals the start of misc options */247if (try_scan(&scan_start, ":")) {248while (scan_start < scan_limit) {249/* ignore separators */250try_scan(&scan_start, ",");251252if (try_scan(&scan_start, "verbose")) {253miscFlags |= J9MODRON_GCCHK_VERBOSE;254continue;255}256257if (try_scan(&scan_start, "manual")) {258miscFlags |= J9MODRON_GCCHK_MANUAL;259continue;260}261262if (try_scan(&scan_start, "quiet")) {263miscFlags &= ~J9MODRON_GCCHK_VERBOSE;264miscFlags |= J9MODRON_GCCHK_MISC_QUIET;265continue;266}267268if (try_scan(&scan_start, "scan")) {269miscFlags |= J9MODRON_GCCHK_MISC_SCAN;270continue;271}272273if (try_scan(&scan_start, "noscan")) {274miscFlags &= ~J9MODRON_GCCHK_MISC_SCAN;275continue;276}277278if (try_scan(&scan_start, "check")) {279miscFlags |= J9MODRON_GCCHK_MISC_CHECK;280continue;281}282283if (try_scan(&scan_start, "nocheck")) {284miscFlags &= ~J9MODRON_GCCHK_MISC_CHECK;285continue;286}287288if (try_scan(&scan_start, "maxerrors=")) {289UDATA max;290scan_udata(&scan_start, &max);291_engine->setMaxErrorsToReport(max);292continue;293}294295if (try_scan(&scan_start, "darkmatter")) {296miscFlags |= J9MODRON_GCCHK_MISC_DARKMATTER;297continue;298}299300#if defined(J9VM_GC_MODRON_SCAVENGER) || defined(J9VM_GC_VLHGC)301if (try_scan(&scan_start, "midscavenge")) {302miscFlags |= J9MODRON_GCCHK_MISC_MIDSCAVENGE;303continue;304}305306if (try_scan(&scan_start, "indexabledataaddress")) {307miscFlags |= J9MODRON_GCCHK_VALID_INDEXABLE_DATA_ADDRESS;308continue;309}310#endif /* J9VM_GC_MODRON_SCAVENGER || defined(J9VM_GC_VLHGC) */311312if (try_scan(&scan_start, "abort")) {313miscFlags |= J9MODRON_GCCHK_MISC_ABORT;314continue;315}316317if (try_scan(&scan_start, "noabort")) {318miscFlags &= ~J9MODRON_GCCHK_MISC_ABORT;319continue;320}321322if (try_scan(&scan_start, "dumpstack")) {323miscFlags |= J9MODRON_GCCHK_MISC_ALWAYS_DUMP_STACK;324continue;325}326327if (try_scan(&scan_start, "nodumpstack")) {328miscFlags &= ~J9MODRON_GCCHK_MISC_ALWAYS_DUMP_STACK;329continue;330}331332if (try_scan(&scan_start, "interval=")) {333scan_udata(&scan_start, &extensions->gcInterval);334miscFlags |= J9MODRON_GCCHK_INTERVAL;335continue;336}337#if defined(J9VM_GC_MODRON_SCAVENGER)338if (try_scan(&scan_start, "localinterval=")) {339scan_udata(&scan_start, &extensions->localGcInterval);340miscFlags |= J9MODRON_GCCHK_LOCAL_INTERVAL;341continue;342}343#endif /* J9VM_GC_MODRON_SCAVENGER */344345if (try_scan(&scan_start, "globalinterval=")) {346scan_udata(&scan_start, &extensions->globalGcInterval);347miscFlags |= J9MODRON_GCCHK_GLOBAL_INTERVAL;348continue;349}350351if (try_scan(&scan_start, "startindex=")) {352scan_udata(&scan_start, &extensions->gcStartIndex);353miscFlags |= J9MODRON_GCCHK_START_INDEX;354continue;355}356357#if defined(J9VM_GC_MODRON_SCAVENGER)358if (try_scan(&scan_start, "scavengerbackout")) {359miscFlags |= J9MODRON_GCCHK_SCAVENGER_BACKOUT;360continue;361}362363if (try_scan(&scan_start, "suppresslocal")) {364miscFlags |= J9MODRON_GCCHK_SUPPRESS_LOCAL;365continue;366}367#endif /* J9VM_GC_MODRON_SCAVENGER */368369if (try_scan(&scan_start, "suppressglobal")) {370miscFlags |= J9MODRON_GCCHK_SUPPRESS_GLOBAL;371continue;372}373374#if defined(J9VM_GC_GENERATIONAL)375if (try_scan(&scan_start, "rememberedsetoverflow")) {376miscFlags |= J9MODRON_GCCHK_REMEMBEREDSET_OVERFLOW;377continue;378}379#endif /* J9VM_GC_GENERATIONAL */380/* Nothing matched */381goto failure;382}383/* Reached end */384goto done;385}386/* Nothing matched */387goto failure;388}389/* Reached end */390goto done;391}392393goto failure;394}395396done:397/* Set defaults if user did not specify */398if (0 == scanFlags) {399scanFlags = J9MODRON_GCCHK_SCAN_ALL_SLOTS;400}401if (0 == checkFlags) {402checkFlags = J9MODRON_GCCHK_VERIFY_ALL;403}404405generateCheckList(scanFlags);406_checkFlags = checkFlags;407_miscFlags = miscFlags;408409if (J9MODRON_GCCHK_SCAN_OBJECT_HEAP == (scanFlags & J9MODRON_GCCHK_SCAN_OBJECT_HEAP)) {410/* initialize OwnableSynchronizerCount On Object Heap for ownableSynchronizer consistency check */411_engine->initializeOwnableSynchronizerCountOnHeap();412}413if (J9MODRON_GCCHK_SCAN_OWNABLE_SYNCHRONIZER == (scanFlags & J9MODRON_GCCHK_SCAN_OWNABLE_SYNCHRONIZER)) {414/* initialize OwnableSynchronizerCount On Lists for ownableSynchronizer consistency check */415_engine->initializeOwnableSynchronizerCountOnList();416}417418return true;419420failure:421/* no match */422scan_failed(_portLibrary, "gcchk", scan_start);423printHelp(_portLibrary);424425return false;426}427428void429GC_CheckCycle::run(GCCheckInvokedBy invokedBy, UDATA filterFlags)430{431_invokedBy = invokedBy;432_engine->startCheckCycle(_javaVM, this);433434GC_Check *mover = _checks;435while(mover) {436/* Use this mover (checker) only if its bitmask set in the filter flags */437if (mover->getBitId() == (filterFlags & mover->getBitId())) {438bool check = (J9MODRON_GCCHK_MISC_CHECK == (_miscFlags & J9MODRON_GCCHK_MISC_CHECK));439bool scan = (J9MODRON_GCCHK_MISC_SCAN == (_miscFlags & J9MODRON_GCCHK_MISC_SCAN));440mover->run(check, scan);441}442mover = mover->getNext();443}444if (_miscFlags & J9MODRON_GCCHK_MISC_ABORT) {445if (_errorCount > 0) {446abort();447}448}449_engine->endCheckCycle(_javaVM);450}451452/**453* Fix up dead objects.454*455* This routine fixes up any dead objects in the heap so that the checkJ9ObjectPointer()456* method can identify dead objects by virtue of the fact that their class457* pointer is unaligned, ie low_tagged.458*459* This is not necessary if the Object Map is available as we can perform the460* necessary check by calling the memory manager j9gc_ext_is_liveObject() function461*462*/463void464GC_CheckCycle::fixDeadObjects(GCCheckInvokedBy invokedBy)465{466_invokedBy = invokedBy;467GC_FixDeadObjects fixer = GC_FixDeadObjects(_javaVM, _engine);468fixer.run(true, false);469}470471GC_CheckCycle *472GC_CheckCycle::newInstance(J9JavaVM *javaVM, GC_CheckEngine *engine, const char *args, UDATA manualCountInvocation)473{474MM_Forge *forge = MM_GCExtensions::getExtensions(javaVM)->getForge();475476GC_CheckCycle *checkCycle = (GC_CheckCycle *) forge->allocate(sizeof(GC_CheckCycle), MM_AllocationCategory::DIAGNOSTIC, J9_GET_CALLSITE());477if(checkCycle) {478new(checkCycle) GC_CheckCycle(javaVM, engine, manualCountInvocation);479if (!checkCycle->initialize(args)) {480checkCycle = NULL;481}482}483return checkCycle;484}485486void487GC_CheckCycle::kill()488{489MM_Forge *forge = MM_GCExtensions::getExtensions(_javaVM)->getForge();490491/* free the list of checks */492GC_Check *mover = _checks;493while(mover) {494mover = mover->getNext();495_checks->kill();496_checks = mover;497}498499/* then this object itself */500forge->free(this);501}502503504