From 171d56aab67b1691f391a3beb65888ebb5232b62 Mon Sep 17 00:00:00 2001 From: Graham Chapman Date: Thu, 15 Feb 2018 10:12:54 -0500 Subject: [PATCH 1/2] Add methods inherited from superinterfaces to iTables Modify iTables to contain every method in both the local interface and any extended interfaces so that the resolved interface class in the RAM constant pool for interface methods represents the interface that the receiver class must implement, rather than the class that declared the resolved interface method. Signed-off-by: Graham Chapman --- .../java/lang/invoke/InterfaceHandle.java | 11 +- runtime/jcl/common/java_dyn_methodhandle.c | 4 +- runtime/oti/j9nonbuilder.h | 1 - runtime/oti/util_api.h | 14 +- runtime/oti/vm_api.h | 8 - runtime/util/hshelp.c | 88 ++++++----- runtime/util/mthutil.c | 41 ++++++ runtime/vm/MHInterpreter.cpp | 6 +- runtime/vm/createramclass.cpp | 137 ++++++++---------- runtime/vm/intfunc.c | 3 +- runtime/vm/jnicsup.cpp | 8 +- runtime/vm/resolvesupport.cpp | 16 +- 12 files changed, 202 insertions(+), 135 deletions(-) diff --git a/jcl/src/java.base/share/classes/java/lang/invoke/InterfaceHandle.java b/jcl/src/java.base/share/classes/java/lang/invoke/InterfaceHandle.java index fca3c30111a..d78fe1b2dfe 100644 --- a/jcl/src/java.base/share/classes/java/lang/invoke/InterfaceHandle.java +++ b/jcl/src/java.base/share/classes/java/lang/invoke/InterfaceHandle.java @@ -1,6 +1,6 @@ /*[INCLUDE-IF Sidecar17]*/ /******************************************************************************* - * Copyright (c) 2009, 2009 IBM Corp. and others + * Copyright (c) 2009, 2018 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -68,12 +68,13 @@ public InterfaceHandle(InterfaceHandle originalHandle, MethodType newType) { /// {{{ JIT support protected final long vtableOffset(Object receiver) { /*[IF]*/ - /* Must be 'defc' rather than 'type().parameterType(0)' so that the - * itable index matches the defining interface, otherwise handles - * on interfaces methods defined in parent interfaces will crash + /* Must be 'referenceClass' rather than 'type().parameterType(0)' or + * 'defc' so that the itable index matches the defining interface at + * handle creation time, otherwise handles on interfaces methods defined + * in parent interfaces will crash */ /*[ENDIF]*/ - Class interfaceClass = defc; + Class interfaceClass = referenceClass; if (interfaceClass.isInstance(receiver)) { long interfaceJ9Class = getJ9ClassFromClass(interfaceClass); long receiverJ9Class = getJ9ClassFromClass(receiver.getClass()); diff --git a/runtime/jcl/common/java_dyn_methodhandle.c b/runtime/jcl/common/java_dyn_methodhandle.c index 14ad48ff51c..00360ee6331 100644 --- a/runtime/jcl/common/java_dyn_methodhandle.c +++ b/runtime/jcl/common/java_dyn_methodhandle.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2001, 2017 IBM Corp. and others + * Copyright (c) 2001, 2018 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -95,7 +95,7 @@ lookupInterfaceMethod(J9VMThread *currentThread, J9Class *lookupClass, J9UTF8 *n vmFuncs->setCurrentExceptionNLS(currentThread, J9VMCONSTANTPOOL_JAVALANGINCOMPATIBLECLASSCHANGEERROR, J9NLS_JCL_PRIVATE_INTERFACE_REQUIRES_INVOKESPECIAL); method = NULL; } else { - *methodIndex = vmFuncs->getITableIndexForMethod(method); + *methodIndex = getITableIndexForMethod(method, lookupClass); if (*methodIndex == -1) { method = NULL; } diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index b7574d1a56c..0715a96b537 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -4481,7 +4481,6 @@ typedef struct J9InternalVMFunctions { UDATA ( *resolveVirtualMethodRef)(struct J9VMThread *vmStruct, J9ConstantPool *constantPool, UDATA cpIndex, UDATA resolveFlags, struct J9Method **resolvedMethod) ; struct J9Method* ( *resolveInterfaceMethodRef)(struct J9VMThread *vmStruct, J9ConstantPool *constantPool, UDATA cpIndex, UDATA resolveFlags) ; UDATA ( *getVTableIndexForMethod)(struct J9Method * method, struct J9Class *clazz, struct J9VMThread *vmThread) ; - UDATA ( *getITableIndexForMethod)(struct J9Method * method) ; IDATA ( *checkVisibility)(struct J9VMThread* currentThread, struct J9Class* sourceClass, struct J9Class* destClass, UDATA modifiers, UDATA lookupOptions) ; void (JNICALL *sendClinit)(struct J9VMThread *vmContext, struct J9Class *clazz, UDATA reserved1, UDATA reserved2, UDATA reserved3) ; void ( *freeStackWalkCaches)(struct J9VMThread * currentThread, J9StackWalkState * walkState) ; diff --git a/runtime/oti/util_api.h b/runtime/oti/util_api.h index ee263a14c55..90bf7990c82 100644 --- a/runtime/oti/util_api.h +++ b/runtime/oti/util_api.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 1991, 2017 IBM Corp. and others + * Copyright (c) 1991, 2018 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -1872,6 +1872,18 @@ getReturnTypeFromSignature(U_8 * inData, UDATA inLength, U_8 **outData); /* ---------------- mthutil.c ---------------- */ +/** + * @brief Retrieve the index of an interface method within the iTable for an interface + * (not necessarily the same interface, as iTables contain methods from all + * extended interfaces as well as the local one). + * @param method The interface method + * @param targetInterface The interface in whose table to search + * (NULL to use the declaring class of method) + * @return UDATA The iTable index (not including the fixed J9ITable header), or -1 if not found + */ +UDATA +getITableIndexForMethod(J9Method * method, J9Class *targetInterface); + /** * Returns the first ROM method following the argument. * If this is called on the last ROM method in a ROM class diff --git a/runtime/oti/vm_api.h b/runtime/oti/vm_api.h index bfc3f1457f1..240c3d84ac0 100644 --- a/runtime/oti/vm_api.h +++ b/runtime/oti/vm_api.h @@ -3885,14 +3885,6 @@ illegalAccessMessage(J9VMThread *currentThread, IDATA badMemberModifier, J9Class void fillJITVTableSlot(J9VMThread *vmStruct, UDATA *currentSlot, J9Method *currentMethod); -/** - * @brief - * @param method - * @return UDATA - */ -UDATA -getITableIndexForMethod(J9Method * method); - /** * @brief * @param method diff --git a/runtime/util/hshelp.c b/runtime/util/hshelp.c index 9469f50c43f..cd7d39ebc97 100644 --- a/runtime/util/hshelp.c +++ b/runtime/util/hshelp.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 1991, 2017 IBM Corp. and others + * Copyright (c) 1991, 2018 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -993,25 +993,28 @@ fixITablesForFastHCR(J9VMThread *currentThread, J9HashTable *classPairs) } while (superITable != iTable) { - J9Class *interfaceClass = iTable->interfaceClass; - J9JVMTIClassPair exemplar; - J9JVMTIClassPair *result; - - exemplar.originalRAMClass = interfaceClass; - result = hashTableFind(classPairs, &exemplar); - if ((NULL != result) && (NULL != result->methodRemap)) { - UDATA methodIndex; + J9ITable *allInterfaces = (J9ITable*)iTable->interfaceClass->iTable; + UDATA *iTableMethods = (UDATA *)(iTable + 1); + do { + J9Class *interfaceClass = allInterfaces->interfaceClass; + J9JVMTIClassPair exemplar; + J9JVMTIClassPair *result; UDATA methodCount = interfaceClass->romClass->romMethodCount; - UDATA *vTable = (UDATA *)(clazz + 1); - UDATA *iTableMethods = (UDATA *)(iTable + 1); - for (methodIndex = 0; methodIndex < methodCount; methodIndex++) { - UDATA vTableIndex = findMethodInVTable(&interfaceClass->ramMethods[methodIndex], vTable); - - Assert_hshelp_false((UDATA)-1 == vTableIndex); - iTableMethods[methodIndex] = (vTableIndex * sizeof(UDATA)) + sizeof(J9Class); + exemplar.originalRAMClass = interfaceClass; + result = hashTableFind(classPairs, &exemplar); + if ((NULL != result) && (NULL != result->methodRemap)) { + UDATA methodIndex; + UDATA *vTable = (UDATA *)(clazz + 1); + + for (methodIndex = 0; methodIndex < methodCount; methodIndex++) { + UDATA vTableIndex = findMethodInVTable(&interfaceClass->ramMethods[methodIndex], vTable); + iTableMethods[methodIndex] = (vTableIndex * sizeof(UDATA)) + sizeof(J9Class); + } } - } + iTableMethods += methodCount; + allInterfaces = allInterfaces->next; + } while (NULL != allInterfaces); iTable = iTable->next; } } @@ -1695,24 +1698,41 @@ fixRAMConstantPoolForFastHCR(J9ConstantPool *ramConstantPool, J9HashTable *class case J9CPTYPE_INTERFACE_METHOD: { J9RAMInterfaceMethodRef *methodRef = (J9RAMInterfaceMethodRef *) &ramConstantPool[cpIndex]; UDATA methodIndex = ((methodRef->methodIndexAndArgCount & ~255) >> 8); - J9Class *interfaceClass = (J9Class *) methodRef->interfaceClass; - - classPair.originalRAMClass = interfaceClass; - classResult = hashTableFind(classHashTable, &classPair); - if (NULL != classResult) { - J9Class *obsoleteClass = classResult->replacementClass.ramClass; - - if (NULL != obsoleteClass) { - J9Method *method = &obsoleteClass->ramMethods[methodIndex]; - - methodPair.oldMethod = method; - methodResult = hashTableFind(methodHashTable, &methodPair); - if (NULL != methodResult) { - UDATA argCount = (methodRef->methodIndexAndArgCount & 255); - UDATA newMethodIndex = getMethodIndex(methodResult->newMethod); - - methodRef->methodIndexAndArgCount = ((newMethodIndex << 8) | argCount); + J9Class *resolvedClass = (J9Class *) methodRef->interfaceClass; + /* Don't fix unresolved entries */ + if (NULL != resolvedClass) { + /* Find the appropriate segment for the referenced method within the + * resolvedClass iTable. This is fast HCR (no addition or removal of + * methods), so the shape of the iTables cannot change, just the ordering + * of methods within them. + */ + J9ITable *allInterfaces = (J9ITable*)resolvedClass->iTable; + for(;;) { + J9Class *interfaceClass = allInterfaces->interfaceClass; + UDATA methodCount = interfaceClass->romClass->romMethodCount; + if (methodIndex < methodCount) { + classPair.originalRAMClass = interfaceClass; + classResult = hashTableFind(classHashTable, &classPair); + /* If the class was not replaced, no need to update the constant pool */ + if (NULL != classResult) { + J9Class *obsoleteClass = classResult->replacementClass.ramClass; + if (NULL != obsoleteClass) { + /* If the referenced method was not reordered, no need to update the constant pool */ + methodPair.oldMethod = obsoleteClass->ramMethods + methodIndex; + methodResult = hashTableFind(methodHashTable, &methodPair); + if (NULL != methodResult) { + UDATA argCount = (methodRef->methodIndexAndArgCount & 255); + UDATA newMethodIndex = getITableIndexForMethod(methodResult->newMethod, resolvedClass); + /* Fix the index in the resolved CP entry, retaining the argCount */ + methodRef->methodIndexAndArgCount = ((newMethodIndex << 8) | argCount); + } + } + } + /* iTable segment was located, stop the scan */ + break; } + methodIndex -= methodCount; + allInterfaces = allInterfaces->next; } } break; diff --git a/runtime/util/mthutil.c b/runtime/util/mthutil.c index 788cf4d5ce7..f521f3263a6 100644 --- a/runtime/util/mthutil.c +++ b/runtime/util/mthutil.c @@ -215,6 +215,47 @@ getCodeTypeAnnotationsDataFromROMMethod(J9ROMMethod *romMethod) return result; } +UDATA +getITableIndexForMethod(J9Method * method, J9Class *targetInterface) +{ + J9Class *methodClass = J9_CLASS_FROM_METHOD(method); + const UDATA methodCount = methodClass->romClass->romMethodCount; + const UDATA methodIndex = method - methodClass->ramMethods; + UDATA skip = 0; + /* NULL targetInterface implies searching only within methodClass, which may be an obsolete class. + * This works because the methods for the local interface always appear first in the iTable, with + * extended interface methods appearing after. + */ + if (NULL != targetInterface) { + /* Locate methodClass within the extends chain of targetInterface */ + J9ITable *allInterfaces = (J9ITable*)targetInterface->iTable; + for(;;) { + J9Class *interfaceClass = allInterfaces->interfaceClass; + if (interfaceClass == methodClass) { + break; + } + skip += interfaceClass->romClass->romMethodCount; + allInterfaces = allInterfaces->next; + } + } + /* The iTableIndex is the same as the (ram/rom)method index. + * This includes static and private methods - they just exist + * as dead entries in the iTable. + * + * Code below is the equivalent of doing: + * for (; methodIndex < methodCount; methodIndex++) { + * if (ramMethod == method) { + * return methodIndex; + * } + * ramMethod++; + * } + */ + if (methodIndex < methodCount) { + return methodIndex + skip; + } + return -1; +} + J9MethodDebugInfo * methodDebugInfoFromROMMethod(J9ROMMethod *romMethod) { diff --git a/runtime/vm/MHInterpreter.cpp b/runtime/vm/MHInterpreter.cpp index 7ac31b65b15..996fc6bda5c 100644 --- a/runtime/vm/MHInterpreter.cpp +++ b/runtime/vm/MHInterpreter.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2001, 2017 IBM Corp. and others + * Copyright (c) 2001, 2018 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -186,13 +186,13 @@ VM_MHInterpreter::dispatchLoop(j9object_t methodHandle) if (NULL != receiver) { _currentThread->sp += 1; J9Class *receiverClazz = J9OBJECT_CLAZZ(_currentThread, receiver); - J9Class *interfaceClazz = getPrimitiveHandleDefc(methodHandle); + J9Class *interfaceClazz = J9VM_J9CLASS_FROM_HEAPCLASS(_currentThread, J9VMJAVALANGINVOKEPRIMITIVEHANDLE_REFERENCECLASS(_currentThread, methodHandle)); method = convertITableIndexToVirtualMethod(receiverClazz, interfaceClazz, getVMSlot(methodHandle)); if (NULL != method) { goto runMethod; } prepareForExceptionThrow(_currentThread); - setClassCastException(_currentThread, receiverClazz, interfaceClazz); + setCurrentExceptionUTF(_currentThread, J9VMCONSTANTPOOL_JAVALANGINCOMPATIBLECLASSCHANGEERROR, NULL); goto throwCurrentException; } nextAction = THROW_NPE; diff --git a/runtime/vm/createramclass.cpp b/runtime/vm/createramclass.cpp index d51c9ee4314..427725c7f7e 100644 --- a/runtime/vm/createramclass.cpp +++ b/runtime/vm/createramclass.cpp @@ -263,6 +263,59 @@ unmarkInterfaces(J9Class *interfaceHead) } } +static void +addITableMethods(J9VMThread* vmStruct, J9Class *ramClass, J9Class *interfaceClass, UDATA **currentSlot) +{ + J9ROMClass *interfaceRomClass = interfaceClass->romClass; + UDATA count = interfaceRomClass->romMethodCount; + if (count != 0) { + UDATA *vTable = (UDATA *)(ramClass + 1); + UDATA vTableSize = *vTable; + J9Method *interfaceRamMethod = interfaceClass->ramMethods; + while (count-- > 0) { + J9ROMMethod *interfaceRomMethod = J9_ROM_METHOD_FROM_RAM_METHOD(interfaceRamMethod); + J9UTF8 *interfaceMethodName = J9ROMMETHOD_NAME(interfaceRomMethod); + J9UTF8 *interfaceMethodSig = J9ROMMETHOD_SIGNATURE(interfaceRomMethod); + UDATA vTableIndex = 0; + UDATA searchIndex = 2; + + /* Search the vTable for a public method of the correct name. */ + while (searchIndex <= vTableSize) { + J9Method *vTableRamMethod = (J9Method *)vTable[searchIndex]; + J9ROMMethod *vTableRomMethod = J9_ROM_METHOD_FROM_RAM_METHOD(vTableRamMethod); + J9UTF8 *vTableMethodName = J9ROMMETHOD_NAME(vTableRomMethod); + J9UTF8 *vTableMethodSig = J9ROMMETHOD_SIGNATURE(vTableRomMethod); + + if (vTableRomMethod->modifiers & J9_JAVA_PUBLIC) { + if ((J9UTF8_LENGTH(interfaceMethodName) == J9UTF8_LENGTH(vTableMethodName)) + && (J9UTF8_LENGTH(interfaceMethodSig) == J9UTF8_LENGTH(vTableMethodSig)) + && (memcmp(J9UTF8_DATA(interfaceMethodName), J9UTF8_DATA(vTableMethodName), J9UTF8_LENGTH(vTableMethodName)) == 0) + && (memcmp(J9UTF8_DATA(interfaceMethodSig), J9UTF8_DATA(vTableMethodSig), J9UTF8_LENGTH(vTableMethodSig)) == 0) + ) { + vTableIndex = (searchIndex * sizeof(UDATA)) + sizeof(J9Class); + break; + } + } + searchIndex++; + } + +#if defined(J9VM_TRACE_ITABLE) + { + PORT_ACCESS_FROM_VMC(vmStruct); + j9tty_printf(PORTLIB, "\n map %.*s%.*s to vTableIndex=%d (%d)", J9UTF8_LENGTH(interfaceMethodName), + J9UTF8_DATA(interfaceMethodName), J9UTF8_LENGTH(interfaceMethodSig), J9UTF8_DATA(interfaceMethodSig), vTableIndex, searchIndex); + } +#endif + + /* fill in interface index --> vTableIndex mapping */ + **currentSlot = vTableIndex; + (*currentSlot)++; + + interfaceRamMethod++; + } + } +} + static void createITable(J9VMThread* vmStruct, J9Class *ramClass, J9Class *interfaceClass, J9ITable ***previousLink, UDATA **currentSlot, UDATA depth) { @@ -276,54 +329,12 @@ createITable(J9VMThread* vmStruct, J9Class *ramClass, J9Class *interfaceClass, J /* If the newly-built class is not an interface class, fill in the iTable. */ if (J9_JAVA_INTERFACE != (ramClass->romClass->modifiers & J9_JAVA_INTERFACE)) { - J9ROMClass *interfaceRomClass = interfaceClass->romClass; - UDATA count = interfaceRomClass->romMethodCount; - if (count != 0) { - UDATA *vTable = (UDATA *)(ramClass + 1); - UDATA vTableSize = *vTable; - J9Method *interfaceRamMethod = interfaceClass->ramMethods; - while (count-- > 0) { - J9ROMMethod *interfaceRomMethod = J9_ROM_METHOD_FROM_RAM_METHOD(interfaceRamMethod); - J9UTF8 *interfaceMethodName = J9ROMMETHOD_NAME(interfaceRomMethod); - J9UTF8 *interfaceMethodSig = J9ROMMETHOD_SIGNATURE(interfaceRomMethod); - UDATA vTableIndex = 0; - UDATA searchIndex = 2; - - /* Search the vTable for a public method of the correct name. */ - while (searchIndex <= vTableSize) { - J9Method *vTableRamMethod = (J9Method *)vTable[searchIndex]; - J9ROMMethod *vTableRomMethod = J9_ROM_METHOD_FROM_RAM_METHOD(vTableRamMethod); - J9UTF8 *vTableMethodName = J9ROMMETHOD_NAME(vTableRomMethod); - J9UTF8 *vTableMethodSig = J9ROMMETHOD_SIGNATURE(vTableRomMethod); - - if (vTableRomMethod->modifiers & J9_JAVA_PUBLIC) { - if ((J9UTF8_LENGTH(interfaceMethodName) == J9UTF8_LENGTH(vTableMethodName)) - && (J9UTF8_LENGTH(interfaceMethodSig) == J9UTF8_LENGTH(vTableMethodSig)) - && (memcmp(J9UTF8_DATA(interfaceMethodName), J9UTF8_DATA(vTableMethodName), J9UTF8_LENGTH(vTableMethodName)) == 0) - && (memcmp(J9UTF8_DATA(interfaceMethodSig), J9UTF8_DATA(vTableMethodSig), J9UTF8_LENGTH(vTableMethodSig)) == 0) - ) { - vTableIndex = (searchIndex * sizeof(UDATA)) + sizeof(J9Class); - break; - } - } - searchIndex++; - } - -#if defined(J9VM_TRACE_ITABLE) - { - PORT_ACCESS_FROM_VMC(vmStruct); - j9tty_printf(PORTLIB, "\n map %.*s%.*s to vTableIndex=%d (%d)", J9UTF8_LENGTH(interfaceMethodName), - J9UTF8_DATA(interfaceMethodName), J9UTF8_LENGTH(interfaceMethodSig), J9UTF8_DATA(interfaceMethodSig), vTableIndex, searchIndex); - } -#endif - - /* fill in interface index --> vTableIndex mapping */ - **currentSlot = vTableIndex; - (*currentSlot)++; - - interfaceRamMethod++; - } - } + /* iTables contain all methods from the local interface, and any interfaces it extends */ + J9ITable *allInterfaces = (J9ITable*)interfaceClass->iTable; + do { + addITableMethods(vmStruct, ramClass, allInterfaces->interfaceClass, currentSlot); + allInterfaces = allInterfaces->next; + } while (NULL != allInterfaces); } } @@ -1322,30 +1333,6 @@ getVTableIndexForNameAndSigStartingAt(UDATA *vTable, J9UTF8 *name, J9UTF8 *signa return 0; } -UDATA -getITableIndexForMethod(J9Method * method) -{ - /* The iTableIndex is the same as the (ram/rom)method index. - * This includes static and private methods - they just exist - * as dead entries in the iTable. - * - * Code below is the equivalent of doing: - * for (; methodIndex < methodCount; methodIndex++) { - * if (ramMethod == method) { - * return methodIndex; - * } - * ramMethod++; - * } - */ - J9Class *methodClass = J9_CLASS_FROM_METHOD(method); - const UDATA methodCount = methodClass->romClass->romMethodCount; - const UDATA methodIndex = method - methodClass->ramMethods; - if (methodIndex < methodCount) { - return methodIndex; - } - return -1; -} - UDATA getVTableIndexForMethod(J9Method * method, J9Class *clazz, J9VMThread *vmThread) { @@ -2073,7 +2060,11 @@ internalCreateRAMClassFromROMClassImpl(J9VMThread *vmThread, J9ClassLoader *clas while (interfaceWalk != NULL) { /* The iTables for interface classes do not contain entries for methods. */ /* add methods supported by this interface to tally */ - iTableSlotCount += interfaceWalk->romClass->romMethodCount; + J9ITable *allInterfaces = (J9ITable*)interfaceWalk->iTable; + do { + iTableSlotCount += allInterfaces->interfaceClass->romClass->romMethodCount; + allInterfaces = allInterfaces->next; + } while (NULL != allInterfaces); interfaceWalk = (J9Class *)((UDATA)interfaceWalk->instanceDescription & ~INTERFACE_TAG); } } diff --git a/runtime/vm/intfunc.c b/runtime/vm/intfunc.c index 24082eb072b..6ad17372354 100644 --- a/runtime/vm/intfunc.c +++ b/runtime/vm/intfunc.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 1991, 2017 IBM Corp. and others + * Copyright (c) 1991, 2018 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -113,7 +113,6 @@ J9InternalVMFunctions J9InternalFunctions = { resolveVirtualMethodRef, resolveInterfaceMethodRef, getVTableIndexForMethod, - getITableIndexForMethod, checkVisibility, sendClinit, freeStackWalkCaches, diff --git a/runtime/vm/jnicsup.cpp b/runtime/vm/jnicsup.cpp index 02659f57562..4e0ceb0ae2d 100644 --- a/runtime/vm/jnicsup.cpp +++ b/runtime/vm/jnicsup.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 1991, 2017 IBM Corp. and others + * Copyright (c) 1991, 2018 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -2110,7 +2110,11 @@ initializeMethodID(J9VMThread * currentThread, J9JNIMethodID * methodID, J9Metho J9Class * declaringClass = J9_CLASS_FROM_METHOD(method); if (declaringClass->romClass->modifiers & J9AccInterface) { - vTableIndex = getITableIndexForMethod(method) | J9_JNI_MID_INTERFACE; + /* Because methodIDs do not store the original lookup class for interface methods, + * always use the declaring class of the interface method. Pass NULL here to allow + * for methodIDs to be created on obsolete classes for HCR purposes. + */ + vTableIndex = getITableIndexForMethod(method, NULL) | J9_JNI_MID_INTERFACE; } else { vTableIndex = getVTableIndexForMethod(method, declaringClass, currentThread); } diff --git a/runtime/vm/resolvesupport.cpp b/runtime/vm/resolvesupport.cpp index 1648c95a217..8b39e2eefeb 100644 --- a/runtime/vm/resolvesupport.cpp +++ b/runtime/vm/resolvesupport.cpp @@ -1005,15 +1005,23 @@ resolveInterfaceMethodRefInto(J9VMThread *vmStruct, J9ConstantPool *ramCP, UDATA if (method != NULL) { if (ramCPEntry != NULL) { J9RAMInterfaceMethodRef *ramInterfaceMethodRef = (J9RAMInterfaceMethodRef *)&ramCP[cpIndex]; - UDATA methodIndex = getITableIndexForMethod(method) << 8; + J9Class *methodClass = J9_CLASS_FROM_METHOD(method); + UDATA methodIndex = 0; UDATA oldArgCount = ramInterfaceMethodRef->methodIndexAndArgCount & 255; - J9Class *methodClass; + /* Object methods may be invoked via invokeinterface. In that case, use Object + * for the interfaceClass in the ref. The methodIndex value doesn't matter as + * Object will never be found in an iTable. + */ + if (J9_ARE_ANY_BITS_SET(methodClass->romClass->modifiers, J9_JAVA_INTERFACE)) { + methodIndex = getITableIndexForMethod(method, interfaceClass) << 8; + } else { + interfaceClass = methodClass; + } methodIndex |= oldArgCount; - methodClass = J9_CLASS_FROM_METHOD(method); ramCPEntry->methodIndexAndArgCount = methodIndex; /* interfaceClass is used to indicate resolved. Make sure to write it last */ issueWriteBarrier(); - ramCPEntry->interfaceClass = (UDATA)methodClass; + ramCPEntry->interfaceClass = (UDATA)interfaceClass; } /* indicate success */ returnValue = method; From 517ffdebce7bde1cf63292345a0499e9eed6a5ff Mon Sep 17 00:00:00 2001 From: Peter Bain Date: Thu, 15 Feb 2018 10:43:36 -0500 Subject: [PATCH 2/2] Check for arithmetic overflow in JNI string and array functions Verify that start + size is a valid non-negative 32-bit number. Signed-off-by: Peter Bain --- runtime/vm/jnimisc.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/runtime/vm/jnimisc.cpp b/runtime/vm/jnimisc.cpp index 23ae5f99f96..46942244c6d 100644 --- a/runtime/vm/jnimisc.cpp +++ b/runtime/vm/jnimisc.cpp @@ -589,7 +589,10 @@ getOrSetArrayRegion(JNIEnv *env, jarray array, jsize start, jsize len, void *buf UDATA ustart = (UDATA)(IDATA)start; UDATA ulen = (UDATA)(IDATA)len; UDATA end = ustart + ulen; - if ((ustart >= size) || (end > size)) { + if ((ustart >= size) + || (end > size) + || (end < ustart) /* overflow */ + ) { if ((ustart != size) || (0 != ulen)) { gpCheckSetCurrentException(currentThread, J9VMCONSTANTPOOL_JAVALANGARRAYINDEXOUTOFBOUNDSEXCEPTION, NULL); } @@ -808,7 +811,10 @@ getStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf) { J9VMThread *currentThread = (J9VMThread*)env; VM_VMAccess::inlineEnterVMFromJNI(currentThread); - if ((start < 0) || (len < 0)) { + if ((start < 0) + || (len < 0) + || (((U_32) (start + len)) > I_32_MAX) + ) { outOfBounds: gpCheckSetCurrentException(currentThread, J9VMCONSTANTPOOL_JAVALANGSTRINGINDEXOUTOFBOUNDSEXCEPTION, NULL); } else { @@ -937,7 +943,10 @@ getStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf) { J9VMThread *currentThread = (J9VMThread*)env; VM_VMAccess::inlineEnterVMFromJNI(currentThread); - if ((start < 0) || (len < 0)) { + if ((start < 0) + || (len < 0) + || (((U_32) (start + len)) > I_32_MAX) + ) { outOfBounds: gpCheckSetCurrentException(currentThread, J9VMCONSTANTPOOL_JAVALANGSTRINGINDEXOUTOFBOUNDSEXCEPTION, NULL); } else {