1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
|
# HG changeset patch
# Parent 9792762e75f795196a5ff68e8cd5a52380b332d0
diff -r 9792762e75f7 src/share/vm/classfile/javaClasses.cpp
--- a/src/share/vm/classfile/javaClasses.cpp Mon Dec 07 11:59:52 2015 -0800
+++ b/src/share/vm/classfile/javaClasses.cpp Mon Dec 07 13:08:09 2015 -0800
@@ -2409,6 +2409,52 @@
}
}
+// Support for java_lang_invoke_DirectMethodHandle$StaticAccessor
+
+int java_lang_invoke_DirectMethodHandle_StaticAccessor::_static_offset_offset;
+
+long java_lang_invoke_DirectMethodHandle_StaticAccessor::static_offset(oop dmh) {
+ assert(_static_offset_offset != 0, "");
+ return dmh->long_field(_static_offset_offset);
+}
+
+void java_lang_invoke_DirectMethodHandle_StaticAccessor::set_static_offset(oop dmh, long static_offset) {
+ assert(_static_offset_offset != 0, "");
+ dmh->long_field_put(_static_offset_offset, static_offset);
+}
+
+
+void java_lang_invoke_DirectMethodHandle_StaticAccessor::compute_offsets() {
+ klassOop klass_oop = SystemDictionary::DirectMethodHandle_StaticAccessor_klass();
+ if (klass_oop != NULL && EnableInvokeDynamic) {
+ compute_offset(_static_offset_offset, klass_oop, vmSymbols::static_offset_name(), vmSymbols::long_signature());
+ }
+}
+
+// Support for java_lang_invoke_DirectMethodHandle$Accessor
+
+int java_lang_invoke_DirectMethodHandle_Accessor::_field_offset_offset;
+
+int java_lang_invoke_DirectMethodHandle_Accessor::field_offset(oop dmh) {
+ assert(_field_offset_offset != 0, "");
+ return dmh->int_field(_field_offset_offset);
+}
+
+void java_lang_invoke_DirectMethodHandle_Accessor::set_field_offset(oop dmh, int field_offset) {
+ assert(_field_offset_offset != 0, "");
+ dmh->int_field_put(_field_offset_offset, field_offset);
+}
+
+
+void java_lang_invoke_DirectMethodHandle_Accessor::compute_offsets() {
+ klassOop klass_oop = SystemDictionary::DirectMethodHandle_Accessor_klass();
+ if (klass_oop != NULL && EnableInvokeDynamic) {
+ compute_offset(_field_offset_offset, klass_oop, vmSymbols::field_offset_name(), vmSymbols::int_signature());
+ }
+}
+
+
+
// Support for java_lang_invoke_MethodHandle
int java_lang_invoke_MethodHandle::_type_offset;
@@ -3028,6 +3074,8 @@
if (EnableInvokeDynamic) {
java_lang_invoke_MethodHandle::compute_offsets();
java_lang_invoke_DirectMethodHandle::compute_offsets();
+ java_lang_invoke_DirectMethodHandle_StaticAccessor::compute_offsets();
+ java_lang_invoke_DirectMethodHandle_Accessor::compute_offsets();
java_lang_invoke_MemberName::compute_offsets();
java_lang_invoke_LambdaForm::compute_offsets();
java_lang_invoke_MethodType::compute_offsets();
diff -r 9792762e75f7 src/share/vm/classfile/javaClasses.hpp
--- a/src/share/vm/classfile/javaClasses.hpp Mon Dec 07 11:59:52 2015 -0800
+++ b/src/share/vm/classfile/javaClasses.hpp Mon Dec 07 13:08:09 2015 -0800
@@ -940,6 +940,54 @@
static int member_offset_in_bytes() { return _member_offset; }
};
+// Interface to java.lang.invoke.DirectMethodHandle$StaticAccessor objects
+
+class java_lang_invoke_DirectMethodHandle_StaticAccessor: AllStatic {
+ friend class JavaClasses;
+
+ private:
+ static int _static_offset_offset; // offset to static field
+
+ static void compute_offsets();
+
+ public:
+ // Accessors
+ static long static_offset(oop dmh);
+ static void set_static_offset(oop dmh, long value);
+
+ // Testers
+ static bool is_subclass(klassOop klass) {
+ return Klass::cast(klass)->is_subclass_of(SystemDictionary::DirectMethodHandle_StaticAccessor_klass());
+ }
+ static bool is_instance(oop obj) {
+ return obj != NULL && is_subclass(obj->klass());
+ }
+};
+
+// Interface to java.lang.invoke.DirectMethodHandle$Accessor objects
+
+class java_lang_invoke_DirectMethodHandle_Accessor: AllStatic {
+ friend class JavaClasses;
+
+ private:
+ static int _field_offset_offset; // offset to field
+
+ static void compute_offsets();
+
+ public:
+ // Accessors
+ static int field_offset(oop dmh);
+ static void set_field_offset(oop dmh, int value);
+
+ // Testers
+ static bool is_subclass(klassOop klass) {
+ return Klass::cast(klass)->is_subclass_of(SystemDictionary::DirectMethodHandle_Accessor_klass());
+ }
+ static bool is_instance(oop obj) {
+ return obj != NULL && is_subclass(obj->klass());
+ }
+};
+
// Interface to java.lang.invoke.LambdaForm objects
// (These are a private interface for managing adapter code generation.)
diff -r 9792762e75f7 src/share/vm/classfile/systemDictionary.cpp
--- a/src/share/vm/classfile/systemDictionary.cpp Mon Dec 07 11:59:52 2015 -0800
+++ b/src/share/vm/classfile/systemDictionary.cpp Mon Dec 07 13:08:09 2015 -0800
@@ -44,6 +44,7 @@
#include "oops/oop.inline2.hpp"
#include "oops/typeArrayKlass.hpp"
#include "prims/jvmtiEnvBase.hpp"
+#include "prims/jvmtiRedefineClassesTrace.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/fieldType.hpp"
@@ -2032,9 +2033,11 @@
assert(check->klass_part()->oop_is_instance(), "noninstance in systemdictionary");
if ((defining == true) && ((k() != check) && k->old_version() != check)) {
ResourceMark rm(Thread::current());
- tty->print_cr("(%d / %d) (%s/%s)", k->revision_number(), check->klass_part()->revision_number(), k->name()->as_C_string(), check->klass_part()->name()->as_C_string());
- k()->print();
- check->print();
+ if (RC_TRACE_ENABLED(0x00000001)) {
+ tty->print_cr("(%d / %d) (%s/%s)", k->revision_number(), check->klass_part()->revision_number(), k->name()->as_C_string(), check->klass_part()->name()->as_C_string());
+ k()->print();
+ check->print();
+ }
linkage_error = "loader (instance of %s): attempted duplicate class "
"definition for name: \"%s\"";
} else {
diff -r 9792762e75f7 src/share/vm/classfile/systemDictionary.hpp
--- a/src/share/vm/classfile/systemDictionary.hpp Mon Dec 07 11:59:52 2015 -0800
+++ b/src/share/vm/classfile/systemDictionary.hpp Mon Dec 07 13:08:09 2015 -0800
@@ -148,6 +148,8 @@
do_klass(reflect_UnsafeStaticFieldAccessorImpl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15 ) \
\
/* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \
+ do_klass(DirectMethodHandle_StaticAccessor_klass, java_lang_invoke_DirectMethodHandle_StaticAccessor, Opt ) \
+ do_klass(DirectMethodHandle_Accessor_klass, java_lang_invoke_DirectMethodHandle_Accessor, Opt ) \
do_klass(MethodHandle_klass, java_lang_invoke_MethodHandle, Pre_JSR292 ) \
do_klass(MemberName_klass, java_lang_invoke_MemberName, Pre_JSR292 ) \
do_klass(MethodHandleNatives_klass, java_lang_invoke_MethodHandleNatives, Pre_JSR292 ) \
diff -r 9792762e75f7 src/share/vm/classfile/vmSymbols.hpp
--- a/src/share/vm/classfile/vmSymbols.hpp Mon Dec 07 11:59:52 2015 -0800
+++ b/src/share/vm/classfile/vmSymbols.hpp Mon Dec 07 13:08:09 2015 -0800
@@ -248,6 +248,8 @@
/* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \
template(java_lang_invoke_CallSite, "java/lang/invoke/CallSite") \
template(java_lang_invoke_ConstantCallSite, "java/lang/invoke/ConstantCallSite") \
+ template(java_lang_invoke_DirectMethodHandle_StaticAccessor, "java/lang/invoke/DirectMethodHandle$StaticAccessor") \
+ template(java_lang_invoke_DirectMethodHandle_Accessor, "java/lang/invoke/DirectMethodHandle$Accessor") \
template(java_lang_invoke_DirectMethodHandle, "java/lang/invoke/DirectMethodHandle") \
template(java_lang_invoke_MutableCallSite, "java/lang/invoke/MutableCallSite") \
template(java_lang_invoke_VolatileCallSite, "java/lang/invoke/VolatileCallSite") \
@@ -485,6 +487,10 @@
template(int_StringBuffer_signature, "(I)Ljava/lang/StringBuffer;") \
template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \
template(int_String_signature, "(I)Ljava/lang/String;") \
+ template(static_offset_name, "staticOffset") \
+ template(static_base_name, "staticBase") \
+ template(field_offset_name, "fieldOffset") \
+ template(field_type_name, "fieldType") \
/* signature symbols needed by intrinsics */ \
VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \
\
diff -r 9792762e75f7 src/share/vm/prims/jvmtiRedefineClasses.cpp
--- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Dec 07 11:59:52 2015 -0800
+++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Dec 07 13:08:09 2015 -0800
@@ -2110,6 +2110,120 @@
}
+// import java_lang_invoke_MemberName.*
+enum {
+ REFERENCE_KIND_SHIFT = java_lang_invoke_MemberName::MN_REFERENCE_KIND_SHIFT,
+ REFERENCE_KIND_MASK = java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK,
+};
+
+static oop field_name_or_null(Symbol* s) {
+ if (s == NULL) return NULL;
+ return StringTable::lookup(s);
+}
+
+static oop object_java_mirror() {
+ return Klass::cast(SystemDictionary::Object_klass())->java_mirror();
+}
+
+static oop field_signature_type_or_null(Symbol* s) {
+ if (s == NULL) return NULL;
+ BasicType bt = FieldType::basic_type(s);
+ if (is_java_primitive(bt)) {
+ assert(s->utf8_length() == 1, "");
+ return java_lang_Class::primitive_mirror(bt);
+ }
+ // Here are some more short cuts for common types.
+ // They are optional, since reference types can be resolved lazily.
+ if (bt == T_OBJECT) {
+ if (s == vmSymbols::object_signature()) {
+ return object_java_mirror();
+ } else if (s == vmSymbols::class_signature()) {
+ return Klass::cast(SystemDictionary::Class_klass())->java_mirror();
+ } else if (s == vmSymbols::string_signature()) {
+ return Klass::cast(SystemDictionary::String_klass())->java_mirror();
+ }
+ }
+ return NULL;
+}
+
+bool update_member_name(oop obj) {
+ int flags = java_lang_invoke_MemberName::flags(obj);
+ int ref_kind = (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK;
+ if (MethodHandles::ref_kind_is_method(ref_kind)) {
+ methodOop m = (methodOop) java_lang_invoke_MemberName::vmtarget(obj);
+ if (m != NULL && !instanceKlass::cast(m->method_holder())->is_newest_version()) {
+ // Let's try to re-resolve method
+ KlassHandle newest = instanceKlass::cast(m->method_holder())->newest_version();
+ methodOop new_method = instanceKlass::cast(newest())->find_method(m->name(), m->signature());
+
+ // Note: we might set NULL at this point, which should force AbstractMethodError at runtime
+ bool do_dispatch = (ref_kind != JVM_REF_invokeSpecial);
+ MethodHandles::init_method_MemberName(obj, new_method, do_dispatch, newest);
+ }
+ } else if (MethodHandles::ref_kind_is_field(ref_kind)) {
+ klassOop k = (klassOop) java_lang_invoke_MemberName::vmtarget(obj);
+ if (k == NULL) {
+ return false; // Was cleared before, this MemberName is invalid.
+ }
+
+ if (k != NULL && !Klass::cast(k)->is_newest_version()) {
+ // Let's try to re-resolve field
+ fieldDescriptor fd;
+ int offset = java_lang_invoke_MemberName::vmindex(obj);
+ bool is_static = MethodHandles::ref_kind_is_static(ref_kind);
+ instanceKlass *ik = instanceKlass::cast(k);
+ if (ik->find_local_field_from_offset(offset, is_static, &fd)) {
+ KlassHandle newest = Klass::cast(k)->newest_version();
+ fieldDescriptor fd_new;
+ if (instanceKlass::cast(newest())->find_local_field(fd.name(), fd.signature(), &fd_new)) {
+ bool is_setter = MethodHandles::ref_kind_is_setter(ref_kind);
+ oop type = field_signature_type_or_null(fd_new.signature());
+ oop name = field_name_or_null(fd_new.name());
+ MethodHandles::init_field_MemberName(obj, newest, fd_new.access_flags(), type, name, fd_new.offset(), is_setter);
+ } else {
+ // Matching field is not found in new version, not much we can do here.
+ // JVM will crash once faulty MH is invoked.
+ // However, to avoid that all DMH's using this faulty MH are cleared (set to NULL)
+ // Eventually, we probably want to replace them with something more meaningful,
+ // like instance throwing NoSuchFieldError or DMH that will resort to dynamic
+ // field resolution (with possibility of type conversion)
+ java_lang_invoke_MemberName::set_vmtarget(obj, NULL);
+ java_lang_invoke_MemberName::set_vmindex(obj, 0);
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool update_direct_method_handle(oop obj) {
+ // Always update member name first.
+ oop mem_name = java_lang_invoke_DirectMethodHandle::member(obj);
+ if (!update_member_name(mem_name)) {
+ return false;
+ }
+
+ // Here we rely on DirectMethodHandle implementation.
+ // The current implementation caches field offset in $StaticAccessor/$Accessor
+ int flags = java_lang_invoke_MemberName::flags(mem_name);
+ int ref_kind = (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK;
+ if (MethodHandles::ref_kind_is_field(ref_kind)) {
+ // Note: we don't care about staticBase field (which is java.lang.Class)
+ // It should be processed during normal object update.
+ // Update offset in StaticAccessor
+ int offset = java_lang_invoke_MemberName::vmindex(mem_name);
+ if (offset != 0) { // index of 0 means that field no longer exist
+ if (java_lang_invoke_DirectMethodHandle_StaticAccessor::is_instance(obj)) {
+ java_lang_invoke_DirectMethodHandle_StaticAccessor::set_static_offset(obj, offset);
+ } else if (java_lang_invoke_DirectMethodHandle_Accessor::is_instance(obj)) {
+ java_lang_invoke_DirectMethodHandle_Accessor::set_field_offset(obj, offset);
+ }
+ }
+ }
+ return true;
+}
+
template <class T> void VM_RedefineClasses::do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
@@ -2148,6 +2262,18 @@
}
}
}
+ } else {
+ // JSR 292 support, uptade java.lang.invoke.MemberName instances
+ if (java_lang_invoke_MemberName::is_instance(obj)) {
+ update_member_name(obj);
+ } else if (java_lang_invoke_DirectMethodHandle::is_instance(obj)) {
+ if (!update_direct_method_handle(obj)) {
+ // DMH is no longer valid, replace it with null reference.
+ // See note above. We probably want to replace this with something more meaningful.
+ oopDesc::encode_store_heap_oop(p, NULL);
+ //S::oop_store(p, NULL);
+ }
+ }
}
}
}
@@ -2245,6 +2371,12 @@
virtual void do_object(oop obj) {
if (!obj->is_instanceKlass()) {
+ // JSR 292 support, uptade java.lang.invoke.MemberName instances
+ // Update before we update its fields, so if it is a field ref, its vmtarget still points at old klass
+ if (java_lang_invoke_MemberName::is_instance(obj)) {
+ update_member_name(obj);
+ }
+
obj->oop_iterate(_closure);
if (obj->blueprint()->is_redefining()) {
@@ -2822,6 +2954,11 @@
// TODO:
transfer_old_native_function_registrations(the_old_class);
+ // Swap method handles
+ MemberNameTable* mnt = the_old_class->member_names();
+ assert(the_new_class->member_names() == NULL, "");
+ the_new_class->set_member_names(mnt);
+ the_old_class->set_member_names(NULL);
#ifdef ASSERT
diff -r 9792762e75f7 src/share/vm/runtime/mutexLocker.cpp
--- a/src/share/vm/runtime/mutexLocker.cpp Mon Dec 07 11:59:52 2015 -0800
+++ b/src/share/vm/runtime/mutexLocker.cpp Mon Dec 07 13:08:09 2015 -0800
@@ -267,7 +267,7 @@
def(Heap_lock , Monitor, nonleaf+1, false);
def(JfieldIdCreation_lock , Mutex , nonleaf+1, true ); // jfieldID, Used in VM_Operation
def(JNICachedItableIndex_lock , Mutex , nonleaf+1, false); // Used to cache an itable index during JNI invoke
- def(MemberNameTable_lock , Mutex , nonleaf+1, false); // Used to protect MemberNameTable
+ def(MemberNameTable_lock , Mutex , nonleaf+1, true); // Used to protect MemberNameTable
def(CompiledIC_lock , Mutex , nonleaf+2, false); // locks VtableStubs_lock, InlineCacheBuffer_lock
def(CompileTaskAlloc_lock , Mutex , nonleaf+2, true );
|