From 24f324b48e8f823fdef1d79689e08f53a0ebad0e Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Thu, 24 Sep 2020 13:22:10 -0400 Subject: [PATCH 01/14] Implement MethodHandleNatives native code Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- runtime/jcl/CMakeLists.txt | 7 + .../java_lang_invoke_MethodHandleNatives.cpp | 1434 +++++++++++++++++ runtime/jcl/common/jclcinit.c | 11 + runtime/jcl/exports.cmake | 20 + runtime/jcl/j9jcl.tdf | 31 + runtime/jcl/module.xml | 8 + ...ang_invoke_MethodHandleNatives_exports.xml | 36 + ...ang_invoke_MethodHandleNatives_objects.xml | 22 + runtime/oti/j9nonbuilder.h | 4 + runtime/oti/jclprots.h | 16 + 10 files changed, 1589 insertions(+) create mode 100644 runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp create mode 100644 runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_exports.xml create mode 100644 runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_objects.xml diff --git a/runtime/jcl/CMakeLists.txt b/runtime/jcl/CMakeLists.txt index ba3c06e4d49..094d7dc710f 100644 --- a/runtime/jcl/CMakeLists.txt +++ b/runtime/jcl/CMakeLists.txt @@ -175,6 +175,13 @@ if(J9VM_OPT_METHOD_HANDLE) ) endif() +if(J9VM_OPT_OPENJDK_METHODHANDLE) + target_sources(jclse + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/common/java_lang_invoke_MethodHandleNatives.cpp + ) +endif() + if(JAVA_SPEC_VERSION EQUAL 8) # sources for Java 8 only target_sources(jclse diff --git a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp new file mode 100644 index 00000000000..4e03e25cde9 --- /dev/null +++ b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp @@ -0,0 +1,1434 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 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 + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * 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-exception + *******************************************************************************/ + +#include "j9.h" +#include "jclprots.h" +#include "j9cp.h" +#include "j9protos.h" +#include "ut_j9jcl.h" +#include "j9port.h" +#include "jclglob.h" +#include "jcl_internal.h" +#include "util_api.h" +#include "j9vmconstantpool.h" +#include "ObjectAccessBarrierAPI.hpp" +#include "objhelp.h" + +#include +#include + +#include "VMHelpers.hpp" + +extern "C" { + +#define MN_IS_METHOD 0x00010000 +#define MN_IS_CONSTRUCTOR 0x00020000 +#define MN_IS_FIELD 0x00040000 +#define MN_IS_TYPE 0x00080000 +#define MN_CALLER_SENSITIVE 0x00100000 + +#define MN_REFERENCE_KIND_SHIFT 24 +#define MN_REFERENCE_KIND_MASK 0xF + +#define MN_SEARCH_SUPERCLASSES 0x00100000 +#define MN_SEARCH_INTERFACES 0x00200000 + +void +initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refObject) +{ + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + + J9Class* refClass = J9OBJECT_CLAZZ(currentThread, refObject); + + jint flags = 0; + jlong vmindex = 0; + jlong target = 0; + j9object_t clazzObject = NULL; + j9object_t nameObject = NULL; + j9object_t typeObject = NULL; + + if (refClass == J9VMJAVALANGREFLECTFIELD(vm)) { + J9JNIFieldID *fieldID = vm->reflectFunctions.idFromFieldObject(currentThread, NULL, refObject); + vmindex = (jlong)fieldID; + target = (jlong)fieldID->field; + + flags = fieldID->field->modifiers & CFR_FIELD_ACCESS_MASK; + flags |= MN_IS_FIELD; + flags |= (J9_ARE_ANY_BITS_SET(flags, J9AccStatic) ? MH_REF_GETSTATIC : MH_REF_GETFIELD) << MN_REFERENCE_KIND_SHIFT; + J9UTF8 *name = J9ROMFIELDSHAPE_NAME(fieldID->field); + J9UTF8 *signature = J9ROMFIELDSHAPE_SIGNATURE(fieldID->field); + + nameObject = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(name), (U_32)J9UTF8_LENGTH(name), J9_STR_INTERN); + typeObject = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(signature), (U_32)J9UTF8_LENGTH(signature), J9_STR_INTERN); + + clazzObject = J9VM_J9CLASS_TO_HEAPCLASS(fieldID->declaringClass); + + J9VMJAVALANGINVOKEMEMBERNAME_SET_NAME(currentThread, membernameObject, nameObject); + J9VMJAVALANGINVOKEMEMBERNAME_SET_TYPE(currentThread, membernameObject, typeObject); + Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setField(currentThread, (U_32)J9UTF8_LENGTH(name), J9UTF8_DATA(name), (U_32)J9UTF8_LENGTH(signature), J9UTF8_DATA(signature)); + } else if (refClass == J9VMJAVALANGREFLECTMETHOD(vm)) { + J9JNIMethodID *methodID = vm->reflectFunctions.idFromMethodObject(currentThread, refObject); + vmindex = (jlong)methodID; + target = (jlong)methodID->method; + + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(methodID->method); + + flags = romMethod->modifiers & CFR_METHOD_ACCESS_MASK; + flags |= MN_IS_METHOD; + if (J9_ARE_ANY_BITS_SET(methodID->vTableIndex, J9_JNI_MID_INTERFACE)) { + flags |= MH_REF_INVOKEINTERFACE << MN_REFERENCE_KIND_SHIFT; + } else if (J9_ARE_ANY_BITS_SET(romMethod->modifiers , J9AccStatic)) { + flags |= MH_REF_INVOKESTATIC << MN_REFERENCE_KIND_SHIFT; + } else if (J9_ARE_ANY_BITS_SET(romMethod->modifiers , J9AccFinal) || !J9ROMMETHOD_HAS_VTABLE(romMethod)) { + flags |= MH_REF_INVOKESPECIAL << MN_REFERENCE_KIND_SHIFT; + } else { + flags |= MH_REF_INVOKEVIRTUAL << MN_REFERENCE_KIND_SHIFT; + } + + clazzObject = J9VMJAVALANGREFLECTMETHOD_DECLARINGCLASS(currentThread, refObject); + } else if (refClass == J9VMJAVALANGREFLECTCONSTRUCTOR(vm)) { + J9JNIMethodID *methodID = vm->reflectFunctions.idFromConstructorObject(currentThread, refObject); + vmindex = (jlong)methodID; + target = (jlong)methodID->method; + + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(methodID->method); + + flags = romMethod->modifiers & CFR_METHOD_ACCESS_MASK; + flags |= MN_IS_CONSTRUCTOR | (MH_REF_INVOKESPECIAL << MN_REFERENCE_KIND_SHIFT); + + clazzObject = J9VMJAVALANGREFLECTMETHOD_DECLARINGCLASS(currentThread, refObject); + } else { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGILLEGALARGUMENTEXCEPTION, NULL); + } + + if (!VM_VMHelpers::exceptionPending(currentThread)) { + J9VMJAVALANGINVOKEMEMBERNAME_SET_FLAGS(currentThread, membernameObject, flags); + J9VMJAVALANGINVOKEMEMBERNAME_SET_CLAZZ(currentThread, membernameObject, clazzObject); + J9OBJECT_U64_STORE(currentThread, membernameObject, vm->vmindexOffset, (U_64)vmindex); + J9OBJECT_U64_STORE(currentThread, membernameObject, vm->vmtargetOffset, (U_64)target); + Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setData(currentThread, flags, clazzObject, vmindex, target); + } +} + +static char * +sigForPrimitiveOrVoid(J9JavaVM *vm, J9Class *clazz) +{ + char result = 0; + if (clazz == vm->booleanReflectClass) + result = 'Z'; + else if (clazz == vm->byteReflectClass) + result = 'B'; + else if (clazz == vm->charReflectClass) + result = 'C'; + else if (clazz == vm->shortReflectClass) + result = 'S'; + else if (clazz == vm->intReflectClass) + result = 'I'; + else if (clazz == vm->longReflectClass) + result = 'J'; + else if (clazz == vm->floatReflectClass) + result = 'F'; + else if (clazz == vm->doubleReflectClass) + result = 'D'; + else if (clazz == vm->voidReflectClass) + result = 'V'; + + if (result) { + PORT_ACCESS_FROM_JAVAVM(vm); + char* signature = (char*)j9mem_allocate_memory(2 * sizeof(char*), OMRMEM_CATEGORY_VM); + signature[0] = result; + signature[1] = '\0'; + return signature; + } + return NULL; +} + +char * +getClassSignature(J9VMThread *currentThread, J9Class * clazz) +{ + PORT_ACCESS_FROM_JAVAVM(currentThread->javaVM); + + U_32 numDims = 0; + + J9Class * myClass = clazz; + while (J9ROMCLASS_IS_ARRAY(myClass->romClass)) + { + J9Class * componentClass = (J9Class *)(((J9ArrayClass*)myClass)->componentType); + if (J9ROMCLASS_IS_PRIMITIVE_TYPE(componentClass->romClass)) { + break; + } + numDims++; + myClass = componentClass; + } + J9UTF8 * romName = J9ROMCLASS_CLASSNAME(myClass->romClass); + U_32 len = J9UTF8_LENGTH(romName); + char * name = (char *)J9UTF8_DATA(romName); + U_32 length = len + numDims; + if (* name != '[') + length += 2; + + length++; //for null-termination + char * sig = (char *)j9mem_allocate_memory(length, OMRMEM_CATEGORY_VM); + U_32 i; + for (i = 0; i < numDims; i++) + sig[i] = '['; + if (*name != '[') + sig[i++] = 'L'; + memcpy(sig+i, name, len); + i += len; + if (*name != '[') + sig[i++] = ';'; + + sig[length-1] = '\0'; + return sig; +} + +char * +getSignatureFromMethodType(J9VMThread *currentThread, j9object_t typeObject, UDATA *signatureLength) +{ + J9JavaVM *vm = currentThread->javaVM; + j9object_t ptypes = J9VMJAVALANGINVOKEMETHODTYPE_PTYPES(currentThread, typeObject); + U_32 numArgs = J9INDEXABLEOBJECT_SIZE(currentThread, ptypes); + + PORT_ACCESS_FROM_JAVAVM(vm); + + char** signatures = (char**)j9mem_allocate_memory((numArgs + 1) * sizeof(char*), OMRMEM_CATEGORY_VM); + *signatureLength = 2; //space for '(', ')' + for (U_32 i = 0; i < numArgs; i++) { + j9object_t pObject = J9JAVAARRAYOFOBJECT_LOAD(currentThread, ptypes, i); + J9Class *pclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, pObject); + signatures[i] = sigForPrimitiveOrVoid(vm, pclass); + if (!signatures[i]) + signatures[i] = getClassSignature(currentThread, pclass); + + *signatureLength += strlen(signatures[i]); + } + + // Return type + j9object_t rtype = J9VMJAVALANGINVOKEMETHODTYPE_RTYPE(currentThread, typeObject); + J9Class *rclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, rtype); + char* rSignature = sigForPrimitiveOrVoid(vm, rclass); + if (!rSignature) + rSignature = getClassSignature(currentThread, rclass); + + *signatureLength += strlen(rSignature); + + char* methodDescriptor = (char*)j9mem_allocate_memory(*signatureLength+1, OMRMEM_CATEGORY_VM); + char* cursor = methodDescriptor; + *cursor++ = '('; + + // Copy class signatures to descriptor string + for (U_32 i = 0; i < numArgs; i++) { + U_32 len = strlen(signatures[i]); + strncpy(cursor, signatures[i], len); + cursor += len; + j9mem_free_memory(signatures[i]); + } + + *cursor++ = ')'; + // Copy return type signature to descriptor string + strcpy(cursor, rSignature); + j9mem_free_memory(signatures); + return methodDescriptor; +} + +static J9Class * +classForSignature(struct J9VMThread *vmThread, U_8 **sigDataPtr, struct J9ClassLoader *classLoader) +{ + U_8 *sigData = *sigDataPtr; + J9JavaVM *vm = vmThread->javaVM; + J9Class *clazz = NULL; + UDATA arity = 0; + U_8 c = 0; + UDATA i = 0; + + for (c = *sigData++; '[' == c; c = *sigData++) { + arity++; + } + + /* Non-array case */ + switch (c) { + case 'Q': + case 'L': { + /* object case */ + U_8 *tempData = sigData; + UDATA length = 0; + + /* find the signature length -> up to the ";" */ + while (';' != *sigData++) { + length++; + } + + /* find the class from the signature chunk */ + clazz = vm->internalVMFunctions->internalFindClassUTF8(vmThread, tempData, length, classLoader, J9_FINDCLASS_FLAG_THROW_ON_FAIL); + break; + } + case 'I': + clazz = vm->intReflectClass; + break; + case 'Z': + clazz = vm->booleanReflectClass; + break; + case 'J': + clazz = vm->longReflectClass; + break; +#if defined(J9VM_INTERP_FLOAT_SUPPORT) + case 'D': + clazz = vm->doubleReflectClass; + break; + case 'F': + clazz = vm->floatReflectClass; + break; +#endif + case 'C': + clazz = vm->charReflectClass; + break; + case 'B': + clazz = vm->byteReflectClass; + break; + case 'S': + clazz = vm->shortReflectClass; + break; + case 'V': + clazz = vm->voidReflectClass; + break; + } + + for (i = 0; (i < arity) && (NULL != clazz); i++) { + clazz = fetchArrayClass(vmThread, clazz); + } + + if (NULL != clazz) { + *sigDataPtr = sigData; + } + + return clazz; +} + +static j9object_t +createFieldFromID(struct J9VMThread *vmThread, J9JNIFieldID *j9FieldID) +{ + J9UTF8 *nameUTF = NULL; + j9object_t nameString = NULL; + U_8 *signatureData = NULL; + J9Class *typeClass = NULL; + j9object_t fieldObject = NULL; + J9Class *jlrFieldClass = J9VMJAVALANGREFLECTFIELD(vmThread->javaVM); + UDATA initStatus; + + if (NULL == jlrFieldClass) { + return NULL; + } + + initStatus = jlrFieldClass->initializeStatus; + if (initStatus != J9ClassInitSucceeded && initStatus != (UDATA) vmThread) { + vmThread->javaVM->internalVMFunctions->initializeClass(vmThread, jlrFieldClass); + if (vmThread->currentException != NULL) { + return NULL; + } + } + + fieldObject = vmThread->javaVM->memoryManagerFunctions->J9AllocateObject(vmThread, jlrFieldClass, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + if (NULL == fieldObject) { + vmThread->javaVM->internalVMFunctions->setHeapOutOfMemoryError(vmThread); + return NULL; + } + + PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, fieldObject); + + signatureData = J9UTF8_DATA(J9ROMFIELDSHAPE_SIGNATURE(j9FieldID->field)); + typeClass = classForSignature(vmThread, &signatureData, j9FieldID->declaringClass->classLoader); + if (NULL == typeClass) { + DROP_OBJECT_IN_SPECIAL_FRAME(vmThread); /* fieldObject */ + return NULL; + } + + fieldObject = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0); + J9VMJAVALANGREFLECTFIELD_SET_TYPE(vmThread, fieldObject, J9VM_J9CLASS_TO_HEAPCLASS(typeClass)); + + nameUTF = J9ROMFIELDSHAPE_NAME(j9FieldID->field); + nameString = vmThread->javaVM->memoryManagerFunctions->j9gc_createJavaLangString(vmThread, J9UTF8_DATA(nameUTF), (U_32) J9UTF8_LENGTH(nameUTF), J9_STR_INTERN); + if (NULL == nameString) { + DROP_OBJECT_IN_SPECIAL_FRAME(vmThread); /* fieldObject */ + return NULL; + } + + fieldObject = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0); + J9VMJAVALANGREFLECTFIELD_SET_NAME(vmThread, fieldObject, nameString); + + if (0 != (j9FieldID->field->modifiers & J9FieldFlagHasGenericSignature)) { + J9UTF8 *sigUTF = romFieldGenericSignature(j9FieldID->field); + j9object_t sigString = vmThread->javaVM->memoryManagerFunctions->j9gc_createJavaLangString(vmThread, J9UTF8_DATA(sigUTF), (U_32) J9UTF8_LENGTH(sigUTF), 0); + if (NULL == sigString) { + DROP_OBJECT_IN_SPECIAL_FRAME(vmThread); /* fieldObject */ + return NULL; + } + + fieldObject = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0); +#if defined(USE_SUN_REFLECT) + J9VMJAVALANGREFLECTFIELD_SET_SIGNATURE(vmThread, fieldObject, sigString); +#endif + } + + { + j9object_t byteArray = getFieldAnnotationData(vmThread, j9FieldID->declaringClass, j9FieldID); + if (NULL != vmThread->currentException) { + DROP_OBJECT_IN_SPECIAL_FRAME(vmThread); /* fieldObject */ + return NULL; + } + if (NULL != byteArray) { + fieldObject = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0); + J9VMJAVALANGREFLECTFIELD_SET_ANNOTATIONS(vmThread, fieldObject, byteArray); + } + } + + fieldObject = POP_OBJECT_IN_SPECIAL_FRAME(vmThread); + + /* Java 7 uses int field ID's to avoid modifying Sun JCL code */ + J9VMJAVALANGREFLECTFIELD_SET_INTFIELDID(vmThread, fieldObject, (U_32)(j9FieldID->index)); + + J9VMJAVALANGREFLECTFIELD_SET_DECLARINGCLASS(vmThread, fieldObject, J9VM_J9CLASS_TO_HEAPCLASS(j9FieldID->declaringClass)); +#if defined(USE_SUN_REFLECT) + J9VMJAVALANGREFLECTFIELD_SET_MODIFIERS(vmThread, fieldObject, j9FieldID->field->modifiers & CFR_FIELD_ACCESS_MASK); +#endif + + return fieldObject; +} + +j9object_t +createFieldObject(J9VMThread *currentThread, J9ROMFieldShape *romField, J9Class *declaringClass, J9UTF8 *name, J9UTF8 *sig, bool isStaticField) +{ + J9InternalVMFunctions *vmFuncs = currentThread->javaVM->internalVMFunctions; + + J9JNIFieldID *fieldID = NULL; + UDATA offset = 0; + UDATA inconsistentData = 0; + + if (isStaticField) { + offset = (UDATA)vmFuncs->staticFieldAddress(currentThread, declaringClass, J9UTF8_DATA(name), J9UTF8_LENGTH(name), J9UTF8_DATA(sig), J9UTF8_LENGTH(sig), NULL, NULL, 0, NULL); + offset -= (UDATA)declaringClass->ramStatics; + } else { + offset = vmFuncs->instanceFieldOffset(currentThread, declaringClass, J9UTF8_DATA(name), J9UTF8_LENGTH(name), J9UTF8_DATA(sig), J9UTF8_LENGTH(sig), NULL, NULL, 0); + } + + fieldID = vmFuncs->getJNIFieldID(currentThread, declaringClass, romField, offset, &inconsistentData); + + return createFieldFromID(currentThread, fieldID); +} + +j9object_t +resolveRefToObject(J9VMThread *currentThread, J9ConstantPool *ramConstantPool, U_16 cpIndex, bool resolve) +{ + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + + j9object_t result = NULL; + + J9RAMSingleSlotConstantRef *ramCP = (J9RAMSingleSlotConstantRef*)ramConstantPool + cpIndex; + U_32 *cpShapeDescription = J9ROMCLASS_CPSHAPEDESCRIPTION(J9_CLASS_FROM_CP(ramConstantPool)->romClass); + + switch (J9_CP_TYPE(cpShapeDescription, cpIndex)) { + case J9CPTYPE_CLASS: + { + J9Class *clazz = (J9Class*)ramCP->value; + if ((NULL == clazz) && resolve) { + clazz = vmFuncs->resolveClassRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); + } + if (NULL != clazz) { + result = J9VM_J9CLASS_TO_HEAPCLASS(clazz); + } + break; + } + case J9CPTYPE_STRING: + { + result = (j9object_t)ramCP->value; + if ((NULL == result) && resolve) { + result = vmFuncs->resolveStringRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); + } + break; + } + case J9CPTYPE_INT: + { + result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGINTEGER_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + J9VMJAVALANGINTEGER_SET_VALUE(currentThread, result, ramCP->value); + break; + } + case J9CPTYPE_FLOAT: + { + result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGFLOAT_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + J9VMJAVALANGFLOAT_SET_VALUE(currentThread, result, ramCP->value); + break; + } + case J9CPTYPE_LONG: + { + J9ROMConstantRef *romCP = (J9ROMConstantRef*)J9_ROM_CP_FROM_CP(ramConstantPool) + cpIndex; + U_64 value = romCP->slot1; + value = (value << 32) + romCP->slot2; + result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGLONG_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + J9VMJAVALANGLONG_SET_VALUE(currentThread, result, value); + break; + } + case J9CPTYPE_DOUBLE: + { + J9ROMConstantRef *romCP = (J9ROMConstantRef*)J9_ROM_CP_FROM_CP(ramConstantPool) + cpIndex; + U_64 value = romCP->slot1; + value = (value << 32) + romCP->slot2; + result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGDOUBLE_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + J9VMJAVALANGDOUBLE_SET_VALUE(currentThread, result, value); + break; + } + case J9CPTYPE_METHOD_TYPE: + { + result = (j9object_t)ramCP->value; + if ((NULL == result) && resolve) { + result = vmFuncs->resolveMethodTypeRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); + } + break; + } + case J9CPTYPE_METHODHANDLE: + { + result = (j9object_t)ramCP->value; + if ((NULL == result) && resolve) { + result = vmFuncs->resolveMethodHandleRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE | J9_RESOLVE_FLAG_NO_CLASS_INIT); + } + break; + } + case J9CPTYPE_CONSTANT_DYNAMIC: + { + result = (j9object_t)ramCP->value; + if ((NULL == result) && resolve) { + result = vmFuncs->resolveConstantDynamic(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); + } + break; + } + } + + return result; +} + +J9Method * +lookupMethod(J9VMThread *currentThread, J9Class *resolvedClass, J9JNINameAndSignature *nas, J9Class *callerClass, UDATA lookupOptions) +{ + J9Method *result = NULL; + if (resolvedClass == J9VMJAVALANGINVOKEMETHODHANDLE(currentThread->javaVM)) { + if ((0 == strcmp(nas->name, "linkToVirtual")) + || (0 == strcmp(nas->name, "linkToStatic")) + || (0 == strcmp(nas->name, "linkToSpecial")) + || (0 == strcmp(nas->name, "linkToInterface")) + || (0 == strcmp(nas->name, "invokeBasic")) + ) { + nas->signature = NULL; + nas->signatureLength = 0; + + /* Set flag for partial signature lookup. Signature length is already initialized to 0. */ + lookupOptions |= J9_LOOK_PARTIAL_SIGNATURE; + } + } + + result = (J9Method*)currentThread->javaVM->internalVMFunctions->javaLookupMethod(currentThread, resolvedClass, (J9ROMNameAndSignature*)nas, callerClass, lookupOptions); + + return result; +} + + +/** + * static native void init(MemberName self, Object ref); + */ +void JNICALL +Java_java_lang_invoke_MethodHandleNatives_init(JNIEnv *env, jclass clazz, jobject self, jobject ref) +{ + J9VMThread *currentThread = (J9VMThread*)env; + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + vmFuncs->internalEnterVMFromJNI(currentThread); + + Trc_JCL_java_lang_invoke_MethodHandleNatives_init_Entry(env, self, ref); + if (NULL == self || NULL == ref) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL); + } else { + j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + j9object_t refObject = J9_JNI_UNWRAP_REFERENCE(ref); + + initImpl(currentThread, membernameObject, refObject); + } + Trc_JCL_java_lang_invoke_MethodHandleNatives_init_Exit(env); + vmFuncs->internalExitVMToJNI(currentThread); +} + +/** + * static native void expand(MemberName self); + */ +void JNICALL +Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobject self) +{ + J9VMThread *currentThread = (J9VMThread*)env; + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + vmFuncs->internalEnterVMFromJNI(currentThread); + + Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Entry(env, self); + if (NULL == self) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL); + } else { + j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + j9object_t clazzObject = J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject); + j9object_t nameObject = J9VMJAVALANGINVOKEMEMBERNAME_NAME(currentThread, membernameObject); + j9object_t typeObject = J9VMJAVALANGINVOKEMEMBERNAME_TYPE(currentThread, membernameObject); + jint flags = J9VMJAVALANGINVOKEMEMBERNAME_FLAGS(currentThread, membernameObject); + jlong vmindex = (jlong)J9OBJECT_ADDRESS_LOAD(currentThread, membernameObject, vm->vmindexOffset); + + Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Data(env, membernameObject, clazzObject, nameObject, typeObject, flags, vmindex); + if (J9_ARE_ANY_BITS_SET(flags, MN_IS_FIELD)) { + if ((NULL != clazzObject) && (NULL != (void*)vmindex)) { + // J9Class *declaringClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, clazzObject); + + J9JNIFieldID *field = (J9JNIFieldID*)vmindex; + J9UTF8 *name = J9ROMFIELDSHAPE_NAME(field->field); + J9UTF8 *signature = J9ROMFIELDSHAPE_SIGNATURE(field->field); + + if (nameObject == NULL) { + j9object_t nameString = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(name), (U_32)J9UTF8_LENGTH(name), J9_STR_INTERN); + J9VMJAVALANGINVOKEMEMBERNAME_SET_NAME(currentThread, membernameObject, nameString); + } + if (typeObject == NULL) { + j9object_t signatureString = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(signature), (U_32)J9UTF8_LENGTH(signature), J9_STR_INTERN); + J9VMJAVALANGINVOKEMEMBERNAME_SET_TYPE(currentThread, membernameObject, signatureString); + } + } else { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGILLEGALARGUMENTEXCEPTION, NULL); + } + } else if (J9_ARE_ANY_BITS_SET(flags, MN_IS_METHOD | MN_IS_CONSTRUCTOR)) { + if (NULL != (void*)vmindex) { + J9JNIMethodID *methodID = (J9JNIMethodID*)vmindex; + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(methodID->method); + + if (clazzObject == NULL) { + j9object_t newClassObject = J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_METHOD(methodID->method)); + J9VMJAVALANGINVOKEMEMBERNAME_SET_CLAZZ(currentThread, membernameObject, newClassObject); + } + if (nameObject == NULL) { + J9UTF8 *name = J9ROMMETHOD_NAME(romMethod); + j9object_t nameString = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(name), (U_32)J9UTF8_LENGTH(name), J9_STR_INTERN); + J9VMJAVALANGINVOKEMEMBERNAME_SET_NAME(currentThread, membernameObject, nameString); + } + if (typeObject == NULL) { + J9UTF8 *signature = J9ROMMETHOD_SIGNATURE(romMethod); + j9object_t signatureString = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(signature), (U_32)J9UTF8_LENGTH(signature), J9_STR_INTERN); + J9VMJAVALANGINVOKEMEMBERNAME_SET_TYPE(currentThread, membernameObject, signatureString); + } + } else { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGILLEGALARGUMENTEXCEPTION, NULL); + } + } else { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); + } + } + Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Exit(env); + vmFuncs->internalExitVMToJNI(currentThread); +} + +/** + * static native MemberName resolve(MemberName self, Class caller, + * boolean speculativeResolve) throws LinkageError, ClassNotFoundException; + */ +jobject JNICALL +Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, jobject self, jclass caller, jboolean speculativeResolve) +{ + J9VMThread *currentThread = (J9VMThread*)env; + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + jobject result = NULL; + vmFuncs->internalEnterVMFromJNI(currentThread); + + Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Entry(env, self, caller, (speculativeResolve ? "true" : "false")); + if (NULL == self) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); + } else { + j9object_t callerObject = (NULL == caller) ? NULL : J9_JNI_UNWRAP_REFERENCE(caller); + j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + j9object_t clazzObject = J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject); + j9object_t nameObject = J9VMJAVALANGINVOKEMEMBERNAME_NAME(currentThread, membernameObject); + j9object_t typeObject = J9VMJAVALANGINVOKEMEMBERNAME_TYPE(currentThread, membernameObject); + jlong vmindex = (jlong)(UDATA)J9OBJECT_U64_LOAD(currentThread, membernameObject, vm->vmindexOffset); + jlong target = (jlong)(UDATA)J9OBJECT_U64_LOAD(currentThread, membernameObject, vm->vmtargetOffset); + + jint flags = J9VMJAVALANGINVOKEMEMBERNAME_FLAGS(currentThread, membernameObject); + jint new_flags = 0; + j9object_t new_clazz = NULL; + + Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Data(env, membernameObject, clazzObject, callerObject, nameObject, typeObject, flags, vmindex, target); + if (0 != target) { + result = self; + } else { + J9Class *resolvedClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, clazzObject); + J9Class *callerClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, callerObject); + + int ref_kind = (flags >> MN_REFERENCE_KIND_SHIFT) & MN_REFERENCE_KIND_MASK; + + PORT_ACCESS_FROM_JAVAVM(vm); + + UDATA nameLength = vmFuncs->getStringUTF8Length(currentThread, nameObject) + 1; + char *name = (char*)j9mem_allocate_memory(nameLength, OMRMEM_CATEGORY_VM); + UDATA signatureLength = 0; + char *signature = NULL; + J9Class *typeClass = J9OBJECT_CLAZZ(currentThread, typeObject); + if (J9VMJAVALANGINVOKEMETHODTYPE(vm) == typeClass) { + j9object_t sigString = J9VMJAVALANGINVOKEMETHODTYPE_METHODDESCRIPTOR(currentThread, typeObject); + if (NULL != sigString) { + signatureLength = vmFuncs->getStringUTF8Length(currentThread, sigString) + 1; + signature = (char*)j9mem_allocate_memory(signatureLength, OMRMEM_CATEGORY_VM); + vmFuncs->copyStringToUTF8Helper(currentThread, sigString, J9_STR_NULL_TERMINATE_RESULT | J9_STR_XLAT , 0, J9VMJAVALANGSTRING_LENGTH(currentThread, sigString), (U_8 *)signature, signatureLength); + } else { + signature = getSignatureFromMethodType(currentThread, typeObject, &signatureLength); + } + } else if (J9VMJAVALANGSTRING_OR_NULL(vm) == typeClass) { + signatureLength = vmFuncs->getStringUTF8Length(currentThread, typeObject) + 1; + signature = (char*)j9mem_allocate_memory(signatureLength, OMRMEM_CATEGORY_VM); + UDATA stringLength = J9VMJAVALANGSTRING_LENGTH(currentThread, typeObject); + vmFuncs->copyStringToUTF8Helper(currentThread, typeObject, J9_STR_NULL_TERMINATE_RESULT | J9_STR_XLAT , 0, stringLength, (U_8 *)signature, signatureLength); + } else if (J9VMJAVALANGCLASS(vm) == typeClass) { + J9Class *rclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, typeObject); + signature = sigForPrimitiveOrVoid(vm, rclass); + if (!signature) { + signature = getClassSignature(currentThread, rclass); + } + + signatureLength = strlen(signature); + } else { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); + vmFuncs->internalExitVMToJNI(currentThread); + return NULL; + } + vmFuncs->copyStringToUTF8Helper(currentThread, nameObject, J9_STR_NULL_TERMINATE_RESULT | J9_STR_XLAT , 0, J9VMJAVALANGSTRING_LENGTH(currentThread, nameObject), (U_8 *)name, nameLength); + + Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_NAS(env, name, signature); + + if (J9_ARE_ANY_BITS_SET(flags, MN_IS_METHOD | MN_IS_CONSTRUCTOR)) { + J9JNINameAndSignature nas; + UDATA lookupOptions = J9_LOOK_JNI; + + if (JNI_TRUE == speculativeResolve) { + lookupOptions |= J9_LOOK_NO_THROW; + } + switch (ref_kind) + { + case MH_REF_INVOKEINTERFACE: + lookupOptions |= J9_LOOK_INTERFACE; + break; + case MH_REF_INVOKESPECIAL: + lookupOptions |= (J9_LOOK_VIRTUAL | J9_LOOK_ALLOW_FWD | J9_LOOK_HANDLE_DEFAULT_METHOD_CONFLICTS); + break; + case MH_REF_INVOKESTATIC: + lookupOptions |= J9_LOOK_STATIC; + if (J9_ARE_ANY_BITS_SET(resolvedClass->romClass->modifiers, J9AccInterface)) { + lookupOptions |= J9_LOOK_INTERFACE; + } + break; + default: + lookupOptions |= J9_LOOK_VIRTUAL; + break; + } + + nas.name = name; + nas.signature = signature; + nas.nameLength = (U_32)strlen(name); + nas.signatureLength = (U_32)strlen(signature); + + /* Check if signature polymorphic native calls */ + J9Method *method = lookupMethod(currentThread, resolvedClass, &nas, callerClass, lookupOptions); + + if (NULL != method) { + J9JNIMethodID *methodID = vmFuncs->getJNIMethodID(currentThread, method); + vmindex = (jlong)(UDATA)methodID; + target = (jlong)(UDATA)method; + + new_clazz = J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_METHOD(method)); + + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(methodID->method); + new_flags = flags | (romMethod->modifiers & CFR_METHOD_ACCESS_MASK); + } + } if (J9_ARE_ANY_BITS_SET(flags, MN_IS_FIELD)) { + J9Class *declaringClass; + J9ROMFieldShape *romField; + UDATA lookupOptions = 0; + UDATA offset = 0; + if (JNI_TRUE == speculativeResolve) { + lookupOptions |= J9_RESOLVE_FLAG_NO_THROW_ON_FAIL; + } + + offset = vmFuncs->instanceFieldOffset(currentThread, + resolvedClass, + (U_8*)name, strlen(name), + (U_8*)signature, strlen(signature), + &declaringClass, (UDATA*)&romField, + lookupOptions); + + if (offset == (UDATA)-1) { + declaringClass = NULL; + + if (VM_VMHelpers::exceptionPending(currentThread)) { + VM_VMHelpers::clearException(currentThread); + } + + void* fieldAddress = vmFuncs->staticFieldAddress(currentThread, + resolvedClass, + (U_8*)name, strlen(name), + (U_8*)signature, strlen(signature), + &declaringClass, (UDATA*)&romField, + lookupOptions, + NULL); + + if (fieldAddress == NULL) { + declaringClass = NULL; + } else { + offset = (UDATA)fieldAddress - (UDATA)declaringClass->ramStatics; + } + } + + if (NULL != declaringClass) { + UDATA inconsistentData = 0; + J9JNIFieldID *fieldID = vmFuncs->getJNIFieldID(currentThread, declaringClass, romField, offset, &inconsistentData); + vmindex = (jlong)(UDATA)fieldID; + + new_clazz = J9VM_J9CLASS_TO_HEAPCLASS(declaringClass); + new_flags = MN_IS_FIELD | (fieldID->field->modifiers & CFR_FIELD_ACCESS_MASK); + romField = fieldID->field; + + if (J9_ARE_ANY_BITS_SET(romField->modifiers, J9AccStatic)) { + offset = fieldID->offset | J9_SUN_STATIC_FIELD_OFFSET_TAG; + if (J9_ARE_ANY_BITS_SET(romField->modifiers, J9AccFinal)) { + offset |= J9_SUN_FINAL_FIELD_OFFSET_TAG; + } + + if ((MH_REF_PUTFIELD == ref_kind) || (MH_REF_PUTSTATIC == ref_kind)) { + new_flags |= (MH_REF_PUTSTATIC << MN_REFERENCE_KIND_SHIFT); + } else { + new_flags |= (MH_REF_GETSTATIC << MN_REFERENCE_KIND_SHIFT); + } + } else { + if ((MH_REF_PUTFIELD == ref_kind) || (MH_REF_PUTSTATIC == ref_kind)) { + new_flags |= (MH_REF_PUTFIELD << MN_REFERENCE_KIND_SHIFT); + } else { + new_flags |= (MH_REF_GETFIELD << MN_REFERENCE_KIND_SHIFT); + } + } + + target = (jlong)offset; + } + } + + if ((0 != vmindex) && (0 != target)) { + membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + J9VMJAVALANGINVOKEMEMBERNAME_SET_FLAGS(currentThread, membernameObject, new_flags); + J9VMJAVALANGINVOKEMEMBERNAME_SET_CLAZZ(currentThread, membernameObject, new_clazz); + J9OBJECT_U64_STORE(currentThread, membernameObject, vm->vmindexOffset, (U_64)vmindex); + J9OBJECT_U64_STORE(currentThread, membernameObject, vm->vmtargetOffset, (U_64)target); + + Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_resolved(env, vmindex, target, new_clazz, flags); + + result = vmFuncs->j9jni_createLocalRef(env, membernameObject); + } + j9mem_free_memory(name); + j9mem_free_memory(signature); + + if ((NULL == result) && (JNI_TRUE != speculativeResolve) && !VM_VMHelpers::exceptionPending(currentThread)) { + if (J9_ARE_ANY_BITS_SET(flags, MN_IS_FIELD)) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNOSUCHFIELDERROR, NULL); + } else if (J9_ARE_ANY_BITS_SET(flags, MN_IS_CONSTRUCTOR | MN_IS_METHOD)) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNOSUCHMETHODERROR, NULL); + } else { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGLINKAGEERROR, NULL); + } + } + } + } + Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Exit(env); + vmFuncs->internalExitVMToJNI(currentThread); + return result; +} + +/** + * static native int getMembers(Class defc, String matchName, String matchSig, + * int matchFlags, Class caller, int skip, MemberName[] results); + */ +jint JNICALL +Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, jclass defc, jstring matchName, jstring matchSig, jint matchFlags, jclass caller, jint skip, jobjectArray results) +{ + J9VMThread *currentThread = (J9VMThread*)env; + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + vmFuncs->internalEnterVMFromJNI(currentThread); + jint result = 0; + + Trc_JCL_java_lang_invoke_MethodHandleNatives_getMembers_Entry(env, defc, matchName, matchSig, matchFlags, caller, skip, results); + + if ((NULL == defc) || (NULL == results)) { + result = -1; + } else { + j9object_t defcObject = J9_JNI_UNWRAP_REFERENCE(defc); + j9array_t resultsArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(results); + j9object_t nameObject = ((NULL == matchName) ? NULL : J9_JNI_UNWRAP_REFERENCE(matchName)); + j9object_t sigObject = ((NULL == matchSig) ? NULL : J9_JNI_UNWRAP_REFERENCE(matchSig)); + // j9object_t callerObject = ((NULL == caller) ? NULL : J9_JNI_UNWRAP_REFERENCE(caller)); + + if (NULL == defcObject) { + result = -1; + } else if (!(((NULL != matchName) && (NULL == nameObject)) || ((NULL != matchSig) && (NULL == sigObject)))) { + J9Class *defClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, defcObject); + UDATA length = J9INDEXABLEOBJECT_SIZE(currentThread, resultsArray); + UDATA index = 0; + if (!((NULL != nameObject) && (0 == J9VMJAVALANGSTRING_LENGTH(currentThread, nameObject)))) { + if (J9ROMCLASS_IS_INTERFACE(defClass->romClass)) { + result = -1; + } else { + if (J9_ARE_ANY_BITS_SET(matchFlags, MN_IS_FIELD)) { + J9ROMFieldShape *romField = NULL; + J9ROMFieldWalkState walkState; + + UDATA classDepth = 0; + if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_SUPERCLASSES)) { + /* walk superclasses */ + J9CLASS_DEPTH(defClass); + } + J9Class *currentClass = defClass; + + while (NULL != currentClass) { + /* walk currentClass */ + memset(&walkState, 0, sizeof(walkState)); + romField = romFieldsStartDo(currentClass->romClass, &walkState); + + while (NULL != romField) { + J9UTF8 *nameUTF = J9ROMFIELDSHAPE_NAME(romField); + J9UTF8 *signatureUTF = J9ROMFIELDSHAPE_SIGNATURE(romField); + if (((NULL == nameObject) || (0 != vmFuncs->compareStringToUTF8(currentThread, nameObject, FALSE, J9UTF8_DATA(nameUTF), J9UTF8_LENGTH(nameUTF)))) + && ((NULL != sigObject) && (0 == vmFuncs->compareStringToUTF8(currentThread, sigObject, FALSE, J9UTF8_DATA(signatureUTF), J9UTF8_LENGTH(signatureUTF)))) + ) { + if (skip > 0) { + skip -=1; + } else { + if (index < length) { + j9object_t memberName = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultsArray, index); + if (NULL == memberName) { + vmFuncs->internalExitVMToJNI(currentThread); + return -99; + } + j9object_t fieldObj = NULL; + if (romField->modifiers & J9AccStatic) { + /* create static field object */ + fieldObj = createFieldObject(currentThread, romField, defClass, nameUTF, signatureUTF, true); + } else { + /* create instance field object */ + fieldObj = createFieldObject(currentThread, romField, defClass, nameUTF, signatureUTF, false); + } + initImpl(currentThread, memberName, fieldObj); + } + } + result += 1; + } + romField = romFieldsNextDo(&walkState); + } + + /* get the superclass */ + if (classDepth >= 1) { + classDepth -= 1; + currentClass = defClass->superclasses[classDepth]; + } else { + currentClass = NULL; + } + } + + /* walk interfaces */ + if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_INTERFACES)) { + J9ITable *currentITable = (J9ITable *)defClass->iTable; + + while (NULL != currentITable) { + memset(&walkState, 0, sizeof(walkState)); + romField = romFieldsStartDo(currentITable->interfaceClass->romClass, &walkState); + while (NULL != romField) { + J9UTF8 *nameUTF = J9ROMFIELDSHAPE_NAME(romField); + J9UTF8 *signatureUTF = J9ROMFIELDSHAPE_SIGNATURE(romField); + if (((NULL == nameObject) || (0 != vmFuncs->compareStringToUTF8(currentThread, nameObject, FALSE, J9UTF8_DATA(nameUTF), J9UTF8_LENGTH(nameUTF)))) + && ((NULL != sigObject) && (0 == vmFuncs->compareStringToUTF8(currentThread, sigObject, FALSE, J9UTF8_DATA(signatureUTF), J9UTF8_LENGTH(signatureUTF)))) + ) { + if (skip > 0) { + skip -=1; + } else { + if (index < length) { + j9object_t memberName = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultsArray, index); + if (NULL == memberName) { + vmFuncs->internalExitVMToJNI(currentThread); + return -99; + } + j9object_t fieldObj = NULL; + if (romField->modifiers & J9AccStatic) { + /* create static field object */ + fieldObj = createFieldObject(currentThread, romField, defClass, nameUTF, signatureUTF, true); + } else { + /* create instance field object */ + fieldObj = createFieldObject(currentThread, romField, defClass, nameUTF, signatureUTF, false); + } + initImpl(currentThread, memberName, fieldObj); + } + } + result += 1; + } + romField = romFieldsNextDo(&walkState); + } + currentITable = currentITable->next; + } + } + } else if (J9_ARE_ANY_BITS_SET(matchFlags, MN_IS_CONSTRUCTOR | MN_IS_METHOD)) { + UDATA classDepth = 0; + if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_SUPERCLASSES)) { + /* walk superclasses */ + J9CLASS_DEPTH(defClass); + } + J9Class *currentClass = defClass; + + while (NULL != currentClass) { + if (!J9ROMCLASS_IS_PRIMITIVE_OR_ARRAY(currentClass->romClass)) { + J9Method *currentMethod = currentClass->ramMethods; + J9Method *endOfMethods = currentMethod + currentClass->romClass->romMethodCount; + while (currentMethod != endOfMethods) { + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod); + J9UTF8 *nameUTF = J9ROMMETHOD_SIGNATURE(romMethod); + J9UTF8 *signatureUTF = J9ROMMETHOD_SIGNATURE(romMethod); + if (((NULL == nameObject) || (0 != vmFuncs->compareStringToUTF8(currentThread, nameObject, FALSE, J9UTF8_DATA(nameUTF), J9UTF8_LENGTH(nameUTF)))) + && ((NULL != sigObject) && (0 == vmFuncs->compareStringToUTF8(currentThread, sigObject, FALSE, J9UTF8_DATA(signatureUTF), J9UTF8_LENGTH(signatureUTF)))) + ) { + if (skip > 0) { + skip -=1; + } else { + if (index < length) { + j9object_t memberName = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultsArray, index); + if (NULL == memberName) { + vmFuncs->internalExitVMToJNI(currentThread); + return -99; + } + j9object_t methodObj = NULL; + if (J9_ARE_NO_BITS_SET(romMethod->modifiers, J9AccStatic) && ('<' == (char)*J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)))) { + /* create constructor object */ + methodObj = vm->reflectFunctions.createConstructorObject(currentMethod, currentClass, NULL, currentThread); + } else { + /* create method object */ + methodObj = vm->reflectFunctions.createMethodObject(currentMethod, currentClass, NULL, currentThread); + } + initImpl(currentThread, memberName, methodObj); + } + } + result += 1; + } + currentMethod += 1; + } + } + + /* get the superclass */ + if (classDepth >= 1) { + classDepth -= 1; + currentClass = defClass->superclasses[classDepth]; + } else { + currentClass = NULL; + } + } + + /* walk interfaces */ + if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_INTERFACES)) { + J9ITable *currentITable = (J9ITable *)defClass->iTable; + + while (NULL != currentITable) { + J9Class *currentClass = currentITable->interfaceClass; + J9Method *currentMethod = currentClass->ramMethods; + J9Method *endOfMethods = currentMethod + currentClass->romClass->romMethodCount; + while (currentMethod != endOfMethods) { + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod); + J9UTF8 *nameUTF = J9ROMMETHOD_SIGNATURE(romMethod); + J9UTF8 *signatureUTF = J9ROMMETHOD_SIGNATURE(romMethod); + if (((NULL == nameObject) || (0 != vmFuncs->compareStringToUTF8(currentThread, nameObject, FALSE, J9UTF8_DATA(nameUTF), J9UTF8_LENGTH(nameUTF)))) + && ((NULL != sigObject) && (0 == vmFuncs->compareStringToUTF8(currentThread, sigObject, FALSE, J9UTF8_DATA(signatureUTF), J9UTF8_LENGTH(signatureUTF)))) + ) { + if (skip > 0) { + skip -=1; + } else { + if (index < length) { + j9object_t memberName = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultsArray, index); + if (NULL == memberName) { + vmFuncs->internalExitVMToJNI(currentThread); + return -99; + } + j9object_t methodObj = NULL; + if (J9_ARE_NO_BITS_SET(romMethod->modifiers, J9AccStatic) && ('<' == (char)*J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)))) { + /* create constructor object */ + methodObj = vm->reflectFunctions.createConstructorObject(currentMethod, currentClass, NULL, currentThread); + } else { + /* create method object */ + methodObj = vm->reflectFunctions.createMethodObject(currentMethod, currentClass, NULL, currentThread); + } + initImpl(currentThread, memberName, methodObj); + } + } + result += 1; + } + currentMethod += 1; + } + currentITable = currentITable->next; + } + } + } + } + } + } + } + Trc_JCL_java_lang_invoke_MethodHandleNatives_getMembers_Exit(env, result); + vmFuncs->internalExitVMToJNI(currentThread); + return result; +} + +/** + * static native long objectFieldOffset(MemberName self); // e.g., returns vmindex + */ +jlong JNICALL +Java_java_lang_invoke_MethodHandleNatives_objectFieldOffset(JNIEnv *env, jclass clazz, jobject self) +{ + J9VMThread *currentThread = (J9VMThread*)env; + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + vmFuncs->internalEnterVMFromJNI(currentThread); + jlong result = 0; + + Trc_JCL_java_lang_invoke_MethodHandleNatives_objectFieldOffset_Entry(env, self); + + if (NULL == self) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL); + } else { + j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + j9object_t clazzObject = J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject); + + if (NULL == clazzObject) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); + } else { + jint flags = J9VMJAVALANGINVOKEMEMBERNAME_FLAGS(currentThread, membernameObject); + if (J9_ARE_ALL_BITS_SET(flags, MN_IS_FIELD) && J9_ARE_NO_BITS_SET(flags, J9AccStatic)) { + J9JNIFieldID *fieldID = (J9JNIFieldID*)(UDATA)J9OBJECT_U64_LOAD(currentThread, membernameObject, vm->vmindexOffset); + result = (jlong)fieldID->offset + J9VMTHREAD_OBJECT_HEADER_SIZE(currentThread); + } else { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); + } + } + } + + Trc_JCL_java_lang_invoke_MethodHandleNatives_objectFieldOffset_Exit(env, result); + vmFuncs->internalExitVMToJNI(currentThread); + return result; +} + +/** + * static native long staticFieldOffset(MemberName self); // e.g., returns vmindex + */ +jlong JNICALL +Java_java_lang_invoke_MethodHandleNatives_staticFieldOffset(JNIEnv *env, jclass clazz, jobject self) +{ + J9VMThread *currentThread = (J9VMThread*)env; + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + vmFuncs->internalEnterVMFromJNI(currentThread); + jlong result = 0; + + Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldOffset_Entry(env, self); + + if (NULL == self) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL); + } else { + j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + j9object_t clazzObject = J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject); + + if (NULL == clazzObject) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); + } else { + jint flags = J9VMJAVALANGINVOKEMEMBERNAME_FLAGS(currentThread, membernameObject); + if (J9_ARE_ALL_BITS_SET(flags, MN_IS_FIELD & J9AccStatic)) { + result = (jlong)(UDATA)J9OBJECT_U64_LOAD(currentThread, membernameObject, vm->vmtargetOffset); + } else { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); + } + } + } + Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldOffset_Exit(env, result); + vmFuncs->internalExitVMToJNI(currentThread); + return result; +} + +/** + * static native Object staticFieldBase(MemberName self); // e.g., returns clazz + */ +jobject JNICALL +Java_java_lang_invoke_MethodHandleNatives_staticFieldBase(JNIEnv *env, jclass clazz, jobject self) +{ + J9VMThread *currentThread = (J9VMThread*)env; + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + vmFuncs->internalEnterVMFromJNI(currentThread); + jobject result = NULL; + + Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldBase_Entry(env, self); + if (NULL == self) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL); + } else { + j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + j9object_t clazzObject = J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject); + + if (NULL == clazzObject) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); + } else { + jint flags = J9VMJAVALANGINVOKEMEMBERNAME_FLAGS(currentThread, membernameObject); + if (J9_ARE_ALL_BITS_SET(flags, MN_IS_FIELD & J9AccStatic)) { + result = vmFuncs->j9jni_createLocalRef(env, clazzObject); + } else { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); + } + } + } + Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldBase_Exit(env, result); + vmFuncs->internalExitVMToJNI(currentThread); + return result; +} + +/** + * static native Object getMemberVMInfo(MemberName self); // returns {vmindex,vmtarget} + */ +jobject JNICALL +Java_java_lang_invoke_MethodHandleNatives_getMemberVMInfo(JNIEnv *env, jclass clazz, jobject self) +{ + J9VMThread *currentThread = (J9VMThread*)env; + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + jobject result = NULL; + vmFuncs->internalEnterVMFromJNI(currentThread); + + Trc_JCL_java_lang_invoke_MethodHandleNatives_getMemberVMInfo_Entry(env, self); + if (NULL != self) { + j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + j9object_t clazzObject = J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject); + jint flags = J9VMJAVALANGINVOKEMEMBERNAME_FLAGS(currentThread, membernameObject); + jlong vmindex = (jlong)(UDATA)J9OBJECT_U64_LOAD(currentThread, membernameObject, vm->vmindexOffset); + j9object_t target; + if (J9_ARE_ANY_BITS_SET(flags, MN_IS_FIELD)) { + vmindex = ((J9JNIFieldID*)vmindex)->offset; + target = clazzObject; + } else { + J9JNIMethodID *methodID = (J9JNIMethodID*)vmindex; + if (J9_ARE_ANY_BITS_SET(methodID->vTableIndex, J9_JNI_MID_INTERFACE)) { + vmindex = methodID->vTableIndex & ~J9_JNI_MID_INTERFACE; + } else if (0 == methodID->vTableIndex) { + vmindex = -1; + } else { + vmindex = methodID->vTableIndex; + } + target = membernameObject; + } + + j9object_t box = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGLONG_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + J9VMJAVALANGLONG_SET_VALUE(currentThread, box, vmindex); + + J9Class *arrayClass = fetchArrayClass(currentThread, J9VMJAVALANGOBJECT(vm)); + j9object_t arrayObject = vm->memoryManagerFunctions->J9AllocateIndexableObject(currentThread, arrayClass, 2, J9_GC_ALLOCATE_OBJECT_INSTRUMENTABLE); + J9JAVAARRAYOFOBJECT_STORE(currentThread, arrayObject, 0, box); + J9JAVAARRAYOFOBJECT_STORE(currentThread, arrayObject, 0, target); + + result = vmFuncs->j9jni_createLocalRef(env, clazzObject); + } + Trc_JCL_java_lang_invoke_MethodHandleNatives_getMemberVMInfo_Exit(env, result); + vmFuncs->internalExitVMToJNI(currentThread); + return result; + +} + +/** + * static native void setCallSiteTargetNormal(CallSite site, MethodHandle target) + */ +void JNICALL +Java_java_lang_invoke_MethodHandleNatives_setCallSiteTargetNormal(JNIEnv *env, jclass clazz, jobject callsite, jobject target) +{ + J9VMThread *currentThread = (J9VMThread*)env; + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + vmFuncs->internalEnterVMFromJNI(currentThread); + + if ((NULL == callsite) || (NULL == target)) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL); + } else { + j9object_t callsiteObject = J9_JNI_UNWRAP_REFERENCE(callsite); + j9object_t targetObject = J9_JNI_UNWRAP_REFERENCE(target); + + UDATA offset = (UDATA)vmFuncs->instanceFieldOffset(currentThread, J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, callsiteObject), (U_8*)"target", strlen("target"), (U_8*)"Ljava/lang/invoke/MethodHandle;", strlen("Ljava/lang/invoke/MethodHandle;"), NULL, NULL, 0); + MM_ObjectAccessBarrierAPI objectAccessBarrier = MM_ObjectAccessBarrierAPI(currentThread); + objectAccessBarrier.inlineMixedObjectStoreObject(currentThread, callsiteObject, offset, targetObject, false); + } + vmFuncs->internalExitVMToJNI(currentThread); +} + +/** + * static native void setCallSiteTargetVolatile(CallSite site, MethodHandle target); + */ +void JNICALL +Java_java_lang_invoke_MethodHandleNatives_setCallSiteTargetVolatile(JNIEnv *env, jclass clazz, jobject callsite, jobject target) +{ + J9VMThread *currentThread = (J9VMThread*)env; + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + vmFuncs->internalEnterVMFromJNI(currentThread); + + if ((NULL == callsite) || (NULL == target)) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL); + } else { + j9object_t callsiteObject = J9_JNI_UNWRAP_REFERENCE(callsite); + j9object_t targetObject = J9_JNI_UNWRAP_REFERENCE(target); + + UDATA offset = (UDATA)vmFuncs->instanceFieldOffset(currentThread, J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, callsiteObject), (U_8*)"target", strlen("target"), (U_8*)"Ljava/lang/invoke/MethodHandle;", strlen("Ljava/lang/invoke/MethodHandle;"), NULL, NULL, 0); + MM_ObjectAccessBarrierAPI objectAccessBarrier = MM_ObjectAccessBarrierAPI(currentThread); + objectAccessBarrier.inlineMixedObjectStoreObject(currentThread, callsiteObject, offset, targetObject, true); + } + vmFuncs->internalExitVMToJNI(currentThread); +} + +/** + * static native void copyOutBootstrapArguments(Class caller, int[] indexInfo, + int start, int end, + Object[] buf, int pos, + boolean resolve, + Object ifNotAvailable); + */ +void JNICALL +Java_java_lang_invoke_MethodHandleNatives_copyOutBootstrapArguments(JNIEnv *env, jclass clazz, jclass caller, jintArray indexInfo, jint start, jint end, jobjectArray buf, jint pos, jboolean resolve, jobject ifNotAvailable) +{ + J9VMThread *currentThread = (J9VMThread*)env; + J9JavaVM *vm = currentThread->javaVM; + J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + vmFuncs->internalEnterVMFromJNI(currentThread); + + if ((NULL == caller) || (NULL == indexInfo) || (NULL == buf)) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); + } else { + J9Class *callerClass = J9VM_J9CLASS_FROM_JCLASS(currentThread, caller); + j9array_t indexInfoArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(indexInfo); + j9array_t bufferArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(buf); + + if ((NULL == callerClass) || (NULL == indexInfoArray) || (NULL == bufferArray) || (J9INDEXABLEOBJECT_SIZE(currentThread, indexInfoArray) < 2)) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); + } else if (((start < -4) || (start > end) || (pos < 0)) || ((jint)J9INDEXABLEOBJECT_SIZE(currentThread, bufferArray) <= pos) || ((jint)J9INDEXABLEOBJECT_SIZE(currentThread, bufferArray) <= (pos + end - start))) { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGLINKAGEERROR, NULL); + } else { + // U_16 bsmArgCount = (U_16)J9JAVAARRAYOFINT_LOAD(currentThread, indexInfoArray, 0); + U_16 cpIndex = (U_16)J9JAVAARRAYOFINT_LOAD(currentThread, indexInfoArray, 1); + J9ROMClass *romClass = callerClass->romClass; + U_32 * cpShapeDescription = J9ROMCLASS_CPSHAPEDESCRIPTION(romClass); + if (J9_CP_TYPE(cpShapeDescription, cpIndex) == J9CPTYPE_CONSTANT_DYNAMIC) { + J9ROMConstantDynamicRef *romConstantRef = (J9ROMConstantDynamicRef*)(J9_ROM_CP_FROM_ROM_CLASS(romClass) + cpIndex); + J9SRP *callSiteData = (J9SRP *) J9ROMCLASS_CALLSITEDATA(romClass); + U_16 *bsmIndices = (U_16 *) (callSiteData + romClass->callSiteCount); + U_16 *bsmData = bsmIndices + romClass->callSiteCount; + + /* clear the J9DescriptionCpPrimitiveType flag with mask to get bsmIndex */ + U_32 bsmIndex = (romConstantRef->bsmIndexAndCpType >> J9DescriptionCpTypeShift) & J9DescriptionCpBsmIndexMask; + J9ROMNameAndSignature* nameAndSig = SRP_PTR_GET(&romConstantRef->nameAndSignature, J9ROMNameAndSignature*); + + /* Walk bsmData - skip all bootstrap methods before bsmIndex */ + for (U_32 i = 0; i < bsmIndex; i++) { + /* increment by size of bsm data plus header */ + bsmData += (bsmData[1] + 2); + } + + U_16 bsmCPIndex = bsmData[0]; + U_16 argCount = bsmData[1]; + bsmData += 2; + + j9object_t obj; + j9object_t ifNotAvailableObject = NULL; + if (NULL != ifNotAvailable) { + ifNotAvailableObject = J9_JNI_UNWRAP_REFERENCE(ifNotAvailable); + } + while (start < end) { + obj = NULL; + if (start >= 0) { + U_16 argIndex = bsmData[start]; + J9ConstantPool *ramConstantPool = J9_CP_FROM_CLASS(callerClass); + obj = resolveRefToObject(currentThread, ramConstantPool, argIndex, (JNI_TRUE == resolve)); + if ((NULL == obj) && (JNI_TRUE != resolve)) { + obj = ifNotAvailableObject; + } + } else if (start == -4) { + obj = resolveRefToObject(currentThread, J9_CP_FROM_CLASS(callerClass), bsmCPIndex, true); + } else if (start == -3) { + J9UTF8 *name = J9ROMNAMEANDSIGNATURE_NAME(nameAndSig); + obj = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(name), (U_32)J9UTF8_LENGTH(name), J9_STR_INTERN); + } else if (start == -2) { + J9UTF8 *signature = J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSig); + /* Call VM Entry point to create the MethodType - Result is put into the + * currentThread->returnValue as entry points don't "return" in the expected way + */ + vmFuncs->sendFromMethodDescriptorString(currentThread, signature, callerClass->classLoader, NULL); + obj = (j9object_t)currentThread->returnValue; + } else if (start == -1) { + obj = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGINTEGER_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + J9VMJAVALANGINTEGER_SET_VALUE(currentThread, obj, argCount); + } + J9JAVAARRAYOFOBJECT_STORE(currentThread, bufferArray, pos, obj); + start += 1; + pos += 1; + } + } else { + vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGLINKAGEERROR, NULL); + } + } + } + vmFuncs->internalExitVMToJNI(currentThread); +} + +/** + * private static native void clearCallSiteContext(CallSiteContext context); + */ +void JNICALL +Java_java_lang_invoke_MethodHandleNatives_clearCallSiteContext(JNIEnv *env, jclass clazz, jobject context) +{ + return; +} + +/** + * private static native int getNamedCon(int which, Object[] name); + */ +jint JNICALL +Java_java_lang_invoke_MethodHandleNatives_getNamedCon(JNIEnv *env, jclass clazz, jint which, jobjectArray name) +{ + return 0; +} + +/** + * private static native void registerNatives(); + */ +void JNICALL +Java_java_lang_invoke_MethodHandleNatives_registerNatives(JNIEnv *env, jclass clazz) +{ + return; +} + + +} /* extern "C" */ diff --git a/runtime/jcl/common/jclcinit.c b/runtime/jcl/common/jclcinit.c index 2760f15c1eb..95bdab3fafd 100644 --- a/runtime/jcl/common/jclcinit.c +++ b/runtime/jcl/common/jclcinit.c @@ -615,6 +615,17 @@ initializeRequiredClasses(J9VMThread *vmThread, char* dllName) return 1; } +#ifdef J9VM_OPT_OPENJDK_METHODHANDLE + if (0 != vmFuncs->addHiddenInstanceField(vm, "java/lang/invoke/MemberName", "vmindex", "J", &vm->vmindexOffset)) { + return 1; + } + + if (0 != vmFuncs->addHiddenInstanceField(vm, "java/lang/invoke/MemberName", "vmtarget", "J", &vm->vmtargetOffset)) { + return 1; + } +#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */ + + vmThread->privateFlags |= J9_PRIVATE_FLAGS_REPORT_ERROR_LOADING_CLASS; objectClass = vmFuncs->internalFindKnownClass(vmThread, J9VMCONSTANTPOOL_JAVALANGOBJECT, J9_FINDKNOWNCLASS_FLAG_NON_FATAL); diff --git a/runtime/jcl/exports.cmake b/runtime/jcl/exports.cmake index 961b42c897f..60536796c87 100644 --- a/runtime/jcl/exports.cmake +++ b/runtime/jcl/exports.cmake @@ -602,3 +602,23 @@ if(NOT JAVA_SPEC_VERSION LESS 16) Java_jdk_internal_vm_vector_VectorSupport_getMaxLaneCount ) endif() + +# OpenJDK methodhandle support +if(J9VM_OPT_OPENJDK_METHODHANDLE) + omr_add_exports(jclse + Java_java_lang_invoke_MethodHandleNatives_init + Java_java_lang_invoke_MethodHandleNatives_expand + Java_java_lang_invoke_MethodHandleNatives_resolve + Java_java_lang_invoke_MethodHandleNatives_getMembers + Java_java_lang_invoke_MethodHandleNatives_objectFieldOffset + Java_java_lang_invoke_MethodHandleNatives_staticFieldOffset + Java_java_lang_invoke_MethodHandleNatives_staticFieldBase + Java_java_lang_invoke_MethodHandleNatives_getMemberVMInfo + Java_java_lang_invoke_MethodHandleNatives_setCallSiteTargetNormal + Java_java_lang_invoke_MethodHandleNatives_setCallSiteTargetVolatile + Java_java_lang_invoke_MethodHandleNatives_copyOutBootstrapArguments + Java_java_lang_invoke_MethodHandleNatives_clearCallSiteContext + Java_java_lang_invoke_MethodHandleNatives_getNamedCon + Java_java_lang_invoke_MethodHandleNatives_registerNatives + ) +endif() diff --git a/runtime/jcl/j9jcl.tdf b/runtime/jcl/j9jcl.tdf index 7eb839f8aca..40d951798c9 100644 --- a/runtime/jcl/j9jcl.tdf +++ b/runtime/jcl/j9jcl.tdf @@ -644,3 +644,34 @@ TraceEntry=Trc_JCL_attach_closeSemaphoreEntry Overhead=1 Level=1 Template="Java_ TraceEntry=Trc_JCL_attach_destroySemaphoreEntry Overhead=1 Level=1 Template="Java_com_ibm_tools_attach_javaSE_IPC_destroySemaphoreImpl destroying semaphore (%p)" TraceEvent=Trc_JCL_init_nativeLibrariesLoadMethodID Overhead=1 Level=3 Template="init nativeLibrariesLoadMethodID (0x%zx)" + +TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setField Overhead=1 Level=3 Template="Set field MemberName: name=%.*s, signature=%.*s" +TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setData Overhead=1 Level=3 Template="Set MemberName data: flags=0x%08X, clazz=%p, vmindex=%ld, target=%ld" + +TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_init_Entry Overhead=1 Level=3 Template="MethodHandleNatives_init Enter: self = %p, ref = %p" +TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_init_Exit Overhead=1 Level=3 Template="MethodHandleNatives_init Exit" + +TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Entry Overhead=1 Level=3 Template="MethodHandleNatives_expand Enter: self = %p" +TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Data Overhead=1 Level=3 Template="MethodHandleNatives_expand Data: membername = %p, clazz = %p, name = %p, type = %p, flags = 0x%08X, vmindex = %ld" +TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Exit Overhead=1 Level=3 Template="MethodHandleNatives_expand Exit" + +TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Entry Overhead=1 Level=3 Template="MethodHandleNatives_resolve Enter: self = %p, caller = %p, speculativeResolve = %s" +TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Data Overhead=1 Level=3 Template="MethodHandleNatives_resolve Data: membername = %p, clazz = %p, caller = %p, name = %p, type = %p, flags = 0x%08X, vmindex = %ld, target = %ld" +TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_NAS Overhead=1 Level=3 Template="MethodHandleNatives_resolve NAS: name = %s, signature = %s" +TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_resolved Overhead=1 Level=3 Template="MethodHandleNatives_resolve Resolved to: vmindex = %ld, target = %ld, class = %p, flags = 0x%08X" +TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Exit Overhead=1 Level=3 Template="MethodHandleNatives_resolve Exit" + +TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_getMembers_Entry Overhead=1 Level=3 Template="MethodHandleNatives_getMembers Enter: defc = %p, matchName = %p, matchSig = %p, matchFlags = 0x%08X, caller = %p, skip = %d, results = %p" +TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_getMembers_Exit Overhead=1 Level=3 Template="MethodHandleNatives_getMembers Exit: result = %d" + +TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_objectFieldOffset_Entry Overhead=1 Level=3 Template="MethodHandleNatives_objectFieldOffset Enter: self = %p" +TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_objectFieldOffset_Exit Overhead=1 Level=3 Template="MethodHandleNatives_objectFieldOffset Exit: result = %ld" + +TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldOffset_Entry Overhead=1 Level=3 Template="MethodHandleNatives_staticFieldOffset Enter: self = %p" +TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldOffset_Exit Overhead=1 Level=3 Template="MethodHandleNatives_staticFieldOffset Exit: result = %ld" + +TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldBase_Entry Overhead=1 Level=3 Template="MethodHandleNatives_staticFieldBase Enter: self = %p" +TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldBase_Exit Overhead=1 Level=3 Template="MethodHandleNatives_staticFieldBase Exit: result = %p" + +TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_getMemberVMInfo_Entry Overhead=1 Level=3 Template="MethodHandleNatives_getMemberVMInfo Enter: self = %p" +TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_getMemberVMInfo_Exit Overhead=1 Level=3 Template="MethodHandleNatives_getMemberVMInfo Exit: result = %p" diff --git a/runtime/jcl/module.xml b/runtime/jcl/module.xml index bc325f7207c..bd2dac9a73e 100644 --- a/runtime/jcl/module.xml +++ b/runtime/jcl/module.xml @@ -22,6 +22,7 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-excepti --> + @@ -43,6 +44,7 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-excepti + @@ -80,6 +82,9 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-excepti + + + @@ -143,6 +148,9 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-excepti + + + diff --git a/runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_exports.xml b/runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_exports.xml new file mode 100644 index 00000000000..e42872e1f41 --- /dev/null +++ b/runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_exports.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + diff --git a/runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_objects.xml b/runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_objects.xml new file mode 100644 index 00000000000..f7deaf14f6d --- /dev/null +++ b/runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_objects.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index 2fcafdeea7a..6a89ec013d9 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -5388,6 +5388,10 @@ typedef struct J9JavaVM { U_32 minimumReservedRatio; U_32 cancelAbsoluteThreshold; U_32 minimumLearningRatio; +#ifdef J9VM_OPT_OPENJDK_METHODHANDLE + UDATA vmindexOffset; + UDATA vmtargetOffset; +#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */ } J9JavaVM; #define J9VM_PHASE_NOT_STARTUP 2 diff --git a/runtime/oti/jclprots.h b/runtime/oti/jclprots.h index 2d885e0d78a..4da081a617c 100644 --- a/runtime/oti/jclprots.h +++ b/runtime/oti/jclprots.h @@ -950,6 +950,22 @@ extern J9_CFUNC void JNICALL Java_java_lang_invoke_MethodHandleNatives_checkClassBytes(JNIEnv *env, jclass jlClass, jbyteArray classRep); #endif /* JAVA_SPEC_VERSION >= 15 */ +/* java_lang_invoke_MethodHandleNatives.cpp */ +void JNICALL Java_java_lang_invoke_MethodHandleNatives_init(JNIEnv *env, jclass clazz, jobject self, jobject ref); +void JNICALL Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobject self); +jobject JNICALL Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, jobject self, jclass caller, jboolean speculativeResolve); +jint JNICALL Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, jclass defc, jstring matchName, jstring matchSig, jint matchFlags, jclass caller, jint skip, jobjectArray results); +jlong JNICALL Java_java_lang_invoke_MethodHandleNatives_objectFieldOffset(JNIEnv *env, jclass clazz, jobject self); +jlong JNICALL Java_java_lang_invoke_MethodHandleNatives_staticFieldOffset(JNIEnv *env, jclass clazz, jobject self); +jobject JNICALL Java_java_lang_invoke_MethodHandleNatives_staticFieldBase(JNIEnv *env, jclass clazz, jobject self); +jobject JNICALL Java_java_lang_invoke_MethodHandleNatives_getMemberVMInfo(JNIEnv *env, jclass clazz, jobject self); +void JNICALL Java_java_lang_invoke_MethodHandleNatives_setCallSiteTargetNormal(JNIEnv *env, jclass clazz, jobject callsite, jobject target); +void JNICALL Java_java_lang_invoke_MethodHandleNatives_setCallSiteTargetVolatile(JNIEnv *env, jclass clazz, jobject callsite, jobject target); +void JNICALL Java_java_lang_invoke_MethodHandleNatives_copyOutBootstrapArguments(JNIEnv *env, jclass clazz, jclass caller, jintArray indexInfo, jint start, jint end, jobjectArray buf, jint pos, jboolean resolve, jobject ifNotAvailable); +void JNICALL Java_java_lang_invoke_MethodHandleNatives_clearCallSiteContext(JNIEnv *env, jclass clazz, jobject context); +jint JNICALL Java_java_lang_invoke_MethodHandleNatives_getNamedCon(JNIEnv *env, jclass clazz, jint which, jobjectArray name); +void JNICALL Java_java_lang_invoke_MethodHandleNatives_registerNatives(JNIEnv *env, jclass clazz); + /* java_lang_invoke_VarHandle.c */ #if defined(J9VM_OPT_METHOD_HANDLE) jlong JNICALL Java_java_lang_invoke_FieldVarHandle_lookupField(JNIEnv *env, jobject handle, jclass lookupClass, jstring name, jstring signature, jclass type, jboolean isStatic, jclass accessClass); From 4f80dd349cd6bbdf5010ccc7037960046521883b Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Tue, 24 Nov 2020 11:08:36 -0500 Subject: [PATCH 02/14] Add documentation for MethodHandleNatives native functions Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- .../java_lang_invoke_MethodHandleNatives.cpp | 102 +++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp index 4e03e25cde9..199e19b1a4a 100644 --- a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp +++ b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp @@ -40,6 +40,10 @@ extern "C" { +/* Constants mapped from java.lang.invoke.MethodHandleNatives$Constants + * These constants are validated by the MethodHandleNatives$Constants.verifyConstants() + * method when Java assertions are enabled + */ #define MN_IS_METHOD 0x00010000 #define MN_IS_CONSTRUCTOR 0x00020000 #define MN_IS_FIELD 0x00040000 @@ -47,11 +51,28 @@ extern "C" { #define MN_CALLER_SENSITIVE 0x00100000 #define MN_REFERENCE_KIND_SHIFT 24 -#define MN_REFERENCE_KIND_MASK 0xF +#define MN_REFERENCE_KIND_MASK 0xF /* (flag >> MN_REFERENCE_KIND_SHIFT) & MN_REFERENCE_KIND_MASK */ #define MN_SEARCH_SUPERCLASSES 0x00100000 #define MN_SEARCH_INTERFACES 0x00200000 +/* Private MemberName object init helper + * + * Set the MemberName fields based on the refObject given: + * For j.l.reflect.Field: + * find JNIFieldID for refObject, create j.l.String for name and signature and store in MN.name/type fields. + * set vmindex to the fieldID pointer and target to the J9ROMFieldShape struct. + * set MN.clazz to declaring class in the fieldID struct. + * For j.l.reflect.Method or j.l.reflect.Constructor: + * find JNIMethodID, set vmindex to the methodID pointer and target to the J9Method struct. + * set MN.clazz to the refObject's declaring class. + * + * Then for both, compute the MN.flags using access flags and invocation type based on the JNI-id. + * + * Throw an IllegalArgumentException if the refObject is not a Field/Method/Constructor + * + * Note: caller must have vmaccess before invoking this helper + */ void initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refObject) { @@ -530,6 +551,8 @@ J9Method * lookupMethod(J9VMThread *currentThread, J9Class *resolvedClass, J9JNINameAndSignature *nas, J9Class *callerClass, UDATA lookupOptions) { J9Method *result = NULL; + + /* If looking for a MethodHandle polymorphic INL method, allow any caller signature. */ if (resolvedClass == J9VMJAVALANGINVOKEMETHODHANDLE(currentThread->javaVM)) { if ((0 == strcmp(nas->name, "linkToVirtual")) || (0 == strcmp(nas->name, "linkToStatic")) @@ -553,6 +576,11 @@ lookupMethod(J9VMThread *currentThread, J9Class *resolvedClass, J9JNINameAndSign /** * static native void init(MemberName self, Object ref); + * + * Initializes a MemberName object using the given ref object. + * see initImpl for detail + * Throw NPE if self or ref is null + * Throw IllegalArgumentException if ref is not a field/method/constructor */ void JNICALL Java_java_lang_invoke_MethodHandleNatives_init(JNIEnv *env, jclass clazz, jobject self, jobject ref) @@ -577,6 +605,12 @@ Java_java_lang_invoke_MethodHandleNatives_init(JNIEnv *env, jclass clazz, jobjec /** * static native void expand(MemberName self); + * + * Given a MemberName object, try to set the uninitialized fields from existing values. + * + * Throws NullPointerException if MemberName object is null. + * Throws IllegalArgumentException if MemberName doesn't contain required data to expand. + * Throws InternalError if the MemberName object contains invalid data or completely uninitialized. */ void JNICALL Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobject self) @@ -599,13 +633,13 @@ Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobj Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Data(env, membernameObject, clazzObject, nameObject, typeObject, flags, vmindex); if (J9_ARE_ANY_BITS_SET(flags, MN_IS_FIELD)) { + /* For Field MemberName, the clazz and vmindex fields must be set. */ if ((NULL != clazzObject) && (NULL != (void*)vmindex)) { - // J9Class *declaringClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, clazzObject); - J9JNIFieldID *field = (J9JNIFieldID*)vmindex; J9UTF8 *name = J9ROMFIELDSHAPE_NAME(field->field); J9UTF8 *signature = J9ROMFIELDSHAPE_SIGNATURE(field->field); + /* if name/type field is uninitialized, create j.l.String from ROM field name/sig and store in MN fields. */ if (nameObject == NULL) { j9object_t nameString = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(name), (U_32)J9UTF8_LENGTH(name), J9_STR_INTERN); J9VMJAVALANGINVOKEMEMBERNAME_SET_NAME(currentThread, membernameObject, nameString); @@ -619,9 +653,11 @@ Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobj } } else if (J9_ARE_ANY_BITS_SET(flags, MN_IS_METHOD | MN_IS_CONSTRUCTOR)) { if (NULL != (void*)vmindex) { + /* For method/constructor MemberName, the vmindex field is required for expand.*/ J9JNIMethodID *methodID = (J9JNIMethodID*)vmindex; J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(methodID->method); + /* Retrieve method info using JNIMethodID, store to MN fields. */ if (clazzObject == NULL) { j9object_t newClassObject = J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_METHOD(methodID->method)); J9VMJAVALANGINVOKEMEMBERNAME_SET_CLAZZ(currentThread, membernameObject, newClassObject); @@ -650,6 +686,15 @@ Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobj /** * static native MemberName resolve(MemberName self, Class caller, * boolean speculativeResolve) throws LinkageError, ClassNotFoundException; + * + * Resolve the method/field represented by the MemberName using the supplied caller + * Store the resolved Method/Field's JNI-id in vmindex, field offset / method pointer in vmtarget + * + * If the speculativeResolve flag is not set, failed resolution will throw the corresponding exception. + * If the resolution failed with no exception: + * Throw NoSuchFieldError for field MemberName + * Throw NoSuchMethodError for method/constructor MemberName + * Throw LinkageError for other */ jobject JNICALL Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, jobject self, jclass caller, jboolean speculativeResolve) @@ -677,6 +722,7 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job j9object_t new_clazz = NULL; Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Data(env, membernameObject, clazzObject, callerObject, nameObject, typeObject, flags, vmindex, target); + /* Check if MemberName is already resolved */ if (0 != target) { result = self; } else { @@ -692,6 +738,12 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job UDATA signatureLength = 0; char *signature = NULL; J9Class *typeClass = J9OBJECT_CLAZZ(currentThread, typeObject); + + /* The type field of a MemberName could be in: + * MethodType: MethodType representing method/constructor MemberName's method signature + * String: String representing MemberName's signature (field or method) + * Class: Class representing field MemberName's field type + */ if (J9VMJAVALANGINVOKEMETHODTYPE(vm) == typeClass) { j9object_t sigString = J9VMJAVALANGINVOKEMETHODTYPE_METHODDESCRIPTOR(currentThread, typeObject); if (NULL != sigString) { @@ -730,6 +782,8 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job if (JNI_TRUE == speculativeResolve) { lookupOptions |= J9_LOOK_NO_THROW; } + + /* Determine the lookup type based on reference kind and resolved class flags */ switch (ref_kind) { case MH_REF_INVOKEINTERFACE: @@ -776,6 +830,10 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job lookupOptions |= J9_RESOLVE_FLAG_NO_THROW_ON_FAIL; } + /* MemberName doesn't differentiate if a field is static or not, + * the resolve code have to attempt to resolve as instance field first, + * then as static field if the first attempt failed. + */ offset = vmFuncs->instanceFieldOffset(currentThread, resolvedClass, (U_8*)name, strlen(name), @@ -870,6 +928,21 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job /** * static native int getMembers(Class defc, String matchName, String matchSig, * int matchFlags, Class caller, int skip, MemberName[] results); + * + * Search the defc (defining class) chain for field/method that matches the given search parameters, + * for each matching result found, initialize the next MemberName object in results array to reference the found field/method + * + * - defc: the class to start the search + * - matchName: name to match, NULL to match any field/method name + * - matchSig: signature to match, NULL to match any field/method type + * - matchFlags: flags defining search options: + * MN_IS_FIELD - search for fields + * MN_IS_CONSTRUCTOR | MN_IS_METHOD - search for method/constructor + * MN_SEARCH_SUPERCLASSES - search the superclasses of the defining class + * MN_SEARCH_INTERFACES - search the interfaces implemented by the defining class + * - caller: the caller class performing the lookup + * - skip: number of matching results to skip before storing + * - results: an array of MemberName objects to hold the matched field/method */ jint JNICALL Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, jclass defc, jstring matchName, jstring matchSig, jint matchFlags, jclass caller, jint skip, jobjectArray results) @@ -1105,6 +1178,9 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, /** * static native long objectFieldOffset(MemberName self); // e.g., returns vmindex + * + * Returns the objectFieldOffset of the field represented by the MemberName + * result should be same as if calling Unsafe.objectFieldOffset with the actual field object */ jlong JNICALL Java_java_lang_invoke_MethodHandleNatives_objectFieldOffset(JNIEnv *env, jclass clazz, jobject self) @@ -1143,6 +1219,9 @@ Java_java_lang_invoke_MethodHandleNatives_objectFieldOffset(JNIEnv *env, jclass /** * static native long staticFieldOffset(MemberName self); // e.g., returns vmindex + * + * Returns the staticFieldOffset of the field represented by the MemberName + * result should be same as if calling Unsafe.staticFieldOffset with the actual field object */ jlong JNICALL Java_java_lang_invoke_MethodHandleNatives_staticFieldOffset(JNIEnv *env, jclass clazz, jobject self) @@ -1179,6 +1258,9 @@ Java_java_lang_invoke_MethodHandleNatives_staticFieldOffset(JNIEnv *env, jclass /** * static native Object staticFieldBase(MemberName self); // e.g., returns clazz + * + * Returns the staticFieldBase of the field represented by the MemberName + * result should be same as if calling Unsafe.staticFieldBase with the actual field object */ jobject JNICALL Java_java_lang_invoke_MethodHandleNatives_staticFieldBase(JNIEnv *env, jclass clazz, jobject self) @@ -1214,6 +1296,12 @@ Java_java_lang_invoke_MethodHandleNatives_staticFieldBase(JNIEnv *env, jclass cl /** * static native Object getMemberVMInfo(MemberName self); // returns {vmindex,vmtarget} + * + * Return a 2-element java array containing the vm offset/target data + * For a field MemberName, array contains: + * (field offset, declaring class) + * For a method MemberName, array contains: + * (vtable index, MemberName object) */ jobject JNICALL Java_java_lang_invoke_MethodHandleNatives_getMemberVMInfo(JNIEnv *env, jclass clazz, jobject self) @@ -1367,6 +1455,14 @@ Java_java_lang_invoke_MethodHandleNatives_copyOutBootstrapArguments(JNIEnv *env, ifNotAvailableObject = J9_JNI_UNWRAP_REFERENCE(ifNotAvailable); } while (start < end) { + /* Copy the arguments between start and end to the buf array + * + * Negative start index refer to the mandatory arguments for a bootstrap method + * -4 -> Lookup + * -3 -> name (String) + * -2 -> signature (MethodType) + * -1 -> argCount of optional arguments + */ obj = NULL; if (start >= 0) { U_16 argIndex = bsmData[start]; From e1ac202b6514cf057e0ee93b8b72ffba76b2cb03 Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Thu, 10 Dec 2020 16:41:44 -0500 Subject: [PATCH 03/14] Fix indent in MethodHandleNatives_exports.xml Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- ...ang_invoke_MethodHandleNatives_exports.xml | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_exports.xml b/runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_exports.xml index e42872e1f41..a3ccdb0572a 100644 --- a/runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_exports.xml +++ b/runtime/jcl/uma/java_lang_invoke_MethodHandleNatives_exports.xml @@ -19,18 +19,18 @@ 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-exception --> - - - - - - - - - - - - - - + + + + + + + + + + + + + + From 4b3dc1e9f629a93c9504c8d173dbfd15e14f5e14 Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Tue, 24 Nov 2020 11:25:57 -0500 Subject: [PATCH 04/14] Update initImpl & fix formating - use reflect object's name/type/signature field instead of constructing new object - fill in name/signature for method/constructor rather than lazily computing during resolve - idFromReflectObject can't fail as long as the object is not null Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- .../java_lang_invoke_MethodHandleNatives.cpp | 81 ++++++++++--------- runtime/jcl/j9jcl.tdf | 3 +- 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp index 199e19b1a4a..af8c64800df 100644 --- a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp +++ b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp @@ -76,8 +76,8 @@ extern "C" { void initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refObject) { - J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9JavaVM *vm = currentThread->javaVM; + const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; J9Class* refClass = J9OBJECT_CLAZZ(currentThread, refObject); @@ -96,17 +96,11 @@ initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refO flags = fieldID->field->modifiers & CFR_FIELD_ACCESS_MASK; flags |= MN_IS_FIELD; flags |= (J9_ARE_ANY_BITS_SET(flags, J9AccStatic) ? MH_REF_GETSTATIC : MH_REF_GETFIELD) << MN_REFERENCE_KIND_SHIFT; - J9UTF8 *name = J9ROMFIELDSHAPE_NAME(fieldID->field); - J9UTF8 *signature = J9ROMFIELDSHAPE_SIGNATURE(fieldID->field); - nameObject = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(name), (U_32)J9UTF8_LENGTH(name), J9_STR_INTERN); - typeObject = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(signature), (U_32)J9UTF8_LENGTH(signature), J9_STR_INTERN); + nameObject = J9VMJAVALANGREFLECTFIELD_NAME(currentThread, refObject); + typeObject = J9VMJAVALANGREFLECTFIELD_TYPE(currentThread, refObject); clazzObject = J9VM_J9CLASS_TO_HEAPCLASS(fieldID->declaringClass); - - J9VMJAVALANGINVOKEMEMBERNAME_SET_NAME(currentThread, membernameObject, nameObject); - J9VMJAVALANGINVOKEMEMBERNAME_SET_TYPE(currentThread, membernameObject, typeObject); - Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setField(currentThread, (U_32)J9UTF8_LENGTH(name), J9UTF8_DATA(name), (U_32)J9UTF8_LENGTH(signature), J9UTF8_DATA(signature)); } else if (refClass == J9VMJAVALANGREFLECTMETHOD(vm)) { J9JNIMethodID *methodID = vm->reflectFunctions.idFromMethodObject(currentThread, refObject); vmindex = (jlong)methodID; @@ -126,6 +120,8 @@ initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refO flags |= MH_REF_INVOKEVIRTUAL << MN_REFERENCE_KIND_SHIFT; } + nameObject = J9VMJAVALANGREFLECTMETHOD_NAME(currentThread, refObject); + typeObject = J9VMJAVALANGREFLECTMETHOD_SIGNATURE(currentThread, refObject); clazzObject = J9VMJAVALANGREFLECTMETHOD_DECLARINGCLASS(currentThread, refObject); } else if (refClass == J9VMJAVALANGREFLECTCONSTRUCTOR(vm)) { J9JNIMethodID *methodID = vm->reflectFunctions.idFromConstructorObject(currentThread, refObject); @@ -137,6 +133,7 @@ initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refO flags = romMethod->modifiers & CFR_METHOD_ACCESS_MASK; flags |= MN_IS_CONSTRUCTOR | (MH_REF_INVOKESPECIAL << MN_REFERENCE_KIND_SHIFT); + typeObject = J9VMJAVALANGREFLECTCONSTRUCTOR_SIGNATURE(currentThread, refObject); clazzObject = J9VMJAVALANGREFLECTMETHOD_DECLARINGCLASS(currentThread, refObject); } else { vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGILLEGALARGUMENTEXCEPTION, NULL); @@ -144,10 +141,12 @@ initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refO if (!VM_VMHelpers::exceptionPending(currentThread)) { J9VMJAVALANGINVOKEMEMBERNAME_SET_FLAGS(currentThread, membernameObject, flags); + J9VMJAVALANGINVOKEMEMBERNAME_SET_NAME(currentThread, membernameObject, nameObject); + J9VMJAVALANGINVOKEMEMBERNAME_SET_TYPE(currentThread, membernameObject, typeObject); J9VMJAVALANGINVOKEMEMBERNAME_SET_CLAZZ(currentThread, membernameObject, clazzObject); J9OBJECT_U64_STORE(currentThread, membernameObject, vm->vmindexOffset, (U_64)vmindex); J9OBJECT_U64_STORE(currentThread, membernameObject, vm->vmtargetOffset, (U_64)target); - Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setData(currentThread, flags, clazzObject, vmindex, target); + Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setData(currentThread, flags, nameObject, typeObject, clazzObject, vmindex, target); } } @@ -155,28 +154,29 @@ static char * sigForPrimitiveOrVoid(J9JavaVM *vm, J9Class *clazz) { char result = 0; - if (clazz == vm->booleanReflectClass) + if (clazz == vm->booleanReflectClass) { result = 'Z'; - else if (clazz == vm->byteReflectClass) + } else if (clazz == vm->byteReflectClass) { result = 'B'; - else if (clazz == vm->charReflectClass) + } else if (clazz == vm->charReflectClass) { result = 'C'; - else if (clazz == vm->shortReflectClass) + } else if (clazz == vm->shortReflectClass) { result = 'S'; - else if (clazz == vm->intReflectClass) + } else if (clazz == vm->intReflectClass) { result = 'I'; - else if (clazz == vm->longReflectClass) + } else if (clazz == vm->longReflectClass) { result = 'J'; - else if (clazz == vm->floatReflectClass) + } else if (clazz == vm->floatReflectClass) { result = 'F'; - else if (clazz == vm->doubleReflectClass) + } else if (clazz == vm->doubleReflectClass) { result = 'D'; - else if (clazz == vm->voidReflectClass) + } else if (clazz == vm->voidReflectClass) { result = 'V'; + } - if (result) { + if (result != 0) { PORT_ACCESS_FROM_JAVAVM(vm); - char* signature = (char*)j9mem_allocate_memory(2 * sizeof(char*), OMRMEM_CATEGORY_VM); + char* signature = (char*)j9mem_allocate_memory(2, OMRMEM_CATEGORY_VM); signature[0] = result; signature[1] = '\0'; return signature; @@ -184,7 +184,7 @@ sigForPrimitiveOrVoid(J9JavaVM *vm, J9Class *clazz) return NULL; } -char * +static char * getClassSignature(J9VMThread *currentThread, J9Class * clazz) { PORT_ACCESS_FROM_JAVAVM(currentThread->javaVM); @@ -192,8 +192,7 @@ getClassSignature(J9VMThread *currentThread, J9Class * clazz) U_32 numDims = 0; J9Class * myClass = clazz; - while (J9ROMCLASS_IS_ARRAY(myClass->romClass)) - { + while (J9ROMCLASS_IS_ARRAY(myClass->romClass)) { J9Class * componentClass = (J9Class *)(((J9ArrayClass*)myClass)->componentType); if (J9ROMCLASS_IS_PRIMITIVE_TYPE(componentClass->romClass)) { break; @@ -201,26 +200,34 @@ getClassSignature(J9VMThread *currentThread, J9Class * clazz) numDims++; myClass = componentClass; } + J9UTF8 * romName = J9ROMCLASS_CLASSNAME(myClass->romClass); U_32 len = J9UTF8_LENGTH(romName); char * name = (char *)J9UTF8_DATA(romName); U_32 length = len + numDims; - if (* name != '[') + if (* name != '[') { length += 2; + } length++; //for null-termination char * sig = (char *)j9mem_allocate_memory(length, OMRMEM_CATEGORY_VM); U_32 i; - for (i = 0; i < numDims; i++) + for (i = 0; i < numDims; i++) { sig[i] = '['; - if (*name != '[') + } + + if (*name != '[') { sig[i++] = 'L'; + } + memcpy(sig+i, name, len); i += len; - if (*name != '[') - sig[i++] = ';'; + if (*name != '[') { + sig[i++] = ';'; + } sig[length-1] = '\0'; + return sig; } @@ -239,8 +246,9 @@ getSignatureFromMethodType(J9VMThread *currentThread, j9object_t typeObject, UDA j9object_t pObject = J9JAVAARRAYOFOBJECT_LOAD(currentThread, ptypes, i); J9Class *pclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, pObject); signatures[i] = sigForPrimitiveOrVoid(vm, pclass); - if (!signatures[i]) + if (!signatures[i]) { signatures[i] = getClassSignature(currentThread, pclass); + } *signatureLength += strlen(signatures[i]); } @@ -249,8 +257,9 @@ getSignatureFromMethodType(J9VMThread *currentThread, j9object_t typeObject, UDA j9object_t rtype = J9VMJAVALANGINVOKEMETHODTYPE_RTYPE(currentThread, typeObject); J9Class *rclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, rtype); char* rSignature = sigForPrimitiveOrVoid(vm, rclass); - if (!rSignature) + if (rSignature == NULL) { rSignature = getClassSignature(currentThread, rclass); + } *signatureLength += strlen(rSignature); @@ -355,14 +364,12 @@ createFieldFromID(struct J9VMThread *vmThread, J9JNIFieldID *j9FieldID) J9Class *typeClass = NULL; j9object_t fieldObject = NULL; J9Class *jlrFieldClass = J9VMJAVALANGREFLECTFIELD(vmThread->javaVM); - UDATA initStatus; if (NULL == jlrFieldClass) { return NULL; } - initStatus = jlrFieldClass->initializeStatus; - if (initStatus != J9ClassInitSucceeded && initStatus != (UDATA) vmThread) { + if (VM_VMHelpers::classRequiresInitialization(vmThread, jlrFieldClass)) { vmThread->javaVM->internalVMFunctions->initializeClass(vmThread, jlrFieldClass); if (vmThread->currentException != NULL) { return NULL; @@ -591,7 +598,7 @@ Java_java_lang_invoke_MethodHandleNatives_init(JNIEnv *env, jclass clazz, jobjec vmFuncs->internalEnterVMFromJNI(currentThread); Trc_JCL_java_lang_invoke_MethodHandleNatives_init_Entry(env, self, ref); - if (NULL == self || NULL == ref) { + if ((NULL == self) || (NULL == ref)) { vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL); } else { j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); @@ -729,7 +736,7 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job J9Class *resolvedClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, clazzObject); J9Class *callerClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, callerObject); - int ref_kind = (flags >> MN_REFERENCE_KIND_SHIFT) & MN_REFERENCE_KIND_MASK; + jint ref_kind = (flags >> MN_REFERENCE_KIND_SHIFT) & MN_REFERENCE_KIND_MASK; PORT_ACCESS_FROM_JAVAVM(vm); diff --git a/runtime/jcl/j9jcl.tdf b/runtime/jcl/j9jcl.tdf index 40d951798c9..5f10926247f 100644 --- a/runtime/jcl/j9jcl.tdf +++ b/runtime/jcl/j9jcl.tdf @@ -645,8 +645,7 @@ TraceEntry=Trc_JCL_attach_destroySemaphoreEntry Overhead=1 Level=1 Template="Jav TraceEvent=Trc_JCL_init_nativeLibrariesLoadMethodID Overhead=1 Level=3 Template="init nativeLibrariesLoadMethodID (0x%zx)" -TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setField Overhead=1 Level=3 Template="Set field MemberName: name=%.*s, signature=%.*s" -TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setData Overhead=1 Level=3 Template="Set MemberName data: flags=0x%08X, clazz=%p, vmindex=%ld, target=%ld" +TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setData Overhead=1 Level=3 Template="Set MemberName data: flags=0x%08X, name=%p, type=%p, clazz=%p, vmindex=%ld, target=%ld" TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_init_Entry Overhead=1 Level=3 Template="MethodHandleNatives_init Enter: self = %p, ref = %p" TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_init_Exit Overhead=1 Level=3 Template="MethodHandleNatives_init Exit" From 85aac41f29e06f29b656d898ebbaf5401b7518fe Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Tue, 8 Dec 2020 22:51:15 -0500 Subject: [PATCH 05/14] move createFieldObject to reflecthelp.c - expand reflectFunctions table - reflectFunctions->createFieldObject Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- .../java_lang_invoke_MethodHandleNatives.cpp | 190 +----------------- runtime/jcl/common/reflecthelp.c | 16 ++ runtime/oti/j9nonbuilder.h | 1 + 3 files changed, 21 insertions(+), 186 deletions(-) diff --git a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp index af8c64800df..edb5a0c57aa 100644 --- a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp +++ b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp @@ -282,188 +282,6 @@ getSignatureFromMethodType(J9VMThread *currentThread, j9object_t typeObject, UDA return methodDescriptor; } -static J9Class * -classForSignature(struct J9VMThread *vmThread, U_8 **sigDataPtr, struct J9ClassLoader *classLoader) -{ - U_8 *sigData = *sigDataPtr; - J9JavaVM *vm = vmThread->javaVM; - J9Class *clazz = NULL; - UDATA arity = 0; - U_8 c = 0; - UDATA i = 0; - - for (c = *sigData++; '[' == c; c = *sigData++) { - arity++; - } - - /* Non-array case */ - switch (c) { - case 'Q': - case 'L': { - /* object case */ - U_8 *tempData = sigData; - UDATA length = 0; - - /* find the signature length -> up to the ";" */ - while (';' != *sigData++) { - length++; - } - - /* find the class from the signature chunk */ - clazz = vm->internalVMFunctions->internalFindClassUTF8(vmThread, tempData, length, classLoader, J9_FINDCLASS_FLAG_THROW_ON_FAIL); - break; - } - case 'I': - clazz = vm->intReflectClass; - break; - case 'Z': - clazz = vm->booleanReflectClass; - break; - case 'J': - clazz = vm->longReflectClass; - break; -#if defined(J9VM_INTERP_FLOAT_SUPPORT) - case 'D': - clazz = vm->doubleReflectClass; - break; - case 'F': - clazz = vm->floatReflectClass; - break; -#endif - case 'C': - clazz = vm->charReflectClass; - break; - case 'B': - clazz = vm->byteReflectClass; - break; - case 'S': - clazz = vm->shortReflectClass; - break; - case 'V': - clazz = vm->voidReflectClass; - break; - } - - for (i = 0; (i < arity) && (NULL != clazz); i++) { - clazz = fetchArrayClass(vmThread, clazz); - } - - if (NULL != clazz) { - *sigDataPtr = sigData; - } - - return clazz; -} - -static j9object_t -createFieldFromID(struct J9VMThread *vmThread, J9JNIFieldID *j9FieldID) -{ - J9UTF8 *nameUTF = NULL; - j9object_t nameString = NULL; - U_8 *signatureData = NULL; - J9Class *typeClass = NULL; - j9object_t fieldObject = NULL; - J9Class *jlrFieldClass = J9VMJAVALANGREFLECTFIELD(vmThread->javaVM); - - if (NULL == jlrFieldClass) { - return NULL; - } - - if (VM_VMHelpers::classRequiresInitialization(vmThread, jlrFieldClass)) { - vmThread->javaVM->internalVMFunctions->initializeClass(vmThread, jlrFieldClass); - if (vmThread->currentException != NULL) { - return NULL; - } - } - - fieldObject = vmThread->javaVM->memoryManagerFunctions->J9AllocateObject(vmThread, jlrFieldClass, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); - if (NULL == fieldObject) { - vmThread->javaVM->internalVMFunctions->setHeapOutOfMemoryError(vmThread); - return NULL; - } - - PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, fieldObject); - - signatureData = J9UTF8_DATA(J9ROMFIELDSHAPE_SIGNATURE(j9FieldID->field)); - typeClass = classForSignature(vmThread, &signatureData, j9FieldID->declaringClass->classLoader); - if (NULL == typeClass) { - DROP_OBJECT_IN_SPECIAL_FRAME(vmThread); /* fieldObject */ - return NULL; - } - - fieldObject = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0); - J9VMJAVALANGREFLECTFIELD_SET_TYPE(vmThread, fieldObject, J9VM_J9CLASS_TO_HEAPCLASS(typeClass)); - - nameUTF = J9ROMFIELDSHAPE_NAME(j9FieldID->field); - nameString = vmThread->javaVM->memoryManagerFunctions->j9gc_createJavaLangString(vmThread, J9UTF8_DATA(nameUTF), (U_32) J9UTF8_LENGTH(nameUTF), J9_STR_INTERN); - if (NULL == nameString) { - DROP_OBJECT_IN_SPECIAL_FRAME(vmThread); /* fieldObject */ - return NULL; - } - - fieldObject = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0); - J9VMJAVALANGREFLECTFIELD_SET_NAME(vmThread, fieldObject, nameString); - - if (0 != (j9FieldID->field->modifiers & J9FieldFlagHasGenericSignature)) { - J9UTF8 *sigUTF = romFieldGenericSignature(j9FieldID->field); - j9object_t sigString = vmThread->javaVM->memoryManagerFunctions->j9gc_createJavaLangString(vmThread, J9UTF8_DATA(sigUTF), (U_32) J9UTF8_LENGTH(sigUTF), 0); - if (NULL == sigString) { - DROP_OBJECT_IN_SPECIAL_FRAME(vmThread); /* fieldObject */ - return NULL; - } - - fieldObject = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0); -#if defined(USE_SUN_REFLECT) - J9VMJAVALANGREFLECTFIELD_SET_SIGNATURE(vmThread, fieldObject, sigString); -#endif - } - - { - j9object_t byteArray = getFieldAnnotationData(vmThread, j9FieldID->declaringClass, j9FieldID); - if (NULL != vmThread->currentException) { - DROP_OBJECT_IN_SPECIAL_FRAME(vmThread); /* fieldObject */ - return NULL; - } - if (NULL != byteArray) { - fieldObject = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0); - J9VMJAVALANGREFLECTFIELD_SET_ANNOTATIONS(vmThread, fieldObject, byteArray); - } - } - - fieldObject = POP_OBJECT_IN_SPECIAL_FRAME(vmThread); - - /* Java 7 uses int field ID's to avoid modifying Sun JCL code */ - J9VMJAVALANGREFLECTFIELD_SET_INTFIELDID(vmThread, fieldObject, (U_32)(j9FieldID->index)); - - J9VMJAVALANGREFLECTFIELD_SET_DECLARINGCLASS(vmThread, fieldObject, J9VM_J9CLASS_TO_HEAPCLASS(j9FieldID->declaringClass)); -#if defined(USE_SUN_REFLECT) - J9VMJAVALANGREFLECTFIELD_SET_MODIFIERS(vmThread, fieldObject, j9FieldID->field->modifiers & CFR_FIELD_ACCESS_MASK); -#endif - - return fieldObject; -} - -j9object_t -createFieldObject(J9VMThread *currentThread, J9ROMFieldShape *romField, J9Class *declaringClass, J9UTF8 *name, J9UTF8 *sig, bool isStaticField) -{ - J9InternalVMFunctions *vmFuncs = currentThread->javaVM->internalVMFunctions; - - J9JNIFieldID *fieldID = NULL; - UDATA offset = 0; - UDATA inconsistentData = 0; - - if (isStaticField) { - offset = (UDATA)vmFuncs->staticFieldAddress(currentThread, declaringClass, J9UTF8_DATA(name), J9UTF8_LENGTH(name), J9UTF8_DATA(sig), J9UTF8_LENGTH(sig), NULL, NULL, 0, NULL); - offset -= (UDATA)declaringClass->ramStatics; - } else { - offset = vmFuncs->instanceFieldOffset(currentThread, declaringClass, J9UTF8_DATA(name), J9UTF8_LENGTH(name), J9UTF8_DATA(sig), J9UTF8_LENGTH(sig), NULL, NULL, 0); - } - - fieldID = vmFuncs->getJNIFieldID(currentThread, declaringClass, romField, offset, &inconsistentData); - - return createFieldFromID(currentThread, fieldID); -} - j9object_t resolveRefToObject(J9VMThread *currentThread, J9ConstantPool *ramConstantPool, U_16 cpIndex, bool resolve) { @@ -1015,10 +833,10 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, j9object_t fieldObj = NULL; if (romField->modifiers & J9AccStatic) { /* create static field object */ - fieldObj = createFieldObject(currentThread, romField, defClass, nameUTF, signatureUTF, true); + fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, true); } else { /* create instance field object */ - fieldObj = createFieldObject(currentThread, romField, defClass, nameUTF, signatureUTF, false); + fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, false); } initImpl(currentThread, memberName, fieldObj); } @@ -1062,10 +880,10 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, j9object_t fieldObj = NULL; if (romField->modifiers & J9AccStatic) { /* create static field object */ - fieldObj = createFieldObject(currentThread, romField, defClass, nameUTF, signatureUTF, true); + fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, true); } else { /* create instance field object */ - fieldObj = createFieldObject(currentThread, romField, defClass, nameUTF, signatureUTF, false); + fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, false); } initImpl(currentThread, memberName, fieldObj); } diff --git a/runtime/jcl/common/reflecthelp.c b/runtime/jcl/common/reflecthelp.c index 980078cb06d..560ca77e299 100644 --- a/runtime/jcl/common/reflecthelp.c +++ b/runtime/jcl/common/reflecthelp.c @@ -1133,6 +1133,21 @@ createStaticFieldObject(struct J9ROMFieldShape *romField, struct J9Class *declar return field; } +static j9object_t +createFieldObject(J9VMThread *vmThread, J9ROMFieldShape *romField, J9Class *declaringClass, bool isStaticField) +{ + UDATA inconsistentData = 0; + j9object_t field = NULL; + + if (isStaticField) { + field = createStaticFieldObject(romField, declaringClass, NULL, vmThread, &inconsistentData); + } else { + field = createInstanceFieldObject(romField, declaringClass, NULL, vmThread, &inconsistentData); + } + + return field; +} + static jfieldID reflectFieldToID(J9VMThread *vmThread, jobject reflectField) { @@ -1194,6 +1209,7 @@ initializeReflection(J9JavaVM *javaVM) reflectFunctions->idFromFieldObject = idFromFieldObject; reflectFunctions->idFromMethodObject = idFromMethodObject; reflectFunctions->idFromConstructorObject = idFromConstructorObject; + reflectFunctions->createFieldObject = createFieldObject; } /** diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index 6a89ec013d9..1e5083c3d28 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -4973,6 +4973,7 @@ typedef struct J9ReflectFunctionTable { struct J9JNIFieldID* ( *idFromFieldObject)(struct J9VMThread* vmStruct, j9object_t declaringClassObject, j9object_t fieldObject) ; struct J9JNIMethodID* ( *idFromMethodObject)(struct J9VMThread* vmStruct, j9object_t methodObject) ; struct J9JNIMethodID* ( *idFromConstructorObject)(struct J9VMThread* vmStruct, j9object_t constructorObject) ; + j9object_t ( *createFieldObject)(struct J9VMThread *vmThread, struct J9ROMFieldShape *romField, struct J9Class *declaringClass, bool isStaticField) ; } J9ReflectFunctionTable; /* @ddr_namespace: map_to_type=J9VMRuntimeStateListener */ From a39651b243d474c776c85997f4f50ab26f9e71b1 Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Wed, 9 Dec 2020 01:23:23 -0500 Subject: [PATCH 06/14] Add OOM check and check for CallerSensitive annotation - replace copyStringToUTF8Helper with copyStringToUTF8WithMemAlloc - add MN_CALLER_SENSITIVE check - add OOM checks and exit with goto - throw and handle nativeOOMError - fix all missing Error checking and refetch after any GC point - fix tracepoint modifiers - fix use of bool in c code - fix declaration skipped by goto Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- .../java_lang_invoke_MethodHandleNatives.cpp | 754 +++++++++++------- runtime/jcl/common/reflecthelp.c | 2 +- runtime/jcl/j9jcl.tdf | 12 +- runtime/oti/j9nonbuilder.h | 2 +- 4 files changed, 473 insertions(+), 297 deletions(-) diff --git a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp index edb5a0c57aa..1083895ce1a 100644 --- a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp +++ b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp @@ -76,7 +76,7 @@ extern "C" { void initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refObject) { - const J9JavaVM *vm = currentThread->javaVM; + J9JavaVM *vm = currentThread->javaVM; const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; J9Class* refClass = J9OBJECT_CLAZZ(currentThread, refObject); @@ -109,6 +109,9 @@ initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refO J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(methodID->method); flags = romMethod->modifiers & CFR_METHOD_ACCESS_MASK; + if (J9_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccMethodCallerSensitive)) { + flags |= MN_CALLER_SENSITIVE; + } flags |= MN_IS_METHOD; if (J9_ARE_ANY_BITS_SET(methodID->vTableIndex, J9_JNI_MID_INTERFACE)) { flags |= MH_REF_INVOKEINTERFACE << MN_REFERENCE_KIND_SHIFT; @@ -131,6 +134,9 @@ initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refO J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(methodID->method); flags = romMethod->modifiers & CFR_METHOD_ACCESS_MASK; + if (J9_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccMethodCallerSensitive)) { + flags |= MN_CALLER_SENSITIVE; + } flags |= MN_IS_CONSTRUCTOR | (MH_REF_INVOKESPECIAL << MN_REFERENCE_KIND_SHIFT); typeObject = J9VMJAVALANGREFLECTCONSTRUCTOR_SIGNATURE(currentThread, refObject); @@ -151,8 +157,9 @@ initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refO } static char * -sigForPrimitiveOrVoid(J9JavaVM *vm, J9Class *clazz) +sigForPrimitiveOrVoid(J9VMThread *currentThread, J9Class *clazz) { + J9JavaVM *vm = currentThread->javaVM; char result = 0; if (clazz == vm->booleanReflectClass) { result = 'Z'; @@ -177,9 +184,13 @@ sigForPrimitiveOrVoid(J9JavaVM *vm, J9Class *clazz) if (result != 0) { PORT_ACCESS_FROM_JAVAVM(vm); char* signature = (char*)j9mem_allocate_memory(2, OMRMEM_CATEGORY_VM); - signature[0] = result; - signature[1] = '\0'; - return signature; + if (NULL != signature) { + signature[0] = result; + signature[1] = '\0'; + return signature; + } else { + vm->internalVMFunctions->setNativeOutOfMemoryError(currentThread, 0, 0); + } } return NULL; } @@ -191,7 +202,7 @@ getClassSignature(J9VMThread *currentThread, J9Class * clazz) U_32 numDims = 0; - J9Class * myClass = clazz; + J9Class *myClass = clazz; while (J9ROMCLASS_IS_ARRAY(myClass->romClass)) { J9Class * componentClass = (J9Class *)(((J9ArrayClass*)myClass)->componentType); if (J9ROMCLASS_IS_PRIMITIVE_TYPE(componentClass->romClass)) { @@ -201,32 +212,36 @@ getClassSignature(J9VMThread *currentThread, J9Class * clazz) myClass = componentClass; } - J9UTF8 * romName = J9ROMCLASS_CLASSNAME(myClass->romClass); + J9UTF8 *romName = J9ROMCLASS_CLASSNAME(myClass->romClass); U_32 len = J9UTF8_LENGTH(romName); - char * name = (char *)J9UTF8_DATA(romName); + char * name = (char *)J9UTF8_DATA(romName); U_32 length = len + numDims; if (* name != '[') { length += 2; } - length++; //for null-termination + length++; /* for null-termination */ char * sig = (char *)j9mem_allocate_memory(length, OMRMEM_CATEGORY_VM); - U_32 i; - for (i = 0; i < numDims; i++) { - sig[i] = '['; - } + if (NULL == sig) { + currentThread->javaVM->internalVMFunctions->setNativeOutOfMemoryError(currentThread, 0, 0); + } else { + U_32 i; + for (i = 0; i < numDims; i++) { + sig[i] = '['; + } - if (*name != '[') { - sig[i++] = 'L'; - } + if (*name != '[') { + sig[i++] = 'L'; + } - memcpy(sig+i, name, len); - i += len; + memcpy(sig+i, name, len); + i += len; - if (*name != '[') { - sig[i++] = ';'; + if (*name != '[') { + sig[i++] = ';'; + } + sig[length-1] = '\0'; } - sig[length-1] = '\0'; return sig; } @@ -238,47 +253,85 @@ getSignatureFromMethodType(J9VMThread *currentThread, j9object_t typeObject, UDA j9object_t ptypes = J9VMJAVALANGINVOKEMETHODTYPE_PTYPES(currentThread, typeObject); U_32 numArgs = J9INDEXABLEOBJECT_SIZE(currentThread, ptypes); + char* methodDescriptor = NULL; + char* cursor = NULL; + char* rSignature = NULL; + PORT_ACCESS_FROM_JAVAVM(vm); - char** signatures = (char**)j9mem_allocate_memory((numArgs + 1) * sizeof(char*), OMRMEM_CATEGORY_VM); - *signatureLength = 2; //space for '(', ')' + char** signatures = (char**)j9mem_allocate_memory((numArgs) * sizeof(char*), OMRMEM_CATEGORY_VM); + if (NULL == signatures) { + vm->internalVMFunctions->setNativeOutOfMemoryError(currentThread, 0, 0); + goto done; + } + + *signatureLength = 2; /* space for '(', ')' */ for (U_32 i = 0; i < numArgs; i++) { j9object_t pObject = J9JAVAARRAYOFOBJECT_LOAD(currentThread, ptypes, i); J9Class *pclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, pObject); - signatures[i] = sigForPrimitiveOrVoid(vm, pclass); - if (!signatures[i]) { + signatures[i] = sigForPrimitiveOrVoid(currentThread, pclass); + if (VM_VMHelpers::exceptionPending(currentThread)) { + goto done; + } else if (NULL == signatures[i]) { signatures[i] = getClassSignature(currentThread, pclass); + if (VM_VMHelpers::exceptionPending(currentThread)) { + goto done; + } } *signatureLength += strlen(signatures[i]); } - // Return type - j9object_t rtype = J9VMJAVALANGINVOKEMETHODTYPE_RTYPE(currentThread, typeObject); - J9Class *rclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, rtype); - char* rSignature = sigForPrimitiveOrVoid(vm, rclass); - if (rSignature == NULL) { - rSignature = getClassSignature(currentThread, rclass); + { + /* Return type */ + j9object_t rtype = J9VMJAVALANGINVOKEMETHODTYPE_RTYPE(currentThread, typeObject); + J9Class *rclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, rtype); + rSignature = sigForPrimitiveOrVoid(currentThread, rclass); + if (VM_VMHelpers::exceptionPending(currentThread)) { + goto done; + } else if (rSignature == NULL) { + rSignature = getClassSignature(currentThread, rclass); + if (VM_VMHelpers::exceptionPending(currentThread)) { + goto done; + } + } } *signatureLength += strlen(rSignature); - char* methodDescriptor = (char*)j9mem_allocate_memory(*signatureLength+1, OMRMEM_CATEGORY_VM); - char* cursor = methodDescriptor; + methodDescriptor = (char*)j9mem_allocate_memory(*signatureLength+1, OMRMEM_CATEGORY_VM); + if (NULL == methodDescriptor) { + vm->internalVMFunctions->setNativeOutOfMemoryError(currentThread, 0, 0); + goto done; + } + cursor = methodDescriptor; *cursor++ = '('; - // Copy class signatures to descriptor string + /* Copy class signatures to descriptor string */ for (U_32 i = 0; i < numArgs; i++) { U_32 len = strlen(signatures[i]); strncpy(cursor, signatures[i], len); cursor += len; - j9mem_free_memory(signatures[i]); } *cursor++ = ')'; - // Copy return type signature to descriptor string + /* Copy return type signature to descriptor string */ strcpy(cursor, rSignature); - j9mem_free_memory(signatures); + +done: + if (NULL != rSignature) { + j9mem_free_memory(rSignature); + } + if (NULL != signatures) { + for (U_32 i = 0; i < numArgs; i++) { + if (NULL != signatures[i]) { + j9mem_free_memory(signatures[i]); + } else { + break; + } + } + j9mem_free_memory(signatures); + } return methodDescriptor; } @@ -286,7 +339,7 @@ j9object_t resolveRefToObject(J9VMThread *currentThread, J9ConstantPool *ramConstantPool, U_16 cpIndex, bool resolve) { J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; j9object_t result = NULL; @@ -316,12 +369,20 @@ resolveRefToObject(J9VMThread *currentThread, J9ConstantPool *ramConstantPool, U case J9CPTYPE_INT: { result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGINTEGER_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + if (NULL == result) { + vmFuncs->setHeapOutOfMemoryError(currentThread); + goto done; + } J9VMJAVALANGINTEGER_SET_VALUE(currentThread, result, ramCP->value); break; } case J9CPTYPE_FLOAT: { result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGFLOAT_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + if (NULL == result) { + vmFuncs->setHeapOutOfMemoryError(currentThread); + goto done; + } J9VMJAVALANGFLOAT_SET_VALUE(currentThread, result, ramCP->value); break; } @@ -331,6 +392,10 @@ resolveRefToObject(J9VMThread *currentThread, J9ConstantPool *ramConstantPool, U U_64 value = romCP->slot1; value = (value << 32) + romCP->slot2; result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGLONG_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + if (NULL == result) { + vmFuncs->setHeapOutOfMemoryError(currentThread); + goto done; + } J9VMJAVALANGLONG_SET_VALUE(currentThread, result, value); break; } @@ -340,6 +405,10 @@ resolveRefToObject(J9VMThread *currentThread, J9ConstantPool *ramConstantPool, U U_64 value = romCP->slot1; value = (value << 32) + romCP->slot2; result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGDOUBLE_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + if (NULL == result) { + vmFuncs->setHeapOutOfMemoryError(currentThread); + goto done; + } J9VMJAVALANGDOUBLE_SET_VALUE(currentThread, result, value); break; } @@ -368,7 +437,7 @@ resolveRefToObject(J9VMThread *currentThread, J9ConstantPool *ramConstantPool, U break; } } - +done: return result; } @@ -442,7 +511,7 @@ Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobj { J9VMThread *currentThread = (J9VMThread*)env; J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; vmFuncs->internalEnterVMFromJNI(currentThread); Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Entry(env, self); @@ -450,28 +519,33 @@ Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobj vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL); } else { j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); - j9object_t clazzObject = J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject); - j9object_t nameObject = J9VMJAVALANGINVOKEMEMBERNAME_NAME(currentThread, membernameObject); - j9object_t typeObject = J9VMJAVALANGINVOKEMEMBERNAME_TYPE(currentThread, membernameObject); jint flags = J9VMJAVALANGINVOKEMEMBERNAME_FLAGS(currentThread, membernameObject); jlong vmindex = (jlong)J9OBJECT_ADDRESS_LOAD(currentThread, membernameObject, vm->vmindexOffset); - Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Data(env, membernameObject, clazzObject, nameObject, typeObject, flags, vmindex); + Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Data(env, membernameObject, flags, vmindex); if (J9_ARE_ANY_BITS_SET(flags, MN_IS_FIELD)) { /* For Field MemberName, the clazz and vmindex fields must be set. */ - if ((NULL != clazzObject) && (NULL != (void*)vmindex)) { + if ((NULL != J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject)) && (NULL != (void*)vmindex)) { J9JNIFieldID *field = (J9JNIFieldID*)vmindex; - J9UTF8 *name = J9ROMFIELDSHAPE_NAME(field->field); - J9UTF8 *signature = J9ROMFIELDSHAPE_SIGNATURE(field->field); /* if name/type field is uninitialized, create j.l.String from ROM field name/sig and store in MN fields. */ - if (nameObject == NULL) { + if (NULL == J9VMJAVALANGINVOKEMEMBERNAME_NAME(currentThread, membernameObject)) { + J9UTF8 *name = J9ROMFIELDSHAPE_NAME(field->field); j9object_t nameString = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(name), (U_32)J9UTF8_LENGTH(name), J9_STR_INTERN); - J9VMJAVALANGINVOKEMEMBERNAME_SET_NAME(currentThread, membernameObject, nameString); + if (NULL != nameString) { + /* Refetch reference after GC point */ + membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + J9VMJAVALANGINVOKEMEMBERNAME_SET_NAME(currentThread, membernameObject, nameString); + } } - if (typeObject == NULL) { + if (NULL == J9VMJAVALANGINVOKEMEMBERNAME_TYPE(currentThread, membernameObject)) { + J9UTF8 *signature = J9ROMFIELDSHAPE_SIGNATURE(field->field); j9object_t signatureString = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(signature), (U_32)J9UTF8_LENGTH(signature), J9_STR_INTERN); - J9VMJAVALANGINVOKEMEMBERNAME_SET_TYPE(currentThread, membernameObject, signatureString); + if (NULL != signatureString) { + /* Refetch reference after GC point */ + membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + J9VMJAVALANGINVOKEMEMBERNAME_SET_TYPE(currentThread, membernameObject, signatureString); + } } } else { vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGILLEGALARGUMENTEXCEPTION, NULL); @@ -483,19 +557,27 @@ Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobj J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(methodID->method); /* Retrieve method info using JNIMethodID, store to MN fields. */ - if (clazzObject == NULL) { + if (NULL == J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject)) { j9object_t newClassObject = J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_METHOD(methodID->method)); J9VMJAVALANGINVOKEMEMBERNAME_SET_CLAZZ(currentThread, membernameObject, newClassObject); } - if (nameObject == NULL) { + if (NULL == J9VMJAVALANGINVOKEMEMBERNAME_NAME(currentThread, membernameObject)) { J9UTF8 *name = J9ROMMETHOD_NAME(romMethod); j9object_t nameString = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(name), (U_32)J9UTF8_LENGTH(name), J9_STR_INTERN); - J9VMJAVALANGINVOKEMEMBERNAME_SET_NAME(currentThread, membernameObject, nameString); + if (NULL != nameString) { + /* Refetch reference after GC point */ + membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + J9VMJAVALANGINVOKEMEMBERNAME_SET_NAME(currentThread, membernameObject, nameString); + } } - if (typeObject == NULL) { + if (NULL == J9VMJAVALANGINVOKEMEMBERNAME_TYPE(currentThread, membernameObject)) { J9UTF8 *signature = J9ROMMETHOD_SIGNATURE(romMethod); j9object_t signatureString = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(signature), (U_32)J9UTF8_LENGTH(signature), J9_STR_INTERN); - J9VMJAVALANGINVOKEMEMBERNAME_SET_TYPE(currentThread, membernameObject, signatureString); + if (NULL != signatureString) { + /* Refetch reference after GC point */ + membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + J9VMJAVALANGINVOKEMEMBERNAME_SET_TYPE(currentThread, membernameObject, signatureString); + } } } else { vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGILLEGALARGUMENTEXCEPTION, NULL); @@ -526,7 +608,7 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job { J9VMThread *currentThread = (J9VMThread*)env; J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; jobject result = NULL; vmFuncs->internalEnterVMFromJNI(currentThread); @@ -534,11 +616,7 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job if (NULL == self) { vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); } else { - j9object_t callerObject = (NULL == caller) ? NULL : J9_JNI_UNWRAP_REFERENCE(caller); j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); - j9object_t clazzObject = J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject); - j9object_t nameObject = J9VMJAVALANGINVOKEMEMBERNAME_NAME(currentThread, membernameObject); - j9object_t typeObject = J9VMJAVALANGINVOKEMEMBERNAME_TYPE(currentThread, membernameObject); jlong vmindex = (jlong)(UDATA)J9OBJECT_U64_LOAD(currentThread, membernameObject, vm->vmindexOffset); jlong target = (jlong)(UDATA)J9OBJECT_U64_LOAD(currentThread, membernameObject, vm->vmtargetOffset); @@ -546,20 +624,22 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job jint new_flags = 0; j9object_t new_clazz = NULL; - Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Data(env, membernameObject, clazzObject, callerObject, nameObject, typeObject, flags, vmindex, target); + Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Data(env, membernameObject, caller, flags, vmindex, target); /* Check if MemberName is already resolved */ if (0 != target) { result = self; } else { + /* Initialize nameObject after creating typeString which could trigger GC */ + j9object_t nameObject = NULL; + j9object_t typeObject = J9VMJAVALANGINVOKEMEMBERNAME_TYPE(currentThread, membernameObject); + j9object_t clazzObject = J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject); J9Class *resolvedClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, clazzObject); - J9Class *callerClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, callerObject); jint ref_kind = (flags >> MN_REFERENCE_KIND_SHIFT) & MN_REFERENCE_KIND_MASK; PORT_ACCESS_FROM_JAVAVM(vm); - - UDATA nameLength = vmFuncs->getStringUTF8Length(currentThread, nameObject) + 1; - char *name = (char*)j9mem_allocate_memory(nameLength, OMRMEM_CATEGORY_VM); + UDATA nameLength = 0; + char *name = NULL; UDATA signatureLength = 0; char *signature = NULL; J9Class *typeClass = J9OBJECT_CLAZZ(currentThread, typeObject); @@ -572,35 +652,50 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job if (J9VMJAVALANGINVOKEMETHODTYPE(vm) == typeClass) { j9object_t sigString = J9VMJAVALANGINVOKEMETHODTYPE_METHODDESCRIPTOR(currentThread, typeObject); if (NULL != sigString) { - signatureLength = vmFuncs->getStringUTF8Length(currentThread, sigString) + 1; - signature = (char*)j9mem_allocate_memory(signatureLength, OMRMEM_CATEGORY_VM); - vmFuncs->copyStringToUTF8Helper(currentThread, sigString, J9_STR_NULL_TERMINATE_RESULT | J9_STR_XLAT , 0, J9VMJAVALANGSTRING_LENGTH(currentThread, sigString), (U_8 *)signature, signatureLength); + signature = vmFuncs->copyStringToUTF8WithMemAlloc(currentThread, sigString, J9_STR_NULL_TERMINATE_RESULT | J9_STR_XLAT, "", 0, NULL, 0, &signatureLength); } else { signature = getSignatureFromMethodType(currentThread, typeObject, &signatureLength); + // TODO store this signature as j.l.String in MT } } else if (J9VMJAVALANGSTRING_OR_NULL(vm) == typeClass) { - signatureLength = vmFuncs->getStringUTF8Length(currentThread, typeObject) + 1; - signature = (char*)j9mem_allocate_memory(signatureLength, OMRMEM_CATEGORY_VM); - UDATA stringLength = J9VMJAVALANGSTRING_LENGTH(currentThread, typeObject); - vmFuncs->copyStringToUTF8Helper(currentThread, typeObject, J9_STR_NULL_TERMINATE_RESULT | J9_STR_XLAT , 0, stringLength, (U_8 *)signature, signatureLength); + signature = vmFuncs->copyStringToUTF8WithMemAlloc(currentThread, typeObject, J9_STR_NULL_TERMINATE_RESULT | J9_STR_XLAT, "", 0, NULL, 0, &signatureLength); } else if (J9VMJAVALANGCLASS(vm) == typeClass) { J9Class *rclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, typeObject); - signature = sigForPrimitiveOrVoid(vm, rclass); - if (!signature) { + signature = sigForPrimitiveOrVoid(currentThread, rclass); + if ((NULL == signature) && (!VM_VMHelpers::exceptionPending(currentThread))) { signature = getClassSignature(currentThread, rclass); } signatureLength = strlen(signature); } else { vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); - vmFuncs->internalExitVMToJNI(currentThread); - return NULL; + goto done; + } + + /* Check if signature string is correctly generated */ + if (NULL == signature) { + if (!VM_VMHelpers::exceptionPending(currentThread)) { + vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0); + } + goto done; + } + + /* Refetch reference after GC point */ + membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + nameObject = J9VMJAVALANGINVOKEMEMBERNAME_NAME(currentThread, membernameObject); + name = vmFuncs->copyStringToUTF8WithMemAlloc(currentThread, nameObject, J9_STR_NULL_TERMINATE_RESULT, "", 0, NULL, 0, &nameLength); + if (NULL == name) { + j9mem_free_memory(signature); + vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0); + goto done; } - vmFuncs->copyStringToUTF8Helper(currentThread, nameObject, J9_STR_NULL_TERMINATE_RESULT | J9_STR_XLAT , 0, J9VMJAVALANGSTRING_LENGTH(currentThread, nameObject), (U_8 *)name, nameLength); Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_NAS(env, name, signature); if (J9_ARE_ANY_BITS_SET(flags, MN_IS_METHOD | MN_IS_CONSTRUCTOR)) { + j9object_t callerObject = (NULL == caller) ? NULL : J9_JNI_UNWRAP_REFERENCE(caller); + J9Class *callerClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, callerObject); + J9JNINameAndSignature nas; UDATA lookupOptions = J9_LOOK_JNI; @@ -630,12 +725,17 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job nas.name = name; nas.signature = signature; - nas.nameLength = (U_32)strlen(name); - nas.signatureLength = (U_32)strlen(signature); + nas.nameLength = (U_32)nameLength; + nas.signatureLength = (U_32)signatureLength; /* Check if signature polymorphic native calls */ J9Method *method = lookupMethod(currentThread, resolvedClass, &nas, callerClass, lookupOptions); + /* Check for resolution exception */ + if (VM_VMHelpers::exceptionPending(currentThread)) { + goto done; + } + if (NULL != method) { J9JNIMethodID *methodID = vmFuncs->getJNIMethodID(currentThread, method); vmindex = (jlong)(UDATA)methodID; @@ -645,6 +745,9 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(methodID->method); new_flags = flags | (romMethod->modifiers & CFR_METHOD_ACCESS_MASK); + if (J9_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccMethodCallerSensitive)) { + new_flags |= MN_CALLER_SENSITIVE; + } } } if (J9_ARE_ANY_BITS_SET(flags, MN_IS_FIELD)) { J9Class *declaringClass; @@ -720,7 +823,11 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job } } + j9mem_free_memory(name); + j9mem_free_memory(signature); + if ((0 != vmindex) && (0 != target)) { + /* Refetch reference after GC point */ membernameObject = J9_JNI_UNWRAP_REFERENCE(self); J9VMJAVALANGINVOKEMEMBERNAME_SET_FLAGS(currentThread, membernameObject, new_flags); J9VMJAVALANGINVOKEMEMBERNAME_SET_CLAZZ(currentThread, membernameObject, new_clazz); @@ -731,8 +838,6 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job result = vmFuncs->j9jni_createLocalRef(env, membernameObject); } - j9mem_free_memory(name); - j9mem_free_memory(signature); if ((NULL == result) && (JNI_TRUE != speculativeResolve) && !VM_VMHelpers::exceptionPending(currentThread)) { if (J9_ARE_ANY_BITS_SET(flags, MN_IS_FIELD)) { @@ -745,6 +850,11 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job } } } + +done: + if ((JNI_TRUE == speculativeResolve) && VM_VMHelpers::exceptionPending(currentThread)) { + VM_VMHelpers::clearException(currentThread); + } Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Exit(env); vmFuncs->internalExitVMToJNI(currentThread); return result; @@ -774,61 +884,134 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, { J9VMThread *currentThread = (J9VMThread*)env; J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; vmFuncs->internalEnterVMFromJNI(currentThread); jint result = 0; + J9UTF8 *name = NULL; + J9UTF8 *sig = NULL; + j9object_t callerObject = ((NULL == caller) ? NULL : J9_JNI_UNWRAP_REFERENCE(caller)); + + PORT_ACCESS_FROM_JAVAVM(vm); Trc_JCL_java_lang_invoke_MethodHandleNatives_getMembers_Entry(env, defc, matchName, matchSig, matchFlags, caller, skip, results); - if ((NULL == defc) || (NULL == results)) { + if ((NULL == defc) || (NULL == results) || ((NULL != callerObject) && (J9VMJAVALANGCLASS(vm) != J9OBJECT_CLAZZ(currentThread, callerObject)))) { result = -1; } else { j9object_t defcObject = J9_JNI_UNWRAP_REFERENCE(defc); - j9array_t resultsArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(results); - j9object_t nameObject = ((NULL == matchName) ? NULL : J9_JNI_UNWRAP_REFERENCE(matchName)); - j9object_t sigObject = ((NULL == matchSig) ? NULL : J9_JNI_UNWRAP_REFERENCE(matchSig)); - // j9object_t callerObject = ((NULL == caller) ? NULL : J9_JNI_UNWRAP_REFERENCE(caller)); - - if (NULL == defcObject) { - result = -1; - } else if (!(((NULL != matchName) && (NULL == nameObject)) || ((NULL != matchSig) && (NULL == sigObject)))) { - J9Class *defClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, defcObject); + J9Class *defClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, defcObject); + + if (NULL != matchName) { + name = vmFuncs->copyStringToJ9UTF8WithMemAlloc(currentThread, J9_JNI_UNWRAP_REFERENCE(matchName), J9_STR_NONE, "", 0, NULL, 0); + if (NULL == name) { + vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0); + goto done; + } + } + if (NULL != matchSig) { + sig = vmFuncs->copyStringToJ9UTF8WithMemAlloc(currentThread, J9_JNI_UNWRAP_REFERENCE(matchSig), J9_STR_NONE, "", 0, NULL, 0); + if (NULL == sig) { + vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0); + goto done; + } + } + + if (!(((NULL != matchName) && (0 == J9UTF8_LENGTH(name))) || ((NULL != matchSig) && (0 == J9UTF8_LENGTH(sig))))) { + j9array_t resultsArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(results); UDATA length = J9INDEXABLEOBJECT_SIZE(currentThread, resultsArray); UDATA index = 0; - if (!((NULL != nameObject) && (0 == J9VMJAVALANGSTRING_LENGTH(currentThread, nameObject)))) { - if (J9ROMCLASS_IS_INTERFACE(defClass->romClass)) { - result = -1; - } else { - if (J9_ARE_ANY_BITS_SET(matchFlags, MN_IS_FIELD)) { - J9ROMFieldShape *romField = NULL; - J9ROMFieldWalkState walkState; - - UDATA classDepth = 0; - if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_SUPERCLASSES)) { - /* walk superclasses */ - J9CLASS_DEPTH(defClass); + + if (J9ROMCLASS_IS_INTERFACE(defClass->romClass)) { + result = -1; + } else { + if (J9_ARE_ANY_BITS_SET(matchFlags, MN_IS_FIELD)) { + J9ROMFieldShape *romField = NULL; + J9ROMFieldWalkState walkState; + + UDATA classDepth = 0; + if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_SUPERCLASSES)) { + /* walk superclasses */ + J9CLASS_DEPTH(defClass); + } + J9Class *currentClass = defClass; + + while (NULL != currentClass) { + /* walk currentClass */ + memset(&walkState, 0, sizeof(walkState)); + romField = romFieldsStartDo(currentClass->romClass, &walkState); + + while (NULL != romField) { + J9UTF8 *nameUTF = J9ROMFIELDSHAPE_NAME(romField); + J9UTF8 *signatureUTF = J9ROMFIELDSHAPE_SIGNATURE(romField); + + if (((NULL == matchName) || J9UTF8_EQUALS(name, nameUTF)) + && ((NULL == matchSig) || J9UTF8_EQUALS(sig, signatureUTF)) + ) { + if (skip > 0) { + skip -=1; + } else { + if (index < length) { + /* Refetch reference after GC point */ + resultsArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(results); + j9object_t memberName = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultsArray, index); + if (NULL == memberName) { + result = -99; + goto done; + } + j9object_t fieldObj = NULL; + if (romField->modifiers & J9AccStatic) { + /* create static field object */ + fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, TRUE); + } else { + /* create instance field object */ + fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, FALSE); + } + if (NULL != fieldObj) { + initImpl(currentThread, memberName, fieldObj); + } + if (VM_VMHelpers::exceptionPending(currentThread)) { + goto done; + } + } + } + result += 1; + } + romField = romFieldsNextDo(&walkState); } - J9Class *currentClass = defClass; - while (NULL != currentClass) { - /* walk currentClass */ - memset(&walkState, 0, sizeof(walkState)); - romField = romFieldsStartDo(currentClass->romClass, &walkState); + /* get the superclass */ + if (classDepth >= 1) { + classDepth -= 1; + currentClass = defClass->superclasses[classDepth]; + } else { + currentClass = NULL; + } + } + /* walk interfaces */ + if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_INTERFACES)) { + J9ITable *currentITable = (J9ITable *)defClass->iTable; + + while (NULL != currentITable) { + memset(&walkState, 0, sizeof(walkState)); + romField = romFieldsStartDo(currentITable->interfaceClass->romClass, &walkState); while (NULL != romField) { J9UTF8 *nameUTF = J9ROMFIELDSHAPE_NAME(romField); J9UTF8 *signatureUTF = J9ROMFIELDSHAPE_SIGNATURE(romField); - if (((NULL == nameObject) || (0 != vmFuncs->compareStringToUTF8(currentThread, nameObject, FALSE, J9UTF8_DATA(nameUTF), J9UTF8_LENGTH(nameUTF)))) - && ((NULL != sigObject) && (0 == vmFuncs->compareStringToUTF8(currentThread, sigObject, FALSE, J9UTF8_DATA(signatureUTF), J9UTF8_LENGTH(signatureUTF)))) + + if (((NULL == matchName) || J9UTF8_EQUALS(name, nameUTF)) + && ((NULL == matchSig) || J9UTF8_EQUALS(sig, signatureUTF)) ) { if (skip > 0) { skip -=1; } else { if (index < length) { + /* Refetch reference after GC point */ + resultsArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(results); j9object_t memberName = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultsArray, index); if (NULL == memberName) { - vmFuncs->internalExitVMToJNI(currentThread); - return -99; + result = -99; + goto done; } j9object_t fieldObj = NULL; if (romField->modifiers & J9AccStatic) { @@ -838,164 +1021,145 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, /* create instance field object */ fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, false); } - initImpl(currentThread, memberName, fieldObj); + if (NULL != fieldObj) { + initImpl(currentThread, memberName, fieldObj); + } + if (VM_VMHelpers::exceptionPending(currentThread)) { + goto done; + } } } result += 1; } romField = romFieldsNextDo(&walkState); } - - /* get the superclass */ - if (classDepth >= 1) { - classDepth -= 1; - currentClass = defClass->superclasses[classDepth]; - } else { - currentClass = NULL; - } + currentITable = currentITable->next; } - - /* walk interfaces */ - if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_INTERFACES)) { - J9ITable *currentITable = (J9ITable *)defClass->iTable; - - while (NULL != currentITable) { - memset(&walkState, 0, sizeof(walkState)); - romField = romFieldsStartDo(currentITable->interfaceClass->romClass, &walkState); - while (NULL != romField) { - J9UTF8 *nameUTF = J9ROMFIELDSHAPE_NAME(romField); - J9UTF8 *signatureUTF = J9ROMFIELDSHAPE_SIGNATURE(romField); - if (((NULL == nameObject) || (0 != vmFuncs->compareStringToUTF8(currentThread, nameObject, FALSE, J9UTF8_DATA(nameUTF), J9UTF8_LENGTH(nameUTF)))) - && ((NULL != sigObject) && (0 == vmFuncs->compareStringToUTF8(currentThread, sigObject, FALSE, J9UTF8_DATA(signatureUTF), J9UTF8_LENGTH(signatureUTF)))) - ) { - if (skip > 0) { - skip -=1; - } else { - if (index < length) { - j9object_t memberName = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultsArray, index); - if (NULL == memberName) { - vmFuncs->internalExitVMToJNI(currentThread); - return -99; - } - j9object_t fieldObj = NULL; - if (romField->modifiers & J9AccStatic) { - /* create static field object */ - fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, true); - } else { - /* create instance field object */ - fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, false); - } - initImpl(currentThread, memberName, fieldObj); + } + } else if (J9_ARE_ANY_BITS_SET(matchFlags, MN_IS_CONSTRUCTOR | MN_IS_METHOD)) { + UDATA classDepth = 0; + if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_SUPERCLASSES)) { + /* walk superclasses */ + J9CLASS_DEPTH(defClass); + } + J9Class *currentClass = defClass; + + while (NULL != currentClass) { + if (!J9ROMCLASS_IS_PRIMITIVE_OR_ARRAY(currentClass->romClass)) { + J9Method *currentMethod = currentClass->ramMethods; + J9Method *endOfMethods = currentMethod + currentClass->romClass->romMethodCount; + while (currentMethod != endOfMethods) { + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod); + J9UTF8 *nameUTF = J9ROMMETHOD_SIGNATURE(romMethod); + J9UTF8 *signatureUTF = J9ROMMETHOD_SIGNATURE(romMethod); + + if (((NULL == matchName) || J9UTF8_EQUALS(name, nameUTF)) + && ((NULL == matchSig) || J9UTF8_EQUALS(sig, signatureUTF)) + ) { + if (skip > 0) { + skip -=1; + } else { + if (index < length) { + /* Refetch reference after GC point */ + resultsArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(results); + j9object_t memberName = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultsArray, index); + if (NULL == memberName) { + result = -99; + goto done; } - } - result += 1; - } - romField = romFieldsNextDo(&walkState); - } - currentITable = currentITable->next; - } - } - } else if (J9_ARE_ANY_BITS_SET(matchFlags, MN_IS_CONSTRUCTOR | MN_IS_METHOD)) { - UDATA classDepth = 0; - if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_SUPERCLASSES)) { - /* walk superclasses */ - J9CLASS_DEPTH(defClass); - } - J9Class *currentClass = defClass; - - while (NULL != currentClass) { - if (!J9ROMCLASS_IS_PRIMITIVE_OR_ARRAY(currentClass->romClass)) { - J9Method *currentMethod = currentClass->ramMethods; - J9Method *endOfMethods = currentMethod + currentClass->romClass->romMethodCount; - while (currentMethod != endOfMethods) { - J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod); - J9UTF8 *nameUTF = J9ROMMETHOD_SIGNATURE(romMethod); - J9UTF8 *signatureUTF = J9ROMMETHOD_SIGNATURE(romMethod); - if (((NULL == nameObject) || (0 != vmFuncs->compareStringToUTF8(currentThread, nameObject, FALSE, J9UTF8_DATA(nameUTF), J9UTF8_LENGTH(nameUTF)))) - && ((NULL != sigObject) && (0 == vmFuncs->compareStringToUTF8(currentThread, sigObject, FALSE, J9UTF8_DATA(signatureUTF), J9UTF8_LENGTH(signatureUTF)))) - ) { - if (skip > 0) { - skip -=1; - } else { - if (index < length) { - j9object_t memberName = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultsArray, index); - if (NULL == memberName) { - vmFuncs->internalExitVMToJNI(currentThread); - return -99; - } - j9object_t methodObj = NULL; - if (J9_ARE_NO_BITS_SET(romMethod->modifiers, J9AccStatic) && ('<' == (char)*J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)))) { - /* create constructor object */ - methodObj = vm->reflectFunctions.createConstructorObject(currentMethod, currentClass, NULL, currentThread); - } else { - /* create method object */ - methodObj = vm->reflectFunctions.createMethodObject(currentMethod, currentClass, NULL, currentThread); - } + j9object_t methodObj = NULL; + if (J9_ARE_NO_BITS_SET(romMethod->modifiers, J9AccStatic) && ('<' == (char)*J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)))) { + /* create constructor object */ + methodObj = vm->reflectFunctions.createConstructorObject(currentMethod, currentClass, NULL, currentThread); + } else { + /* create method object */ + methodObj = vm->reflectFunctions.createMethodObject(currentMethod, currentClass, NULL, currentThread); + } + if (NULL != methodObj) { initImpl(currentThread, memberName, methodObj); } + if (VM_VMHelpers::exceptionPending(currentThread)) { + goto done; + } } - result += 1; } - currentMethod += 1; + result += 1; } + currentMethod += 1; } + } - /* get the superclass */ - if (classDepth >= 1) { - classDepth -= 1; - currentClass = defClass->superclasses[classDepth]; - } else { - currentClass = NULL; - } + /* get the superclass */ + if (classDepth >= 1) { + classDepth -= 1; + currentClass = defClass->superclasses[classDepth]; + } else { + currentClass = NULL; } + } - /* walk interfaces */ - if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_INTERFACES)) { - J9ITable *currentITable = (J9ITable *)defClass->iTable; - - while (NULL != currentITable) { - J9Class *currentClass = currentITable->interfaceClass; - J9Method *currentMethod = currentClass->ramMethods; - J9Method *endOfMethods = currentMethod + currentClass->romClass->romMethodCount; - while (currentMethod != endOfMethods) { - J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod); - J9UTF8 *nameUTF = J9ROMMETHOD_SIGNATURE(romMethod); - J9UTF8 *signatureUTF = J9ROMMETHOD_SIGNATURE(romMethod); - if (((NULL == nameObject) || (0 != vmFuncs->compareStringToUTF8(currentThread, nameObject, FALSE, J9UTF8_DATA(nameUTF), J9UTF8_LENGTH(nameUTF)))) - && ((NULL != sigObject) && (0 == vmFuncs->compareStringToUTF8(currentThread, sigObject, FALSE, J9UTF8_DATA(signatureUTF), J9UTF8_LENGTH(signatureUTF)))) - ) { - if (skip > 0) { - skip -=1; - } else { - if (index < length) { - j9object_t memberName = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultsArray, index); - if (NULL == memberName) { - vmFuncs->internalExitVMToJNI(currentThread); - return -99; - } - j9object_t methodObj = NULL; - if (J9_ARE_NO_BITS_SET(romMethod->modifiers, J9AccStatic) && ('<' == (char)*J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)))) { - /* create constructor object */ - methodObj = vm->reflectFunctions.createConstructorObject(currentMethod, currentClass, NULL, currentThread); - } else { - /* create method object */ - methodObj = vm->reflectFunctions.createMethodObject(currentMethod, currentClass, NULL, currentThread); - } + /* walk interfaces */ + if (J9_ARE_ANY_BITS_SET(matchFlags, MN_SEARCH_INTERFACES)) { + J9ITable *currentITable = (J9ITable *)defClass->iTable; + + while (NULL != currentITable) { + J9Class *currentClass = currentITable->interfaceClass; + J9Method *currentMethod = currentClass->ramMethods; + J9Method *endOfMethods = currentMethod + currentClass->romClass->romMethodCount; + while (currentMethod != endOfMethods) { + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod); + J9UTF8 *nameUTF = J9ROMMETHOD_SIGNATURE(romMethod); + J9UTF8 *signatureUTF = J9ROMMETHOD_SIGNATURE(romMethod); + + if (((NULL == matchName) || J9UTF8_EQUALS(name, nameUTF)) + && ((NULL == matchSig) || J9UTF8_EQUALS(sig, signatureUTF)) + ) { + if (skip > 0) { + skip -=1; + } else { + if (index < length) { + /* Refetch reference after GC point */ + resultsArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(results); + j9object_t memberName = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultsArray, index); + if (NULL == memberName) { + result = -99; + goto done; + } + j9object_t methodObj = NULL; + if (J9_ARE_NO_BITS_SET(romMethod->modifiers, J9AccStatic) && ('<' == (char)*J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)))) { + /* create constructor object */ + methodObj = vm->reflectFunctions.createConstructorObject(currentMethod, currentClass, NULL, currentThread); + } else { + /* create method object */ + methodObj = vm->reflectFunctions.createMethodObject(currentMethod, currentClass, NULL, currentThread); + } + if (NULL != methodObj) { initImpl(currentThread, memberName, methodObj); } + if (VM_VMHelpers::exceptionPending(currentThread)) { + goto done; + } } - result += 1; } - currentMethod += 1; + result += 1; } - currentITable = currentITable->next; + currentMethod += 1; } + currentITable = currentITable->next; } } } } } } +done: + if (NULL != name) { + j9mem_free_memory(name); + } + if (NULL != sig) { + j9mem_free_memory(sig); + } + Trc_JCL_java_lang_invoke_MethodHandleNatives_getMembers_Exit(env, result); vmFuncs->internalExitVMToJNI(currentThread); return result; @@ -1012,7 +1176,7 @@ Java_java_lang_invoke_MethodHandleNatives_objectFieldOffset(JNIEnv *env, jclass { J9VMThread *currentThread = (J9VMThread*)env; J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; vmFuncs->internalEnterVMFromJNI(currentThread); jlong result = 0; @@ -1053,7 +1217,7 @@ Java_java_lang_invoke_MethodHandleNatives_staticFieldOffset(JNIEnv *env, jclass { J9VMThread *currentThread = (J9VMThread*)env; J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; vmFuncs->internalEnterVMFromJNI(currentThread); jlong result = 0; @@ -1091,8 +1255,7 @@ jobject JNICALL Java_java_lang_invoke_MethodHandleNatives_staticFieldBase(JNIEnv *env, jclass clazz, jobject self) { J9VMThread *currentThread = (J9VMThread*)env; - J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9InternalVMFunctions *vmFuncs = currentThread->javaVM->internalVMFunctions; vmFuncs->internalEnterVMFromJNI(currentThread); jobject result = NULL; @@ -1133,41 +1296,51 @@ Java_java_lang_invoke_MethodHandleNatives_getMemberVMInfo(JNIEnv *env, jclass cl { J9VMThread *currentThread = (J9VMThread*)env; J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; jobject result = NULL; vmFuncs->internalEnterVMFromJNI(currentThread); Trc_JCL_java_lang_invoke_MethodHandleNatives_getMemberVMInfo_Entry(env, self); if (NULL != self) { - j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); - j9object_t clazzObject = J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject); - jint flags = J9VMJAVALANGINVOKEMEMBERNAME_FLAGS(currentThread, membernameObject); - jlong vmindex = (jlong)(UDATA)J9OBJECT_U64_LOAD(currentThread, membernameObject, vm->vmindexOffset); - j9object_t target; - if (J9_ARE_ANY_BITS_SET(flags, MN_IS_FIELD)) { - vmindex = ((J9JNIFieldID*)vmindex)->offset; - target = clazzObject; + J9Class *arrayClass = fetchArrayClass(currentThread, J9VMJAVALANGOBJECT(vm)); + j9object_t arrayObject = vm->memoryManagerFunctions->J9AllocateIndexableObject(currentThread, arrayClass, 2, J9_GC_ALLOCATE_OBJECT_INSTRUMENTABLE); + if (NULL == arrayObject) { + vmFuncs->setHeapOutOfMemoryError(currentThread); } else { - J9JNIMethodID *methodID = (J9JNIMethodID*)vmindex; - if (J9_ARE_ANY_BITS_SET(methodID->vTableIndex, J9_JNI_MID_INTERFACE)) { - vmindex = methodID->vTableIndex & ~J9_JNI_MID_INTERFACE; - } else if (0 == methodID->vTableIndex) { - vmindex = -1; + PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, arrayObject); + j9object_t box = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGLONG_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + if (NULL == box) { + /* Drop arrayObject */ + DROP_OBJECT_IN_SPECIAL_FRAME(currentThread); + vmFuncs->setHeapOutOfMemoryError(currentThread); } else { - vmindex = methodID->vTableIndex; - } - target = membernameObject; - } - - j9object_t box = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGLONG_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); - J9VMJAVALANGLONG_SET_VALUE(currentThread, box, vmindex); + arrayObject = POP_OBJECT_IN_SPECIAL_FRAME(currentThread); + j9object_t membernameObject = J9_JNI_UNWRAP_REFERENCE(self); + jint flags = J9VMJAVALANGINVOKEMEMBERNAME_FLAGS(currentThread, membernameObject); + jlong vmindex = (jlong)(UDATA)J9OBJECT_U64_LOAD(currentThread, membernameObject, vm->vmindexOffset); + j9object_t target; + if (J9_ARE_ANY_BITS_SET(flags, MN_IS_FIELD)) { + vmindex = ((J9JNIFieldID*)vmindex)->offset; + target = J9VMJAVALANGINVOKEMEMBERNAME_CLAZZ(currentThread, membernameObject); + } else { + J9JNIMethodID *methodID = (J9JNIMethodID*)vmindex; + if (J9_ARE_ANY_BITS_SET(methodID->vTableIndex, J9_JNI_MID_INTERFACE)) { + vmindex = methodID->vTableIndex & ~J9_JNI_MID_INTERFACE; + } else if (0 == methodID->vTableIndex) { + vmindex = -1; + } else { + vmindex = methodID->vTableIndex; + } + target = membernameObject; + } - J9Class *arrayClass = fetchArrayClass(currentThread, J9VMJAVALANGOBJECT(vm)); - j9object_t arrayObject = vm->memoryManagerFunctions->J9AllocateIndexableObject(currentThread, arrayClass, 2, J9_GC_ALLOCATE_OBJECT_INSTRUMENTABLE); - J9JAVAARRAYOFOBJECT_STORE(currentThread, arrayObject, 0, box); - J9JAVAARRAYOFOBJECT_STORE(currentThread, arrayObject, 0, target); + J9VMJAVALANGLONG_SET_VALUE(currentThread, box, vmindex); + J9JAVAARRAYOFOBJECT_STORE(currentThread, arrayObject, 0, box); + J9JAVAARRAYOFOBJECT_STORE(currentThread, arrayObject, 0, target); - result = vmFuncs->j9jni_createLocalRef(env, clazzObject); + result = vmFuncs->j9jni_createLocalRef(env, arrayObject); + } + } } Trc_JCL_java_lang_invoke_MethodHandleNatives_getMemberVMInfo_Exit(env, result); vmFuncs->internalExitVMToJNI(currentThread); @@ -1182,8 +1355,7 @@ void JNICALL Java_java_lang_invoke_MethodHandleNatives_setCallSiteTargetNormal(JNIEnv *env, jclass clazz, jobject callsite, jobject target) { J9VMThread *currentThread = (J9VMThread*)env; - J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9InternalVMFunctions *vmFuncs = currentThread->javaVM->internalVMFunctions; vmFuncs->internalEnterVMFromJNI(currentThread); if ((NULL == callsite) || (NULL == target)) { @@ -1206,8 +1378,7 @@ void JNICALL Java_java_lang_invoke_MethodHandleNatives_setCallSiteTargetVolatile(JNIEnv *env, jclass clazz, jobject callsite, jobject target) { J9VMThread *currentThread = (J9VMThread*)env; - J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9InternalVMFunctions *vmFuncs = currentThread->javaVM->internalVMFunctions; vmFuncs->internalEnterVMFromJNI(currentThread); if ((NULL == callsite) || (NULL == target)) { @@ -1235,7 +1406,7 @@ Java_java_lang_invoke_MethodHandleNatives_copyOutBootstrapArguments(JNIEnv *env, { J9VMThread *currentThread = (J9VMThread*)env; J9JavaVM *vm = currentThread->javaVM; - J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; + const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; vmFuncs->internalEnterVMFromJNI(currentThread); if ((NULL == caller) || (NULL == indexInfo) || (NULL == buf)) { @@ -1245,12 +1416,12 @@ Java_java_lang_invoke_MethodHandleNatives_copyOutBootstrapArguments(JNIEnv *env, j9array_t indexInfoArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(indexInfo); j9array_t bufferArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(buf); - if ((NULL == callerClass) || (NULL == indexInfoArray) || (NULL == bufferArray) || (J9INDEXABLEOBJECT_SIZE(currentThread, indexInfoArray) < 2)) { + if ((J9INDEXABLEOBJECT_SIZE(currentThread, indexInfoArray) < 2)) { vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); } else if (((start < -4) || (start > end) || (pos < 0)) || ((jint)J9INDEXABLEOBJECT_SIZE(currentThread, bufferArray) <= pos) || ((jint)J9INDEXABLEOBJECT_SIZE(currentThread, bufferArray) <= (pos + end - start))) { vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGLINKAGEERROR, NULL); } else { - // U_16 bsmArgCount = (U_16)J9JAVAARRAYOFINT_LOAD(currentThread, indexInfoArray, 0); + /* U_16 bsmArgCount = (U_16)J9JAVAARRAYOFINT_LOAD(currentThread, indexInfoArray, 0); */ U_16 cpIndex = (U_16)J9JAVAARRAYOFINT_LOAD(currentThread, indexInfoArray, 1); J9ROMClass *romClass = callerClass->romClass; U_32 * cpShapeDescription = J9ROMCLASS_CPSHAPEDESCRIPTION(romClass); @@ -1274,11 +1445,6 @@ Java_java_lang_invoke_MethodHandleNatives_copyOutBootstrapArguments(JNIEnv *env, U_16 argCount = bsmData[1]; bsmData += 2; - j9object_t obj; - j9object_t ifNotAvailableObject = NULL; - if (NULL != ifNotAvailable) { - ifNotAvailableObject = J9_JNI_UNWRAP_REFERENCE(ifNotAvailable); - } while (start < end) { /* Copy the arguments between start and end to the buf array * @@ -1288,13 +1454,13 @@ Java_java_lang_invoke_MethodHandleNatives_copyOutBootstrapArguments(JNIEnv *env, * -2 -> signature (MethodType) * -1 -> argCount of optional arguments */ - obj = NULL; + j9object_t obj = NULL; if (start >= 0) { U_16 argIndex = bsmData[start]; J9ConstantPool *ramConstantPool = J9_CP_FROM_CLASS(callerClass); obj = resolveRefToObject(currentThread, ramConstantPool, argIndex, (JNI_TRUE == resolve)); - if ((NULL == obj) && (JNI_TRUE != resolve)) { - obj = ifNotAvailableObject; + if ((NULL == obj) && (JNI_TRUE != resolve) && (NULL != ifNotAvailable)) { + obj = J9_JNI_UNWRAP_REFERENCE(ifNotAvailable); } } else if (start == -4) { obj = resolveRefToObject(currentThread, J9_CP_FROM_CLASS(callerClass), bsmCPIndex, true); @@ -1310,8 +1476,17 @@ Java_java_lang_invoke_MethodHandleNatives_copyOutBootstrapArguments(JNIEnv *env, obj = (j9object_t)currentThread->returnValue; } else if (start == -1) { obj = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGINTEGER_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); - J9VMJAVALANGINTEGER_SET_VALUE(currentThread, obj, argCount); + if (NULL == obj) { + vmFuncs->setHeapOutOfMemoryError(currentThread); + } else { + J9VMJAVALANGINTEGER_SET_VALUE(currentThread, obj, argCount); + } + } + if (VM_VMHelpers::exceptionPending(currentThread)) { + goto done; } + /* Refetch reference after GC point */ + bufferArray = (j9array_t)J9_JNI_UNWRAP_REFERENCE(buf); J9JAVAARRAYOFOBJECT_STORE(currentThread, bufferArray, pos, obj); start += 1; pos += 1; @@ -1321,6 +1496,7 @@ Java_java_lang_invoke_MethodHandleNatives_copyOutBootstrapArguments(JNIEnv *env, } } } +done: vmFuncs->internalExitVMToJNI(currentThread); } diff --git a/runtime/jcl/common/reflecthelp.c b/runtime/jcl/common/reflecthelp.c index 560ca77e299..b33379feee9 100644 --- a/runtime/jcl/common/reflecthelp.c +++ b/runtime/jcl/common/reflecthelp.c @@ -1134,7 +1134,7 @@ createStaticFieldObject(struct J9ROMFieldShape *romField, struct J9Class *declar } static j9object_t -createFieldObject(J9VMThread *vmThread, J9ROMFieldShape *romField, J9Class *declaringClass, bool isStaticField) +createFieldObject(J9VMThread *vmThread, J9ROMFieldShape *romField, J9Class *declaringClass, BOOLEAN isStaticField) { UDATA inconsistentData = 0; j9object_t field = NULL; diff --git a/runtime/jcl/j9jcl.tdf b/runtime/jcl/j9jcl.tdf index 5f10926247f..e337acb5028 100644 --- a/runtime/jcl/j9jcl.tdf +++ b/runtime/jcl/j9jcl.tdf @@ -645,29 +645,29 @@ TraceEntry=Trc_JCL_attach_destroySemaphoreEntry Overhead=1 Level=1 Template="Jav TraceEvent=Trc_JCL_init_nativeLibrariesLoadMethodID Overhead=1 Level=3 Template="init nativeLibrariesLoadMethodID (0x%zx)" -TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setData Overhead=1 Level=3 Template="Set MemberName data: flags=0x%08X, name=%p, type=%p, clazz=%p, vmindex=%ld, target=%ld" +TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_initImpl_setData Overhead=1 Level=3 Template="Set MemberName data: flags=0x%08X, name=%p, type=%p, clazz=%p, vmindex=%lld, target=%lld" TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_init_Entry Overhead=1 Level=3 Template="MethodHandleNatives_init Enter: self = %p, ref = %p" TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_init_Exit Overhead=1 Level=3 Template="MethodHandleNatives_init Exit" TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Entry Overhead=1 Level=3 Template="MethodHandleNatives_expand Enter: self = %p" -TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Data Overhead=1 Level=3 Template="MethodHandleNatives_expand Data: membername = %p, clazz = %p, name = %p, type = %p, flags = 0x%08X, vmindex = %ld" +TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Data Overhead=1 Level=3 Template="MethodHandleNatives_expand Data: membername = %p, flags = 0x%08X, vmindex = %lld" TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_expand_Exit Overhead=1 Level=3 Template="MethodHandleNatives_expand Exit" TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Entry Overhead=1 Level=3 Template="MethodHandleNatives_resolve Enter: self = %p, caller = %p, speculativeResolve = %s" -TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Data Overhead=1 Level=3 Template="MethodHandleNatives_resolve Data: membername = %p, clazz = %p, caller = %p, name = %p, type = %p, flags = 0x%08X, vmindex = %ld, target = %ld" +TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Data Overhead=1 Level=3 Template="MethodHandleNatives_resolve Data: membername = %p, caller = %p, flags = 0x%08X, vmindex = %lld, target = %lld" TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_NAS Overhead=1 Level=3 Template="MethodHandleNatives_resolve NAS: name = %s, signature = %s" -TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_resolved Overhead=1 Level=3 Template="MethodHandleNatives_resolve Resolved to: vmindex = %ld, target = %ld, class = %p, flags = 0x%08X" +TraceEvent=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_resolved Overhead=1 Level=3 Template="MethodHandleNatives_resolve Resolved to: vmindex = %lld, target = %lld, class = %p, flags = 0x%08X" TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_resolve_Exit Overhead=1 Level=3 Template="MethodHandleNatives_resolve Exit" TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_getMembers_Entry Overhead=1 Level=3 Template="MethodHandleNatives_getMembers Enter: defc = %p, matchName = %p, matchSig = %p, matchFlags = 0x%08X, caller = %p, skip = %d, results = %p" TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_getMembers_Exit Overhead=1 Level=3 Template="MethodHandleNatives_getMembers Exit: result = %d" TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_objectFieldOffset_Entry Overhead=1 Level=3 Template="MethodHandleNatives_objectFieldOffset Enter: self = %p" -TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_objectFieldOffset_Exit Overhead=1 Level=3 Template="MethodHandleNatives_objectFieldOffset Exit: result = %ld" +TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_objectFieldOffset_Exit Overhead=1 Level=3 Template="MethodHandleNatives_objectFieldOffset Exit: result = %lld" TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldOffset_Entry Overhead=1 Level=3 Template="MethodHandleNatives_staticFieldOffset Enter: self = %p" -TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldOffset_Exit Overhead=1 Level=3 Template="MethodHandleNatives_staticFieldOffset Exit: result = %ld" +TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldOffset_Exit Overhead=1 Level=3 Template="MethodHandleNatives_staticFieldOffset Exit: result = %lld" TraceEntry=Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldBase_Entry Overhead=1 Level=3 Template="MethodHandleNatives_staticFieldBase Enter: self = %p" TraceExit=Trc_JCL_java_lang_invoke_MethodHandleNatives_staticFieldBase_Exit Overhead=1 Level=3 Template="MethodHandleNatives_staticFieldBase Exit: result = %p" diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index 1e5083c3d28..f5cd3ed5fb0 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -4973,7 +4973,7 @@ typedef struct J9ReflectFunctionTable { struct J9JNIFieldID* ( *idFromFieldObject)(struct J9VMThread* vmStruct, j9object_t declaringClassObject, j9object_t fieldObject) ; struct J9JNIMethodID* ( *idFromMethodObject)(struct J9VMThread* vmStruct, j9object_t methodObject) ; struct J9JNIMethodID* ( *idFromConstructorObject)(struct J9VMThread* vmStruct, j9object_t constructorObject) ; - j9object_t ( *createFieldObject)(struct J9VMThread *vmThread, struct J9ROMFieldShape *romField, struct J9Class *declaringClass, bool isStaticField) ; + j9object_t ( *createFieldObject)(struct J9VMThread *vmThread, struct J9ROMFieldShape *romField, struct J9Class *declaringClass, BOOLEAN isStaticField) ; } J9ReflectFunctionTable; /* @ddr_namespace: map_to_type=J9VMRuntimeStateListener */ From 662cc6ed9db8abe41d55171d903eab0dddd63297 Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Thu, 10 Dec 2020 16:59:56 -0500 Subject: [PATCH 07/14] ifdef JCL function headers Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- runtime/oti/jclprots.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/oti/jclprots.h b/runtime/oti/jclprots.h index 4da081a617c..77ed923c589 100644 --- a/runtime/oti/jclprots.h +++ b/runtime/oti/jclprots.h @@ -951,6 +951,7 @@ Java_java_lang_invoke_MethodHandleNatives_checkClassBytes(JNIEnv *env, jclass jl #endif /* JAVA_SPEC_VERSION >= 15 */ /* java_lang_invoke_MethodHandleNatives.cpp */ +#if defined(J9VM_OPT_OPENJDK_METHODHANDLE) void JNICALL Java_java_lang_invoke_MethodHandleNatives_init(JNIEnv *env, jclass clazz, jobject self, jobject ref); void JNICALL Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobject self); jobject JNICALL Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, jobject self, jclass caller, jboolean speculativeResolve); @@ -965,6 +966,7 @@ void JNICALL Java_java_lang_invoke_MethodHandleNatives_copyOutBootstrapArguments void JNICALL Java_java_lang_invoke_MethodHandleNatives_clearCallSiteContext(JNIEnv *env, jclass clazz, jobject context); jint JNICALL Java_java_lang_invoke_MethodHandleNatives_getNamedCon(JNIEnv *env, jclass clazz, jint which, jobjectArray name); void JNICALL Java_java_lang_invoke_MethodHandleNatives_registerNatives(JNIEnv *env, jclass clazz); +#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */ /* java_lang_invoke_VarHandle.c */ #if defined(J9VM_OPT_METHOD_HANDLE) From 6f404969436769862cbdeb4fe25acfc3cd06218c Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Tue, 22 Dec 2020 15:18:49 -0500 Subject: [PATCH 08/14] Update comments for MN.expand and MN.resolve Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp index 1083895ce1a..c427517d6b4 100644 --- a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp +++ b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp @@ -500,7 +500,8 @@ Java_java_lang_invoke_MethodHandleNatives_init(JNIEnv *env, jclass clazz, jobjec /** * static native void expand(MemberName self); * - * Given a MemberName object, try to set the uninitialized fields from existing values. + * Given a MemberName object, try to set the uninitialized fields from existing VM metadata. + * Uses VM metadata (vmindex & vmtarget) to set symblic data fields (name & type & defc) * * Throws NullPointerException if MemberName object is null. * Throws IllegalArgumentException if MemberName doesn't contain required data to expand. @@ -594,7 +595,7 @@ Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobj * static native MemberName resolve(MemberName self, Class caller, * boolean speculativeResolve) throws LinkageError, ClassNotFoundException; * - * Resolve the method/field represented by the MemberName using the supplied caller + * Resolve the method/field represented by the MemberName's symbolic data (name & type & defc) with the supplied caller * Store the resolved Method/Field's JNI-id in vmindex, field offset / method pointer in vmtarget * * If the speculativeResolve flag is not set, failed resolution will throw the corresponding exception. From 512cf55aea390761ec72b5300662ed562c4d2cc8 Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Tue, 22 Dec 2020 15:27:32 -0500 Subject: [PATCH 09/14] Use rom constants for (int/float/long/double) Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- .../java_lang_invoke_MethodHandleNatives.cpp | 159 +++++++++--------- 1 file changed, 79 insertions(+), 80 deletions(-) diff --git a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp index c427517d6b4..fc3b2333710 100644 --- a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp +++ b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp @@ -347,96 +347,95 @@ resolveRefToObject(J9VMThread *currentThread, J9ConstantPool *ramConstantPool, U U_32 *cpShapeDescription = J9ROMCLASS_CPSHAPEDESCRIPTION(J9_CLASS_FROM_CP(ramConstantPool)->romClass); switch (J9_CP_TYPE(cpShapeDescription, cpIndex)) { - case J9CPTYPE_CLASS: - { - J9Class *clazz = (J9Class*)ramCP->value; - if ((NULL == clazz) && resolve) { - clazz = vmFuncs->resolveClassRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); - } - if (NULL != clazz) { - result = J9VM_J9CLASS_TO_HEAPCLASS(clazz); - } - break; + case J9CPTYPE_CLASS: { + J9Class *clazz = (J9Class*)ramCP->value; + if ((NULL == clazz) && resolve) { + clazz = vmFuncs->resolveClassRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); } - case J9CPTYPE_STRING: - { - result = (j9object_t)ramCP->value; - if ((NULL == result) && resolve) { - result = vmFuncs->resolveStringRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); - } - break; + if (NULL != clazz) { + result = J9VM_J9CLASS_TO_HEAPCLASS(clazz); } - case J9CPTYPE_INT: - { - result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGINTEGER_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); - if (NULL == result) { - vmFuncs->setHeapOutOfMemoryError(currentThread); - goto done; - } - J9VMJAVALANGINTEGER_SET_VALUE(currentThread, result, ramCP->value); - break; + break; + } + case J9CPTYPE_STRING: { + result = (j9object_t)ramCP->value; + if ((NULL == result) && resolve) { + result = vmFuncs->resolveStringRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); } - case J9CPTYPE_FLOAT: - { - result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGFLOAT_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); - if (NULL == result) { - vmFuncs->setHeapOutOfMemoryError(currentThread); - goto done; - } - J9VMJAVALANGFLOAT_SET_VALUE(currentThread, result, ramCP->value); - break; + break; + } + case J9CPTYPE_INT: { + J9ROMSingleSlotConstantRef *romCP = (J9ROMSingleSlotConstantRef*)J9_ROM_CP_FROM_CP(ramConstantPool) + cpIndex; + result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGINTEGER_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + if (NULL == result) { + vmFuncs->setHeapOutOfMemoryError(currentThread); + goto done; } - case J9CPTYPE_LONG: - { - J9ROMConstantRef *romCP = (J9ROMConstantRef*)J9_ROM_CP_FROM_CP(ramConstantPool) + cpIndex; - U_64 value = romCP->slot1; - value = (value << 32) + romCP->slot2; - result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGLONG_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); - if (NULL == result) { - vmFuncs->setHeapOutOfMemoryError(currentThread); - goto done; - } - J9VMJAVALANGLONG_SET_VALUE(currentThread, result, value); - break; + J9VMJAVALANGINTEGER_SET_VALUE(currentThread, result, romCP->data); + break; + } + case J9CPTYPE_FLOAT: { + J9ROMSingleSlotConstantRef *romCP = (J9ROMSingleSlotConstantRef*)J9_ROM_CP_FROM_CP(ramConstantPool) + cpIndex; + result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGFLOAT_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + if (NULL == result) { + vmFuncs->setHeapOutOfMemoryError(currentThread); + goto done; } - case J9CPTYPE_DOUBLE: - { - J9ROMConstantRef *romCP = (J9ROMConstantRef*)J9_ROM_CP_FROM_CP(ramConstantPool) + cpIndex; - U_64 value = romCP->slot1; - value = (value << 32) + romCP->slot2; - result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGDOUBLE_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); - if (NULL == result) { - vmFuncs->setHeapOutOfMemoryError(currentThread); - goto done; - } - J9VMJAVALANGDOUBLE_SET_VALUE(currentThread, result, value); - break; + J9VMJAVALANGFLOAT_SET_VALUE(currentThread, result, romCP->data); + break; + } + case J9CPTYPE_LONG: { + J9ROMConstantRef *romCP = (J9ROMConstantRef*)J9_ROM_CP_FROM_CP(ramConstantPool) + cpIndex; +#ifdef J9VM_ENV_LITTLE_ENDIAN + U_64 value = (((U_64)(romCP->slot2)) << 32) | ((U_64)(romCP->slot1)); +#else + U_64 value = (((U_64)(romCP->slot1)) << 32) | ((U_64)(romCP->slot2)); +#endif + result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGLONG_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + if (NULL == result) { + vmFuncs->setHeapOutOfMemoryError(currentThread); + goto done; } - case J9CPTYPE_METHOD_TYPE: - { - result = (j9object_t)ramCP->value; - if ((NULL == result) && resolve) { - result = vmFuncs->resolveMethodTypeRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); - } - break; + J9VMJAVALANGLONG_SET_VALUE(currentThread, result, value); + break; + } + case J9CPTYPE_DOUBLE: { + J9ROMConstantRef *romCP = (J9ROMConstantRef*)J9_ROM_CP_FROM_CP(ramConstantPool) + cpIndex; +#ifdef J9VM_ENV_LITTLE_ENDIAN + U_64 value = (((U_64)(romCP->slot2)) << 32) | ((U_64)(romCP->slot1)); +#else + U_64 value = (((U_64)(romCP->slot1)) << 32) | ((U_64)(romCP->slot2)); +#endif + result = vm->memoryManagerFunctions->J9AllocateObject(currentThread, J9VMJAVALANGDOUBLE_OR_NULL(vm), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + if (NULL == result) { + vmFuncs->setHeapOutOfMemoryError(currentThread); + goto done; } - case J9CPTYPE_METHODHANDLE: - { - result = (j9object_t)ramCP->value; - if ((NULL == result) && resolve) { - result = vmFuncs->resolveMethodHandleRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE | J9_RESOLVE_FLAG_NO_CLASS_INIT); - } - break; + J9VMJAVALANGDOUBLE_SET_VALUE(currentThread, result, value); + break; + } + case J9CPTYPE_METHOD_TYPE: { + result = (j9object_t)ramCP->value; + if ((NULL == result) && resolve) { + result = vmFuncs->resolveMethodTypeRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); } - case J9CPTYPE_CONSTANT_DYNAMIC: - { - result = (j9object_t)ramCP->value; - if ((NULL == result) && resolve) { - result = vmFuncs->resolveConstantDynamic(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); - } - break; + break; + } + case J9CPTYPE_METHODHANDLE: { + result = (j9object_t)ramCP->value; + if ((NULL == result) && resolve) { + result = vmFuncs->resolveMethodHandleRef(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE | J9_RESOLVE_FLAG_NO_CLASS_INIT); + } + break; + } + case J9CPTYPE_CONSTANT_DYNAMIC: { + result = (j9object_t)ramCP->value; + if ((NULL == result) && resolve) { + result = vmFuncs->resolveConstantDynamic(currentThread, ramConstantPool, cpIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE); } + break; } + } /* switch */ done: return result; } From eb86b1723c36e31919066a45f7f579dd70cfb8bc Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Tue, 22 Dec 2020 15:57:56 -0500 Subject: [PATCH 10/14] remove NULL check before j9mem_free_memory Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- .../java_lang_invoke_MethodHandleNatives.cpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp index fc3b2333710..90f9d4bfb62 100644 --- a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp +++ b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp @@ -319,16 +319,11 @@ getSignatureFromMethodType(J9VMThread *currentThread, j9object_t typeObject, UDA strcpy(cursor, rSignature); done: - if (NULL != rSignature) { - j9mem_free_memory(rSignature); - } + j9mem_free_memory(rSignature); + if (NULL != signatures) { for (U_32 i = 0; i < numArgs; i++) { - if (NULL != signatures[i]) { - j9mem_free_memory(signatures[i]); - } else { - break; - } + j9mem_free_memory(signatures[i]); } j9mem_free_memory(signatures); } @@ -1153,12 +1148,8 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, } } done: - if (NULL != name) { - j9mem_free_memory(name); - } - if (NULL != sig) { - j9mem_free_memory(sig); - } + j9mem_free_memory(name); + j9mem_free_memory(sig); Trc_JCL_java_lang_invoke_MethodHandleNatives_getMembers_Exit(env, result); vmFuncs->internalExitVMToJNI(currentThread); From 57bbf4f674c5dc466192039b02fc4b00f04867c1 Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Tue, 22 Dec 2020 15:16:09 -0500 Subject: [PATCH 11/14] combine getClassSignature and sigForPrimitiveOrVoid - use Class.classNameString if possible - check if arrayClass to set proper classNameString format Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- .../java_lang_invoke_MethodHandleNatives.cpp | 181 +++++++++--------- 1 file changed, 92 insertions(+), 89 deletions(-) diff --git a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp index 90f9d4bfb62..b26286cfeb8 100644 --- a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp +++ b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp @@ -157,90 +157,105 @@ initImpl(J9VMThread *currentThread, j9object_t membernameObject, j9object_t refO } static char * -sigForPrimitiveOrVoid(J9VMThread *currentThread, J9Class *clazz) +sigForPrimitiveOrVoid(J9JavaVM *vm, J9Class *clazz) { - J9JavaVM *vm = currentThread->javaVM; - char result = 0; - if (clazz == vm->booleanReflectClass) { - result = 'Z'; - } else if (clazz == vm->byteReflectClass) { - result = 'B'; - } else if (clazz == vm->charReflectClass) { - result = 'C'; - } else if (clazz == vm->shortReflectClass) { - result = 'S'; - } else if (clazz == vm->intReflectClass) { - result = 'I'; - } else if (clazz == vm->longReflectClass) { - result = 'J'; - } else if (clazz == vm->floatReflectClass) { - result = 'F'; - } else if (clazz == vm->doubleReflectClass) { - result = 'D'; - } else if (clazz == vm->voidReflectClass) { - result = 'V'; - } - - if (result != 0) { - PORT_ACCESS_FROM_JAVAVM(vm); - char* signature = (char*)j9mem_allocate_memory(2, OMRMEM_CATEGORY_VM); - if (NULL != signature) { - signature[0] = result; - signature[1] = '\0'; - return signature; - } else { - vm->internalVMFunctions->setNativeOutOfMemoryError(currentThread, 0, 0); + PORT_ACCESS_FROM_JAVAVM(vm); + char* signature = (char*)j9mem_allocate_memory(2, OMRMEM_CATEGORY_VM); + + if (NULL != signature) { + if (clazz == vm->booleanReflectClass) { + signature[0] = 'Z'; + } else if (clazz == vm->byteReflectClass) { + signature[0] = 'B'; + } else if (clazz == vm->charReflectClass) { + signature[0] = 'C'; + } else if (clazz == vm->shortReflectClass) { + signature[0] = 'S'; + } else if (clazz == vm->intReflectClass) { + signature[0] = 'I'; + } else if (clazz == vm->longReflectClass) { + signature[0] = 'J'; + } else if (clazz == vm->floatReflectClass) { + signature[0] = 'F'; + } else if (clazz == vm->doubleReflectClass) { + signature[0] = 'D'; + } else if (clazz == vm->voidReflectClass) { + signature[0] = 'V'; } + + signature[1] = '\0'; } - return NULL; + + return signature; } static char * getClassSignature(J9VMThread *currentThread, J9Class * clazz) { - PORT_ACCESS_FROM_JAVAVM(currentThread->javaVM); + J9JavaVM *vm = currentThread->javaVM; + PORT_ACCESS_FROM_JAVAVM(vm); + char *sig = NULL; - U_32 numDims = 0; + if (J9ROMCLASS_IS_PRIMITIVE_TYPE(clazz->romClass)) { + sig = sigForPrimitiveOrVoid(vm, clazz); + } else { + j9object_t sigString = J9VMJAVALANGCLASS_CLASSNAMESTRING(currentThread, J9VM_J9CLASS_TO_HEAPCLASS(clazz)); + if (NULL != sigString) { + /* +3 so that we can fit 'L' and ';' around the class name with the null-terminator */ + UDATA utfLength = vm->internalVMFunctions->getStringUTF8Length(currentThread, sigString) + 3; + sig = (char *)j9mem_allocate_memory(utfLength, OMRMEM_CATEGORY_VM); + if (NULL != sig) { + if (J9ROMCLASS_IS_ARRAY(clazz->romClass)) { + vm->internalVMFunctions->copyStringToUTF8Helper(currentThread, sigString, J9_STR_NULL_TERMINATE_RESULT | J9_STR_XLAT, 0, J9VMJAVALANGSTRING_LENGTH(currentThread, sigString), (U_8*)sig, utfLength); + } else { + sig[0] = 'L'; + vm->internalVMFunctions->copyStringToUTF8Helper(currentThread, sigString, J9_STR_XLAT, 0, J9VMJAVALANGSTRING_LENGTH(currentThread, sigString), (U_8*)(sig + 1), utfLength - 1); + sig[utfLength - 2] = ';'; + sig[utfLength - 1] = '\0'; + } + } + } else { + U_32 numDims = 0; - J9Class *myClass = clazz; - while (J9ROMCLASS_IS_ARRAY(myClass->romClass)) { - J9Class * componentClass = (J9Class *)(((J9ArrayClass*)myClass)->componentType); - if (J9ROMCLASS_IS_PRIMITIVE_TYPE(componentClass->romClass)) { - break; - } - numDims++; - myClass = componentClass; - } + J9Class *myClass = clazz; + while (J9ROMCLASS_IS_ARRAY(myClass->romClass)) { + J9Class * componentClass = (J9Class *)(((J9ArrayClass*)myClass)->componentType); + if (J9ROMCLASS_IS_PRIMITIVE_TYPE(componentClass->romClass)) { + break; + } + numDims++; + myClass = componentClass; + } - J9UTF8 *romName = J9ROMCLASS_CLASSNAME(myClass->romClass); - U_32 len = J9UTF8_LENGTH(romName); - char * name = (char *)J9UTF8_DATA(romName); - U_32 length = len + numDims; - if (* name != '[') { - length += 2; - } + J9UTF8 *romName = J9ROMCLASS_CLASSNAME(myClass->romClass); + U_32 nameLength = J9UTF8_LENGTH(romName); + char * name = (char *)J9UTF8_DATA(romName); + U_32 sigLength = nameLength + numDims; + if (* name != '[') { + sigLength += 2; + } - length++; /* for null-termination */ - char * sig = (char *)j9mem_allocate_memory(length, OMRMEM_CATEGORY_VM); - if (NULL == sig) { - currentThread->javaVM->internalVMFunctions->setNativeOutOfMemoryError(currentThread, 0, 0); - } else { - U_32 i; - for (i = 0; i < numDims; i++) { - sig[i] = '['; - } + sigLength++; /* for null-termination */ + sig = (char *)j9mem_allocate_memory(sigLength, OMRMEM_CATEGORY_VM); + if (NULL != sig) { + U_32 i; + for (i = 0; i < numDims; i++) { + sig[i] = '['; + } - if (*name != '[') { - sig[i++] = 'L'; - } + if (*name != '[') { + sig[i++] = 'L'; + } - memcpy(sig+i, name, len); - i += len; + memcpy(sig+i, name, nameLength); + i += nameLength; - if (*name != '[') { - sig[i++] = ';'; + if (*name != '[') { + sig[i++] = ';'; + } + sig[sigLength-1] = '\0'; + } } - sig[length-1] = '\0'; } return sig; @@ -261,22 +276,18 @@ getSignatureFromMethodType(J9VMThread *currentThread, j9object_t typeObject, UDA char** signatures = (char**)j9mem_allocate_memory((numArgs) * sizeof(char*), OMRMEM_CATEGORY_VM); if (NULL == signatures) { - vm->internalVMFunctions->setNativeOutOfMemoryError(currentThread, 0, 0); goto done; } + memset(signatures, 0, (numArgs) * sizeof(char*)); + *signatureLength = 2; /* space for '(', ')' */ for (U_32 i = 0; i < numArgs; i++) { j9object_t pObject = J9JAVAARRAYOFOBJECT_LOAD(currentThread, ptypes, i); J9Class *pclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, pObject); - signatures[i] = sigForPrimitiveOrVoid(currentThread, pclass); - if (VM_VMHelpers::exceptionPending(currentThread)) { + signatures[i] = getClassSignature(currentThread, pclass); + if (NULL == signatures[i]) { goto done; - } else if (NULL == signatures[i]) { - signatures[i] = getClassSignature(currentThread, pclass); - if (VM_VMHelpers::exceptionPending(currentThread)) { - goto done; - } } *signatureLength += strlen(signatures[i]); @@ -286,14 +297,9 @@ getSignatureFromMethodType(J9VMThread *currentThread, j9object_t typeObject, UDA /* Return type */ j9object_t rtype = J9VMJAVALANGINVOKEMETHODTYPE_RTYPE(currentThread, typeObject); J9Class *rclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, rtype); - rSignature = sigForPrimitiveOrVoid(currentThread, rclass); - if (VM_VMHelpers::exceptionPending(currentThread)) { + rSignature = getClassSignature(currentThread, rclass); + if (NULL == rSignature) { goto done; - } else if (rSignature == NULL) { - rSignature = getClassSignature(currentThread, rclass); - if (VM_VMHelpers::exceptionPending(currentThread)) { - goto done; - } } } @@ -301,7 +307,6 @@ getSignatureFromMethodType(J9VMThread *currentThread, j9object_t typeObject, UDA methodDescriptor = (char*)j9mem_allocate_memory(*signatureLength+1, OMRMEM_CATEGORY_VM); if (NULL == methodDescriptor) { - vm->internalVMFunctions->setNativeOutOfMemoryError(currentThread, 0, 0); goto done; } cursor = methodDescriptor; @@ -656,12 +661,10 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(JNIEnv *env, jclass clazz, job signature = vmFuncs->copyStringToUTF8WithMemAlloc(currentThread, typeObject, J9_STR_NULL_TERMINATE_RESULT | J9_STR_XLAT, "", 0, NULL, 0, &signatureLength); } else if (J9VMJAVALANGCLASS(vm) == typeClass) { J9Class *rclass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, typeObject); - signature = sigForPrimitiveOrVoid(currentThread, rclass); - if ((NULL == signature) && (!VM_VMHelpers::exceptionPending(currentThread))) { - signature = getClassSignature(currentThread, rclass); + signature = getClassSignature(currentThread, rclass); + if (NULL != signature) { + signatureLength = strlen(signature); } - - signatureLength = strlen(signature); } else { vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL); goto done; From 6f74d5fb50c08a123c683e33156384d0e62d5274 Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Wed, 23 Dec 2020 16:45:48 -0500 Subject: [PATCH 12/14] Store memberName to sp to avoid GC issue Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- .../java_lang_invoke_MethodHandleNatives.cpp | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp index b26286cfeb8..3f27891853b 100644 --- a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp +++ b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp @@ -956,14 +956,12 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, result = -99; goto done; } - j9object_t fieldObj = NULL; - if (romField->modifiers & J9AccStatic) { - /* create static field object */ - fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, TRUE); - } else { - /* create instance field object */ - fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, FALSE); - } + PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, memberName); + + /* create static field object */ + j9object_t fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, (romField->modifiers & J9AccStatic) == J9AccStatic); + memberName = POP_OBJECT_IN_SPECIAL_FRAME(currentThread); + if (NULL != fieldObj) { initImpl(currentThread, memberName, fieldObj); } @@ -1011,14 +1009,12 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, result = -99; goto done; } - j9object_t fieldObj = NULL; - if (romField->modifiers & J9AccStatic) { - /* create static field object */ - fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, true); - } else { - /* create instance field object */ - fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, false); - } + PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, memberName); + + /* create field object */ + j9object_t fieldObj = vm->reflectFunctions.createFieldObject(currentThread, romField, defClass, (romField->modifiers & J9AccStatic) == J9AccStatic); + memberName = POP_OBJECT_IN_SPECIAL_FRAME(currentThread); + if (NULL != fieldObj) { initImpl(currentThread, memberName, fieldObj); } @@ -1065,6 +1061,8 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, result = -99; goto done; } + PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, memberName); + j9object_t methodObj = NULL; if (J9_ARE_NO_BITS_SET(romMethod->modifiers, J9AccStatic) && ('<' == (char)*J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)))) { /* create constructor object */ @@ -1073,6 +1071,8 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, /* create method object */ methodObj = vm->reflectFunctions.createMethodObject(currentMethod, currentClass, NULL, currentThread); } + memberName = POP_OBJECT_IN_SPECIAL_FRAME(currentThread); + if (NULL != methodObj) { initImpl(currentThread, memberName, methodObj); } @@ -1123,6 +1123,8 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, result = -99; goto done; } + PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, memberName); + j9object_t methodObj = NULL; if (J9_ARE_NO_BITS_SET(romMethod->modifiers, J9AccStatic) && ('<' == (char)*J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod)))) { /* create constructor object */ @@ -1131,6 +1133,8 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(JNIEnv *env, jclass clazz, /* create method object */ methodObj = vm->reflectFunctions.createMethodObject(currentMethod, currentClass, NULL, currentThread); } + memberName = POP_OBJECT_IN_SPECIAL_FRAME(currentThread); + if (NULL != methodObj) { initImpl(currentThread, memberName, methodObj); } From a7bf780bff333f7df479c7e92728a957f8ac0085 Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Tue, 12 Jan 2021 12:34:11 -0500 Subject: [PATCH 13/14] Update Copyright date Co-authored-by: Babneet Singh Signed-off-by: Jack Lu --- runtime/jcl/CMakeLists.txt | 2 +- runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp | 2 +- runtime/jcl/common/jclcinit.c | 2 +- runtime/jcl/common/reflecthelp.c | 2 +- runtime/jcl/exports.cmake | 2 +- runtime/jcl/j9jcl.tdf | 2 +- runtime/jcl/module.xml | 2 +- .../jcl/uma/java_lang_invoke_MethodHandleNatives_exports.xml | 2 +- .../jcl/uma/java_lang_invoke_MethodHandleNatives_objects.xml | 2 +- runtime/oti/jclprots.h | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/runtime/jcl/CMakeLists.txt b/runtime/jcl/CMakeLists.txt index 094d7dc710f..1fc935a26a2 100644 --- a/runtime/jcl/CMakeLists.txt +++ b/runtime/jcl/CMakeLists.txt @@ -1,5 +1,5 @@ ################################################################################ -# Copyright (c) 2017, 2020 IBM Corp. and others +# Copyright (c) 2017, 2021 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 diff --git a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp index 3f27891853b..67e453e018f 100644 --- a/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp +++ b/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020, 2020 IBM Corp. and others + * Copyright (c) 2021, 2021 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 diff --git a/runtime/jcl/common/jclcinit.c b/runtime/jcl/common/jclcinit.c index 95bdab3fafd..88f09ad4763 100644 --- a/runtime/jcl/common/jclcinit.c +++ b/runtime/jcl/common/jclcinit.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 1998, 2020 IBM Corp. and others + * Copyright (c) 1998, 2021 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 diff --git a/runtime/jcl/common/reflecthelp.c b/runtime/jcl/common/reflecthelp.c index b33379feee9..988e18f6fd0 100644 --- a/runtime/jcl/common/reflecthelp.c +++ b/runtime/jcl/common/reflecthelp.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2001, 2020 IBM Corp. and others + * Copyright (c) 2001, 2021 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 diff --git a/runtime/jcl/exports.cmake b/runtime/jcl/exports.cmake index 60536796c87..faaba8fc3d1 100644 --- a/runtime/jcl/exports.cmake +++ b/runtime/jcl/exports.cmake @@ -1,5 +1,5 @@ ################################################################################ -# Copyright (c) 2019, 2020 IBM Corp. and others +# Copyright (c) 2019, 2021 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 diff --git a/runtime/jcl/j9jcl.tdf b/runtime/jcl/j9jcl.tdf index e337acb5028..4a35fdddb53 100644 --- a/runtime/jcl/j9jcl.tdf +++ b/runtime/jcl/j9jcl.tdf @@ -1,4 +1,4 @@ -// Copyright (c) 2006, 2020 IBM Corp. and others +// Copyright (c) 2006, 2021 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 diff --git a/runtime/jcl/module.xml b/runtime/jcl/module.xml index bd2dac9a73e..7fcc0cfa5ff 100644 --- a/runtime/jcl/module.xml +++ b/runtime/jcl/module.xml @@ -1,6 +1,6 @@