|
1 /* |
|
2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 * |
|
23 */ |
|
24 |
|
25 #include "precompiled.hpp" |
|
26 #include "jvm.h" |
|
27 #include "classfile/classFileParser.hpp" |
|
28 #include "classfile/classFileStream.hpp" |
|
29 #include "classfile/javaClasses.inline.hpp" |
|
30 #include "classfile/stackMapTable.hpp" |
|
31 #include "classfile/verificationType.hpp" |
|
32 #include "interpreter/bytecodes.hpp" |
|
33 #include "jfr/instrumentation/jfrEventClassTransformer.hpp" |
|
34 #include "jfr/jfr.hpp" |
|
35 #include "jfr/jni/jfrJavaSupport.hpp" |
|
36 #include "jfr/jni/jfrUpcalls.hpp" |
|
37 #include "jfr/support/jfrEventClass.hpp" |
|
38 #include "jfr/utilities/jfrBigEndian.hpp" |
|
39 #include "jfr/writers/jfrBigEndianWriter.hpp" |
|
40 #include "logging/log.hpp" |
|
41 #include "memory/allocation.inline.hpp" |
|
42 #include "memory/resourceArea.hpp" |
|
43 #include "oops/array.hpp" |
|
44 #include "oops/instanceKlass.hpp" |
|
45 #include "oops/method.hpp" |
|
46 #include "prims/jvmtiRedefineClasses.hpp" |
|
47 #include "runtime/handles.inline.hpp" |
|
48 #include "runtime/os.hpp" |
|
49 #include "runtime/thread.inline.hpp" |
|
50 #include "utilities/exceptions.hpp" |
|
51 #include "utilities/globalDefinitions.hpp" |
|
52 #include "utilities/macros.hpp" |
|
53 |
|
54 static const u2 number_of_new_methods = 5; |
|
55 static const u2 number_of_new_fields = 3; |
|
56 static const int extra_stream_bytes = 0x280; |
|
57 static const u2 invalid_cp_index = 0; |
|
58 |
|
59 static const char* utf8_constants[] = { |
|
60 "Code", // 0 |
|
61 "J", // 1 |
|
62 "commit", // 2 |
|
63 "eventHandler", // 3 |
|
64 "Ljdk/jfr/internal/handlers/EventHandler;", // 4 |
|
65 "duration", // 5 |
|
66 "begin", // 6 |
|
67 "()V", // 7 |
|
68 "isEnabled", // 8 |
|
69 "()Z", // 9 |
|
70 "end", // 10 |
|
71 "shouldCommit", // 11 |
|
72 "startTime", // 12 |
|
73 "<clinit>", // 13 |
|
74 "jdk/jfr/FlightRecorder", // 14 |
|
75 "register", // 15 |
|
76 "(Ljava/lang/Class;)V", // 16 // LAST_REQUIRED_UTF8 |
|
77 "StackMapTable", // 17 |
|
78 "Exceptions", // 18 |
|
79 "LineNumberTable", // 20 |
|
80 "LocalVariableTable", // 21 |
|
81 "LocalVariableTypeTable", // 22 |
|
82 "RuntimeVisibleAnnotation" // 23 |
|
83 }; |
|
84 |
|
85 enum utf8_req_symbols { |
|
86 UTF8_REQ_Code, |
|
87 UTF8_REQ_J_FIELD_DESC, |
|
88 UTF8_REQ_commit, |
|
89 UTF8_REQ_eventHandler, |
|
90 UTF8_REQ_eventHandler_FIELD_DESC, |
|
91 UTF8_REQ_duration, |
|
92 UTF8_REQ_begin, |
|
93 UTF8_REQ_EMPTY_VOID_METHOD_DESC, |
|
94 UTF8_REQ_isEnabled, |
|
95 UTF8_REQ_EMPTY_BOOLEAN_METHOD_DESC, |
|
96 UTF8_REQ_end, |
|
97 UTF8_REQ_shouldCommit, |
|
98 UTF8_REQ_startTime, |
|
99 UTF8_REQ_clinit, |
|
100 UTF8_REQ_FlightRecorder, |
|
101 UTF8_REQ_register, |
|
102 UTF8_REQ_CLASS_VOID_METHOD_DESC, |
|
103 NOF_UTF8_REQ_SYMBOLS |
|
104 }; |
|
105 |
|
106 enum utf8_opt_symbols { |
|
107 UTF8_OPT_StackMapTable = NOF_UTF8_REQ_SYMBOLS, |
|
108 UTF8_OPT_Exceptions, |
|
109 UTF8_OPT_LineNumberTable, |
|
110 UTF8_OPT_LocalVariableTable, |
|
111 UTF8_OPT_LocalVariableTypeTable, |
|
112 UTF8_OPT_RuntimeVisibleAnnotation, |
|
113 NOF_UTF8_SYMBOLS |
|
114 }; |
|
115 |
|
116 static u1 empty_void_method_code_attribute[] = { |
|
117 0x0, |
|
118 0x0, |
|
119 0x0, |
|
120 0xd, // attribute len |
|
121 0x0, |
|
122 0x0, // max stack |
|
123 0x0, |
|
124 0x1, // max locals |
|
125 0x0, |
|
126 0x0, |
|
127 0x0, |
|
128 0x1, // code length |
|
129 Bytecodes::_return, |
|
130 0x0, |
|
131 0x0, // ex table len |
|
132 0x0, |
|
133 0x0 // attributes_count |
|
134 }; |
|
135 |
|
136 static u1 boolean_method_code_attribute[] = { |
|
137 0x0, |
|
138 0x0, |
|
139 0x0, |
|
140 0xe, |
|
141 0x0, |
|
142 0x1, // max stack |
|
143 0x0, |
|
144 0x1, // max locals |
|
145 0x0, |
|
146 0x0, |
|
147 0x0, |
|
148 0x2, |
|
149 Bytecodes::_iconst_0, |
|
150 Bytecodes::_ireturn, |
|
151 0x0, |
|
152 0x0, // ex table len |
|
153 0x0, |
|
154 0x0, // attributes_count |
|
155 }; |
|
156 |
|
157 // annotation processing support |
|
158 |
|
159 enum { // initial annotation layout |
|
160 atype_off = 0, // utf8 such as 'Ljava/lang/annotation/Retention;' |
|
161 count_off = 2, // u2 such as 1 (one value) |
|
162 member_off = 4, // utf8 such as 'value' |
|
163 tag_off = 6, // u1 such as 'c' (type) or 'e' (enum) |
|
164 e_tag_val = 'e', |
|
165 e_type_off = 7, // utf8 such as 'Ljava/lang/annotation/RetentionPolicy;' |
|
166 e_con_off = 9, // utf8 payload, such as 'SOURCE', 'CLASS', 'RUNTIME' |
|
167 e_size = 11, // end of 'e' annotation |
|
168 c_tag_val = 'c', // payload is type |
|
169 c_con_off = 7, // utf8 payload, such as 'I' |
|
170 c_size = 9, // end of 'c' annotation |
|
171 s_tag_val = 's', // payload is String |
|
172 s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;' |
|
173 s_size = 9, |
|
174 min_size = 6 // smallest possible size (zero members) |
|
175 }; |
|
176 |
|
177 static int skip_annotation_value(const address, int, int); // fwd decl |
|
178 |
|
179 // Skip an annotation. Return >=limit if there is any problem. |
|
180 static int next_annotation_index(const address buffer, int limit, int index) { |
|
181 assert(buffer != NULL, "invariant"); |
|
182 index += 2; // skip atype |
|
183 if ((index += 2) >= limit) { |
|
184 return limit; |
|
185 } |
|
186 int nof_members = JfrBigEndian::read<u2>(buffer + index - 2); |
|
187 while (--nof_members >= 0 && index < limit) { |
|
188 index += 2; // skip member |
|
189 index = skip_annotation_value(buffer, limit, index); |
|
190 } |
|
191 return index; |
|
192 } |
|
193 |
|
194 // Skip an annotation value. Return >=limit if there is any problem. |
|
195 static int skip_annotation_value(const address buffer, int limit, int index) { |
|
196 assert(buffer != NULL, "invariant"); |
|
197 // value := switch (tag:u1) { |
|
198 // case B, C, I, S, Z, D, F, J, c: con:u2; |
|
199 // case e: e_class:u2 e_name:u2; |
|
200 // case s: s_con:u2; |
|
201 // case [: do(nval:u2) {value}; |
|
202 // case @: annotation; |
|
203 // case s: s_con:u2; |
|
204 // } |
|
205 if ((index += 1) >= limit) { |
|
206 return limit; |
|
207 } |
|
208 const u1 tag = buffer[index - 1]; |
|
209 switch (tag) { |
|
210 case 'B': |
|
211 case 'C': |
|
212 case 'I': |
|
213 case 'S': |
|
214 case 'Z': |
|
215 case 'D': |
|
216 case 'F': |
|
217 case 'J': |
|
218 case 'c': |
|
219 case 's': |
|
220 index += 2; // skip con or s_con |
|
221 break; |
|
222 case 'e': |
|
223 index += 4; // skip e_class, e_name |
|
224 break; |
|
225 case '[': |
|
226 { |
|
227 if ((index += 2) >= limit) { |
|
228 return limit; |
|
229 } |
|
230 int nof_values = JfrBigEndian::read<u2>(buffer + index - 2); |
|
231 while (--nof_values >= 0 && index < limit) { |
|
232 index = skip_annotation_value(buffer, limit, index); |
|
233 } |
|
234 } |
|
235 break; |
|
236 case '@': |
|
237 index = next_annotation_index(buffer, limit, index); |
|
238 break; |
|
239 default: |
|
240 return limit; // bad tag byte |
|
241 } |
|
242 return index; |
|
243 } |
|
244 |
|
245 static const u2 number_of_elements_offset = (u2)2; |
|
246 static const u2 element_name_offset = (u2)(number_of_elements_offset + 2); |
|
247 static const u2 element_name_size = (u2)2; |
|
248 static const u2 value_type_relative_offset = (u2)2; |
|
249 static const u2 value_relative_offset = (u2)(value_type_relative_offset + 1); |
|
250 |
|
251 // see JVMS - 4.7.16. The RuntimeVisibleAnnotations Attribute |
|
252 |
|
253 class AnnotationElementIterator : public StackObj { |
|
254 private: |
|
255 const InstanceKlass* _ik; |
|
256 const address _buffer; |
|
257 const u2 _limit; // length of annotation |
|
258 mutable u2 _current; // element |
|
259 mutable u2 _next; // element |
|
260 u2 value_index() const { |
|
261 return JfrBigEndian::read<u2>(_buffer + _current + value_relative_offset); |
|
262 } |
|
263 |
|
264 public: |
|
265 AnnotationElementIterator(const InstanceKlass* ik, address buffer, u2 limit) : _ik(ik), |
|
266 _buffer(buffer), |
|
267 _limit(limit), |
|
268 _next(element_name_offset), |
|
269 _current(element_name_offset) { |
|
270 assert(_buffer != NULL, "invariant"); |
|
271 assert(_next == element_name_offset, "invariant"); |
|
272 assert(_current == element_name_offset, "invariant"); |
|
273 } |
|
274 |
|
275 bool has_next() const { |
|
276 return _next < _limit; |
|
277 } |
|
278 |
|
279 void move_to_next() const { |
|
280 assert(has_next(), "invariant"); |
|
281 _current = _next; |
|
282 if (_next < _limit) { |
|
283 _next = skip_annotation_value(_buffer, _limit, _next + element_name_size); |
|
284 } |
|
285 assert(_next <= _limit, "invariant"); |
|
286 assert(_current <= _limit, "invariant"); |
|
287 } |
|
288 |
|
289 u2 number_of_elements() const { |
|
290 return JfrBigEndian::read<u2>(_buffer + number_of_elements_offset); |
|
291 } |
|
292 |
|
293 const Symbol* name() const { |
|
294 assert(_current < _next, "invariant"); |
|
295 return _ik->constants()->symbol_at(JfrBigEndian::read<u2>(_buffer + _current)); |
|
296 } |
|
297 |
|
298 char value_type() const { |
|
299 return JfrBigEndian::read<u1>(_buffer + _current + value_type_relative_offset); |
|
300 } |
|
301 |
|
302 jint read_int() const { |
|
303 return _ik->constants()->int_at(value_index()); |
|
304 } |
|
305 |
|
306 bool read_bool() const { |
|
307 return read_int() != 0; |
|
308 } |
|
309 }; |
|
310 |
|
311 class AnnotationIterator : public StackObj { |
|
312 private: |
|
313 const InstanceKlass* _ik; |
|
314 // ensure _limit field is declared before _buffer |
|
315 u2 _limit; // length of annotations array |
|
316 const address _buffer; |
|
317 mutable u2 _current; // annotation |
|
318 mutable u2 _next; // annotation |
|
319 |
|
320 public: |
|
321 AnnotationIterator(const InstanceKlass* ik, AnnotationArray* ar) : _ik(ik), |
|
322 _current(0), |
|
323 _next(0), |
|
324 _limit(ar != NULL ? ar->length() : 0), |
|
325 _buffer(_limit > 2 ? ar->adr_at(2) : NULL) { |
|
326 if (_buffer != NULL) { |
|
327 _limit -= 2; // subtract sizeof(u2) number of annotations field |
|
328 } |
|
329 } |
|
330 bool has_next() const { |
|
331 return _next < _limit; |
|
332 } |
|
333 |
|
334 void move_to_next() const { |
|
335 assert(has_next(), "invariant"); |
|
336 _current = _next; |
|
337 if (_next < _limit) { |
|
338 _next = next_annotation_index(_buffer, _limit, _next); |
|
339 } |
|
340 assert(_next <= _limit, "invariant"); |
|
341 assert(_current <= _limit, "invariant"); |
|
342 } |
|
343 const AnnotationElementIterator elements() const { |
|
344 assert(_current < _next, "invariant"); |
|
345 return AnnotationElementIterator(_ik, _buffer + _current, _next - _current); |
|
346 } |
|
347 const Symbol* type() const { |
|
348 assert(_buffer != NULL, "invariant"); |
|
349 assert(_current < _limit, "invariant"); |
|
350 return _ik->constants()->symbol_at(JfrBigEndian::read<u2>(_buffer + _current)); |
|
351 } |
|
352 }; |
|
353 |
|
354 static unsigned int unused_hash = 0; |
|
355 static const char value_name[] = "value"; |
|
356 static bool has_registered_annotation(const InstanceKlass* ik, const Symbol* annotation_type, bool& value) { |
|
357 assert(annotation_type != NULL, "invariant"); |
|
358 AnnotationArray* class_annotations = ik->class_annotations(); |
|
359 if (class_annotations == NULL) { |
|
360 return false; |
|
361 } |
|
362 |
|
363 const AnnotationIterator annotation_iterator(ik, class_annotations); |
|
364 while (annotation_iterator.has_next()) { |
|
365 annotation_iterator.move_to_next(); |
|
366 if (annotation_iterator.type() == annotation_type) { |
|
367 // target annotation found |
|
368 static const Symbol* value_symbol = |
|
369 SymbolTable::lookup_only(value_name, sizeof value_name - 1, unused_hash); |
|
370 assert(value_symbol != NULL, "invariant"); |
|
371 const AnnotationElementIterator element_iterator = annotation_iterator.elements(); |
|
372 while (element_iterator.has_next()) { |
|
373 element_iterator.move_to_next(); |
|
374 if (value_symbol == element_iterator.name()) { |
|
375 // "value" element |
|
376 assert('Z' == element_iterator.value_type(), "invariant"); |
|
377 value = element_iterator.read_bool(); |
|
378 return true; |
|
379 } |
|
380 } |
|
381 } |
|
382 } |
|
383 return false; |
|
384 } |
|
385 |
|
386 static bool registered_annotation_value(const InstanceKlass* ik, const Symbol* const registered_symbol) { |
|
387 assert(registered_symbol != NULL, "invariant"); |
|
388 assert(ik != NULL, "invariant"); |
|
389 assert(JdkJfrEvent::is_a(ik), "invariant"); |
|
390 bool registered_value = false; |
|
391 if (has_registered_annotation(ik, registered_symbol, registered_value)) { |
|
392 return registered_value; |
|
393 } |
|
394 InstanceKlass* super = InstanceKlass::cast(ik->super()); |
|
395 return registered_annotation_value(super, registered_symbol); |
|
396 } |
|
397 |
|
398 static const char registered_constant[] = "Ljdk/jfr/Registered;"; |
|
399 |
|
400 // Evaluate to the value of the first found "Ljdk/jfr/Registered;" annotation. |
|
401 // Searching moves upwards in the klass hierarchy in order to support |
|
402 // inherited annotations in addition to the ability to override. |
|
403 static bool should_register_klass(const InstanceKlass* ik) { |
|
404 static const Symbol* const registered_symbol = SymbolTable::lookup_only(registered_constant, |
|
405 sizeof registered_constant - 1, |
|
406 unused_hash); |
|
407 assert(registered_symbol != NULL, "invariant"); |
|
408 return registered_annotation_value(ik, registered_symbol); |
|
409 } |
|
410 /* |
|
411 * Map an utf8 constant back to its CONSTANT_UTF8_INFO |
|
412 */ |
|
413 static u2 utf8_info_index(const InstanceKlass* ik, const Symbol* const target, TRAPS) { |
|
414 assert(target != NULL, "invariant"); |
|
415 const ConstantPool* cp = ik->constants(); |
|
416 const int cp_len = cp->length(); |
|
417 for (u2 index = 1; index < cp_len; ++index) { |
|
418 const constantTag tag = cp->tag_at(index); |
|
419 if (tag.is_utf8()) { |
|
420 const Symbol* const utf8_sym = cp->symbol_at(index); |
|
421 assert(utf8_sym != NULL, "invariant"); |
|
422 if (utf8_sym == target) { |
|
423 return index; |
|
424 } |
|
425 } |
|
426 } |
|
427 // not in constant pool |
|
428 return invalid_cp_index; |
|
429 } |
|
430 |
|
431 #ifdef ASSERT |
|
432 static bool is_index_within_range(u2 index, u2 orig_cp_len, u2 new_cp_entries_len) { |
|
433 return index > 0 && index < orig_cp_len + new_cp_entries_len; |
|
434 } |
|
435 #endif |
|
436 |
|
437 static u2 add_utf8_info(JfrBigEndianWriter& writer, const char* utf8_constant, u2 orig_cp_len, u2& new_cp_entries_len) { |
|
438 assert(utf8_constant != NULL, "invariant"); |
|
439 writer.write<u1>(JVM_CONSTANT_Utf8); |
|
440 writer.write_utf8_u2_len(utf8_constant); |
|
441 assert(writer.is_valid(), "invariant"); |
|
442 // return index for the added utf8 info |
|
443 return orig_cp_len + new_cp_entries_len++; |
|
444 } |
|
445 |
|
446 static u2 add_method_ref_info(JfrBigEndianWriter& writer, |
|
447 u2 cls_name_index, |
|
448 u2 method_index, |
|
449 u2 desc_index, |
|
450 u2 orig_cp_len, |
|
451 u2& number_of_new_constants, |
|
452 TRAPS) { |
|
453 assert(is_index_within_range(cls_name_index, orig_cp_len, number_of_new_constants), "invariant"); |
|
454 assert(is_index_within_range(method_index, orig_cp_len, number_of_new_constants), "invariant"); |
|
455 assert(is_index_within_range(desc_index, orig_cp_len, number_of_new_constants), "invariant"); |
|
456 writer.write<u1>(JVM_CONSTANT_Class); |
|
457 writer.write<u2>(cls_name_index); |
|
458 const u2 cls_entry_index = orig_cp_len + number_of_new_constants; |
|
459 ++number_of_new_constants; |
|
460 writer.write<u1>(JVM_CONSTANT_NameAndType); |
|
461 writer.write<u2>(method_index); |
|
462 writer.write<u2>(desc_index); |
|
463 const u2 nat_entry_index = orig_cp_len + number_of_new_constants; |
|
464 ++number_of_new_constants; |
|
465 writer.write<u1>(JVM_CONSTANT_Methodref); |
|
466 writer.write<u2>(cls_entry_index); |
|
467 writer.write<u2>(nat_entry_index); |
|
468 // post-increment number_of_new_constants |
|
469 // value returned is the index to the added method_ref |
|
470 return orig_cp_len + number_of_new_constants++; |
|
471 } |
|
472 |
|
473 static u2 add_flr_register_method_constants(JfrBigEndianWriter& writer, |
|
474 const u2* utf8_indexes, |
|
475 u2 orig_cp_len, |
|
476 u2& number_of_new_constants, |
|
477 TRAPS) { |
|
478 assert(utf8_indexes != NULL, "invariant"); |
|
479 return add_method_ref_info(writer, |
|
480 utf8_indexes[UTF8_REQ_FlightRecorder], |
|
481 utf8_indexes[UTF8_REQ_register], |
|
482 utf8_indexes[UTF8_REQ_CLASS_VOID_METHOD_DESC], |
|
483 orig_cp_len, |
|
484 number_of_new_constants, |
|
485 THREAD); |
|
486 } |
|
487 |
|
488 /* |
|
489 * field_info { |
|
490 * u2 access_flags; |
|
491 * u2 name_index; |
|
492 * u2 descriptor_index; |
|
493 * u2 attributes_count; |
|
494 * attribute_info attributes[attributes_count]; |
|
495 * } |
|
496 */ |
|
497 static jlong add_field_info(JfrBigEndianWriter& writer, u2 name_index, u2 desc_index, bool is_static = false) { |
|
498 assert(name_index > 0, "invariant"); |
|
499 assert(desc_index > 0, "invariant"); |
|
500 DEBUG_ONLY(const jlong start_offset = writer.current_offset();) |
|
501 writer.write<u2>(JVM_ACC_SYNTHETIC | JVM_ACC_PRIVATE | (is_static ? JVM_ACC_STATIC : JVM_ACC_TRANSIENT)); // flags |
|
502 writer.write(name_index); |
|
503 writer.write(desc_index); |
|
504 writer.write((u2)0x0); // attributes_count |
|
505 assert(writer.is_valid(), "invariant"); |
|
506 DEBUG_ONLY(assert(start_offset + 8 == writer.current_offset(), "invariant");) |
|
507 return writer.current_offset(); |
|
508 } |
|
509 |
|
510 static u2 add_field_infos(JfrBigEndianWriter& writer, const u2* utf8_indexes) { |
|
511 assert(utf8_indexes != NULL, "invariant"); |
|
512 add_field_info(writer, |
|
513 utf8_indexes[UTF8_REQ_eventHandler], |
|
514 utf8_indexes[UTF8_REQ_eventHandler_FIELD_DESC], |
|
515 true); // static |
|
516 |
|
517 add_field_info(writer, |
|
518 utf8_indexes[UTF8_REQ_startTime], |
|
519 utf8_indexes[UTF8_REQ_J_FIELD_DESC]); |
|
520 |
|
521 add_field_info(writer, |
|
522 utf8_indexes[UTF8_REQ_duration], |
|
523 utf8_indexes[UTF8_REQ_J_FIELD_DESC]); |
|
524 |
|
525 return number_of_new_fields; |
|
526 } |
|
527 |
|
528 /* |
|
529 * method_info { |
|
530 * u2 access_flags; |
|
531 * u2 name_index; |
|
532 * u2 descriptor_index; |
|
533 * u2 attributes_count; |
|
534 * attribute_info attributes[attributes_count]; |
|
535 * } |
|
536 * |
|
537 * Code_attribute { |
|
538 * u2 attribute_name_index; |
|
539 * u4 attribute_length; |
|
540 * u2 max_stack; |
|
541 * u2 max_locals; |
|
542 * u4 code_length; |
|
543 * u1 code[code_length]; |
|
544 * u2 exception_table_length; |
|
545 * { u2 start_pc; |
|
546 * u2 end_pc; |
|
547 * u2 handler_pc; |
|
548 * u2 catch_type; |
|
549 * } exception_table[exception_table_length]; |
|
550 * u2 attributes_count; |
|
551 * attribute_info attributes[attributes_count]; |
|
552 * } |
|
553 */ |
|
554 |
|
555 static jlong add_method_info(JfrBigEndianWriter& writer, |
|
556 u2 name_index, |
|
557 u2 desc_index, |
|
558 u2 code_index, |
|
559 const u1* const code, |
|
560 const size_t code_len) { |
|
561 assert(name_index > 0, "invariant"); |
|
562 assert(desc_index > 0, "invariant"); |
|
563 assert(code_index > 0, "invariant"); |
|
564 DEBUG_ONLY(const jlong start_offset = writer.current_offset();) |
|
565 writer.write<u2>(JVM_ACC_SYNTHETIC | JVM_ACC_PUBLIC); // flags |
|
566 writer.write(name_index); |
|
567 writer.write(desc_index); |
|
568 writer.write<u2>(0x1); // attributes_count ; 1 for "Code" attribute |
|
569 assert(writer.is_valid(), "invariant"); |
|
570 DEBUG_ONLY(assert(start_offset + 8 == writer.current_offset(), "invariant");) |
|
571 // Code attribute |
|
572 writer.write(code_index); // "Code" |
|
573 writer.bytes(code, code_len); |
|
574 DEBUG_ONLY(assert((start_offset + 8 + 2 + (jlong)code_len) == writer.current_offset(), "invariant");) |
|
575 return writer.current_offset(); |
|
576 } |
|
577 |
|
578 /* |
|
579 * On return, the passed stream will be positioned |
|
580 * just after the constant pool section in the classfile |
|
581 * and the cp length is returned. |
|
582 * |
|
583 * Stream should come in at the start position. |
|
584 */ |
|
585 static u2 position_stream_after_cp(const ClassFileStream* stream) { |
|
586 assert(stream != NULL, "invariant"); |
|
587 assert(stream->current_offset() == 0, "invariant"); |
|
588 stream->skip_u4_fast(2); // 8 bytes skipped |
|
589 const u2 cp_len = stream->get_u2_fast(); |
|
590 assert(cp_len > 0, "invariant"); |
|
591 // now spin the stream position to just after the constant pool |
|
592 for (u2 index = 1; index < cp_len; ++index) { |
|
593 const u1 tag = stream->get_u1_fast(); // cp tag |
|
594 switch (tag) { |
|
595 case JVM_CONSTANT_Class: |
|
596 case JVM_CONSTANT_String: { |
|
597 stream->skip_u2_fast(1); // skip 2 bytes |
|
598 continue; |
|
599 } |
|
600 case JVM_CONSTANT_Fieldref: |
|
601 case JVM_CONSTANT_Methodref: |
|
602 case JVM_CONSTANT_InterfaceMethodref: |
|
603 case JVM_CONSTANT_Integer: |
|
604 case JVM_CONSTANT_Float: |
|
605 case JVM_CONSTANT_NameAndType: |
|
606 case JVM_CONSTANT_InvokeDynamic: { |
|
607 stream->skip_u4_fast(1); // skip 4 bytes |
|
608 continue; |
|
609 } |
|
610 case JVM_CONSTANT_Long: |
|
611 case JVM_CONSTANT_Double: { |
|
612 stream->skip_u4_fast(2); // skip 8 bytes |
|
613 // Skip entry following eigth-byte constant, see JVM book p. 98 |
|
614 ++index; |
|
615 continue; |
|
616 } |
|
617 case JVM_CONSTANT_Utf8: { |
|
618 u2 utf8_length = stream->get_u2_fast(); |
|
619 stream->skip_u1_fast(utf8_length); // skip 2 + len bytes |
|
620 continue; |
|
621 } |
|
622 case JVM_CONSTANT_MethodHandle: |
|
623 case JVM_CONSTANT_MethodType: { |
|
624 if (tag == JVM_CONSTANT_MethodHandle) { |
|
625 stream->skip_u1_fast(1); |
|
626 stream->skip_u2_fast(1); // skip 3 bytes |
|
627 } |
|
628 else if (tag == JVM_CONSTANT_MethodType) { |
|
629 stream->skip_u2_fast(1); // skip 3 bytes |
|
630 } |
|
631 } |
|
632 continue; |
|
633 default: |
|
634 assert(false, "error in skip logic!"); |
|
635 break; |
|
636 } // end switch(tag) |
|
637 } |
|
638 return cp_len; |
|
639 } |
|
640 |
|
641 /* |
|
642 * On return, the passed stream will be positioned |
|
643 * just after the fields section in the classfile |
|
644 * and the number of fields will be returned. |
|
645 * |
|
646 * Stream should come in positioned just before fields_count |
|
647 */ |
|
648 static u2 position_stream_after_fields(const ClassFileStream* stream) { |
|
649 assert(stream != NULL, "invariant"); |
|
650 assert(stream->current_offset() > 0, "invariant"); |
|
651 // fields len |
|
652 const u2 orig_fields_len = stream->get_u2_fast(); |
|
653 // fields |
|
654 for (u2 i = 0; i < orig_fields_len; ++i) { |
|
655 stream->skip_u2_fast(3); |
|
656 const u2 attrib_info_len = stream->get_u2_fast(); |
|
657 for (u2 j = 0; j < attrib_info_len; ++j) { |
|
658 stream->skip_u2_fast(1); |
|
659 const u4 attrib_len = stream->get_u4_fast(); |
|
660 stream->skip_u1_fast(attrib_len); |
|
661 } |
|
662 } |
|
663 return orig_fields_len; |
|
664 } |
|
665 |
|
666 /* |
|
667 * On return, the passed stream will be positioned |
|
668 * just after the methods section in the classfile |
|
669 * and the number of methods will be returned. |
|
670 * |
|
671 * Stream should come in positioned just before methods_count |
|
672 */ |
|
673 static u2 position_stream_after_methods(JfrBigEndianWriter& writer, |
|
674 const ClassFileStream* stream, |
|
675 const u2* utf8_indexes, |
|
676 bool register_klass, |
|
677 const Method* clinit_method, |
|
678 u4& orig_method_len_offset) { |
|
679 assert(stream != NULL, "invariant"); |
|
680 assert(stream->current_offset() > 0, "invariant"); |
|
681 assert(utf8_indexes != NULL, "invariant"); |
|
682 // We will come back to this location when we |
|
683 // know how many methods there will be. |
|
684 writer.reserve(sizeof(u2)); |
|
685 const u2 orig_methods_len = stream->get_u2_fast(); |
|
686 // Move copy position past original method_count |
|
687 // in order to not copy the original count |
|
688 orig_method_len_offset += sizeof(u2); |
|
689 for (u2 i = 0; i < orig_methods_len; ++i) { |
|
690 const u4 method_offset = stream->current_offset(); |
|
691 stream->skip_u2_fast(1); // Access Flags |
|
692 const u2 name_index = stream->get_u2_fast(); // Name index |
|
693 stream->skip_u2_fast(1); // Descriptor index |
|
694 const u2 attributes_count = stream->get_u2_fast(); |
|
695 for (u2 j = 0; j < attributes_count; ++j) { |
|
696 stream->skip_u2_fast(1); |
|
697 const u4 attrib_len = stream->get_u4_fast(); |
|
698 stream->skip_u1_fast(attrib_len); |
|
699 } |
|
700 if (clinit_method != NULL && name_index == clinit_method->name_index()) { |
|
701 // The method just parsed is an existing <clinit> method. |
|
702 // If the class has the @Registered(false) annotation, i.e. marking a class |
|
703 // for opting out from automatic registration, then we do not need to do anything. |
|
704 if (!register_klass) { |
|
705 continue; |
|
706 } |
|
707 // Automatic registration with the jfr system is acccomplished |
|
708 // by pre-pending code to the <clinit> method of the class. |
|
709 // We will need to re-create a new <clinit> in a later step. |
|
710 // For now, ensure that this method is excluded from the methods |
|
711 // being copied. |
|
712 writer.bytes(stream->buffer() + orig_method_len_offset, |
|
713 method_offset - orig_method_len_offset); |
|
714 assert(writer.is_valid(), "invariant"); |
|
715 |
|
716 // Update copy position to skip copy of <clinit> method |
|
717 orig_method_len_offset = stream->current_offset(); |
|
718 } |
|
719 } |
|
720 return orig_methods_len; |
|
721 } |
|
722 |
|
723 static u2 add_method_infos(JfrBigEndianWriter& writer, const u2* utf8_indexes) { |
|
724 assert(utf8_indexes != NULL, "invariant"); |
|
725 add_method_info(writer, |
|
726 utf8_indexes[UTF8_REQ_begin], |
|
727 utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC], |
|
728 utf8_indexes[UTF8_REQ_Code], |
|
729 empty_void_method_code_attribute, |
|
730 sizeof(empty_void_method_code_attribute)); |
|
731 |
|
732 assert(writer.is_valid(), "invariant"); |
|
733 |
|
734 add_method_info(writer, |
|
735 utf8_indexes[UTF8_REQ_end], |
|
736 utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC], |
|
737 utf8_indexes[UTF8_REQ_Code], |
|
738 empty_void_method_code_attribute, |
|
739 sizeof(empty_void_method_code_attribute)); |
|
740 |
|
741 assert(writer.is_valid(), "invariant"); |
|
742 |
|
743 add_method_info(writer, |
|
744 utf8_indexes[UTF8_REQ_commit], |
|
745 utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC], |
|
746 utf8_indexes[UTF8_REQ_Code], |
|
747 empty_void_method_code_attribute, |
|
748 sizeof(empty_void_method_code_attribute)); |
|
749 |
|
750 assert(writer.is_valid(), "invariant"); |
|
751 |
|
752 add_method_info(writer, |
|
753 utf8_indexes[UTF8_REQ_isEnabled], |
|
754 utf8_indexes[UTF8_REQ_EMPTY_BOOLEAN_METHOD_DESC], |
|
755 utf8_indexes[UTF8_REQ_Code], |
|
756 boolean_method_code_attribute, |
|
757 sizeof(boolean_method_code_attribute)); |
|
758 |
|
759 assert(writer.is_valid(), "invariant"); |
|
760 |
|
761 add_method_info(writer, |
|
762 utf8_indexes[UTF8_REQ_shouldCommit], |
|
763 utf8_indexes[UTF8_REQ_EMPTY_BOOLEAN_METHOD_DESC], |
|
764 utf8_indexes[UTF8_REQ_Code], |
|
765 boolean_method_code_attribute, |
|
766 sizeof(boolean_method_code_attribute)); |
|
767 assert(writer.is_valid(), "invariant"); |
|
768 return number_of_new_methods; |
|
769 } |
|
770 |
|
771 static void adjust_exception_table(JfrBigEndianWriter& writer, u2 bci_adjustment_offset, const Method* method, TRAPS) { |
|
772 const u2 ex_table_length = method != NULL ? (u2)method->exception_table_length() : 0; |
|
773 writer.write<u2>(ex_table_length); // Exception table length |
|
774 if (ex_table_length > 0) { |
|
775 assert(method != NULL, "invariant"); |
|
776 const ExceptionTableElement* const ex_elements = method->exception_table_start(); |
|
777 for (int i = 0; i < ex_table_length; ++i) { |
|
778 assert(ex_elements != NULL, "invariant"); |
|
779 writer.write<u2>(ex_elements[i].start_pc + bci_adjustment_offset); |
|
780 writer.write<u2>(ex_elements[i].end_pc + bci_adjustment_offset); |
|
781 writer.write<u2>(ex_elements[i].handler_pc + bci_adjustment_offset); |
|
782 writer.write<u2>(ex_elements[i].catch_type_index); // no adjustment |
|
783 } |
|
784 } |
|
785 } |
|
786 |
|
787 enum StackMapFrameTypes { |
|
788 SAME_FRAME_BEGIN = 0, |
|
789 SAME_FRAME_END = 63, |
|
790 SAME_LOCALS_1_STACK_ITEM_FRAME_BEGIN = 64, |
|
791 SAME_LOCALS_1_STACK_ITEM_FRAME_END = 127, |
|
792 SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247, |
|
793 CHOP_FRAME_BEGIN = 248, |
|
794 CHOP_FRAME_END = 250, |
|
795 SAME_FRAME_EXTENDED = 251, |
|
796 APPEND_FRAME_BEGIN = 252, |
|
797 APPEND_FRAME_END = 254, |
|
798 FULL_FRAME = 255 |
|
799 }; |
|
800 |
|
801 static void adjust_stack_map(JfrBigEndianWriter& writer, |
|
802 Array<u1>* stack_map, |
|
803 const u2* utf8_indexes, |
|
804 u2 bci_adjustment_offset, |
|
805 TRAPS) { |
|
806 assert(stack_map != NULL, "invariant"); |
|
807 assert(utf8_indexes != NULL, "invariant"); |
|
808 writer.write<u2>(utf8_indexes[UTF8_OPT_StackMapTable]); |
|
809 const jlong stack_map_attrib_len_offset = writer.current_offset(); |
|
810 writer.reserve(sizeof(u4)); |
|
811 StackMapStream stream(stack_map); |
|
812 const u2 stack_map_entries = stream.get_u2(THREAD); |
|
813 // number of entries |
|
814 writer.write<u2>(stack_map_entries); // new stack map entry added |
|
815 const u1 frame_type = stream.get_u1(THREAD); |
|
816 // SAME_FRAME and SAME_LOCALS_1_STACK_ITEM_FRAME encode |
|
817 // their offset_delta into the actual frame type itself. |
|
818 // If such a frame type is the first frame, then we transform |
|
819 // it to a SAME_FRAME_EXTENDED or a SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED frame. |
|
820 // This is done in order to not overflow frame types accidentally |
|
821 // when adjusting the offset_delta. In changing the frame types, |
|
822 // we can work with an explicit u2 offset_delta field (like the other frame types) |
|
823 if (frame_type <= SAME_FRAME_END) { |
|
824 writer.write<u1>(SAME_FRAME_EXTENDED); |
|
825 writer.write<u2>(frame_type + bci_adjustment_offset); |
|
826 } else if (frame_type >= SAME_LOCALS_1_STACK_ITEM_FRAME_BEGIN && |
|
827 frame_type <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) { |
|
828 writer.write<u1>(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED); |
|
829 writer.write<u2>((frame_type - SAME_LOCALS_1_STACK_ITEM_FRAME_BEGIN) + bci_adjustment_offset); |
|
830 } else if (frame_type >= SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { |
|
831 // SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED to FULL_FRAME |
|
832 // has a u2 offset_delta field |
|
833 writer.write<u1>(frame_type); |
|
834 writer.write<u2>(stream.get_u2(THREAD) + bci_adjustment_offset); |
|
835 } else { |
|
836 assert(false, "stackMapFrame type is invalid"); |
|
837 } |
|
838 |
|
839 while (!stream.at_end()) { |
|
840 writer.write<u1>(stream.get_u1(THREAD)); |
|
841 } |
|
842 |
|
843 u4 stack_map_attrib_len = writer.current_offset() - stack_map_attrib_len_offset; |
|
844 // the stack_map_table_attributes_length value is exclusive |
|
845 stack_map_attrib_len -= sizeof(u4); |
|
846 writer.write_at_offset(stack_map_attrib_len, stack_map_attrib_len_offset); |
|
847 } |
|
848 |
|
849 static void adjust_line_number_table(JfrBigEndianWriter& writer, |
|
850 const u2* utf8_indexes, |
|
851 u4 bci_adjustement_offset, |
|
852 const Method* method, |
|
853 TRAPS) { |
|
854 assert(utf8_indexes != NULL, "invariant"); |
|
855 assert(method != NULL, "invariant"); |
|
856 assert(method->has_linenumber_table(), "invariant"); |
|
857 writer.write(utf8_indexes[UTF8_OPT_LineNumberTable]); |
|
858 const jlong lnt_attributes_length_offset = writer.current_offset(); |
|
859 writer.reserve(sizeof(u4)); |
|
860 const jlong lnt_attributes_entries_offset = writer.current_offset(); |
|
861 writer.reserve(sizeof(u2)); |
|
862 u1* lnt = method->compressed_linenumber_table(); |
|
863 CompressedLineNumberReadStream lnt_stream(lnt); |
|
864 u2 line_number_table_entries = 0; |
|
865 while (lnt_stream.read_pair()) { |
|
866 ++line_number_table_entries; |
|
867 const u2 bci = (u2)lnt_stream.bci(); |
|
868 writer.write<u2>(bci + (u2)bci_adjustement_offset); |
|
869 writer.write<u2>((u2)lnt_stream.line()); |
|
870 } |
|
871 writer.write_at_offset(line_number_table_entries, lnt_attributes_entries_offset); |
|
872 u4 lnt_table_attributes_len = writer.current_offset() - lnt_attributes_length_offset; |
|
873 // the line_number_table_attributes_length value is exclusive |
|
874 lnt_table_attributes_len -= sizeof(u4); |
|
875 writer.write_at_offset(lnt_table_attributes_len, lnt_attributes_length_offset); |
|
876 } |
|
877 |
|
878 // returns the number of lvtt entries |
|
879 static u2 adjust_local_variable_table(JfrBigEndianWriter& writer, |
|
880 const u2* utf8_indexes, |
|
881 u2 bci_adjustment_offset, |
|
882 const Method* method, |
|
883 TRAPS) { |
|
884 assert(utf8_indexes != NULL, "invariant"); |
|
885 assert(method != NULL, "invariant"); |
|
886 assert(method->has_localvariable_table(), "invariant"); |
|
887 writer.write<u2>(utf8_indexes[UTF8_OPT_LocalVariableTable]); |
|
888 const jlong lvt_attributes_length_offset = writer.current_offset(); |
|
889 writer.reserve(sizeof(u4)); |
|
890 const int lvt_len = method->localvariable_table_length(); |
|
891 writer.write<u2>((u2)lvt_len); |
|
892 const LocalVariableTableElement* table = method->localvariable_table_start(); |
|
893 assert(table != NULL, "invariant"); |
|
894 u2 num_lvtt_entries = 0; |
|
895 for (int i = 0; i < lvt_len; ++i) { |
|
896 writer.write<u2>(table[i].start_bci + bci_adjustment_offset); |
|
897 writer.write<u2>(table[i].length); |
|
898 writer.write<u2>(table[i].name_cp_index); |
|
899 writer.write<u2>(table[i].descriptor_cp_index); |
|
900 writer.write<u2>(table[i].slot); |
|
901 if (table[i].signature_cp_index > 0) { |
|
902 ++num_lvtt_entries; |
|
903 } |
|
904 } |
|
905 u4 lvt_table_attributes_len = writer.current_offset() - lvt_attributes_length_offset; |
|
906 // the lvt_table_attributes_length value is exclusive |
|
907 lvt_table_attributes_len -= sizeof(u4); |
|
908 writer.write_at_offset(lvt_table_attributes_len, lvt_attributes_length_offset); |
|
909 return num_lvtt_entries; |
|
910 } |
|
911 |
|
912 static void adjust_local_variable_type_table(JfrBigEndianWriter& writer, |
|
913 const u2* utf8_indexes, |
|
914 u2 bci_adjustment_offset, |
|
915 u2 num_lvtt_entries, |
|
916 const Method* method, |
|
917 TRAPS) { |
|
918 assert(num_lvtt_entries > 0, "invariant"); |
|
919 writer.write<u2>(utf8_indexes[UTF8_OPT_LocalVariableTypeTable]); |
|
920 const jlong lvtt_attributes_length_offset = writer.current_offset(); |
|
921 writer.reserve(sizeof(u4)); |
|
922 writer.write<u2>(num_lvtt_entries); |
|
923 const LocalVariableTableElement* table = method->localvariable_table_start(); |
|
924 assert(table != NULL, "invariant"); |
|
925 const int lvt_len = method->localvariable_table_length(); |
|
926 for (int i = 0; i < lvt_len; ++i) { |
|
927 if (table[i].signature_cp_index > 0) { |
|
928 writer.write<u2>(table[i].start_bci + bci_adjustment_offset); |
|
929 writer.write<u2>(table[i].length); |
|
930 writer.write<u2>(table[i].name_cp_index); |
|
931 writer.write<u2>(table[i].signature_cp_index); |
|
932 writer.write<u2>(table[i].slot); |
|
933 } |
|
934 } |
|
935 u4 lvtt_table_attributes_len = writer.current_offset() - lvtt_attributes_length_offset; |
|
936 // the lvtt_table_attributes_length value is exclusive |
|
937 lvtt_table_attributes_len -= sizeof(u4); |
|
938 writer.write_at_offset(lvtt_table_attributes_len, lvtt_attributes_length_offset); |
|
939 } |
|
940 |
|
941 static void adjust_code_attributes(JfrBigEndianWriter& writer, |
|
942 const u2* utf8_indexes, |
|
943 u2 bci_adjustment_offset, |
|
944 const Method* clinit_method, |
|
945 TRAPS) { |
|
946 // "Code" attributes |
|
947 assert(utf8_indexes != NULL, "invariant"); |
|
948 const jlong code_attributes_offset = writer.current_offset(); |
|
949 writer.reserve(sizeof(u2)); |
|
950 u2 number_of_code_attributes = 0; |
|
951 if (clinit_method != NULL) { |
|
952 Array<u1>* stack_map = clinit_method->stackmap_data(); |
|
953 if (stack_map != NULL) { |
|
954 ++number_of_code_attributes; |
|
955 adjust_stack_map(writer, stack_map, utf8_indexes, bci_adjustment_offset, THREAD); |
|
956 assert(writer.is_valid(), "invariant"); |
|
957 } |
|
958 if (clinit_method != NULL && clinit_method->has_linenumber_table()) { |
|
959 ++number_of_code_attributes; |
|
960 adjust_line_number_table(writer, utf8_indexes, bci_adjustment_offset, clinit_method, THREAD); |
|
961 assert(writer.is_valid(), "invariant"); |
|
962 } |
|
963 if (clinit_method != NULL && clinit_method->has_localvariable_table()) { |
|
964 ++number_of_code_attributes; |
|
965 const u2 num_of_lvtt_entries = adjust_local_variable_table(writer, utf8_indexes, bci_adjustment_offset, clinit_method, THREAD); |
|
966 assert(writer.is_valid(), "invariant"); |
|
967 if (num_of_lvtt_entries > 0) { |
|
968 ++number_of_code_attributes; |
|
969 adjust_local_variable_type_table(writer, utf8_indexes, bci_adjustment_offset, num_of_lvtt_entries, clinit_method, THREAD); |
|
970 assert(writer.is_valid(), "invariant"); |
|
971 } |
|
972 } |
|
973 } |
|
974 |
|
975 // Store the number of code_attributes |
|
976 writer.write_at_offset(number_of_code_attributes, code_attributes_offset); |
|
977 } |
|
978 |
|
979 static jlong insert_clinit_method(const InstanceKlass* ik, |
|
980 const ClassFileParser& parser, |
|
981 JfrBigEndianWriter& writer, |
|
982 u2 orig_constant_pool_len, |
|
983 const u2* utf8_indexes, |
|
984 const u2 register_method_ref_index, |
|
985 const Method* clinit_method, |
|
986 TRAPS) { |
|
987 assert(utf8_indexes != NULL, "invariant"); |
|
988 // The injected code length is always this value. |
|
989 // This is to ensure that padding can be done |
|
990 // where needed and to simplify size calculations. |
|
991 static const u2 injected_code_length = 8; |
|
992 const u2 name_index = utf8_indexes[UTF8_REQ_clinit]; |
|
993 const u2 desc_index = utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC]; |
|
994 const u2 max_stack = MAX2(clinit_method != NULL ? clinit_method->verifier_max_stack() : 1, 1); |
|
995 const u2 max_locals = MAX2(clinit_method != NULL ? clinit_method->max_locals() : 0, 0); |
|
996 const u2 orig_bytecodes_length = clinit_method != NULL ? (u2)clinit_method->code_size() : 0; |
|
997 const address orig_bytecodes = clinit_method != NULL ? clinit_method->code_base() : NULL; |
|
998 const u2 new_code_length = injected_code_length + orig_bytecodes_length; |
|
999 DEBUG_ONLY(const jlong start_offset = writer.current_offset();) |
|
1000 writer.write<u2>(JVM_ACC_STATIC); // flags |
|
1001 writer.write<u2>(name_index); |
|
1002 writer.write<u2>(desc_index); |
|
1003 writer.write<u2>((u2)0x1); // attributes_count // "Code" |
|
1004 assert(writer.is_valid(), "invariant"); |
|
1005 DEBUG_ONLY(assert(start_offset + 8 == writer.current_offset(), "invariant");) |
|
1006 // "Code" attribute |
|
1007 writer.write<u2>(utf8_indexes[UTF8_REQ_Code]); // "Code" |
|
1008 const jlong code_attribute_length_offset = writer.current_offset(); |
|
1009 writer.reserve(sizeof(u4)); |
|
1010 writer.write<u2>(max_stack); // max stack |
|
1011 writer.write<u2>(max_locals); // max locals |
|
1012 writer.write<u4>((u4)new_code_length); // code length |
|
1013 |
|
1014 /* BEGIN CLINIT CODE */ |
|
1015 |
|
1016 // Note the use of ldc_w here instead of ldc. |
|
1017 // This is to handle all values of "this_class_index" |
|
1018 writer.write<u1>((u1)Bytecodes::_ldc_w); |
|
1019 writer.write<u2>((u2)parser.this_class_index()); // load constant "this class" |
|
1020 writer.write<u1>((u1)Bytecodes::_invokestatic); |
|
1021 // invoke "FlightRecorder.register(Ljava/lang/Class;") |
|
1022 writer.write<u2>(register_method_ref_index); |
|
1023 if (clinit_method == NULL) { |
|
1024 writer.write<u1>((u1)Bytecodes::_nop); |
|
1025 writer.write<u1>((u1)Bytecodes::_return); |
|
1026 } else { |
|
1027 // If we are pre-pending to original code, |
|
1028 // do padding to minimize disruption to the original. |
|
1029 // It might have dependencies on 4-byte boundaries |
|
1030 // i.e. lookupswitch and tableswitch instructions |
|
1031 writer.write<u1>((u1)Bytecodes::_nop); |
|
1032 writer.write<u1>((u1)Bytecodes::_nop); |
|
1033 // insert original clinit code |
|
1034 writer.bytes(orig_bytecodes, orig_bytecodes_length); |
|
1035 } |
|
1036 |
|
1037 /* END CLINIT CODE */ |
|
1038 |
|
1039 assert(writer.is_valid(), "invariant"); |
|
1040 adjust_exception_table(writer, injected_code_length, clinit_method, THREAD); |
|
1041 assert(writer.is_valid(), "invariant"); |
|
1042 adjust_code_attributes(writer, utf8_indexes, injected_code_length, clinit_method, THREAD); |
|
1043 assert(writer.is_valid(), "invariant"); |
|
1044 u4 code_attribute_len = writer.current_offset() - code_attribute_length_offset; |
|
1045 // the code_attribute_length value is exclusive |
|
1046 code_attribute_len -= sizeof(u4); |
|
1047 writer.write_at_offset(code_attribute_len, code_attribute_length_offset); |
|
1048 return writer.current_offset(); |
|
1049 } |
|
1050 |
|
1051 // Caller needs ResourceMark |
|
1052 static ClassFileStream* create_new_bytes_for_event_klass(const InstanceKlass* ik, const ClassFileParser& parser, TRAPS) { |
|
1053 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); |
|
1054 static const u2 public_final_flag_mask = JVM_ACC_PUBLIC | JVM_ACC_FINAL; |
|
1055 const ClassFileStream* const orig_stream = parser.clone_stream(); |
|
1056 const int orig_stream_length = orig_stream->length(); |
|
1057 // allocate an identically sized buffer |
|
1058 u1* const new_buffer = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, u1, orig_stream_length); |
|
1059 if (new_buffer == NULL) { |
|
1060 return NULL; |
|
1061 } |
|
1062 assert(new_buffer != NULL, "invariant"); |
|
1063 // memcpy the entire [B |
|
1064 memcpy(new_buffer, orig_stream->buffer(), orig_stream_length); |
|
1065 const u2 orig_cp_len = position_stream_after_cp(orig_stream); |
|
1066 assert(orig_cp_len > 0, "invariant"); |
|
1067 assert(orig_stream->current_offset() > 0, "invariant"); |
|
1068 orig_stream->skip_u2_fast(3); // access_flags, this_class_index, super_class_index |
|
1069 const u2 iface_len = orig_stream->get_u2_fast(); |
|
1070 orig_stream->skip_u2_fast(iface_len); |
|
1071 // fields len |
|
1072 const u2 orig_fields_len = orig_stream->get_u2_fast(); |
|
1073 // fields |
|
1074 for (u2 i = 0; i < orig_fields_len; ++i) { |
|
1075 orig_stream->skip_u2_fast(3); |
|
1076 const u2 attrib_info_len = orig_stream->get_u2_fast(); |
|
1077 for (u2 j = 0; j < attrib_info_len; ++j) { |
|
1078 orig_stream->skip_u2_fast(1); |
|
1079 const u4 attrib_len = orig_stream->get_u4_fast(); |
|
1080 orig_stream->skip_u1_fast(attrib_len); |
|
1081 } |
|
1082 } |
|
1083 // methods |
|
1084 const u2 orig_methods_len = orig_stream->get_u2_fast(); |
|
1085 for (u2 i = 0; i < orig_methods_len; ++i) { |
|
1086 const u4 access_flag_offset = orig_stream->current_offset(); |
|
1087 const u2 flags = orig_stream->get_u2_fast(); |
|
1088 // Rewrite JVM_ACC_FINAL -> JVM_ACC_PUBLIC |
|
1089 if (public_final_flag_mask == flags) { |
|
1090 JfrBigEndianWriter accessflagsrewriter(new_buffer + access_flag_offset, sizeof(u2)); |
|
1091 accessflagsrewriter.write<u2>(JVM_ACC_PUBLIC); |
|
1092 assert(accessflagsrewriter.is_valid(), "invariant"); |
|
1093 } |
|
1094 orig_stream->skip_u2_fast(2); |
|
1095 const u2 attributes_count = orig_stream->get_u2_fast(); |
|
1096 for (u2 j = 0; j < attributes_count; ++j) { |
|
1097 orig_stream->skip_u2_fast(1); |
|
1098 const u4 attrib_len = orig_stream->get_u4_fast(); |
|
1099 orig_stream->skip_u1_fast(attrib_len); |
|
1100 } |
|
1101 } |
|
1102 return new ClassFileStream(new_buffer, orig_stream_length, NULL, ClassFileStream::verify); |
|
1103 } |
|
1104 |
|
1105 // Attempt to locate an existing UTF8_INFO mapping the utf8_constant. |
|
1106 // If no UTF8_INFO exists, add (append) a new one to the constant pool. |
|
1107 static u2 find_or_add_utf8_info(JfrBigEndianWriter& writer, |
|
1108 const InstanceKlass* ik, |
|
1109 const char* const utf8_constant, |
|
1110 u2 orig_cp_len, |
|
1111 u2& added_cp_entries, |
|
1112 TRAPS) { |
|
1113 assert(utf8_constant != NULL, "invariant"); |
|
1114 TempNewSymbol utf8_sym = SymbolTable::new_symbol(utf8_constant, THREAD); |
|
1115 // lookup existing |
|
1116 const int utf8_orig_idx = utf8_info_index(ik, utf8_sym, THREAD); |
|
1117 if (utf8_orig_idx != invalid_cp_index) { |
|
1118 // existing constant pool entry found |
|
1119 return utf8_orig_idx; |
|
1120 } |
|
1121 // no existing match, need to add a new utf8 cp entry |
|
1122 assert(invalid_cp_index == utf8_orig_idx, "invariant"); |
|
1123 // add / append new |
|
1124 return add_utf8_info(writer, utf8_constant, orig_cp_len, added_cp_entries); |
|
1125 } |
|
1126 |
|
1127 /* |
|
1128 * This routine will resolve the required utf8_constants array |
|
1129 * to their constant pool indexes (mapping to their UTF8_INFO's) |
|
1130 * Only if a constant is actually needed and does not already exist |
|
1131 * will it be added. |
|
1132 * |
|
1133 * The passed in indexes array will be populated with the resolved indexes. |
|
1134 * The number of newly added constant pool entries is returned. |
|
1135 */ |
|
1136 static u2 resolve_utf8_indexes(JfrBigEndianWriter& writer, |
|
1137 const InstanceKlass* ik, |
|
1138 u2* const utf8_indexes, |
|
1139 u2 orig_cp_len, |
|
1140 const Method* clinit_method, |
|
1141 TRAPS) { |
|
1142 assert(utf8_indexes != NULL, "invariant"); |
|
1143 u2 added_cp_entries = 0; |
|
1144 // resolve all required symbols |
|
1145 for (u2 index = 0; index < NOF_UTF8_REQ_SYMBOLS; ++index) { |
|
1146 utf8_indexes[index] = find_or_add_utf8_info(writer, |
|
1147 ik, |
|
1148 utf8_constants[index], |
|
1149 orig_cp_len, |
|
1150 added_cp_entries, |
|
1151 THREAD); |
|
1152 } |
|
1153 // Now determine optional constants (mainly "Code" attributes) |
|
1154 if (clinit_method != NULL && clinit_method->has_stackmap_table()) { |
|
1155 utf8_indexes[UTF8_OPT_StackMapTable] = |
|
1156 find_or_add_utf8_info(writer, |
|
1157 ik, |
|
1158 utf8_constants[UTF8_OPT_StackMapTable], |
|
1159 orig_cp_len, |
|
1160 added_cp_entries, |
|
1161 THREAD); |
|
1162 } else { |
|
1163 utf8_indexes[UTF8_OPT_StackMapTable] = invalid_cp_index; |
|
1164 } |
|
1165 |
|
1166 if (clinit_method != NULL && clinit_method->has_linenumber_table()) { |
|
1167 utf8_indexes[UTF8_OPT_LineNumberTable] = |
|
1168 find_or_add_utf8_info(writer, |
|
1169 ik, |
|
1170 utf8_constants[UTF8_OPT_LineNumberTable], |
|
1171 orig_cp_len, |
|
1172 added_cp_entries, |
|
1173 THREAD); |
|
1174 } else { |
|
1175 utf8_indexes[UTF8_OPT_LineNumberTable] = invalid_cp_index; |
|
1176 } |
|
1177 |
|
1178 if (clinit_method != NULL && clinit_method->has_localvariable_table()) { |
|
1179 utf8_indexes[UTF8_OPT_LocalVariableTable] = |
|
1180 find_or_add_utf8_info(writer, |
|
1181 ik, |
|
1182 utf8_constants[UTF8_OPT_LocalVariableTable], |
|
1183 orig_cp_len, |
|
1184 added_cp_entries, |
|
1185 THREAD); |
|
1186 |
|
1187 utf8_indexes[UTF8_OPT_LocalVariableTypeTable] = |
|
1188 find_or_add_utf8_info(writer, |
|
1189 ik, |
|
1190 utf8_constants[UTF8_OPT_LocalVariableTypeTable], |
|
1191 orig_cp_len, |
|
1192 added_cp_entries, |
|
1193 THREAD); |
|
1194 } else { |
|
1195 utf8_indexes[UTF8_OPT_LocalVariableTable] = invalid_cp_index; |
|
1196 utf8_indexes[UTF8_OPT_LocalVariableTypeTable] = invalid_cp_index; |
|
1197 } |
|
1198 |
|
1199 return added_cp_entries; |
|
1200 } |
|
1201 |
|
1202 static u1* new_bytes_for_lazy_instrumentation(const InstanceKlass* ik, |
|
1203 const ClassFileParser& parser, |
|
1204 jint& size_of_new_bytes, |
|
1205 TRAPS) { |
|
1206 assert(ik != NULL, "invariant"); |
|
1207 // If the class already has a clinit method |
|
1208 // we need to take that into account |
|
1209 const Method* clinit_method = ik->class_initializer(); |
|
1210 const bool register_klass = should_register_klass(ik); |
|
1211 const ClassFileStream* const orig_stream = parser.clone_stream(); |
|
1212 const int orig_stream_size = orig_stream->length(); |
|
1213 assert(orig_stream->current_offset() == 0, "invariant"); |
|
1214 const u2 orig_cp_len = position_stream_after_cp(orig_stream); |
|
1215 assert(orig_cp_len > 0, "invariant"); |
|
1216 assert(orig_stream->current_offset() > 0, "invariant"); |
|
1217 // Dimension and allocate a working byte buffer |
|
1218 // to be used in building up a modified class [B. |
|
1219 const jint new_buffer_size = extra_stream_bytes + orig_stream_size; |
|
1220 u1* const new_buffer = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, u1, new_buffer_size); |
|
1221 if (new_buffer == NULL) { |
|
1222 log_error(jfr, system) ("Thread local allocation (native) for " SIZE_FORMAT |
|
1223 " bytes failed in JfrClassAdapter::on_klass_creation", (size_t)new_buffer_size); |
|
1224 return NULL; |
|
1225 } |
|
1226 assert(new_buffer != NULL, "invariant"); |
|
1227 // [B wrapped in a big endian writer |
|
1228 JfrBigEndianWriter writer(new_buffer, new_buffer_size); |
|
1229 assert(writer.current_offset() == 0, "invariant"); |
|
1230 const u4 orig_access_flag_offset = orig_stream->current_offset(); |
|
1231 // Copy original stream from the beginning up to AccessFlags |
|
1232 // This means the original constant pool contents are copied unmodified |
|
1233 writer.bytes(orig_stream->buffer(), orig_access_flag_offset); |
|
1234 assert(writer.is_valid(), "invariant"); |
|
1235 assert(writer.current_offset() == orig_access_flag_offset, "invariant"); // same positions |
|
1236 // Our writer now sits just after the last original constant pool entry. |
|
1237 // I.e. we are in a good position to append new constant pool entries |
|
1238 // This array will contain the resolved indexes |
|
1239 // in order to reference UTF8_INFO's needed |
|
1240 u2 utf8_indexes[NOF_UTF8_SYMBOLS]; |
|
1241 // Resolve_utf8_indexes will be conservative in attempting to |
|
1242 // locate an existing UTF8_INFO; it will only append constants |
|
1243 // that is absolutely required |
|
1244 u2 number_of_new_constants = resolve_utf8_indexes(writer, ik, utf8_indexes, orig_cp_len, clinit_method, THREAD); |
|
1245 // UTF8_INFO entries now added to the constant pool |
|
1246 // In order to invoke a method we would need additional |
|
1247 // constants, JVM_CONSTANT_Class, JVM_CONSTANT_NameAndType |
|
1248 // and JVM_CONSTANT_Methodref. |
|
1249 const u2 flr_register_method_ref_index = |
|
1250 register_klass ? |
|
1251 add_flr_register_method_constants(writer, |
|
1252 utf8_indexes, |
|
1253 orig_cp_len, |
|
1254 number_of_new_constants, |
|
1255 THREAD) : invalid_cp_index; |
|
1256 |
|
1257 // New constant pool entries added and all UTF8_INFO indexes resolved |
|
1258 // Now update the class file constant_pool_count with an updated count |
|
1259 writer.write_at_offset<u2>(orig_cp_len + number_of_new_constants, 8); |
|
1260 assert(writer.is_valid(), "invariant"); |
|
1261 orig_stream->skip_u2_fast(3); // access_flags, this_class_index, super_class_index |
|
1262 const u2 iface_len = orig_stream->get_u2_fast(); // interfaces |
|
1263 orig_stream->skip_u2_fast(iface_len); |
|
1264 const u4 orig_fields_len_offset = orig_stream->current_offset(); |
|
1265 // Copy from AccessFlags up to and including interfaces |
|
1266 writer.bytes(orig_stream->buffer() + orig_access_flag_offset, |
|
1267 orig_fields_len_offset - orig_access_flag_offset); |
|
1268 assert(writer.is_valid(), "invariant"); |
|
1269 const jlong new_fields_len_offset = writer.current_offset(); |
|
1270 const u2 orig_fields_len = position_stream_after_fields(orig_stream); |
|
1271 u4 orig_method_len_offset = orig_stream->current_offset(); |
|
1272 // Copy up to and including fields |
|
1273 writer.bytes(orig_stream->buffer() + orig_fields_len_offset, orig_method_len_offset - orig_fields_len_offset); |
|
1274 assert(writer.is_valid(), "invariant"); |
|
1275 // We are sitting just after the original number of field_infos |
|
1276 // so this is a position where we can add (append) new field_infos |
|
1277 const u2 number_of_new_fields = add_field_infos(writer, utf8_indexes); |
|
1278 assert(writer.is_valid(), "invariant"); |
|
1279 const jlong new_method_len_offset = writer.current_offset(); |
|
1280 // Additional field_infos added, update classfile fields_count |
|
1281 writer.write_at_offset<u2>(orig_fields_len + number_of_new_fields, new_fields_len_offset); |
|
1282 assert(writer.is_valid(), "invariant"); |
|
1283 // Our current location is now at classfile methods_count |
|
1284 const u2 orig_methods_len = position_stream_after_methods(writer, |
|
1285 orig_stream, |
|
1286 utf8_indexes, |
|
1287 register_klass, |
|
1288 clinit_method, |
|
1289 orig_method_len_offset); |
|
1290 const u4 orig_attributes_count_offset = orig_stream->current_offset(); |
|
1291 // Copy existing methods |
|
1292 writer.bytes(orig_stream->buffer() + orig_method_len_offset, orig_attributes_count_offset - orig_method_len_offset); |
|
1293 assert(writer.is_valid(), "invariant"); |
|
1294 // We are sitting just after the original number of method_infos |
|
1295 // so this is a position where we can add (append) new method_infos |
|
1296 u2 number_of_new_methods = add_method_infos(writer, utf8_indexes); |
|
1297 |
|
1298 // We have just added the new methods. |
|
1299 // |
|
1300 // What about the state of <clinit>? |
|
1301 // We would need to do: |
|
1302 // 1. Nothing (@Registered(false) annotation) |
|
1303 // 2. Build up a new <clinit> - and if the original class already contains a <clinit>, |
|
1304 // merging will be neccessary. |
|
1305 // |
|
1306 if (register_klass) { |
|
1307 insert_clinit_method(ik, parser, writer, orig_cp_len, utf8_indexes, flr_register_method_ref_index, clinit_method, THREAD); |
|
1308 } |
|
1309 number_of_new_methods += clinit_method != NULL ? 0 : register_klass ? 1 : 0; |
|
1310 // Update classfile methods_count |
|
1311 writer.write_at_offset<u2>(orig_methods_len + number_of_new_methods, new_method_len_offset); |
|
1312 assert(writer.is_valid(), "invariant"); |
|
1313 // Copy last remaining bytes |
|
1314 writer.bytes(orig_stream->buffer() + orig_attributes_count_offset, orig_stream_size - orig_attributes_count_offset); |
|
1315 assert(writer.is_valid(), "invariant"); |
|
1316 assert(writer.current_offset() > orig_stream->length(), "invariant"); |
|
1317 size_of_new_bytes = (jint)writer.current_offset(); |
|
1318 return new_buffer; |
|
1319 } |
|
1320 |
|
1321 static void log_pending_exception(oop throwable) { |
|
1322 assert(throwable != NULL, "invariant"); |
|
1323 oop msg = java_lang_Throwable::message(throwable); |
|
1324 if (msg != NULL) { |
|
1325 char* text = java_lang_String::as_utf8_string(msg); |
|
1326 if (text != NULL) { |
|
1327 log_error(jfr, system) ("%s", text); |
|
1328 } |
|
1329 } |
|
1330 } |
|
1331 |
|
1332 static bool should_force_instrumentation() { |
|
1333 return !JfrOptionSet::allow_event_retransforms() || JfrEventClassTransformer::is_force_instrumentation(); |
|
1334 } |
|
1335 |
|
1336 static ClassFileStream* create_new_bytes_for_subklass(const InstanceKlass* ik, const ClassFileParser& parser, Thread* t) { |
|
1337 assert(JdkJfrEvent::is_a(ik), "invariant"); |
|
1338 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t)); |
|
1339 jint size_of_new_bytes = 0; |
|
1340 const u1* new_bytes = new_bytes_for_lazy_instrumentation(ik, parser, size_of_new_bytes, t); |
|
1341 if (new_bytes == NULL) { |
|
1342 return NULL; |
|
1343 } |
|
1344 assert(new_bytes != NULL, "invariant"); |
|
1345 assert(size_of_new_bytes > 0, "invariant"); |
|
1346 |
|
1347 bool force_instrumentation = should_force_instrumentation(); |
|
1348 if (Jfr::is_recording() || force_instrumentation) { |
|
1349 jint size_instrumented_data = 0; |
|
1350 unsigned char* instrumented_data = NULL; |
|
1351 const jclass super = (jclass)JNIHandles::make_local(ik->super()->java_mirror()); |
|
1352 JfrUpcalls::new_bytes_eager_instrumentation(TRACE_ID(ik), |
|
1353 force_instrumentation, |
|
1354 super, |
|
1355 size_of_new_bytes, |
|
1356 new_bytes, |
|
1357 &size_instrumented_data, |
|
1358 &instrumented_data, |
|
1359 t); |
|
1360 if (t->has_pending_exception()) { |
|
1361 log_pending_exception(t->pending_exception()); |
|
1362 t->clear_pending_exception(); |
|
1363 return NULL; |
|
1364 } |
|
1365 assert(instrumented_data != NULL, "invariant"); |
|
1366 assert(size_instrumented_data > 0, "invariant"); |
|
1367 return new ClassFileStream(instrumented_data, size_instrumented_data, NULL, ClassFileStream::verify); |
|
1368 } |
|
1369 return new ClassFileStream(new_bytes, size_of_new_bytes, NULL, ClassFileStream::verify); |
|
1370 } |
|
1371 |
|
1372 static bool cache_bytes(InstanceKlass* ik, ClassFileStream* new_stream, InstanceKlass* new_ik, TRAPS) { |
|
1373 assert(ik != NULL, "invariant"); |
|
1374 assert(new_ik != NULL, "invariant"); |
|
1375 assert(new_ik->name() != NULL, "invariant"); |
|
1376 assert(new_stream != NULL, "invariant"); |
|
1377 assert(!HAS_PENDING_EXCEPTION, "invariant"); |
|
1378 static const bool can_retransform = JfrOptionSet::allow_retransforms(); |
|
1379 if (!can_retransform) { |
|
1380 return true; |
|
1381 } |
|
1382 const jint stream_len = new_stream->length(); |
|
1383 JvmtiCachedClassFileData* p = |
|
1384 (JvmtiCachedClassFileData*)NEW_C_HEAP_ARRAY_RETURN_NULL(u1, offset_of(JvmtiCachedClassFileData, data) + stream_len, mtInternal); |
|
1385 if (p == NULL) { |
|
1386 log_error(jfr, system)("Allocation using C_HEAP_ARRAY for " SIZE_FORMAT |
|
1387 " bytes failed in JfrClassAdapter::on_klass_creation", (size_t)offset_of(JvmtiCachedClassFileData, data) + stream_len); |
|
1388 return false; |
|
1389 } |
|
1390 p->length = stream_len; |
|
1391 memcpy(p->data, new_stream->buffer(), stream_len); |
|
1392 new_ik->set_cached_class_file(p); |
|
1393 JvmtiCachedClassFileData* const cached_class_data = ik->get_cached_class_file(); |
|
1394 if (cached_class_data != NULL) { |
|
1395 os::free(cached_class_data); |
|
1396 ik->set_cached_class_file(NULL); |
|
1397 } |
|
1398 return true; |
|
1399 } |
|
1400 |
|
1401 static InstanceKlass* create_new_instance_klass(InstanceKlass* ik, ClassFileStream* stream, TRAPS) { |
|
1402 assert(stream != NULL, "invariant"); |
|
1403 ResourceMark rm(THREAD); |
|
1404 ClassLoaderData* const cld = ik->class_loader_data(); |
|
1405 Handle pd(THREAD, ik->protection_domain()); |
|
1406 Symbol* const class_name = ik->name(); |
|
1407 const char* const klass_name = class_name != NULL ? class_name->as_C_string() : ""; |
|
1408 ClassFileParser new_parser(stream, |
|
1409 class_name, |
|
1410 cld, |
|
1411 pd, |
|
1412 NULL, // host klass |
|
1413 NULL, // cp_patches |
|
1414 ClassFileParser::INTERNAL, // internal visibility |
|
1415 THREAD); |
|
1416 if (HAS_PENDING_EXCEPTION) { |
|
1417 log_pending_exception(PENDING_EXCEPTION); |
|
1418 CLEAR_PENDING_EXCEPTION; |
|
1419 return NULL; |
|
1420 } |
|
1421 InstanceKlass* const new_ik = new_parser.create_instance_klass(false, THREAD); |
|
1422 if (HAS_PENDING_EXCEPTION) { |
|
1423 log_pending_exception(PENDING_EXCEPTION); |
|
1424 CLEAR_PENDING_EXCEPTION; |
|
1425 return NULL; |
|
1426 } |
|
1427 assert(new_ik != NULL, "invariant"); |
|
1428 assert(new_ik->name() != NULL, "invariant"); |
|
1429 assert(strncmp(ik->name()->as_C_string(), new_ik->name()->as_C_string(), strlen(ik->name()->as_C_string())) == 0, "invariant"); |
|
1430 return cache_bytes(ik, stream, new_ik, THREAD) ? new_ik : NULL; |
|
1431 } |
|
1432 |
|
1433 static void rewrite_klass_pointer(InstanceKlass*& ik, InstanceKlass* new_ik, ClassFileParser& parser, TRAPS) { |
|
1434 assert(ik != NULL, "invariant"); |
|
1435 assert(new_ik != NULL, "invariant"); |
|
1436 assert(new_ik->name() != NULL, "invariant"); |
|
1437 assert(JdkJfrEvent::is(new_ik) || JdkJfrEvent::is_subklass(new_ik), "invariant"); |
|
1438 assert(!HAS_PENDING_EXCEPTION, "invariant"); |
|
1439 // assign original InstanceKlass* back onto "its" parser object for proper destruction |
|
1440 parser.set_klass_to_deallocate(ik); |
|
1441 // now rewrite original pointer to newly created InstanceKlass |
|
1442 ik = new_ik; |
|
1443 } |
|
1444 |
|
1445 // During retransform/redefine, copy the Method specific trace flags |
|
1446 // from the previous ik ("the original klass") to the new ik ("the scratch_klass"). |
|
1447 // The open code for retransform/redefine does not know about these. |
|
1448 // In doing this migration here, we ensure the new Methods (defined in scratch klass) |
|
1449 // will carry over trace tags from the old Methods being replaced, |
|
1450 // ensuring flag/tag continuity while being transparent to open code. |
|
1451 static void copy_method_trace_flags(const InstanceKlass* the_original_klass, const InstanceKlass* the_scratch_klass) { |
|
1452 assert(the_original_klass != NULL, "invariant"); |
|
1453 assert(the_scratch_klass != NULL, "invariant"); |
|
1454 assert(the_original_klass->name() == the_scratch_klass->name(), "invariant"); |
|
1455 const Array<Method*>* old_methods = the_original_klass->methods(); |
|
1456 const Array<Method*>* new_methods = the_scratch_klass->methods(); |
|
1457 const bool equal_array_length = old_methods->length() == new_methods->length(); |
|
1458 // The Method array has the property of being sorted. |
|
1459 // If they are the same length, there is a one-to-one mapping. |
|
1460 // If they are unequal, there was a method added (currently only |
|
1461 // private static methods allowed to be added), use lookup. |
|
1462 for (int i = 0; i < old_methods->length(); ++i) { |
|
1463 const Method* const old_method = old_methods->at(i); |
|
1464 Method* const new_method = equal_array_length ? new_methods->at(i) : |
|
1465 the_scratch_klass->find_method(old_method->name(), old_method->signature()); |
|
1466 assert(new_method != NULL, "invariant"); |
|
1467 assert(new_method->name() == old_method->name(), "invariant"); |
|
1468 assert(new_method->signature() == old_method->signature(), "invariant"); |
|
1469 *new_method->trace_flags_addr() = old_method->trace_flags(); |
|
1470 assert(new_method->trace_flags() == old_method->trace_flags(), "invariant"); |
|
1471 } |
|
1472 } |
|
1473 |
|
1474 static bool is_retransforming(const InstanceKlass* ik, TRAPS) { |
|
1475 assert(ik != NULL, "invariant"); |
|
1476 assert(JdkJfrEvent::is_a(ik), "invariant"); |
|
1477 Symbol* const name = ik->name(); |
|
1478 assert(name != NULL, "invariant"); |
|
1479 Handle class_loader(THREAD, ik->class_loader()); |
|
1480 Handle protection_domain(THREAD, ik->protection_domain()); |
|
1481 // nota bene: use lock-free dictionary lookup |
|
1482 const InstanceKlass* prev_ik = (const InstanceKlass*)SystemDictionary::find(name, class_loader, protection_domain, THREAD); |
|
1483 if (prev_ik == NULL) { |
|
1484 return false; |
|
1485 } |
|
1486 // an existing ik implies a retransform/redefine |
|
1487 assert(prev_ik != NULL, "invariant"); |
|
1488 assert(JdkJfrEvent::is_a(prev_ik), "invariant"); |
|
1489 copy_method_trace_flags(prev_ik, ik); |
|
1490 return true; |
|
1491 } |
|
1492 |
|
1493 // target for JFR_ON_KLASS_CREATION hook |
|
1494 void JfrEventClassTransformer::on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS) { |
|
1495 assert(ik != NULL, "invariant"); |
|
1496 if (JdkJfrEvent::is(ik)) { |
|
1497 ResourceMark rm(THREAD); |
|
1498 HandleMark hm(THREAD); |
|
1499 ClassFileStream* new_stream = create_new_bytes_for_event_klass(ik, parser, THREAD); |
|
1500 if (new_stream == NULL) { |
|
1501 log_error(jfr, system)("JfrClassAdapter: unable to create ClassFileStream"); |
|
1502 return; |
|
1503 } |
|
1504 assert(new_stream != NULL, "invariant"); |
|
1505 InstanceKlass* new_ik = create_new_instance_klass(ik, new_stream, THREAD); |
|
1506 if (new_ik == NULL) { |
|
1507 log_error(jfr, system)("JfrClassAdapter: unable to create InstanceKlass"); |
|
1508 return; |
|
1509 } |
|
1510 assert(new_ik != NULL, "invariant"); |
|
1511 // We now need to explicitly tag the replaced klass as the jdk.jfr.Event klass |
|
1512 assert(!JdkJfrEvent::is(new_ik), "invariant"); |
|
1513 JdkJfrEvent::tag_as(new_ik); |
|
1514 assert(JdkJfrEvent::is(new_ik), "invariant"); |
|
1515 rewrite_klass_pointer(ik, new_ik, parser, THREAD); |
|
1516 return; |
|
1517 } |
|
1518 assert(JdkJfrEvent::is_subklass(ik), "invariant"); |
|
1519 if (is_retransforming(ik, THREAD)) { |
|
1520 // not the initial klass load |
|
1521 return; |
|
1522 } |
|
1523 if (ik->is_abstract()) { |
|
1524 // abstract classes are not instrumented |
|
1525 return; |
|
1526 } |
|
1527 ResourceMark rm(THREAD); |
|
1528 HandleMark hm(THREAD); |
|
1529 ClassFileStream* const new_stream = create_new_bytes_for_subklass(ik, parser, THREAD); |
|
1530 if (NULL == new_stream) { |
|
1531 log_error(jfr, system)("JfrClassAdapter: unable to create ClassFileStream"); |
|
1532 return; |
|
1533 } |
|
1534 assert(new_stream != NULL, "invariant"); |
|
1535 InstanceKlass* new_ik = create_new_instance_klass(ik, new_stream, THREAD); |
|
1536 if (new_ik == NULL) { |
|
1537 log_error(jfr, system)("JfrClassAdapter: unable to create InstanceKlass"); |
|
1538 return; |
|
1539 } |
|
1540 assert(new_ik != NULL, "invariant"); |
|
1541 // would have been tagged already as a subklass during the normal process of traceid assignment |
|
1542 assert(JdkJfrEvent::is_subklass(new_ik), "invariant"); |
|
1543 traceid id = ik->trace_id(); |
|
1544 ik->set_trace_id(0); |
|
1545 new_ik->set_trace_id(id); |
|
1546 rewrite_klass_pointer(ik, new_ik, parser, THREAD); |
|
1547 } |
|
1548 |
|
1549 static bool _force_instrumentation = false; |
|
1550 void JfrEventClassTransformer::set_force_instrumentation(bool force_instrumentation) { |
|
1551 _force_instrumentation = force_instrumentation; |
|
1552 } |
|
1553 |
|
1554 bool JfrEventClassTransformer::is_force_instrumentation() { |
|
1555 return _force_instrumentation; |
|
1556 } |