2 * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.binding.dom.codec.impl;
10 import static java.util.Objects.requireNonNull;
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;
35 final class ByteBuddyUtils {
36 private static final StackManipulation LOAD_THIS = MethodVariableAccess.loadThis();
38 private ByteBuddyUtils() {
42 // TODO: eliminate this method once MethodVariableAccess.loadThis() returns a singleton
43 static StackManipulation loadThis() {
47 static StackManipulation invokeMethod(final Method method) {
48 return MethodInvocation.invoke(describe(method));
51 static StackManipulation invokeMethod(final Class<?> clazz, final String name, final Class<?>... args) {
52 return MethodInvocation.invoke(describe(clazz, name, args));
55 static AsmVisitorWrapper computeFrames() {
56 return ComputeFrames.INSTANCE;
59 static StackManipulation ifEq(final Label label) {
60 return new IfEq(label);
63 static StackManipulation markLabel(final Label label) {
64 return new Mark(label);
67 static StackManipulation getField(final Field field) {
68 return FieldAccess.forField(new ForLoadedField(field).asDefined()).read();
71 static StackManipulation getField(final TypeDescription instrumentedType, final String fieldName) {
72 return fieldAccess(instrumentedType, fieldName).read();
75 static StackManipulation putField(final TypeDescription instrumentedType, final String fieldName) {
76 return fieldAccess(instrumentedType, fieldName).write();
79 private static ForLoadedMethod describe(final Method method) {
80 return new ForLoadedMethod(method);
83 private static ForLoadedMethod describe(final Class<?> clazz, final String name, final Class<?>... args) {
84 return describe(getMethod(clazz, name, args));
87 private static Defined fieldAccess(final TypeDescription instrumentedType, final String fieldName) {
88 return FieldAccess.forField(instrumentedType.getDeclaredFields().filter(ElementMatchers.named(fieldName))
93 * Utility wrapper to force ASM to compute frames.
95 private enum ComputeFrames implements AsmVisitorWrapper {
99 public int mergeWriter(final int flags) {
100 return flags | ClassWriter.COMPUTE_FRAMES;
104 public int mergeReader(final int flags) {
105 return flags | ClassWriter.COMPUTE_FRAMES;
109 public ClassVisitor wrap(final TypeDescription td, final ClassVisitor cv, final Implementation.Context ctx,
110 final TypePool tp, final FieldList<FieldDescription.InDefinedShape> fields, final MethodList<?> methods,
111 final int wflags, final int rflags) {
117 * IFEQ opcode invocation, jumping to a particular label.
119 private static final class IfEq implements StackManipulation {
120 private static final StackManipulation.Size SIZE = new StackManipulation.Size(-1, 0);
122 private final Label label;
124 IfEq(final Label label) {
125 this.label = requireNonNull(label);
129 public boolean isValid() {
134 public StackManipulation.Size apply(final MethodVisitor mv, final Implementation.Context ctx) {
135 mv.visitJumpInsn(Opcodes.IFEQ, label);
141 * A label definition, marking the spot where IfEq should jump.
143 private static final class Mark implements StackManipulation {
144 private static final StackManipulation.Size SIZE = new StackManipulation.Size(0, 0);
146 private final Label label;
148 Mark(final Label label) {
149 this.label = requireNonNull(label);
153 public boolean isValid() {
158 public StackManipulation.Size apply(final MethodVisitor mv, final Implementation.Context ctx) {
159 mv.visitLabel(label);
164 private static Method getMethod(final Class<?> clazz, final String name, final Class<?>... args) {
166 return clazz.getDeclaredMethod(name, args);
167 } catch (NoSuchMethodException e) {
168 throw new IllegalStateException(e);