1 /*
2 * Copyright 2014 - 2020 Rafael Winterhalter
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.bytebuddy.implementation;
17
18 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19 import net.bytebuddy.description.method.MethodDescription;
20 import net.bytebuddy.dynamic.scaffold.InstrumentedType;
21 import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
22 import net.bytebuddy.implementation.bytecode.Removal;
23 import net.bytebuddy.implementation.bytecode.StackManipulation;
24 import net.bytebuddy.implementation.bytecode.member.MethodReturn;
25 import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
26 import net.bytebuddy.jar.asm.MethodVisitor;
27
28 /**
29 * This implementation will create a new method which simply calls its super method. If no such method is defined,
30 * an exception will be thrown. Constructors are considered to have a super method if the direct super class defines
31 * a constructor with an identical signature. Default methods are invoked as such if they are non-ambiguous. Static
32 * methods can have a (pseudo) super method if a type that defines such a method is rebased. Rebased types can also
33 * shadow constructors or methods of an actual super class. Besides implementing constructors, this implementation
34 * is useful when a method of a super type is not supposed to be altered but should be equipped with additional
35 * annotations. Furthermore, this implementation allows to hard code a super method call to be performed after
36 * performing another {@link Implementation}.
37 */
38 public enum SuperMethodCall implements Implementation.Composable {
39
40 /**
41 * The singleton instance.
42 */
43 INSTANCE;
44
45 /**
46 * {@inheritDoc}
47 */
48 public InstrumentedType prepare(InstrumentedType instrumentedType) {
49 return instrumentedType;
50 }
51
52 /**
53 * {@inheritDoc}
54 */
55 public ByteCodeAppender appender(Target implementationTarget) {
56 return new Appender(implementationTarget, Appender.TerminationHandler.RETURNING);
57 }
58
59 /**
60 * {@inheritDoc}
61 */
62 public Implementation andThen(Implementation implementation) {
63 return new Compound(WithoutReturn.INSTANCE, implementation);
64 }
65
66 /**
67 * {@inheritDoc}
68 */
69 public Composable andThen(Composable implementation) {
70 return new Compound.Composable(WithoutReturn.INSTANCE, implementation);
71 }
72
73 /**
74 * A super method invocation where the return value is dropped instead of returning from the method.
75 */
76 protected enum WithoutReturn implements Implementation {
77
78 /**
79 * The singleton instance.
80 */
81 INSTANCE;
82
83 /**
84 * {@inheritDoc}
85 */
86 public InstrumentedType prepare(InstrumentedType instrumentedType) {
87 return instrumentedType;
88 }
89
90 /**
91 * {@inheritDoc}
92 */
93 public ByteCodeAppender appender(Target implementationTarget) {
94 return new Appender(implementationTarget, Appender.TerminationHandler.DROPPING);
95 }
96 }
97
98 /**
99 * An appender for implementing a {@link net.bytebuddy.implementation.SuperMethodCall}.
100 */
101 @HashCodeAndEqualsPlugin.Enhance
102 protected static class Appender implements ByteCodeAppender {
103
104 /**
105 * The target of the current implementation.
106 */
107 private final Target implementationTarget;
108
109 /**
110 * The termination handler to apply after invoking the super method.
111 */
112 private final TerminationHandler terminationHandler;
113
114 /**
115 * Creates a new appender.
116 *
117 * @param implementationTarget The implementation target of the current type creation.
118 * @param terminationHandler The termination handler to apply after invoking the super method.
119 */
120 protected Appender(Target implementationTarget, TerminationHandler terminationHandler) {
121 this.implementationTarget = implementationTarget;
122 this.terminationHandler = terminationHandler;
123 }
124
125 /**
126 * {@inheritDoc}
127 */
128 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
129 StackManipulation superMethodCall = implementationTarget
130 .invokeDominant(instrumentedMethod.asSignatureToken())
131 .withCheckedCompatibilityTo(instrumentedMethod.asTypeToken());
132 if (!superMethodCall.isValid()) {
133 throw new IllegalStateException("Cannot call super (or default) method for " + instrumentedMethod);
134 }
135 StackManipulation.Size size = new StackManipulation.Compound(
136 MethodVariableAccess.allArgumentsOf(instrumentedMethod).prependThisReference(),
137 superMethodCall,
138 terminationHandler.of(instrumentedMethod)
139 ).apply(methodVisitor, implementationContext);
140 return new Size(size.getMaximalSize(), instrumentedMethod.getStackSize());
141 }
142
143 /**
144 * A handler that determines how to handle the method return value.
145 */
146 protected enum TerminationHandler {
147
148 /**
149 * A termination handler that returns the value of the super method invocation.
150 */
151 RETURNING {
152 @Override
153 protected StackManipulation of(MethodDescription methodDescription) {
154 return MethodReturn.of(methodDescription.getReturnType());
155 }
156 },
157
158 /**
159 * A termination handler that simply pops the value of the super method invocation off the stack.
160 */
161 DROPPING {
162 @Override
163 protected StackManipulation of(MethodDescription methodDescription) {
164 return Removal.of(methodDescription.getReturnType());
165 }
166 };
167
168 /**
169 * Creates a stack manipulation that represents this handler's behavior.
170 *
171 * @param methodDescription The method for which this handler is supposed to create a stack
172 * manipulation for.
173 * @return The stack manipulation that implements this handler.
174 */
175 protected abstract StackManipulation of(MethodDescription methodDescription);
176 }
177 }
178 }
179