Path: blob/master/runtime/bcverify/bcverify.c
12506 views
/*******************************************************************************1* Copyright (c) 1991, 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 <string.h>2324#include "bcvcfr.h"25#include "bcverify.h"26#include "j9bcvnls.h"2728#include "cfreader.h"29#include "bcnames.h"30#include "pcstack.h"31#include "j9cp.h"32#include "j9protos.h"33#include "j9consts.h"34#include "omrthread.h"35#include "jvminit.h"36#include "vrfyconvert.h"37#include "bcverify_internal.h"38#include "vrfytbl.h"39#include "vmhook_internal.h"40#include "SCQueryFunctions.h"4142#define _UTE_STATIC_43#include "ut_j9bcverify.h"4445#include "bcverify.h"4647/* Define for debug48#define DEBUG_BCV49*/5051#define BYTECODE_MAP_DEFAULT_SIZE (2 * 1024)52#define STACK_MAPS_DEFAULT_SIZE (2 * 1024)53#define LIVE_STACK_DEFAULT_SIZE 25654#define ROOT_QUEUE_DEFAULT_SIZE 25655#define CLASSNAMELIST_DEFAULT_SIZE (128 * sizeof(UDATA *)) /* 128 pointers */56#define CLASSNAMESEGMENT_DEFAULT_SIZE 1024 /* 1k bytes - minimum of 8 bytes per classNameList entry */5758#define BCV_INTERNAL_DEFAULT_SIZE (32*1024)5960#define THIS_DLL_NAME J9_VERIFY_DLL_NAME61#define OPT_XVERIFY "-Xverify"62#define OPT_XVERIFY_COLON "-Xverify:"63#define OPT_ALL "all"64#define OPT_OPT "opt"65#define OPT_NO_OPT "noopt"66#define OPT_NO_FALLBACK "nofallback"67#define OPT_IGNORE_STACK_MAPS "ignorestackmaps"68#define OPT_EXCLUDEATTRIBUTE_EQUAL "excludeattribute="69#define OPT_BOOTCLASSPATH_STATIC "bootclasspathstatic"70#define OPT_DO_PROTECTED_ACCESS_CHECK "doProtectedAccessCheck"7172static IDATA buildBranchMap (J9BytecodeVerificationData * verifyData);73static IDATA decompressStackMaps (J9BytecodeVerificationData * verifyData, IDATA localsCount, U_8 * stackMapData);74static VMINLINE IDATA parseLocals (J9BytecodeVerificationData * verifyData, U_8** stackMapData, J9BranchTargetStack * liveStack, IDATA localDelta, IDATA localsCount, IDATA maxLocals);75static VMINLINE IDATA parseStack (J9BytecodeVerificationData * verifyData, U_8** stackMapData, J9BranchTargetStack * liveStack, UDATA stackCount, UDATA maxStack);76static UDATA parseElement (J9BytecodeVerificationData * verifyData, U_8 ** stackMapData);77static VMINLINE void copyStack (J9BranchTargetStack *source, J9BranchTargetStack *destination);78static IDATA mergeObjectTypes (J9BytecodeVerificationData *verifyData, UDATA sourceType, UDATA * targetTypePointer);79static IDATA mergeStacks (J9BytecodeVerificationData * verifyData, UDATA target);80static J9UTF8 * mergeClasses(J9BytecodeVerificationData *verifyData, U_8* firstClass, UDATA firstLength, U_8* secondClass, UDATA secondLength, IDATA *reasonCode);81static void bcvHookClassesUnload (J9HookInterface** hook, UDATA eventNum, void* eventData, void* userData);82static void printMethod (J9BytecodeVerificationData * verifyData);83static IDATA simulateStack (J9BytecodeVerificationData * verifyData);8485static IDATA parseOptions (J9JavaVM *vm, char *optionValues, char **errorString);86static IDATA setVerifyState ( J9JavaVM *vm, char *option, char **errorString );878889/**90* Walk the J9-format stack maps and set the uninitialized_this flag appropriately91* for each map. It is set to TRUE for the map, if the map's stack contains an92* uninitialized_this object.93* NOTE: This is only necessary for <init> methods.94*/95static void96setInitializedThisStatus(J9BytecodeVerificationData *verifyData)97{98J9BranchTargetStack * currentStack = NULL;99IDATA nextMapIndex = 0;100101while (nextMapIndex < verifyData->stackMapsCount) {102currentStack = BCV_INDEX_STACK (nextMapIndex);103nextMapIndex++;104105/* Ensure we're not a stack map for dead code */106if (currentStack->stackBaseIndex != -1) {107BOOLEAN flag_uninitialized = FALSE;108IDATA i = 0;109for (; i < currentStack->stackTopIndex; i++) {110if ((currentStack->stackElements[i] & BCV_SPECIAL_INIT) == BCV_SPECIAL_INIT) {111flag_uninitialized = TRUE;112break;113}114}115currentStack->uninitializedThis = flag_uninitialized;116}117}118}119120121122/*123API124@verifyData - internal data structure125@firstClass - U_8 pointer to class name126@firstLength - UDATA length of class name127@secondClass - U_8 pointer to class name128@secondLength - UDATA length of class name129130Answer the first common class shared by the two classes.131If one of the classes is a parent of the other, answer that class.132Return NULL on error.133sets reasonCode to BCV_FAIL on verification error134sets reasonCode to BCV_ERR_INSUFFICIENT_MEMORY on OOM135sets reasonCode to BCV_ERR_INTERNAL_ERROR otherwise136*/137#define SUPERCLASS(clazz) ((clazz)->superclasses[ J9CLASS_DEPTH(clazz) - 1 ])138static J9UTF8 *139mergeClasses(J9BytecodeVerificationData *verifyData, U_8* firstClass, UDATA firstLength, U_8* secondClass, UDATA secondLength, IDATA *reasonCode)140{141J9Class *sourceRAM, *targetRAM;142UDATA sourceDepth, targetDepth;143144/* Go get the ROM class for the source and target. Check if it returns null immediately to prevent145* having to load the second class in an error case */146sourceRAM = j9rtv_verifierGetRAMClass( verifyData, verifyData->classLoader, firstClass, firstLength, reasonCode);147if (NULL == sourceRAM) {148return NULL;149}150151targetRAM = j9rtv_verifierGetRAMClass( verifyData, verifyData->classLoader, secondClass, secondLength, reasonCode );152if (NULL == targetRAM) {153return NULL;154}155sourceRAM = J9_CURRENT_CLASS(sourceRAM);156sourceDepth = J9CLASS_DEPTH(sourceRAM);157targetDepth = J9CLASS_DEPTH(targetRAM);158159/* walk up the chain until sourceROM == targetROM */160while( sourceRAM != targetRAM ) {161if( sourceDepth >= targetDepth ) {162sourceRAM = SUPERCLASS(sourceRAM);163if ( sourceRAM ) {164sourceDepth = J9CLASS_DEPTH(sourceRAM);165}166}167if (sourceRAM == targetRAM )168break;169if( sourceDepth <= targetDepth ) {170targetRAM = SUPERCLASS(targetRAM);171if ( targetRAM ) {172targetDepth = J9CLASS_DEPTH(targetRAM);173}174}175if( (sourceRAM == NULL) || (targetRAM == NULL) ) {176*reasonCode = BCV_FAIL;177return NULL;178}179}180181/* good, both sourceROM and targetROM are the same class -- this is the new target class */182return( J9ROMCLASS_CLASSNAME( targetRAM->romClass ) );183}184#undef SUPERCLASS185186187/*188Determine the number of branch targets in this method.189190Returns191count of unique branch targets and exception handler starts.192BCV_ERR_INTERNAL_ERROR for any unexpected error193*/194195static IDATA196buildBranchMap (J9BytecodeVerificationData * verifyData)197{198J9ROMMethod *romMethod = verifyData->romMethod;199U_32 *bytecodeMap = verifyData->bytecodeMap;200U_8 *bcStart;201U_8 *bcIndex;202U_8 *bcEnd;203UDATA npairs, temp;204IDATA pc, start, high, low, pcs;205I_16 shortBranch;206I_32 longBranch;207UDATA bc, size;208UDATA count = 0;209210bcStart = J9_BYTECODE_START_FROM_ROM_METHOD(romMethod);211bcIndex = bcStart;212bcEnd = bcStart + J9_BYTECODE_SIZE_FROM_ROM_METHOD(romMethod);213214while (bcIndex < bcEnd) {215bc = *bcIndex;216size = J9JavaInstructionSizeAndBranchActionTable[bc];217if (size == 0) {218verifyData->errorPC = bcIndex - bcStart;219Trc_BCV_buildBranchMap_UnknownInstruction(verifyData->vmStruct,220(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),221J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),222(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),223J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),224(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(romMethod)),225J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)),226bc, verifyData->errorPC, verifyData->errorPC);227return BCV_ERR_INTERNAL_ERROR;228}229230switch (size >> 4) {231232case 5: /* switches */233start = bcIndex - bcStart;234pc = (start + 4) & ~3;235bcIndex = bcStart + pc;236longBranch = (I_32) PARAM_32(bcIndex, 0);237bcIndex += 4;238if (bytecodeMap[start + longBranch] == 0) {239bytecodeMap[start + longBranch] = BRANCH_TARGET;240count++;241}242low = (I_32) PARAM_32(bcIndex, 0);243bcIndex += 4;244low = (I_32) low;245if (bc == JBtableswitch) {246high = (I_32) PARAM_32(bcIndex, 0);247bcIndex += 4;248high = (I_32) high;249npairs = (UDATA) (high - low + 1);250pcs = 0;251} else {252npairs = (UDATA) low;253pcs = 4;254}255256for (temp = 0; temp < npairs; temp++) {257bcIndex += pcs;258longBranch = (I_32) PARAM_32(bcIndex, 0);259bcIndex += 4;260if (bytecodeMap[start + longBranch] == 0) {261bytecodeMap[start + longBranch] = BRANCH_TARGET;262count++;263}264}265continue;266267case 2: /* gotos */268if (bc == JBgotow) {269start = bcIndex - bcStart;270longBranch = (I_32) PARAM_32(bcIndex, 1);271if (bytecodeMap[start + longBranch] == 0) {272bytecodeMap[start + longBranch] = BRANCH_TARGET;273count++;274}275break;276} /* fall through for JBgoto */277278case 1: /* ifs */279shortBranch = (I_16) PARAM_16(bcIndex, 1);280start = bcIndex - bcStart;281if (bytecodeMap[start + shortBranch] == 0) {282bytecodeMap[start + shortBranch] = BRANCH_TARGET;283count++;284}285break;286287}288bcIndex += size & 7;289}290291/* need to walk exceptions as well, since they are branch targets */292if (romMethod->modifiers & J9AccMethodHasExceptionInfo) {293J9ExceptionInfo * exceptionData = J9_EXCEPTION_DATA_FROM_ROM_METHOD(romMethod);294J9ExceptionHandler *handler;295296if (exceptionData->catchCount) {297handler = J9EXCEPTIONINFO_HANDLERS(exceptionData);298for (temp=0; temp < (U_32) exceptionData->catchCount; temp++) {299pc = (IDATA) handler->startPC;300pcs = (IDATA) handler->handlerPC;301/* Avoid re-walking a handler that handles itself */302if (pc != pcs) {303bytecodeMap[pc] |= BRANCH_EXCEPTION_START;304}305if ((bytecodeMap[pcs] & BRANCH_TARGET) == 0) {306bytecodeMap[pcs] |= BRANCH_TARGET;307count++;308}309handler++;310}311}312}313Trc_BCV_buildBranchMap_branchCount(verifyData->vmStruct,314(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),315J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),316(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),317J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),318(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(romMethod)),319J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)),320count);321322return count;323}324325326327/*328Convert the StackMap Attribute maps to internal uncompressed stackmaps.329330Returns331BCV_SUCCESS on success,332BCV_FAIL on verification error333*/334static IDATA335decompressStackMaps (J9BytecodeVerificationData * verifyData, IDATA localsCount, U_8 * stackMapData)336{337J9ROMMethod *romMethod = verifyData->romMethod;338UDATA maxStack = J9_MAX_STACK_FROM_ROM_METHOD(romMethod);339IDATA maxLocals = J9_ARG_COUNT_FROM_ROM_METHOD(romMethod) + J9_TEMP_COUNT_FROM_ROM_METHOD(romMethod);340UDATA length = (UDATA) J9_BYTECODE_SIZE_FROM_ROM_METHOD(romMethod);341UDATA i;342IDATA rc = BCV_SUCCESS;343J9BranchTargetStack *liveStack = (J9BranchTargetStack *)verifyData->liveStack;344J9BranchTargetStack *branchTargetStack = BCV_FIRST_STACK();345U_8 mapType;346UDATA mapPC = -1;347UDATA temp;348UDATA start = 0; /* Used in BUILD_VERIFY_ERROR */349UDATA mapIndex = 0;350UDATA errorModule = J9NLS_BCV_ERR_NO_ERROR__MODULE; /* default to BCV NLS catalog */351352Trc_BCV_decompressStackMaps_Entry(verifyData->vmStruct, localsCount);353/* localsCount records the current locals depth as all stack maps (except full frame) are relative to the previous frame */354for (i = 0; i < (UDATA) verifyData->stackMapsCount; i++) {355IDATA localDelta = 0;356UDATA stackCount = 0;357358NEXT_U8(mapType, stackMapData);359mapPC++;360361if (mapType < CFR_STACKMAP_SAME_LOCALS_1_STACK) {362/* Same frame 0-63 */363mapPC += (UDATA) mapType;364/* done */365366} else if (mapType < CFR_STACKMAP_SAME_LOCALS_1_STACK_END) {367/* Same with one stack entry frame 64-127 */368mapPC += (UDATA) ((UDATA) mapType - CFR_STACKMAP_SAME_LOCALS_1_STACK);369stackCount = 1;370371} else {372mapPC += NEXT_U16(temp, stackMapData);373374if (mapType == CFR_STACKMAP_SAME_LOCALS_1_STACK_EXTENDED) {375/* Same with one stack entry extended address frame 247 */376stackCount = 1;377378} else if (mapType < CFR_STACKMAP_FULL) {379/* Chop 3-1 locals frame 248-250 */380/* Same with extended address frame 251 */381/* Append 1-3 locals frame 252-254 */382localDelta = ((IDATA) mapType) - CFR_STACKMAP_SAME_EXTENDED;383384} else if (mapType == CFR_STACKMAP_FULL) {385/* Full frame 255 */386localDelta = NEXT_U16(temp, stackMapData);387localsCount = 0;388}389}390391localsCount = parseLocals (verifyData, &stackMapData, liveStack, localDelta, localsCount, maxLocals);392if (localsCount < 0) {393BUILD_VERIFY_ERROR (errorModule, J9NLS_BCV_ERR_INCONSISTENT_STACK__ID);394/* Jazz 82615: Set the pc value of the current stackmap frame to show up in the error message frame work */395liveStack->pc = mapPC;396verifyData->errorPC = mapPC;397398Trc_BCV_decompressStackMaps_LocalsArrayOverFlowUnderFlow(verifyData->vmStruct,399(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),400J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),401(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),402J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),403(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(romMethod)),404J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)),405i, mapPC);406rc = BCV_FAIL;407break;408}409410if (mapType == CFR_STACKMAP_FULL) {411stackCount = NEXT_U16(temp, stackMapData);412}413414if (BCV_SUCCESS != parseStack (verifyData, &stackMapData, liveStack, stackCount, maxStack)) {415BUILD_VERIFY_ERROR (errorModule, J9NLS_BCV_ERR_INCONSISTENT_STACK__ID);416/* Jazz 82615: Set the pc value of the current stackmap frame to show up in the error message frame work */417liveStack->pc = mapPC;418verifyData->errorPC = mapPC;419420Trc_BCV_decompressStackMaps_StackArrayOverFlow(verifyData->vmStruct,421(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),422J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),423(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),424J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),425(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(romMethod)),426J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)),427i, mapPC);428rc = BCV_FAIL;429break;430}431432if (mapPC >= length) {433/* should never get here - caught in staticverify.c checkStackMap */434BUILD_VERIFY_ERROR (errorModule, J9NLS_BCV_ERR_INCONSISTENT_STACK__ID);435Trc_BCV_decompressStackMaps_MapOutOfRange(verifyData->vmStruct,436(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),437J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),438(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),439J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),440(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(romMethod)),441J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)),442i, mapPC, length);443rc = BCV_FAIL;444break;445}446447(verifyData->bytecodeMap)[mapPC] |= (mapIndex << BRANCH_INDEX_SHIFT) | BRANCH_TARGET;448mapIndex++;449450copyStack (liveStack, branchTargetStack);451branchTargetStack->pc = mapPC;452/* Point to the next stack */453branchTargetStack = BCV_NEXT_STACK (branchTargetStack);454}455456Trc_BCV_decompressStackMaps_Exit(verifyData->vmStruct, rc);457return rc;458}459460461462/* Specifically returns BCV_ERR_INTERNAL_ERROR for failure */463464static IDATA465parseLocals (J9BytecodeVerificationData * verifyData, U_8** stackMapData, J9BranchTargetStack * liveStack, IDATA localDelta, IDATA localsCount, IDATA maxLocals)466{467UDATA i;468UDATA stackEntry;469UDATA unusedLocals;470471if (localDelta < 0) {472/* Clear the chopped elements */473for (;localDelta; localDelta++) {474localsCount--;475if (localsCount < 0) {476goto _underflow;477}478liveStack->stackElements[localsCount] = BCV_BASE_TYPE_TOP;479480/* Check long/double type as long as there still remains local variables481* in the stackmap frame.482*/483if (localsCount > 0) {484/* Possibly remove a double or long (counts as 1 local, but two slots).485* A double or a long is pushed as <top, double|long>486*/487stackEntry = liveStack->stackElements[localsCount - 1];488if ((BCV_BASE_TYPE_DOUBLE == stackEntry) || (BCV_BASE_TYPE_LONG == stackEntry)) {489localsCount--;490if (localsCount < 0) {491goto _underflow;492}493liveStack->stackElements[localsCount] = BCV_BASE_TYPE_TOP;494}495}496}497498} else {499for (;localDelta; localDelta--) {500stackEntry = parseElement (verifyData, stackMapData);501if (localsCount >= maxLocals) {502/* Overflow */503goto _overflow;504}505liveStack->stackElements[localsCount++] = stackEntry;506if ((BCV_BASE_TYPE_DOUBLE == stackEntry) || (BCV_BASE_TYPE_LONG == stackEntry)) {507if (localsCount >= maxLocals) {508/* Overflow */509goto _overflow;510}511liveStack->stackElements[localsCount++] = BCV_BASE_TYPE_TOP;512}513}514515/* Clear the remaining locals */516unusedLocals = liveStack->stackBaseIndex - localsCount;517for (i = localsCount; i < (unusedLocals + localsCount); i++) {518liveStack->stackElements[i] = BCV_BASE_TYPE_TOP;519}520}521522return localsCount;523524_underflow:525/* Jazz 82615: Set the error code in the case of underflow on 'locals' in the current stackmap frame */526verifyData->errorDetailCode = BCV_ERR_STACKMAP_FRAME_LOCALS_UNDERFLOW;527528Trc_BCV_parseLocals_LocalsArrayUnderFlow(verifyData->vmStruct,529(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),530J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),531(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),532J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),533(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),534J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)));535return BCV_ERR_INTERNAL_ERROR;536537_overflow:538/* Jazz 82615: Set the error code, the location of the last local variable allowed on 'locals'539* and the maximum local size in the case of overflow on 'locals' in the currrent stackmap frame.540*/541verifyData->errorDetailCode = BCV_ERR_STACKMAP_FRAME_LOCALS_OVERFLOW;542verifyData->errorCurrentFramePosition = (maxLocals > 0) ? (U_32)(maxLocals - 1) : 0;543verifyData->errorTempData = (UDATA)maxLocals;544545Trc_BCV_parseLocals_LocalsArrayOverFlow(verifyData->vmStruct,546(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),547J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),548(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),549J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),550(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),551J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)));552return BCV_ERR_INTERNAL_ERROR;553}554555556/*557* returns BCV_SUCCESS on success558* returns BCV_ERR_INTERNAL_ERROR on failure559*/560561static IDATA562parseStack (J9BytecodeVerificationData * verifyData, U_8** stackMapData, J9BranchTargetStack * liveStack, UDATA stackCount, UDATA maxStack)563{564UDATA stackEntry;565UDATA* stackTop = RELOAD_STACKBASE(liveStack); /* Clears the stack */566UDATA* stackBase = stackTop;567568for (;stackCount; stackCount--) {569stackEntry = parseElement (verifyData, stackMapData);570if ((UDATA) (stackTop - stackBase) >= maxStack) {571/* Jazz 82615: Set the error code and the location of wrong data type on 'stack' (only keep the maximum size for stack) */572verifyData->errorDetailCode = BCV_ERR_STACKMAP_FRAME_STACK_OVERFLOW;573verifyData->errorCurrentFramePosition = (U_32)(stackBase - liveStack->stackElements);574if (maxStack > 0) {575verifyData->errorCurrentFramePosition += (U_32)(maxStack - 1);576}577verifyData->errorTempData = maxStack;578return BCV_ERR_INTERNAL_ERROR;579}580PUSH(stackEntry);581if ((stackEntry == BCV_BASE_TYPE_DOUBLE) || (stackEntry == BCV_BASE_TYPE_LONG)) {582if ((UDATA) (stackTop - stackBase) >= maxStack) {583/* Jazz 82615: Set the error code and the location of wrong data type on 'stack' (only keep the maximum size for stack) */584verifyData->errorDetailCode = BCV_ERR_STACKMAP_FRAME_STACK_OVERFLOW;585verifyData->errorCurrentFramePosition = (U_32)(stackBase - liveStack->stackElements);586if (maxStack > 0) {587verifyData->errorCurrentFramePosition += (U_32)(maxStack - 1);588}589verifyData->errorTempData = maxStack;590return BCV_ERR_INTERNAL_ERROR;591}592PUSH(BCV_BASE_TYPE_TOP);593}594}595596SAVE_STACKTOP(liveStack, stackTop);597return BCV_SUCCESS;598}599600601/*602* returns stackEntry603* No error path in this function604*/605606static UDATA607parseElement (J9BytecodeVerificationData * verifyData, U_8** stackMapData)608{609J9ROMClass * romClass = verifyData->romClass;610U_8 entryType;611U_8 *mapData = *stackMapData;612U_16 cpIndex;613UDATA stackEntry;614615NEXT_U8(entryType, mapData);616617if (entryType < CFR_STACKMAP_TYPE_INIT_OBJECT) {618/* return primitive type */619stackEntry = verificationTokenDecode[entryType];620621} else if (entryType == CFR_STACKMAP_TYPE_INIT_OBJECT) {622J9ROMMethod *romMethod = verifyData->romMethod;623J9UTF8* className = J9ROMCLASS_CLASSNAME(romClass);624stackEntry = convertClassNameToStackMapType(verifyData, J9UTF8_DATA(className), J9UTF8_LENGTH(className), BCV_SPECIAL_INIT, 0);625626} else if (entryType == CFR_STACKMAP_TYPE_OBJECT) {627J9UTF8 *utf8string;628J9ROMConstantPoolItem *constantPool = J9_ROM_CP_FROM_ROM_CLASS(romClass);629630NEXT_U16(cpIndex, mapData);631utf8string = J9ROMSTRINGREF_UTF8DATA((J9ROMStringRef *) (&constantPool[cpIndex]));632pushClassType(verifyData, utf8string, &stackEntry);633634} else if (entryType == CFR_STACKMAP_TYPE_NEW_OBJECT) {635NEXT_U16(cpIndex, mapData);636stackEntry = BCV_SPECIAL_NEW | (((UDATA) cpIndex) << BCV_CLASS_INDEX_SHIFT);637638} else {639/* Primitive arrays */640U_16 arity;641642stackEntry = (UDATA) verificationTokenDecode[entryType];643NEXT_U16(arity, mapData);644stackEntry |= (((UDATA) arity) << BCV_ARITY_SHIFT);645}646647*stackMapData = mapData;648return stackEntry;649}650651652653static void654copyStack (J9BranchTargetStack *source, J9BranchTargetStack *destination)655{656UDATA pc = destination->pc;657658memcpy((UDATA *) destination, (UDATA *) source, (source->stackTopIndex + BCV_TARGET_STACK_HEADER_UDATA_SIZE) * sizeof(UDATA));659660destination->pc = pc;661}662663664/* returns665* BCV_SUCCESS : no merge necessary666* BCV_FAIL : cause a rewalk667* BCV_ERR_INSUFFICIENT_MEMORY : OOM - no rewalk668*/669static IDATA670mergeObjectTypes (J9BytecodeVerificationData *verifyData, UDATA sourceType, UDATA * targetTypePointer)671{672J9ROMClass * romClass = verifyData->romClass;673UDATA targetType = *targetTypePointer;674UDATA sourceIndex, targetIndex;675J9UTF8 *name;676UDATA classArity, targetArity, classIndex;677IDATA rc = BCV_SUCCESS;678U_8 *sourceName, *targetName;679UDATA sourceLength, targetLength;680U_32 *offset;681IDATA reasonCode = 0;682683/* assume that sourceType and targetType are not equal */684685/* if target is more general than source, then its fine */686rc = isClassCompatible( verifyData, sourceType, targetType, &reasonCode ) ;687688if (TRUE == rc) {689return BCV_SUCCESS; /* no merge required */690} else { /* FALSE == rc */691/* VM error, no need to continue, return appropriate rc */692if (BCV_ERR_INTERNAL_ERROR == reasonCode) {693*targetTypePointer = (U_32)BCV_JAVA_LANG_OBJECT_INDEX << BCV_CLASS_INDEX_SHIFT;694Trc_BCV_mergeObjectTypes_UnableToLoadClass(verifyData->vmStruct,695(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),696J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),697(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),698J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),699(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),700J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),701sourceType, targetType);702return (IDATA) BCV_FAIL;703} else if (BCV_ERR_INSUFFICIENT_MEMORY == reasonCode) {704Trc_BCV_mergeObjectTypes_MergeClasses_OutOfMemoryException(verifyData->vmStruct,705(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),706J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),707(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),708J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),709(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),710J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)));711return BCV_ERR_INSUFFICIENT_MEMORY;712}713}714715/* Types were not compatible, thus target is not equal or more general than source */716717/* NULL always loses to objects */718if (targetType == BCV_BASE_TYPE_NULL) {719Trc_BCV_mergeObjectTypes_NullTargetOverwritten(verifyData->vmStruct,720(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),721J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),722(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),723J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),724(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),725J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),726sourceType);727*targetTypePointer = sourceType;728/* cause a re-walk */729return (IDATA) BCV_FAIL;730}731732/* if the source or target are base type arrays, decay them to object arrays of arity n-1 (or just Object) */733/* Base arrays already have an implicit arity of 1, so just keep the arity for object */734if (sourceType & BCV_TAG_BASE_ARRAY_OR_NULL) {735Trc_BCV_mergeObjectTypes_DecaySourceArray(verifyData->vmStruct,736(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),737J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),738(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),739J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),740(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),741J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),742sourceType);743sourceType = (sourceType & BCV_ARITY_MASK) | ((U_32)BCV_JAVA_LANG_OBJECT_INDEX << BCV_CLASS_INDEX_SHIFT);744}745746if (targetType & BCV_TAG_BASE_ARRAY_OR_NULL) {747Trc_BCV_mergeObjectTypes_DecayTargetArray(verifyData->vmStruct,748(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),749J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),750(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),751J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),752(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),753J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),754targetType);755targetType = (targetType & BCV_ARITY_MASK) | ((U_32)BCV_JAVA_LANG_OBJECT_INDEX << BCV_CLASS_INDEX_SHIFT);756}757758classArity = sourceType & BCV_ARITY_MASK;759targetArity = targetType & BCV_ARITY_MASK;760761if (classArity == targetArity) {762/* Find the common parent class if the same arity */763764sourceIndex = (sourceType & BCV_CLASS_INDEX_MASK) >> BCV_CLASS_INDEX_SHIFT;765targetIndex = (targetType & BCV_CLASS_INDEX_MASK) >> BCV_CLASS_INDEX_SHIFT;766767offset = (U_32 *) verifyData->classNameList[sourceIndex];768sourceLength = (UDATA) J9UTF8_LENGTH(offset + 1);769770if (offset[0] == 0) {771sourceName = J9UTF8_DATA(offset + 1);772773} else {774sourceName = (U_8 *) ((UDATA) offset[0] + (UDATA) romClass);775}776777offset = (U_32 *) verifyData->classNameList[targetIndex];778targetLength = (UDATA) J9UTF8_LENGTH(offset + 1);779780if (offset[0] == 0) {781targetName = J9UTF8_DATA(offset + 1);782783} else {784targetName = (U_8 *) ((UDATA) offset[0] + (UDATA) romClass);785}786787name = mergeClasses(verifyData, sourceName, sourceLength, targetName, targetLength, &reasonCode);788789if (NULL == name) {790if (BCV_ERR_INSUFFICIENT_MEMORY == reasonCode) {791Trc_BCV_mergeObjectTypes_MergeClasses_OutOfMemoryException(verifyData->vmStruct,792(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),793J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),794(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),795J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),796(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),797J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)));798return BCV_ERR_INSUFFICIENT_MEMORY;799} else {800Trc_BCV_mergeObjectTypes_MergeClassesFail(verifyData->vmStruct,801(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),802J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),803(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),804J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),805(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),806J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),807sourceLength, sourceName, targetLength, targetName);808*targetTypePointer = sourceType;809/* cause a re-walk */810return (IDATA) BCV_FAIL;811}812}813814classIndex = findClassName( verifyData, J9UTF8_DATA(name), J9UTF8_LENGTH(name) );815Trc_BCV_mergeObjectTypes_MergeClassesSucceed(verifyData->vmStruct,816(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),817J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),818(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),819J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),820(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),821J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),822sourceLength, sourceName, targetLength, targetName, J9UTF8_LENGTH(name), J9UTF8_DATA(name), classIndex);823824} else {825826/* Different arity means common parent class is the minimum arity of class Object */827classIndex = BCV_JAVA_LANG_OBJECT_INDEX;828829Trc_BCV_mergeObjectTypes_MergeClassesMinimumArity(verifyData->vmStruct,830(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),831J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),832(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),833J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),834(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),835J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),836classArity, targetArity);837/* Find minimum common arity of arrays */838if( targetArity < classArity ) {839classArity = targetArity;840}841}842843/* slam new type into targetTypePointer */844*targetTypePointer = classArity | ( classIndex << BCV_CLASS_INDEX_SHIFT );845Trc_BCV_mergeObjectTypes_MergedClass(verifyData->vmStruct,846(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),847J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),848(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),849J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),850(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),851J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),852*targetTypePointer);853/* cause a re-walk */854return (IDATA) BCV_FAIL;855}856857/*858* returns BCV_SUCCESS on success859* returns BCV_FAIL on failure860* returns BCV_ERR_INSUFFICIENT_MEMORY on OOM */861static IDATA862mergeStacks (J9BytecodeVerificationData * verifyData, UDATA target)863{864J9ROMClass *romClass = verifyData->romClass;865J9ROMMethod *romMethod = verifyData->romMethod;866UDATA maxIndex = J9_ARG_COUNT_FROM_ROM_METHOD(romMethod) + J9_TEMP_COUNT_FROM_ROM_METHOD(romMethod);867U_32 *bytecodeMap = verifyData->bytecodeMap;868UDATA i = 0;869UDATA stackIndex = bytecodeMap[target] >> BRANCH_INDEX_SHIFT;870IDATA rewalk = FALSE;871IDATA rc = BCV_SUCCESS;872UDATA *targetStackPtr = NULL;873UDATA *targetStackTop = NULL;874UDATA *sourceStackPtr = NULL;875UDATA *sourceStackTop = NULL;876UDATA *sourceStackTemps = NULL;877J9BranchTargetStack *liveStack = (J9BranchTargetStack *) verifyData->liveStack;878J9BranchTargetStack *targetStack = BCV_INDEX_STACK(stackIndex);879880Trc_BCV_mergeStacks_Entry(verifyData->vmStruct,881(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),882J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),883(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),884J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),885(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),886J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),887target, target);888889if (targetStack->stackBaseIndex == -1) {890891/* Target location does not have a stack, so give the target our current stack */892copyStack(liveStack, targetStack);893verifyData->unwalkedQueue[verifyData->unwalkedQueueTail++] = target;894verifyData->unwalkedQueueTail %= (verifyData->rootQueueSize / sizeof(UDATA));895bytecodeMap[target] |= BRANCH_ON_UNWALKED_QUEUE;896Trc_BCV_mergeStacks_CopyStack(verifyData->vmStruct,897(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),898J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),899(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),900J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),901(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),902J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),903stackIndex, target, target);904goto _finished;905906} else {907/* These variables are reused across loop iterations */908UDATA mergePC = (UDATA) -1;909U_32 resultArrayBase = 0;910911/* Check stack size equality */912if (targetStack->stackTopIndex != liveStack->stackTopIndex) {913rc = BCV_FAIL;914Trc_BCV_mergeStacks_DepthMismatch(verifyData->vmStruct,915(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),916J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),917(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),918J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),919(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),920J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),921stackIndex, target, target,922liveStack->stackTopIndex, targetStack->stackTopIndex);923goto _finished;924}925926/* Now we have to merge stacks */927targetStackPtr = targetStack->stackElements;928targetStackTop = RELOAD_STACKTOP(targetStack);929sourceStackPtr = liveStack->stackElements;930sourceStackTop = RELOAD_STACKTOP(liveStack);931932/* remember where the temps end */933sourceStackTemps = RELOAD_STACKBASE(liveStack);934935Trc_BCV_mergeStacks_MergeStacks(verifyData->vmStruct,936(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),937J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),938(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),939J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),940(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),941J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),942stackIndex, target, target);943944while (sourceStackPtr != sourceStackTop) {945946/* Merge if the source and target slots are not identical */947if (*sourceStackPtr != *targetStackPtr) {948UDATA sourceItem = *sourceStackPtr;949UDATA targetItem = *targetStackPtr;950951/* Merge in the locals */952if (sourceStackPtr < sourceStackTemps ) {953954/* Merge when either the source or target not an object */955if ((sourceItem | targetItem) & (BCV_BASE_OR_SPECIAL)) {956957/* Mismatch results in undefined local - rewalk if modified stack958* Note: BCV_SPECIAL_INIT must be reserved to flag the uninitialized_this object959* existing in the stackmap frame when invoking setInitializedThisStatus() after960* the stackmaps are successfully built.961*/962if (((UDATA)(BCV_BASE_TYPE_TOP) != targetItem)963&& (0 == (targetItem & BCV_SPECIAL_INIT))964) {965*targetStackPtr = (UDATA) (BCV_BASE_TYPE_TOP);966rewalk = TRUE;967}968969/* Merge two objects */970} else {971972/* extra checks here to avoid calling local mapper unnecessarily */973/* Null source or java/lang/Object targets always work trivially */974if ((*sourceStackPtr != BCV_BASE_TYPE_NULL) && (*targetStackPtr != (BCV_JAVA_LANG_OBJECT_INDEX << BCV_CLASS_INDEX_SHIFT))) {975976/* Null target always causes a re-walk - source is never null here */977if (*targetStackPtr == BCV_BASE_TYPE_NULL) {978*targetStackPtr = *sourceStackPtr;979rewalk = TRUE;980} else {981/* Use local mapper to check merge necessity in locals */982if ((verifyData->verificationFlags & J9_VERIFY_OPTIMIZE) && (maxIndex <= 32)) {983/* Only handle 32 locals or less */984UDATA index = (UDATA) (sourceStackPtr - liveStack->stackElements);985986/* Reuse map in this merge if needed for multiple merges at same map */987if (mergePC == ((UDATA) -1)) {988mergePC = target;989if (j9localmap_LocalBitsForPC(verifyData->portLib, romClass, romMethod, mergePC, &resultArrayBase, NULL, NULL, NULL) != 0) {990/* local map error - force a full merge */991resultArrayBase = (U_32) -1;992}993}994995if (resultArrayBase & (1 << index)) {996UDATA origSource = *sourceStackPtr;997UDATA origTarget = *targetStackPtr;998IDATA tempRC = mergeObjectTypes(verifyData, *sourceStackPtr, targetStackPtr);9991000/* Merge the objects - the result is live */1001if (BCV_FAIL == tempRC) {1002rewalk = TRUE;1003} else if (BCV_ERR_INSUFFICIENT_MEMORY == tempRC) {1004rc = BCV_ERR_INSUFFICIENT_MEMORY;1005goto _finished;1006}10071008Trc_BCV_mergeStacks_OptMergeRequired(verifyData->vmStruct,1009(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),1010J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),1011(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),1012J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),1013(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),1014J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),1015origSource, origTarget, *targetStackPtr);10161017} else {1018Trc_BCV_mergeStacks_OptMergeNotRequired(verifyData->vmStruct,1019(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),1020J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),1021(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),1022J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),1023(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),1024J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),1025*sourceStackPtr, *targetStackPtr);1026/* Tag undefined - local variable is dead */1027*targetStackPtr = (UDATA) (BCV_BASE_TYPE_TOP);1028rewalk = TRUE;1029}10301031} else {1032IDATA tempRC = mergeObjectTypes(verifyData, *sourceStackPtr, targetStackPtr);1033if (BCV_FAIL == tempRC) {1034rewalk = TRUE;1035} else if (BCV_ERR_INSUFFICIENT_MEMORY == tempRC) {1036rc = BCV_ERR_INSUFFICIENT_MEMORY;1037goto _finished;1038}1039}1040}1041}1042}10431044/* Merge is on the stack */1045} else {10461047if (!((sourceItem | targetItem) & BCV_BASE_OR_SPECIAL)) {1048/* Merge two objects */1049IDATA tempRC = mergeObjectTypes(verifyData, *sourceStackPtr, targetStackPtr);1050if (BCV_FAIL == tempRC) {1051rewalk = TRUE;1052} else if (BCV_ERR_INSUFFICIENT_MEMORY == tempRC) {1053rc = BCV_ERR_INSUFFICIENT_MEMORY;1054goto _finished;1055}1056}1057}1058}1059sourceStackPtr++;1060targetStackPtr++;1061}1062}10631064/* add to the root set if we changed the target stack */1065if (rewalk) {1066if (!(bytecodeMap[target] & BRANCH_ON_REWALK_QUEUE)) {1067Trc_BCV_mergeStacks_QueueForRewalk(verifyData->vmStruct,1068(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),1069J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),1070(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),1071J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),1072(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),1073J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),1074target, target);1075verifyData->rewalkQueue[verifyData->rewalkQueueTail++] = target;1076verifyData->rewalkQueueTail %= (verifyData->rootQueueSize / sizeof(UDATA));1077bytecodeMap[target] |= BRANCH_ON_REWALK_QUEUE;1078bytecodeMap[target] &= ~BRANCH_ON_UNWALKED_QUEUE;1079}1080}10811082_finished:10831084Trc_BCV_mergeStacks_Exit(verifyData->vmStruct,1085(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),1086J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),1087(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(verifyData->romMethod)),1088J9UTF8_DATA(J9ROMMETHOD_NAME(verifyData->romMethod)),1089(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),1090J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(verifyData->romMethod)),1091rc);10921093return rc;1094}109510961097109810991100#ifdef DEBUG_BCV1101static void1102printMethod (J9BytecodeVerificationData * verifyData)1103{1104J9ROMClass *romClass = verifyData->romCLass;1105J9ROMMethod *method = verifyData->romMethod;1106U_8* string;1107#if 01108J9CfrAttributeExceptions* exceptions;1109#endif1110IDATA arity, i, j;11111112string = J9UTF8_DATA(J9ROMCLASS_CLASSNAME(romClass));1113printf("<");1114for( i=0; i< J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(romClass)); i++ )1115{1116printf( "%c", (string[i] == '/')?'.':string[i]);1117}1118printf(">");11191120if( strncmp( string, "java/util/Arrays", i ) == 0 ) {1121printf("stop");1122}11231124/* Return type. */1125string = J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(method));1126i = 0;1127while(string[i++] != ')');1128arity = 0;1129while(string[i] == '[') arity++, i++;1130switch(string[i])1131{1132case 'B':1133printf( "byte");1134break;11351136case 'C':1137printf( "char");1138break;11391140case 'D':1141printf( "double");1142break;11431144case 'F':1145printf( "float");1146break;11471148case 'I':1149printf( "int");1150break;11511152case 'J':1153printf( "long");1154break;11551156case 'L':1157i++;1158while(string[i] != ';')1159{1160printf( "%c", (string[i] == '/')?'.':string[i]);1161i++;1162}1163break;11641165case 'S':1166printf( "short");1167break;11681169case 'V':1170printf( "void");1171break;11721173case 'Z':1174printf( "boolean");1175break;1176}1177for(i = 0; i < arity; i++)1178printf( "[]");11791180printf( " %.*s(", J9UTF8_LENGTH(J9ROMMETHOD_NAME(method)), J9UTF8_DATA(J9ROMMETHOD_NAME(method)));11811182for(i = 1; string[i] != ')'; i++)1183{1184arity = 0;1185while(string[i] == '[') arity++, i++;1186switch(string[i])1187{1188case 'B':1189printf( "byte");1190break;11911192case 'C':1193printf( "char");1194break;11951196case 'D':1197printf( "double");1198break;11991200case 'F':1201printf( "float");1202break;12031204case 'I':1205printf( "int");1206break;12071208case 'J':1209printf( "long");1210break;12111212case 'L':1213i++;1214while(string[i] != ';')1215{1216printf( "%c", (string[i] == '/')?'.':string[i]);1217i++;1218}1219break;12201221case 'S':1222printf( "short");1223break;12241225case 'V':1226printf( "void");1227break;12281229case 'Z':1230printf( "boolean");1231break;1232}1233for(j = 0; j < arity; j++)1234printf( "[]");12351236if(string[i + 1] != ')')1237printf( ", ");1238}12391240printf( ")");1241#if 0 /* need to fix this code to work with J9ROMMethods.. */1242for(i = 0; i < method->attributesCount; i++)1243{1244if(method->attributes[i]->tag == CFR_ATTRIBUTE_Exceptions)1245{1246exceptions = (J9CfrAttributeExceptions*)method->attributes[i];12471248printf( " throws ");1249for(j = 0; j < exceptions->numberOfExceptions - 1; j++)1250{1251if(exceptions->exceptionIndexTable[j] != 0)1252{1253index = classfile->constantPool[exceptions->exceptionIndexTable[j]].slot1;1254string = classfile->constantPool[index].bytes;1255while(*string)1256{1257printf( "%c", (*string == '/')?'.':*string);1258string++;1259}1260printf( ", ");1261}1262}1263index = classfile->constantPool[exceptions->exceptionIndexTable[j]].slot1;1264string = classfile->constantPool[index].bytes;1265while(*string)1266{1267printf( "%c", (*string == '/')?'.':*string);1268string++;1269}12701271i = method->attributesCount;1272}1273}1274#endif1275printf( ";\n");1276return;1277}127812791280#endif12811282/*1283* return BCV_SUCCESS on success1284* returns BCV_ERR_INTERNAL_ERROR on any errors1285* returns BCV_ERR_INSUFFICIENT_MEMORY on OOM12861287*/12881289static IDATA1290simulateStack (J9BytecodeVerificationData * verifyData)1291{12921293#define CHECK_END \1294if(pc > length) { \1295errorType = J9NLS_BCV_ERR_UNEXPECTED_EOF__ID; \1296verboseErrorCode = BCV_ERR_UNEXPECTED_EOF; \1297goto _verifyError; \1298}12991300J9ROMClass * romClass = verifyData->romClass;1301J9ROMMethod * romMethod = verifyData->romMethod;1302J9BranchTargetStack * liveStack = (J9BranchTargetStack *) verifyData->liveStack;1303U_32 * bytecodeMap = verifyData->bytecodeMap;1304IDATA start = 0;1305UDATA pc = 0;1306UDATA length, index, target;1307J9ROMConstantPoolItem *constantPool;1308J9ROMConstantPoolItem *info;1309J9UTF8 *utf8string;1310U_8 *code;1311U_8 *bcIndex;1312UDATA bc = 0;1313UDATA popCount, type1, type2, action;1314UDATA type, temp1, temp2, temp3, maxStack;1315UDATA justLoadedStack = FALSE;1316UDATA *stackBase;1317UDATA *stackTop;1318UDATA *temps;1319UDATA stackIndex;1320UDATA wideIndex = FALSE;1321UDATA *ptr;1322IDATA i1, i2;1323UDATA classIndex;1324UDATA errorModule = J9NLS_BCV_ERR_NO_ERROR__MODULE; /* default to BCV NLS catalog */1325U_16 errorType;1326I_16 offset16;1327I_32 offset32;1328J9BranchTargetStack * branch;1329UDATA checkIfInsideException = romMethod->modifiers & J9AccMethodHasExceptionInfo;1330UDATA tempStoreChange;1331J9ExceptionInfo *exceptionData = J9_EXCEPTION_DATA_FROM_ROM_METHOD(romMethod);1332J9ExceptionHandler *handler;1333UDATA exception;1334J9SRP *callSiteData = (J9SRP *) J9ROMCLASS_CALLSITEDATA(romClass);1335UDATA* originalStackTop;1336UDATA originalStackZeroEntry;1337/* Jazz 104084: Initialize verification error codes by default */1338IDATA verboseErrorCode = 0;1339UDATA errorTargetType = (UDATA)-1;1340UDATA errorStackIndex = (UDATA)-1;1341UDATA errorTempData = (UDATA)-1;13421343Trc_BCV_simulateStack_Entry(verifyData->vmStruct);13441345#ifdef DEBUG_BCV1346printMethod(verifyData);1347#endif13481349verifyData->unwalkedQueueHead = 0;1350verifyData->unwalkedQueueTail = 0;1351verifyData->rewalkQueueHead = 0;1352verifyData->rewalkQueueTail = 0;13531354code = J9_BYTECODE_START_FROM_ROM_METHOD(romMethod);1355length = (UDATA) J9_BYTECODE_SIZE_FROM_ROM_METHOD(romMethod);1356maxStack = J9_MAX_STACK_FROM_ROM_METHOD(romMethod);13571358/* Jazz 105041: Initialize the 1st data slot on 'stack' with 'top' (placeholdler)1359* to avoid storing garbage data type in the error message buffer1360* when stack underflow occurs.1361*/1362liveStack->stackElements[liveStack->stackBaseIndex] = BCV_BASE_TYPE_TOP;13631364RELOAD_LIVESTACK;13651366bcIndex = code;13671368constantPool = J9_ROM_CP_FROM_ROM_CLASS(romClass);13691370while (pc < length) {1371if ((UDATA) (stackTop - stackBase) > maxStack) {1372errorType = J9NLS_BCV_ERR_STACK_OVERFLOW__ID;1373verboseErrorCode = BCV_ERR_STACK_OVERFLOW;1374SAVE_STACKTOP(liveStack, stackTop);1375goto _verifyError;1376}13771378/* If exception start PC, or possible branch to inside an exception range, */1379/* copy the existing stack shape into the exception stack */1380if ((bytecodeMap[pc] & BRANCH_EXCEPTION_START) || (justLoadedStack && checkIfInsideException)) {1381handler = J9EXCEPTIONINFO_HANDLERS(exceptionData);1382SAVE_STACKTOP(liveStack, stackTop);13831384/* Save the current liveStack element zero */1385/* Reset the stack pointer to push the exception on the empty stack */1386originalStackTop = stackTop;1387originalStackZeroEntry = liveStack->stackElements[liveStack->stackBaseIndex];13881389for (exception = 0; exception < (UDATA) exceptionData->catchCount; exception++) {13901391/* find the matching branch target, and copy/merge the stack with the exception object */1392if ((pc >= handler->startPC) && (pc < handler->endPC)) {1393#ifdef DEBUG_BCV1394printf("exception startPC: %d\n", handler->startPC);1395#endif1396stackIndex = bytecodeMap[handler->handlerPC] >> BRANCH_INDEX_SHIFT;1397branch = BCV_INDEX_STACK (stackIndex);13981399/* "push" the exception object */1400classIndex = BCV_JAVA_LANG_THROWABLE_INDEX;1401if (handler->exceptionClassIndex) {1402/* look up the class in the constant pool */1403utf8string = J9ROMSTRINGREF_UTF8DATA((J9ROMStringRef *)(&constantPool [handler->exceptionClassIndex]));1404classIndex = findClassName(verifyData, J9UTF8_DATA(utf8string), J9UTF8_LENGTH(utf8string));1405}14061407/* Empty the stack */1408stackTop = &(liveStack->stackElements[liveStack->stackBaseIndex]);1409PUSH(classIndex << BCV_CLASS_INDEX_SHIFT);1410SAVE_STACKTOP(liveStack, stackTop);14111412if (BCV_ERR_INSUFFICIENT_MEMORY == mergeStacks (verifyData, handler->handlerPC)) {1413errorType = J9NLS_BCV_ERR_VERIFY_OUT_OF_MEMORY__ID;1414goto _outOfMemoryError;1415}1416}1417handler++;1418}14191420/* Restore liveStack */1421liveStack->stackElements[liveStack->stackBaseIndex] = originalStackZeroEntry;1422stackTop = originalStackTop;1423}14241425start = (IDATA) pc;14261427/* Merge all branchTargets encountered */1428if (bytecodeMap[pc] & BRANCH_TARGET) {1429/* Don't try to merge a stack we just loaded */1430if (!justLoadedStack) {1431SAVE_STACKTOP(liveStack, stackTop);1432if (BCV_ERR_INSUFFICIENT_MEMORY == mergeStacks (verifyData, start)) {1433errorType = J9NLS_BCV_ERR_VERIFY_OUT_OF_MEMORY__ID;1434goto _outOfMemoryError;1435}1436goto _checkFinished;1437}1438}1439justLoadedStack = FALSE;14401441bcIndex = code + pc;1442bc = *bcIndex;1443#ifdef DEBUG_BCV1444#if 1 /* for really verbose logging */1445printf("pc: %d bc: %d\n", pc, bc);1446#endif1447#endif1448pc += (J9JavaInstructionSizeAndBranchActionTable[bc] & 7);1449CHECK_END;14501451popCount = JavaStackActionTable[bc] & 0x07;1452if ((stackTop - popCount) < stackBase) {1453errorType = J9NLS_BCV_ERR_STACK_UNDERFLOW__ID;1454verboseErrorCode = BCV_ERR_STACK_UNDERFLOW;1455/* Given that the actual data type involved has not yet been located through pop operation1456* when stack underflow occurs, it needs to step back by 1 slot to the actual data type1457* to be manipulated by the opcode.1458*/1459errorStackIndex = (U_32)(stackTop - liveStack->stackElements - 1);1460/* Always set to the location of the 1st data type on 'stack' to show up if stackTop <= stackBase */1461if (stackTop <= stackBase) {1462errorStackIndex = (U_32)(stackBase - liveStack->stackElements);1463}1464goto _verifyError;1465}14661467type1 = (UDATA) J9JavaBytecodeVerificationTable[bc];1468action = type1 >> 8;1469type2 = (type1 >> 4) & 0xF;1470type1 = (UDATA) decodeTable[type1 & 0xF];1471type2 = (UDATA) decodeTable[type2];14721473switch (action) {1474case RTV_NOP:1475case RTV_INCREMENT:1476break;14771478case RTV_WIDE_LOAD_TEMP_PUSH:1479if (type1 == BCV_GENERIC_OBJECT) {1480/* Only set for wide Objects - primitives don't read temps */1481wideIndex = TRUE;1482} /* Fall through case !!! */14831484case RTV_LOAD_TEMP_PUSH:1485if (type1 == BCV_GENERIC_OBJECT) {1486/* aload family */1487index = type2 & 0x7;1488if (type2 == 0) {1489index = PARAM_8(bcIndex, 1);1490if (wideIndex) {1491index = PARAM_16(bcIndex, 1);1492wideIndex = FALSE;1493}1494}1495type1 = temps[index];1496PUSH(type1);1497break;1498} /* Fall through case !!! */14991500case RTV_PUSH_CONSTANT:15011502_pushConstant:1503PUSH(type1);1504if (type1 & BCV_WIDE_TYPE_MASK) {1505PUSH(BCV_BASE_TYPE_TOP);1506}1507break;15081509case RTV_PUSH_CONSTANT_POOL_ITEM:1510switch (bc) {1511case JBldc:1512case JBldcw:1513if (bc == JBldc) {1514index = PARAM_8(bcIndex, 1);1515} else {1516index = PARAM_16(bcIndex, 1);1517}1518stackTop = pushLdcType(verifyData, romClass, index, stackTop);1519break;15201521/* Change lookup table to generate constant of correct type */1522case JBldc2lw:1523PUSH_LONG_CONSTANT;1524break;15251526case JBldc2dw:1527PUSH_DOUBLE_CONSTANT;1528break;1529}1530break;15311532case RTV_ARRAY_FETCH_PUSH:1533DROP(1);1534type = POP;1535if (type != BCV_BASE_TYPE_NULL) {1536if (bc == JBaaload) {1537type1 = type - 0x01000000; /* reduce types arity by one */1538PUSH(type1);1539break;1540}1541}1542goto _pushConstant;1543break;15441545case RTV_WIDE_POP_STORE_TEMP:1546wideIndex = TRUE; /* Fall through case !!! */15471548case RTV_POP_STORE_TEMP:1549index = type2 & 0x7;1550if (type2 == 0) {1551index = PARAM_8(bcIndex, 1);1552if (wideIndex) {1553index = PARAM_16(bcIndex, 1);1554wideIndex = FALSE;1555}1556}15571558tempStoreChange = FALSE;15591560if (type1 == BCV_GENERIC_OBJECT) {1561/* astore family */1562type = POP;1563tempStoreChange = (type != temps[index]);1564STORE_TEMP(index, type);1565} else {1566DROP(popCount);1567/* because of pre-index local clearing - the order here matters */1568if (type1 & BCV_WIDE_TYPE_MASK) {1569tempStoreChange = (temps[index + 1] != BCV_BASE_TYPE_TOP);1570STORE_TEMP((index + 1), BCV_BASE_TYPE_TOP);1571}1572tempStoreChange |= (type1 != temps[index]);1573STORE_TEMP(index, type1);1574}15751576if (checkIfInsideException && tempStoreChange) {1577/* For all exception handlers covering this instruction */1578handler = J9EXCEPTIONINFO_HANDLERS(exceptionData);1579SAVE_STACKTOP(liveStack, stackTop);15801581/* Save the current liveStack element zero */1582/* Reset the stack pointer to push the exception on the empty stack */1583originalStackTop = stackTop;1584originalStackZeroEntry = liveStack->stackElements[liveStack->stackBaseIndex];15851586for (exception = 0; exception < (UDATA) exceptionData->catchCount; exception++) {15871588/* Find all matching exception ranges and copy/merge the stack with the exception object */1589if (((UDATA) start >= handler->startPC) && ((UDATA) start < handler->endPC)) {1590#ifdef DEBUG_BCV1591printf("exception map change at startPC: %d\n", handler->startPC);1592#endif1593stackIndex = bytecodeMap[handler->handlerPC] >> BRANCH_INDEX_SHIFT;1594branch = BCV_INDEX_STACK (stackIndex);15951596/* "push" the exception object */1597classIndex = BCV_JAVA_LANG_THROWABLE_INDEX;1598if (handler->exceptionClassIndex) {1599/* look up the class in the constant pool */1600utf8string = J9ROMSTRINGREF_UTF8DATA((J9ROMStringRef *) (&constantPool [handler->exceptionClassIndex]));1601classIndex = findClassName(verifyData, J9UTF8_DATA(utf8string), J9UTF8_LENGTH(utf8string));1602}16031604/* Empty the stack */1605stackTop = &(liveStack->stackElements[liveStack->stackBaseIndex]);1606PUSH(classIndex << BCV_CLASS_INDEX_SHIFT);1607SAVE_STACKTOP(liveStack, stackTop);16081609if (BCV_ERR_INSUFFICIENT_MEMORY == mergeStacks (verifyData, branch->pc)) {1610errorType = J9NLS_BCV_ERR_VERIFY_OUT_OF_MEMORY__ID;1611goto _outOfMemoryError;1612}1613}1614handler++;1615}16161617/* Restore liveStack */1618liveStack->stackElements[liveStack->stackBaseIndex] = originalStackZeroEntry;1619stackTop = originalStackTop;1620}1621break;16221623case RTV_POP_X_PUSH_X:1624popCount = 0;1625if (type2) {1626/* shift family */1627popCount = 1;1628} /* fall through */16291630case RTV_ARRAY_STORE:1631DROP(popCount);1632break;16331634case RTV_POP_X_PUSH_Y:1635/* Cause push of output type */1636type1 = type2; /* fall through */16371638case RTV_POP_2_PUSH:1639DROP(popCount);1640goto _pushConstant;1641break;16421643case RTV_BRANCH:1644popCount = type2 & 0x07;1645stackTop -= popCount;16461647if (bc == JBgotow) {1648offset32 = (I_32) PARAM_32(bcIndex, 1);1649target = start + offset32;1650} else {1651offset16 = (I_16) PARAM_16(bcIndex, 1);1652target = start + offset16;1653}16541655SAVE_STACKTOP(liveStack, stackTop);1656/* Merge our stack to the target */1657if (BCV_ERR_INSUFFICIENT_MEMORY == mergeStacks (verifyData, target)) {1658errorType = J9NLS_BCV_ERR_VERIFY_OUT_OF_MEMORY__ID;1659goto _outOfMemoryError;1660}16611662/* Unconditional branch (goto family) */1663if (popCount == 0) {1664goto _checkFinished;1665}1666break;16671668case RTV_RETURN:1669goto _checkFinished;1670break;16711672case RTV_STATIC_FIELD_ACCESS:1673index = PARAM_16(bcIndex, 1);1674info = &constantPool[index];1675utf8string = ((J9UTF8 *) (J9ROMNAMEANDSIGNATURE_SIGNATURE(J9ROMFIELDREF_NAMEANDSIGNATURE((J9ROMFieldRef *) info))));16761677if (bc >= JBgetfield) {1678/* field bytecode receiver */1679DROP(1);1680}16811682if (bc & 1) {1683/* JBputfield/JBpustatic - odd bc's */1684DROP(1);1685if ((*J9UTF8_DATA(utf8string) == 'D') || (*J9UTF8_DATA(utf8string) == 'J')) {1686DROP(1);1687}16881689} else {1690/* JBgetfield/JBgetstatic - even bc's */1691stackTop = pushFieldType(verifyData, utf8string, stackTop);1692}1693break;16941695case RTV_SEND:1696if (bc == JBinvokeinterface2) {1697/* Set to point to JBinvokeinterface */1698bcIndex += 2;1699}1700index = PARAM_16(bcIndex, 1);1701if (JBinvokestaticsplit == bc) {1702index = *(U_16 *)(J9ROMCLASS_STATICSPLITMETHODREFINDEXES(romClass) + index);1703} else if (JBinvokespecialsplit == bc) {1704index = *(U_16 *)(J9ROMCLASS_SPECIALSPLITMETHODREFINDEXES(romClass) + index);1705}1706if (bc == JBinvokedynamic) {1707/* TODO invokedynamic should allow for a 3 byte index. Adjust 'index' to include the other byte */1708utf8string = ((J9UTF8 *) (J9ROMNAMEANDSIGNATURE_SIGNATURE(SRP_PTR_GET(callSiteData + index, J9ROMNameAndSignature*))));1709} else {1710info = &constantPool[index];1711utf8string = ((J9UTF8 *) (J9ROMNAMEANDSIGNATURE_SIGNATURE(J9ROMMETHODREF_NAMEANDSIGNATURE((J9ROMMethodRef *) info))));1712}1713stackTop -= getSendSlotsFromSignature(J9UTF8_DATA(utf8string));17141715if ((JBinvokestatic != bc)1716&& (JBinvokedynamic != bc)1717&& (JBinvokestaticsplit != bc)1718) {1719if ((JBinvokespecial == bc)1720|| (JBinvokespecialsplit == bc)1721) {17221723type = POP;1724if (J9UTF8_DATA(J9ROMNAMEANDSIGNATURE_NAME(J9ROMMETHODREF_NAMEANDSIGNATURE((J9ROMMethodRef *) info)))[0] == '<') {17251726/* This is <init>, verify that this is a NEW or INIT object */1727if (type & BCV_SPECIAL) {1728temp1 = getSpecialType(verifyData, type, code);1729/* This invoke special will make all copies of this "type" on the stack a real1730object, find all copies of this object and initialize them */1731ptr = temps; /* assumption that stack follows temps */1732/* we don't strictly need to walk temps here, the pending stack would be enough */1733while (ptr != stackTop) {1734if (*ptr == type) {1735*ptr = temp1;1736}1737ptr++;1738}1739type = temp1;1740break;1741}1742}1743} else { /* virtual or interface */1744DROP(1);1745}1746}17471748stackTop = pushReturnType(verifyData, utf8string, stackTop);1749break;17501751case RTV_PUSH_NEW:1752switch (bc) {1753case JBnew:1754case JBnewdup:1755/* put a uninitialized object of the correct type on the stack */1756PUSH(BCV_SPECIAL_NEW | (start << BCV_CLASS_INDEX_SHIFT));1757break;17581759case JBnewarray:1760index = PARAM_8(bcIndex, 1);1761type = (UDATA) newArrayParamConversion[index];1762DROP(1); /* pop the size of the array */1763PUSH(type); /* arity of one implicit */1764break;17651766case JBanewarray:1767index = PARAM_16(bcIndex, 1);1768DROP(1); /* pop the size of the array */1769info = &constantPool[index];1770utf8string = J9ROMSTRINGREF_UTF8DATA((J9ROMStringRef *) info);17711772stackTop = pushClassType(verifyData, utf8string, stackTop);1773/* arity is one greater than signature */1774type = POP;1775PUSH(( (UDATA)1 << BCV_ARITY_SHIFT) + type);1776break;17771778case JBmultianewarray:1779/* points to cp entry for class of object to create */1780index = PARAM_16(bcIndex, 1);1781i1 = PARAM_8(bcIndex, 3);1782DROP(i1);1783if (stackTop < stackBase) {1784errorType = J9NLS_BCV_ERR_STACK_UNDERFLOW__ID;1785verboseErrorCode = BCV_ERR_STACK_UNDERFLOW;1786/* Always set to the location of the 1st data type on 'stack' to show up if stackTop <= stackBase */1787errorStackIndex = (U_32)(stackBase - liveStack->stackElements);1788goto _verifyError;1789}17901791info = &constantPool[index];1792utf8string = J9ROMSTRINGREF_UTF8DATA((J9ROMStringRef *) info);17931794stackTop = pushClassType(verifyData, utf8string, stackTop);1795break;1796}1797break;17981799case RTV_MISC:1800switch (bc) {1801case JBathrow:1802goto _checkFinished;1803break;18041805case JBarraylength:1806case JBinstanceof:1807DROP(1);1808PUSH_INTEGER_CONSTANT;1809break;18101811case JBtableswitch:1812case JBlookupswitch:1813DROP(1);1814index = (UDATA) ((4 - (pc & 3)) & 3); /* consume padding */1815pc += index;1816bcIndex += index;1817pc += 8;1818CHECK_END;1819offset32 = (I_32) PARAM_32(bcIndex, 1);1820bcIndex += 4;1821target = offset32 + start;1822SAVE_STACKTOP(liveStack, stackTop);1823if (BCV_ERR_INSUFFICIENT_MEMORY == mergeStacks (verifyData, target)) {1824errorType = J9NLS_BCV_ERR_VERIFY_OUT_OF_MEMORY__ID;1825goto _outOfMemoryError;1826}18271828if (bc == JBtableswitch) {1829i1 = (I_32) PARAM_32(bcIndex, 1);1830bcIndex += 4;1831pc += 4;1832i2 = (I_32) PARAM_32(bcIndex, 1);1833bcIndex += 4;18341835pc += ((I_32)i2 - (I_32)i1 + 1) * 4;1836CHECK_END;18371838/* Add the table switch destinations in reverse order to more closely mimic the order that people1839(ie: the TCKs) expect you to load classes */1840bcIndex += (((I_32)i2 - (I_32)i1) * 4); /* point at the last table switch entry */18411842/* Count the entries */1843i2 = (I_32)i2 - (I_32)i1 + 1;1844for (i1 = 0; (I_32)i1 < (I_32)i2; i1++) {1845offset32 = (I_32) PARAM_32(bcIndex, 1);1846bcIndex -= 4; /* back up to point at the previous table switch entry */1847target = offset32 + start;1848if (BCV_ERR_INSUFFICIENT_MEMORY == mergeStacks (verifyData, target)) {1849errorType = J9NLS_BCV_ERR_VERIFY_OUT_OF_MEMORY__ID;1850goto _outOfMemoryError;1851}1852}1853} else {1854i2 = (I_32) PARAM_32(bcIndex, 1);1855bcIndex += 4;18561857pc += (I_32)i2 * 8;1858CHECK_END;1859for (i1 = 0; (I_32)i1 < (I_32)i2; i1++) {1860bcIndex += 4;1861offset32 = (I_32) PARAM_32(bcIndex, 1);1862bcIndex += 4;1863target = offset32 + start;1864if (BCV_ERR_INSUFFICIENT_MEMORY == mergeStacks (verifyData, target)) {1865errorType = J9NLS_BCV_ERR_VERIFY_OUT_OF_MEMORY__ID;1866goto _outOfMemoryError;1867}1868}1869}1870goto _checkFinished;1871break;18721873case JBmonitorenter:1874case JBmonitorexit:1875DROP(1);1876break;18771878case JBcheckcast:1879index = PARAM_16(bcIndex, 1);1880DROP(1);1881info = &constantPool[index];1882utf8string = J9ROMSTRINGREF_UTF8DATA((J9ROMStringRef *) info);1883stackTop = pushClassType(verifyData, utf8string, stackTop);1884break;1885}1886break;18871888case RTV_POP_2_PUSH_INT:1889DROP(popCount);1890PUSH_INTEGER_CONSTANT;1891break;18921893case RTV_BYTECODE_POP:1894case RTV_BYTECODE_POP2:1895DROP(popCount);1896break;18971898case RTV_BYTECODE_DUP:1899type = POP;1900PUSH(type);1901PUSH(type);1902break;19031904case RTV_BYTECODE_DUPX1:1905type = POP;1906temp1 = POP;1907PUSH(type);1908PUSH(temp1);1909PUSH(type);1910break;19111912case RTV_BYTECODE_DUPX2:1913type = POP;1914temp1 = POP;1915temp2 = POP;1916PUSH(type);1917PUSH(temp2);1918PUSH(temp1);1919PUSH(type);1920break;19211922case RTV_BYTECODE_DUP2:1923temp1 = POP;1924temp2 = POP;1925PUSH(temp2);1926PUSH(temp1);1927PUSH(temp2);1928PUSH(temp1);1929break;19301931case RTV_BYTECODE_DUP2X1:1932type = POP;1933temp1 = POP;1934temp2 = POP;1935PUSH(temp1);1936PUSH(type);1937PUSH(temp2);1938PUSH(temp1);1939PUSH(type);1940break;19411942case RTV_BYTECODE_DUP2X2:1943type = POP;1944temp1 = POP;1945temp2 = POP;1946temp3 = POP;1947PUSH(temp1);1948PUSH(type);1949PUSH(temp3);1950PUSH(temp2);1951PUSH(temp1);1952PUSH(type);1953break;19541955case RTV_BYTECODE_SWAP:1956type = POP;1957temp1 = POP;1958PUSH(type);1959PUSH(temp1);1960break;19611962case RTV_UNIMPLEMENTED:1963errorType = J9NLS_BCV_ERR_BC_UNKNOWN__ID;1964/* Jazz 104084: Set the error code in the case of unrecognized opcode. */1965verboseErrorCode = BCV_ERR_BAD_BYTECODE;1966goto _verifyError;1967break;1968}1969continue;19701971_checkFinished:19721973if (verifyData->unwalkedQueueHead != verifyData->unwalkedQueueTail) {1974pc = verifyData->unwalkedQueue[verifyData->unwalkedQueueHead++];1975verifyData->unwalkedQueueHead %= (verifyData->rootQueueSize / sizeof(UDATA));1976if ((bytecodeMap[pc] & BRANCH_ON_UNWALKED_QUEUE) == 0) {1977goto _checkFinished;1978}1979bytecodeMap[pc] &= ~BRANCH_ON_UNWALKED_QUEUE;1980bcIndex = code + pc;1981stackIndex = bytecodeMap[pc] >> BRANCH_INDEX_SHIFT;1982branch = BCV_INDEX_STACK (stackIndex);1983copyStack(branch, liveStack);1984RELOAD_LIVESTACK;1985justLoadedStack = TRUE;1986Trc_BCV_simulateStack_NewWalkFrom(verifyData->vmStruct,1987(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),1988J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),1989(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),1990J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),1991(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(romMethod)),1992J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)),1993start, start, pc, pc);1994} else if (verifyData->rewalkQueueHead != verifyData->rewalkQueueTail) {1995pc = verifyData->rewalkQueue[verifyData->rewalkQueueHead++];1996verifyData->rewalkQueueHead %= (verifyData->rootQueueSize / sizeof(UDATA));1997if ((bytecodeMap[pc] & BRANCH_ON_REWALK_QUEUE) == 0) {1998goto _checkFinished;1999}2000bytecodeMap[pc] &= ~BRANCH_ON_REWALK_QUEUE;2001bcIndex = code + pc;2002stackIndex = bytecodeMap[pc] >> BRANCH_INDEX_SHIFT;2003branch = BCV_INDEX_STACK (stackIndex);2004copyStack(branch, liveStack);2005RELOAD_LIVESTACK;2006justLoadedStack = TRUE;2007Trc_BCV_simulateStack_RewalkFrom(verifyData->vmStruct,2008(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),2009J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),2010(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),2011J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),2012(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(romMethod)),2013J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)),2014start, start, pc, pc);2015} else {2016Trc_BCV_simulateStack_Exit(verifyData->vmStruct);2017/* else we are done the rootSet -- return */2018return BCV_SUCCESS;2019}2020}2021#undef CHECK_END20222023errorType = J9NLS_BCV_ERR_UNEXPECTED_EOF__ID; /* should never reach here */20242025_verifyError:2026/* Jazz 104084: Store the verification error data here when error occurs */2027storeVerifyErrorData(verifyData, (I_16)verboseErrorCode, (U_32)errorStackIndex, errorTargetType, errorTempData, start);20282029BUILD_VERIFY_ERROR(errorModule, errorType);2030Trc_BCV_simulateStack_verifyError(verifyData->vmStruct,2031verifyData->errorPC,2032verifyData->errorCode);2033Trc_BCV_simulateStack_verifyErrorBytecode(verifyData->vmStruct,2034(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),2035J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),2036(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),2037J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),2038(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(romMethod)),2039J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)),2040verifyData->errorCode, verifyData->errorPC, verifyData->errorPC, bc);2041Trc_BCV_simulateStack_Exit(verifyData->vmStruct);20422043return BCV_ERR_INTERNAL_ERROR;20442045_outOfMemoryError:2046BUILD_VERIFY_ERROR(errorModule, errorType);2047Trc_BCV_simulateStack_verifyError(verifyData->vmStruct,2048verifyData->errorPC,2049verifyData->errorCode);20502051Trc_BCV_simulateStack_verifyErrorBytecode_OutOfMemoryException(verifyData->vmStruct,2052(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),2053J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),2054(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),2055J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),2056(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(romMethod)),2057J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)),2058verifyData->errorCode, verifyData->errorPC, verifyData->errorPC, bc);2059Trc_BCV_simulateStack_Exit(verifyData->vmStruct);20602061return BCV_ERR_INSUFFICIENT_MEMORY;20622063}20642065/*2066* return BCV_SUCCESS on success2067* returns BCV_ERR_INSUFFICIENT_MEMORY on OOM2068*/20692070IDATA2071allocateVerifyBuffers (J9PortLibrary * portLib, J9BytecodeVerificationData *verifyData)2072{2073Trc_BCV_allocateVerifyBuffers_Event1(verifyData->vmStruct);20742075verifyData->classNameList = 0;2076verifyData->classNameListEnd = 0;2077verifyData->classNameSegment = 0;2078verifyData->classNameSegmentFree = 0;2079verifyData->classNameSegmentEnd = 0;2080verifyData->bytecodeMap = 0;2081verifyData->stackMaps = 0;2082verifyData->liveStack = 0;2083verifyData->unwalkedQueue = 0;2084verifyData->rewalkQueue = 0;20852086verifyData->classNameList = (J9UTF8 **) bcvalloc (verifyData, (UDATA) CLASSNAMELIST_DEFAULT_SIZE);2087verifyData->classNameListEnd = (J9UTF8 **)((UDATA)verifyData->classNameList + CLASSNAMELIST_DEFAULT_SIZE);20882089verifyData->classNameSegment = bcvalloc (verifyData, (UDATA) CLASSNAMESEGMENT_DEFAULT_SIZE);2090verifyData->classNameSegmentEnd = verifyData->classNameSegment + CLASSNAMESEGMENT_DEFAULT_SIZE;2091verifyData->classNameSegmentFree = verifyData->classNameSegment;20922093verifyData->bytecodeMap = bcvalloc (verifyData, (UDATA) BYTECODE_MAP_DEFAULT_SIZE);2094verifyData->bytecodeMapSize = BYTECODE_MAP_DEFAULT_SIZE;20952096verifyData->stackMaps = bcvalloc (verifyData, (UDATA) STACK_MAPS_DEFAULT_SIZE);2097verifyData->stackMapsSize = STACK_MAPS_DEFAULT_SIZE;2098verifyData->stackMapsCount = 0;20992100verifyData->unwalkedQueue = bcvalloc (verifyData, (UDATA) ROOT_QUEUE_DEFAULT_SIZE);2101verifyData->unwalkedQueueHead = 0;2102verifyData->unwalkedQueueTail = 0;2103verifyData->rewalkQueue = bcvalloc (verifyData, (UDATA) ROOT_QUEUE_DEFAULT_SIZE);2104verifyData->rewalkQueueHead = 0;2105verifyData->rewalkQueueTail = 0;2106verifyData->rootQueueSize = ROOT_QUEUE_DEFAULT_SIZE;21072108verifyData->liveStack = bcvalloc (verifyData, (UDATA) LIVE_STACK_DEFAULT_SIZE);2109verifyData->liveStackSize = LIVE_STACK_DEFAULT_SIZE;2110verifyData->stackSize = 0;21112112RESET_VERIFY_ERROR(verifyData);21132114verifyData->portLib = portLib;21152116if (!(verifyData->classNameList && verifyData->classNameSegment && verifyData->bytecodeMap2117&& verifyData->stackMaps && verifyData->unwalkedQueue && verifyData->rewalkQueue && verifyData->liveStack)) {2118freeVerifyBuffers (portLib, verifyData);2119Trc_BCV_allocateVerifyBuffers_allocFailure(verifyData->vmStruct);2120return BCV_ERR_INSUFFICIENT_MEMORY;2121}2122/* Now we know the allocates were successful, initialize the required data */2123verifyData->classNameList[0] = NULL;2124return BCV_SUCCESS;2125}212621272128/*2129BCV interface to j9mem_allocate_memory.2130@return pointer to allocated memory, or 0 if allocation fails.2131@note Does not deallocate the internal buffer2132*/21332134void*2135bcvalloc (J9BytecodeVerificationData * verifyData, UDATA byteCount)2136{2137UDATA *returnVal = 0;2138J9BCVAlloc *temp1, *temp2;21392140PORT_ACCESS_FROM_PORT(verifyData->portLib);21412142/* Round to UDATA multiple */2143byteCount = (UDATA) ((byteCount + (sizeof(UDATA) - 1)) & ~(sizeof(UDATA) - 1));2144/* Allow room for the linking header */2145byteCount += sizeof(UDATA);21462147if (verifyData->internalBufferStart == 0) {2148verifyData->internalBufferStart = j9mem_allocate_memory(BCV_INTERNAL_DEFAULT_SIZE, J9MEM_CATEGORY_CLASSES);2149if (verifyData->internalBufferStart == 0) {2150return 0;2151}2152verifyData->internalBufferEnd = (UDATA *) ((UDATA)verifyData->internalBufferStart + BCV_INTERNAL_DEFAULT_SIZE);2153verifyData->currentAlloc = verifyData->internalBufferStart;2154*verifyData->currentAlloc = (UDATA) verifyData->currentAlloc;2155}21562157temp1 = (J9BCVAlloc *) verifyData->currentAlloc;2158temp2 = (J9BCVAlloc *) ((UDATA) temp1 + byteCount);21592160if ((UDATA *) temp2 >= verifyData->internalBufferEnd) {2161returnVal = j9mem_allocate_memory(byteCount, J9MEM_CATEGORY_CLASSES);2162Trc_BCV_bcvalloc_ExternalAlloc(verifyData->vmStruct,2163(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),2164J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),2165byteCount, returnVal);2166if (returnVal == 0) {2167return 0;2168}2169} else {2170/* tag the back pointer as the block following this pointer is in use */2171temp1->prev = (J9BCVAlloc *) ((UDATA) temp1->prev | 1);2172temp2->prev = temp1;2173verifyData->currentAlloc = (UDATA *) temp2;2174returnVal = temp1->data;2175}2176return returnVal;2177}2178217921802181/*2182BCV interface to j9mem_allocate_memory.2183*/21842185void2186bcvfree (J9BytecodeVerificationData * verifyData, void* address)2187{2188J9BCVAlloc *temp1, *temp2;21892190PORT_ACCESS_FROM_PORT(verifyData->portLib);21912192if (((UDATA *) address >= verifyData->internalBufferEnd) || ((UDATA *) address < verifyData->internalBufferStart)) {2193Trc_BCV_bcvalloc_ExternalFreeAddress(verifyData->vmStruct, address);2194j9mem_free_memory(address);2195return;2196}21972198temp1 = (J9BCVAlloc *) ((UDATA *) address - 1);2199/* flag block following the pointer as free */2200temp1->prev = (J9BCVAlloc *) ((UDATA) temp1->prev & ~1);2201temp2 = (J9BCVAlloc *) verifyData->currentAlloc;22022203while (temp1 == temp2->prev) {2204/* Release most recent alloc and any preceding contiguous already freed allocs */2205temp2 = temp2->prev;2206temp1 = temp2->prev;2207if ((UDATA) temp1->prev & 1) {2208/* stop if an in-use block is found */2209verifyData->currentAlloc = (UDATA *) temp2;2210break;2211}2212if (temp1 == temp2) {2213/* all blocks unused - release the buffer */2214j9mem_free_memory(verifyData->internalBufferStart);2215verifyData->internalBufferStart = 0; /* Set the internal buffer start to zero so it will be re-allocated next time */2216verifyData->internalBufferEnd = 0;2217break;2218}2219}2220}222122222223void2224freeVerifyBuffers (J9PortLibrary * portLib, J9BytecodeVerificationData *verifyData)2225{2226Trc_BCV_freeVerifyBuffers_Event1(verifyData->vmStruct);22272228if (verifyData->classNameList ) {2229bcvfree (verifyData, verifyData->classNameList);2230}22312232if (verifyData->classNameSegment ) {2233bcvfree (verifyData, verifyData->classNameSegment);2234}22352236if (verifyData->bytecodeMap ) {2237bcvfree (verifyData, verifyData->bytecodeMap);2238}22392240if (verifyData->stackMaps ) {2241bcvfree (verifyData, verifyData->stackMaps);2242}22432244if (verifyData->unwalkedQueue ) {2245bcvfree (verifyData, verifyData->unwalkedQueue);2246}22472248if (verifyData->rewalkQueue ) {2249bcvfree (verifyData, verifyData->rewalkQueue);2250}22512252if (verifyData->liveStack ) {2253bcvfree (verifyData, verifyData->liveStack);2254}22552256verifyData->classNameList = 0;2257verifyData->classNameListEnd = 0;2258verifyData->classNameSegment = 0;2259verifyData->classNameSegmentFree = 0;2260verifyData->classNameSegmentEnd = 0;2261verifyData->bytecodeMap = 0;2262verifyData->stackMaps = 0;2263verifyData->liveStack = 0;2264verifyData->unwalkedQueue = 0;2265verifyData->rewalkQueue = 0;2266}2267226822692270void2271j9bcv_freeVerificationData (J9PortLibrary * portLib, J9BytecodeVerificationData * verifyData)2272{2273PORT_ACCESS_FROM_PORT(portLib);2274if (verifyData) {2275#ifdef J9VM_THR_PREEMPTIVE2276JavaVM* jniVM = (JavaVM*)verifyData->javaVM;2277J9ThreadEnv* threadEnv;2278(*jniVM)->GetEnv(jniVM, (void**)&threadEnv, J9THREAD_VERSION_1_1);22792280threadEnv->monitor_destroy( verifyData->verifierMutex );2281#endif2282freeVerifyBuffers( PORTLIB, verifyData );2283j9mem_free_memory( verifyData->excludeAttribute );2284j9mem_free_memory( verifyData );2285}2286}22872288/*2289* returns J9BytecodeVerificationData* on success2290* returns NULL on OOM2291*/2292J9BytecodeVerificationData *2293j9bcv_initializeVerificationData(J9JavaVM* javaVM)2294{2295J9BytecodeVerificationData * verifyData;2296PORT_ACCESS_FROM_JAVAVM(javaVM);2297JavaVM* jniVM = (JavaVM*)javaVM;2298J9ThreadEnv* threadEnv;22992300(*jniVM)->GetEnv(jniVM, (void**)&threadEnv, J9THREAD_VERSION_1_1);23012302verifyData = j9mem_allocate_memory((UDATA) sizeof(*verifyData), J9MEM_CATEGORY_CLASSES);2303if( !verifyData ) {2304goto error_no_memory;2305}23062307/* blank the vmStruct field */2308verifyData->vmStruct = NULL;2309verifyData->javaVM = javaVM;23102311#ifdef J9VM_THR_PREEMPTIVE2312threadEnv->monitor_init_with_name(&verifyData->verifierMutex, 0, "BCVD verifier");2313if (!verifyData->verifierMutex) {2314goto error_no_memory;2315}2316#endif23172318verifyData->verifyBytecodesFunction = j9bcv_verifyBytecodes;2319verifyData->checkClassLoadingConstraintForNameFunction = j9bcv_checkClassLoadingConstraintForName;2320verifyData->internalBufferStart = 0;2321verifyData->internalBufferEnd = 0;2322verifyData->portLib = PORTLIB;2323verifyData->ignoreStackMaps = 0;2324verifyData->excludeAttribute = NULL;2325verifyData->redefinedClassesCount = 0;23262327if (BCV_ERR_INSUFFICIENT_MEMORY == allocateVerifyBuffers (PORTLIB, verifyData)) {2328goto error_no_memory;2329}23302331/* default verification options */2332verifyData->verificationFlags = J9_VERIFY_SKIP_BOOTSTRAP_CLASSES | J9_VERIFY_OPTIMIZE;23332334return verifyData;23352336error_no_memory:2337if (verifyData) {2338#ifdef J9VM_THR_PREEMPTIVE2339threadEnv->monitor_destroy (verifyData->verifierMutex);2340#endif2341j9mem_free_memory(verifyData);2342}2343return NULL;2344}2345234623472348#define ALLOC_BUFFER(name, needed) \2349if (needed > name##Size) { \2350bcvfree(verifyData, name); \2351name = bcvalloc(verifyData, needed); \2352if (NULL == name) { \2353name##Size = 0; \2354result = BCV_ERR_INSUFFICIENT_MEMORY; \2355break; \2356} \2357name##Size = needed; \2358}23592360/*2361* Sequence the 2 verification passes - flow based type inference stack map generation2362* and linear stack map verification2363*2364* returns BCV_SUCCESS on success2365* returns BCV_ERR_INSUFFICIENT_MEMORY on OOM2366*/23672368IDATA2369j9bcv_verifyBytecodes (J9PortLibrary * portLib, J9Class * clazz, J9ROMClass * romClass,2370J9BytecodeVerificationData * verifyData)2371{2372UDATA i, j;2373J9ROMMethod *romMethod;2374UDATA argCount;2375UDATA length;2376UDATA mapLength;2377BOOLEAN hasStackMaps = (J9ROMCLASS_HAS_VERIFY_DATA(romClass) != 0);2378UDATA oldState;2379IDATA result = 0;2380UDATA rootQueueSize;2381U_32 *bytecodeMap;2382UDATA start = 0;2383J9BranchTargetStack *liveStack;2384U_8 *stackMapData;2385UDATA stackMapsSize;2386UDATA *stackTop;2387BOOLEAN classVersionRequiresStackmaps = romClass->majorVersion >= CFR_MAJOR_VERSION_REQUIRING_STACKMAPS;2388BOOLEAN newFormat = (classVersionRequiresStackmaps || hasStackMaps);2389BOOLEAN verboseVerification = (J9_VERIFY_VERBOSE_VERIFICATION == (verifyData->verificationFlags & J9_VERIFY_VERBOSE_VERIFICATION));23902391PORT_ACCESS_FROM_PORT(portLib);23922393Trc_BCV_j9bcv_verifyBytecodes_Entry(verifyData->vmStruct,2394(UDATA) J9UTF8_LENGTH((J9ROMCLASS_CLASSNAME(romClass))),2395J9UTF8_DATA(J9ROMCLASS_CLASSNAME(romClass)));23962397/* save current and set vmState */2398oldState = verifyData->vmStruct->omrVMThread->vmState;2399verifyData->vmStruct->omrVMThread->vmState = J9VMSTATE_BCVERIFY;24002401verifyData->romClass = romClass;2402verifyData->errorPC = 0;24032404verifyData->romClassInSharedClasses = j9shr_Query_IsAddressInCache(verifyData->javaVM, romClass, romClass->romSize);24052406/* List is used for the whole class */2407initializeClassNameList(verifyData);240824092410romMethod = (J9ROMMethod *) J9ROMCLASS_ROMMETHODS(romClass);24112412if (verboseVerification) {2413ALWAYS_TRIGGER_J9HOOK_VM_CLASS_VERIFICATION_START(verifyData->javaVM->hookInterface, verifyData, newFormat);2414}24152416/* For each method in the class */2417for (i = 0; i < (UDATA) romClass->romMethodCount; i++) {24182419UDATA createStackMaps;24202421verifyData->ignoreStackMaps = (verifyData->verificationFlags & J9_VERIFY_IGNORE_STACK_MAPS) != 0;2422verifyData->createdStackMap = FALSE;2423verifyData->romMethod = romMethod;24242425Trc_BCV_j9bcv_verifyBytecodes_VerifyMethod(verifyData->vmStruct,2426(UDATA) J9UTF8_LENGTH((J9ROMCLASS_CLASSNAME(romClass))),2427J9UTF8_DATA(J9ROMCLASS_CLASSNAME(romClass)),2428(UDATA) J9UTF8_LENGTH((J9ROMMETHOD_NAME(romMethod))),2429J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),2430(UDATA) J9UTF8_LENGTH((J9ROMMETHOD_SIGNATURE(romMethod))),2431J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)),2432romMethod->modifiers);24332434/* If native or abstract method, do nothing */2435if (!((romMethod->modifiers & J9AccNative) || (romMethod->modifiers & J9AccAbstract))) {2436BOOLEAN isInitMethod = FALSE;24372438/* BCV_TARGET_STACK_HEADER_UDATA_SIZE for pc/stackBase/stackEnd in J9BranchTargetStack and2439* BCV_STACK_OVERFLOW_BUFFER_UDATA_SIZE for late overflow detection of longs/doubles2440*/2441verifyData->stackSize = (J9_MAX_STACK_FROM_ROM_METHOD(romMethod)2442+ J9_ARG_COUNT_FROM_ROM_METHOD(romMethod)2443+ J9_TEMP_COUNT_FROM_ROM_METHOD(romMethod)2444+ BCV_TARGET_STACK_HEADER_UDATA_SIZE2445+ BCV_STACK_OVERFLOW_BUFFER_UDATA_SIZE) * sizeof(UDATA);24462447ALLOC_BUFFER(verifyData->liveStack, verifyData->stackSize);24482449length = (UDATA) (J9_BYTECODE_SIZE_FROM_ROM_METHOD(romMethod));2450mapLength = length * sizeof(U_32);24512452ALLOC_BUFFER(verifyData->bytecodeMap, mapLength);2453bytecodeMap = verifyData->bytecodeMap;24542455_fallBack:2456memset(bytecodeMap, 0, mapLength);24572458createStackMaps = !classVersionRequiresStackmaps && (verifyData->ignoreStackMaps || !hasStackMaps);24592460if (createStackMaps) {2461verifyData->stackMapsCount = buildBranchMap(verifyData);24622463if (verifyData->stackMapsCount == (UDATA)BCV_ERR_INTERNAL_ERROR) {2464BUILD_VERIFY_ERROR(J9NLS_BCV_ERR_BYTECODES_INVALID__MODULE, J9NLS_BCV_ERR_BYTECODES_INVALID__ID);2465result = BCV_ERR_INTERNAL_ERROR;2466break;2467}2468} else {24692470U_32 *stackMapMethod = getStackMapInfoForROMMethod(romMethod);24712472verifyData->stackMapsCount = 0;2473stackMapData = 0;24742475/*Access the stored stack map data for this method, get pointer and map count */2476if (stackMapMethod) {2477stackMapData = (U_8 *)(stackMapMethod + 1);2478NEXT_U16(verifyData->stackMapsCount, stackMapData);2479}2480}24812482stackMapsSize = (verifyData->stackSize) * (verifyData->stackMapsCount);24832484ALLOC_BUFFER(verifyData->stackMaps, stackMapsSize);24852486if (createStackMaps && verifyData->stackMapsCount) {2487UDATA mapIndex = 0;2488/* Non-empty internal stackMap created */2489verifyData->createdStackMap = TRUE;24902491liveStack = BCV_FIRST_STACK ();2492/* Initialize stackMaps */2493for (j = 0; j < length; j++) {2494if ((bytecodeMap)[j] & BRANCH_TARGET) {2495liveStack->pc = j; /* offset of the branch target */2496liveStack->stackBaseIndex = -1;2497liveStack->stackTopIndex = -1;2498liveStack = BCV_NEXT_STACK (liveStack);2499(bytecodeMap)[j] |= (mapIndex << BRANCH_INDEX_SHIFT);2500mapIndex++;2501}2502}25032504rootQueueSize = (verifyData->stackMapsCount + 1) * sizeof(UDATA);25052506if (rootQueueSize > verifyData->rootQueueSize) {2507bcvfree(verifyData, verifyData->unwalkedQueue);2508verifyData->unwalkedQueue = bcvalloc(verifyData, rootQueueSize);2509bcvfree(verifyData, verifyData->rewalkQueue);2510verifyData->rewalkQueue = bcvalloc(verifyData, rootQueueSize);2511verifyData->rootQueueSize = rootQueueSize;2512if (!(verifyData->unwalkedQueue && verifyData->rewalkQueue)) {2513result = BCV_ERR_INSUFFICIENT_MEMORY;2514break;2515}2516}2517}25182519liveStack = (J9BranchTargetStack *) verifyData->liveStack;2520stackTop = &(liveStack->stackElements[0]);25212522isInitMethod = buildStackFromMethodSignature(verifyData, &stackTop, &argCount);25232524SAVE_STACKTOP(liveStack, stackTop);2525liveStack->stackBaseIndex = liveStack->stackTopIndex;25262527result = 0;2528if (verifyData->stackMapsCount) {2529if (createStackMaps) {2530result = simulateStack (verifyData);2531} else {2532result = decompressStackMaps (verifyData, argCount, stackMapData);2533}2534}25352536if (BCV_ERR_INSUFFICIENT_MEMORY == result) {2537goto _done;2538}25392540/* If stack maps created */2541/* Only perform second verification pass with a valid J9Class */2542if ((result == BCV_SUCCESS) && clazz) {2543if (isInitMethod) {2544/* CMVC 199785: Jazz103 45899: Only run this when the stack has been built correctly */2545setInitializedThisStatus(verifyData);2546}25472548if (newFormat && verboseVerification) {2549ALWAYS_TRIGGER_J9HOOK_VM_METHOD_VERIFICATION_START(verifyData->javaVM->hookInterface, verifyData);2550}25512552result = j9rtv_verifyBytecodes (verifyData);25532554if (BCV_ERR_INSUFFICIENT_MEMORY == result) {2555goto _done;2556}25572558if (newFormat && verboseVerification) {2559BOOLEAN willFailOver = FALSE;2560/*2561* If verification failed and will fail over to older verifier, we only output stack map frame details2562* if the frame count is bigger than 0.2563*/2564if ((BCV_SUCCESS != result)2565&& !classVersionRequiresStackmaps2566&& !createStackMaps2567&& (J9_VERIFY_NO_FALLBACK != (verifyData->verificationFlags & J9_VERIFY_NO_FALLBACK))) {2568willFailOver = TRUE;2569}25702571if (!willFailOver || (verifyData->stackMapsCount > 0)) {2572ALWAYS_TRIGGER_J9HOOK_VM_STACKMAPFRAME_VERIFICATION(verifyData->javaVM->hookInterface, verifyData);2573}2574}2575}2576/* If verify error */2577if (result) {2578/* Check verification fallback criteria */2579if (classVersionRequiresStackmaps || createStackMaps || (verifyData->verificationFlags & J9_VERIFY_NO_FALLBACK)) {2580/* no retry */2581result = BCV_ERR_INTERNAL_ERROR;2582break;2583} else {2584/* reset verification failure */2585RESET_VERIFY_ERROR(verifyData);2586verifyData->errorPC = (UDATA) 0;2587verifyData->errorModule = 0;2588verifyData->errorCode = 0;25892590Trc_BCV_j9bcv_verifyBytecodes_ReverifyMethod(verifyData->vmStruct,2591(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(romClass)),2592J9UTF8_DATA(J9ROMCLASS_CLASSNAME(romClass)),2593(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),2594J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),2595(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(romMethod)),2596J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)));25972598/* retry with ignoreStackMaps enabled */2599verifyData->ignoreStackMaps = TRUE;26002601if (verboseVerification) {2602newFormat = FALSE;2603ALWAYS_TRIGGER_J9HOOK_VM_CLASS_VERIFICATION_FALLBACK(verifyData->javaVM->hookInterface, verifyData, newFormat);2604}26052606goto _fallBack;2607}2608}2609}26102611romMethod = J9_NEXT_ROM_METHOD(romMethod);2612}26132614_done:2615verifyData->vmStruct->omrVMThread->vmState = oldState;2616if (result == BCV_ERR_INSUFFICIENT_MEMORY) {2617Trc_BCV_j9bcv_verifyBytecodes_OutOfMemory(verifyData->vmStruct,2618(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(verifyData->romClass)),2619J9UTF8_DATA(J9ROMCLASS_CLASSNAME(verifyData->romClass)),2620(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),2621J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)),2622(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(romMethod)),2623J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod)));2624}26252626if (verboseVerification) {2627ALWAYS_TRIGGER_J9HOOK_VM_CLASS_VERIFICATION_END(verifyData->javaVM->hookInterface, verifyData, newFormat);2628}26292630Trc_BCV_j9bcv_verifyBytecodes_Exit(verifyData->vmStruct, result);26312632return result;2633}2634#undef ALLOC_BUFFER263526362637/*2638* returns J9VMDLLMAIN_OK on success2639* returns J9VMDLLMAIN_FAILED on error2640*/2641IDATA2642j9bcv_J9VMDllMain (J9JavaVM* vm, IDATA stage, void* reserved)2643{2644J9BytecodeVerificationData* verifyData = NULL;2645char optionValuesBuffer[128]; /* Needs to be big enough to hold -Xverify option values */2646char* optionValuesBufferPtr = optionValuesBuffer;2647J9VMDllLoadInfo* loadInfo = NULL;2648IDATA xVerifyIndex = -1;2649IDATA xVerifyColonIndex = -1;2650IDATA verboseVerificationIndex = -1;2651IDATA noVerboseVerificationIndex = -1;2652IDATA verifyErrorDetailsIndex = -1;2653IDATA noVerifyErrorDetailsIndex = -1;2654IDATA classRelationshipVerifierIndex = -1;2655IDATA noClassRelationshipVerifierIndex = -1;2656IDATA returnVal = J9VMDLLMAIN_OK;2657#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)2658J9HookInterface ** vmHooks = vm->internalVMFunctions->getVMHookInterface(vm);2659#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */26602661PORT_ACCESS_FROM_JAVAVM(vm);26622663switch(stage) {26642665case ALL_VM_ARGS_CONSUMED :2666FIND_AND_CONSUME_ARG( OPTIONAL_LIST_MATCH, OPT_XVERIFY, NULL);2667break;26682669case BYTECODE_TABLE_SET :2670loadInfo = FIND_DLL_TABLE_ENTRY( THIS_DLL_NAME );2671verifyData = j9bcv_initializeVerificationData(vm);2672if( !verifyData ) {2673loadInfo->fatalErrorStr = "j9bcv_initializeVerificationData failed";2674returnVal = J9VMDLLMAIN_FAILED;2675break;2676}26772678vm->bytecodeVerificationData = verifyData;2679vm->runtimeFlags |= J9_RUNTIME_VERIFY;26802681#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)2682if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_CLASSES_UNLOAD, bcvHookClassesUnload, OMR_GET_CALLSITE(), vm)) {2683returnVal = J9VMDLLMAIN_FAILED;2684break;2685}2686#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */26872688/* Parse the -Xverify and -Xverify:<opt> commandline options.2689* Rules:2690* 1. -Xverify skips any previous -Xverify:<opt> arguments. -Xverify is the default state.2691* 2. Any -Xverify:<opt> prior to -Xverify is ignored.2692* 3. All -Xverify:<opt> after the -Xverify are processed in left-to-right order.2693* 4. -Xverify:<opt>,<opt> etc is also valid.2694* 5. -Xverify: is an error.2695* 6. -Xverify:<opt> processing occurs in the parseOptions function.2696*2697* This parsing is a duplicate of the parsing in the function VMInitStages of jvminit.c2698*/2699xVerifyIndex = FIND_ARG_IN_VMARGS( EXACT_MATCH, OPT_XVERIFY, NULL);2700xVerifyColonIndex = FIND_ARG_IN_VMARGS_FORWARD( STARTSWITH_MATCH, OPT_XVERIFY_COLON, NULL);2701while (xVerifyColonIndex >= 0) {2702/* Ignore -Xverify:<opt>'s prior to the last -Xverify */2703if (xVerifyColonIndex > xVerifyIndex) {2704/* Deal with possible -Xverify:<opt>,<opt> case */2705GET_OPTION_VALUES( xVerifyColonIndex, ':', ',', &optionValuesBufferPtr, 128 );27062707if(*optionValuesBuffer) {2708if (!parseOptions(vm, optionValuesBuffer, &loadInfo->fatalErrorStr)) {2709returnVal = J9VMDLLMAIN_FAILED;2710}2711} else {2712loadInfo->fatalErrorStr = "No options specified for -Xverify:<opt>";2713returnVal = J9VMDLLMAIN_FAILED;2714}2715}2716/* Advance to next argument */2717xVerifyColonIndex = FIND_NEXT_ARG_IN_VMARGS_FORWARD(STARTSWITH_MATCH, OPT_XVERIFY_COLON, NULL, xVerifyColonIndex);2718}27192720verboseVerificationIndex = FIND_AND_CONSUME_ARG(EXACT_MATCH, VMOPT_XXVERBOSEVERIFICATION, NULL);2721noVerboseVerificationIndex = FIND_AND_CONSUME_ARG(EXACT_MATCH, VMOPT_XXNOVERBOSEVERIFICATION, NULL);2722if (verboseVerificationIndex > noVerboseVerificationIndex) {2723vm->bytecodeVerificationData->verificationFlags |= J9_VERIFY_VERBOSE_VERIFICATION;2724}27252726verifyErrorDetailsIndex = FIND_AND_CONSUME_ARG(EXACT_MATCH, VMOPT_XXVERIFYERRORDETAILS, NULL);2727noVerifyErrorDetailsIndex = FIND_AND_CONSUME_ARG(EXACT_MATCH, VMOPT_XXNOVERIFYERRORDETAILS, NULL);2728if (verifyErrorDetailsIndex >= noVerifyErrorDetailsIndex) {2729vm->bytecodeVerificationData->verificationFlags |= J9_VERIFY_ERROR_DETAILS;2730}27312732/* Set runtime flag for -XX:+ClassRelationshipVerifier */2733classRelationshipVerifierIndex = FIND_AND_CONSUME_ARG(EXACT_MATCH, VMOPT_XXCLASSRELATIONSHIPVERIFIER, NULL);2734noClassRelationshipVerifierIndex = FIND_AND_CONSUME_ARG(EXACT_MATCH, VMOPT_XXNOCLASSRELATIONSHIPVERIFIER, NULL);2735if (classRelationshipVerifierIndex > noClassRelationshipVerifierIndex) {2736if (J9_ARE_ANY_BITS_SET(vm->runtimeFlags, J9_RUNTIME_XFUTURE)) {2737loadInfo->fatalErrorStr = "-XX:+ClassRelationshipVerifier cannot be used if -Xfuture or if -Xverify:all is enabled";2738returnVal = J9VMDLLMAIN_FAILED;2739} else {2740vm->extendedRuntimeFlags2 |= J9_EXTENDED_RUNTIME2_ENABLE_CLASS_RELATIONSHIP_VERIFIER;2741}2742}27432744break;27452746case LIBRARIES_ONUNLOAD :2747if (vm->bytecodeVerificationData) {2748j9bcv_freeVerificationData(PORTLIB, vm->bytecodeVerificationData);2749#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)2750(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_CLASSES_UNLOAD, bcvHookClassesUnload, vm);2751#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */2752}2753break;2754}2755return returnVal;2756}275727582759static IDATA2760setVerifyState(J9JavaVM *vm, char *option, char **errorString)2761{2762PORT_ACCESS_FROM_JAVAVM(vm);27632764if (0 == strcmp(option, OPT_ALL)) {2765/* JDK7 - CMVC 151154: Sun launcher converts -Xfuture to -Xverify:all */2766vm->runtimeFlags |= J9_RUNTIME_XFUTURE;2767vm->bytecodeVerificationData->verificationFlags &= ~J9_VERIFY_SKIP_BOOTSTRAP_CLASSES;2768} else if (0 == strcmp(option, OPT_OPT)) {2769/* on by default - will override a "noopt" before it */2770vm->bytecodeVerificationData->verificationFlags |= J9_VERIFY_OPTIMIZE;2771} else if (0 == strcmp(option, OPT_NO_OPT)) {2772vm->bytecodeVerificationData->verificationFlags &= ~J9_VERIFY_OPTIMIZE;2773} else if (0 == strcmp(option, OPT_NO_FALLBACK)) {2774vm->bytecodeVerificationData->verificationFlags |= J9_VERIFY_NO_FALLBACK;2775} else if (0 == strcmp(option, OPT_IGNORE_STACK_MAPS)) {2776vm->bytecodeVerificationData->verificationFlags |= J9_VERIFY_IGNORE_STACK_MAPS;2777} else if (0 == strncmp(option, OPT_EXCLUDEATTRIBUTE_EQUAL, sizeof(OPT_EXCLUDEATTRIBUTE_EQUAL) - 1)) {2778if (0 != option[sizeof(OPT_EXCLUDEATTRIBUTE_EQUAL)]) {2779UDATA length;2780vm->bytecodeVerificationData->verificationFlags |= J9_VERIFY_EXCLUDE_ATTRIBUTE;2781/* Save the parameter string, NULL terminated and the length excluding the NULL */2782length = strlen(option) - sizeof(OPT_EXCLUDEATTRIBUTE_EQUAL) + 1;2783vm->bytecodeVerificationData->excludeAttribute = j9mem_allocate_memory(length + 1, J9MEM_CATEGORY_CLASSES);2784if (NULL == vm->bytecodeVerificationData->excludeAttribute) {2785if (errorString) {2786*errorString = "Out of memory processing -Xverify:<opt>";2787}2788return FALSE;2789}2790memcpy(vm->bytecodeVerificationData->excludeAttribute, &(option[sizeof(OPT_EXCLUDEATTRIBUTE_EQUAL) - 1]), length + 1);2791}2792} else if (0 == strcmp(option, OPT_BOOTCLASSPATH_STATIC)) {2793vm->bytecodeVerificationData->verificationFlags |= J9_VERIFY_BOOTCLASSPATH_STATIC;2794} else if (0 == strcmp(option, OPT_DO_PROTECTED_ACCESS_CHECK)) {2795vm->bytecodeVerificationData->verificationFlags |= J9_VERIFY_DO_PROTECTED_ACCESS_CHECK;2796} else {2797if (errorString) {2798*errorString = "Unrecognised option(s) for -Xverify:<opt>";2799}2800return FALSE;2801}2802return TRUE;2803}2804280528062807static IDATA2808parseOptions(J9JavaVM *vm, char *optionValues, char **errorString)2809{2810char *optionValue = optionValues; /* Values are separated by single NULL characters. */28112812/* call setVerifyState on each individual option */2813while (*optionValue) {2814if( !setVerifyState( vm, optionValue, errorString ) ) {2815return FALSE;2816}2817optionValue = optionValue + strlen(optionValue) + 1; /* Step past null separator to next element */2818}2819return TRUE;2820}282128222823#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)2824/**2825* Unlink any constraints related to dying classloaders2826*/2827static void2828bcvHookClassesUnload(J9HookInterface** hook, UDATA eventNum, void* eventData, void* userData)2829{2830J9JavaVM *javaVM = userData;28312832if (0 != (javaVM->runtimeFlags & J9_RUNTIME_VERIFY)) {2833unlinkClassLoadingConstraints(javaVM);2834}2835}2836#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */28372838283928402841