• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

raphw / byte-buddy / #732

29 Jan 2025 08:32PM UTC coverage: 85.163% (-0.04%) from 85.2%
#732

push

raphw
Fix modifiers.

29221 of 34312 relevant lines covered (85.16%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.84
/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/member/MethodInvocation.java
1
/*
2
 * Copyright 2014 - Present 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.bytecode.member;
17

18
import net.bytebuddy.ClassFileVersion;
19
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
20
import net.bytebuddy.description.method.MethodDescription;
21
import net.bytebuddy.description.type.TypeDescription;
22
import net.bytebuddy.description.type.TypeList;
23
import net.bytebuddy.implementation.Implementation;
24
import net.bytebuddy.implementation.bytecode.StackManipulation;
25
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
26
import net.bytebuddy.utility.JavaConstant;
27
import net.bytebuddy.utility.JavaType;
28
import org.objectweb.asm.MethodVisitor;
29
import org.objectweb.asm.Opcodes;
30

31
import java.util.List;
32

33
/**
34
 * A builder for a method invocation.
35
 */
36
public enum MethodInvocation {
1✔
37

38
    /**
39
     * A virtual method invocation.
40
     */
41
    VIRTUAL(Opcodes.INVOKEVIRTUAL, Opcodes.H_INVOKEVIRTUAL, Opcodes.INVOKEVIRTUAL, Opcodes.H_INVOKEVIRTUAL),
1✔
42

43
    /**
44
     * An interface-typed virtual method invocation.
45
     */
46
    INTERFACE(Opcodes.INVOKEINTERFACE, Opcodes.H_INVOKEINTERFACE, Opcodes.INVOKEINTERFACE, Opcodes.H_INVOKEINTERFACE),
1✔
47

48
    /**
49
     * A static method invocation.
50
     */
51
    STATIC(Opcodes.INVOKESTATIC, Opcodes.H_INVOKESTATIC, Opcodes.INVOKESTATIC, Opcodes.H_INVOKESTATIC),
1✔
52

53
    /**
54
     * A specialized pseudo-virtual method invocation for a non-constructor.
55
     */
56
    SPECIAL(Opcodes.INVOKESPECIAL, Opcodes.H_INVOKESPECIAL, Opcodes.INVOKESPECIAL, Opcodes.H_INVOKESPECIAL),
1✔
57

58
    /**
59
     * A specialized pseudo-virtual method invocation for a constructor.
60
     */
61
    SPECIAL_CONSTRUCTOR(Opcodes.INVOKESPECIAL, Opcodes.H_NEWINVOKESPECIAL, Opcodes.INVOKESPECIAL, Opcodes.H_NEWINVOKESPECIAL),
1✔
62

63
    /**
64
     * A private method call that is potentially virtual.
65
     */
66
    VIRTUAL_PRIVATE(Opcodes.INVOKEVIRTUAL, Opcodes.H_INVOKEVIRTUAL, Opcodes.INVOKESPECIAL, Opcodes.H_INVOKESPECIAL),
1✔
67

68
    /**
69
     * A private method call that is potentially virtual on an interface type.
70
     */
71
    INTERFACE_PRIVATE(Opcodes.INVOKEINTERFACE, Opcodes.H_INVOKEINTERFACE, Opcodes.INVOKESPECIAL, Opcodes.H_INVOKESPECIAL);
1✔
72

73
    /**
74
     * The opcode for invoking a method.
75
     */
76
    private final int opcode;
77

78
    /**
79
     * The handle being used for a dynamic method invocation.
80
     */
81
    private final int handle;
82

83
    /**
84
     * The opcode for invoking a method before Java 11.
85
     */
86
    private final int legacyOpcode;
87

88
    /**
89
     * The handle being used for a dynamic method invocation before Java 11.
90
     */
91
    private final int legacyHandle;
92

93
    /**
94
     * Creates a new type of method invocation.
95
     *
96
     * @param opcode       The opcode for invoking a method.
97
     * @param handle       The handle being used for a dynamic method invocation.
98
     * @param legacyOpcode The opcode for invoking a method before Java 11.
99
     * @param legacyHandle The handle being used for a dynamic method invocation before Java 11.
100
     */
101
    MethodInvocation(int opcode, int handle, int legacyOpcode, int legacyHandle) {
1✔
102
        this.opcode = opcode;
1✔
103
        this.handle = handle;
1✔
104
        this.legacyOpcode = legacyOpcode;
1✔
105
        this.legacyHandle = legacyHandle;
1✔
106
    }
1✔
107

108
    /**
109
     * Creates a method invocation with an implicitly determined invocation type.
110
     *
111
     * @param methodDescription The method to be invoked.
112
     * @return A stack manipulation with implicitly determined invocation type.
113
     */
114
    public static WithImplicitInvocationTargetType invoke(MethodDescription.InDefinedShape methodDescription) {
115
        if (methodDescription.isTypeInitializer()) {
1✔
116
            return IllegalInvocation.INSTANCE;
1✔
117
        } else if (methodDescription.isStatic()) { // Check this property first, private static methods must use INVOKESTATIC
1✔
118
            return STATIC.new Invocation(methodDescription);
1✔
119
        } else if (methodDescription.isConstructor()) {
1✔
120
            return SPECIAL_CONSTRUCTOR.new Invocation(methodDescription); // Check this property second, constructors might be private
1✔
121
        } else if (methodDescription.isPrivate()) {
1✔
122
            return (methodDescription.getDeclaringType().isInterface()
1✔
123
                    ? INTERFACE_PRIVATE
124
                    : VIRTUAL_PRIVATE).new Invocation(methodDescription);
125
        } else if (methodDescription.getDeclaringType().isInterface()) { // Check this property last, default methods must be called by INVOKESPECIAL
1✔
126
            return INTERFACE.new Invocation(methodDescription);
1✔
127
        } else {
128
            return VIRTUAL.new Invocation(methodDescription);
1✔
129
        }
130
    }
131

132
    /**
133
     * Creates a method invocation with an implicitly determined invocation type. If the method's return type derives from its declared shape, the value
134
     * is additionally casted to the value of the generically resolved method.
135
     *
136
     * @param methodDescription The method to be invoked.
137
     * @return A stack manipulation with implicitly determined invocation type.
138
     */
139
    public static WithImplicitInvocationTargetType invoke(MethodDescription methodDescription) {
140
        MethodDescription.InDefinedShape declaredMethod = methodDescription.asDefined();
1✔
141
        return declaredMethod.getReturnType().asErasure().equals(methodDescription.getReturnType().asErasure())
1✔
142
                ? invoke(declaredMethod)
1✔
143
                : OfGenericMethod.of(methodDescription, invoke(declaredMethod));
1✔
144
    }
145

146
    /**
147
     * Returns a method invocation of {@code java.lang.invoke.MethodHandles#lookup()}.
148
     *
149
     * @return A method invocation for resolving the current lookup.
150
     */
151
    public static StackManipulation lookup() {
152
        return invoke(new MethodDescription.Latent(JavaType.METHOD_HANDLES.getTypeStub(), new MethodDescription.Token("lookup",
1✔
153
                Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC,
154
                JavaType.METHOD_HANDLES_LOOKUP.getTypeStub().asGenericType())));
1✔
155
    }
156

157
    /**
158
     * An illegal implicit method invocation.
159
     */
160
    protected enum IllegalInvocation implements WithImplicitInvocationTargetType {
1✔
161

162
        /**
163
         * The singleton instance.
164
         */
165
        INSTANCE;
1✔
166

167
        /**
168
         * {@inheritDoc}
169
         */
170
        public StackManipulation virtual(TypeDescription invocationTarget) {
171
            return Illegal.INSTANCE;
1✔
172
        }
173

174
        /**
175
         * {@inheritDoc}
176
         */
177
        public StackManipulation special(TypeDescription invocationTarget) {
178
            return Illegal.INSTANCE;
1✔
179
        }
180

181
        /**
182
         * {@inheritDoc}
183
         */
184
        public StackManipulation dynamic(String methodName,
185
                                         TypeDescription returnType,
186
                                         List<? extends TypeDescription> methodType,
187
                                         List<? extends JavaConstant> arguments) {
188
            return Illegal.INSTANCE;
1✔
189
        }
190

191
        /**
192
         * {@inheritDoc}
193
         */
194
        public StackManipulation onHandle(HandleType type) {
195
            return Illegal.INSTANCE;
1✔
196
        }
197

198
        /**
199
         * {@inheritDoc}
200
         */
201
        public boolean isValid() {
202
            return false;
1✔
203
        }
204

205
        /**
206
         * {@inheritDoc}
207
         */
208
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
209
            return Illegal.INSTANCE.apply(methodVisitor, implementationContext);
×
210
        }
211
    }
212

213
    /**
214
     * Represents a method invocation where the invocation type (static, virtual, special, interface) is derived
215
     * from the given method's description.
216
     */
217
    public interface WithImplicitInvocationTargetType extends StackManipulation {
218

219
        /**
220
         * Transforms this method invocation into a virtual (or interface) method invocation on the given type.
221
         *
222
         * @param invocationTarget The type on which the method is to be invoked virtually on.
223
         * @return A stack manipulation representing this method invocation.
224
         */
225
        StackManipulation virtual(TypeDescription invocationTarget);
226

227
        /**
228
         * Transforms this method invocation into a special invocation on the given type.
229
         *
230
         * @param invocationTarget The type on which the method is to be invoked specially on.
231
         * @return A stack manipulation representing this method invocation.
232
         */
233
        StackManipulation special(TypeDescription invocationTarget);
234

235
        /**
236
         * Invokes the method as a bootstrap method to bind a call site with the given properties. Note that the
237
         * Java virtual machine currently only knows how to resolve bootstrap methods that link static methods
238
         * or a constructor.
239
         *
240
         * @param methodName The name of the method to be bound.
241
         * @param returnType The return type of the method to be bound.
242
         * @param methodType The parameter types of the method to be bound.
243
         * @param arguments  The arguments to be passed to the bootstrap method.
244
         * @return A stack manipulation that represents the dynamic method invocation.
245
         */
246
        StackManipulation dynamic(String methodName,
247
                                  TypeDescription returnType,
248
                                  List<? extends TypeDescription> methodType,
249
                                  List<? extends JavaConstant> arguments);
250

251
        /**
252
         * Invokes the method via a {@code MethodHandle}.
253
         *
254
         * @param type The type of invocation.
255
         * @return A stack manipulation that represents a method call of the specified method via a method handle.
256
         */
257
        StackManipulation onHandle(HandleType type);
258
    }
259

260
    /**
261
     * A method invocation of a generically resolved method.
262
     */
263
    @HashCodeAndEqualsPlugin.Enhance
264
    protected static class OfGenericMethod implements WithImplicitInvocationTargetType {
265

266
        /**
267
         * The generically resolved return type of the method.
268
         */
269
        private final TypeDescription targetType;
270

271
        /**
272
         * The invocation of the method in its defined shape.
273
         */
274
        private final WithImplicitInvocationTargetType invocation;
275

276
        /**
277
         * Creates a generic method invocation.
278
         *
279
         * @param targetType The generically resolved return type of the method.
280
         * @param invocation The invocation of the method in its defined shape.
281
         */
282
        protected OfGenericMethod(TypeDescription targetType, WithImplicitInvocationTargetType invocation) {
1✔
283
            this.targetType = targetType;
1✔
284
            this.invocation = invocation;
1✔
285
        }
1✔
286

287
        /**
288
         * Creates a generic access dispatcher for a given method.
289
         *
290
         * @param methodDescription The generically resolved return type of the method.
291
         * @param invocation        The invocation of the method in its defined shape.
292
         * @return A method access dispatcher for the given method.
293
         */
294
        protected static WithImplicitInvocationTargetType of(MethodDescription methodDescription, WithImplicitInvocationTargetType invocation) {
295
            return new OfGenericMethod(methodDescription.getReturnType().asErasure(), invocation);
1✔
296
        }
297

298
        /**
299
         * {@inheritDoc}
300
         */
301
        public StackManipulation virtual(TypeDescription invocationTarget) {
302
            return new StackManipulation.Compound(invocation.virtual(invocationTarget), TypeCasting.to(targetType));
1✔
303
        }
304

305
        /**
306
         * {@inheritDoc}
307
         */
308
        public StackManipulation special(TypeDescription invocationTarget) {
309
            return new StackManipulation.Compound(invocation.special(invocationTarget), TypeCasting.to(targetType));
1✔
310
        }
311

312
        /**
313
         * {@inheritDoc}
314
         */
315
        public StackManipulation dynamic(String methodName, TypeDescription returnType, List<? extends TypeDescription> methodType, List<? extends JavaConstant> arguments) {
316
            return invocation.dynamic(methodName, returnType, methodType, arguments);
1✔
317
        }
318

319
        /**
320
         * {@inheritDoc}
321
         */
322
        public StackManipulation onHandle(HandleType type) {
323
            return new Compound(invocation.onHandle(type), TypeCasting.to(targetType));
×
324
        }
325

326
        /**
327
         * {@inheritDoc}
328
         */
329
        public boolean isValid() {
330
            return invocation.isValid();
1✔
331
        }
332

333
        /**
334
         * {@inheritDoc}
335
         */
336
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
337
            return new Compound(invocation, TypeCasting.to(targetType)).apply(methodVisitor, implementationContext);
×
338
        }
339
    }
340

341
    /**
342
     * An implementation of a method invoking stack manipulation.
343
     */
344
    @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
345
    protected class Invocation extends StackManipulation.AbstractBase implements WithImplicitInvocationTargetType {
346

347
        /**
348
         * The method to be invoked.
349
         */
350
        private final TypeDescription typeDescription;
351

352
        /**
353
         * The type on which this method is to be invoked.
354
         */
355
        private final MethodDescription.InDefinedShape methodDescription;
356

357
        /**
358
         * Creates an invocation of a given method on its declaring type as an invocation target.
359
         *
360
         * @param methodDescription The method to be invoked.
361
         */
362
        protected Invocation(MethodDescription.InDefinedShape methodDescription) {
363
            this(methodDescription, methodDescription.getDeclaringType());
1✔
364
        }
1✔
365

366
        /**
367
         * Creates an invocation of a given method on a given invocation target type.
368
         *
369
         * @param methodDescription The method to be invoked.
370
         * @param typeDescription   The type on which this method is to be invoked.
371
         */
372
        protected Invocation(MethodDescription.InDefinedShape methodDescription, TypeDescription typeDescription) {
1✔
373
            this.typeDescription = typeDescription;
1✔
374
            this.methodDescription = methodDescription;
1✔
375
        }
1✔
376

377
        /**
378
         * {@inheritDoc}
379
         */
380
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
381
            methodVisitor.visitMethodInsn(opcode == legacyOpcode || implementationContext.getClassFileVersion().isAtLeast(ClassFileVersion.JAVA_V11)
1✔
382
                            ? opcode
1✔
383
                            : legacyOpcode,
1✔
384
                    typeDescription.getInternalName(),
1✔
385
                    methodDescription.getInternalName(),
1✔
386
                    methodDescription.getDescriptor(),
1✔
387
                    typeDescription.isInterface());
1✔
388
            int parameterSize = methodDescription.getStackSize(), returnValueSize = methodDescription.getReturnType().getStackSize().getSize();
1✔
389
            return new Size(returnValueSize - parameterSize, Math.max(0, returnValueSize - parameterSize));
1✔
390
        }
391

392
        /**
393
         * {@inheritDoc}
394
         */
395
        public StackManipulation virtual(TypeDescription invocationTarget) {
396
            if (methodDescription.isConstructor() || methodDescription.isStatic()) {
1✔
397
                return Illegal.INSTANCE;
1✔
398
            } else if (methodDescription.isPrivate()) {
1✔
399
                return methodDescription.getDeclaringType().equals(invocationTarget)
1✔
400
                        ? this
401
                        : Illegal.INSTANCE;
402
            } else if (invocationTarget.isInterface()) {
1✔
403
                return methodDescription.getDeclaringType().represents(Object.class)
1✔
404
                        ? this
405
                        : INTERFACE.new Invocation(methodDescription, invocationTarget);
406
            } else {
407
                return VIRTUAL.new Invocation(methodDescription, invocationTarget);
1✔
408
            }
409
        }
410

411
        /**
412
         * {@inheritDoc}
413
         */
414
        public StackManipulation special(TypeDescription invocationTarget) {
415
            return methodDescription.isSpecializableFor(invocationTarget)
1✔
416
                    ? SPECIAL.new Invocation(methodDescription, invocationTarget)
417
                    : Illegal.INSTANCE;
418
        }
419

420
        /**
421
         * {@inheritDoc}
422
         */
423
        public StackManipulation dynamic(String name,
424
                                         TypeDescription returnType,
425
                                         List<? extends TypeDescription> methodType,
426
                                         List<? extends JavaConstant> arguments) {
427
            return methodDescription.isInvokeBootstrap(TypeList.Explicit.of(arguments)) ? new Invokedynamic(name,
1✔
428
                    JavaConstant.MethodType.of(returnType, methodType),
1✔
429
                    JavaConstant.MethodHandle.of(methodDescription),
1✔
430
                    arguments) : Illegal.INSTANCE;
431
        }
432

433
        /**
434
         * {@inheritDoc}
435
         */
436
        public StackManipulation onHandle(HandleType type) {
437
            return new HandleInvocation(methodDescription, type);
1✔
438
        }
439
    }
440

441

442
    /**
443
     * Performs a method invocation on a method handle with a polymorphic type signature.
444
     */
445
    @HashCodeAndEqualsPlugin.Enhance
446
    protected static class HandleInvocation extends StackManipulation.AbstractBase {
447

448
        /**
449
         * The internal name of the method handle type.
450
         */
451
        private static final String METHOD_HANDLE = "java/lang/invoke/MethodHandle";
452

453
        /**
454
         * The invoked method.
455
         */
456
        private final MethodDescription.InDefinedShape methodDescription;
457

458
        /**
459
         * The type of method handle invocation.
460
         */
461
        private final HandleType type;
462

463
        /**
464
         * Creates a new method handle invocation.
465
         *
466
         * @param methodDescription The invoked method.
467
         * @param type              The type of method handle invocation.
468
         */
469
        protected HandleInvocation(MethodDescription.InDefinedShape methodDescription, HandleType type) {
1✔
470
            this.methodDescription = methodDescription;
1✔
471
            this.type = type;
1✔
472
        }
1✔
473

474
        /**
475
         * {@inheritDoc}
476
         */
477
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
478
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
479
                    METHOD_HANDLE,
480
                    type.getMethodName(),
1✔
481
                    methodDescription.isStatic() || methodDescription.isConstructor()
1✔
482
                            ? methodDescription.getDescriptor()
1✔
483
                            : "(" + methodDescription.getDeclaringType().getDescriptor() + methodDescription.getDescriptor().substring(1),
1✔
484
                    false);
485
            int parameterSize = 1 + methodDescription.getStackSize(), returnValueSize = methodDescription.getReturnType().getStackSize().getSize();
1✔
486
            return new Size(returnValueSize - parameterSize, Math.max(0, returnValueSize - parameterSize));
1✔
487
        }
488
    }
489

490
    /**
491
     * The type of method handle invocation.
492
     */
493
    public enum HandleType {
1✔
494

495
        /**
496
         * An exact invocation without type adjustments.
497
         */
498
        EXACT("invokeExact"),
1✔
499

500
        /**
501
         * A regular invocation with standard type adjustments.
502
         */
503
        REGULAR("invoke");
1✔
504

505
        /**
506
         * The name of the invoked method.
507
         */
508
        private final String methodName;
509

510
        /**
511
         * Creates a new handle type.
512
         *
513
         * @param methodName The name of the invoked method.
514
         */
515
        HandleType(String methodName) {
1✔
516
            this.methodName = methodName;
1✔
517
        }
1✔
518

519
        /**
520
         * Returns the name of the represented method.
521
         *
522
         * @return The name of the invoked method.
523
         */
524
        protected String getMethodName() {
525
            return methodName;
1✔
526
        }
527
    }
528
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc