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
--- 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:
--- 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:
--- 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:
--- 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;
--- 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:
--- 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:
--- 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());
}
}
--- 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();
--- 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) \
--- 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) {
--- 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
--- 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 <MEMFLAGS F> 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();
--- 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") \
--- 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
--- 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);
--- 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);
--- 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 {
--- 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);
--- 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);
--- 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);
--- 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
--- 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; }
--- 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));
--- 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) \
--- 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;
}
--- 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
--- 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;
--- 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()) {
--- 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.
--- 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.
--- 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<jweak>(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;
}
--- 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<jweak> {
- 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
--- /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<oop, mtClass>(_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<oop, mtClass>::new_entry(hash, rmethod_name);
+ Hashtable<oop, mtClass>::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<oop, mtClass>::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
--- /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<oop, mtClass> {
+ public:
+ ResolvedMethodEntry* next() const {
+ return (ResolvedMethodEntry*)HashtableEntry<oop, mtClass>::next();
+ }
+
+ ResolvedMethodEntry** next_addr() {
+ return (ResolvedMethodEntry**)HashtableEntry<oop, mtClass>::next_addr();
+ }
+
+ void print_on(outputStream* st) const;
+};
+
+class ResolvedMethodTable : public Hashtable<oop, mtClass> {
+ 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<oop, mtClass>::bucket(i);
+ }
+
+ ResolvedMethodEntry** bucket_addr(int i) {
+ return (ResolvedMethodEntry**) Hashtable<oop, mtClass>::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
--- 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();
--- 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) {}
--- 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);
--- 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
--- 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);
}
--- /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");
+ }
+}