Adjust to {Container,Input,Output}SchemaNode split
[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.implementation.bytecode.member.MethodVariableAccess;
27 import net.bytebuddy.jar.asm.ClassVisitor;
28 import net.bytebuddy.jar.asm.ClassWriter;
29 import net.bytebuddy.jar.asm.Label;
30 import net.bytebuddy.jar.asm.MethodVisitor;
31 import net.bytebuddy.jar.asm.Opcodes;
32 import net.bytebuddy.matcher.ElementMatchers;
33 import net.bytebuddy.pool.TypePool;
34
35 final class ByteBuddyUtils {
36     static final StackManipulation THIS = MethodVariableAccess.loadThis();
37
38     private ByteBuddyUtils() {
39
40     }
41
42     static StackManipulation invokeMethod(final Method method) {
43         return MethodInvocation.invoke(describe(method));
44     }
45
46     static StackManipulation invokeMethod(final Class<?> clazz, final String name, final Class<?>... args) {
47         return MethodInvocation.invoke(describe(clazz, name, args));
48     }
49
50     static AsmVisitorWrapper computeFrames() {
51         return ComputeFrames.INSTANCE;
52     }
53
54     static StackManipulation ifEq(final Label label) {
55         return new IfEq(label);
56     }
57
58     static StackManipulation markLabel(final Label label) {
59         return new Mark(label);
60     }
61
62     static StackManipulation loadThis() {
63         return THIS;
64     }
65
66     static StackManipulation getField(final Field field) {
67         return FieldAccess.forField(new ForLoadedField(field).asDefined()).read();
68     }
69
70     static StackManipulation getField(final TypeDescription instrumentedType, final String fieldName) {
71         return fieldAccess(instrumentedType, fieldName).read();
72     }
73
74     static StackManipulation putField(final TypeDescription instrumentedType, final String fieldName) {
75         return fieldAccess(instrumentedType, fieldName).write();
76     }
77
78     private static ForLoadedMethod describe(final Method method) {
79         return new ForLoadedMethod(method);
80     }
81
82     private static ForLoadedMethod describe(final Class<?> clazz, final String name, final Class<?>... args) {
83         return describe(getMethod(clazz, name, args));
84     }
85
86     private static Defined fieldAccess(final TypeDescription instrumentedType, final String fieldName) {
87         return FieldAccess.forField(instrumentedType.getDeclaredFields().filter(ElementMatchers.named(fieldName))
88             .getOnly());
89     }
90
91     /**
92      * Utility wrapper to force ASM to compute frames.
93      */
94     private enum ComputeFrames implements AsmVisitorWrapper {
95         INSTANCE;
96
97         @Override
98         public int mergeWriter(final int flags) {
99             return flags | ClassWriter.COMPUTE_FRAMES;
100         }
101
102         @Override
103         public int mergeReader(final int flags) {
104             return flags | ClassWriter.COMPUTE_FRAMES;
105         }
106
107         @Override
108         public ClassVisitor wrap(final TypeDescription td, final ClassVisitor cv, final Implementation.Context ctx,
109                 final TypePool tp, final FieldList<FieldDescription.InDefinedShape> fields, final MethodList<?> methods,
110                 final int wflags, final int rflags) {
111             return cv;
112         }
113     }
114
115     /**
116      * IFEQ opcode invocation, jumping to a particular label.
117      */
118     private static final class IfEq implements StackManipulation {
119         private static final StackManipulation.Size SIZE = new StackManipulation.Size(-1, 0);
120
121         private final Label label;
122
123         IfEq(final Label label) {
124             this.label = requireNonNull(label);
125         }
126
127         @Override
128         public boolean isValid() {
129             return true;
130         }
131
132         @Override
133         public StackManipulation.Size apply(final MethodVisitor mv, final Implementation.Context ctx) {
134             mv.visitJumpInsn(Opcodes.IFEQ, label);
135             return SIZE;
136         }
137     }
138
139     /**
140      * A label definition, marking the spot where IfEq should jump.
141      */
142     private static final class Mark implements StackManipulation {
143         private static final StackManipulation.Size SIZE = new StackManipulation.Size(0, 0);
144
145         private final Label label;
146
147         Mark(final Label label) {
148             this.label = requireNonNull(label);
149         }
150
151         @Override
152         public boolean isValid() {
153             return true;
154         }
155
156         @Override
157         public StackManipulation.Size apply(final MethodVisitor mv, final Implementation.Context ctx) {
158             mv.visitLabel(label);
159             return SIZE;
160         }
161     }
162
163     private static Method getMethod(final Class<?> clazz, final String name, final Class<?>... args) {
164         try {
165             return clazz.getDeclaredMethod(name, args);
166         } catch (NoSuchMethodException e) {
167             throw new IllegalStateException(e);
168         }
169     }
170 }