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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.jfr.internal; 27 28 import java.lang.reflect.Field; 29 import java.lang.reflect.Modifier; 30 import java.lang.reflect.Parameter; 31 import java.util.ArrayList; 32 import java.util.HashSet; 33 import java.util.List; 34 import java.util.Set; 35 import java.util.function.Consumer; 36 37 import jdk.internal.org.objectweb.asm.ClassReader; 38 import jdk.internal.org.objectweb.asm.ClassWriter; 39 import jdk.internal.org.objectweb.asm.Label; 40 import jdk.internal.org.objectweb.asm.MethodVisitor; 41 import jdk.internal.org.objectweb.asm.Opcodes; 42 import jdk.internal.org.objectweb.asm.Type; 43 import jdk.internal.org.objectweb.asm.commons.Method; 44 import jdk.internal.org.objectweb.asm.tree.AnnotationNode; 45 import jdk.internal.org.objectweb.asm.tree.ClassNode; 46 import jdk.internal.org.objectweb.asm.tree.FieldNode; 47 import jdk.internal.org.objectweb.asm.tree.MethodNode; 48 import jdk.jfr.Enabled; 49 import jdk.jfr.Event; 50 import jdk.jfr.Name; 51 import jdk.jfr.Registered; 52 import jdk.jfr.SettingControl; 53 import jdk.jfr.SettingDefinition; 54 import jdk.jfr.internal.handlers.EventHandler; 55 56 /** 57 * Class responsible for adding instrumentation to a subclass of {@link Event}. 58 * 59 */ 60 public final class EventInstrumentation { 61 static final class SettingInfo { 62 private String methodName; 63 private String internalSettingName; 64 private String settingDescriptor; 65 final String fieldName; 66 final int index; 67 // Used when instantiating Setting 68 SettingControl settingControl; 69 70 public SettingInfo(String fieldName, int index) { 71 this.fieldName = fieldName; 72 this.index = index; 73 } 74 } 75 76 static final class FieldInfo { 77 private final static Type STRING = Type.getType(String.class); 78 final String fieldName; 79 final String fieldDescriptor; 80 final String internalClassName; 81 82 public FieldInfo(String fieldName, String fieldDescriptor, String internalClassName) { 83 this.fieldName = fieldName; 84 this.fieldDescriptor = fieldDescriptor; 85 this.internalClassName = internalClassName; 86 } 87 88 public boolean isString() { 89 return STRING.getDescriptor().equals(fieldDescriptor); 90 } 91 } 92 93 public static final String FIELD_EVENT_THREAD = "eventThread"; 94 public static final String FIELD_STACK_TRACE = "stackTrace"; 95 public static final String FIELD_DURATION = "duration"; 96 97 static final String FIELD_EVENT_HANDLER = "eventHandler"; 98 static final String FIELD_START_TIME = "startTime"; 99 100 private static final Class<? extends EventHandler> eventHandlerProxy = EventHandlerProxyCreator.proxyClass; 101 private static final Type ANNOTATION_TYPE_NAME = Type.getType(Name.class); 102 private static final Type ANNOTATION_TYPE_REGISTERED = Type.getType(Registered.class); 103 private static final Type ANNOTATION_TYPE_ENABLED = Type.getType(Enabled.class); 104 private static final Type TYPE_EVENT_HANDLER = Type.getType(eventHandlerProxy); 105 private static final Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class); 106 private static final Method METHOD_COMMIT = new Method("commit", Type.VOID_TYPE, new Type[0]); 107 private static final Method METHOD_BEGIN = new Method("begin", Type.VOID_TYPE, new Type[0]); 108 private static final Method METHOD_END = new Method("end", Type.VOID_TYPE, new Type[0]); 109 private static final Method METHOD_IS_ENABLED = new Method("isEnabled", Type.BOOLEAN_TYPE, new Type[0]); 110 private static final Method METHOD_TIME_STAMP = new Method("timestamp", Type.LONG_TYPE, new Type[0]); 111 private static final Method METHOD_EVENT_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[0]); 112 private static final Method METHOD_EVENT_HANDLER_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[] { Type.LONG_TYPE }); 113 private static final Method METHOD_DURATION = new Method("duration", Type.LONG_TYPE, new Type[] { Type.LONG_TYPE }); 114 115 private final ClassNode classNode; 116 private final List<SettingInfo> settingInfos; 117 private final List<FieldInfo> fieldInfos;; 118 private final Method writeMethod; 119 private final String eventHandlerXInternalName; 120 private final String eventName; 121 private boolean guardHandlerReference; 122 private Class<?> superClass; 123 124 EventInstrumentation(Class<?> superClass, byte[] bytes, long id) { 125 this.superClass = superClass; 126 this.classNode = createClassNode(bytes); 127 this.settingInfos = buildSettingInfos(superClass, classNode); 128 this.fieldInfos = buildFieldInfos(superClass, classNode); 129 this.writeMethod = makeWriteMethod(fieldInfos); 130 this.eventHandlerXInternalName = ASMToolkit.getInternalName(EventHandlerCreator.makeEventHandlerName(id)); 131 String n = annotationValue(classNode, ANNOTATION_TYPE_NAME.getDescriptor(), String.class); 132 this.eventName = n == null ? classNode.name.replace("/", ".") : n; 133 134 } 135 136 public String getClassName() { 137 return classNode.name.replace("/","."); 138 } 139 140 private ClassNode createClassNode(byte[] bytes) { 141 ClassNode classNode = new ClassNode(); 142 ClassReader classReader = new ClassReader(bytes); 143 classReader.accept(classNode, 0); 144 return classNode; 145 } 146 147 boolean isRegistered() { 148 Boolean result = annotationValue(classNode, ANNOTATION_TYPE_REGISTERED.getDescriptor(), Boolean.class); 149 if (result != null) { 150 return result.booleanValue(); 151 } 152 if (superClass != null) { 153 Registered r = superClass.getAnnotation(Registered.class); 154 if (r != null) { 155 return r.value(); 156 } 157 } 158 return true; 159 } 160 161 boolean isEnabled() { 162 Boolean result = annotationValue(classNode, ANNOTATION_TYPE_ENABLED.getDescriptor(), Boolean.class); 163 if (result != null) { 164 return result.booleanValue(); 165 } 166 if (superClass != null) { 167 Enabled e = superClass.getAnnotation(Enabled.class); 168 if (e != null) { 169 return e.value(); 170 } 171 } 172 return true; 173 } 174 175 @SuppressWarnings("unchecked") 176 private static <T> T annotationValue(ClassNode classNode, String typeDescriptor, Class<?> type) { 177 if (classNode.visibleAnnotations != null) { 178 for (AnnotationNode a : classNode.visibleAnnotations) { 179 if (typeDescriptor.equals(a.desc)) { 180 List<Object> values = a.values; 181 if (values != null && values.size() == 2) { 182 Object key = values.get(0); 183 Object value = values.get(1); 184 if (key instanceof String && value != null) { 185 if (type == value.getClass()) { 186 String keyName = (String) key; 187 if ("value".equals(keyName)) { 188 return (T) value; 189 } 190 } 191 } 192 } 193 } 194 } 195 } 196 return null; 197 } 198 199 private static List<SettingInfo> buildSettingInfos(Class<?> superClass, ClassNode classNode) { 200 Set<String> methodSet = new HashSet<>(); 201 List<SettingInfo> settingInfos = new ArrayList<>(); 202 String settingDescriptor = Type.getType(SettingDefinition.class).getDescriptor(); 203 for (MethodNode m : classNode.methods) { 204 if (m.visibleAnnotations != null) { 205 for (AnnotationNode an : m.visibleAnnotations) { 206 // We can't really validate the method at this 207 // stage. We would need to check that the parameter 208 // is an instance of SettingControl. 209 if (settingDescriptor.equals(an.desc)) { 210 Type returnType = Type.getReturnType(m.desc); 211 if (returnType.equals(Type.getType(Boolean.TYPE))) { 212 Type[] args = Type.getArgumentTypes(m.desc); 213 if (args.length == 1) { 214 Type paramType = args[0]; 215 String fieldName = EventControl.FIELD_SETTING_PREFIX + settingInfos.size(); 216 int index = settingInfos.size(); 217 SettingInfo si = new SettingInfo(fieldName, index); 218 si.methodName = m.name; 219 si.settingDescriptor = paramType.getDescriptor(); 220 si.internalSettingName = paramType.getInternalName(); 221 methodSet.add(m.name); 222 settingInfos.add(si); 223 } 224 } 225 } 226 } 227 } 228 } 229 for (Class<?> c = superClass; c != Event.class; c = c.getSuperclass()) { 230 for (java.lang.reflect.Method method : c.getDeclaredMethods()) { 231 if (!methodSet.contains(method.getName())) { 232 // skip private method in base classes 233 if (!Modifier.isPrivate(method.getModifiers())) { 234 if (method.getReturnType().equals(Boolean.TYPE)) { 235 if (method.getParameterCount() == 1) { 236 Parameter param = method.getParameters()[0]; 237 Type paramType = Type.getType(param.getType()); 238 String fieldName = EventControl.FIELD_SETTING_PREFIX + settingInfos.size(); 239 int index = settingInfos.size(); 240 SettingInfo si = new SettingInfo(fieldName, index); 241 si.methodName = method.getName(); 242 si.settingDescriptor = paramType.getDescriptor(); 243 si.internalSettingName = paramType.getInternalName(); 244 methodSet.add(method.getName()); 245 settingInfos.add(si); 246 } 247 } 248 } 249 } 250 } 251 } 252 return settingInfos; 253 254 } 255 256 private static List<FieldInfo> buildFieldInfos(Class<?> superClass, ClassNode classNode) { 257 Set<String> fieldSet = new HashSet<>(); 258 List<FieldInfo> fieldInfos = new ArrayList<>(classNode.fields.size()); 259 // These two field are added by native as transient so they will be 260 // ignored by the loop below. 261 // The benefit of adding them manually is that we can 262 // control in which order they occur and we can add @Name, @Description 263 // in Java, instead of in native. It also means code for adding implicit 264 // fields for native can be reused by Java. 265 fieldInfos.add(new FieldInfo("startTime", Type.LONG_TYPE.getDescriptor(), classNode.name)); 266 fieldInfos.add(new FieldInfo("duration", Type.LONG_TYPE.getDescriptor(), classNode.name)); 267 for (FieldNode field : classNode.fields) { 268 String className = Type.getType(field.desc).getClassName(); 269 if (!fieldSet.contains(field.name) && isValidField(field.access, className)) { 270 FieldInfo fi = new FieldInfo(field.name, field.desc, classNode.name); 271 fieldInfos.add(fi); 272 fieldSet.add(field.name); 273 } 274 } 275 for (Class<?> c = superClass; c != Event.class; c = c.getSuperclass()) { 276 for (Field field : c.getDeclaredFields()) { 277 // skip private field in base classes 278 if (!Modifier.isPrivate(field.getModifiers())) { 279 if (isValidField(field.getModifiers(), field.getType().getName())) { 280 String fieldName = field.getName(); 281 if (!fieldSet.contains(fieldName)) { 282 Type fieldType = Type.getType(field.getType()); 283 String internalClassName = ASMToolkit.getInternalName(c.getName()); 284 fieldInfos.add(new FieldInfo(fieldName, fieldType.getDescriptor(), internalClassName)); 285 fieldSet.add(fieldName); 286 } 287 } 288 } 289 } 290 } 291 return fieldInfos; 292 } 293 294 public static boolean isValidField(int access, String className) { 295 if (Modifier.isTransient(access) || Modifier.isStatic(access)) { 296 return false; 297 } 298 return jdk.jfr.internal.Type.isValidJavaFieldType(className); 299 } 300 301 public byte[] buildInstrumented() { 302 makeInstrumented(); 303 return toByteArray(); 304 } 305 306 private byte[] toByteArray() { 307 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 308 classNode.accept(cw); 309 cw.visitEnd(); 310 byte[] result = cw.toByteArray(); 311 Utils.writeGeneratedASM(classNode.name, result); 312 return result; 313 } 314 315 public byte[] builUninstrumented() { 316 makeUninstrumented(); 317 return toByteArray(); 318 } 319 320 private void makeInstrumented() { 321 // MyEvent#isEnabled() 322 updateMethod(METHOD_IS_ENABLED, methodVisitor -> { 323 Label nullLabel = new Label(); 324 if (guardHandlerReference) { 325 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_EVENT_HANDLER.getDescriptor()); 326 methodVisitor.visitJumpInsn(Opcodes.IFNULL, nullLabel); 327 } 328 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_EVENT_HANDLER.getDescriptor()); 329 ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_IS_ENABLED); 330 methodVisitor.visitInsn(Opcodes.IRETURN); 331 if (guardHandlerReference) { 332 methodVisitor.visitLabel(nullLabel); 333 methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); 334 methodVisitor.visitInsn(Opcodes.ICONST_0); 335 methodVisitor.visitInsn(Opcodes.IRETURN); 336 } 337 }); 338 339 // MyEvent#begin() 340 updateMethod(METHOD_BEGIN, methodVisitor -> { 341 methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); 342 ASMToolkit.invokeStatic(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP); 343 methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_START_TIME, "J"); 344 methodVisitor.visitInsn(Opcodes.RETURN); 345 }); 346 347 // MyEvent#end() 348 updateMethod(METHOD_END, methodVisitor -> { 349 methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); 350 methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); 351 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J"); 352 ASMToolkit.invokeStatic(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_DURATION); 353 methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J"); 354 methodVisitor.visitInsn(Opcodes.RETURN); 355 methodVisitor.visitMaxs(0, 0); 356 }); 357 358 // MyEvent#commit() - Java event writer 359 updateMethod(METHOD_COMMIT, methodVisitor -> { 360 // if (!isEnable()) { 361 // return; 362 // } 363 methodVisitor.visitCode(); 364 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); 365 methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_IS_ENABLED.getName(), METHOD_IS_ENABLED.getDescriptor(), false); 366 Label l0 = new Label(); 367 methodVisitor.visitJumpInsn(Opcodes.IFNE, l0); 368 methodVisitor.visitInsn(Opcodes.RETURN); 369 methodVisitor.visitLabel(l0); 370 methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); 371 // if (startTime == 0) { 372 // startTime = EventWriter.timestamp(); 373 // } else { 374 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); 375 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J"); 376 methodVisitor.visitInsn(Opcodes.LCONST_0); 377 methodVisitor.visitInsn(Opcodes.LCMP); 378 Label durationalEvent = new Label(); 379 methodVisitor.visitJumpInsn(Opcodes.IFNE, durationalEvent); 380 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); 381 methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP.getName(), 382 METHOD_TIME_STAMP.getDescriptor(), false); 383 methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_START_TIME, "J"); 384 Label commit = new Label(); 385 methodVisitor.visitJumpInsn(Opcodes.GOTO, commit); 386 // if (duration == 0) { 387 // duration = EventWriter.timestamp() - startTime; 388 // } 389 // } 390 methodVisitor.visitLabel(durationalEvent); 391 methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); 392 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); 393 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J"); 394 methodVisitor.visitInsn(Opcodes.LCONST_0); 395 methodVisitor.visitInsn(Opcodes.LCMP); 396 methodVisitor.visitJumpInsn(Opcodes.IFNE, commit); 397 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); 398 methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false); 399 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); 400 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J"); 401 methodVisitor.visitInsn(Opcodes.LSUB); 402 methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J"); 403 methodVisitor.visitLabel(commit); 404 // if (shouldCommit()) { 405 methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); 406 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); 407 methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_EVENT_SHOULD_COMMIT.getName(), METHOD_EVENT_SHOULD_COMMIT.getDescriptor(), false); 408 Label end = new Label(); 409 // eventHandler.write(...); 410 // } 411 methodVisitor.visitJumpInsn(Opcodes.IFEQ, end); 412 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(eventHandlerProxy)); 413 414 methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName); 415 for (FieldInfo fi : fieldInfos) { 416 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); 417 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, fi.internalClassName, fi.fieldName, fi.fieldDescriptor); 418 } 419 420 methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, eventHandlerXInternalName, writeMethod.getName(), writeMethod.getDescriptor(), false); 421 methodVisitor.visitLabel(end); 422 methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); 423 methodVisitor.visitInsn(Opcodes.RETURN); 424 methodVisitor.visitEnd(); 425 }); 426 427 // MyEvent#shouldCommit() 428 updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> { 429 Label fail = new Label(); 430 // if (!eventHandler.shoouldCommit(duration) goto fail; 431 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(eventHandlerProxy)); 432 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); 433 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J"); 434 ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_EVENT_HANDLER_SHOULD_COMMIT); 435 methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail); 436 for (SettingInfo si : settingInfos) { 437 // if (!settingsMethod(eventHandler.settingX)) goto fail; 438 methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); 439 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(eventHandlerProxy)); 440 methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName); 441 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, eventHandlerXInternalName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor()); 442 methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.internalSettingName); 443 methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), si.methodName, "(" + si.settingDescriptor + ")Z", false); 444 methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail); 445 } 446 // return true 447 methodVisitor.visitInsn(Opcodes.ICONST_1); 448 methodVisitor.visitInsn(Opcodes.IRETURN); 449 // return false 450 methodVisitor.visitLabel(fail); 451 methodVisitor.visitInsn(Opcodes.ICONST_0); 452 methodVisitor.visitInsn(Opcodes.IRETURN); 453 }); 454 } 455 456 private void makeUninstrumented() { 457 updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT); 458 updateExistingWithReturnFalse(METHOD_IS_ENABLED); 459 updateExistingWithEmptyVoidMethod(METHOD_COMMIT); 460 updateExistingWithEmptyVoidMethod(METHOD_BEGIN); 461 updateExistingWithEmptyVoidMethod(METHOD_END); 462 } 463 464 private final void updateExistingWithEmptyVoidMethod(Method voidMethod) { 465 updateMethod(voidMethod, methodVisitor -> { 466 methodVisitor.visitInsn(Opcodes.RETURN); 467 }); 468 } 469 470 private final void updateExistingWithReturnFalse(Method voidMethod) { 471 updateMethod(voidMethod, methodVisitor -> { 472 methodVisitor.visitInsn(Opcodes.ICONST_0); 473 methodVisitor.visitInsn(Opcodes.IRETURN); 474 }); 475 } 476 477 private MethodNode getMethodNode(Method method) { 478 for (MethodNode m : classNode.methods) { 479 if (m.name.equals(method.getName()) && m.desc.equals(method.getDescriptor())) { 480 return m; 481 } 482 } 483 return null; 484 } 485 486 private final void updateMethod(Method method, Consumer<MethodVisitor> code) { 487 MethodNode old = getMethodNode(method); 488 int index = classNode.methods.indexOf(old); 489 classNode.methods.remove(old); 490 MethodVisitor mv = classNode.visitMethod(old.access, old.name, old.desc, null, null); 491 mv.visitCode(); 492 code.accept(mv); 493 mv.visitMaxs(0, 0); 494 MethodNode newMethod = getMethodNode(method); 495 classNode.methods.remove(newMethod); 496 classNode.methods.add(index, newMethod); 497 } 498 499 public static Method makeWriteMethod(List<FieldInfo> fields) { 500 StringBuilder sb = new StringBuilder(); 501 sb.append("("); 502 for (FieldInfo v : fields) { 503 sb.append(v.fieldDescriptor); 504 } 505 sb.append(")V"); 506 return new Method("write", sb.toString()); 507 } 508 509 private String getInternalClassName() { 510 return classNode.name; 511 } 512 513 public List<SettingInfo> getSettingInfos() { 514 return settingInfos; 515 } 516 517 public List<FieldInfo> getFieldInfos() { 518 return fieldInfos; 519 } 520 521 public String getEventName() { 522 return eventName; 523 } 524 525 public void setGuardHandler(boolean guardHandlerReference) { 526 this.guardHandlerReference = guardHandlerReference; 527 } 528 }