# HG changeset patch # User coleenp # Date 1495891261 14400 # Node ID fd4bc78630b15adba7cca8140c67cdf64e9a6239 # Parent 38048d4d20e7ae4c29294264c3ddc64db68c0c50 8174749: Use hash table/oops for MemberName table Summary: Add a Java type called ResolvedMethodName which is immutable and can be stored in a hashtable, that is weakly collected by gc Reviewed-by: sspitsyn, stefank, jrose diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp Sat May 27 09:21:01 2017 -0400 @@ -137,8 +137,9 @@ __ verify_oop(method_temp); __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()))); __ verify_oop(method_temp); - // the following assumes that a Method* is normally compressed in the vmtarget field: - __ ldr(method_temp, Address(method_temp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()))); + __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes()))); + __ verify_oop(method_temp); + __ ldr(method_temp, Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes()))); if (VerifyMethodHandles && !for_compiler_entry) { // make sure recv is already on stack @@ -282,7 +283,8 @@ Address member_clazz( member_reg, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes())); Address member_vmindex( member_reg, NONZERO(java_lang_invoke_MemberName::vmindex_offset_in_bytes())); - Address member_vmtarget( member_reg, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes())); + Address member_vmtarget( member_reg, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes())); + Address vmtarget_method( rmethod, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())); Register temp1_recv_klass = temp1; if (iid != vmIntrinsics::_linkToStatic) { @@ -335,14 +337,16 @@ if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3); } - __ ldr(rmethod, member_vmtarget); + __ load_heap_oop(rmethod, member_vmtarget); + __ ldr(rmethod, vmtarget_method); break; case vmIntrinsics::_linkToStatic: if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3); } - __ ldr(rmethod, member_vmtarget); + __ load_heap_oop(rmethod, member_vmtarget); + __ ldr(rmethod, vmtarget_method); break; case vmIntrinsics::_linkToVirtual: diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/cpu/arm/vm/methodHandles_arm.cpp --- a/hotspot/src/cpu/arm/vm/methodHandles_arm.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/cpu/arm/vm/methodHandles_arm.cpp Sat May 27 09:21:01 2017 -0400 @@ -157,8 +157,9 @@ __ load_heap_oop(tmp, Address(tmp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()))); __ verify_oop(tmp); - // the following assumes that a Method* is normally compressed in the vmtarget field: - __ ldr(Rmethod, Address(tmp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()))); + __ load_heap_oop(Rmethod, Address(tmp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes()))); + __ verify_oop(Rmethod); + __ ldr(Rmethod, Address(Rmethod, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes()))); if (VerifyMethodHandles && !for_compiler_entry) { // make sure recv is already on stack @@ -320,7 +321,8 @@ Address member_clazz( member_reg, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes())); Address member_vmindex( member_reg, NONZERO(java_lang_invoke_MemberName::vmindex_offset_in_bytes())); - Address member_vmtarget(member_reg, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes())); + Address member_vmtarget(member_reg, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes())); + Address vmtarget_method(Rmethod, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())); Register temp1_recv_klass = temp1; if (iid != vmIntrinsics::_linkToStatic) { @@ -375,14 +377,17 @@ if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3); } - __ ldr(Rmethod, member_vmtarget); + __ load_heap_oop(Rmethod, member_vmtarget); + __ ldr(Rmethod, vmtarget_method); break; case vmIntrinsics::_linkToStatic: if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3); } - __ ldr(Rmethod, member_vmtarget); + __ load_heap_oop(Rmethod, member_vmtarget); + __ ldr(Rmethod, vmtarget_method); + break; break; case vmIntrinsics::_linkToVirtual: diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Sat May 27 09:21:01 2017 -0400 @@ -174,8 +174,9 @@ __ verify_oop(method_temp); __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp, temp2); __ verify_oop(method_temp); - // The following assumes that a Method* is normally compressed in the vmtarget field: - __ ld(method_temp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()), method_temp); + __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes()), method_temp); + __ verify_oop(method_temp); + __ ld(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes()), method_temp); if (VerifyMethodHandles && !for_compiler_entry) { // Make sure recv is already on stack. @@ -361,14 +362,16 @@ if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp2); } - __ ld(R19_method, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()), member_reg); + __ load_heap_oop(member_reg, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes()), member_reg); + __ ld(R19_method, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes()), member_reg); break; case vmIntrinsics::_linkToStatic: if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp2); } - __ ld(R19_method, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()), member_reg); + __ load_heap_oop(member_reg, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes()), member_reg); + __ ld(R19_method, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes()), member_reg); break; case vmIntrinsics::_linkToVirtual: diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/cpu/s390/vm/methodHandles_s390.cpp --- a/hotspot/src/cpu/s390/vm/methodHandles_s390.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/cpu/s390/vm/methodHandles_s390.cpp Sat May 27 09:21:01 2017 -0400 @@ -200,10 +200,13 @@ Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()))); __ verify_oop(method_temp); - // The following assumes that a method is normally compressed in the vmtarget field. + __ load_heap_oop(method_temp, + Address(method_temp, + NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes()))); + __ verify_oop(method_temp); __ z_lg(method_temp, Address(method_temp, - NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()))); + NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes()))); if (VerifyMethodHandles && !for_compiler_entry) { // Make sure recv is already on stack. @@ -371,7 +374,8 @@ Address member_clazz( member_reg, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes())); Address member_vmindex( member_reg, NONZERO(java_lang_invoke_MemberName::vmindex_offset_in_bytes())); - Address member_vmtarget(member_reg, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes())); + Address member_vmtarget(member_reg, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes())); + Address vmtarget_method(Z_method, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())); Register temp1_recv_klass = temp1; if (iid != vmIntrinsics::_linkToStatic) { @@ -424,7 +428,8 @@ if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3); } - __ z_lg(Z_method, member_vmtarget); + __ load_heap_oop(Z_method, member_vmtarget); + __ z_lg(Z_method, vmtarget_method); method_is_live = true; break; @@ -432,7 +437,8 @@ if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3); } - __ z_lg(Z_method, member_vmtarget); + __ load_heap_oop(Z_method, member_vmtarget); + __ z_lg(Z_method, vmtarget_method); method_is_live = true; break; diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Sat May 27 09:21:01 2017 -0400 @@ -181,8 +181,9 @@ __ verify_oop(method_temp); __ load_heap_oop(Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes())), method_temp); __ verify_oop(method_temp); - // the following assumes that a Method* is normally compressed in the vmtarget field: - __ ld_ptr( Address(method_temp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes())), method_temp); + __ load_heap_oop(Address(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes())), method_temp); + __ verify_oop(method_temp); + __ ld_ptr( Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())), method_temp); if (VerifyMethodHandles && !for_compiler_entry) { // make sure recv is already on stack @@ -332,7 +333,8 @@ Address member_clazz( member_reg, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes())); Address member_vmindex( member_reg, NONZERO(java_lang_invoke_MemberName::vmindex_offset_in_bytes())); - Address member_vmtarget( member_reg, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes())); + Address member_vmtarget( member_reg, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes())); + Address vmtarget_method( G5_method, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())); Register temp1_recv_klass = temp1; if (iid != vmIntrinsics::_linkToStatic) { @@ -384,14 +386,16 @@ if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp2); } - __ ld_ptr(member_vmtarget, G5_method); + __ load_heap_oop(member_vmtarget, G5_method); + __ ld_ptr(vmtarget_method, G5_method); break; case vmIntrinsics::_linkToStatic: if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp2); } - __ ld_ptr(member_vmtarget, G5_method); + __ load_heap_oop(member_vmtarget, G5_method); + __ ld_ptr(vmtarget_method, G5_method); break; case vmIntrinsics::_linkToVirtual: diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/cpu/x86/vm/methodHandles_x86.cpp --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Sat May 27 09:21:01 2017 -0400 @@ -169,8 +169,9 @@ __ verify_oop(method_temp); __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()))); __ verify_oop(method_temp); - // the following assumes that a Method* is normally compressed in the vmtarget field: - __ movptr(method_temp, Address(method_temp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()))); + __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes()))); + __ verify_oop(method_temp); + __ movptr(method_temp, Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes()))); if (VerifyMethodHandles && !for_compiler_entry) { // make sure recv is already on stack @@ -331,7 +332,8 @@ Address member_clazz( member_reg, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes())); Address member_vmindex( member_reg, NONZERO(java_lang_invoke_MemberName::vmindex_offset_in_bytes())); - Address member_vmtarget( member_reg, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes())); + Address member_vmtarget( member_reg, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes())); + Address vmtarget_method( rbx_method, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())); Register temp1_recv_klass = temp1; if (iid != vmIntrinsics::_linkToStatic) { @@ -383,14 +385,16 @@ if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3); } - __ movptr(rbx_method, member_vmtarget); + __ load_heap_oop(rbx_method, member_vmtarget); + __ movptr(rbx_method, vmtarget_method); break; case vmIntrinsics::_linkToStatic: if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3); } - __ movptr(rbx_method, member_vmtarget); + __ load_heap_oop(rbx_method, member_vmtarget); + __ movptr(rbx_method, vmtarget_method); break; case vmIntrinsics::_linkToVirtual: diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java --- a/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java Sat May 27 09:21:01 2017 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,8 @@ static final ResolvedJavaType lambdaFormType; static final ResolvedJavaField methodHandleFormField; static final ResolvedJavaField lambdaFormVmentryField; - static final HotSpotResolvedJavaField memberNameVmtargetField; + static final ResolvedJavaField methodField; + static final HotSpotResolvedJavaField vmtargetField; /** * Search for an instance field with the given name in a class. @@ -88,7 +89,10 @@ lambdaFormType = resolveType("java.lang.invoke.LambdaForm"); methodHandleFormField = findFieldInClass(methodHandleType, "form", lambdaFormType); lambdaFormVmentryField = findFieldInClass(lambdaFormType, "vmentry", memberNameType); - memberNameVmtargetField = (HotSpotResolvedJavaField) findFieldInClass(memberNameType, "vmtarget", resolveType(long.class)); + ResolvedJavaType methodType = resolveType("java.lang.invoke.ResolvedMethodName"); + methodField = findFieldInClass(memberNameType, "method", methodType); + vmtargetField = (HotSpotResolvedJavaField) findFieldInClass(methodType, "vmtarget", resolveType(HotSpotJVMCIRuntime.getHostWordKind().toJavaClass())); + } catch (Throwable ex) { throw new JVMCIError(ex); } @@ -139,24 +143,30 @@ memberName = constantReflection.readFieldValue(LazyInitialization.lambdaFormVmentryField, lambdaForm); assert memberName.isNonNull(); } - return getTargetMethod(memberName); + JavaConstant method = constantReflection.readFieldValue(LazyInitialization.methodField, memberName); + return getTargetMethod(method); } @Override public ResolvedJavaMethod resolveLinkToTarget(JavaConstant memberName) { - return getTargetMethod(memberName); + if (memberName.isNull()) { + return null; + } + JavaConstant method = constantReflection.readFieldValue(LazyInitialization.methodField, memberName); + return getTargetMethod(method); } /** - * Returns the {@link ResolvedJavaMethod} for the vmtarget of a java.lang.invoke.MemberName. + * Returns the {@link ResolvedJavaMethod} for the method of a java.lang.invoke.MemberName. */ - private static ResolvedJavaMethod getTargetMethod(JavaConstant memberName) { - if (memberName.isNull()) { - return null; + private static ResolvedJavaMethod getTargetMethod(JavaConstant method) { + if (method == null) { + // If readFieldValue returns NULL the type was wrong + throw new IllegalArgumentException("unexpected type for memberName"); } - Object object = ((HotSpotObjectConstantImpl) memberName).object(); - /* Read the ResolvedJavaMethod from the injected field MemberName.vmtarget */ - return compilerToVM().getResolvedJavaMethod(object, LazyInitialization.memberNameVmtargetField.offset()); + Object object = ((HotSpotObjectConstantImpl) method).object(); + /* Read the ResolvedJavaMethod from the injected field MemberName.method.vmtarget */ + return compilerToVM().getResolvedJavaMethod(object, LazyInitialization.vmtargetField.offset()); } } diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Sat May 27 09:21:01 2017 -0400 @@ -45,6 +45,7 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "oops/typeArrayOop.hpp" +#include "prims/resolvedMethodTable.hpp" #include "runtime/fieldDescriptor.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.hpp" @@ -2228,11 +2229,11 @@ return method; } -void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci) { +void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci, TRAPS) { // set Method* or mid/cpref Handle mname(Thread::current(), stackFrame->obj_field(_memberName_offset)); InstanceKlass* ik = method->method_holder(); - CallInfo info(method(), ik); + CallInfo info(method(), ik, CHECK); MethodHandles::init_method_MemberName(mname, info); // set bci java_lang_StackFrameInfo::set_bci(stackFrame(), bci); @@ -3083,9 +3084,9 @@ } void java_lang_invoke_DirectMethodHandle::compute_offsets() { - Klass* klass_oop = SystemDictionary::DirectMethodHandle_klass(); - if (klass_oop != NULL) { - compute_offset(_member_offset, klass_oop, vmSymbols::member_name(), vmSymbols::java_lang_invoke_MemberName_signature()); + Klass* k = SystemDictionary::DirectMethodHandle_klass(); + if (k != NULL) { + compute_offset(_member_offset, k, vmSymbols::member_name(), vmSymbols::java_lang_invoke_MemberName_signature()); } } @@ -3098,36 +3099,43 @@ int java_lang_invoke_MemberName::_name_offset; int java_lang_invoke_MemberName::_type_offset; int java_lang_invoke_MemberName::_flags_offset; -int java_lang_invoke_MemberName::_vmtarget_offset; -int java_lang_invoke_MemberName::_vmloader_offset; +int java_lang_invoke_MemberName::_method_offset; int java_lang_invoke_MemberName::_vmindex_offset; +int java_lang_invoke_ResolvedMethodName::_vmtarget_offset; +int java_lang_invoke_ResolvedMethodName::_vmholder_offset; + int java_lang_invoke_LambdaForm::_vmentry_offset; void java_lang_invoke_MethodHandle::compute_offsets() { - Klass* klass_oop = SystemDictionary::MethodHandle_klass(); - if (klass_oop != NULL) { - compute_offset(_type_offset, klass_oop, vmSymbols::type_name(), vmSymbols::java_lang_invoke_MethodType_signature()); - compute_offset(_form_offset, klass_oop, vmSymbols::form_name(), vmSymbols::java_lang_invoke_LambdaForm_signature()); + Klass* k = SystemDictionary::MethodHandle_klass(); + if (k != NULL) { + compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_lang_invoke_MethodType_signature()); + compute_offset(_form_offset, k, vmSymbols::form_name(), vmSymbols::java_lang_invoke_LambdaForm_signature()); } } void java_lang_invoke_MemberName::compute_offsets() { - Klass* klass_oop = SystemDictionary::MemberName_klass(); - if (klass_oop != NULL) { - compute_offset(_clazz_offset, klass_oop, vmSymbols::clazz_name(), vmSymbols::class_signature()); - compute_offset(_name_offset, klass_oop, vmSymbols::name_name(), vmSymbols::string_signature()); - compute_offset(_type_offset, klass_oop, vmSymbols::type_name(), vmSymbols::object_signature()); - compute_offset(_flags_offset, klass_oop, vmSymbols::flags_name(), vmSymbols::int_signature()); - MEMBERNAME_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); - } + Klass* k = SystemDictionary::MemberName_klass(); + assert (k != NULL, "jdk mismatch"); + compute_offset(_clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature()); + compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); + compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::object_signature()); + compute_offset(_flags_offset, k, vmSymbols::flags_name(), vmSymbols::int_signature()); + compute_offset(_method_offset, k, vmSymbols::method_name(), vmSymbols::java_lang_invoke_ResolvedMethodName_signature()); + MEMBERNAME_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); +} + +void java_lang_invoke_ResolvedMethodName::compute_offsets() { + Klass* k = SystemDictionary::ResolvedMethodName_klass(); + assert(k != NULL, "jdk mismatch"); + RESOLVEDMETHOD_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } void java_lang_invoke_LambdaForm::compute_offsets() { - Klass* klass_oop = SystemDictionary::LambdaForm_klass(); - if (klass_oop != NULL) { - compute_offset(_vmentry_offset, klass_oop, vmSymbols::vmentry_name(), vmSymbols::java_lang_invoke_MemberName_signature()); - } + Klass* k = SystemDictionary::LambdaForm_klass(); + assert (k != NULL, "jdk mismatch"); + compute_offset(_vmentry_offset, k, vmSymbols::vmentry_name(), vmSymbols::java_lang_invoke_MemberName_signature()); } bool java_lang_invoke_LambdaForm::is_instance(oop obj) { @@ -3195,9 +3203,12 @@ mname->int_field_put(_flags_offset, flags); } -Metadata* java_lang_invoke_MemberName::vmtarget(oop mname) { + +// Return vmtarget from ResolvedMethodName method field through indirection +Method* java_lang_invoke_MemberName::vmtarget(oop mname) { assert(is_instance(mname), "wrong type"); - return (Metadata*)mname->address_field(_vmtarget_offset); + oop method = mname->obj_field(_method_offset); + return method == NULL ? NULL : java_lang_invoke_ResolvedMethodName::vmtarget(method); } bool java_lang_invoke_MemberName::is_method(oop mname) { @@ -3205,32 +3216,9 @@ return (flags(mname) & (MN_IS_METHOD | MN_IS_CONSTRUCTOR)) > 0; } -void java_lang_invoke_MemberName::set_vmtarget(oop mname, Metadata* ref) { +void java_lang_invoke_MemberName::set_method(oop mname, oop resolved_method) { assert(is_instance(mname), "wrong type"); - // check the type of the vmtarget - oop dependency = NULL; - if (ref != NULL) { - switch (flags(mname) & (MN_IS_METHOD | - MN_IS_CONSTRUCTOR | - MN_IS_FIELD)) { - case MN_IS_METHOD: - case MN_IS_CONSTRUCTOR: - assert(ref->is_method(), "should be a method"); - dependency = ((Method*)ref)->method_holder()->java_mirror(); - break; - case MN_IS_FIELD: - assert(ref->is_klass(), "should be a class"); - dependency = ((Klass*)ref)->java_mirror(); - break; - default: - ShouldNotReachHere(); - } - } - mname->address_field_put(_vmtarget_offset, (address)ref); - // Add a reference to the loader (actually mirror because anonymous classes will not have - // distinct loaders) to ensure the metadata is kept alive - // This mirror may be different than the one in clazz field. - mname->obj_field_put(_vmloader_offset, dependency); + mname->obj_field_put(_method_offset, resolved_method); } intptr_t java_lang_invoke_MemberName::vmindex(oop mname) { @@ -3243,13 +3231,37 @@ mname->address_field_put(_vmindex_offset, (address) index); } -bool java_lang_invoke_MemberName::equals(oop mn1, oop mn2) { - if (mn1 == mn2) { - return true; + +Method* java_lang_invoke_ResolvedMethodName::vmtarget(oop resolved_method) { + assert(is_instance(resolved_method), "wrong type"); + Method* m = (Method*)resolved_method->address_field(_vmtarget_offset); + assert(m->is_method(), "must be"); + return m; +} + +// Used by redefinition to change Method* to new Method* with same hash (name, signature) +void java_lang_invoke_ResolvedMethodName::set_vmtarget(oop resolved_method, Method* m) { + assert(is_instance(resolved_method), "wrong type"); + resolved_method->address_field_put(_vmtarget_offset, (address)m); +} + +oop java_lang_invoke_ResolvedMethodName::find_resolved_method(const methodHandle& m, TRAPS) { + // lookup ResolvedMethod oop in the table, or create a new one and intern it + oop resolved_method = ResolvedMethodTable::find_method(m()); + if (resolved_method == NULL) { + InstanceKlass* k = SystemDictionary::ResolvedMethodName_klass(); + if (!k->is_initialized()) { + k->initialize(CHECK_NULL); + } + oop new_resolved_method = k->allocate_instance(CHECK_NULL); + new_resolved_method->address_field_put(_vmtarget_offset, (address)m()); + // Add a reference to the loader (actually mirror because anonymous classes will not have + // distinct loaders) to ensure the metadata is kept alive. + // This mirror may be different than the one in clazz field. + new_resolved_method->obj_field_put(_vmholder_offset, m->method_holder()->java_mirror()); + resolved_method = ResolvedMethodTable::add_method(Handle(THREAD, new_resolved_method)); } - return (vmtarget(mn1) == vmtarget(mn2) && flags(mn1) == flags(mn2) && - vmindex(mn1) == vmindex(mn2) && - clazz(mn1) == clazz(mn2)); + return resolved_method; } oop java_lang_invoke_LambdaForm::vmentry(oop lform) { @@ -3856,6 +3868,7 @@ java_lang_invoke_MethodHandle::compute_offsets(); java_lang_invoke_DirectMethodHandle::compute_offsets(); java_lang_invoke_MemberName::compute_offsets(); + java_lang_invoke_ResolvedMethodName::compute_offsets(); java_lang_invoke_LambdaForm::compute_offsets(); java_lang_invoke_MethodType::compute_offsets(); java_lang_invoke_CallSite::compute_offsets(); diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/classfile/javaClasses.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.hpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Sat May 27 09:21:01 2017 -0400 @@ -1005,10 +1005,33 @@ // Interface to java.lang.invoke.MemberName objects // (These are a private interface for Java code to query the class hierarchy.) +#define RESOLVEDMETHOD_INJECTED_FIELDS(macro) \ + macro(java_lang_invoke_ResolvedMethodName, vmholder, object_signature, false) \ + macro(java_lang_invoke_ResolvedMethodName, vmtarget, intptr_signature, false) + +class java_lang_invoke_ResolvedMethodName : AllStatic { + friend class JavaClasses; + + static int _vmtarget_offset; + static int _vmholder_offset; + + static void compute_offsets(); + public: + static int vmtarget_offset_in_bytes() { return _vmtarget_offset; } + + static Method* vmtarget(oop resolved_method); + static void set_vmtarget(oop resolved_method, Method* method); + + // find or create resolved member name + static oop find_resolved_method(const methodHandle& m, TRAPS); + + static bool is_instance(oop resolved_method); +}; + + #define MEMBERNAME_INJECTED_FIELDS(macro) \ - macro(java_lang_invoke_MemberName, vmloader, object_signature, false) \ - macro(java_lang_invoke_MemberName, vmindex, intptr_signature, false) \ - macro(java_lang_invoke_MemberName, vmtarget, intptr_signature, false) + macro(java_lang_invoke_MemberName, vmindex, intptr_signature, false) + class java_lang_invoke_MemberName: AllStatic { friend class JavaClasses; @@ -1019,14 +1042,13 @@ // private String name; // may be null if not yet materialized // private Object type; // may be null if not yet materialized // private int flags; // modifier bits; see reflect.Modifier - // private intptr vmtarget; // VM-specific target value + // private ResolvedMethodName method; // holds VM-specific target value // private intptr_t vmindex; // member index within class or interface static int _clazz_offset; static int _name_offset; static int _type_offset; static int _flags_offset; - static int _vmtarget_offset; - static int _vmloader_offset; + static int _method_offset; static int _vmindex_offset; static void compute_offsets(); @@ -1045,8 +1067,9 @@ static int flags(oop mname); static void set_flags(oop mname, int flags); - static Metadata* vmtarget(oop mname); - static void set_vmtarget(oop mname, Metadata* target); + // Link through ResolvedMethodName field to get Method* + static Method* vmtarget(oop mname); + static void set_method(oop mname, oop method); static intptr_t vmindex(oop mname); static void set_vmindex(oop mname, intptr_t index); @@ -1078,10 +1101,8 @@ static int type_offset_in_bytes() { return _type_offset; } static int name_offset_in_bytes() { return _name_offset; } static int flags_offset_in_bytes() { return _flags_offset; } - static int vmtarget_offset_in_bytes() { return _vmtarget_offset; } + static int method_offset_in_bytes() { return _method_offset; } static int vmindex_offset_in_bytes() { return _vmindex_offset; } - - static bool equals(oop mt1, oop mt2); }; @@ -1358,7 +1379,7 @@ public: // Setters static void set_declaringClass(oop info, oop value); - static void set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci); + static void set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci, TRAPS); static void set_bci(oop info, int value); static void set_version(oop info, short value); @@ -1472,6 +1493,7 @@ #define ALL_INJECTED_FIELDS(macro) \ CLASS_INJECTED_FIELDS(macro) \ CLASSLOADER_INJECTED_FIELDS(macro) \ + RESOLVEDMETHOD_INJECTED_FIELDS(macro) \ MEMBERNAME_INJECTED_FIELDS(macro) \ CALLSITECONTEXT_INJECTED_FIELDS(macro) \ STACKFRAMEINFO_INJECTED_FIELDS(macro) \ diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/classfile/javaClasses.inline.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp Sat May 27 09:21:01 2017 -0400 @@ -143,7 +143,11 @@ } inline bool java_lang_invoke_MemberName::is_instance(oop obj) { - return obj != NULL && is_subclass(obj->klass()); + return obj != NULL && obj->klass() == SystemDictionary::MemberName_klass(); +} + +inline bool java_lang_invoke_ResolvedMethodName::is_instance(oop obj) { + return obj != NULL && obj->klass() == SystemDictionary::ResolvedMethodName_klass(); } inline bool java_lang_invoke_MethodType::is_instance(oop obj) { diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Sat May 27 09:21:01 2017 -0400 @@ -42,8 +42,10 @@ #include "code/codeCache.hpp" #include "compiler/compileBroker.hpp" #include "gc/shared/gcLocker.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/interpreter.hpp" +#include "logging/log.hpp" #include "memory/filemap.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" @@ -57,6 +59,7 @@ #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" #include "prims/jvmtiEnvBase.hpp" +#include "prims/resolvedMethodTable.hpp" #include "prims/methodHandles.hpp" #include "runtime/arguments.hpp" #include "runtime/biasedLocking.hpp" @@ -1915,23 +1918,43 @@ // Assumes classes in the SystemDictionary are only unloaded at a safepoint // Note: anonymous classes are not in the SD. bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive, - bool clean_previous_versions) { - // First, mark for unload all ClassLoaderData referencing a dead class loader. - bool unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive, - clean_previous_versions); + GCTimer* gc_timer, + bool do_cleaning) { + + + bool unloading_occurred; + { + GCTraceTime(Debug, gc, phases) t("ClassLoaderData", gc_timer); + + // First, mark for unload all ClassLoaderData referencing a dead class loader. + unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive, + do_cleaning); + } + if (unloading_occurred) { + GCTraceTime(Debug, gc, phases) t("Dictionary", gc_timer); dictionary()->do_unloading(); constraints()->purge_loader_constraints(); resolution_errors()->purge_resolution_errors(); } - // Oops referenced by the system dictionary may get unreachable independently - // of the class loader (eg. cached protection domain oops). So we need to - // explicitly unlink them here instead of in Dictionary::do_unloading. - dictionary()->unlink(is_alive); + + { + GCTraceTime(Debug, gc, phases) t("ProtectionDomainCacheTable", gc_timer); + // Oops referenced by the system dictionary may get unreachable independently + // of the class loader (eg. cached protection domain oops). So we need to + // explicitly unlink them here instead of in Dictionary::do_unloading. + dictionary()->unlink(is_alive); #ifdef ASSERT - VerifySDReachableAndLiveClosure cl(is_alive); - dictionary()->oops_do(&cl); + VerifySDReachableAndLiveClosure cl(is_alive); + dictionary()->oops_do(&cl); #endif + } + + if (do_cleaning) { + GCTraceTime(Debug, gc, phases) t("ResolvedMethodTable", gc_timer); + ResolvedMethodTable::unlink(is_alive); + } + return unloading_occurred; } @@ -1945,6 +1968,10 @@ // Visit extra methods invoke_method_table()->oops_do(strong); + + if (weak != NULL) { + ResolvedMethodTable::oops_do(weak); + } } void SystemDictionary::oops_do(OopClosure* f) { @@ -1957,6 +1984,8 @@ // Visit extra methods invoke_method_table()->oops_do(f); + + ResolvedMethodTable::oops_do(f); } // Just the classes from defining class loaders @@ -2526,9 +2555,8 @@ TRAPS) { methodHandle empty; if (mname.not_null()) { - Metadata* vmtarget = java_lang_invoke_MemberName::vmtarget(mname()); - if (vmtarget != NULL && vmtarget->is_method()) { - Method* m = (Method*)vmtarget; + Method* m = java_lang_invoke_MemberName::vmtarget(mname()); + if (m != NULL) { oop appendix = appendix_box->obj_at(0); if (TraceMethodHandles) { #ifndef PRODUCT diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/classfile/systemDictionary.hpp --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Sat May 27 09:21:01 2017 -0400 @@ -78,6 +78,7 @@ template class HashtableBucket; class ResolutionErrorTable; class SymbolPropertyTable; +class GCTimer; // Certain classes are preloaded, such as java.lang.Object and java.lang.String. // They are all "well-known", in the sense that no class loader is allowed @@ -155,6 +156,7 @@ do_klass(MethodHandle_klass, java_lang_invoke_MethodHandle, Pre ) \ do_klass(VarHandle_klass, java_lang_invoke_VarHandle, Pre ) \ do_klass(MemberName_klass, java_lang_invoke_MemberName, Pre ) \ + do_klass(ResolvedMethodName_klass, java_lang_invoke_ResolvedMethodName, Pre ) \ do_klass(MethodHandleNatives_klass, java_lang_invoke_MethodHandleNatives, Pre ) \ do_klass(LambdaForm_klass, java_lang_invoke_LambdaForm, Opt ) \ do_klass(MethodType_klass, java_lang_invoke_MethodType, Pre ) \ @@ -366,7 +368,8 @@ // Unload (that is, break root links to) all unmarked classes and // loaders. Returns "true" iff something was unloaded. static bool do_unloading(BoolObjectClosure* is_alive, - bool clean_previous_versions = true); + GCTimer* gc_timer, + bool do_cleaning = true); // Used by DumpSharedSpaces only to remove classes that failed verification static void remove_classes_in_error_state(); diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/classfile/vmSymbols.hpp --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Sat May 27 09:21:01 2017 -0400 @@ -288,11 +288,13 @@ template(java_lang_invoke_VarHandle, "java/lang/invoke/VarHandle") \ template(java_lang_invoke_MethodType, "java/lang/invoke/MethodType") \ template(java_lang_invoke_MethodType_signature, "Ljava/lang/invoke/MethodType;") \ + template(java_lang_invoke_ResolvedMethodName_signature, "Ljava/lang/invoke/ResolvedMethodName;")\ template(java_lang_invoke_MemberName_signature, "Ljava/lang/invoke/MemberName;") \ template(java_lang_invoke_LambdaForm_signature, "Ljava/lang/invoke/LambdaForm;") \ template(java_lang_invoke_MethodHandle_signature, "Ljava/lang/invoke/MethodHandle;") \ /* internal classes known only to the JVM: */ \ template(java_lang_invoke_MemberName, "java/lang/invoke/MemberName") \ + template(java_lang_invoke_ResolvedMethodName, "java/lang/invoke/ResolvedMethodName") \ template(java_lang_invoke_MethodHandleNatives, "java/lang/invoke/MethodHandleNatives") \ template(java_lang_invoke_MethodHandleNatives_CallSiteContext, "java/lang/invoke/MethodHandleNatives$CallSiteContext") \ template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \ @@ -413,8 +415,8 @@ template(values_name, "values") \ template(receiver_name, "receiver") \ template(vmtarget_name, "vmtarget") \ - template(next_target_name, "next_target") \ - template(vmloader_name, "vmloader") \ + template(vmholder_name, "vmholder") \ + template(method_name, "method") \ template(vmindex_name, "vmindex") \ template(vmcount_name, "vmcount") \ template(vmentry_name, "vmentry") \ diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Sat May 27 09:21:01 2017 -0400 @@ -5232,7 +5232,7 @@ GCTraceTime(Debug, gc, phases) t("Class Unloading", _gc_timer_cm); // Unload classes and purge the SystemDictionary. - bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure); + bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure, _gc_timer_cm); // Unload nmethods. CodeCache::do_unloading(&_is_alive_closure, purged_class); @@ -5254,7 +5254,6 @@ } } - // Restore any preserved marks as a result of mark stack or // work queue overflow restore_preserved_marks_if_any(); // done single-threaded for now diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Sat May 27 09:21:01 2017 -0400 @@ -74,6 +74,7 @@ #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" +#include "prims/resolvedMethodTable.hpp" #include "runtime/atomic.hpp" #include "runtime/init.hpp" #include "runtime/orderAccess.inline.hpp" @@ -3843,12 +3844,36 @@ } }; +class G1ResolvedMethodCleaningTask : public StackObj { + BoolObjectClosure* _is_alive; + volatile jint _resolved_method_task_claimed; +public: + G1ResolvedMethodCleaningTask(BoolObjectClosure* is_alive) : + _is_alive(is_alive), _resolved_method_task_claimed(0) {} + + bool claim_resolved_method_task() { + if (_resolved_method_task_claimed) { + return false; + } + return Atomic::cmpxchg(1, (jint*)&_resolved_method_task_claimed, 0) == 0; + } + + // These aren't big, one thread can do it all. + void work() { + if (claim_resolved_method_task()) { + ResolvedMethodTable::unlink(_is_alive); + } + } +}; + + // To minimize the remark pause times, the tasks below are done in parallel. class G1ParallelCleaningTask : public AbstractGangTask { private: G1StringAndSymbolCleaningTask _string_symbol_task; G1CodeCacheUnloadingTask _code_cache_task; G1KlassCleaningTask _klass_cleaning_task; + G1ResolvedMethodCleaningTask _resolved_method_cleaning_task; public: // The constructor is run in the VMThread. @@ -3856,7 +3881,8 @@ AbstractGangTask("Parallel Cleaning"), _string_symbol_task(is_alive, true, true, G1StringDedup::is_enabled()), _code_cache_task(num_workers, is_alive, unloading_occurred), - _klass_cleaning_task(is_alive) { + _klass_cleaning_task(is_alive), + _resolved_method_cleaning_task(is_alive) { } // The parallel work done by all worker threads. @@ -3870,6 +3896,9 @@ // Clean the Strings and Symbols. _string_symbol_task.work(worker_id); + // Clean unreferenced things in the ResolvedMethodTable + _resolved_method_cleaning_task.work(); + // Wait for all workers to finish the first code cache cleaning pass. _code_cache_task.barrier_wait(worker_id); diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Sat May 27 09:21:01 2017 -0400 @@ -1752,7 +1752,7 @@ // Unload Klasses, String, Symbols, Code Cache, etc. if (ClassUnloadingWithConcurrentMark) { GCTraceTime(Debug, gc, phases) debug("Class Unloading", _gc_timer_cm); - bool purged_classes = SystemDictionary::do_unloading(&g1_is_alive, false /* Defer klass cleaning */); + bool purged_classes = SystemDictionary::do_unloading(&g1_is_alive, _gc_timer_cm, false /* Defer cleaning */); g1h->complete_cleaning(&g1_is_alive, purged_classes); } else { GCTraceTime(Debug, gc, phases) debug("Cleanup", _gc_timer_cm); diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp --- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Sat May 27 09:21:01 2017 -0400 @@ -165,7 +165,7 @@ GCTraceTime(Debug, gc, phases) trace("Class Unloading", gc_timer()); // Unload classes and purge the SystemDictionary. - bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive); + bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive, gc_timer()); g1h->complete_cleaning(&GenMarkSweep::is_alive, purged_class); } else { diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp --- a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Sat May 27 09:21:01 2017 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -540,7 +540,7 @@ GCTraceTime(Debug, gc, phases) t("Class Unloading", _gc_timer); // Unload classes and purge the SystemDictionary. - bool purged_class = SystemDictionary::do_unloading(is_alive_closure()); + bool purged_class = SystemDictionary::do_unloading(is_alive_closure(), _gc_timer); // Unload nmethods. CodeCache::do_unloading(is_alive_closure(), purged_class); diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp --- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Sat May 27 09:21:01 2017 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2120,7 +2120,7 @@ GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", &_gc_timer); // Follow system dictionary roots and unload classes. - bool purged_class = SystemDictionary::do_unloading(is_alive_closure()); + bool purged_class = SystemDictionary::do_unloading(is_alive_closure(), &_gc_timer); // Unload nmethods. CodeCache::do_unloading(is_alive_closure(), purged_class); diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/gc/serial/genMarkSweep.cpp --- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Sat May 27 09:21:01 2017 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -223,7 +223,7 @@ GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", gc_timer()); // Unload classes and purge the SystemDictionary. - bool purged_class = SystemDictionary::do_unloading(&is_alive); + bool purged_class = SystemDictionary::do_unloading(&is_alive, gc_timer()); // Unload nmethods. CodeCache::do_unloading(&is_alive, purged_class); diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/interpreter/linkResolver.cpp --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Sat May 27 09:21:01 2017 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/defaultMethods.hpp" +#include "classfile/javaClasses.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -131,7 +132,7 @@ } // utility query for unreflecting a method -CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass) { +CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass, TRAPS) { Klass* resolved_method_holder = resolved_method->method_holder(); if (resolved_klass == NULL) { // 2nd argument defaults to holder of 1st resolved_klass = resolved_method_holder; @@ -180,9 +181,19 @@ _call_kind = kind; _call_index = index; _resolved_appendix = Handle(); + // Find or create a ResolvedMethod instance for this Method* + set_resolved_method_name(CHECK); + DEBUG_ONLY(verify()); } +void CallInfo::set_resolved_method_name(TRAPS) { + Method* m = _resolved_method(); + assert(m != NULL, "Should already have a Method*"); + oop rmethod_name = java_lang_invoke_ResolvedMethodName::find_resolved_method(m, CHECK); + _resolved_method_name = Handle(THREAD, rmethod_name); +} + #ifdef ASSERT void CallInfo::verify() { switch (call_kind()) { // the meaning and allowed value of index depends on kind diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/interpreter/linkResolver.hpp --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp Sat May 27 09:21:01 2017 -0400 @@ -56,6 +56,7 @@ int _call_index; // vtable or itable index of selected class method (if any) Handle _resolved_appendix; // extra argument in constant pool (if CPCE::has_appendix) Handle _resolved_method_type; // MethodType (for invokedynamic and invokehandle call sites) + Handle _resolved_method_name; // Object holding the ResolvedMethodName void set_static(Klass* resolved_klass, const methodHandle& resolved_method, TRAPS); void set_interface(Klass* resolved_klass, Klass* selected_klass, @@ -88,8 +89,9 @@ } // utility to extract an effective CallInfo from a method and an optional receiver limit - // does not queue the method for compilation - CallInfo(Method* resolved_method, Klass* resolved_klass = NULL); + // does not queue the method for compilation. This also creates a ResolvedMethodName + // object for the resolved_method. + CallInfo(Method* resolved_method, Klass* resolved_klass, TRAPS); Klass* resolved_klass() const { return _resolved_klass; } Klass* selected_klass() const { return _selected_klass; } @@ -97,6 +99,9 @@ methodHandle selected_method() const { return _selected_method; } Handle resolved_appendix() const { return _resolved_appendix; } Handle resolved_method_type() const { return _resolved_method_type; } + Handle resolved_method_name() const { return _resolved_method_name; } + // Materialize a java.lang.invoke.ResolvedMethodName for this resolved_method + void set_resolved_method_name(TRAPS); BasicType result_type() const { return selected_method()->result_type(); } CallKind call_kind() const { return _call_kind; } diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp Sat May 27 09:21:01 2017 -0400 @@ -668,7 +668,7 @@ oop base_object = JNIHandles::resolve(base); if (base_object == NULL) { method = *((Method**)(offset)); - } else if (base_object->is_a(SystemDictionary::MemberName_klass())) { + } else if (base_object->is_a(SystemDictionary::ResolvedMethodName_klass())) { method = (Method*) (intptr_t) base_object->long_field(offset); } else if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { method = *((Method**)(HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object) + offset)); diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/logging/logTag.hpp --- a/hotspot/src/share/vm/logging/logTag.hpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/logging/logTag.hpp Sat May 27 09:21:01 2017 -0400 @@ -83,6 +83,7 @@ LOG_TAG(logging) \ LOG_TAG(mark) \ LOG_TAG(marking) \ + LOG_TAG(membername) \ LOG_TAG(memops) \ LOG_TAG(methodcomparator) \ LOG_TAG(metadata) \ @@ -128,6 +129,7 @@ LOG_TAG(subclass) \ LOG_TAG(survivor) \ LOG_TAG(sweep) \ + LOG_TAG(table) \ LOG_TAG(task) \ DEBUG_ONLY(LOG_TAG(test)) \ LOG_TAG(thread) \ diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/memory/universe.cpp --- a/hotspot/src/share/vm/memory/universe.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/memory/universe.cpp Sat May 27 09:21:01 2017 -0400 @@ -56,6 +56,7 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayKlass.hpp" +#include "prims/resolvedMethodTable.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" #include "runtime/commandLineFlagConstraintList.hpp" @@ -686,6 +687,8 @@ Universe::initialize_verify_flags(); } + ResolvedMethodTable::create_table(); + return JNI_OK; } diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Sat May 27 09:21:01 2017 -0400 @@ -2131,17 +2131,6 @@ FreeHeap(jmeths); } - // Deallocate MemberNameTable - { - Mutex* lock_or_null = SafepointSynchronize::is_at_safepoint() ? NULL : MemberNameTable_lock; - MutexLockerEx ml(lock_or_null, Mutex::_no_safepoint_check_flag); - MemberNameTable* mnt = member_names(); - if (mnt != NULL) { - delete mnt; - set_member_names(NULL); - } - } - // Release dependencies. // It is desirable to use DC::remove_all_dependents() here, but, unfortunately, // it is not safe (see JDK-8143408). The problem is that the klass dependency @@ -2770,32 +2759,6 @@ return NULL; } -oop InstanceKlass::add_member_name(Handle mem_name, bool intern) { - jweak mem_name_wref = JNIHandles::make_weak_global(mem_name); - MutexLocker ml(MemberNameTable_lock); - DEBUG_ONLY(NoSafepointVerifier nsv); - - // Check if method has been redefined while taking out MemberNameTable_lock, if so - // return false. We cannot cache obsolete methods. They will crash when the function - // is called! - Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(mem_name()); - if (method->is_obsolete()) { - return NULL; - } else if (method->is_old()) { - // Replace method with redefined version - java_lang_invoke_MemberName::set_vmtarget(mem_name(), method_with_idnum(method->method_idnum())); - } - - if (_member_names == NULL) { - _member_names = new (ResourceObj::C_HEAP, mtClass) MemberNameTable(idnum_allocated_count()); - } - if (intern) { - return _member_names->find_or_add_member_name(mem_name_wref); - } else { - return _member_names->add_member_name(mem_name_wref); - } -} - // ----------------------------------------------------------------------------------------------------- // Printing diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Sat May 27 09:21:01 2017 -0400 @@ -66,7 +66,6 @@ class jniIdMapBase; class JNIid; class JvmtiCachedClassFieldMap; -class MemberNameTable; class SuperTypeClosure; // This is used in iterators below. @@ -219,7 +218,8 @@ _misc_is_scratch_class = 1 << 11, // class is the redefined scratch class _misc_is_shared_boot_class = 1 << 12, // defining class loader is boot class loader _misc_is_shared_platform_class = 1 << 13, // defining class loader is platform class loader - _misc_is_shared_app_class = 1 << 14 // defining class loader is app class loader + _misc_is_shared_app_class = 1 << 14, // defining class loader is app class loader + _misc_has_resolved_methods = 1 << 15 // resolved methods table entries added for this class }; u2 loader_type_bits() { return _misc_is_shared_boot_class|_misc_is_shared_platform_class|_misc_is_shared_app_class; @@ -229,7 +229,6 @@ u2 _major_version; // major version number of class file Thread* _init_thread; // Pointer to current thread doing initialization (to handle recusive initialization) OopMapCache* volatile _oop_map_cache; // OopMapCache for all methods in the klass (allocated lazily) - MemberNameTable* _member_names; // Member names JNIid* _jni_ids; // First JNI identifier for static fields in this class jmethodID* volatile _methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or NULL if none intptr_t _dep_context; // packed DependencyContext structure @@ -747,6 +746,13 @@ _misc_flags |= _misc_is_scratch_class; } + bool has_resolved_methods() const { + return (_misc_flags & _misc_has_resolved_methods) != 0; + } + + void set_has_resolved_methods() { + _misc_flags |= _misc_has_resolved_methods; + } private: void set_kind(unsigned kind) { @@ -1334,11 +1340,6 @@ // jvm support jint compute_modifier_flags(TRAPS) const; - // JSR-292 support - MemberNameTable* member_names() { return _member_names; } - void set_member_names(MemberNameTable* member_names) { _member_names = member_names; } - oop add_member_name(Handle member_name, bool intern); - public: // JVMTI support jint jvmti_class_status() const; diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/prims/jvm.cpp --- a/hotspot/src/share/vm/prims/jvm.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/prims/jvm.cpp Sat May 27 09:21:01 2017 -0400 @@ -673,21 +673,6 @@ bs->write_region(MemRegion((HeapWord*)new_obj_oop, size)); Handle new_obj(THREAD, new_obj_oop); - // Special handling for MemberNames. Since they contain Method* metadata, they - // must be registered so that RedefineClasses can fix metadata contained in them. - if (java_lang_invoke_MemberName::is_instance(new_obj()) && - java_lang_invoke_MemberName::is_method(new_obj())) { - Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(new_obj()); - // MemberName may be unresolved, so doesn't need registration until resolved. - if (method != NULL) { - methodHandle m(THREAD, method); - // This can safepoint and redefine method, so need both new_obj and method - // in a handle, for two different reasons. new_obj can move, method can be - // deleted if nothing is using it on the stack. - m->method_holder()->add_member_name(new_obj, false); - } - } - // Caution: this involves a java upcall, so the clone should be // "gc-robust" by this stage. if (klass->has_finalizer()) { diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Sat May 27 09:21:01 2017 -0400 @@ -43,6 +43,7 @@ #include "oops/oop.inline.hpp" #include "prims/jvmtiImpl.hpp" #include "prims/jvmtiRedefineClasses.hpp" +#include "prims/resolvedMethodTable.hpp" #include "prims/methodComparator.hpp" #include "runtime/deoptimization.hpp" #include "runtime/relocator.hpp" @@ -67,6 +68,7 @@ _class_count = class_count; _class_defs = class_defs; _class_load_kind = class_load_kind; + _any_class_has_resolved_methods = false; _res = JVMTI_ERROR_NONE; } @@ -201,6 +203,12 @@ MethodDataCleaner clean_weak_method_links; ClassLoaderDataGraph::classes_do(&clean_weak_method_links); + // JSR-292 support + if (_any_class_has_resolved_methods) { + bool trace_name_printed = false; + ResolvedMethodTable::adjust_method_entries(&trace_name_printed); + } + // Disable any dependent concurrent compilations SystemDictionary::notice_modification(); @@ -3823,6 +3831,8 @@ compute_added_deleted_matching_methods(); update_jmethod_ids(); + _any_class_has_resolved_methods = the_class->has_resolved_methods() || _any_class_has_resolved_methods; + // Attach new constant pool to the original klass. The original // klass still refers to the old constant pool (for now). scratch_class->constants()->set_pool_holder(the_class); @@ -4037,13 +4047,6 @@ AdjustCpoolCacheAndVtable adjust_cpool_cache_and_vtable(THREAD); ClassLoaderDataGraph::classes_do(&adjust_cpool_cache_and_vtable); - // JSR-292 support - MemberNameTable* mnt = the_class->member_names(); - if (mnt != NULL) { - bool trace_name_printed = false; - mnt->adjust_method_entries(the_class, &trace_name_printed); - } - if (the_class->oop_map_cache() != NULL) { // Flush references to any obsolete methods from the oop map cache // so that obsolete methods are not pinned. diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Sat May 27 09:21:01 2017 -0400 @@ -374,6 +374,11 @@ InstanceKlass** _scratch_classes; jvmtiError _res; + // Set if any of the InstanceKlasses have entries in the ResolvedMethodTable + // to avoid walking after redefinition if the redefined classes do not + // have any entries. + bool _any_class_has_resolved_methods; + // Performance measurement support. These timers do not cover all // the work done for JVM/TI RedefineClasses() but they do cover // the heavy lifting. diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/prims/methodHandles.cpp --- a/hotspot/src/share/vm/prims/methodHandles.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/prims/methodHandles.cpp Sat May 27 09:21:01 2017 -0400 @@ -122,14 +122,7 @@ ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE }; -Handle MethodHandles::new_MemberName(TRAPS) { - Handle empty; - InstanceKlass* k = SystemDictionary::MemberName_klass(); - if (!k->is_initialized()) k->initialize(CHECK_(empty)); - return Handle(THREAD, k->allocate_instance(THREAD)); -} - -oop MethodHandles::init_MemberName(Handle mname, Handle target) { +oop MethodHandles::init_MemberName(Handle mname, Handle target, TRAPS) { // This method is used from java.lang.invoke.MemberName constructors. // It fills in the new MemberName from a java.lang.reflect.Member. Thread* thread = Thread::current(); @@ -159,7 +152,7 @@ Method* m = InstanceKlass::cast(k)->method_with_idnum(slot); if (m == NULL || is_signature_polymorphic(m->intrinsic_id())) return NULL; // do not resolve unless there is a concrete signature - CallInfo info(m, k); + CallInfo info(m, k, CHECK_NULL); return init_method_MemberName(mname, info); } } else if (target_klass == SystemDictionary::reflect_Constructor_klass()) { @@ -169,14 +162,14 @@ if (k != NULL && k->is_instance_klass()) { Method* m = InstanceKlass::cast(k)->method_with_idnum(slot); if (m == NULL) return NULL; - CallInfo info(m, k); + CallInfo info(m, k, CHECK_NULL); return init_method_MemberName(mname, info); } } return NULL; } -oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info, bool intern) { +oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) { assert(info.resolved_appendix().is_null(), "only normal methods here"); methodHandle m = info.resolved_method(); assert(m.not_null(), "null method handle"); @@ -265,32 +258,35 @@ flags |= CALLER_SENSITIVE; } + Handle resolved_method = info.resolved_method_name(); + assert(java_lang_invoke_ResolvedMethodName::vmtarget(resolved_method()) == m(), + "Should not change after link resolultion"); + oop mname_oop = mname(); - java_lang_invoke_MemberName::set_flags( mname_oop, flags); - java_lang_invoke_MemberName::set_vmtarget(mname_oop, m()); - java_lang_invoke_MemberName::set_vmindex( mname_oop, vmindex); // vtable/itable index - java_lang_invoke_MemberName::set_clazz( mname_oop, m_klass->java_mirror()); + java_lang_invoke_MemberName::set_flags (mname_oop, flags); + java_lang_invoke_MemberName::set_method (mname_oop, resolved_method()); + java_lang_invoke_MemberName::set_vmindex(mname_oop, vmindex); // vtable/itable index + java_lang_invoke_MemberName::set_clazz (mname_oop, m_klass->java_mirror()); // Note: name and type can be lazily computed by resolve_MemberName, // if Java code needs them as resolved String and MethodType objects. - // The clazz must be eagerly stored, because it provides a GC - // root to help keep alive the Method*. // If relevant, the vtable or itable value is stored as vmindex. // This is done eagerly, since it is readily available without // constructing any new objects. - return m->method_holder()->add_member_name(mname, intern); + return mname(); } oop MethodHandles::init_field_MemberName(Handle mname, fieldDescriptor& fd, bool is_setter) { int flags = (jushort)( fd.access_flags().as_short() & JVM_RECOGNIZED_FIELD_MODIFIERS ); flags |= IS_FIELD | ((fd.is_static() ? JVM_REF_getStatic : JVM_REF_getField) << REFERENCE_KIND_SHIFT); if (is_setter) flags += ((JVM_REF_putField - JVM_REF_getField) << REFERENCE_KIND_SHIFT); - Metadata* vmtarget = fd.field_holder(); int vmindex = fd.offset(); // determines the field uniquely when combined with static bit + oop mname_oop = mname(); - java_lang_invoke_MemberName::set_flags(mname_oop, flags); - java_lang_invoke_MemberName::set_vmtarget(mname_oop, vmtarget); - java_lang_invoke_MemberName::set_vmindex(mname_oop, vmindex); - java_lang_invoke_MemberName::set_clazz(mname_oop, fd.field_holder()->java_mirror()); + java_lang_invoke_MemberName::set_flags (mname_oop, flags); + java_lang_invoke_MemberName::set_method (mname_oop, NULL); + java_lang_invoke_MemberName::set_vmindex(mname_oop, vmindex); + java_lang_invoke_MemberName::set_clazz (mname_oop, fd.field_holder()->java_mirror()); + oop type = field_signature_type_or_null(fd.signature()); oop name = field_name_or_null(fd.name()); if (name != NULL) @@ -745,6 +741,7 @@ // Caller is responsible to prevent this from happening. THROW_MSG_(vmSymbols::java_lang_InternalError(), "appendix", empty); } + result.set_resolved_method_name(CHECK_(empty)); oop mname2 = init_method_MemberName(mname, result); return Handle(THREAD, mname2); } @@ -764,6 +761,7 @@ } } assert(result.is_statically_bound(), ""); + result.set_resolved_method_name(CHECK_(empty)); oop mname2 = init_method_MemberName(mname, result); return Handle(THREAD, mname2); } @@ -794,11 +792,6 @@ // which refers directly to JVM internals. void MethodHandles::expand_MemberName(Handle mname, int suppress, TRAPS) { assert(java_lang_invoke_MemberName::is_instance(mname()), ""); - Metadata* vmtarget = java_lang_invoke_MemberName::vmtarget(mname()); - int vmindex = java_lang_invoke_MemberName::vmindex(mname()); - if (vmtarget == NULL) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "nothing to expand"); - } bool have_defc = (java_lang_invoke_MemberName::clazz(mname()) != NULL); bool have_name = (java_lang_invoke_MemberName::name(mname()) != NULL); @@ -817,10 +810,12 @@ case IS_METHOD: case IS_CONSTRUCTOR: { - assert(vmtarget->is_method(), "method or constructor vmtarget is Method*"); - methodHandle m(THREAD, (Method*)vmtarget); + Method* vmtarget = java_lang_invoke_MemberName::vmtarget(mname()); + if (vmtarget == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "nothing to expand"); + } + methodHandle m(THREAD, vmtarget); DEBUG_ONLY(vmtarget = NULL); // safety - if (m.is_null()) break; if (!have_defc) { InstanceKlass* defc = m->method_holder(); java_lang_invoke_MemberName::set_clazz(mname(), defc->java_mirror()); @@ -838,17 +833,17 @@ } case IS_FIELD: { - assert(vmtarget->is_klass(), "field vmtarget is Klass*"); - if (!((Klass*) vmtarget)->is_instance_klass()) break; - InstanceKlass* defc = InstanceKlass::cast((Klass*) vmtarget); - DEBUG_ONLY(vmtarget = NULL); // safety + oop clazz = java_lang_invoke_MemberName::clazz(mname()); + if (clazz == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "nothing to expand (as field)"); + } + InstanceKlass* defc = InstanceKlass::cast(java_lang_Class::as_Klass(clazz)); + DEBUG_ONLY(clazz = NULL); // safety + int vmindex = java_lang_invoke_MemberName::vmindex(mname()); bool is_static = ((flags & JVM_ACC_STATIC) != 0); fieldDescriptor fd; // find_field initializes fd if found if (!defc->find_field_from_offset(vmindex, is_static, &fd)) break; // cannot expand - if (!have_defc) { - java_lang_invoke_MemberName::set_clazz(mname(), defc->java_mirror()); - } if (!have_name) { //not java_lang_String::create_from_symbol; let's intern member names oop name = StringTable::intern(fd.name(), CHECK); @@ -871,7 +866,7 @@ int MethodHandles::find_MemberNames(Klass* k, Symbol* name, Symbol* sig, int mflags, Klass* caller, - int skip, objArrayHandle results) { + int skip, objArrayHandle results, TRAPS) { // %%% take caller into account! Thread* thread = Thread::current(); @@ -968,10 +963,8 @@ Handle result(thread, results->obj_at(rfill++)); if (!java_lang_invoke_MemberName::is_instance(result())) return -99; // caller bug! - CallInfo info(m); - // Since this is going through the methods to create MemberNames, don't search - // for matching methods already in the table - oop saved = MethodHandles::init_method_MemberName(result, info, /*intern*/false); + CallInfo info(m, NULL, CHECK_0); + oop saved = MethodHandles::init_method_MemberName(result, info); if (saved != result()) results->obj_at_put(rfill-1, saved); // show saved instance to user } else if (++overflow >= overflow_limit) { @@ -1033,95 +1026,6 @@ } } -//------------------------------------------------------------------------------ -// MemberNameTable -// - -MemberNameTable::MemberNameTable(int methods_cnt) - : GrowableArray(methods_cnt, true) { - assert_locked_or_safepoint(MemberNameTable_lock); -} - -MemberNameTable::~MemberNameTable() { - assert_locked_or_safepoint(MemberNameTable_lock); - int len = this->length(); - - for (int idx = 0; idx < len; idx++) { - jweak ref = this->at(idx); - JNIHandles::destroy_weak_global(ref); - } -} - -oop MemberNameTable::add_member_name(jweak mem_name_wref) { - assert_locked_or_safepoint(MemberNameTable_lock); - this->push(mem_name_wref); - return JNIHandles::resolve(mem_name_wref); -} - -oop MemberNameTable::find_or_add_member_name(jweak mem_name_wref) { - assert_locked_or_safepoint(MemberNameTable_lock); - oop new_mem_name = JNIHandles::resolve(mem_name_wref); - - // Find matching member name in the list. - // This is linear because these are short lists. - int len = this->length(); - int new_index = len; - for (int idx = 0; idx < len; idx++) { - oop mname = JNIHandles::resolve(this->at(idx)); - if (mname == NULL) { - new_index = idx; - continue; - } - if (java_lang_invoke_MemberName::equals(new_mem_name, mname)) { - JNIHandles::destroy_weak_global(mem_name_wref); - return mname; - } - } - // Not found, push the new one, or reuse empty slot - this->at_put_grow(new_index, mem_name_wref); - return new_mem_name; -} - -#if INCLUDE_JVMTI -// It is called at safepoint only for RedefineClasses -void MemberNameTable::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) { - assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); - // For each redefined method - for (int idx = 0; idx < length(); idx++) { - oop mem_name = JNIHandles::resolve(this->at(idx)); - if (mem_name == NULL) { - continue; - } - Method* old_method = (Method*)java_lang_invoke_MemberName::vmtarget(mem_name); - - if (old_method == NULL || !old_method->is_old()) { - continue; // skip uninteresting entries - } - if (old_method->is_deleted()) { - // skip entries with deleted methods - continue; - } - Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); - - assert(new_method != NULL, "method_with_idnum() should not be NULL"); - assert(old_method != new_method, "sanity check"); - - java_lang_invoke_MemberName::set_vmtarget(mem_name, new_method); - - if (log_is_enabled(Info, redefine, class, update)) { - ResourceMark rm; - if (!(*trace_name_printed)) { - log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name()); - *trace_name_printed = true; - } - log_debug(redefine, class, update, constantpool) - ("MemberName method update: %s(%s)", - new_method->name()->as_C_string(), new_method->signature()->as_C_string()); - } - } -} -#endif // INCLUDE_JVMTI - // // Here are the native methods in java.lang.invoke.MethodHandleNatives // They are the private interface between this JVM and the HotSpot-specific @@ -1201,7 +1105,7 @@ if (target_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); } Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); Handle target(THREAD, JNIHandles::resolve_non_null(target_jh)); - MethodHandles::init_MemberName(mname, target); + MethodHandles::init_MemberName(mname, target, CHECK); } JVM_END @@ -1266,7 +1170,7 @@ static jlong find_member_field_offset(oop mname, bool must_be_static, TRAPS) { if (mname == NULL || - java_lang_invoke_MemberName::vmtarget(mname) == NULL) { + java_lang_invoke_MemberName::clazz(mname) == NULL) { THROW_MSG_0(vmSymbols::java_lang_InternalError(), "mname not resolved"); } else { int flags = java_lang_invoke_MemberName::flags(mname); @@ -1305,17 +1209,17 @@ if (mname_jh == NULL) return NULL; Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); intptr_t vmindex = java_lang_invoke_MemberName::vmindex(mname()); - Metadata* vmtarget = java_lang_invoke_MemberName::vmtarget(mname()); objArrayHandle result = oopFactory::new_objArray_handle(SystemDictionary::Object_klass(), 2, CHECK_NULL); jvalue vmindex_value; vmindex_value.j = (long)vmindex; oop x = java_lang_boxing_object::create(T_LONG, &vmindex_value, CHECK_NULL); result->obj_at_put(0, x); - x = NULL; - if (vmtarget == NULL) { - x = NULL; - } else if (vmtarget->is_klass()) { - x = ((Klass*) vmtarget)->java_mirror(); - } else if (vmtarget->is_method()) { + + int flags = java_lang_invoke_MemberName::flags(mname()); + if ((flags & IS_FIELD) != 0) { + x = java_lang_invoke_MemberName::clazz(mname()); + } else { + Method* vmtarget = java_lang_invoke_MemberName::vmtarget(mname()); + assert(vmtarget != NULL && vmtarget->is_method(), "vmtarget is only method"); x = mname(); } result->obj_at_put(1, x); @@ -1360,7 +1264,7 @@ } int res = MethodHandles::find_MemberNames(k, name, sig, mflags, - caller, skip, results); + caller, skip, results, CHECK_0); // TO DO: expand at least some of the MemberNames, to avoid massive callbacks return res; } diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/prims/methodHandles.hpp --- a/hotspot/src/share/vm/prims/methodHandles.hpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/prims/methodHandles.hpp Sat May 27 09:21:01 2017 -0400 @@ -63,14 +63,13 @@ // working with member names static Handle resolve_MemberName(Handle mname, Klass* caller, TRAPS); // compute vmtarget/vmindex from name/type static void expand_MemberName(Handle mname, int suppress, TRAPS); // expand defc/name/type if missing - static Handle new_MemberName(TRAPS); // must be followed by init_MemberName - static oop init_MemberName(Handle mname_h, Handle target_h); // compute vmtarget/vmindex from target + static oop init_MemberName(Handle mname_h, Handle target_h, TRAPS); // compute vmtarget/vmindex from target static oop init_field_MemberName(Handle mname_h, fieldDescriptor& fd, bool is_setter = false); - static oop init_method_MemberName(Handle mname_h, CallInfo& info, bool intern = true); + static oop init_method_MemberName(Handle mname_h, CallInfo& info); static int method_ref_kind(Method* m, bool do_dispatch_if_possible = true); static int find_MemberNames(Klass* k, Symbol* name, Symbol* sig, int mflags, Klass* caller, - int skip, objArrayHandle results); + int skip, objArrayHandle results, TRAPS); // bit values for suppress argument to expand_MemberName: enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 }; @@ -227,22 +226,4 @@ void generate(); }; -//------------------------------------------------------------------------------ -// MemberNameTable -// - -class MemberNameTable : public GrowableArray { - public: - MemberNameTable(int methods_cnt); - ~MemberNameTable(); - oop add_member_name(jweak mem_name_ref); - oop find_or_add_member_name(jweak mem_name_ref); - -#if INCLUDE_JVMTI - // RedefineClasses() API support: - // If a MemberName refers to old_method then update it to refer to new_method. - void adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed); -#endif // INCLUDE_JVMTI -}; - #endif // SHARE_VM_PRIMS_METHODHANDLES_HPP diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/prims/resolvedMethodTable.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/prims/resolvedMethodTable.cpp Sat May 27 09:21:01 2017 -0400 @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/shared/gcLocker.hpp" +#include "memory/allocation.hpp" +#include "oops/oop.inline.hpp" +#include "oops/method.hpp" +#include "oops/symbol.hpp" +#include "prims/resolvedMethodTable.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/mutexLocker.hpp" +#include "utilities/hashtable.inline.hpp" +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS +#include "gc/g1/g1SATBCardTableModRefBS.hpp" +#endif + + +ResolvedMethodTable::ResolvedMethodTable() + : Hashtable(_table_size, sizeof(ResolvedMethodEntry)) { } + +oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) { + for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) { + if (p->hash() == hash) { + oop target = p->literal(); + // The method is in the table as a target already + if (java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) { + ResourceMark rm; + log_debug(membername, table) ("ResolvedMethod entry found for %s index %d", + method->name_and_sig_as_C_string(), index); + return target; + } + } + } + return NULL; +} + +unsigned int ResolvedMethodTable::compute_hash(Method* method) { + unsigned int name_hash = method->name()->identity_hash(); + unsigned int signature_hash = method->signature()->identity_hash(); + return name_hash ^ signature_hash; +} + + +oop ResolvedMethodTable::lookup(Method* method) { + unsigned int hash = compute_hash(method); + int index = hash_to_index(hash); + return lookup(index, hash, method); +} + +// Tell the GC that this oop was looked up in the table +static void ensure_oop_alive(oop mname) { + // A lookup in the ResolvedMethodTable could return an object that was previously + // considered dead. The SATB part of G1 needs to get notified about this + // potential resurrection, otherwise the marking might not find the object. +#if INCLUDE_ALL_GCS + if (UseG1GC && mname != NULL) { + G1SATBCardTableModRefBS::enqueue(mname); + } +#endif +} + +oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) { + assert_locked_or_safepoint(ResolvedMethodTable_lock); + + unsigned int hash = compute_hash(method); + int index = hash_to_index(hash); + + // One was added while aquiring the lock + oop entry = lookup(index, hash, method); + if (entry != NULL) { + ensure_oop_alive(entry); + return entry; + } + + ResolvedMethodEntry* p = (ResolvedMethodEntry*) Hashtable::new_entry(hash, rmethod_name); + Hashtable::add_entry(index, p); + ResourceMark rm; + log_debug(membername, table) ("ResolvedMethod entry added for %s index %d", + method->name_and_sig_as_C_string(), index); + return p->literal(); +} + +ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL; + +oop ResolvedMethodTable::find_method(Method* method) { + oop entry = _the_table->lookup(method); + ensure_oop_alive(entry); + return entry; +} + +oop ResolvedMethodTable::add_method(Handle resolved_method_name) { + MutexLocker ml(ResolvedMethodTable_lock); + DEBUG_ONLY(NoSafepointVerifier nsv); + + // Check if method has been redefined while taking out ResolvedMethodTable_lock, if so + // use new method. + Method* method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(resolved_method_name()); + assert(method->is_method(), "must be method"); + if (method->is_old()) { + // Replace method with redefined version + InstanceKlass* holder = method->method_holder(); + method = holder->method_with_idnum(method->method_idnum()); + java_lang_invoke_ResolvedMethodName::set_vmtarget(resolved_method_name(), method); + } + // Set flag in class to indicate this InstanceKlass has entries in the table + // to avoid walking table during redefinition if none of the redefined classes + // have any membernames in the table. + method->method_holder()->set_has_resolved_methods(); + + return _the_table->basic_add(method, resolved_method_name()); +} + +// Removing entries +int ResolvedMethodTable::_oops_removed = 0; +int ResolvedMethodTable::_oops_counted = 0; + +// Serially invoke removed unused oops from the table. +// This is done late during GC. +void ResolvedMethodTable::unlink(BoolObjectClosure* is_alive) { + _oops_removed = 0; + _oops_counted = 0; + for (int i = 0; i < _the_table->table_size(); ++i) { + ResolvedMethodEntry** p = _the_table->bucket_addr(i); + ResolvedMethodEntry* entry = _the_table->bucket(i); + while (entry != NULL) { + _oops_counted++; + if (is_alive->do_object_b(entry->literal())) { + p = entry->next_addr(); + } else { + _oops_removed++; + if (log_is_enabled(Debug, membername, table)) { + Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(entry->literal()); + ResourceMark rm; + log_debug(membername, table) ("ResolvedMethod entry removed for %s index %d", + m->name_and_sig_as_C_string(), i); + } + *p = entry->next(); + _the_table->free_entry(entry); + } + // get next entry + entry = (ResolvedMethodEntry*)HashtableEntry::make_ptr(*p); + } + } + log_debug(membername, table) ("ResolvedMethod entries counted %d removed %d", + _oops_counted, _oops_removed); +} + +// Serially invoke "f->do_oop" on the locations of all oops in the table. +void ResolvedMethodTable::oops_do(OopClosure* f) { + for (int i = 0; i < _the_table->table_size(); ++i) { + ResolvedMethodEntry* entry = _the_table->bucket(i); + while (entry != NULL) { + f->do_oop(entry->literal_addr()); + entry = entry->next(); + } + } +} + +#ifndef PRODUCT +void ResolvedMethodTable::print() { + for (int i = 0; i < table_size(); ++i) { + ResolvedMethodEntry* entry = bucket(i); + while (entry != NULL) { + tty->print("%d : ", i); + oop rmethod_name = entry->literal(); + rmethod_name->print(); + Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(rmethod_name); + m->print(); + entry = entry->next(); + } + } +} +#endif // PRODUCT + +#if INCLUDE_JVMTI +// It is called at safepoint only for RedefineClasses +void ResolvedMethodTable::adjust_method_entries(bool * trace_name_printed) { + assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); + // For each entry in RMT, change to new method + for (int i = 0; i < _the_table->table_size(); ++i) { + ResolvedMethodEntry* entry = _the_table->bucket(i); + while (entry != NULL) { + + oop mem_name = entry->literal(); + Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name); + + if (old_method->is_old()) { + + if (old_method->is_deleted()) { + // leave deleted method in ResolvedMethod for now (this is a bug that we don't mark + // these on_stack) + continue; + } + + InstanceKlass* holder = old_method->method_holder(); + Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); + assert(holder == new_method->method_holder(), "call after swapping redefined guts"); + assert(new_method != NULL, "method_with_idnum() should not be NULL"); + assert(old_method != new_method, "sanity check"); + + java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name, new_method); + + ResourceMark rm; + if (!(*trace_name_printed)) { + log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name()); + *trace_name_printed = true; + } + log_debug(redefine, class, update, constantpool) + ("ResolvedMethod method update: %s(%s)", + new_method->name()->as_C_string(), new_method->signature()->as_C_string()); + } + entry = entry->next(); + } + } +} +#endif // INCLUDE_JVMTI diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/prims/resolvedMethodTable.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/prims/resolvedMethodTable.hpp Sat May 27 09:21:01 2017 -0400 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_PRIMS_RESOLVEDMETHOD_HPP +#define SHARE_VM_PRIMS_RESOLVEDMETHOD_HPP + +#include "oops/symbol.hpp" +#include "utilities/hashtable.hpp" + +// Hashtable to record Method* used in ResolvedMethods, via. ResolvedMethod oops. +// This is needed for redefinition to replace Method* with redefined versions. + +// Entry in a ResolvedMethodTable, mapping a single oop of java_lang_invoke_ResolvedMethodName which +// holds JVM Method* in vmtarget. + +class ResolvedMethodEntry : public HashtableEntry { + public: + ResolvedMethodEntry* next() const { + return (ResolvedMethodEntry*)HashtableEntry::next(); + } + + ResolvedMethodEntry** next_addr() { + return (ResolvedMethodEntry**)HashtableEntry::next_addr(); + } + + void print_on(outputStream* st) const; +}; + +class ResolvedMethodTable : public Hashtable { + enum Constants { + _table_size = 1007 + }; + + static int _oops_removed; + static int _oops_counted; + + static ResolvedMethodTable* _the_table; +private: + ResolvedMethodEntry* bucket(int i) { + return (ResolvedMethodEntry*) Hashtable::bucket(i); + } + + ResolvedMethodEntry** bucket_addr(int i) { + return (ResolvedMethodEntry**) Hashtable::bucket_addr(i); + } + + unsigned int compute_hash(Method* method); + + // need not be locked; no state change + oop lookup(int index, unsigned int hash, Method* method); + oop lookup(Method* method); + + // must be done under ResolvedMethodTable_lock + oop basic_add(Method* method, oop rmethod_name); + +public: + ResolvedMethodTable(); + + static void create_table() { + assert(_the_table == NULL, "One symbol table allowed."); + _the_table = new ResolvedMethodTable(); + } + + // Called from java_lang_invoke_ResolvedMethodName + static oop find_method(Method* method); + static oop add_method(Handle rmethod_name); + +#if INCLUDE_JVMTI + // It is called at safepoint only for RedefineClasses + static void adjust_method_entries(bool * trace_name_printed); +#endif // INCLUDE_JVMTI + + // Cleanup cleared entries + static void unlink(BoolObjectClosure* is_alive); + static void oops_do(OopClosure* f); + +#ifndef PRODUCT + void print(); +#endif + void verify(); +}; + +#endif // SHARE_VM_PRIMS_RESOLVEDMETHOD_HPP diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/prims/stackwalk.cpp --- a/hotspot/src/share/vm/prims/stackwalk.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/prims/stackwalk.cpp Sat May 27 09:21:01 2017 -0400 @@ -167,7 +167,7 @@ const methodHandle& method, TRAPS) { if (_need_method_info) { Handle stackFrame(THREAD, frames_array->obj_at(index)); - fill_stackframe(stackFrame, method); + fill_stackframe(stackFrame, method, CHECK); } else { frames_array->obj_at_put(index, method->method_holder()->java_mirror()); } @@ -270,15 +270,15 @@ } // Fill StackFrameInfo with declaringClass and bci and initialize memberName -void BaseFrameStream::fill_stackframe(Handle stackFrame, const methodHandle& method) { +void BaseFrameStream::fill_stackframe(Handle stackFrame, const methodHandle& method, TRAPS) { java_lang_StackFrameInfo::set_declaringClass(stackFrame(), method->method_holder()->java_mirror()); - java_lang_StackFrameInfo::set_method_and_bci(stackFrame, method, bci()); + java_lang_StackFrameInfo::set_method_and_bci(stackFrame, method, bci(), THREAD); } // Fill LiveStackFrameInfo with locals, monitors, and expressions void LiveFrameStream::fill_live_stackframe(Handle stackFrame, const methodHandle& method, TRAPS) { - fill_stackframe(stackFrame, method); + fill_stackframe(stackFrame, method, CHECK); if (_jvf != NULL) { StackValueCollection* locals = _jvf->locals(); StackValueCollection* expressions = _jvf->expressions(); diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/prims/stackwalk.hpp --- a/hotspot/src/share/vm/prims/stackwalk.hpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/prims/stackwalk.hpp Sat May 27 09:21:01 2017 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ JavaThread* _thread; jlong _anchor; protected: - void fill_stackframe(Handle stackFrame, const methodHandle& method); + void fill_stackframe(Handle stackFrame, const methodHandle& method, TRAPS); public: BaseFrameStream(JavaThread* thread) : _thread(thread), _anchor(0L) {} diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/runtime/mutexLocker.cpp --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Sat May 27 09:21:01 2017 -0400 @@ -45,7 +45,7 @@ Mutex* VMStatistic_lock = NULL; Mutex* JNIGlobalHandle_lock = NULL; Mutex* JNIHandleBlockFreeList_lock = NULL; -Mutex* MemberNameTable_lock = NULL; +Mutex* ResolvedMethodTable_lock = NULL; Mutex* JmethodIdCreation_lock = NULL; Mutex* JfieldIdCreation_lock = NULL; Monitor* JNICritical_lock = NULL; @@ -255,7 +255,7 @@ def(Heap_lock , PaddedMonitor, nonleaf+1, false, Monitor::_safepoint_check_sometimes); def(JfieldIdCreation_lock , PaddedMutex , nonleaf+1, true, Monitor::_safepoint_check_always); // jfieldID, Used in VM_Operation - def(MemberNameTable_lock , PaddedMutex , nonleaf+1, false, Monitor::_safepoint_check_always); // Used to protect MemberNameTable + def(ResolvedMethodTable_lock , PaddedMutex , nonleaf+1, false, Monitor::_safepoint_check_always); // Used to protect ResolvedMethodTable def(CompiledIC_lock , PaddedMutex , nonleaf+2, false, Monitor::_safepoint_check_always); // locks VtableStubs_lock, InlineCacheBuffer_lock def(CompileTaskAlloc_lock , PaddedMutex , nonleaf+2, true, Monitor::_safepoint_check_always); diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/runtime/mutexLocker.hpp --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Sat May 27 09:21:01 2017 -0400 @@ -38,7 +38,7 @@ extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment extern Mutex* JNIGlobalHandle_lock; // a lock on creating JNI global handles extern Mutex* JNIHandleBlockFreeList_lock; // a lock on the JNI handle block free list -extern Mutex* MemberNameTable_lock; // a lock on the MemberNameTable updates +extern Mutex* ResolvedMethodTable_lock; // a lock on the ResolvedMethodTable updates extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers extern Monitor* JNICritical_lock; // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Fri May 26 13:47:33 2017 -0700 +++ b/hotspot/src/share/vm/runtime/thread.cpp Sat May 27 09:21:01 2017 -0400 @@ -3493,6 +3493,7 @@ TraceTime timer("Initialize java.lang.invoke classes", TRACETIME_LOG(Info, startuptime)); initialize_class(vmSymbols::java_lang_invoke_MethodHandle(), CHECK); + initialize_class(vmSymbols::java_lang_invoke_ResolvedMethodName(), CHECK); initialize_class(vmSymbols::java_lang_invoke_MemberName(), CHECK); initialize_class(vmSymbols::java_lang_invoke_MethodHandleNatives(), CHECK); } diff -r 38048d4d20e7 -r fd4bc78630b1 hotspot/test/runtime/MemberName/MemberNameLeak.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/MemberName/MemberNameLeak.java Sat May 27 09:21:01 2017 -0400 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8174749 + * @summary MemberNameTable should reuse entries + * @library /test/lib + * @run main MemberNameLeak + */ + +import java.lang.invoke.*; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class MemberNameLeak { + static class Leak { + public void callMe() { + } + + public static void main(String[] args) throws Throwable { + Leak leak = new Leak(); + + for (int i = 0; i < 10; i++) { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType mt = MethodType.fromMethodDescriptorString("()V", Leak.class.getClassLoader()); + // findSpecial leaks some native mem + MethodHandle mh = lookup.findSpecial(Leak.class, "callMe", mt, Leak.class); + mh.invokeExact(leak); + } + + System.gc(); // make mh unused + } + } + + public static void test(String gc) throws Throwable { + // Run this Leak class with logging + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xlog:membername+table=trace", + gc, Leak.class.getName()); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("ResolvedMethod entry added for MemberNameLeak$Leak.callMe()V"); + output.shouldContain("ResolvedMethod entry found for MemberNameLeak$Leak.callMe()V"); + output.shouldContain("ResolvedMethod entry removed for MemberNameLeak$Leak.callMe()V"); + output.shouldHaveExitValue(0); + } + + public static void main(java.lang.String[] unused) throws Throwable { + test("-XX:+UseG1GC"); + test("-XX:+UseParallelGC"); + test("-XX:+UseSerialGC"); + test("-XX:+UseConcMarkSweepGC"); + } +}