Bump byte-buddy to 1.11.5
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / ByteBuddyUtils.java
1 /*
2  * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.binding.dom.codec.impl;
9
10 import static java.util.Objects.requireNonNull;
11
12 import java.lang.reflect.Field;
13 import java.lang.reflect.Method;
14 import net.bytebuddy.asm.AsmVisitorWrapper;
15 import net.bytebuddy.description.field.FieldDescription;
16 import net.bytebuddy.description.field.FieldDescription.ForLoadedField;
17 import net.bytebuddy.description.field.FieldList;
18 import net.bytebuddy.description.method.MethodDescription.ForLoadedMethod;
19 import net.bytebuddy.description.method.MethodList;
20 import net.bytebuddy.description.type.TypeDescription;
21 import net.bytebuddy.implementation.Implementation;
22 import net.bytebuddy.implementation.bytecode.StackManipulation;
23 import net.bytebuddy.implementation.bytecode.member.FieldAccess;
24 import net.bytebuddy.implementation.bytecode.member.FieldAccess.Defined;
25 import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
26 import net.bytebuddy.jar.asm.ClassVisitor;
27 import net.bytebuddy.jar.asm.ClassWriter;
28 import net.bytebuddy.jar.asm.Label;
29 import net.bytebuddy.jar.asm.MethodVisitor;
30 import net.bytebuddy.jar.asm.Opcodes;
31 import net.bytebuddy.matcher.ElementMatchers;
32 import net.bytebuddy.pool.TypePool;
33
34 final class ByteBuddyUtils {
35     private ByteBuddyUtils() {
36         // Hidden on purpose
37     }
38
39     static StackManipulation invokeMethod(final Method method) {
40         return MethodInvocation.invoke(describe(method));
41     }
42
43     static StackManipulation invokeMethod(final Class<?> clazz, final String name, final Class<?>... args) {
44         return MethodInvocation.invoke(describe(clazz, name, args));
45     }
46
47     static AsmVisitorWrapper computeFrames() {
48         return ComputeFrames.INSTANCE;
49     }
50
51     static StackManipulation ifEq(final Label label) {
52         return new IfEq(label);
53     }
54
55     static StackManipulation markLabel(final Label label) {
56         return new Mark(label);
57     }
58
59     static StackManipulation getField(final Field field) {
60         return FieldAccess.forField(new ForLoadedField(field).asDefined()).read();
61     }
62
63     static StackManipulation getField(final TypeDescription instrumentedType, final String fieldName) {
64         return fieldAccess(instrumentedType, fieldName).read();
65     }
66
67     static StackManipulation putField(final TypeDescription instrumentedType, final String fieldName) {
68         return fieldAccess(instrumentedType, fieldName).write();
69     }
70
71     private static ForLoadedMethod describe(final Method method) {
72         return new ForLoadedMethod(method);
73     }
74
75     private static ForLoadedMethod describe(final Class<?> clazz, final String name, final Class<?>... args) {
76         return describe(getMethod(clazz, name, args));
77     }
78
79     private static Defined fieldAccess(final TypeDescription instrumentedType, final String fieldName) {
80         return FieldAccess.forField(instrumentedType.getDeclaredFields().filter(ElementMatchers.named(fieldName))
81             .getOnly());
82     }
83
84     /**
85      * Utility wrapper to force ASM to compute frames.
86      */
87     private enum ComputeFrames implements AsmVisitorWrapper {
88         INSTANCE;
89
90         @Override
91         public int mergeWriter(final int flags) {
92             return flags | ClassWriter.COMPUTE_FRAMES;
93         }
94
95         @Override
96         public int mergeReader(final int flags) {
97             return flags | ClassWriter.COMPUTE_FRAMES;
98         }
99
100         @Override
101         public ClassVisitor wrap(final TypeDescription td, final ClassVisitor cv, final Implementation.Context ctx,
102                 final TypePool tp, final FieldList<FieldDescription.InDefinedShape> fields, final MethodList<?> methods,
103                 final int wflags, final int rflags) {
104             return cv;
105         }
106     }
107
108     /**
109      * IFEQ opcode invocation, jumping to a particular label.
110      */
111     private static final class IfEq implements StackManipulation {
112         private static final StackManipulation.Size SIZE = new StackManipulation.Size(-1, 0);
113
114         private final Label label;
115
116         IfEq(final Label label) {
117             this.label = requireNonNull(label);
118         }
119
120         @Override
121         public boolean isValid() {
122             return true;
123         }
124
125         @Override
126         public StackManipulation.Size apply(final MethodVisitor mv, final Implementation.Context ctx) {
127             mv.visitJumpInsn(Opcodes.IFEQ, label);
128             return SIZE;
129         }
130     }
131
132     /**
133      * A label definition, marking the spot where IfEq should jump.
134      */
135     private static final class Mark implements StackManipulation {
136         private static final StackManipulation.Size SIZE = new StackManipulation.Size(0, 0);
137
138         private final Label label;
139
140         Mark(final Label label) {
141             this.label = requireNonNull(label);
142         }
143
144         @Override
145         public boolean isValid() {
146             return true;
147         }
148
149         @Override
150         public StackManipulation.Size apply(final MethodVisitor mv, final Implementation.Context ctx) {
151             mv.visitLabel(label);
152             return SIZE;
153         }
154     }
155
156     private static Method getMethod(final Class<?> clazz, final String name, final Class<?>... args) {
157         try {
158             return clazz.getDeclaredMethod(name, args);
159         } catch (NoSuchMethodException e) {
160             throw new IllegalStateException(e);
161         }
162     }
163 }