Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/jfr/instrumentation/jfrEventClassTransformer.cpp
38920 views
/*1* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "jvm.h"26#include "classfile/classFileParser.hpp"27#include "classfile/classFileStream.hpp"28#include "classfile/javaClasses.hpp"29#include "classfile/stackMapTable.hpp"30#include "classfile/verificationType.hpp"31#include "interpreter/bytecodes.hpp"32#include "jfr/instrumentation/jfrEventClassTransformer.hpp"33#include "jfr/jfr.hpp"34#include "jfr/jni/jfrJavaSupport.hpp"35#include "jfr/jni/jfrUpcalls.hpp"36#include "jfr/support/jfrEventClass.hpp"37#include "jfr/utilities/jfrBigEndian.hpp"38#include "jfr/writers/jfrBigEndianWriter.hpp"39#include "memory/allocation.inline.hpp"40#include "memory/resourceArea.hpp"41//#include "oops/array.hpp"42#include "oops/instanceKlass.hpp"43#include "oops/method.hpp"44#include "prims/jvmtiRedefineClasses.hpp"45#include "runtime/handles.inline.hpp"46#include "runtime/os.hpp"47#include "runtime/thread.inline.hpp"48#include "utilities/exceptions.hpp"49#include "utilities/globalDefinitions.hpp"50#include "utilities/macros.hpp"5152static const u2 number_of_new_methods = 5;53static const u2 number_of_new_fields = 3;54static const int extra_stream_bytes = 0x280;55static const u2 invalid_cp_index = 0;5657static const char* utf8_constants[] = {58"Code", // 059"J", // 160"commit", // 261"eventHandler", // 362"Ljdk/jfr/proxy/internal/EventHandlerProxy;", // 463"duration", // 564"begin", // 665"()V", // 766"isEnabled", // 867"()Z", // 968"end", // 1069"shouldCommit", // 1170"startTime", // 1271"<clinit>", // 1372"jdk/jfr/FlightRecorder", // 1473"register", // 1574"(Ljava/lang/Class;)V", // 16 // LAST_REQUIRED_UTF875"StackMapTable", // 1776"Exceptions", // 1877"LineNumberTable", // 2078"LocalVariableTable", // 2179"LocalVariableTypeTable", // 2280"RuntimeVisibleAnnotation" // 2381};8283enum utf8_req_symbols {84UTF8_REQ_Code,85UTF8_REQ_J_FIELD_DESC,86UTF8_REQ_commit,87UTF8_REQ_eventHandler,88UTF8_REQ_eventHandler_FIELD_DESC,89UTF8_REQ_duration,90UTF8_REQ_begin,91UTF8_REQ_EMPTY_VOID_METHOD_DESC,92UTF8_REQ_isEnabled,93UTF8_REQ_EMPTY_BOOLEAN_METHOD_DESC,94UTF8_REQ_end,95UTF8_REQ_shouldCommit,96UTF8_REQ_startTime,97UTF8_REQ_clinit,98UTF8_REQ_FlightRecorder,99UTF8_REQ_register,100UTF8_REQ_CLASS_VOID_METHOD_DESC,101NOF_UTF8_REQ_SYMBOLS102};103104enum utf8_opt_symbols {105UTF8_OPT_StackMapTable = NOF_UTF8_REQ_SYMBOLS,106UTF8_OPT_Exceptions,107UTF8_OPT_LineNumberTable,108UTF8_OPT_LocalVariableTable,109UTF8_OPT_LocalVariableTypeTable,110UTF8_OPT_RuntimeVisibleAnnotation,111NOF_UTF8_SYMBOLS112};113114static u1 empty_void_method_code_attribute[] = {1150x0,1160x0,1170x0,1180xd, // attribute len1190x0,1200x0, // max stack1210x0,1220x1, // max locals1230x0,1240x0,1250x0,1260x1, // code length127Bytecodes::_return,1280x0,1290x0, // ex table len1300x0,1310x0 // attributes_count132};133134static u1 boolean_method_code_attribute[] = {1350x0,1360x0,1370x0,1380xe,1390x0,1400x1, // max stack1410x0,1420x1, // max locals1430x0,1440x0,1450x0,1460x2,147Bytecodes::_iconst_0,148Bytecodes::_ireturn,1490x0,1500x0, // ex table len1510x0,1520x0, // attributes_count153};154155// annotation processing support156157enum { // initial annotation layout158atype_off = 0, // utf8 such as 'Ljava/lang/annotation/Retention;'159count_off = 2, // u2 such as 1 (one value)160member_off = 4, // utf8 such as 'value'161tag_off = 6, // u1 such as 'c' (type) or 'e' (enum)162e_tag_val = 'e',163e_type_off = 7, // utf8 such as 'Ljava/lang/annotation/RetentionPolicy;'164e_con_off = 9, // utf8 payload, such as 'SOURCE', 'CLASS', 'RUNTIME'165e_size = 11, // end of 'e' annotation166c_tag_val = 'c', // payload is type167c_con_off = 7, // utf8 payload, such as 'I'168c_size = 9, // end of 'c' annotation169s_tag_val = 's', // payload is String170s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;'171s_size = 9,172min_size = 6 // smallest possible size (zero members)173};174175static int skip_annotation_value(const address, int, int); // fwd decl176177// Skip an annotation. Return >=limit if there is any problem.178static int next_annotation_index(const address buffer, int limit, int index) {179assert(buffer != NULL, "invariant");180index += 2; // skip atype181if ((index += 2) >= limit) {182return limit;183}184int nof_members = JfrBigEndian::read<u2>(buffer + index - 2);185while (--nof_members >= 0 && index < limit) {186index += 2; // skip member187index = skip_annotation_value(buffer, limit, index);188}189return index;190}191192// Skip an annotation value. Return >=limit if there is any problem.193static int skip_annotation_value(const address buffer, int limit, int index) {194assert(buffer != NULL, "invariant");195// value := switch (tag:u1) {196// case B, C, I, S, Z, D, F, J, c: con:u2;197// case e: e_class:u2 e_name:u2;198// case s: s_con:u2;199// case [: do(nval:u2) {value};200// case @: annotation;201// case s: s_con:u2;202// }203if ((index += 1) >= limit) {204return limit;205}206const u1 tag = buffer[index - 1];207switch (tag) {208case 'B':209case 'C':210case 'I':211case 'S':212case 'Z':213case 'D':214case 'F':215case 'J':216case 'c':217case 's':218index += 2; // skip con or s_con219break;220case 'e':221index += 4; // skip e_class, e_name222break;223case '[':224{225if ((index += 2) >= limit) {226return limit;227}228int nof_values = JfrBigEndian::read<u2>(buffer + index - 2);229while (--nof_values >= 0 && index < limit) {230index = skip_annotation_value(buffer, limit, index);231}232}233break;234case '@':235index = next_annotation_index(buffer, limit, index);236break;237default:238return limit; // bad tag byte239}240return index;241}242243static const u2 number_of_elements_offset = (u2)2;244static const u2 element_name_offset = (u2)(number_of_elements_offset + 2);245static const u2 element_name_size = (u2)2;246static const u2 value_type_relative_offset = (u2)2;247static const u2 value_relative_offset = (u2)(value_type_relative_offset + 1);248249// see JVMS - 4.7.16. The RuntimeVisibleAnnotations Attribute250251class AnnotationElementIterator : public StackObj {252private:253const InstanceKlass* _ik;254const address _buffer;255const u2 _limit; // length of annotation256mutable u2 _current; // element257mutable u2 _next; // element258u2 value_index() const {259return JfrBigEndian::read<u2>(_buffer + _current + value_relative_offset);260}261262public:263AnnotationElementIterator(const InstanceKlass* ik, address buffer, u2 limit) : _ik(ik),264_buffer(buffer),265_limit(limit),266_next(element_name_offset),267_current(element_name_offset) {268assert(_buffer != NULL, "invariant");269assert(_next == element_name_offset, "invariant");270assert(_current == element_name_offset, "invariant");271}272273bool has_next() const {274return _next < _limit;275}276277void move_to_next() const {278assert(has_next(), "invariant");279_current = _next;280if (_next < _limit) {281_next = skip_annotation_value(_buffer, _limit, _next + element_name_size);282}283assert(_next <= _limit, "invariant");284assert(_current <= _limit, "invariant");285}286287u2 number_of_elements() const {288return JfrBigEndian::read<u2>(_buffer + number_of_elements_offset);289}290291const Symbol* name() const {292assert(_current < _next, "invariant");293return _ik->constants()->symbol_at(JfrBigEndian::read<u2>(_buffer + _current));294}295296char value_type() const {297return JfrBigEndian::read<u1>(_buffer + _current + value_type_relative_offset);298}299300jint read_int() const {301return _ik->constants()->int_at(value_index());302}303304bool read_bool() const {305return read_int() != 0;306}307};308309class AnnotationIterator : public StackObj {310private:311const InstanceKlass* _ik;312// ensure _limit field is declared before _buffer313u2 _limit; // length of annotations array314const address _buffer;315mutable u2 _current; // annotation316mutable u2 _next; // annotation317318public:319AnnotationIterator(const InstanceKlass* ik, AnnotationArray* ar) : _ik(ik),320_current(0),321_next(0),322_limit(ar != NULL ? ar->length() : 0),323_buffer(_limit > 2 ? ar->adr_at(2) : NULL) {324if (_buffer != NULL) {325_limit -= 2; // subtract sizeof(u2) number of annotations field326}327}328bool has_next() const {329return _next < _limit;330}331332void move_to_next() const {333assert(has_next(), "invariant");334_current = _next;335if (_next < _limit) {336_next = next_annotation_index(_buffer, _limit, _next);337}338assert(_next <= _limit, "invariant");339assert(_current <= _limit, "invariant");340}341const AnnotationElementIterator elements() const {342assert(_current < _next, "invariant");343return AnnotationElementIterator(_ik, _buffer + _current, _next - _current);344}345const Symbol* type() const {346assert(_buffer != NULL, "invariant");347assert(_current < _limit, "invariant");348return _ik->constants()->symbol_at(JfrBigEndian::read<u2>(_buffer + _current));349}350};351352static unsigned int unused_hash = 0;353static const char value_name[] = "value";354static bool has_registered_annotation(const InstanceKlass* ik, const Symbol* annotation_type, bool& value) {355assert(annotation_type != NULL, "invariant");356AnnotationArray* class_annotations = ik->class_annotations();357if (class_annotations == NULL) {358return false;359}360361const AnnotationIterator annotation_iterator(ik, class_annotations);362while (annotation_iterator.has_next()) {363annotation_iterator.move_to_next();364if (annotation_iterator.type() == annotation_type) {365// target annotation found366static const Symbol* value_symbol =367SymbolTable::lookup_only(value_name, sizeof value_name - 1, unused_hash);368assert(value_symbol != NULL, "invariant");369const AnnotationElementIterator element_iterator = annotation_iterator.elements();370while (element_iterator.has_next()) {371element_iterator.move_to_next();372if (value_symbol == element_iterator.name()) {373// "value" element374assert('Z' == element_iterator.value_type(), "invariant");375value = element_iterator.read_bool();376return true;377}378}379}380}381return false;382}383384static bool registered_annotation_value(const InstanceKlass* ik, const Symbol* const registered_symbol) {385assert(registered_symbol != NULL, "invariant");386assert(ik != NULL, "invariant");387assert(JdkJfrEvent::is_a(ik), "invariant");388bool registered_value = false;389if (has_registered_annotation(ik, registered_symbol, registered_value)) {390return registered_value;391}392InstanceKlass* super = InstanceKlass::cast(ik->super());393return registered_annotation_value(super, registered_symbol);394}395396static const char registered_constant[] = "Ljdk/jfr/Registered;";397398// Evaluate to the value of the first found "Ljdk/jfr/Registered;" annotation.399// Searching moves upwards in the klass hierarchy in order to support400// inherited annotations in addition to the ability to override.401static bool should_register_klass(const InstanceKlass* ik) {402static const Symbol* const registered_symbol = SymbolTable::lookup_only(registered_constant,403sizeof registered_constant - 1,404unused_hash);405assert(registered_symbol != NULL, "invariant");406return registered_annotation_value(ik, registered_symbol);407}408/*409* Map an utf8 constant back to its CONSTANT_UTF8_INFO410*/411static u2 utf8_info_index(const InstanceKlass* ik, const Symbol* const target, TRAPS) {412assert(target != NULL, "invariant");413ConstantPool* cp = ik->constants();414const int cp_len = cp->length();415for (u2 index = 1; index < cp_len; ++index) {416const constantTag tag = cp->tag_at(index);417if (tag.is_utf8()) {418const Symbol* const utf8_sym = cp->symbol_at(index);419assert(utf8_sym != NULL, "invariant");420if (utf8_sym == target) {421return index;422}423}424}425// not in constant pool426return invalid_cp_index;427}428429#ifdef ASSERT430static bool is_index_within_range(u2 index, u2 orig_cp_len, u2 new_cp_entries_len) {431return index > 0 && index < orig_cp_len + new_cp_entries_len;432}433#endif434435static u2 add_utf8_info(JfrBigEndianWriter& writer, const char* utf8_constant, u2 orig_cp_len, u2& new_cp_entries_len) {436assert(utf8_constant != NULL, "invariant");437writer.write<u1>(JVM_CONSTANT_Utf8);438writer.write_utf8_u2_len(utf8_constant);439assert(writer.is_valid(), "invariant");440// return index for the added utf8 info441return orig_cp_len + new_cp_entries_len++;442}443444static u2 add_method_ref_info(JfrBigEndianWriter& writer,445u2 cls_name_index,446u2 method_index,447u2 desc_index,448u2 orig_cp_len,449u2& number_of_new_constants,450TRAPS) {451assert(is_index_within_range(cls_name_index, orig_cp_len, number_of_new_constants), "invariant");452assert(is_index_within_range(method_index, orig_cp_len, number_of_new_constants), "invariant");453assert(is_index_within_range(desc_index, orig_cp_len, number_of_new_constants), "invariant");454writer.write<u1>(JVM_CONSTANT_Class);455writer.write<u2>(cls_name_index);456const u2 cls_entry_index = orig_cp_len + number_of_new_constants;457++number_of_new_constants;458writer.write<u1>(JVM_CONSTANT_NameAndType);459writer.write<u2>(method_index);460writer.write<u2>(desc_index);461const u2 nat_entry_index = orig_cp_len + number_of_new_constants;462++number_of_new_constants;463writer.write<u1>(JVM_CONSTANT_Methodref);464writer.write<u2>(cls_entry_index);465writer.write<u2>(nat_entry_index);466// post-increment number_of_new_constants467// value returned is the index to the added method_ref468return orig_cp_len + number_of_new_constants++;469}470471static u2 add_flr_register_method_constants(JfrBigEndianWriter& writer,472const u2* utf8_indexes,473u2 orig_cp_len,474u2& number_of_new_constants,475TRAPS) {476assert(utf8_indexes != NULL, "invariant");477return add_method_ref_info(writer,478utf8_indexes[UTF8_REQ_FlightRecorder],479utf8_indexes[UTF8_REQ_register],480utf8_indexes[UTF8_REQ_CLASS_VOID_METHOD_DESC],481orig_cp_len,482number_of_new_constants,483THREAD);484}485486/*487* field_info {488* u2 access_flags;489* u2 name_index;490* u2 descriptor_index;491* u2 attributes_count;492* attribute_info attributes[attributes_count];493* }494*/495static jlong add_field_info(JfrBigEndianWriter& writer, u2 name_index, u2 desc_index, bool is_static = false) {496assert(name_index > 0, "invariant");497assert(desc_index > 0, "invariant");498DEBUG_ONLY(const jlong start_offset = writer.current_offset();)499writer.write<u2>(JVM_ACC_SYNTHETIC | JVM_ACC_PRIVATE | (is_static ? JVM_ACC_STATIC : JVM_ACC_TRANSIENT)); // flags500writer.write(name_index);501writer.write(desc_index);502writer.write((u2)0x0); // attributes_count503assert(writer.is_valid(), "invariant");504DEBUG_ONLY(assert(start_offset + 8 == writer.current_offset(), "invariant");)505return writer.current_offset();506}507508static u2 add_field_infos(JfrBigEndianWriter& writer, const u2* utf8_indexes) {509assert(utf8_indexes != NULL, "invariant");510add_field_info(writer,511utf8_indexes[UTF8_REQ_eventHandler],512utf8_indexes[UTF8_REQ_eventHandler_FIELD_DESC],513true); // static514515add_field_info(writer,516utf8_indexes[UTF8_REQ_startTime],517utf8_indexes[UTF8_REQ_J_FIELD_DESC]);518519add_field_info(writer,520utf8_indexes[UTF8_REQ_duration],521utf8_indexes[UTF8_REQ_J_FIELD_DESC]);522523return number_of_new_fields;524}525526/*527* method_info {528* u2 access_flags;529* u2 name_index;530* u2 descriptor_index;531* u2 attributes_count;532* attribute_info attributes[attributes_count];533* }534*535* Code_attribute {536* u2 attribute_name_index;537* u4 attribute_length;538* u2 max_stack;539* u2 max_locals;540* u4 code_length;541* u1 code[code_length];542* u2 exception_table_length;543* { u2 start_pc;544* u2 end_pc;545* u2 handler_pc;546* u2 catch_type;547* } exception_table[exception_table_length];548* u2 attributes_count;549* attribute_info attributes[attributes_count];550* }551*/552553static jlong add_method_info(JfrBigEndianWriter& writer,554u2 name_index,555u2 desc_index,556u2 code_index,557const u1* const code,558const size_t code_len) {559assert(name_index > 0, "invariant");560assert(desc_index > 0, "invariant");561assert(code_index > 0, "invariant");562DEBUG_ONLY(const jlong start_offset = writer.current_offset();)563writer.write<u2>(JVM_ACC_SYNTHETIC | JVM_ACC_PUBLIC); // flags564writer.write(name_index);565writer.write(desc_index);566writer.write<u2>(0x1); // attributes_count ; 1 for "Code" attribute567assert(writer.is_valid(), "invariant");568DEBUG_ONLY(assert(start_offset + 8 == writer.current_offset(), "invariant");)569// Code attribute570writer.write(code_index); // "Code"571writer.bytes(code, code_len);572DEBUG_ONLY(assert((start_offset + 8 + 2 + (jlong)code_len) == writer.current_offset(), "invariant");)573return writer.current_offset();574}575576/*577* On return, the passed stream will be positioned578* just after the constant pool section in the classfile579* and the cp length is returned.580*581* Stream should come in at the start position.582*/583static u2 position_stream_after_cp(ClassFileStream* stream) {584assert(stream != NULL, "invariant");585assert(stream->current_offset() == 0, "invariant");586stream->skip_u4_fast(2); // 8 bytes skipped587const u2 cp_len = stream->get_u2_fast();588assert(cp_len > 0, "invariant");589// now spin the stream position to just after the constant pool590for (u2 index = 1; index < cp_len; ++index) {591const u1 tag = stream->get_u1_fast(); // cp tag592switch (tag) {593case JVM_CONSTANT_Class:594case JVM_CONSTANT_String: {595stream->skip_u2_fast(1); // skip 2 bytes596continue;597}598case JVM_CONSTANT_Fieldref:599case JVM_CONSTANT_Methodref:600case JVM_CONSTANT_InterfaceMethodref:601case JVM_CONSTANT_Integer:602case JVM_CONSTANT_Float:603case JVM_CONSTANT_NameAndType:604case JVM_CONSTANT_InvokeDynamic: {605stream->skip_u4_fast(1); // skip 4 bytes606continue;607}608case JVM_CONSTANT_Long:609case JVM_CONSTANT_Double: {610stream->skip_u4_fast(2); // skip 8 bytes611// Skip entry following eigth-byte constant, see JVM book p. 98612++index;613continue;614}615case JVM_CONSTANT_Utf8: {616u2 utf8_length = stream->get_u2_fast();617stream->skip_u1_fast(utf8_length); // skip 2 + len bytes618continue;619}620case JVM_CONSTANT_MethodHandle:621case JVM_CONSTANT_MethodType: {622if (tag == JVM_CONSTANT_MethodHandle) {623stream->skip_u1_fast(1);624stream->skip_u2_fast(1); // skip 3 bytes625}626else if (tag == JVM_CONSTANT_MethodType) {627stream->skip_u2_fast(1); // skip 3 bytes628}629}630continue;631default:632assert(false, "error in skip logic!");633break;634} // end switch(tag)635}636return cp_len;637}638639/*640* On return, the passed stream will be positioned641* just after the fields section in the classfile642* and the number of fields will be returned.643*644* Stream should come in positioned just before fields_count645*/646static u2 position_stream_after_fields(ClassFileStream* stream) {647assert(stream != NULL, "invariant");648assert(stream->current_offset() > 0, "invariant");649// fields len650const u2 orig_fields_len = stream->get_u2_fast();651// fields652for (u2 i = 0; i < orig_fields_len; ++i) {653stream->skip_u2_fast(3);654const u2 attrib_info_len = stream->get_u2_fast();655for (u2 j = 0; j < attrib_info_len; ++j) {656stream->skip_u2_fast(1);657const u4 attrib_len = stream->get_u4_fast();658stream->skip_u1_fast(attrib_len);659}660}661return orig_fields_len;662}663664/*665* On return, the passed stream will be positioned666* just after the methods section in the classfile667* and the number of methods will be returned.668*669* Stream should come in positioned just before methods_count670*/671static u2 position_stream_after_methods(JfrBigEndianWriter& writer,672ClassFileStream* stream,673const u2* utf8_indexes,674bool register_klass,675const Method* clinit_method,676u4& orig_method_len_offset) {677assert(stream != NULL, "invariant");678assert(stream->current_offset() > 0, "invariant");679assert(utf8_indexes != NULL, "invariant");680// We will come back to this location when we681// know how many methods there will be.682writer.reserve(sizeof(u2));683const u2 orig_methods_len = stream->get_u2_fast();684// Move copy position past original method_count685// in order to not copy the original count686orig_method_len_offset += sizeof(u2);687for (u2 i = 0; i < orig_methods_len; ++i) {688const u4 method_offset = stream->current_offset();689stream->skip_u2_fast(1); // Access Flags690const u2 name_index = stream->get_u2_fast(); // Name index691stream->skip_u2_fast(1); // Descriptor index692const u2 attributes_count = stream->get_u2_fast();693for (u2 j = 0; j < attributes_count; ++j) {694stream->skip_u2_fast(1);695const u4 attrib_len = stream->get_u4_fast();696stream->skip_u1_fast(attrib_len);697}698if (clinit_method != NULL && name_index == clinit_method->name_index()) {699// The method just parsed is an existing <clinit> method.700// If the class has the @Registered(false) annotation, i.e. marking a class701// for opting out from automatic registration, then we do not need to do anything.702if (!register_klass) {703continue;704}705// Automatic registration with the jfr system is acccomplished706// by pre-pending code to the <clinit> method of the class.707// We will need to re-create a new <clinit> in a later step.708// For now, ensure that this method is excluded from the methods709// being copied.710writer.bytes(stream->buffer() + orig_method_len_offset,711method_offset - orig_method_len_offset);712assert(writer.is_valid(), "invariant");713714// Update copy position to skip copy of <clinit> method715orig_method_len_offset = stream->current_offset();716}717}718return orig_methods_len;719}720721static u2 add_method_infos(JfrBigEndianWriter& writer, const u2* utf8_indexes) {722assert(utf8_indexes != NULL, "invariant");723add_method_info(writer,724utf8_indexes[UTF8_REQ_begin],725utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC],726utf8_indexes[UTF8_REQ_Code],727empty_void_method_code_attribute,728sizeof(empty_void_method_code_attribute));729730assert(writer.is_valid(), "invariant");731732add_method_info(writer,733utf8_indexes[UTF8_REQ_end],734utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC],735utf8_indexes[UTF8_REQ_Code],736empty_void_method_code_attribute,737sizeof(empty_void_method_code_attribute));738739assert(writer.is_valid(), "invariant");740741add_method_info(writer,742utf8_indexes[UTF8_REQ_commit],743utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC],744utf8_indexes[UTF8_REQ_Code],745empty_void_method_code_attribute,746sizeof(empty_void_method_code_attribute));747748assert(writer.is_valid(), "invariant");749750add_method_info(writer,751utf8_indexes[UTF8_REQ_isEnabled],752utf8_indexes[UTF8_REQ_EMPTY_BOOLEAN_METHOD_DESC],753utf8_indexes[UTF8_REQ_Code],754boolean_method_code_attribute,755sizeof(boolean_method_code_attribute));756757assert(writer.is_valid(), "invariant");758759add_method_info(writer,760utf8_indexes[UTF8_REQ_shouldCommit],761utf8_indexes[UTF8_REQ_EMPTY_BOOLEAN_METHOD_DESC],762utf8_indexes[UTF8_REQ_Code],763boolean_method_code_attribute,764sizeof(boolean_method_code_attribute));765assert(writer.is_valid(), "invariant");766return number_of_new_methods;767}768769static void adjust_exception_table(JfrBigEndianWriter& writer, u2 bci_adjustment_offset, const Method* method, TRAPS) {770const u2 ex_table_length = method != NULL ? (u2)method->exception_table_length() : 0;771writer.write<u2>(ex_table_length); // Exception table length772if (ex_table_length > 0) {773assert(method != NULL, "invariant");774const ExceptionTableElement* const ex_elements = method->exception_table_start();775for (int i = 0; i < ex_table_length; ++i) {776assert(ex_elements != NULL, "invariant");777writer.write<u2>(ex_elements[i].start_pc + bci_adjustment_offset);778writer.write<u2>(ex_elements[i].end_pc + bci_adjustment_offset);779writer.write<u2>(ex_elements[i].handler_pc + bci_adjustment_offset);780writer.write<u2>(ex_elements[i].catch_type_index); // no adjustment781}782}783}784785enum StackMapFrameTypes {786SAME_FRAME_BEGIN = 0,787SAME_FRAME_END = 63,788SAME_LOCALS_1_STACK_ITEM_FRAME_BEGIN = 64,789SAME_LOCALS_1_STACK_ITEM_FRAME_END = 127,790SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247,791CHOP_FRAME_BEGIN = 248,792CHOP_FRAME_END = 250,793SAME_FRAME_EXTENDED = 251,794APPEND_FRAME_BEGIN = 252,795APPEND_FRAME_END = 254,796FULL_FRAME = 255797};798799static void adjust_stack_map(JfrBigEndianWriter& writer,800Array<u1>* stack_map,801const u2* utf8_indexes,802u2 bci_adjustment_offset,803TRAPS) {804assert(stack_map != NULL, "invariant");805assert(utf8_indexes != NULL, "invariant");806writer.write<u2>(utf8_indexes[UTF8_OPT_StackMapTable]);807const jlong stack_map_attrib_len_offset = writer.current_offset();808writer.reserve(sizeof(u4));809StackMapStream stream(stack_map);810const u2 stack_map_entries = stream.get_u2(THREAD);811// number of entries812writer.write<u2>(stack_map_entries); // new stack map entry added813const u1 frame_type = stream.get_u1(THREAD);814// SAME_FRAME and SAME_LOCALS_1_STACK_ITEM_FRAME encode815// their offset_delta into the actual frame type itself.816// If such a frame type is the first frame, then we transform817// it to a SAME_FRAME_EXTENDED or a SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED frame.818// This is done in order to not overflow frame types accidentally819// when adjusting the offset_delta. In changing the frame types,820// we can work with an explicit u2 offset_delta field (like the other frame types)821if (frame_type <= SAME_FRAME_END) {822writer.write<u1>(SAME_FRAME_EXTENDED);823writer.write<u2>(frame_type + bci_adjustment_offset);824} else if (frame_type >= SAME_LOCALS_1_STACK_ITEM_FRAME_BEGIN &&825frame_type <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) {826writer.write<u1>(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED);827writer.write<u2>((frame_type - SAME_LOCALS_1_STACK_ITEM_FRAME_BEGIN) + bci_adjustment_offset);828} else if (frame_type >= SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {829// SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED to FULL_FRAME830// has a u2 offset_delta field831writer.write<u1>(frame_type);832writer.write<u2>(stream.get_u2(THREAD) + bci_adjustment_offset);833} else {834assert(false, "stackMapFrame type is invalid");835}836837while (!stream.at_end()) {838writer.write<u1>(stream.get_u1(THREAD));839}840841u4 stack_map_attrib_len = writer.current_offset() - stack_map_attrib_len_offset;842// the stack_map_table_attributes_length value is exclusive843stack_map_attrib_len -= sizeof(u4);844writer.write_at_offset(stack_map_attrib_len, stack_map_attrib_len_offset);845}846847static void adjust_line_number_table(JfrBigEndianWriter& writer,848const u2* utf8_indexes,849u4 bci_adjustement_offset,850const Method* method,851TRAPS) {852assert(utf8_indexes != NULL, "invariant");853assert(method != NULL, "invariant");854assert(method->has_linenumber_table(), "invariant");855writer.write(utf8_indexes[UTF8_OPT_LineNumberTable]);856const jlong lnt_attributes_length_offset = writer.current_offset();857writer.reserve(sizeof(u4));858const jlong lnt_attributes_entries_offset = writer.current_offset();859writer.reserve(sizeof(u2));860u1* lnt = method->compressed_linenumber_table();861CompressedLineNumberReadStream lnt_stream(lnt);862u2 line_number_table_entries = 0;863while (lnt_stream.read_pair()) {864++line_number_table_entries;865const u2 bci = (u2)lnt_stream.bci();866writer.write<u2>(bci + (u2)bci_adjustement_offset);867writer.write<u2>((u2)lnt_stream.line());868}869writer.write_at_offset(line_number_table_entries, lnt_attributes_entries_offset);870u4 lnt_table_attributes_len = writer.current_offset() - lnt_attributes_length_offset;871// the line_number_table_attributes_length value is exclusive872lnt_table_attributes_len -= sizeof(u4);873writer.write_at_offset(lnt_table_attributes_len, lnt_attributes_length_offset);874}875876// returns the number of lvtt entries877static u2 adjust_local_variable_table(JfrBigEndianWriter& writer,878const u2* utf8_indexes,879u2 bci_adjustment_offset,880const Method* method,881TRAPS) {882assert(utf8_indexes != NULL, "invariant");883assert(method != NULL, "invariant");884assert(method->has_localvariable_table(), "invariant");885writer.write<u2>(utf8_indexes[UTF8_OPT_LocalVariableTable]);886const jlong lvt_attributes_length_offset = writer.current_offset();887writer.reserve(sizeof(u4));888const int lvt_len = method->localvariable_table_length();889writer.write<u2>((u2)lvt_len);890const LocalVariableTableElement* table = method->localvariable_table_start();891assert(table != NULL, "invariant");892u2 num_lvtt_entries = 0;893for (int i = 0; i < lvt_len; ++i) {894writer.write<u2>(table[i].start_bci + bci_adjustment_offset);895writer.write<u2>(table[i].length);896writer.write<u2>(table[i].name_cp_index);897writer.write<u2>(table[i].descriptor_cp_index);898writer.write<u2>(table[i].slot);899if (table[i].signature_cp_index > 0) {900++num_lvtt_entries;901}902}903u4 lvt_table_attributes_len = writer.current_offset() - lvt_attributes_length_offset;904// the lvt_table_attributes_length value is exclusive905lvt_table_attributes_len -= sizeof(u4);906writer.write_at_offset(lvt_table_attributes_len, lvt_attributes_length_offset);907return num_lvtt_entries;908}909910static void adjust_local_variable_type_table(JfrBigEndianWriter& writer,911const u2* utf8_indexes,912u2 bci_adjustment_offset,913u2 num_lvtt_entries,914const Method* method,915TRAPS) {916assert(num_lvtt_entries > 0, "invariant");917writer.write<u2>(utf8_indexes[UTF8_OPT_LocalVariableTypeTable]);918const jlong lvtt_attributes_length_offset = writer.current_offset();919writer.reserve(sizeof(u4));920writer.write<u2>(num_lvtt_entries);921const LocalVariableTableElement* table = method->localvariable_table_start();922assert(table != NULL, "invariant");923const int lvt_len = method->localvariable_table_length();924for (int i = 0; i < lvt_len; ++i) {925if (table[i].signature_cp_index > 0) {926writer.write<u2>(table[i].start_bci + bci_adjustment_offset);927writer.write<u2>(table[i].length);928writer.write<u2>(table[i].name_cp_index);929writer.write<u2>(table[i].signature_cp_index);930writer.write<u2>(table[i].slot);931}932}933u4 lvtt_table_attributes_len = writer.current_offset() - lvtt_attributes_length_offset;934// the lvtt_table_attributes_length value is exclusive935lvtt_table_attributes_len -= sizeof(u4);936writer.write_at_offset(lvtt_table_attributes_len, lvtt_attributes_length_offset);937}938939static void adjust_code_attributes(JfrBigEndianWriter& writer,940const u2* utf8_indexes,941u2 bci_adjustment_offset,942const Method* clinit_method,943TRAPS) {944// "Code" attributes945assert(utf8_indexes != NULL, "invariant");946const jlong code_attributes_offset = writer.current_offset();947writer.reserve(sizeof(u2));948u2 number_of_code_attributes = 0;949if (clinit_method != NULL) {950Array<u1>* stack_map = clinit_method->stackmap_data();951if (stack_map != NULL) {952++number_of_code_attributes;953adjust_stack_map(writer, stack_map, utf8_indexes, bci_adjustment_offset, THREAD);954assert(writer.is_valid(), "invariant");955}956if (clinit_method != NULL && clinit_method->has_linenumber_table()) {957++number_of_code_attributes;958adjust_line_number_table(writer, utf8_indexes, bci_adjustment_offset, clinit_method, THREAD);959assert(writer.is_valid(), "invariant");960}961if (clinit_method != NULL && clinit_method->has_localvariable_table()) {962++number_of_code_attributes;963const u2 num_of_lvtt_entries = adjust_local_variable_table(writer, utf8_indexes, bci_adjustment_offset, clinit_method, THREAD);964assert(writer.is_valid(), "invariant");965if (num_of_lvtt_entries > 0) {966++number_of_code_attributes;967adjust_local_variable_type_table(writer, utf8_indexes, bci_adjustment_offset, num_of_lvtt_entries, clinit_method, THREAD);968assert(writer.is_valid(), "invariant");969}970}971}972973// Store the number of code_attributes974writer.write_at_offset(number_of_code_attributes, code_attributes_offset);975}976977static jlong insert_clinit_method(const InstanceKlass* ik,978ClassFileParser& parser,979JfrBigEndianWriter& writer,980u2 orig_constant_pool_len,981const u2* utf8_indexes,982const u2 register_method_ref_index,983const Method* clinit_method,984TRAPS) {985assert(utf8_indexes != NULL, "invariant");986// The injected code length is always this value.987// This is to ensure that padding can be done988// where needed and to simplify size calculations.989static const u2 injected_code_length = 8;990const u2 name_index = utf8_indexes[UTF8_REQ_clinit];991const u2 desc_index = utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC];992const u2 max_stack = MAX2(clinit_method != NULL ? clinit_method->verifier_max_stack() : 1, 1);993const u2 max_locals = MAX2(clinit_method != NULL ? clinit_method->max_locals() : 0, 0);994const u2 orig_bytecodes_length = clinit_method != NULL ? (u2)clinit_method->code_size() : 0;995const address orig_bytecodes = clinit_method != NULL ? clinit_method->code_base() : NULL;996const u2 new_code_length = injected_code_length + orig_bytecodes_length;997DEBUG_ONLY(const jlong start_offset = writer.current_offset();)998writer.write<u2>(JVM_ACC_STATIC); // flags999writer.write<u2>(name_index);1000writer.write<u2>(desc_index);1001writer.write<u2>((u2)0x1); // attributes_count // "Code"1002assert(writer.is_valid(), "invariant");1003DEBUG_ONLY(assert(start_offset + 8 == writer.current_offset(), "invariant");)1004// "Code" attribute1005writer.write<u2>(utf8_indexes[UTF8_REQ_Code]); // "Code"1006const jlong code_attribute_length_offset = writer.current_offset();1007writer.reserve(sizeof(u4));1008writer.write<u2>(max_stack); // max stack1009writer.write<u2>(max_locals); // max locals1010writer.write<u4>((u4)new_code_length); // code length10111012/* BEGIN CLINIT CODE */10131014// Note the use of ldc_w here instead of ldc.1015// This is to handle all values of "this_class_index"1016writer.write<u1>((u1)Bytecodes::_ldc_w);1017writer.write<u2>((u2)parser.this_class_index()); // load constant "this class"1018writer.write<u1>((u1)Bytecodes::_invokestatic);1019// invoke "FlightRecorder.register(Ljava/lang/Class;")1020writer.write<u2>(register_method_ref_index);1021if (clinit_method == NULL) {1022writer.write<u1>((u1)Bytecodes::_nop);1023writer.write<u1>((u1)Bytecodes::_return);1024} else {1025// If we are pre-pending to original code,1026// do padding to minimize disruption to the original.1027// It might have dependencies on 4-byte boundaries1028// i.e. lookupswitch and tableswitch instructions1029writer.write<u1>((u1)Bytecodes::_nop);1030writer.write<u1>((u1)Bytecodes::_nop);1031// insert original clinit code1032writer.bytes(orig_bytecodes, orig_bytecodes_length);1033}10341035/* END CLINIT CODE */10361037assert(writer.is_valid(), "invariant");1038adjust_exception_table(writer, injected_code_length, clinit_method, THREAD);1039assert(writer.is_valid(), "invariant");1040adjust_code_attributes(writer, utf8_indexes, injected_code_length, clinit_method, THREAD);1041assert(writer.is_valid(), "invariant");1042u4 code_attribute_len = writer.current_offset() - code_attribute_length_offset;1043// the code_attribute_length value is exclusive1044code_attribute_len -= sizeof(u4);1045writer.write_at_offset(code_attribute_len, code_attribute_length_offset);1046return writer.current_offset();1047}10481049// Caller needs ResourceMark1050static ClassFileStream* create_new_bytes_for_event_klass(const InstanceKlass* ik, const ClassFileParser& parser, TRAPS) {1051DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));1052static const u2 public_final_flag_mask = JVM_ACC_PUBLIC | JVM_ACC_FINAL;1053ClassFileStream* const orig_stream = parser.clone_stream();1054const int orig_stream_length = orig_stream->length();1055// allocate an identically sized buffer1056u1* const new_buffer = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, u1, orig_stream_length);1057if (new_buffer == NULL) {1058return NULL;1059}1060assert(new_buffer != NULL, "invariant");1061// memcpy the entire [B1062memcpy(new_buffer, orig_stream->buffer(), orig_stream_length);1063const u2 orig_cp_len = position_stream_after_cp(orig_stream);1064assert(orig_cp_len > 0, "invariant");1065assert(orig_stream->current_offset() > 0, "invariant");1066orig_stream->skip_u2_fast(3); // access_flags, this_class_index, super_class_index1067const u2 iface_len = orig_stream->get_u2_fast();1068orig_stream->skip_u2_fast(iface_len);1069// fields len1070const u2 orig_fields_len = orig_stream->get_u2_fast();1071// fields1072for (u2 i = 0; i < orig_fields_len; ++i) {1073orig_stream->skip_u2_fast(3);1074const u2 attrib_info_len = orig_stream->get_u2_fast();1075for (u2 j = 0; j < attrib_info_len; ++j) {1076orig_stream->skip_u2_fast(1);1077const u4 attrib_len = orig_stream->get_u4_fast();1078orig_stream->skip_u1_fast(attrib_len);1079}1080}1081// methods1082const u2 orig_methods_len = orig_stream->get_u2_fast();1083for (u2 i = 0; i < orig_methods_len; ++i) {1084const u4 access_flag_offset = orig_stream->current_offset();1085const u2 flags = orig_stream->get_u2_fast();1086// Rewrite JVM_ACC_FINAL -> JVM_ACC_PUBLIC1087if (public_final_flag_mask == flags) {1088JfrBigEndianWriter accessflagsrewriter(new_buffer + access_flag_offset, sizeof(u2));1089accessflagsrewriter.write<u2>(JVM_ACC_PUBLIC);1090assert(accessflagsrewriter.is_valid(), "invariant");1091}1092orig_stream->skip_u2_fast(2);1093const u2 attributes_count = orig_stream->get_u2_fast();1094for (u2 j = 0; j < attributes_count; ++j) {1095orig_stream->skip_u2_fast(1);1096const u4 attrib_len = orig_stream->get_u4_fast();1097orig_stream->skip_u1_fast(attrib_len);1098}1099}1100return new ClassFileStream(new_buffer, orig_stream_length, NULL);1101}11021103// Attempt to locate an existing UTF8_INFO mapping the utf8_constant.1104// If no UTF8_INFO exists, add (append) a new one to the constant pool.1105static u2 find_or_add_utf8_info(JfrBigEndianWriter& writer,1106const InstanceKlass* ik,1107const char* const utf8_constant,1108u2 orig_cp_len,1109u2& added_cp_entries,1110TRAPS) {1111assert(utf8_constant != NULL, "invariant");1112TempNewSymbol utf8_sym = SymbolTable::new_symbol(utf8_constant, THREAD);1113// lookup existing1114const int utf8_orig_idx = utf8_info_index(ik, utf8_sym, THREAD);1115if (utf8_orig_idx != invalid_cp_index) {1116// existing constant pool entry found1117return utf8_orig_idx;1118}1119// no existing match, need to add a new utf8 cp entry1120assert(invalid_cp_index == utf8_orig_idx, "invariant");1121// add / append new1122return add_utf8_info(writer, utf8_constant, orig_cp_len, added_cp_entries);1123}11241125/*1126* This routine will resolve the required utf8_constants array1127* to their constant pool indexes (mapping to their UTF8_INFO's)1128* Only if a constant is actually needed and does not already exist1129* will it be added.1130*1131* The passed in indexes array will be populated with the resolved indexes.1132* The number of newly added constant pool entries is returned.1133*/1134static u2 resolve_utf8_indexes(JfrBigEndianWriter& writer,1135const InstanceKlass* ik,1136u2* const utf8_indexes,1137u2 orig_cp_len,1138const Method* clinit_method,1139TRAPS) {1140assert(utf8_indexes != NULL, "invariant");1141u2 added_cp_entries = 0;1142// resolve all required symbols1143for (u2 index = 0; index < NOF_UTF8_REQ_SYMBOLS; ++index) {1144utf8_indexes[index] = find_or_add_utf8_info(writer,1145ik,1146utf8_constants[index],1147orig_cp_len,1148added_cp_entries,1149THREAD);1150}1151// Now determine optional constants (mainly "Code" attributes)1152if (clinit_method != NULL && clinit_method->has_stackmap_table()) {1153utf8_indexes[UTF8_OPT_StackMapTable] =1154find_or_add_utf8_info(writer,1155ik,1156utf8_constants[UTF8_OPT_StackMapTable],1157orig_cp_len,1158added_cp_entries,1159THREAD);1160} else {1161utf8_indexes[UTF8_OPT_StackMapTable] = invalid_cp_index;1162}11631164if (clinit_method != NULL && clinit_method->has_linenumber_table()) {1165utf8_indexes[UTF8_OPT_LineNumberTable] =1166find_or_add_utf8_info(writer,1167ik,1168utf8_constants[UTF8_OPT_LineNumberTable],1169orig_cp_len,1170added_cp_entries,1171THREAD);1172} else {1173utf8_indexes[UTF8_OPT_LineNumberTable] = invalid_cp_index;1174}11751176if (clinit_method != NULL && clinit_method->has_localvariable_table()) {1177utf8_indexes[UTF8_OPT_LocalVariableTable] =1178find_or_add_utf8_info(writer,1179ik,1180utf8_constants[UTF8_OPT_LocalVariableTable],1181orig_cp_len,1182added_cp_entries,1183THREAD);11841185utf8_indexes[UTF8_OPT_LocalVariableTypeTable] =1186find_or_add_utf8_info(writer,1187ik,1188utf8_constants[UTF8_OPT_LocalVariableTypeTable],1189orig_cp_len,1190added_cp_entries,1191THREAD);1192} else {1193utf8_indexes[UTF8_OPT_LocalVariableTable] = invalid_cp_index;1194utf8_indexes[UTF8_OPT_LocalVariableTypeTable] = invalid_cp_index;1195}11961197return added_cp_entries;1198}11991200static u1* new_bytes_for_lazy_instrumentation(InstanceKlass* ik,1201ClassFileParser& parser,1202jint& size_of_new_bytes,1203TRAPS) {1204assert(ik != NULL, "invariant");1205// If the class already has a clinit method1206// we need to take that into account1207const Method* clinit_method = ik->class_initializer();1208const bool register_klass = should_register_klass(ik);1209ClassFileStream* const orig_stream = parser.clone_stream();1210const int orig_stream_size = orig_stream->length();1211assert(orig_stream->current_offset() == 0, "invariant");1212const u2 orig_cp_len = position_stream_after_cp(orig_stream);1213assert(orig_cp_len > 0, "invariant");1214assert(orig_stream->current_offset() > 0, "invariant");1215// Dimension and allocate a working byte buffer1216// to be used in building up a modified class [B.1217const jint new_buffer_size = extra_stream_bytes + orig_stream_size;1218u1* const new_buffer = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, u1, new_buffer_size);1219if (new_buffer == NULL) {1220if (true) tty->print_cr ("Thread local allocation (native) for " SIZE_FORMAT1221" bytes failed in JfrClassAdapter::on_klass_creation", (size_t)new_buffer_size);1222return NULL;1223}1224assert(new_buffer != NULL, "invariant");1225// [B wrapped in a big endian writer1226JfrBigEndianWriter writer(new_buffer, new_buffer_size);1227assert(writer.current_offset() == 0, "invariant");1228const u4 orig_access_flag_offset = orig_stream->current_offset();1229// Copy original stream from the beginning up to AccessFlags1230// This means the original constant pool contents are copied unmodified1231writer.bytes(orig_stream->buffer(), orig_access_flag_offset);1232assert(writer.is_valid(), "invariant");1233assert(writer.current_offset() == (intptr_t)orig_access_flag_offset, "invariant"); // same positions1234// Our writer now sits just after the last original constant pool entry.1235// I.e. we are in a good position to append new constant pool entries1236// This array will contain the resolved indexes1237// in order to reference UTF8_INFO's needed1238u2 utf8_indexes[NOF_UTF8_SYMBOLS];1239// Resolve_utf8_indexes will be conservative in attempting to1240// locate an existing UTF8_INFO; it will only append constants1241// that is absolutely required1242u2 number_of_new_constants = resolve_utf8_indexes(writer, ik, utf8_indexes, orig_cp_len, clinit_method, THREAD);1243// UTF8_INFO entries now added to the constant pool1244// In order to invoke a method we would need additional1245// constants, JVM_CONSTANT_Class, JVM_CONSTANT_NameAndType1246// and JVM_CONSTANT_Methodref.1247const u2 flr_register_method_ref_index =1248register_klass ?1249add_flr_register_method_constants(writer,1250utf8_indexes,1251orig_cp_len,1252number_of_new_constants,1253THREAD) : invalid_cp_index;12541255// New constant pool entries added and all UTF8_INFO indexes resolved1256// Now update the class file constant_pool_count with an updated count1257writer.write_at_offset<u2>(orig_cp_len + number_of_new_constants, 8);1258assert(writer.is_valid(), "invariant");1259orig_stream->skip_u2_fast(3); // access_flags, this_class_index, super_class_index1260const u2 iface_len = orig_stream->get_u2_fast(); // interfaces1261orig_stream->skip_u2_fast(iface_len);1262const u4 orig_fields_len_offset = orig_stream->current_offset();1263// Copy from AccessFlags up to and including interfaces1264writer.bytes(orig_stream->buffer() + orig_access_flag_offset,1265orig_fields_len_offset - orig_access_flag_offset);1266assert(writer.is_valid(), "invariant");1267const jlong new_fields_len_offset = writer.current_offset();1268const u2 orig_fields_len = position_stream_after_fields(orig_stream);1269u4 orig_method_len_offset = orig_stream->current_offset();1270// Copy up to and including fields1271writer.bytes(orig_stream->buffer() + orig_fields_len_offset, orig_method_len_offset - orig_fields_len_offset);1272assert(writer.is_valid(), "invariant");1273// We are sitting just after the original number of field_infos1274// so this is a position where we can add (append) new field_infos1275const u2 number_of_new_fields = add_field_infos(writer, utf8_indexes);1276assert(writer.is_valid(), "invariant");1277const jlong new_method_len_offset = writer.current_offset();1278// Additional field_infos added, update classfile fields_count1279writer.write_at_offset<u2>(orig_fields_len + number_of_new_fields, new_fields_len_offset);1280assert(writer.is_valid(), "invariant");1281// Our current location is now at classfile methods_count1282const u2 orig_methods_len = position_stream_after_methods(writer,1283orig_stream,1284utf8_indexes,1285register_klass,1286clinit_method,1287orig_method_len_offset);1288const u4 orig_attributes_count_offset = orig_stream->current_offset();1289// Copy existing methods1290writer.bytes(orig_stream->buffer() + orig_method_len_offset, orig_attributes_count_offset - orig_method_len_offset);1291assert(writer.is_valid(), "invariant");1292// We are sitting just after the original number of method_infos1293// so this is a position where we can add (append) new method_infos1294u2 number_of_new_methods = add_method_infos(writer, utf8_indexes);12951296// We have just added the new methods.1297//1298// What about the state of <clinit>?1299// We would need to do:1300// 1. Nothing (@Registered(false) annotation)1301// 2. Build up a new <clinit> - and if the original class already contains a <clinit>,1302// merging will be neccessary.1303//1304if (register_klass) {1305insert_clinit_method(ik, parser, writer, orig_cp_len, utf8_indexes, flr_register_method_ref_index, clinit_method, THREAD);1306}1307number_of_new_methods += clinit_method != NULL ? 0 : register_klass ? 1 : 0;1308// Update classfile methods_count1309writer.write_at_offset<u2>(orig_methods_len + number_of_new_methods, new_method_len_offset);1310assert(writer.is_valid(), "invariant");1311// Copy last remaining bytes1312writer.bytes(orig_stream->buffer() + orig_attributes_count_offset, orig_stream_size - orig_attributes_count_offset);1313assert(writer.is_valid(), "invariant");1314assert(writer.current_offset() > orig_stream->length(), "invariant");1315size_of_new_bytes = (jint)writer.current_offset();1316return new_buffer;1317}13181319static void log_pending_exception(oop throwable) {1320assert(throwable != NULL, "invariant");1321oop msg = java_lang_Throwable::message(throwable);1322if (msg != NULL) {1323char* text = java_lang_String::as_utf8_string(msg);1324if (text != NULL) {1325if (true) tty->print_cr ("%s", text);1326}1327}1328}13291330static bool should_force_instrumentation() {1331return !JfrOptionSet::allow_event_retransforms() || JfrEventClassTransformer::is_force_instrumentation();1332}13331334static ClassFileStream* create_new_bytes_for_subklass(InstanceKlass* ik, ClassFileParser& parser, Thread* t) {1335assert(JdkJfrEvent::is_a(ik), "invariant");1336DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t));1337jint size_of_new_bytes = 0;1338u1* new_bytes = new_bytes_for_lazy_instrumentation(ik, parser, size_of_new_bytes, t);1339if (new_bytes == NULL) {1340return NULL;1341}1342assert(new_bytes != NULL, "invariant");1343assert(size_of_new_bytes > 0, "invariant");13441345bool force_instrumentation = should_force_instrumentation();1346if (Jfr::is_recording() || force_instrumentation) {1347jint size_instrumented_data = 0;1348unsigned char* instrumented_data = NULL;1349const jclass super = (jclass)JNIHandles::make_local(ik->super()->java_mirror());1350JfrUpcalls::new_bytes_eager_instrumentation(TRACE_ID(ik),1351force_instrumentation,1352super,1353size_of_new_bytes,1354new_bytes,1355&size_instrumented_data,1356&instrumented_data,1357t);1358if (t->has_pending_exception()) {1359log_pending_exception(t->pending_exception());1360t->clear_pending_exception();1361return NULL;1362}1363assert(instrumented_data != NULL, "invariant");1364assert(size_instrumented_data > 0, "invariant");1365return new ClassFileStream(instrumented_data, size_instrumented_data, NULL);1366}1367return new ClassFileStream(new_bytes, size_of_new_bytes, NULL);1368}13691370static bool cache_bytes(InstanceKlass* ik, ClassFileStream* new_stream, InstanceKlass* new_ik, TRAPS) {1371assert(ik != NULL, "invariant");1372assert(new_ik != NULL, "invariant");1373assert(new_ik->name() != NULL, "invariant");1374assert(new_stream != NULL, "invariant");1375assert(!HAS_PENDING_EXCEPTION, "invariant");1376static const bool can_retransform = JfrOptionSet::allow_retransforms();1377if (!can_retransform) {1378return true;1379}1380const jint stream_len = new_stream->length();1381JvmtiCachedClassFileData* p =1382(JvmtiCachedClassFileData*)NEW_C_HEAP_ARRAY_RETURN_NULL(u1, offset_of(JvmtiCachedClassFileData, data) + stream_len, mtInternal);1383if (p == NULL) {1384if (true) tty->print_cr("Allocation using C_HEAP_ARRAY for " SIZE_FORMAT1385" bytes failed in JfrClassAdapter::on_klass_creation", (size_t)offset_of(JvmtiCachedClassFileData, data) + stream_len);1386return false;1387}1388p->length = stream_len;1389memcpy(p->data, new_stream->buffer(), stream_len);1390new_ik->set_cached_class_file(p);1391JvmtiCachedClassFileData* const cached_class_data = ik->get_cached_class_file();1392if (cached_class_data != NULL) {1393os::free(cached_class_data);1394ik->set_cached_class_file(NULL);1395}1396return true;1397}13981399static InstanceKlass* create_new_instance_klass(InstanceKlass* ik, ClassFileStream* stream, TRAPS) {1400assert(stream != NULL, "invariant");1401ResourceMark rm(THREAD);1402TempNewSymbol parsed_name = NULL;1403ClassLoaderData* const cld = ik->class_loader_data();1404Handle pd(THREAD, ik->protection_domain());1405Symbol* const class_name = ik->name();1406const char* const klass_name = class_name != NULL ? class_name->as_C_string() : "";1407InstanceKlass* const new_ik = ClassFileParser(stream).parseClassFile(1408class_name,1409cld,1410pd,1411NULL, // host klass1412NULL, // cp_patches1413parsed_name,1414true, // need_verify1415THREAD)();1416if (HAS_PENDING_EXCEPTION) {1417log_pending_exception(PENDING_EXCEPTION);1418CLEAR_PENDING_EXCEPTION;1419return NULL;1420}1421assert(new_ik != NULL, "invariant");1422assert(new_ik->name() != NULL, "invariant");1423assert(strncmp(ik->name()->as_C_string(), new_ik->name()->as_C_string(), strlen(ik->name()->as_C_string())) == 0, "invariant");1424return cache_bytes(ik, stream, new_ik, THREAD) ? new_ik : NULL;1425}14261427static void rewrite_klass_pointer(InstanceKlass*& ik, InstanceKlass* new_ik, ClassFileParser& parser, TRAPS) {1428assert(ik != NULL, "invariant");1429assert(new_ik != NULL, "invariant");1430assert(new_ik->name() != NULL, "invariant");1431assert(JdkJfrEvent::is(new_ik) || JdkJfrEvent::is_subklass(new_ik), "invariant");1432assert(!HAS_PENDING_EXCEPTION, "invariant");1433// assign original InstanceKlass* back onto "its" parser object for proper destruction1434parser.set_klass_to_deallocate(ik);1435// now rewrite original pointer to newly created InstanceKlass1436ik = new_ik;1437}14381439// During retransform/redefine, copy the Method specific trace flags1440// from the previous ik ("the original klass") to the new ik ("the scratch_klass").1441// The open code for retransform/redefine does not know about these.1442// In doing this migration here, we ensure the new Methods (defined in scratch klass)1443// will carry over trace tags from the old Methods being replaced,1444// ensuring flag/tag continuity while being transparent to open code.1445static void copy_method_trace_flags(const InstanceKlass* the_original_klass, const InstanceKlass* the_scratch_klass) {1446assert(the_original_klass != NULL, "invariant");1447assert(the_scratch_klass != NULL, "invariant");1448assert(the_original_klass->name() == the_scratch_klass->name(), "invariant");1449const Array<Method*>* old_methods = the_original_klass->methods();1450const Array<Method*>* new_methods = the_scratch_klass->methods();1451const bool equal_array_length = old_methods->length() == new_methods->length();1452// The Method array has the property of being sorted.1453// If they are the same length, there is a one-to-one mapping.1454// If they are unequal, there was a method added (currently only1455// private static methods allowed to be added), use lookup.1456for (int i = 0; i < old_methods->length(); ++i) {1457const Method* const old_method = old_methods->at(i);1458Method* const new_method = equal_array_length ? new_methods->at(i) :1459the_scratch_klass->find_method(old_method->name(), old_method->signature());1460assert(new_method != NULL, "invariant");1461assert(new_method->name() == old_method->name(), "invariant");1462assert(new_method->signature() == old_method->signature(), "invariant");1463*new_method->trace_flags_addr() = old_method->trace_flags();1464assert(new_method->trace_flags() == old_method->trace_flags(), "invariant");1465}1466}14671468static bool is_retransforming(const InstanceKlass* ik, TRAPS) {1469assert(ik != NULL, "invariant");1470assert(JdkJfrEvent::is_a(ik), "invariant");1471Symbol* const name = ik->name();1472assert(name != NULL, "invariant");1473Handle class_loader(THREAD, ik->class_loader());1474Handle protection_domain(THREAD, ik->protection_domain());1475// nota bene: use lock-free dictionary lookup1476const InstanceKlass* prev_ik = (const InstanceKlass*)SystemDictionary::find(name, class_loader, protection_domain, THREAD);1477if (prev_ik == NULL) {1478return false;1479}1480// an existing ik implies a retransform/redefine1481assert(prev_ik != NULL, "invariant");1482assert(JdkJfrEvent::is_a(prev_ik), "invariant");1483copy_method_trace_flags(prev_ik, ik);1484return true;1485}14861487// target for JFR_ON_KLASS_CREATION hook1488void JfrEventClassTransformer::on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS) {1489assert(ik != NULL, "invariant");1490if (JdkJfrEvent::is(ik)) {1491ResourceMark rm(THREAD);1492HandleMark hm(THREAD);1493ClassFileStream* new_stream = create_new_bytes_for_event_klass(ik, parser, THREAD);1494if (new_stream == NULL) {1495if (true) tty->print_cr("JfrClassAdapter: unable to create ClassFileStream");1496return;1497}1498assert(new_stream != NULL, "invariant");1499InstanceKlass* new_ik = create_new_instance_klass(ik, new_stream, THREAD);1500if (new_ik == NULL) {1501if (true) tty->print_cr("JfrClassAdapter: unable to create InstanceKlass");1502return;1503}1504assert(new_ik != NULL, "invariant");1505// We now need to explicitly tag the replaced klass as the jdk.jfr.Event klass1506assert(!JdkJfrEvent::is(new_ik), "invariant");1507JdkJfrEvent::tag_as(new_ik);1508assert(JdkJfrEvent::is(new_ik), "invariant");1509rewrite_klass_pointer(ik, new_ik, parser, THREAD);1510return;1511}1512assert(JdkJfrEvent::is_subklass(ik), "invariant");1513if (is_retransforming(ik, THREAD)) {1514// not the initial klass load1515return;1516}1517if (ik->is_abstract()) {1518// abstract classes are not instrumented1519return;1520}1521ResourceMark rm(THREAD);1522HandleMark hm(THREAD);1523ClassFileStream* const new_stream = create_new_bytes_for_subklass(ik, parser, THREAD);1524if (NULL == new_stream) {1525if (true) tty->print_cr("JfrClassAdapter: unable to create ClassFileStream");1526return;1527}1528assert(new_stream != NULL, "invariant");1529InstanceKlass* new_ik = create_new_instance_klass(ik, new_stream, THREAD);1530if (new_ik == NULL) {1531if (true) tty->print_cr("JfrClassAdapter: unable to create InstanceKlass");1532return;1533}1534assert(new_ik != NULL, "invariant");1535// would have been tagged already as a subklass during the normal process of traceid assignment1536assert(JdkJfrEvent::is_subklass(new_ik), "invariant");1537traceid id = ik->trace_id();1538ik->set_trace_id(0);1539new_ik->set_trace_id(id);1540rewrite_klass_pointer(ik, new_ik, parser, THREAD);1541}15421543static bool _force_instrumentation = false;1544void JfrEventClassTransformer::set_force_instrumentation(bool force_instrumentation) {1545_force_instrumentation = force_instrumentation;1546}15471548bool JfrEventClassTransformer::is_force_instrumentation() {1549return _force_instrumentation;1550}155115521553