├── .github ├── ISSUE_TEMPLATE │ ├── 000-2.x-issue.yml │ ├── 001-1.x-issue.yml │ └── config.yml ├── dependabot.yml ├── project.yml └── workflows │ ├── build.yml │ ├── pre-release.yml │ ├── release-perform.yml │ └── release-prepare.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── build-release-17 ├── build-test-java17 ├── build-test-java21 ├── pom.xml └── src ├── main └── java │ ├── io │ └── quarkus │ │ └── gizmo2 │ │ ├── Assignable.java │ │ ├── ClassOutput.java │ │ ├── ClassVersion.java │ │ ├── Const.java │ │ ├── Expr.java │ │ ├── FieldVar.java │ │ ├── GenericType.java │ │ ├── GenericTyped.java │ │ ├── Gizmo.java │ │ ├── InstanceFieldVar.java │ │ ├── InvokeKind.java │ │ ├── LocalVar.java │ │ ├── MemoryOrder.java │ │ ├── MethodTyped.java │ │ ├── ModifierConfigurator.java │ │ ├── ParamVar.java │ │ ├── Reflection2Gizmo.java │ │ ├── SimpleTyped.java │ │ ├── StaticFieldVar.java │ │ ├── This.java │ │ ├── TypeArgument.java │ │ ├── TypeKind.java │ │ ├── TypeParameter.java │ │ ├── Typed.java │ │ ├── Var.java │ │ ├── creator │ │ ├── AbstractMethodCreator.java │ │ ├── AccessLevel.java │ │ ├── AnnotatableCreator.java │ │ ├── AnnotationCreator.java │ │ ├── AnonymousClassCreator.java │ │ ├── BlockCreator.java │ │ ├── BodyCreator.java │ │ ├── CapturingCreator.java │ │ ├── CaseCreator.java │ │ ├── ClassCreator.java │ │ ├── ConstructorCreator.java │ │ ├── ExecutableCreator.java │ │ ├── FieldCreator.java │ │ ├── InstanceBodyCreator.java │ │ ├── InstanceExecutableCreator.java │ │ ├── InstanceFieldCreator.java │ │ ├── InstanceMethodCreator.java │ │ ├── InterfaceCreator.java │ │ ├── LambdaCreator.java │ │ ├── MemberCreator.java │ │ ├── MethodCreator.java │ │ ├── ModifiableCreator.java │ │ ├── Modifier.java │ │ ├── ModifierFlag.java │ │ ├── ModifierLocation.java │ │ ├── ParamCreator.java │ │ ├── StaticExecutableCreator.java │ │ ├── StaticFieldCreator.java │ │ ├── StaticMethodCreator.java │ │ ├── SwitchCreator.java │ │ ├── TryCreator.java │ │ ├── TypeCreator.java │ │ ├── TypeParameterCreator.java │ │ ├── TypeParameterizedCreator.java │ │ └── ops │ │ │ ├── ClassOps.java │ │ │ ├── CollectionOps.java │ │ │ ├── ComparableOps.java │ │ │ ├── IteratorOps.java │ │ │ ├── ListOps.java │ │ │ ├── MapOps.java │ │ │ ├── ObjectOps.java │ │ │ ├── OptionalOps.java │ │ │ ├── SetOps.java │ │ │ ├── StringBuilderOps.java │ │ │ ├── StringOps.java │ │ │ └── ThrowableOps.java │ │ ├── desc │ │ ├── ClassMethodDesc.java │ │ ├── ConstructorDesc.java │ │ ├── FieldDesc.java │ │ ├── InterfaceMethodDesc.java │ │ ├── MemberDesc.java │ │ └── MethodDesc.java │ │ └── impl │ │ ├── AbstractMethodCreatorImpl.java │ │ ├── AnnotatableCreatorImpl.java │ │ ├── AnnotationCreatorImpl.java │ │ ├── AnonymousClassCreatorImpl.java │ │ ├── ArrayDeref.java │ │ ├── ArrayLength.java │ │ ├── ArrayLoadViaHandle.java │ │ ├── ArrayStore.java │ │ ├── ArrayStoreViaHandle.java │ │ ├── AssignableImpl.java │ │ ├── BinOp.java │ │ ├── BlockCreatorImpl.java │ │ ├── BlockExpr.java │ │ ├── BlockHeader.java │ │ ├── BootstrappedMethodHandleImpl.java │ │ ├── BoundItem.java │ │ ├── Box.java │ │ ├── Break.java │ │ ├── Cast.java │ │ ├── CheckCast.java │ │ ├── ClassCreatorImpl.java │ │ ├── ClassMethodDescImpl.java │ │ ├── ClassStaticFieldCreatorImpl.java │ │ ├── ClassSwitchCreatorImpl.java │ │ ├── Cmp.java │ │ ├── ConstructorCreatorImpl.java │ │ ├── ConstructorDescImpl.java │ │ ├── Conversions.java │ │ ├── DefaultMethodCreatorImpl.java │ │ ├── Dup.java │ │ ├── EnumOrdinalSwitchCreatorImpl.java │ │ ├── EnumSwitchCreatorImpl.java │ │ ├── EqualsHashCodeToStringGenerator.java │ │ ├── ExecutableCreatorImpl.java │ │ ├── FieldCreatorImpl.java │ │ ├── FieldDeref.java │ │ ├── FieldDescImpl.java │ │ ├── FieldGetViaHandle.java │ │ ├── FieldSet.java │ │ ├── FieldSetViaHandle.java │ │ ├── GizmoImpl.java │ │ ├── Goto.java │ │ ├── GotoCase.java │ │ ├── GotoDefault.java │ │ ├── GotoStart.java │ │ ├── HashSwitchCreatorImpl.java │ │ ├── If.java │ │ ├── IfRel.java │ │ ├── IfZero.java │ │ ├── InstanceFieldCreatorImpl.java │ │ ├── InstanceMethodCreatorImpl.java │ │ ├── InstanceOf.java │ │ ├── IntSwitchCreatorImpl.java │ │ ├── InterfaceCreatorImpl.java │ │ ├── InterfaceMethodCreatorImpl.java │ │ ├── InterfaceMethodDescImpl.java │ │ ├── InterfaceStaticFieldCreatorImpl.java │ │ ├── Invoke.java │ │ ├── InvokeDynamic.java │ │ ├── Item.java │ │ ├── LambdaCreatorImpl.java │ │ ├── LineNumber.java │ │ ├── LocalVarAllocator.java │ │ ├── LocalVarDecrement.java │ │ ├── LocalVarImpl.java │ │ ├── LocalVarIncrement.java │ │ ├── LocalVarSet.java │ │ ├── LongSwitchCreatorImpl.java │ │ ├── MethodCreatorImpl.java │ │ ├── MethodDescImpl.java │ │ ├── ModifiableCreatorImpl.java │ │ ├── MonitorEnter.java │ │ ├── MonitorExit.java │ │ ├── NativeMethodCreatorImpl.java │ │ ├── Neg.java │ │ ├── New.java │ │ ├── NewArrayResult.java │ │ ├── NewEmptyArray.java │ │ ├── NewResult.java │ │ ├── Node.java │ │ ├── ParamCreatorImpl.java │ │ ├── ParamSet.java │ │ ├── ParamVarImpl.java │ │ ├── PerfectHashSwitchCreatorImpl.java │ │ ├── Pop.java │ │ ├── Preconditions.java │ │ ├── PrimitiveCast.java │ │ ├── PrivateInterfaceMethodCreatorImpl.java │ │ ├── Rel.java │ │ ├── RelZero.java │ │ ├── Return.java │ │ ├── StaticFieldCreatorImpl.java │ │ ├── StaticFieldGetViaHandle.java │ │ ├── StaticFieldSet.java │ │ ├── StaticFieldSetViaHandle.java │ │ ├── StaticFieldVarImpl.java │ │ ├── StaticInterfaceMethodCreatorImpl.java │ │ ├── StaticMethodCreatorImpl.java │ │ ├── StringSwitchCreatorImpl.java │ │ ├── SwitchCreatorImpl.java │ │ ├── ThisExpr.java │ │ ├── Throw.java │ │ ├── TryCatch.java │ │ ├── TryCreatorImpl.java │ │ ├── TryFinally.java │ │ ├── TypeAnnotatableCreatorImpl.java │ │ ├── TypeCreatorImpl.java │ │ ├── TypeParameterCreatorImpl.java │ │ ├── Unbox.java │ │ ├── UncheckedCast.java │ │ ├── Util.java │ │ ├── WidenPrimitive.java │ │ ├── Yield.java │ │ └── constant │ │ ├── ArrayVarHandleConst.java │ │ ├── BooleanConst.java │ │ ├── ByteConst.java │ │ ├── CharConst.java │ │ ├── ClassConst.java │ │ ├── ConstImpl.java │ │ ├── DoubleConst.java │ │ ├── DynamicConst.java │ │ ├── EnumConst.java │ │ ├── FieldVarHandleConst.java │ │ ├── FloatConst.java │ │ ├── IntBasedConst.java │ │ ├── IntConst.java │ │ ├── InvokeConst.java │ │ ├── LongConst.java │ │ ├── MethodHandleConst.java │ │ ├── MethodTypeConst.java │ │ ├── NullConst.java │ │ ├── ShortConst.java │ │ ├── StaticFieldVarHandleConst.java │ │ ├── StaticFinalFieldConst.java │ │ ├── StringConst.java │ │ ├── VarHandleConst.java │ │ └── VoidConst.java │ └── module-info.java └── test └── java └── io └── quarkus └── gizmo2 ├── AccessFlagsTest.java ├── AnnotationTest.java ├── AnonClassTest.java ├── ArithmeticTest.java ├── ArraysTest.java ├── AtomicsTest.java ├── AutoConversionTest.java ├── BasicTest.java ├── BoxUnboxTest.java ├── CastTest.java ├── CollectionConstantsTest.java ├── ComparisonsTest.java ├── ConditionalsTest.java ├── ConstantsTest.java ├── EqualsHashCodeToStringTest.java ├── FieldAccessTest.java ├── GenericTypeTest.java ├── InstanceExecutableCreatorTest.java ├── InvocationTest.java ├── LambdaTest.java ├── LocalVarTest.java ├── LockingTest.java ├── LoopTest.java ├── MethodThrowsTest.java ├── NewArrayTest.java ├── NewTest.java ├── SwitchTest.java ├── TestClassMaker.java ├── TryTest.java └── ops ├── ListOpsTest.java ├── MapOpsTest.java ├── OptionalOpsTest.java ├── StringBuilderOpsTest.java └── ThrowableOpsTest.java /.github/ISSUE_TEMPLATE/000-2.x-issue.yml: -------------------------------------------------------------------------------- 1 | name: Gizmo 2.x Issue 2 | description: An issue which applies to a 2.x version of Gizmo. 3 | labels: ["2.x"] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: "Issue description" 8 | description: "Please describe the issue below." 9 | value: "" 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/001-1.x-issue.yml: -------------------------------------------------------------------------------- 1 | name: Gizmo 1.x Issue 2 | description: An issue which applies to a 1.x version of Gizmo. 3 | labels: ["1.x"] 4 | title: "[1.x] " 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: "Issue description" 9 | description: "Please describe the issue below." 10 | value: "" 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: maven 5 | directory: "/" 6 | schedule: 7 | interval: daily 8 | time: "21:00" 9 | timezone: Europe/Paris 10 | open-pull-requests-limit: 5 11 | labels: ['dependencies', '2.x'] 12 | - package-ecosystem: maven 13 | target-branch: "1.x" 14 | directory: "/" 15 | schedule: 16 | interval: daily 17 | time: "23:00" 18 | timezone: Europe/Paris 19 | open-pull-requests-limit: 5 20 | labels: ['dependencies', '1.x'] 21 | -------------------------------------------------------------------------------- /.github/project.yml: -------------------------------------------------------------------------------- 1 | release: 2 | current-version: "2.0.0.Alpha3" 3 | next-version: "2.0.0-SNAPSHOT" 4 | 5 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Gizmo 2 CI 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - 'dependabot/**' 7 | paths-ignore: 8 | - '.github/project.yml' 9 | pull_request: 10 | 11 | jobs: 12 | build: 13 | name: "Build with JDK ${{ matrix.java }}" 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | 20 | - name: Set up JDKs 21 | uses: actions/setup-java@v4 22 | with: 23 | distribution: temurin 24 | java-version: | 25 | 17 26 | 21 27 | 24 28 | cache: maven 29 | 30 | - name: Build with Maven 31 | run: mvn -B clean package -Dno-format -Djava17.home="${{env.JAVA_HOME_17_X64}}${{env.JAVA_HOME_17_ARM64}}" -Djava21.home="${{env.JAVA_HOME_21_X64}}${{env.JAVA_HOME_21_ARM64}}" 32 | -------------------------------------------------------------------------------- /.github/workflows/pre-release.yml: -------------------------------------------------------------------------------- 1 | name: Quarkus Pre Release 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '.github/project.yml' 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | pre-release: 14 | name: Pre-Release 15 | uses: quarkusio/.github/.github/workflows/pre-release.yml@main 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /.github/workflows/release-perform.yml: -------------------------------------------------------------------------------- 1 | name: Quarkus Perform Release 2 | run-name: Perform ${{github.event.inputs.tag || github.ref_name}} Release 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | workflow_dispatch: 8 | inputs: 9 | tag: 10 | description: 'Tag to release' 11 | required: true 12 | 13 | permissions: 14 | attestations: write 15 | id-token: write 16 | contents: read 17 | 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | perform-release: 24 | name: Perform Release 25 | uses: quarkusio/.github/.github/workflows/perform-release.yml@main 26 | secrets: inherit 27 | with: 28 | version: ${{github.event.inputs.tag || github.ref_name}} 29 | -------------------------------------------------------------------------------- /.github/workflows/release-prepare.yml: -------------------------------------------------------------------------------- 1 | name: Quarkus Prepare Release 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | types: [ closed ] 7 | paths: 8 | - '.github/project.yml' 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | prepare-release: 16 | name: Prepare Release 17 | if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true}} 18 | uses: quarkusio/.github/.github/workflows/prepare-release.yml@main 19 | secrets: inherit 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | .cache 6 | 7 | ### IntelliJ IDEA ### 8 | .idea 9 | *.iws 10 | *.iml 11 | *.ipr 12 | 13 | ### Eclipse ### 14 | .apt_generated 15 | .classpath 16 | .factorypath 17 | .project 18 | .settings 19 | .springBeans 20 | .sts4-cache 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | 35 | ### Mac OS ### 36 | .DS_Store 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gizmo 2 | 3 | A bytecode generation library. 4 | 5 | [![Version](https://img.shields.io/maven-central/v/io.quarkus.gizmo/gizmo?logo=apache-maven&style=for-the-badge)](https://search.maven.org/artifact/io.quarkus.gizmo/gizmo) 6 | [![GitHub Actions Status]()](https://github.com/quarkusio/gizmo/actions?query=workflow%3A%22Gizmo+2+CI%22) 7 | 8 | ## About 9 | 10 | Gizmo aims at simplifying bytecode generation. 11 | It is heavily used by [Quarkus](https://quarkus.io). 12 | 13 | ## Build 14 | 15 | Gizmo is available on Maven Central but you can build it locally: 16 | 17 | ```bash 18 | mvn clean install 19 | ``` 20 | 21 | ## Release 22 | 23 | To release a new version of Gizmo, follow these steps: 24 | 25 | https://github.com/smallrye/smallrye/wiki/Release-Process#releasing 26 | 27 | The staging repository is automatically closed. The sync with Maven Central should take ~30 minutes. 28 | -------------------------------------------------------------------------------- /build-release-17: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quarkusio/gizmo/19221335879733e97606e70dd17575c813bbf121/build-release-17 -------------------------------------------------------------------------------- /build-test-java17: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quarkusio/gizmo/19221335879733e97606e70dd17575c813bbf121/build-test-java17 -------------------------------------------------------------------------------- /build-test-java21: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quarkusio/gizmo/19221335879733e97606e70dd17575c813bbf121/build-test-java21 -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/Assignable.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import io.quarkus.gizmo2.impl.AssignableImpl; 4 | 5 | /** 6 | * An expression that can be the target of an assignment. 7 | */ 8 | public sealed interface Assignable extends Expr permits Var, AssignableImpl { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/ClassOutput.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import java.io.IOException; 4 | import java.lang.constant.ClassDesc; 5 | import java.nio.file.Files; 6 | import java.nio.file.Path; 7 | 8 | import io.quarkus.gizmo2.impl.Util; 9 | import io.smallrye.common.constraint.Assert; 10 | 11 | /** 12 | * A container for created classes with a specific output strategy. 13 | */ 14 | @FunctionalInterface 15 | public interface ClassOutput { 16 | /** 17 | * Accept and write the class bytes. 18 | * 19 | * @param desc the class descriptor (not {@code null}) 20 | * @param bytes the class file bytes (not {@code null}) 21 | */ 22 | default void write(ClassDesc desc, byte[] bytes) { 23 | if (!desc.isClassOrInterface()) { 24 | throw new IllegalArgumentException("Can only write classes/interfaces"); 25 | } 26 | write(Util.internalName(desc) + ".class", bytes); 27 | } 28 | 29 | /** 30 | * Write a resource to the output. 31 | * 32 | * @param path the resource relative path (not {@code null}) 33 | * @param bytes the resource bytes (not {@code null}) 34 | */ 35 | void write(String path, byte[] bytes); 36 | 37 | /** 38 | * {@return a class output that write the class bytes to this output as well as the given one} 39 | * 40 | * @param next the other class output to write to (must not be {@code null}) 41 | */ 42 | default ClassOutput andThen(ClassOutput next) { 43 | Assert.checkNotNullParam("next", next); 44 | return (desc, bytes) -> { 45 | write(desc, bytes); 46 | next.write(desc, bytes); 47 | }; 48 | } 49 | 50 | /** 51 | * {@return a class output for the given path} 52 | * 53 | * @param basePath the path into which class files should be stored (must not be {@code null}) 54 | */ 55 | static ClassOutput fileWriter(Path basePath) { 56 | Assert.checkNotNullParam("basePath", basePath); 57 | if (!Files.isDirectory(basePath)) { 58 | throw new IllegalArgumentException("Path does not exist or is not an accessible directory: %s".formatted(basePath)); 59 | } 60 | return (name, bytes) -> { 61 | try { 62 | Path path = basePath.resolve(name); 63 | Files.createDirectories(path.getParent()); 64 | Files.write(path, bytes); 65 | } catch (IOException e) { 66 | throw new IllegalArgumentException("Failed to write class %s".formatted(name), e); 67 | } 68 | }; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/ClassVersion.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | /** 4 | * The interesting class file versions that one might want to generate. 5 | * Does not represent all possible class file versions, just 6 | * because that's not necessary. 7 | */ 8 | public enum ClassVersion { 9 | /** 10 | * The class file version of Java 17. 11 | */ 12 | V17, 13 | /** 14 | * The class file version of Java 21. 15 | */ 16 | V21, 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/FieldVar.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.quarkus.gizmo2.desc.FieldDesc; 6 | 7 | /** 8 | * A variable corresponding to a field. 9 | */ 10 | public sealed interface FieldVar extends Var permits InstanceFieldVar, StaticFieldVar { 11 | default ClassDesc type() { 12 | return desc().type(); 13 | } 14 | 15 | default String name() { 16 | return desc().name(); 17 | } 18 | 19 | /** 20 | * {@return the descriptor of the class which contains the field} 21 | */ 22 | default ClassDesc owner() { 23 | return desc().owner(); 24 | } 25 | 26 | /** 27 | * {@return the descriptor of the field} 28 | */ 29 | FieldDesc desc(); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/GenericTyped.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import io.quarkus.gizmo2.creator.FieldCreator; 4 | import io.quarkus.gizmo2.creator.ParamCreator; 5 | import io.quarkus.gizmo2.creator.TypeCreator; 6 | 7 | /** 8 | * A thing which has a generic type. 9 | */ 10 | public sealed interface GenericTyped extends SimpleTyped permits TypeParameter, FieldCreator, ParamCreator, TypeCreator { 11 | /** 12 | * {@return the generic type of this entity (not {@code null})} 13 | */ 14 | GenericType genericType(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/InstanceFieldVar.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import io.quarkus.gizmo2.impl.FieldDeref; 4 | 5 | /** 6 | * An instance field variable. 7 | */ 8 | public sealed interface InstanceFieldVar extends FieldVar permits FieldDeref { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/InvokeKind.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * The kind of invocation. 7 | */ 8 | public enum InvokeKind { 9 | /** 10 | * A virtual invocation. 11 | */ 12 | VIRTUAL, 13 | /** 14 | * An interface invocation. 15 | */ 16 | INTERFACE, 17 | /** 18 | * A so-called "special" invocation. 19 | */ 20 | SPECIAL, 21 | /** 22 | * A static invocation. 23 | */ 24 | STATIC, 25 | ; 26 | 27 | /** 28 | * An immutable list of all values of this type. 29 | */ 30 | public static final List values = List.of(values()); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/LocalVar.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import io.quarkus.gizmo2.creator.BlockCreator; 4 | import io.quarkus.gizmo2.impl.LocalVarImpl; 5 | 6 | /** 7 | * A local variable. 8 | */ 9 | public sealed interface LocalVar extends Var permits LocalVarImpl { 10 | /** 11 | * {@return the block that owns this local variable} 12 | */ 13 | BlockCreator block(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/MemoryOrder.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | /** 4 | * The possible memory order modes. 5 | */ 6 | public enum MemoryOrder { 7 | /** 8 | * Use the declared mode of the variable. 9 | * For fields, this could be {@link #Plain} or {@link #Volatile}. 10 | * For all other types, this is {@link #Plain}. 11 | */ 12 | AsDeclared(true, true), 13 | /** 14 | * Access using "plain" semantics. 15 | * All assignables support this type of access. 16 | */ 17 | Plain(true, true), 18 | /** 19 | * Access using "opaque" semantics. 20 | */ 21 | Opaque(true, true), 22 | /** 23 | * Access using "acquire" semantics. 24 | */ 25 | Acquire(true, false), 26 | /** 27 | * Access using "release" semantics. 28 | */ 29 | Release(false, true), 30 | /** 31 | * Access using "volatile" semantics. 32 | */ 33 | Volatile(true, true), 34 | ; 35 | 36 | private final boolean reads, writes; 37 | 38 | MemoryOrder(final boolean reads, final boolean writes) { 39 | this.reads = reads; 40 | this.writes = writes; 41 | } 42 | 43 | /** 44 | * {@return true if this mode may be used for read operations, or false if it cannot} 45 | */ 46 | public boolean validForReads() { 47 | return reads; 48 | } 49 | 50 | /** 51 | * {@return true if this mode may be used for write operations, or false if it cannot} 52 | */ 53 | public boolean validForWrites() { 54 | return writes; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/ModifierConfigurator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import java.util.List; 4 | 5 | import io.quarkus.gizmo2.creator.AccessLevel; 6 | import io.quarkus.gizmo2.creator.ModifierFlag; 7 | import io.quarkus.gizmo2.creator.ModifierLocation; 8 | 9 | /** 10 | * A configurator for default modifiers. 11 | */ 12 | public interface ModifierConfigurator { 13 | void remove(ModifierLocation location, ModifierFlag modifierFlag); 14 | 15 | default void remove(ModifierLocation location, ModifierFlag... modifierFlags) { 16 | remove(location, List.of(modifierFlags)); 17 | } 18 | 19 | default void remove(ModifierLocation location, List modifierFlags) { 20 | modifierFlags.forEach(flag -> remove(location, flag)); 21 | } 22 | 23 | void add(ModifierLocation location, ModifierFlag modifierFlag); 24 | 25 | default void add(ModifierLocation location, ModifierFlag... modifierFlags) { 26 | add(location, List.of(modifierFlags)); 27 | } 28 | 29 | default void add(ModifierLocation location, List modifierFlags) { 30 | modifierFlags.forEach(flag -> add(location, flag)); 31 | } 32 | 33 | void set(ModifierLocation location, AccessLevel accessLevel); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/ParamVar.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import io.quarkus.gizmo2.impl.ParamVarImpl; 4 | 5 | /** 6 | * A variable representing a method call parameter. 7 | */ 8 | public sealed interface ParamVar extends Var permits ParamVarImpl { 9 | /** 10 | * {@return the parameter index, counting from zero} 11 | * The index does not include any "{@code this}" variable. 12 | * The index only increments once per parameter, even 13 | * if the parameter type is {@code long} or {@code double}. 14 | */ 15 | int index(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/SimpleTyped.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.quarkus.gizmo2.creator.BlockCreator; 6 | import io.quarkus.gizmo2.creator.ClassCreator; 7 | import io.quarkus.gizmo2.creator.SwitchCreator; 8 | import io.quarkus.gizmo2.desc.FieldDesc; 9 | 10 | /** 11 | * A typed thing whose type is a simple type. 12 | */ 13 | public sealed interface SimpleTyped extends Typed 14 | permits Expr, GenericTyped, BlockCreator, ClassCreator, SwitchCreator, FieldDesc { 15 | /** 16 | * {@return the type of this entity (not {@code null})} 17 | */ 18 | ClassDesc type(); 19 | 20 | /** 21 | * {@return the type kind of this entity (not {@code null})} 22 | */ 23 | default TypeKind typeKind() { 24 | return TypeKind.from(type()); 25 | } 26 | 27 | /** 28 | * {@return the number of slots occupied by this entity} 29 | */ 30 | default int slotSize() { 31 | return typeKind().slotSize(); 32 | } 33 | 34 | /** 35 | * {@return {@code true} if this entity has {@code void} type, or {@code false} otherwise} 36 | */ 37 | default boolean isVoid() { 38 | return typeKind() == TypeKind.VOID; 39 | } 40 | 41 | /** 42 | * {@return {@code true} if this entity has a primitive type, or {@code false} if it does not} 43 | */ 44 | default boolean isPrimitive() { 45 | return type().isPrimitive(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/StaticFieldVar.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import io.quarkus.gizmo2.impl.StaticFieldVarImpl; 4 | 5 | /** 6 | * A variable corresponding to a static field. 7 | */ 8 | public sealed interface StaticFieldVar extends FieldVar permits StaticFieldVarImpl { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/This.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import io.quarkus.gizmo2.impl.ThisExpr; 4 | 5 | /** 6 | * The special expression for {@code this}, which is only valid from instance methods and constructors. 7 | */ 8 | public sealed interface This extends Expr permits ThisExpr { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/TypeKind.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.invoke.TypeDescriptor; 5 | 6 | /** 7 | * The kind of a type, which can be one of the primitive types, a reference type, or {@code void}. 8 | */ 9 | public enum TypeKind { 10 | BOOLEAN(io.github.dmlloyd.classfile.TypeKind.BOOLEAN), 11 | BYTE(io.github.dmlloyd.classfile.TypeKind.BYTE), 12 | CHAR(io.github.dmlloyd.classfile.TypeKind.CHAR), 13 | SHORT(io.github.dmlloyd.classfile.TypeKind.SHORT), 14 | INT(io.github.dmlloyd.classfile.TypeKind.INT), 15 | LONG(io.github.dmlloyd.classfile.TypeKind.LONG), 16 | FLOAT(io.github.dmlloyd.classfile.TypeKind.FLOAT), 17 | DOUBLE(io.github.dmlloyd.classfile.TypeKind.DOUBLE), 18 | REFERENCE(io.github.dmlloyd.classfile.TypeKind.REFERENCE), 19 | VOID(io.github.dmlloyd.classfile.TypeKind.VOID), 20 | ; 21 | 22 | private final io.github.dmlloyd.classfile.TypeKind actualKind; 23 | 24 | TypeKind(final io.github.dmlloyd.classfile.TypeKind actualKind) { 25 | this.actualKind = actualKind; 26 | } 27 | 28 | /** 29 | * {@return the most specific class descriptor for this type kind} 30 | */ 31 | public ClassDesc upperBound() { 32 | return actualKind.upperBound(); 33 | } 34 | 35 | /** 36 | * {@return the number of variable or stack slots required by values of this type} 37 | */ 38 | public int slotSize() { 39 | return actualKind.slotSize(); 40 | } 41 | 42 | /** 43 | * {@return the loadable type kind for this type kind} 44 | */ 45 | public TypeKind asLoadable() { 46 | return of(actualKind.asLoadable()); 47 | } 48 | 49 | static TypeKind of(io.github.dmlloyd.classfile.TypeKind actualKind) { 50 | return switch (actualKind) { 51 | case BOOLEAN -> BOOLEAN; 52 | case BYTE -> BYTE; 53 | case CHAR -> CHAR; 54 | case SHORT -> SHORT; 55 | case INT -> INT; 56 | case LONG -> LONG; 57 | case FLOAT -> FLOAT; 58 | case DOUBLE -> DOUBLE; 59 | case REFERENCE -> REFERENCE; 60 | case VOID -> VOID; 61 | }; 62 | } 63 | 64 | /** 65 | * {@return the type kind for the given descriptor} 66 | */ 67 | public static TypeKind from(TypeDescriptor.OfField descriptor) { 68 | return of(io.github.dmlloyd.classfile.TypeKind.from(descriptor)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/Typed.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import java.lang.constant.ConstantDesc; 4 | 5 | import io.quarkus.gizmo2.creator.MemberCreator; 6 | import io.quarkus.gizmo2.desc.MemberDesc; 7 | 8 | /** 9 | * A thing which has a type. 10 | */ 11 | public sealed interface Typed permits MethodTyped, SimpleTyped, MemberCreator, MemberDesc { 12 | /** 13 | * {@return the type of this entity (not {@code null})} 14 | */ 15 | ConstantDesc type(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/Var.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | /** 4 | * An assignable expression that is stored in a variable. 5 | */ 6 | public sealed interface Var extends Assignable permits FieldVar, LocalVar, ParamVar { 7 | /** 8 | * {@return the variable name} 9 | */ 10 | String name(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/AbstractMethodCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import io.quarkus.gizmo2.impl.AbstractMethodCreatorImpl; 4 | import io.quarkus.gizmo2.impl.InterfaceMethodCreatorImpl; 5 | import io.quarkus.gizmo2.impl.NativeMethodCreatorImpl; 6 | 7 | /** 8 | * A builder for abstract methods. 9 | */ 10 | public sealed interface AbstractMethodCreator extends MethodCreator 11 | permits AbstractMethodCreatorImpl, InterfaceMethodCreatorImpl, NativeMethodCreatorImpl { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/AccessLevel.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import static io.github.dmlloyd.classfile.ClassFile.*; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * The possible access levels for an item. 9 | */ 10 | public enum AccessLevel implements Modifier { 11 | /** 12 | * The {@code private} access level. 13 | */ 14 | PRIVATE(ACC_PRIVATE), 15 | /** 16 | * The package-private ("default") access level. 17 | */ 18 | PACKAGE_PRIVATE(0), 19 | /** 20 | * The {@code protected} access level. 21 | */ 22 | PROTECTED(ACC_PROTECTED), 23 | /** 24 | * The {@code public} access level. 25 | */ 26 | PUBLIC(ACC_PUBLIC); 27 | 28 | private final int mask; 29 | 30 | /** 31 | * The list of access values. 32 | */ 33 | public static final List values = List.of(values()); 34 | 35 | AccessLevel(final int mask) { 36 | this.mask = mask; 37 | } 38 | 39 | public boolean validIn(ModifierLocation location) { 40 | return location.supports(this); 41 | } 42 | 43 | public int mask() { 44 | return mask; 45 | } 46 | 47 | /** 48 | * {@return the access level indicated by the given bit mask} 49 | * If multiple access bits are present, then the access level with the highest bit value is returned. 50 | * 51 | * @param bits the bit mask 52 | */ 53 | public static AccessLevel of(int bits) { 54 | int hob = Integer.highestOneBit(bits & fullMask()); 55 | return switch (hob) { 56 | case ACC_PROTECTED -> PROTECTED; 57 | case ACC_PRIVATE -> PRIVATE; 58 | case ACC_PUBLIC -> PUBLIC; 59 | default -> PACKAGE_PRIVATE; 60 | }; 61 | } 62 | 63 | /** 64 | * {@return the full bitmask for all access levels} 65 | */ 66 | public static int fullMask() { 67 | return ACC_PUBLIC | ACC_PROTECTED | ACC_PRIVATE; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/AnonymousClassCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import io.quarkus.gizmo2.impl.AnonymousClassCreatorImpl; 4 | 5 | /** 6 | * A class creator for classes which capture an enclosing lexical scope. 7 | */ 8 | public sealed interface AnonymousClassCreator extends ClassCreator, CapturingCreator permits AnonymousClassCreatorImpl { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/BodyCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import java.util.function.Consumer; 4 | 5 | /** 6 | * A creator that has a body. 7 | */ 8 | public sealed interface BodyCreator 9 | permits CaseCreator, InstanceBodyCreator, LambdaCreator, StaticExecutableCreator, TryCreator { 10 | /** 11 | * Build the body of this executable code. 12 | * 13 | * @param builder the builder (must not be {@code null}) 14 | */ 15 | void body(Consumer builder); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/CapturingCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import io.quarkus.gizmo2.Expr; 4 | import io.quarkus.gizmo2.Var; 5 | 6 | /** 7 | * A creator for an entity which can capture values from an enclosing scope. 8 | */ 9 | public sealed interface CapturingCreator permits AnonymousClassCreator, LambdaCreator { 10 | /** 11 | * Capture an enclosing value as a variable so that it may be used in the lambda body. 12 | * All values that are created outside the lambda must be captured into new variables 13 | * (even {@code this}) in order to be used within the lambda, otherwise a generation-time 14 | * exception may be thrown. 15 | *

16 | * If the given expression is a variable, the given name overrides the variable's name 17 | * within the scope of the lambda. 18 | * 19 | * @param name the name of the variable (must not be {@code null}) 20 | * @param value the capture value (must not be {@code null}) 21 | * @return the captured variable (not {@code null}) 22 | */ 23 | Var capture(String name, Expr value); 24 | 25 | /** 26 | * Capture an enclosing variable so that it may be used in the lambda body. 27 | * 28 | * @param outer the enclosing variable to capture (must not be {@code null}) 29 | * @return the captured variable (not {@code null}) 30 | */ 31 | default Var capture(Var outer) { 32 | return capture(outer.name(), outer); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/CaseCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import java.lang.constant.Constable; 4 | import java.lang.constant.ConstantDesc; 5 | import java.util.function.Consumer; 6 | 7 | import io.quarkus.gizmo2.Const; 8 | import io.quarkus.gizmo2.impl.SwitchCreatorImpl; 9 | 10 | /** 11 | * A creator for {@code switch} statement and expression cases. 12 | * Each case must declare at least one case value before building the body of the case. 13 | */ 14 | public sealed interface CaseCreator extends BodyCreator permits SwitchCreatorImpl.CaseCreatorImpl { 15 | /** 16 | * Add a constant for this case. 17 | * 18 | * @param val the case value to add (must not be {@code null}) 19 | */ 20 | void of(Const val); 21 | 22 | /** 23 | * Add a constant for this case. 24 | * 25 | * @param val the case value to add (must not be {@code null}) 26 | */ 27 | default void of(Constable val) { 28 | of(Const.of(val)); 29 | } 30 | 31 | /** 32 | * Add a constant for this case. 33 | * 34 | * @param val the case value to add (must not be {@code null}) 35 | */ 36 | default void of(ConstantDesc val) { 37 | of(Const.of(val)); 38 | } 39 | 40 | /** 41 | * Add a constant for this case. 42 | * 43 | * @param val the case value to add (must not be {@code null}) 44 | */ 45 | default void of(String val) { 46 | of(Const.of(val)); 47 | } 48 | 49 | /** 50 | * Add a constant for this case. 51 | * 52 | * @param val the case value to add (must not be {@code null}) 53 | */ 54 | default void of(int val) { 55 | of(Const.of(val)); 56 | } 57 | 58 | /** 59 | * Add a constant for this case. 60 | * 61 | * @param val the case value to add (must not be {@code null}) 62 | */ 63 | default void of(long val) { 64 | of(Const.of(val)); 65 | } 66 | 67 | void body(Consumer builder); 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/ConstructorCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import io.github.dmlloyd.classfile.extras.constant.ExtraConstantDescs; 4 | import io.quarkus.gizmo2.desc.ConstructorDesc; 5 | import io.quarkus.gizmo2.impl.ConstructorCreatorImpl; 6 | 7 | /** 8 | * A creator for an instance constructor. 9 | */ 10 | public sealed interface ConstructorCreator extends InstanceExecutableCreator, MemberCreator permits ConstructorCreatorImpl { 11 | /** 12 | * {@return the descriptor of the constructor (not {@code null})} 13 | */ 14 | ConstructorDesc desc(); 15 | 16 | default String name() { 17 | return ExtraConstantDescs.INIT_NAME; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/InstanceBodyCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | /** 4 | * A thing which has an instance body. 5 | */ 6 | public sealed interface InstanceBodyCreator extends BodyCreator permits InstanceExecutableCreator { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/InstanceExecutableCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | /** 4 | * A creator for instance executables. 5 | */ 6 | public sealed interface InstanceExecutableCreator extends ExecutableCreator, InstanceBodyCreator 7 | permits ConstructorCreator, InstanceMethodCreator { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/InstanceFieldCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import io.quarkus.gizmo2.impl.InstanceFieldCreatorImpl; 4 | 5 | /** 6 | * A creator for an instance field. 7 | */ 8 | public sealed interface InstanceFieldCreator extends FieldCreator permits InstanceFieldCreatorImpl { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/InstanceMethodCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import io.quarkus.gizmo2.impl.DefaultMethodCreatorImpl; 4 | import io.quarkus.gizmo2.impl.InstanceMethodCreatorImpl; 5 | import io.quarkus.gizmo2.impl.PrivateInterfaceMethodCreatorImpl; 6 | 7 | /** 8 | * A creator for an instance method. 9 | */ 10 | public sealed interface InstanceMethodCreator extends InstanceExecutableCreator, MethodCreator 11 | permits DefaultMethodCreatorImpl, InstanceMethodCreatorImpl, PrivateInterfaceMethodCreatorImpl { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/LambdaCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.function.Consumer; 5 | 6 | import io.quarkus.gizmo2.ParamVar; 7 | import io.quarkus.gizmo2.impl.LambdaCreatorImpl; 8 | 9 | /** 10 | * A creator for a lambda instance. 11 | */ 12 | public sealed interface LambdaCreator extends BodyCreator, CapturingCreator permits LambdaCreatorImpl { 13 | /** 14 | * {@return the descriptor of the lambda functional interface} 15 | */ 16 | ClassDesc type(); 17 | 18 | /** 19 | * Access a parameter of the functional interface method declaration. 20 | * 21 | * @param name the name to assign to the parameter (must not be {@code null}) 22 | * @param position the parameter position, starting from 0 23 | * @return the parameter's variable (not {@code null}) 24 | */ 25 | ParamVar parameter(String name, int position); 26 | 27 | /** 28 | * Build the body of the lambda. 29 | * 30 | * @param builder the builder for the lambda body (must not be {@code null}) 31 | */ 32 | void body(Consumer builder); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/MemberCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.constant.ConstantDesc; 5 | 6 | import io.quarkus.gizmo2.Typed; 7 | import io.quarkus.gizmo2.desc.MemberDesc; 8 | 9 | /** 10 | * A generalized creator for any kind of class member. 11 | */ 12 | public sealed interface MemberCreator extends ModifiableCreator, Typed 13 | permits ConstructorCreator, FieldCreator, MethodCreator { 14 | 15 | /** 16 | * {@return the descriptor of the member} 17 | */ 18 | MemberDesc desc(); 19 | 20 | /** 21 | * {@return the type of this member (not {@code null})} 22 | */ 23 | ConstantDesc type(); 24 | 25 | /** 26 | * {@return the descriptor of the class which contains this member} 27 | */ 28 | ClassDesc owner(); 29 | 30 | /** 31 | * {@return the member name} 32 | */ 33 | String name(); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/MethodCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.quarkus.gizmo2.GenericType; 6 | import io.quarkus.gizmo2.desc.MethodDesc; 7 | import io.quarkus.gizmo2.impl.MethodCreatorImpl; 8 | import io.quarkus.gizmo2.impl.Util; 9 | 10 | /** 11 | * A creator for any kind of method on a class. 12 | */ 13 | public sealed interface MethodCreator extends ExecutableCreator, MemberCreator 14 | permits AbstractMethodCreator, InstanceMethodCreator, StaticMethodCreator, MethodCreatorImpl { 15 | 16 | /** 17 | * {@return the descriptor of the method} 18 | */ 19 | MethodDesc desc(); 20 | 21 | /** 22 | * Change the generic return type of this method. 23 | * The method type is changed with the new return type. 24 | * 25 | * @param type the generic return type (must not be {@code null}) 26 | */ 27 | void returning(GenericType type); 28 | 29 | /** 30 | * Change the return type of this method. 31 | * The method type is changed with the new return type. 32 | * 33 | * @param type the descriptor of the return type (must not be {@code null}) 34 | */ 35 | void returning(ClassDesc type); 36 | 37 | /** 38 | * Change the return type of this method. 39 | * The method type is changed with the new return type. 40 | * 41 | * @param type the return type (must not be {@code null}) 42 | */ 43 | default void returning(Class type) { 44 | returning(Util.classDesc(type)); 45 | } 46 | 47 | /** 48 | * Add the {@code synchronized} modifier flag to this creator. 49 | * 50 | * @throws IllegalArgumentException if this creator does not support the {@code synchronized} modifier flag 51 | */ 52 | default void synchronized_() { 53 | addFlag(ModifierFlag.SYNCHRONIZED); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/Modifier.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | /** 4 | * Some kind of modifier (flag or access level). 5 | */ 6 | public sealed interface Modifier permits AccessLevel, ModifierFlag { 7 | /** 8 | * {@return {@code true} if this modifier is valid in the given location, or {@code false} if it is invalid} 9 | */ 10 | boolean validIn(ModifierLocation location); 11 | 12 | /** 13 | * {@return the bitmask of this modifier} 14 | */ 15 | int mask(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/ModifierFlag.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import static io.github.dmlloyd.classfile.ClassFile.*; 4 | 5 | import java.util.List; 6 | import java.util.function.Consumer; 7 | 8 | /** 9 | * A modifier for a type or member. 10 | */ 11 | public enum ModifierFlag implements Modifier { 12 | /** 13 | * The {@code abstract} modifier. 14 | */ 15 | ABSTRACT(ACC_ABSTRACT) { 16 | public void forEachExclusive(final Consumer action) { 17 | action.accept(FINAL); 18 | } 19 | }, 20 | /** 21 | * The "bridge" modifier. 22 | */ 23 | BRIDGE(ACC_BRIDGE), 24 | /** 25 | * The {@code final} modifier. 26 | */ 27 | FINAL(ACC_FINAL) { 28 | public void forEachExclusive(final Consumer action) { 29 | action.accept(ABSTRACT); 30 | action.accept(VOLATILE); 31 | } 32 | }, 33 | /** 34 | * The "mandated" modifier. 35 | */ 36 | MANDATED(ACC_MANDATED), 37 | /** 38 | * The {@code static} modifier. 39 | */ 40 | STATIC(ACC_STATIC), 41 | /** 42 | * The {@code synchronized} modifier. 43 | */ 44 | SYNCHRONIZED(ACC_SYNCHRONIZED), 45 | /** 46 | * The "synthetic" modifier. 47 | */ 48 | SYNTHETIC(ACC_SYNTHETIC), 49 | /** 50 | * The {@code transient} modifier. 51 | */ 52 | TRANSIENT(ACC_TRANSIENT), 53 | /** 54 | * The variable-argument modifier. 55 | */ 56 | VARARGS(ACC_VARARGS), 57 | /** 58 | * The {@code volatile} modifier. 59 | */ 60 | VOLATILE(ACC_VOLATILE) { 61 | public void forEachExclusive(final Consumer action) { 62 | action.accept(FINAL); 63 | } 64 | }, 65 | ; 66 | 67 | /** 68 | * The modifier flag list in order by ordinal. 69 | */ 70 | public static final List values = List.of(values()); 71 | 72 | private final int sets; 73 | 74 | ModifierFlag(final int sets) { 75 | this.sets = sets; 76 | } 77 | 78 | public boolean validIn(final ModifierLocation location) { 79 | return location.supports(this); 80 | } 81 | 82 | public int mask() { 83 | return sets; 84 | } 85 | 86 | /** 87 | * Process the given action for each flag which is mutually exclusive with this one. 88 | * 89 | * @param action the action to process (must not be {@code null}) 90 | */ 91 | public void forEachExclusive(Consumer action) { 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/ParamCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.quarkus.gizmo2.GenericType; 6 | import io.quarkus.gizmo2.GenericTyped; 7 | import io.quarkus.gizmo2.impl.ParamCreatorImpl; 8 | import io.quarkus.gizmo2.impl.Util; 9 | 10 | /** 11 | * A creator interface for parameters. 12 | */ 13 | public sealed interface ParamCreator extends ModifiableCreator, GenericTyped permits ParamCreatorImpl { 14 | /** 15 | * Change the type of this parameter. 16 | * 17 | * @param type the new generic type (must not be {@code null}) 18 | * @throws IllegalArgumentException if the new type is different from the established type 19 | */ 20 | void setType(GenericType type); 21 | 22 | /** 23 | * Change the type of this parameter. 24 | * 25 | * @param type the descriptor of the new type (must not be {@code null}) 26 | * @throws IllegalArgumentException if the new type is different from the established type 27 | */ 28 | void setType(ClassDesc type); 29 | 30 | /** 31 | * {@return the type of this parameter (not {@code null})} 32 | */ 33 | ClassDesc type(); 34 | 35 | /** 36 | * Change the type of this parameter. 37 | * 38 | * @param type the new type (must not be {@code null}) 39 | */ 40 | default void setType(Class type) { 41 | setType(Util.classDesc(type)); 42 | } 43 | 44 | /** 45 | * Add the "mandated" modifier flag to this creator. 46 | */ 47 | default void mandated() { 48 | addFlag(ModifierFlag.MANDATED); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/StaticExecutableCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | /** 4 | * A creator for any kind of non-instance executable creator. 5 | */ 6 | public sealed interface StaticExecutableCreator extends ExecutableCreator, BodyCreator permits StaticMethodCreator { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/StaticFieldCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import io.quarkus.gizmo2.impl.StaticFieldCreatorImpl; 4 | 5 | /** 6 | * A creator for a static field. 7 | */ 8 | public sealed interface StaticFieldCreator extends FieldCreator permits StaticFieldCreatorImpl { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/StaticMethodCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import io.quarkus.gizmo2.impl.StaticInterfaceMethodCreatorImpl; 4 | import io.quarkus.gizmo2.impl.StaticMethodCreatorImpl; 5 | 6 | /** 7 | * A builder for static methods. 8 | */ 9 | public sealed interface StaticMethodCreator extends MethodCreator, StaticExecutableCreator 10 | permits StaticMethodCreatorImpl, StaticInterfaceMethodCreatorImpl { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/TypeParameterCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import java.util.List; 4 | 5 | import io.quarkus.gizmo2.GenericType; 6 | import io.quarkus.gizmo2.impl.TypeParameterCreatorImpl; 7 | 8 | /** 9 | * A creator for a type parameter. 10 | */ 11 | public sealed interface TypeParameterCreator extends AnnotatableCreator permits TypeParameterCreatorImpl { 12 | /** 13 | * {@return the name of the type variable being created (not {@code null})} 14 | */ 15 | String name(); 16 | 17 | /** 18 | * Establish the (optional) first bound for the type variable. 19 | * The first bound is a class type. 20 | * 21 | * @param bound the first bound (must not be {@code null}) 22 | */ 23 | void setFirstBound(GenericType.OfClass bound); 24 | 25 | /** 26 | * Establish the (optional) first bound for the type variable. 27 | * The first bound is a type variable. 28 | * In this case, no other bounds may be present. 29 | * 30 | * @param bound the first bound (must not be {@code null}) 31 | */ 32 | void setFirstBound(GenericType.OfTypeVariable bound); 33 | 34 | /** 35 | * Establish the other (secondary) bounds for the type variable. 36 | * The other bounds must all be interface types. 37 | * If the first bound is a type variable, there may be no other bounds. 38 | *

39 | * It is possible to set the other bounds without setting the first bound. 40 | * In this case, all bounds are interface types. 41 | * 42 | * @param bounds the secondary bounds (must not be {@code null}) 43 | */ 44 | void setOtherBounds(List bounds); 45 | 46 | /** 47 | * Establish the other (secondary) bounds for the type variable. 48 | * The other bounds must all be interface types. 49 | * If the first bound is a type variable, there may be no other bounds. 50 | *

51 | * It is possible to set the other bounds without setting the first bound. 52 | * In this case, all bounds are interface types. 53 | * 54 | * @param bounds the secondary bounds (must not be {@code null}) 55 | */ 56 | default void setOtherBounds(GenericType.OfClass... bounds) { 57 | setOtherBounds(List.of(bounds)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/TypeParameterizedCreator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import io.quarkus.gizmo2.GenericType; 6 | 7 | /** 8 | * A creator for things which can have type parameters. 9 | */ 10 | public sealed interface TypeParameterizedCreator permits ClassCreator, InterfaceCreator, ExecutableCreator { 11 | /** 12 | * Creates a type parameter with given {@code name} and allows configuring its bounds. 13 | * Returns a reference to the type parameter in the form of a {@linkplain GenericType.OfTypeVariable type variable}. 14 | * 15 | * @param name the name of the type parameter 16 | * @param builder the builder to configure bounds of the type parameter 17 | * @return the type variable corresponding to the created type parameter 18 | */ 19 | GenericType.OfTypeVariable typeParameter(String name, Consumer builder); 20 | 21 | /** 22 | * Creates a type parameter with given {@code name} and no bounds. 23 | * Returns a reference to the type parameter in the form of a {@linkplain GenericType.OfTypeVariable type variable}. 24 | * 25 | * @param name the name of the type parameter 26 | * @return the type variable corresponding to the created type parameter 27 | */ 28 | default GenericType.OfTypeVariable typeParameter(String name) { 29 | return typeParameter(name, tpc -> { 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/ops/ClassOps.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator.ops; 2 | 3 | import io.quarkus.gizmo2.Const; 4 | import io.quarkus.gizmo2.Expr; 5 | import io.quarkus.gizmo2.creator.BlockCreator; 6 | 7 | /** 8 | * Operations on {@link Class}. 9 | */ 10 | public final class ClassOps extends ObjectOps { 11 | /** 12 | * Construct a new instance. 13 | * 14 | * @param bc the block creator (must not be {@code null}) 15 | * @param clazz the receiver class (must not be {@code null}) 16 | */ 17 | public ClassOps(final BlockCreator bc, final Expr clazz) { 18 | super(Class.class, bc, clazz); 19 | } 20 | 21 | /** 22 | * Generate a call to {@link Class#getName()}. 23 | * 24 | * @return the expression of the result (not {@code null}) 25 | */ 26 | public Expr getName() { 27 | return invokeInstance(String.class, "getName"); 28 | } 29 | 30 | /** 31 | * Generate a call to {@link Class#isInterface()} ()}. 32 | * 33 | * @return the expression of the result (not {@code null}) 34 | */ 35 | public Expr isInterface() { 36 | return invokeInstance(boolean.class, "isInterface"); 37 | } 38 | 39 | /** 40 | * Generate a call to {@link Class#getClassLoader()}. 41 | * 42 | * @return the expression of the result (not {@code null}) 43 | */ 44 | public Expr getClassLoader() { 45 | return invokeInstance(ClassLoader.class, "getClassLoader"); 46 | } 47 | 48 | /** 49 | * Generate a call to {@link Class#asSubclass(Class)}. 50 | * 51 | * @param subclass the expression of the subclass {@code Class} object (must not be {@code null}) 52 | * @return the expression of the result (not {@code null}) 53 | */ 54 | public Expr asSubclass(Expr subclass) { 55 | return invokeInstance(Class.class, "asSubclass", Class.class, subclass); 56 | } 57 | 58 | /** 59 | * Generate a call to {@link Class#asSubclass(Class)}. 60 | * 61 | * @param clazz the subclass {@code Class} object (must not be {@code null}) 62 | * @return the expression of the result (not {@code null}) 63 | */ 64 | public Expr asSubclass(Class clazz) { 65 | return asSubclass(Const.of(clazz)); 66 | } 67 | 68 | /** 69 | * Generate a call to {@link Class#cast(Object)}. 70 | * 71 | * @param object the expression of the object to cast (must not be {@code null}) 72 | * @return the expression of the result (not {@code null}) 73 | */ 74 | public Expr cast(Expr object) { 75 | return invokeInstance(Object.class, "cast", Object.class, object); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/ops/ComparableOps.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator.ops; 2 | 3 | import io.quarkus.gizmo2.Expr; 4 | 5 | /** 6 | * Operations on {@link Comparable}. 7 | */ 8 | public interface ComparableOps { 9 | /** 10 | * Generate a call to {@link Comparable#compareTo(Object)}. 11 | * 12 | * @param other the other object to compare (must not be {@code null}) 13 | * @return the expression of the result (not {@code null}) 14 | */ 15 | Expr compareTo(Expr other); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/ops/IteratorOps.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator.ops; 2 | 3 | import java.util.Iterator; 4 | import java.util.function.Consumer; 5 | 6 | import io.quarkus.gizmo2.Expr; 7 | import io.quarkus.gizmo2.creator.BlockCreator; 8 | 9 | /** 10 | * Operations on an {@link Iterator}. 11 | */ 12 | public class IteratorOps extends ObjectOps { 13 | /** 14 | * Construct a new instance. 15 | * 16 | * @param bc the block creator to wrap (must not be {@code null}) 17 | * @param obj the iterator object (must not be {@code null}) 18 | */ 19 | public IteratorOps(final BlockCreator bc, final Expr obj) { 20 | super(Iterator.class, bc, obj); 21 | } 22 | 23 | /** 24 | * Construct a new instance. 25 | * 26 | * @param receiverType the type class of the receiver (must not be {@code null}) 27 | * @param bc the block creator to wrap (must not be {@code null}) 28 | * @param obj the iterator object (must not be {@code null}) 29 | */ 30 | protected IteratorOps(final Class receiverType, final BlockCreator bc, final Expr obj) { 31 | super(receiverType, bc, obj); 32 | } 33 | 34 | /** 35 | * Call {@link Iterator#hasNext()}. 36 | * 37 | * @return the boolean result of the method call (not {@code null}) 38 | */ 39 | public Expr hasNext() { 40 | return invokeInstance(boolean.class, "hasNext"); 41 | } 42 | 43 | /** 44 | * Call {@link Iterator#next()}. 45 | * 46 | * @return the next iterator item (not {@code null}) 47 | */ 48 | public Expr next() { 49 | return invokeInstance(Object.class, "next"); 50 | } 51 | 52 | /** 53 | * Call {@link Iterator#remove}. 54 | */ 55 | public void remove() { 56 | invokeInstance(void.class, "remove"); 57 | } 58 | 59 | /** 60 | * Call {@link Iterator#forEachRemaining(Consumer)}. 61 | * 62 | * @param action the consumer to pass to the function (not {@code null}) 63 | */ 64 | public void forEachRemaining(Expr action) { 65 | invokeInstance(void.class, "forEachRemaining", Consumer.class, action); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/ops/ListOps.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator.ops; 2 | 3 | import java.util.List; 4 | 5 | import io.quarkus.gizmo2.Const; 6 | import io.quarkus.gizmo2.Expr; 7 | import io.quarkus.gizmo2.creator.BlockCreator; 8 | 9 | /** 10 | * Operations on {@link List}. 11 | */ 12 | public class ListOps extends CollectionOps { 13 | /** 14 | * Construct a new instance. 15 | * 16 | * @param bc the block creator (must not be {@code null}) 17 | * @param obj the list instance (must not be {@code null}) 18 | */ 19 | public ListOps(final BlockCreator bc, final Expr obj) { 20 | super(List.class, bc, obj); 21 | } 22 | 23 | /** 24 | * Construct a new subclass instance. 25 | * 26 | * @param receiverType the type of the receiver (must not be {@code null}) 27 | * @param bc the block creator (must not be {@code null}) 28 | * @param obj the receiver object (must not be {@code null}) 29 | */ 30 | protected ListOps(final Class receiverType, final BlockCreator bc, final Expr obj) { 31 | super(receiverType.asSubclass(List.class), bc, obj); 32 | } 33 | 34 | /** 35 | * Generate a call to {@link List#get(int)}. 36 | * 37 | * @param index the index of the element to return (must not be {@code null}) 38 | * @return the expression of the result (not {@code null}) 39 | */ 40 | public Expr get(Expr index) { 41 | return invokeInstance(Object.class, "get", int.class, index); 42 | } 43 | 44 | /** 45 | * Generate a call to {@link List#get(int)}. 46 | * 47 | * @param index the index of the element to return 48 | * @return the expression of the result (not {@code null}) 49 | */ 50 | public Expr get(int index) { 51 | return invokeInstance(Object.class, "get", int.class, Const.of(index)); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/ops/OptionalOps.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator.ops; 2 | 3 | import java.util.Optional; 4 | 5 | import io.quarkus.gizmo2.Expr; 6 | import io.quarkus.gizmo2.creator.BlockCreator; 7 | 8 | /** 9 | * Operations on {@link Optional}. 10 | */ 11 | public class OptionalOps extends ObjectOps { 12 | 13 | /** 14 | * Construct a new instance. 15 | * 16 | * @param bc the block creator to wrap (must not be {@code null}) 17 | * @param obj the optional object (must not be {@code null}) 18 | */ 19 | public OptionalOps(BlockCreator bc, Expr obj) { 20 | super(Optional.class, bc, obj); 21 | } 22 | 23 | /** 24 | * Generate a call to {@link Optional#get()}. 25 | * 26 | * @return the expression of the result (not {@code null}) 27 | */ 28 | public Expr get() { 29 | return invokeInstance(Object.class, "get"); 30 | } 31 | 32 | /** 33 | * Generate a call to {@link Optional#get()}. 34 | * 35 | * @return the expression of the result (not {@code null}) 36 | */ 37 | public Expr isPresent() { 38 | return invokeInstance(boolean.class, "isPresent"); 39 | } 40 | 41 | /** 42 | * Generate a call to {@link Optional#get()}. 43 | * 44 | * @return the expression of the result (not {@code null}) 45 | */ 46 | public Expr isEmpty() { 47 | return invokeInstance(boolean.class, "isEmpty"); 48 | } 49 | 50 | /** 51 | * Generate a call to {@link Optional#get()}. 52 | * 53 | * @param other the expression to be returned, if no value is present 54 | * @return the expression of the result (not {@code null}) 55 | */ 56 | public Expr orElse(Expr other) { 57 | return invokeInstance(Object.class, "orElse", Object.class, other); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/ops/SetOps.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator.ops; 2 | 3 | import java.util.Set; 4 | 5 | import io.quarkus.gizmo2.Expr; 6 | import io.quarkus.gizmo2.creator.BlockCreator; 7 | 8 | /** 9 | * Operations on {@link Set}. 10 | */ 11 | public class SetOps extends CollectionOps { 12 | /** 13 | * Construct a new instance. 14 | * 15 | * @param bc the block creator (must not be {@code null}) 16 | * @param obj the set instance (must not be {@code null}) 17 | */ 18 | public SetOps(final BlockCreator bc, final Expr obj) { 19 | super(Set.class, bc, obj); 20 | } 21 | 22 | /** 23 | * Construct a new subclass instance. 24 | * 25 | * @param receiverType the type of the receiver (must not be {@code null}) 26 | * @param bc the block creator (must not be {@code null}) 27 | * @param obj the receiver object (must not be {@code null}) 28 | */ 29 | protected SetOps(final Class receiverType, final BlockCreator bc, final Expr obj) { 30 | super(receiverType.asSubclass(Set.class), bc, obj); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/creator/ops/ThrowableOps.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.creator.ops; 2 | 3 | import io.quarkus.gizmo2.Expr; 4 | import io.quarkus.gizmo2.creator.BlockCreator; 5 | 6 | /** 7 | * Operations on {@link Throwable}. 8 | */ 9 | public class ThrowableOps extends ObjectOps { 10 | /** 11 | * Construct a new instance. 12 | * 13 | * @param bc the block creator (must not be {@code null}) 14 | * @param obj the collection instance (must not be {@code null}) 15 | */ 16 | public ThrowableOps(final BlockCreator bc, final Expr obj) { 17 | super(Throwable.class, bc, obj); 18 | } 19 | 20 | /** 21 | * Construct a new subclass instance. 22 | * 23 | * @param receiverType the type of the receiver (must not be {@code null}) 24 | * @param bc the block creator (must not be {@code null}) 25 | * @param obj the receiver object (must not be {@code null}) 26 | */ 27 | protected ThrowableOps(final Class receiverType, final BlockCreator bc, final Expr obj) { 28 | super(receiverType.asSubclass(Throwable.class), bc, obj); 29 | } 30 | 31 | /** 32 | * Generate a call to {@link Throwable#getMessage()}. 33 | * 34 | * @return the expression of the result (not {@code null}) 35 | */ 36 | public Expr getMessage() { 37 | return invokeInstance(String.class, "getMessage"); 38 | } 39 | 40 | /** 41 | * Generate a call to {@link Throwable#getLocalizedMessage()}. 42 | * 43 | * @return the expression of the result (not {@code null}) 44 | */ 45 | public Expr getLocalizedMessage() { 46 | return invokeInstance(String.class, "getLocalizedMessage"); 47 | } 48 | 49 | /** 50 | * Generate a call to {@link Throwable#getCause()}. 51 | * 52 | * @return the expression of the result (not {@code null}) 53 | */ 54 | public Expr getCause() { 55 | return invokeInstance(Throwable.class, "getCause"); 56 | } 57 | 58 | /** 59 | * Generate a call to {@link Throwable#getSuppressed()}. 60 | * 61 | * @return the expression of the result (not {@code null}) 62 | */ 63 | public Expr getSuppressed() { 64 | return invokeInstance(Throwable[].class, "getSuppressed"); 65 | } 66 | 67 | /** 68 | * Generate a call to {@link Throwable#addSuppressed(Throwable)}. 69 | * 70 | * @param exception the expression of the exception to add (must not be {@code null}) 71 | */ 72 | public void addSuppressed(Expr exception) { 73 | invokeInstance(void.class, "addSuppressed", Throwable.class, exception); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/desc/MemberDesc.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.desc; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.constant.ConstantDesc; 5 | 6 | import io.quarkus.gizmo2.Typed; 7 | 8 | /** 9 | * A descriptor for a class member. 10 | */ 11 | public sealed interface MemberDesc extends Typed permits ConstructorDesc, FieldDesc, MethodDesc { 12 | /** 13 | * {@return the descriptor of the class which contains the described member} 14 | */ 15 | ClassDesc owner(); 16 | 17 | /** 18 | * {@return a descriptor representing the type of this member} 19 | */ 20 | ConstantDesc type(); 21 | 22 | /** 23 | * {@return the member name} 24 | */ 25 | String name(); 26 | 27 | /** 28 | * Convert this descriptor to a string and append it to the given builder. 29 | * 30 | * @param b the string builder to append to (must not be {@code null}) 31 | * @return the string builder 32 | */ 33 | StringBuilder toString(StringBuilder b); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/AbstractMethodCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import io.quarkus.gizmo2.creator.AbstractMethodCreator; 6 | import io.quarkus.gizmo2.creator.ModifierLocation; 7 | 8 | public final class AbstractMethodCreatorImpl extends MethodCreatorImpl implements AbstractMethodCreator { 9 | AbstractMethodCreatorImpl(final TypeCreatorImpl owner, final String name) { 10 | super(owner, name); 11 | } 12 | 13 | public ModifierLocation modifierLocation() { 14 | return ModifierLocation.CLASS_ABSTRACT_METHOD; 15 | } 16 | 17 | void accept(final Consumer builder) { 18 | builder.accept(this); 19 | typeCreator.zb.withMethod(name(), type(), modifiers, mb -> { 20 | doBody(null, mb); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ArrayDeref.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.quarkus.gizmo2.impl.Conversions.convert; 4 | import static java.lang.constant.ConstantDescs.CD_int; 5 | 6 | import java.lang.constant.ClassDesc; 7 | import java.util.function.BiFunction; 8 | 9 | import io.github.dmlloyd.classfile.CodeBuilder; 10 | import io.quarkus.gizmo2.Expr; 11 | import io.quarkus.gizmo2.GenericType; 12 | import io.quarkus.gizmo2.MemoryOrder; 13 | 14 | public final class ArrayDeref extends AssignableImpl { 15 | private final Item item; 16 | private final GenericType componentType; 17 | private final Item index; 18 | private boolean bound; 19 | 20 | ArrayDeref(final Item item, final GenericType componentType, final Expr index) { 21 | this.item = item; 22 | this.componentType = componentType; 23 | this.index = convert(index, CD_int); 24 | } 25 | 26 | protected Node forEachDependency(final Node node, final BiFunction op) { 27 | return item.process(index.process(node.prev(), op), op); 28 | } 29 | 30 | public Item array() { 31 | return item; 32 | } 33 | 34 | public Item index() { 35 | return index; 36 | } 37 | 38 | Item emitGet(final BlockCreatorImpl block, final MemoryOrder mode) { 39 | if (!mode.validForReads()) { 40 | throw new IllegalArgumentException("Invalid mode " + mode); 41 | } 42 | return switch (mode) { 43 | case AsDeclared, Plain -> asBound(); 44 | default -> new ArrayLoadViaHandle(this, mode); 45 | }; 46 | } 47 | 48 | Item emitSet(final BlockCreatorImpl block, final Item value, final MemoryOrder mode) { 49 | return switch (mode) { 50 | case AsDeclared, Plain -> new ArrayStore(item, index, value, type()); 51 | default -> new ArrayStoreViaHandle(this, value, mode); 52 | }; 53 | } 54 | 55 | public ClassDesc type() { 56 | return componentType.desc(); 57 | } 58 | 59 | public GenericType genericType() { 60 | return componentType; 61 | } 62 | 63 | protected void bind() { 64 | if (item.bound() || index.bound()) { 65 | bound = true; 66 | } 67 | } 68 | 69 | public boolean bound() { 70 | return bound; 71 | } 72 | 73 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 74 | cb.arrayLoad(Util.actualKindOf(typeKind())); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ArrayLength.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.constant.ConstantDescs; 5 | import java.util.function.BiFunction; 6 | 7 | import io.github.dmlloyd.classfile.CodeBuilder; 8 | 9 | final class ArrayLength extends Item { 10 | private final Item item; 11 | boolean bound; 12 | 13 | ArrayLength(final Item item) { 14 | this.item = item; 15 | } 16 | 17 | @Override 18 | public ClassDesc type() { 19 | return ConstantDescs.CD_int; 20 | } 21 | 22 | protected void bind() { 23 | if (item.bound()) { 24 | bound = true; 25 | } 26 | } 27 | 28 | @Override 29 | public boolean bound() { 30 | return bound; 31 | } 32 | 33 | protected Node forEachDependency(final Node node, final BiFunction op) { 34 | return item.process(node.prev(), op); 35 | } 36 | 37 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 38 | cb.arraylength(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ArrayLoadViaHandle.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.smallrye.common.constraint.Assert.impossibleSwitchCase; 4 | import static java.lang.constant.ConstantDescs.*; 5 | 6 | import java.lang.constant.ClassDesc; 7 | import java.lang.constant.MethodTypeDesc; 8 | import java.util.function.BiFunction; 9 | 10 | import io.github.dmlloyd.classfile.CodeBuilder; 11 | import io.quarkus.gizmo2.GenericType; 12 | import io.quarkus.gizmo2.MemoryOrder; 13 | import io.quarkus.gizmo2.impl.constant.ConstImpl; 14 | 15 | final class ArrayLoadViaHandle extends Item { 16 | private final ArrayDeref arrayDeref; 17 | private final MemoryOrder mode; 18 | 19 | ArrayLoadViaHandle(final ArrayDeref arrayDeref, final MemoryOrder mode) { 20 | this.arrayDeref = arrayDeref; 21 | this.mode = mode; 22 | } 23 | 24 | protected Node forEachDependency(final Node node, final BiFunction op) { 25 | return ConstImpl.ofArrayVarHandle(arrayDeref.array().type()) 26 | .process(arrayDeref.array().process(arrayDeref.index().process(node.prev(), op), op), op); 27 | } 28 | 29 | public ClassDesc type() { 30 | return arrayDeref.type(); 31 | } 32 | 33 | public GenericType genericType() { 34 | return arrayDeref.genericType(); 35 | } 36 | 37 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 38 | cb.invokevirtual(CD_VarHandle, switch (mode) { 39 | case Plain -> "get"; 40 | case Opaque -> "getOpaque"; 41 | case Acquire -> "getAcquire"; 42 | case Volatile -> "getVolatile"; 43 | default -> throw impossibleSwitchCase(mode); 44 | }, MethodTypeDesc.of(type(), arrayDeref.array().type(), CD_int)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ArrayStore.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.quarkus.gizmo2.impl.Conversions.convert; 4 | import static java.lang.constant.ConstantDescs.CD_int; 5 | 6 | import java.lang.constant.ClassDesc; 7 | import java.util.function.BiFunction; 8 | 9 | import io.github.dmlloyd.classfile.CodeBuilder; 10 | import io.github.dmlloyd.classfile.TypeKind; 11 | 12 | final class ArrayStore extends Item { 13 | private final Item arrayExpr; 14 | private final Item index; 15 | private final Item value; 16 | private final ClassDesc componentType; 17 | 18 | ArrayStore(final Item arrayExpr, final Item index, final Item value, final ClassDesc componentType) { 19 | this.arrayExpr = arrayExpr; 20 | this.index = convert(index, CD_int); 21 | this.value = convert(value, componentType); 22 | this.componentType = componentType; 23 | } 24 | 25 | Item arrayExpr() { 26 | return arrayExpr; 27 | } 28 | 29 | Item index() { 30 | return index; 31 | } 32 | 33 | Item value() { 34 | return value; 35 | } 36 | 37 | protected Node forEachDependency(final Node node, final BiFunction op) { 38 | return arrayExpr.process(index.process(value.process(node.prev(), op), op), op); 39 | } 40 | 41 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 42 | cb.arrayStore(TypeKind.from(componentType)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ArrayStoreViaHandle.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static java.lang.constant.ConstantDescs.*; 4 | 5 | import java.lang.constant.MethodTypeDesc; 6 | import java.util.function.BiFunction; 7 | 8 | import io.github.dmlloyd.classfile.CodeBuilder; 9 | import io.quarkus.gizmo2.MemoryOrder; 10 | import io.quarkus.gizmo2.impl.constant.ConstImpl; 11 | import io.smallrye.common.constraint.Assert; 12 | 13 | final class ArrayStoreViaHandle extends Item { 14 | private final ArrayDeref arrayDeref; 15 | private final Item value; 16 | private final MemoryOrder mode; 17 | 18 | ArrayStoreViaHandle(final ArrayDeref arrayDeref, final Item value, final MemoryOrder mode) { 19 | this.arrayDeref = arrayDeref; 20 | this.value = value; 21 | this.mode = mode; 22 | } 23 | 24 | protected Node forEachDependency(final Node node, final BiFunction op) { 25 | return ConstImpl.ofArrayVarHandle(arrayDeref.array().type()) 26 | .process(arrayDeref.array().process(arrayDeref.index().process(value.process(node.prev(), op), op), op), op); 27 | } 28 | 29 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 30 | cb.invokevirtual(CD_VarHandle, switch (mode) { 31 | case Plain -> "set"; 32 | case Opaque -> "setOpaque"; 33 | case Release -> "setRelease"; 34 | case Volatile -> "setVolatile"; 35 | default -> throw Assert.impossibleSwitchCase(mode); 36 | }, MethodTypeDesc.of(CD_void, arrayDeref.array().type(), CD_int, arrayDeref.type())); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/AssignableImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import io.quarkus.gizmo2.Assignable; 4 | import io.quarkus.gizmo2.Const; 5 | import io.quarkus.gizmo2.MemoryOrder; 6 | 7 | public non-sealed abstract class AssignableImpl extends Item implements Assignable { 8 | AssignableImpl() { 9 | } 10 | 11 | abstract Item emitGet(final BlockCreatorImpl block, final MemoryOrder mode); 12 | 13 | abstract Item emitSet(final BlockCreatorImpl block, final Item value, final MemoryOrder mode); 14 | 15 | void emitInc(final BlockCreatorImpl block, final Const amount) { 16 | block.set(this, block.add(this, amount)); 17 | } 18 | 19 | void emitDec(final BlockCreatorImpl block, final Const amount) { 20 | block.set(this, block.sub(this, amount)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/BlockExpr.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | 7 | final class BlockExpr extends Item { 8 | private final ClassDesc type; 9 | 10 | BlockExpr(final ClassDesc type) { 11 | this.type = type; 12 | } 13 | 14 | public ClassDesc type() { 15 | return type; 16 | } 17 | 18 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 19 | // implicit (no operation) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/BlockHeader.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import io.github.dmlloyd.classfile.CodeBuilder; 4 | 5 | final class BlockHeader extends Item { 6 | static final BlockHeader INSTANCE = new BlockHeader(); 7 | 8 | private BlockHeader() { 9 | } 10 | 11 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 12 | // implicit (no operation) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/BootstrappedMethodHandleImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.constant.ConstantDesc; 5 | import java.lang.constant.ConstantDescs; 6 | import java.lang.constant.DirectMethodHandleDesc; 7 | import java.lang.constant.DynamicCallSiteDesc; 8 | import java.lang.constant.MethodHandleDesc; 9 | import java.lang.constant.MethodTypeDesc; 10 | import java.util.List; 11 | 12 | import io.github.dmlloyd.classfile.CodeBuilder; 13 | import io.quarkus.gizmo2.Const; 14 | import io.quarkus.gizmo2.desc.InterfaceMethodDesc; 15 | import io.quarkus.gizmo2.desc.MethodDesc; 16 | 17 | /** 18 | * This class is used for special cases where we need 19 | * an item which represents an indy which yields a static 20 | * call site, from which we obtain a static method handle. 21 | */ 22 | public final class BootstrappedMethodHandleImpl extends Item { 23 | private final ClassDesc owner; 24 | private final MethodDesc bootstrapMethodDesc; 25 | private final MethodTypeDesc methodHandleType; 26 | private final List bootstrapArguments; 27 | 28 | public BootstrappedMethodHandleImpl(final ClassDesc owner, final MethodDesc bootstrapMethodDesc, 29 | final MethodTypeDesc methodHandleType, final List bootstrapArguments) { 30 | this.owner = owner; 31 | this.bootstrapMethodDesc = bootstrapMethodDesc; 32 | this.methodHandleType = methodHandleType; 33 | this.bootstrapArguments = bootstrapArguments; 34 | } 35 | 36 | public ClassDesc type() { 37 | return ConstantDescs.CD_MethodHandle; 38 | } 39 | 40 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 41 | cb.invokedynamic(DynamicCallSiteDesc.of( 42 | MethodHandleDesc.ofMethod( 43 | bootstrapMethodDesc instanceof InterfaceMethodDesc ? DirectMethodHandleDesc.Kind.INTERFACE_STATIC 44 | : DirectMethodHandleDesc.Kind.STATIC, 45 | owner, 46 | bootstrapMethodDesc.name(), 47 | bootstrapMethodDesc.type()), 48 | "_", 49 | methodHandleType, 50 | bootstrapArguments.stream().map(Const::desc).toArray(ConstantDesc[]::new))); 51 | // now extract the method handle from the call site 52 | cb.invokevirtual( 53 | ConstantDescs.CD_MethodHandle, 54 | "getMethodHandle", 55 | MethodTypeDesc.of(ConstantDescs.CD_MethodHandle)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/BoundItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.function.BiFunction; 5 | 6 | import io.github.dmlloyd.classfile.CodeBuilder; 7 | 8 | final class BoundItem extends Item { 9 | private final Item item; 10 | 11 | BoundItem(final Item item) { 12 | this.item = item; 13 | } 14 | 15 | Item item() { 16 | return item; 17 | } 18 | 19 | public ClassDesc type() { 20 | return item.type(); 21 | } 22 | 23 | protected Node forEachDependency(final Node node, final BiFunction op) { 24 | return item.forEachDependency(node, op); 25 | } 26 | 27 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 28 | item.writeCode(cb, block); 29 | } 30 | 31 | public String itemName() { 32 | return item.itemName() + ":bound"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Box.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static java.lang.constant.ConstantDescs.*; 4 | 5 | import java.lang.constant.ClassDesc; 6 | import java.lang.constant.MethodTypeDesc; 7 | 8 | import io.github.dmlloyd.classfile.CodeBuilder; 9 | import io.github.dmlloyd.classfile.Opcode; 10 | import io.quarkus.gizmo2.Expr; 11 | import io.quarkus.gizmo2.GenericType; 12 | 13 | final class Box extends Cast { 14 | private boolean bound; 15 | 16 | private static ClassDesc boxing(ClassDesc unboxType) { 17 | ClassDesc boxType = Conversions.boxingConversion(unboxType) 18 | .orElseThrow(() -> new IllegalArgumentException("No box type for " + unboxType.displayName())); 19 | if (boxType.equals(CD_Void)) { 20 | throw new IllegalArgumentException("Cannot box void"); 21 | } 22 | return boxType; 23 | } 24 | 25 | Box(Expr a) { 26 | this(a, boxing(a.type())); 27 | } 28 | 29 | Box(Expr a, ClassDesc toType) { 30 | super(a, GenericType.of(toType)); 31 | } 32 | 33 | @Override 34 | public boolean bound() { 35 | return bound; 36 | } 37 | 38 | @Override 39 | protected void bind() { 40 | bound = true; 41 | } 42 | 43 | @Override 44 | public void writeCode(CodeBuilder cb, BlockCreatorImpl block) { 45 | ClassDesc boxType = boxing(a.type()); 46 | cb.invoke(Opcode.INVOKESTATIC, boxType, "valueOf", MethodTypeDesc.of(boxType, a.type()), false); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Break.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.Objects; 4 | 5 | import io.github.dmlloyd.classfile.Label; 6 | import io.quarkus.gizmo2.Expr; 7 | import io.quarkus.gizmo2.creator.BlockCreator; 8 | 9 | final class Break extends Goto { 10 | private final BlockCreatorImpl outer; 11 | 12 | public Break(final BlockCreator outer) { 13 | this.outer = (BlockCreatorImpl) outer; 14 | } 15 | 16 | public String itemName() { 17 | return "Break:" + outer; 18 | } 19 | 20 | Label target(final BlockCreatorImpl from) { 21 | TryFinally tryFinally = from.tryFinally; 22 | if (tryFinally != null) { 23 | return tryFinally.cleanup(new BreakKey(outer)); 24 | } else { 25 | return outer.endLabel(); 26 | } 27 | } 28 | 29 | static class BreakKey extends TryFinally.CleanupKey { 30 | private final BlockCreatorImpl outer; 31 | 32 | BreakKey(final BlockCreatorImpl outer) { 33 | this.outer = outer; 34 | } 35 | 36 | void terminate(final BlockCreatorImpl bci, final Expr input) { 37 | bci.break_(outer); 38 | } 39 | 40 | public boolean equals(final Object obj) { 41 | return obj instanceof BreakKey bk && equals(bk); 42 | } 43 | 44 | public boolean equals(final BreakKey other) { 45 | return this == other || other != null && outer == other.outer; 46 | } 47 | 48 | public int hashCode() { 49 | return Objects.hash(BreakKey.class, outer); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Cast.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.function.BiFunction; 5 | 6 | import io.quarkus.gizmo2.Expr; 7 | import io.quarkus.gizmo2.GenericType; 8 | 9 | abstract class Cast extends Item { 10 | final Item a; 11 | final GenericType toType; 12 | 13 | public Cast(final Expr a, final GenericType toType) { 14 | this.a = (Item) a; 15 | this.toType = toType; 16 | } 17 | 18 | protected Node forEachDependency(final Node node, final BiFunction op) { 19 | return a.process(node.prev(), op); 20 | } 21 | 22 | public GenericType genericType() { 23 | return toType; 24 | } 25 | 26 | public ClassDesc type() { 27 | return toType.desc(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/CheckCast.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.annotation.RetentionPolicy; 4 | import java.util.ArrayDeque; 5 | import java.util.ArrayList; 6 | 7 | import io.github.dmlloyd.classfile.CodeBuilder; 8 | import io.github.dmlloyd.classfile.Label; 9 | import io.github.dmlloyd.classfile.TypeAnnotation; 10 | import io.quarkus.gizmo2.Expr; 11 | import io.quarkus.gizmo2.GenericType; 12 | 13 | final class CheckCast extends Cast { 14 | private Label label; 15 | 16 | CheckCast(final Expr a, final GenericType toType) { 17 | super(a, toType); 18 | } 19 | 20 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 21 | label = cb.newBoundLabel(); 22 | cb.checkcast(toType.desc()); 23 | } 24 | 25 | public void writeAnnotations(final RetentionPolicy retention, final ArrayList annotations) { 26 | if (toType.hasAnnotations(retention)) { 27 | Util.computeAnnotations(toType, retention, TypeAnnotation.TargetInfo.ofCastExpr(label, 0), annotations, 28 | new ArrayDeque<>()); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ClassMethodDescImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.constant.MethodTypeDesc; 5 | 6 | import io.quarkus.gizmo2.desc.ClassMethodDesc; 7 | 8 | public final class ClassMethodDescImpl extends MethodDescImpl implements ClassMethodDesc { 9 | public ClassMethodDescImpl(final ClassDesc owner, final String name, final MethodTypeDesc type) { 10 | super(owner, name, type); 11 | } 12 | 13 | public boolean equals(final MethodDescImpl obj) { 14 | return obj instanceof ClassMethodDescImpl other && super.equals(other); 15 | } 16 | 17 | public StringBuilder toString(final StringBuilder b) { 18 | b.append("ClassMethod["); 19 | Util.descName(b, owner()); 20 | b.append('#').append(name()); 21 | b.append(type().descriptorString()); 22 | return b.append(']'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ClassStaticFieldCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.quarkus.gizmo2.creator.ModifierLocation; 6 | 7 | public final class ClassStaticFieldCreatorImpl extends StaticFieldCreatorImpl { 8 | public ClassStaticFieldCreatorImpl(final TypeCreatorImpl tc, final ClassDesc owner, final String name) { 9 | super(tc, owner, name); 10 | } 11 | 12 | public ModifierLocation modifierLocation() { 13 | return ModifierLocation.CLASS_STATIC_FIELD; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ClassSwitchCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static java.lang.constant.ConstantDescs.*; 4 | 5 | import java.lang.constant.ClassDesc; 6 | import java.lang.constant.MethodTypeDesc; 7 | 8 | import io.github.dmlloyd.classfile.CodeBuilder; 9 | import io.github.dmlloyd.classfile.Label; 10 | import io.quarkus.gizmo2.Expr; 11 | import io.quarkus.gizmo2.impl.constant.ClassConst; 12 | 13 | /** 14 | * A switch over {@code Class} objects. 15 | */ 16 | public final class ClassSwitchCreatorImpl extends HashSwitchCreatorImpl { 17 | ClassSwitchCreatorImpl(final BlockCreatorImpl enclosing, final Expr switchVal, final ClassDesc type) { 18 | super(enclosing, switchVal, type, ClassConst.class); 19 | } 20 | 21 | boolean staticEquals(final ClassConst a, final ClassConst b) { 22 | return a.desc().equals(b.desc()); 23 | } 24 | 25 | void equaller(final CodeBuilder cb, final ClassConst value, final Label ifEq) { 26 | value.writeCode(cb, enclosing); 27 | cb.if_acmpeq(ifEq); 28 | } 29 | 30 | int staticHash(final ClassConst val) { 31 | ClassDesc desc = val.desc(); 32 | if (desc.isArray()) { 33 | return desc.descriptorString().hashCode(); 34 | } else if (desc.isPrimitive()) { 35 | return desc.displayName().hashCode(); 36 | } else { 37 | return Util.binaryName(desc).hashCode(); 38 | } 39 | } 40 | 41 | void hash(final CodeBuilder cb) { 42 | cb.invokevirtual(CD_Class, "getName", MethodTypeDesc.of(CD_String)); 43 | cb.invokevirtual(CD_String, "hashCode", MethodTypeDesc.of(CD_int)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ConstructorDescImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.constant.ConstantDescs; 5 | import java.lang.constant.MethodTypeDesc; 6 | import java.util.Objects; 7 | 8 | import io.quarkus.gizmo2.desc.ConstructorDesc; 9 | 10 | public final class ConstructorDescImpl implements ConstructorDesc { 11 | private final ClassDesc owner; 12 | private final MethodTypeDesc type; 13 | private final int hashCode; 14 | 15 | public ConstructorDescImpl(final ClassDesc owner, final MethodTypeDesc type) { 16 | if (!ConstantDescs.CD_void.equals(type.returnType())) { 17 | throw new IllegalArgumentException("Constructor descriptor must have a return type of void"); 18 | } 19 | this.owner = owner; 20 | this.type = type; 21 | hashCode = Objects.hash(owner, "", type); 22 | } 23 | 24 | public ClassDesc owner() { 25 | return owner; 26 | } 27 | 28 | public String name() { 29 | return ""; 30 | } 31 | 32 | public MethodTypeDesc type() { 33 | return type; 34 | } 35 | 36 | public boolean equals(final Object obj) { 37 | return obj instanceof ConstructorDescImpl other && equals(other); 38 | } 39 | 40 | public boolean equals(final ConstructorDescImpl other) { 41 | return this == other 42 | || other != null && hashCode == other.hashCode && owner.equals(other.owner) && type.equals(other.type); 43 | } 44 | 45 | public int hashCode() { 46 | return hashCode; 47 | } 48 | 49 | public StringBuilder toString(final StringBuilder b) { 50 | b.append("Constructor["); 51 | Util.descName(b, owner); 52 | b.append("#"); 53 | b.append(type.descriptorString()); 54 | return b.append(']'); 55 | } 56 | 57 | public String toString() { 58 | return toString(new StringBuilder()).toString(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/DefaultMethodCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import io.quarkus.gizmo2.creator.BlockCreator; 6 | import io.quarkus.gizmo2.creator.InstanceMethodCreator; 7 | import io.quarkus.gizmo2.creator.ModifierLocation; 8 | 9 | public final class DefaultMethodCreatorImpl extends MethodCreatorImpl implements InstanceMethodCreator { 10 | DefaultMethodCreatorImpl(final TypeCreatorImpl owner, final String name) { 11 | super(owner, name); 12 | } 13 | 14 | public ModifierLocation modifierLocation() { 15 | return ModifierLocation.INTERFACE_DEFAULT_METHOD; 16 | } 17 | 18 | public void body(final Consumer builder) { 19 | super.body(builder); 20 | } 21 | 22 | void accept(final Consumer builder) { 23 | builder.accept(this); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Dup.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.function.BiFunction; 5 | 6 | import io.github.dmlloyd.classfile.CodeBuilder; 7 | import io.quarkus.gizmo2.GenericType; 8 | 9 | final class Dup extends Item { 10 | private final Item input; 11 | 12 | Dup(final Item input) { 13 | this.input = input; 14 | } 15 | 16 | public ClassDesc type() { 17 | return input.type(); 18 | } 19 | 20 | public GenericType genericType() { 21 | return input.genericType(); 22 | } 23 | 24 | public Node pop(final Node node) { 25 | // a dup can always be safely removed in lieu of a pop 26 | Node prev = node.prev(); 27 | node.remove(); 28 | return prev; 29 | } 30 | 31 | Node verify(Node node) { 32 | super.verify(node); 33 | // re-process the node 34 | return node.prev(); 35 | } 36 | 37 | protected Node process(final Node node, final BiFunction op) { 38 | Node prev = node.prev(); 39 | super.process(node, op); 40 | return prev; 41 | } 42 | 43 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 44 | switch (typeKind().slotSize()) { 45 | case 2 -> cb.dup2(); 46 | case 1 -> cb.dup(); 47 | case 0 -> { 48 | } 49 | default -> throw new IllegalStateException(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/EnumOrdinalSwitchCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static java.lang.constant.ConstantDescs.*; 4 | 5 | import java.lang.constant.ClassDesc; 6 | import java.lang.constant.MethodTypeDesc; 7 | import java.util.List; 8 | import java.util.NoSuchElementException; 9 | import java.util.stream.Stream; 10 | 11 | import io.github.dmlloyd.classfile.CodeBuilder; 12 | import io.quarkus.gizmo2.Expr; 13 | import io.quarkus.gizmo2.impl.constant.EnumConst; 14 | 15 | /** 16 | * A switch over a single {@code enum} type by ordinal value. 17 | * Such switches are incompatible across modules in the event that the set of {@code enum} constants 18 | * changes. 19 | */ 20 | public final class EnumOrdinalSwitchCreatorImpl extends PerfectHashSwitchCreatorImpl { 21 | final List constants; 22 | 23 | EnumOrdinalSwitchCreatorImpl(final BlockCreatorImpl enclosing, final Expr switchVal, final ClassDesc type, 24 | final Class> enumClass) { 25 | super(enclosing, switchVal, type, EnumConst.class); 26 | constants = Stream.of(enumClass.getEnumConstants()).map(EnumConst::of).map(EnumConst.class::cast).toList(); 27 | } 28 | 29 | int staticHash(final EnumConst val) { 30 | int idx = constants.indexOf(val); 31 | if (idx == -1) { 32 | throw new NoSuchElementException("No known enum constant " + val); 33 | } 34 | return idx; 35 | } 36 | 37 | void hash(final CodeBuilder cb) { 38 | cb.invokevirtual(CD_Enum, "ordinal", MethodTypeDesc.of(CD_int)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/EnumSwitchCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static java.lang.constant.ConstantDescs.*; 4 | 5 | import java.lang.constant.ClassDesc; 6 | import java.lang.constant.MethodTypeDesc; 7 | 8 | import io.github.dmlloyd.classfile.CodeBuilder; 9 | import io.github.dmlloyd.classfile.Label; 10 | import io.quarkus.gizmo2.Expr; 11 | import io.quarkus.gizmo2.impl.constant.EnumConst; 12 | 13 | /** 14 | * A switch over {@code enum} values. 15 | */ 16 | public final class EnumSwitchCreatorImpl extends HashSwitchCreatorImpl { 17 | EnumSwitchCreatorImpl(final BlockCreatorImpl enclosing, final Expr switchVal, final ClassDesc type) { 18 | super(enclosing, switchVal, type, EnumConst.class); 19 | } 20 | 21 | boolean staticEquals(final EnumConst a, final EnumConst b) { 22 | return a.equals(b); 23 | } 24 | 25 | void equaller(final CodeBuilder cb, final EnumConst value, final Label ifEq) { 26 | value.writeCode(cb, enclosing); 27 | cb.if_acmpeq(ifEq); 28 | } 29 | 30 | int staticHash(final EnumConst val) { 31 | return val.name().hashCode(); 32 | } 33 | 34 | void hash(final CodeBuilder cb) { 35 | cb.invokevirtual(CD_Enum, "name", MethodTypeDesc.of(CD_String)); 36 | cb.invokevirtual(CD_String, "hashCode", MethodTypeDesc.of(CD_int)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/FieldDeref.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.function.BiFunction; 5 | 6 | import io.github.dmlloyd.classfile.CodeBuilder; 7 | import io.quarkus.gizmo2.GenericType; 8 | import io.quarkus.gizmo2.InstanceFieldVar; 9 | import io.quarkus.gizmo2.MemoryOrder; 10 | import io.quarkus.gizmo2.desc.FieldDesc; 11 | 12 | public final class FieldDeref extends AssignableImpl implements InstanceFieldVar { 13 | private final Item item; 14 | private final FieldDesc desc; 15 | private final GenericType genericType; 16 | private boolean bound; 17 | 18 | FieldDeref(final Item item, final FieldDesc desc, final GenericType genericType) { 19 | this.item = item; 20 | this.desc = desc; 21 | this.genericType = genericType; 22 | } 23 | 24 | protected Node forEachDependency(final Node node, final BiFunction op) { 25 | return item.process(node.prev(), op); 26 | } 27 | 28 | public boolean bound() { 29 | return bound; 30 | } 31 | 32 | protected void bind() { 33 | if (item.bound()) { 34 | bound = true; 35 | } 36 | } 37 | 38 | public FieldDesc desc() { 39 | return desc; 40 | } 41 | 42 | @Override 43 | public ClassDesc type() { 44 | return desc.type(); 45 | } 46 | 47 | public GenericType genericType() { 48 | return genericType; 49 | } 50 | 51 | public String itemName() { 52 | return item.itemName() + "." + desc.name(); 53 | } 54 | 55 | public Item instance() { 56 | return item; 57 | } 58 | 59 | Item emitGet(final BlockCreatorImpl block, final MemoryOrder mode) { 60 | return switch (mode) { 61 | case AsDeclared -> asBound(); 62 | default -> new FieldGetViaHandle(this, mode); 63 | }; 64 | } 65 | 66 | Item emitSet(final BlockCreatorImpl block, final Item value, final MemoryOrder mode) { 67 | return switch (mode) { 68 | case AsDeclared -> new FieldSet(this, value); 69 | default -> new FieldSetViaHandle(this, value, mode); 70 | }; 71 | } 72 | 73 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 74 | cb.getfield(owner(), name(), type()); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/FieldDescImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.Objects; 5 | 6 | import io.quarkus.gizmo2.desc.FieldDesc; 7 | 8 | public final class FieldDescImpl implements FieldDesc { 9 | private final ClassDesc owner; 10 | private final String name; 11 | private final ClassDesc type; 12 | private final int hashCode; 13 | 14 | public FieldDescImpl(final ClassDesc owner, final String name, final ClassDesc type) { 15 | this.owner = owner; 16 | this.name = name; 17 | this.type = type; 18 | hashCode = Objects.hash(owner, name, type); 19 | } 20 | 21 | public ClassDesc owner() { 22 | return owner; 23 | } 24 | 25 | public String name() { 26 | return name; 27 | } 28 | 29 | public ClassDesc type() { 30 | return type; 31 | } 32 | 33 | public boolean equals(final Object obj) { 34 | return obj instanceof FieldDescImpl other && equals(other); 35 | } 36 | 37 | public boolean equals(final FieldDescImpl other) { 38 | return this == other || other != null && hashCode == other.hashCode && name.equals(other.name) 39 | && owner.equals(other.owner) && type.equals(other.type); 40 | } 41 | 42 | public int hashCode() { 43 | return hashCode; 44 | } 45 | 46 | public StringBuilder toString(final StringBuilder b) { 47 | return Util.descName(Util.descName(b, owner).append('#').append(name).append(':'), type); 48 | } 49 | 50 | public String toString() { 51 | return toString(new StringBuilder()).toString(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/FieldGetViaHandle.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.smallrye.common.constraint.Assert.impossibleSwitchCase; 4 | import static java.lang.constant.ConstantDescs.*; 5 | 6 | import java.lang.constant.ClassDesc; 7 | import java.lang.constant.MethodTypeDesc; 8 | import java.util.function.BiFunction; 9 | 10 | import io.github.dmlloyd.classfile.CodeBuilder; 11 | import io.quarkus.gizmo2.MemoryOrder; 12 | import io.quarkus.gizmo2.impl.constant.ConstImpl; 13 | 14 | final class FieldGetViaHandle extends Item { 15 | private final FieldDeref fieldDeref; 16 | private final MemoryOrder mode; 17 | 18 | FieldGetViaHandle(final FieldDeref fieldDeref, final MemoryOrder mode) { 19 | this.fieldDeref = fieldDeref; 20 | this.mode = mode; 21 | } 22 | 23 | public ClassDesc type() { 24 | return fieldDeref.type(); 25 | } 26 | 27 | protected Node forEachDependency(final Node node, final BiFunction op) { 28 | return ConstImpl.ofFieldVarHandle(fieldDeref.desc()).process(fieldDeref.instance().process(node.prev(), op), op); 29 | } 30 | 31 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 32 | cb.invokevirtual(CD_VarHandle, switch (mode) { 33 | case Plain -> "get"; 34 | case Opaque -> "getOpaque"; 35 | case Acquire -> "getAcquire"; 36 | case Volatile -> "getVolatile"; 37 | default -> throw impossibleSwitchCase(mode); 38 | }, MethodTypeDesc.of(type(), fieldDeref.instance().type())); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/FieldSet.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.BiFunction; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | 7 | final class FieldSet extends Item { 8 | private final FieldDeref fieldDeref; 9 | private final Item value; 10 | 11 | FieldSet(final FieldDeref fieldDeref, final Item value) { 12 | this.fieldDeref = fieldDeref; 13 | this.value = value; 14 | } 15 | 16 | protected Node forEachDependency(final Node node, final BiFunction op) { 17 | return fieldDeref.instance().process(value.process(node.prev(), op), op); 18 | } 19 | 20 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 21 | cb.putfield(fieldDeref.owner(), fieldDeref.name(), fieldDeref.desc().type()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/FieldSetViaHandle.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.smallrye.common.constraint.Assert.impossibleSwitchCase; 4 | import static java.lang.constant.ConstantDescs.*; 5 | 6 | import java.lang.constant.MethodTypeDesc; 7 | import java.util.function.BiFunction; 8 | 9 | import io.github.dmlloyd.classfile.CodeBuilder; 10 | import io.quarkus.gizmo2.MemoryOrder; 11 | import io.quarkus.gizmo2.impl.constant.ConstImpl; 12 | 13 | final class FieldSetViaHandle extends Item { 14 | private final FieldDeref fieldDeref; 15 | private final Item value; 16 | private final MemoryOrder mode; 17 | 18 | FieldSetViaHandle(final FieldDeref fieldDeref, final Item value, final MemoryOrder mode) { 19 | this.fieldDeref = fieldDeref; 20 | this.value = value; 21 | this.mode = mode; 22 | } 23 | 24 | protected Node forEachDependency(Node node, final BiFunction op) { 25 | return ConstImpl.ofFieldVarHandle(fieldDeref.desc()) 26 | .process(fieldDeref.instance().process(value.process(node.prev(), op), op), op); 27 | } 28 | 29 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 30 | cb.invokevirtual(CD_VarHandle, switch (mode) { 31 | case Plain -> "set"; 32 | case Opaque -> "setOpaque"; 33 | case Release -> "setRelease"; 34 | case Volatile -> "setVolatile"; 35 | default -> throw impossibleSwitchCase(mode); 36 | }, MethodTypeDesc.of(CD_void, fieldDeref.instance().type(), fieldDeref.desc().type())); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Goto.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import io.github.dmlloyd.classfile.CodeBuilder; 4 | import io.github.dmlloyd.classfile.Label; 5 | 6 | abstract class Goto extends Item { 7 | Goto() { 8 | } 9 | 10 | public boolean mayFallThrough() { 11 | return false; 12 | } 13 | 14 | /** 15 | * {@return the target label} 16 | * Must only be called from {@link Item#writeCode(CodeBuilder, BlockCreatorImpl)}. 17 | * 18 | * @param from the block that is the originating point of the jump (must not be {@code null}) 19 | */ 20 | abstract Label target(BlockCreatorImpl from); 21 | 22 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 23 | cb.goto_(target(block)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/GotoCase.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.Objects; 4 | 5 | import io.github.dmlloyd.classfile.Label; 6 | import io.quarkus.gizmo2.Const; 7 | import io.quarkus.gizmo2.Expr; 8 | import io.quarkus.gizmo2.creator.SwitchCreator; 9 | 10 | class GotoCase extends Goto { 11 | private final SwitchCreator switch_; 12 | private final Const case_; 13 | 14 | public GotoCase(final SwitchCreator switch_, final Const case_) { 15 | this.switch_ = switch_; 16 | this.case_ = case_; 17 | } 18 | 19 | Label target(final BlockCreatorImpl from) { 20 | TryFinally tryFinally = from.tryFinally; 21 | SwitchCreatorImpl sci = (SwitchCreatorImpl) switch_; 22 | if (tryFinally != null) { 23 | return tryFinally.cleanup(new GotoCaseKey(sci, case_)); 24 | } else { 25 | return findBlock(sci, case_).startLabel(); 26 | } 27 | } 28 | 29 | private static BlockCreatorImpl findBlock(final SwitchCreatorImpl sci, final Const case_) { 30 | SwitchCreatorImpl.CaseCreatorImpl matched = sci.findCase(case_); 31 | if (matched == null) { 32 | return sci.default_; 33 | } 34 | return matched.body; 35 | } 36 | 37 | static class GotoCaseKey extends TryFinally.CleanupKey { 38 | private final SwitchCreatorImpl switch_; 39 | private final Const case_; 40 | 41 | GotoCaseKey(final SwitchCreatorImpl switch_, final Const case_) { 42 | this.switch_ = switch_; 43 | this.case_ = case_; 44 | } 45 | 46 | void terminate(final BlockCreatorImpl bci, final Expr input) { 47 | bci.gotoCase(switch_, case_); 48 | } 49 | 50 | public boolean equals(final Object obj) { 51 | return obj instanceof GotoCaseKey rk && equals(rk); 52 | } 53 | 54 | public boolean equals(final GotoCaseKey other) { 55 | return this == other || other != null && switch_ == other.switch_ && case_.equals(other.case_); 56 | } 57 | 58 | public int hashCode() { 59 | return Objects.hash(GotoCaseKey.class, switch_, case_); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/GotoDefault.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.Objects; 4 | 5 | import io.github.dmlloyd.classfile.Label; 6 | import io.quarkus.gizmo2.Expr; 7 | import io.quarkus.gizmo2.creator.SwitchCreator; 8 | 9 | class GotoDefault extends Goto { 10 | private final SwitchCreator switch_; 11 | 12 | public GotoDefault(final SwitchCreator switch_) { 13 | this.switch_ = switch_; 14 | } 15 | 16 | Label target(final BlockCreatorImpl from) { 17 | TryFinally tryFinally = from.tryFinally; 18 | SwitchCreatorImpl sci = (SwitchCreatorImpl) switch_; 19 | if (tryFinally != null) { 20 | return tryFinally.cleanup(new GotoDefaultKey(sci)); 21 | } else { 22 | return sci.findDefault().startLabel(); 23 | } 24 | } 25 | 26 | static class GotoDefaultKey extends TryFinally.CleanupKey { 27 | private final SwitchCreatorImpl switch_; 28 | 29 | GotoDefaultKey(final SwitchCreatorImpl switch_) { 30 | this.switch_ = switch_; 31 | } 32 | 33 | void terminate(final BlockCreatorImpl bci, final Expr input) { 34 | bci.gotoDefault(switch_); 35 | } 36 | 37 | public boolean equals(final Object obj) { 38 | return obj instanceof GotoDefaultKey rk && equals(rk); 39 | } 40 | 41 | public boolean equals(final GotoDefaultKey other) { 42 | return this == other || other != null && switch_ == other.switch_; 43 | } 44 | 45 | public int hashCode() { 46 | return Objects.hash(GotoDefaultKey.class, switch_); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/GotoStart.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.Objects; 4 | 5 | import io.github.dmlloyd.classfile.Label; 6 | import io.quarkus.gizmo2.Expr; 7 | import io.quarkus.gizmo2.creator.BlockCreator; 8 | 9 | final class GotoStart extends Goto { 10 | private final BlockCreatorImpl outer; 11 | 12 | GotoStart(final BlockCreator outer) { 13 | this.outer = (BlockCreatorImpl) outer; 14 | } 15 | 16 | public String itemName() { 17 | return "GotoStart:" + outer; 18 | } 19 | 20 | Label target(final BlockCreatorImpl from) { 21 | TryFinally tryFinally = from.tryFinally; 22 | if (tryFinally != null) { 23 | return tryFinally.cleanup(new GotoStartKey(outer)); 24 | } else { 25 | return outer.startLabel(); 26 | } 27 | } 28 | 29 | static class GotoStartKey extends TryFinally.CleanupKey { 30 | private final BlockCreatorImpl outer; 31 | 32 | GotoStartKey(final BlockCreatorImpl outer) { 33 | this.outer = outer; 34 | } 35 | 36 | void terminate(final BlockCreatorImpl bci, final Expr input) { 37 | bci.goto_(outer); 38 | } 39 | 40 | public boolean equals(final Object obj) { 41 | return obj instanceof GotoStartKey rk && equals(rk); 42 | } 43 | 44 | public boolean equals(final GotoStartKey other) { 45 | return this == other || other != null && outer == other.outer; 46 | } 47 | 48 | public int hashCode() { 49 | return Objects.hash(GotoStartKey.class, outer); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/IfRel.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.function.BiFunction; 5 | 6 | final class IfRel extends If { 7 | final Item a, b; 8 | 9 | IfRel(final ClassDesc type, final Kind kind, final BlockCreatorImpl whenTrue, final BlockCreatorImpl whenFalse, 10 | final Item a, final Item b) { 11 | super(type, kind, whenTrue, whenFalse); 12 | this.a = a; 13 | this.b = b; 14 | } 15 | 16 | protected Node forEachDependency(final Node node, final BiFunction op) { 17 | return a.process(b.process(node.prev(), op), op); 18 | } 19 | 20 | IfOp op(final Kind kind) { 21 | return switch (a.typeKind().asLoadable()) { 22 | case INT -> kind.if_icmp; 23 | case REFERENCE -> kind.if_acmp; 24 | default -> throw new IllegalStateException(); 25 | }; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/IfZero.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.quarkus.gizmo2.impl.Conversions.convert; 4 | import static java.lang.constant.ConstantDescs.CD_boolean; 5 | 6 | import java.lang.constant.ClassDesc; 7 | import java.util.function.BiFunction; 8 | 9 | final class IfZero extends If { 10 | final Item a; 11 | 12 | IfZero(final ClassDesc type, final Kind kind, final BlockCreatorImpl whenTrue, final BlockCreatorImpl whenFalse, 13 | final Item a, final boolean mustBeBoolean) { 14 | super(type, kind, whenTrue, whenFalse); 15 | this.a = mustBeBoolean ? convert(a, CD_boolean) : a; 16 | } 17 | 18 | protected Node forEachDependency(final Node node, final BiFunction op) { 19 | return a.process(node.prev(), op); 20 | } 21 | 22 | IfOp op(final Kind kind) { 23 | return switch (a.typeKind().asLoadable()) { 24 | case INT -> kind.if_; 25 | case REFERENCE -> kind.if_acmpnull; 26 | default -> throw new IllegalStateException(); 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/InstanceFieldCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.function.Consumer; 5 | 6 | import io.github.dmlloyd.classfile.attribute.SignatureAttribute; 7 | import io.quarkus.gizmo2.Const; 8 | import io.quarkus.gizmo2.creator.BlockCreator; 9 | import io.quarkus.gizmo2.creator.InstanceFieldCreator; 10 | import io.quarkus.gizmo2.creator.ModifierLocation; 11 | import io.quarkus.gizmo2.desc.FieldDesc; 12 | import io.smallrye.common.constraint.Assert; 13 | 14 | public final class InstanceFieldCreatorImpl extends FieldCreatorImpl implements InstanceFieldCreator { 15 | 16 | private Const initial; 17 | private Consumer initializer; 18 | 19 | public InstanceFieldCreatorImpl(final TypeCreatorImpl tc, final ClassDesc owner, final String name) { 20 | super(owner, name, tc); 21 | } 22 | 23 | public ModifierLocation modifierLocation() { 24 | return ModifierLocation.CLASS_INSTANCE_FIELD; 25 | } 26 | 27 | public void setInitial(final Const initial) { 28 | Assert.checkNotNullParam("initial", initial); 29 | checkOneInit(); 30 | setType(initial.type()); 31 | this.initial = initial; 32 | } 33 | 34 | public void setInitializer(final Consumer init) { 35 | Assert.checkNotNullParam("init", init); 36 | checkOneInit(); 37 | initializer = (b0 -> { 38 | FieldDesc desc = desc(); 39 | b0.set(tc.this_().field(desc), b0.blockExpr(desc.type(), init)); 40 | }); 41 | } 42 | 43 | private void checkOneInit() { 44 | if (initial != null || initializer != null) { 45 | throw new IllegalStateException("An instance field may have only one initializer"); 46 | } 47 | } 48 | 49 | void accept(final Consumer builder) { 50 | builder.accept(this); 51 | if (initial != null) { 52 | tc.instancePreinitializer(b0 -> b0.set(tc.this_().field(desc()), initial)); 53 | } else if (initializer != null) { 54 | tc.instanceInitializer(initializer); 55 | } 56 | tc.zb.withField(name(), desc().type(), fb -> { 57 | fb.withFlags(modifiers); 58 | fb.with(SignatureAttribute.of(Util.signatureOf(genericType()))); 59 | addVisible(fb); 60 | addInvisible(fb); 61 | addTypeAnnotations(fb); 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/InstanceMethodCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import io.quarkus.gizmo2.creator.BlockCreator; 6 | import io.quarkus.gizmo2.creator.InstanceMethodCreator; 7 | import io.quarkus.gizmo2.creator.ModifierLocation; 8 | 9 | public final class InstanceMethodCreatorImpl extends MethodCreatorImpl implements InstanceMethodCreator { 10 | InstanceMethodCreatorImpl(final TypeCreatorImpl owner, final String name) { 11 | super(owner, name); 12 | } 13 | 14 | public void body(final Consumer builder) { 15 | super.body(builder); 16 | } 17 | 18 | void accept(final Consumer builder) { 19 | builder.accept(this); 20 | } 21 | 22 | public ModifierLocation modifierLocation() { 23 | return ModifierLocation.CLASS_INSTANCE_METHOD; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/InstanceOf.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.annotation.RetentionPolicy; 4 | import java.lang.constant.ClassDesc; 5 | import java.lang.constant.ConstantDescs; 6 | import java.util.ArrayDeque; 7 | import java.util.ArrayList; 8 | import java.util.function.BiFunction; 9 | 10 | import io.github.dmlloyd.classfile.CodeBuilder; 11 | import io.github.dmlloyd.classfile.Label; 12 | import io.github.dmlloyd.classfile.TypeAnnotation; 13 | import io.quarkus.gizmo2.Expr; 14 | import io.quarkus.gizmo2.GenericType; 15 | 16 | final class InstanceOf extends Item { 17 | private final Item input; 18 | private final GenericType type; 19 | private Label label; 20 | 21 | InstanceOf(final Expr input, final GenericType type) { 22 | this.input = (Item) input; 23 | this.type = type; 24 | } 25 | 26 | public ClassDesc type() { 27 | return ConstantDescs.CD_boolean; 28 | } 29 | 30 | protected Node forEachDependency(final Node node, final BiFunction op) { 31 | return input.process(node.prev(), op); 32 | } 33 | 34 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 35 | label = cb.newBoundLabel(); 36 | cb.instanceOf(type.desc()); 37 | } 38 | 39 | public void writeAnnotations(final RetentionPolicy retention, final ArrayList annotations) { 40 | if (type.hasAnnotations(retention)) { 41 | Util.computeAnnotations(type, retention, TypeAnnotation.TargetInfo.ofInstanceofExpr(label), annotations, 42 | new ArrayDeque<>()); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/IntSwitchCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | import io.quarkus.gizmo2.Expr; 7 | import io.quarkus.gizmo2.impl.constant.IntConst; 8 | 9 | /** 10 | * A switch over {@code int} values. 11 | */ 12 | public final class IntSwitchCreatorImpl extends PerfectHashSwitchCreatorImpl { 13 | IntSwitchCreatorImpl(final BlockCreatorImpl enclosing, final Expr switchVal, final ClassDesc type) { 14 | super(enclosing, switchVal, type, IntConst.class); 15 | } 16 | 17 | int staticHash(final IntConst val) { 18 | return val.intValue(); 19 | } 20 | 21 | void hash(final CodeBuilder cb) { 22 | // no operation (int value is already on stack) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/InterfaceMethodCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import io.quarkus.gizmo2.creator.AbstractMethodCreator; 6 | import io.quarkus.gizmo2.creator.ModifierLocation; 7 | 8 | public final class InterfaceMethodCreatorImpl extends MethodCreatorImpl implements AbstractMethodCreator { 9 | InterfaceMethodCreatorImpl(final TypeCreatorImpl owner, final String name) { 10 | super(owner, name); 11 | } 12 | 13 | public ModifierLocation modifierLocation() { 14 | return ModifierLocation.INTERFACE_ABSTRACT_METHOD; 15 | } 16 | 17 | void accept(final Consumer builder) { 18 | builder.accept(this); 19 | typeCreator.zb.withMethod(name(), type(), modifiers, mb -> { 20 | doBody(null, mb); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/InterfaceMethodDescImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.constant.MethodTypeDesc; 5 | 6 | import io.quarkus.gizmo2.desc.InterfaceMethodDesc; 7 | 8 | public final class InterfaceMethodDescImpl extends MethodDescImpl implements InterfaceMethodDesc { 9 | public InterfaceMethodDescImpl(final ClassDesc owner, final String name, final MethodTypeDesc type) { 10 | super(owner, name, type); 11 | } 12 | 13 | public boolean equals(final MethodDescImpl obj) { 14 | return obj instanceof InterfaceMethodDescImpl other && super.equals(other); 15 | } 16 | 17 | public StringBuilder toString(final StringBuilder b) { 18 | b.append("InterfaceMethod["); 19 | Util.descName(b, owner()); 20 | b.append('#').append(name()); 21 | b.append(type().descriptorString()); 22 | return b.append(']'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/InterfaceStaticFieldCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.quarkus.gizmo2.creator.ModifierLocation; 6 | 7 | public final class InterfaceStaticFieldCreatorImpl extends StaticFieldCreatorImpl { 8 | public InterfaceStaticFieldCreatorImpl(final TypeCreatorImpl tc, final ClassDesc owner, final String name) { 9 | super(tc, owner, name); 10 | } 11 | 12 | public ModifierLocation modifierLocation() { 13 | return ModifierLocation.INTERFACE_STATIC_FIELD; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/InvokeDynamic.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.constant.DynamicCallSiteDesc; 5 | import java.util.List; 6 | import java.util.function.BiFunction; 7 | 8 | import io.github.dmlloyd.classfile.CodeBuilder; 9 | import io.quarkus.gizmo2.Expr; 10 | 11 | final class InvokeDynamic extends Item { 12 | private final List args; 13 | private final DynamicCallSiteDesc callSiteDesc; 14 | 15 | InvokeDynamic(final List args, final DynamicCallSiteDesc callSiteDesc) { 16 | this.args = args; 17 | this.callSiteDesc = callSiteDesc; 18 | } 19 | 20 | protected Node forEachDependency(Node node, final BiFunction op) { 21 | node = node.prev(); 22 | for (int i = args.size() - 1; i >= 0; i--) { 23 | final Item arg = (Item) args.get(i); 24 | node = arg.process(node, op); 25 | } 26 | return node; 27 | } 28 | 29 | public ClassDesc type() { 30 | return callSiteDesc.invocationType().returnType(); 31 | } 32 | 33 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 34 | cb.invokedynamic(callSiteDesc); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/LambdaCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.function.Consumer; 5 | 6 | import io.quarkus.gizmo2.Expr; 7 | import io.quarkus.gizmo2.ParamVar; 8 | import io.quarkus.gizmo2.Var; 9 | import io.quarkus.gizmo2.creator.BlockCreator; 10 | import io.quarkus.gizmo2.creator.LambdaCreator; 11 | 12 | public final class LambdaCreatorImpl implements LambdaCreator { 13 | private final AnonymousClassCreatorImpl acc; 14 | private final InstanceMethodCreatorImpl sam; 15 | 16 | public LambdaCreatorImpl(final AnonymousClassCreatorImpl acc, final InstanceMethodCreatorImpl sam) { 17 | this.acc = acc; 18 | this.sam = sam; 19 | } 20 | 21 | public ClassDesc type() { 22 | return acc.type(); 23 | } 24 | 25 | public ParamVar parameter(final String name, final int position) { 26 | return sam.parameter(name, position); 27 | } 28 | 29 | public void body(final Consumer builder) { 30 | sam.body(builder); 31 | } 32 | 33 | public Var capture(final String name, final Expr value) { 34 | return acc.capture(name, value); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/LineNumber.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import io.github.dmlloyd.classfile.CodeBuilder; 4 | 5 | final class LineNumber extends Item { 6 | private final int lineNumber; 7 | 8 | LineNumber(final int lineNumber) { 9 | this.lineNumber = lineNumber; 10 | } 11 | 12 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 13 | cb.lineNumber(lineNumber); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/LocalVarAllocator.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.annotation.RetentionPolicy; 4 | import java.util.ArrayDeque; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import io.github.dmlloyd.classfile.CodeBuilder; 9 | import io.github.dmlloyd.classfile.Label; 10 | import io.github.dmlloyd.classfile.TypeAnnotation; 11 | import io.quarkus.gizmo2.GenericType; 12 | 13 | final class LocalVarAllocator extends Item { 14 | private final LocalVarImpl localVar; 15 | private Label startScope; 16 | private Label endScope; 17 | 18 | LocalVarAllocator(final LocalVarImpl localVar) { 19 | this.localVar = localVar; 20 | } 21 | 22 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 23 | int slot = cb.allocateLocal(Util.actualKindOf(localVar.typeKind())); 24 | // we reserve the slot for the full remainder of the block to avoid control-flow analysis 25 | startScope = cb.newBoundLabel(); 26 | endScope = block.endLabel(); 27 | cb.localVariable(slot, localVar.name(), localVar.type(), startScope, endScope); 28 | GenericType gt = localVar.genericType(); 29 | if (!gt.isRaw()) { 30 | cb.localVariableType(slot, localVar.name(), Util.signatureOf(gt), startScope, endScope); 31 | } 32 | localVar.slot = slot; 33 | } 34 | 35 | public void writeAnnotations(final RetentionPolicy retention, final ArrayList annotations) { 36 | if (localVar.genericType().hasAnnotations(retention)) { 37 | Util.computeAnnotations(localVar.genericType(), retention, TypeAnnotation.TargetInfo.ofLocalVariable( 38 | List.of( 39 | TypeAnnotation.LocalVarTargetInfo.of(startScope, endScope, localVar.slot))), 40 | annotations, new ArrayDeque<>()); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/LocalVarDecrement.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import io.github.dmlloyd.classfile.CodeBuilder; 4 | import io.quarkus.gizmo2.Const; 5 | import io.quarkus.gizmo2.impl.constant.IntBasedConst; 6 | 7 | final class LocalVarDecrement extends Item { 8 | private final LocalVarImpl localVar; 9 | private final Const amount; 10 | 11 | LocalVarDecrement(final LocalVarImpl localVar, final Const amount) { 12 | this.localVar = localVar; 13 | this.amount = amount; 14 | } 15 | 16 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 17 | localVar.checkSlot(); 18 | cb.iinc(localVar.slot, -((IntBasedConst) amount).intValue()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/LocalVarIncrement.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import io.github.dmlloyd.classfile.CodeBuilder; 4 | import io.quarkus.gizmo2.Const; 5 | import io.quarkus.gizmo2.impl.constant.IntBasedConst; 6 | 7 | final class LocalVarIncrement extends Item { 8 | private final LocalVarImpl localVar; 9 | private final Const amount; 10 | 11 | LocalVarIncrement(final LocalVarImpl localVar, final Const amount) { 12 | this.localVar = localVar; 13 | this.amount = amount; 14 | } 15 | 16 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 17 | localVar.checkSlot(); 18 | cb.iinc(localVar.slot, ((IntBasedConst) amount).intValue()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/LocalVarSet.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.BiFunction; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | 7 | final class LocalVarSet extends Item { 8 | private final LocalVarImpl localVar; 9 | private final Item value; 10 | 11 | LocalVarSet(final LocalVarImpl localVar, final Item value) { 12 | this.localVar = localVar; 13 | this.value = value; 14 | } 15 | 16 | protected Node forEachDependency(final Node node, final BiFunction op) { 17 | return value.process(node.prev(), op); 18 | } 19 | 20 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 21 | localVar.checkSlot(); 22 | cb.storeLocal(Util.actualKindOf(localVar.typeKind()), localVar.slot); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/LongSwitchCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static java.lang.constant.ConstantDescs.*; 4 | 5 | import java.lang.constant.ClassDesc; 6 | import java.lang.constant.MethodTypeDesc; 7 | 8 | import io.github.dmlloyd.classfile.CodeBuilder; 9 | import io.github.dmlloyd.classfile.Label; 10 | import io.quarkus.gizmo2.Expr; 11 | import io.quarkus.gizmo2.impl.constant.LongConst; 12 | 13 | /** 14 | * A switch over {@code long} values. 15 | */ 16 | public final class LongSwitchCreatorImpl extends HashSwitchCreatorImpl { 17 | LongSwitchCreatorImpl(final BlockCreatorImpl enclosing, final Expr switchVal, final ClassDesc type) { 18 | super(enclosing, switchVal, type, LongConst.class); 19 | } 20 | 21 | boolean staticEquals(final LongConst a, final LongConst b) { 22 | return a.longValue() == b.longValue(); 23 | } 24 | 25 | void equaller(final CodeBuilder cb, final LongConst value, final Label ifEq) { 26 | value.writeCode(cb, enclosing); 27 | cb.lcmp(); 28 | cb.ifeq(ifEq); 29 | } 30 | 31 | int staticHash(final LongConst val) { 32 | return val.hashCode(); 33 | } 34 | 35 | void hash(final CodeBuilder cb) { 36 | cb.invokestatic(CD_Long, "hashCode", MethodTypeDesc.of(CD_int, CD_long)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/MethodCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.constant.ClassDesc; 5 | import java.util.function.Consumer; 6 | 7 | import io.quarkus.gizmo2.GenericType; 8 | import io.quarkus.gizmo2.creator.MethodCreator; 9 | import io.quarkus.gizmo2.creator.TypeParameterCreator; 10 | import io.quarkus.gizmo2.desc.MethodDesc; 11 | 12 | public abstract sealed class MethodCreatorImpl extends ExecutableCreatorImpl implements MethodCreator 13 | permits AbstractMethodCreatorImpl, DefaultMethodCreatorImpl, InstanceMethodCreatorImpl, NativeMethodCreatorImpl, 14 | InterfaceMethodCreatorImpl, PrivateInterfaceMethodCreatorImpl, StaticMethodCreatorImpl, 15 | StaticInterfaceMethodCreatorImpl { 16 | final String name; 17 | private MethodDesc desc; 18 | 19 | MethodCreatorImpl(final TypeCreatorImpl owner, final String name) { 20 | super(owner); 21 | this.name = name; 22 | } 23 | 24 | public MethodDesc desc() { 25 | MethodDesc desc = this.desc; 26 | if (desc == null) { 27 | this.desc = desc = typeCreator.methodDesc(name(), type()); 28 | } 29 | return desc; 30 | } 31 | 32 | public void returning(final GenericType type) { 33 | super.returning(type); 34 | } 35 | 36 | public void returning(final ClassDesc type) { 37 | super.returning(type); 38 | } 39 | 40 | void clearType() { 41 | desc = null; 42 | super.clearType(); 43 | } 44 | 45 | public String name() { 46 | return name; 47 | } 48 | 49 | public ElementType annotationTargetType() { 50 | return ElementType.METHOD; 51 | } 52 | 53 | @Override 54 | public GenericType.OfTypeVariable typeParameter(final String name, final Consumer builder) { 55 | TypeParameterCreatorImpl creator = new TypeParameterCreatorImpl(name); 56 | builder.accept(creator); 57 | return addTypeParameter(creator.forMethod(desc)).genericType(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/MethodDescImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.constant.MethodTypeDesc; 5 | import java.util.Objects; 6 | 7 | import io.quarkus.gizmo2.desc.MethodDesc; 8 | 9 | public sealed abstract class MethodDescImpl implements MethodDesc permits ClassMethodDescImpl, InterfaceMethodDescImpl { 10 | private final ClassDesc owner; 11 | private final String name; 12 | private final MethodTypeDesc type; 13 | private final int hashCode; 14 | 15 | MethodDescImpl(final ClassDesc owner, final String name, final MethodTypeDesc type) { 16 | this.owner = owner; 17 | this.name = name; 18 | this.type = type; 19 | hashCode = Objects.hash(owner, name, type); 20 | } 21 | 22 | public ClassDesc owner() { 23 | return owner; 24 | } 25 | 26 | public String name() { 27 | return name; 28 | } 29 | 30 | public MethodTypeDesc type() { 31 | return type; 32 | } 33 | 34 | public boolean equals(final Object obj) { 35 | return obj instanceof MethodDescImpl other && equals(other); 36 | } 37 | 38 | public boolean equals(final MethodDescImpl other) { 39 | return this == other || other != null && hashCode == other.hashCode && name.equals(other.name) 40 | && owner.equals(other.owner) && type.equals(other.type); 41 | } 42 | 43 | public int hashCode() { 44 | return hashCode; 45 | } 46 | 47 | public String toString() { 48 | return toString(new StringBuilder()).toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ModifiableCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import io.quarkus.gizmo2.creator.AccessLevel; 4 | import io.quarkus.gizmo2.creator.ModifiableCreator; 5 | import io.quarkus.gizmo2.creator.Modifier; 6 | import io.quarkus.gizmo2.creator.ModifierFlag; 7 | 8 | public abstract sealed class ModifiableCreatorImpl extends AnnotatableCreatorImpl implements ModifiableCreator 9 | permits ExecutableCreatorImpl, FieldCreatorImpl, ParamCreatorImpl, TypeCreatorImpl { 10 | int modifiers; 11 | 12 | ModifiableCreatorImpl(GizmoImpl gizmo) { 13 | modifiers = gizmo.getDefaultModifiers(modifierLocation()); 14 | } 15 | 16 | public void addFlag(final ModifierFlag flag) { 17 | if (requires(flag)) { 18 | // ignore (it's always set) 19 | return; 20 | } else if (supports(flag)) { 21 | flag.forEachExclusive(this::removeFlag); 22 | modifiers |= flag.mask(); 23 | } else { 24 | throw cannotAdd(flag); 25 | } 26 | } 27 | 28 | public void removeFlag(final ModifierFlag flag) { 29 | if (requires(flag)) { 30 | throw cannotRemove(flag); 31 | } else if (!supports(flag)) { 32 | // ignore (it's always clear 33 | return; 34 | } else { 35 | modifiers &= ~flag.mask(); 36 | } 37 | } 38 | 39 | private boolean requires(final ModifierFlag flag) { 40 | return modifierLocation().requires(flag); 41 | } 42 | 43 | public void setAccess(final AccessLevel access) { 44 | if (supports(access)) { 45 | modifiers = modifiers & ~AccessLevel.fullMask() | access.mask(); 46 | } else { 47 | throw unsupported(access); 48 | } 49 | } 50 | 51 | private static IllegalArgumentException unsupported(final AccessLevel modifier) { 52 | return new IllegalArgumentException("Access level \"%s\" cannot be used here".formatted(modifier)); 53 | } 54 | 55 | private static IllegalArgumentException cannotAdd(final Modifier modifier) { 56 | return new IllegalArgumentException("Modifier \"%s\" cannot be added here".formatted(modifier)); 57 | } 58 | 59 | private static IllegalArgumentException cannotRemove(final Modifier modifier) { 60 | return new IllegalArgumentException("Modifier \"%s\" cannot be removed here".formatted(modifier)); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/MonitorEnter.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.BiFunction; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | 7 | final class MonitorEnter extends Item { 8 | private final Item monitor; 9 | 10 | MonitorEnter(final Item monitor) { 11 | this.monitor = monitor; 12 | } 13 | 14 | protected Node forEachDependency(final Node node, final BiFunction op) { 15 | return monitor.process(node.prev(), op); 16 | } 17 | 18 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 19 | cb.monitorenter(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/MonitorExit.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.BiFunction; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | 7 | final class MonitorExit extends Item { 8 | private final Item monitor; 9 | 10 | MonitorExit(final Item monitor) { 11 | this.monitor = monitor; 12 | } 13 | 14 | protected Node forEachDependency(final Node node, final BiFunction op) { 15 | return monitor.process(node.prev(), op); 16 | } 17 | 18 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 19 | cb.monitorexit(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/NativeMethodCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.github.dmlloyd.classfile.ClassFile.*; 4 | 5 | import java.util.function.Consumer; 6 | 7 | import io.quarkus.gizmo2.creator.AbstractMethodCreator; 8 | import io.quarkus.gizmo2.creator.ModifierLocation; 9 | 10 | public final class NativeMethodCreatorImpl extends MethodCreatorImpl implements AbstractMethodCreator { 11 | NativeMethodCreatorImpl(final TypeCreatorImpl owner, final String name) { 12 | super(owner, name); 13 | // not a user-visible modifier, so set it explicitly here 14 | modifiers |= ACC_NATIVE; 15 | } 16 | 17 | public ModifierLocation modifierLocation() { 18 | return ModifierLocation.CLASS_NATIVE_METHOD; 19 | } 20 | 21 | void accept(final Consumer builder) { 22 | builder.accept(this); 23 | typeCreator.zb.withMethod(name(), type(), modifiers, mb -> { 24 | doBody(null, mb); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Neg.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.quarkus.gizmo2.impl.Conversions.convert; 4 | import static io.quarkus.gizmo2.impl.Conversions.unboxingConversion; 5 | import static io.smallrye.common.constraint.Assert.impossibleSwitchCase; 6 | 7 | import java.lang.constant.ClassDesc; 8 | import java.util.function.BiFunction; 9 | 10 | import io.github.dmlloyd.classfile.CodeBuilder; 11 | import io.quarkus.gizmo2.Expr; 12 | import io.quarkus.gizmo2.TypeKind; 13 | 14 | final class Neg extends Item { 15 | private final Item a; 16 | 17 | Neg(Expr a) { 18 | a = convert(a, unboxingConversion(a.type()).orElse(a.type())); 19 | this.a = (Item) a; 20 | TypeKind typeKind = a.typeKind(); 21 | if (typeKind == TypeKind.REFERENCE || typeKind == TypeKind.BOOLEAN || typeKind == TypeKind.VOID) { 22 | throw new IllegalArgumentException("Cannot negate non-numeric expression: " + a); 23 | } 24 | } 25 | 26 | protected Node forEachDependency(final Node node, final BiFunction op) { 27 | return a.process(node.prev(), op); 28 | } 29 | 30 | public ClassDesc type() { 31 | return a.type(); 32 | } 33 | 34 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 35 | switch (typeKind().asLoadable()) { 36 | case INT -> cb.ineg(); 37 | case LONG -> cb.lneg(); 38 | case FLOAT -> cb.fneg(); 39 | case DOUBLE -> cb.dneg(); 40 | default -> throw impossibleSwitchCase(typeKind().asLoadable()); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/New.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.annotation.RetentionPolicy; 4 | import java.lang.constant.ClassDesc; 5 | import java.util.ArrayDeque; 6 | import java.util.ArrayList; 7 | 8 | import io.github.dmlloyd.classfile.CodeBuilder; 9 | import io.github.dmlloyd.classfile.Label; 10 | import io.github.dmlloyd.classfile.TypeAnnotation; 11 | import io.quarkus.gizmo2.GenericType; 12 | 13 | final class New extends Item { 14 | private final GenericType type; 15 | private Label label; 16 | 17 | New(final GenericType type) { 18 | this.type = type; 19 | } 20 | 21 | @Override 22 | public String itemName() { 23 | return "New:" + type().displayName(); 24 | } 25 | 26 | public GenericType genericType() { 27 | return type; 28 | } 29 | 30 | public ClassDesc type() { 31 | return type.desc(); 32 | } 33 | 34 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 35 | label = cb.newBoundLabel(); 36 | cb.new_(type.desc()); 37 | } 38 | 39 | public void writeAnnotations(final RetentionPolicy retention, final ArrayList annotations) { 40 | if (type.hasAnnotations(retention)) { 41 | Util.computeAnnotations(type, retention, TypeAnnotation.TargetInfo.ofNewExpr(label), annotations, 42 | new ArrayDeque<>()); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/NewArrayResult.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.List; 5 | import java.util.function.BiFunction; 6 | 7 | import io.github.dmlloyd.classfile.CodeBuilder; 8 | 9 | public class NewArrayResult extends Item { 10 | private final NewEmptyArray newEmptyArray; 11 | private final List elements; 12 | 13 | NewArrayResult(NewEmptyArray newEmptyArray, List elements) { 14 | this.newEmptyArray = newEmptyArray; 15 | this.elements = elements; 16 | } 17 | 18 | @Override 19 | public String itemName() { 20 | return "NewArrayResult:" + newEmptyArray.type().displayName(); 21 | } 22 | 23 | @Override 24 | public ClassDesc type() { 25 | return newEmptyArray.type(); 26 | } 27 | 28 | @Override 29 | protected Node forEachDependency(Node node, BiFunction op) { 30 | node = node.prev(); 31 | int size = elements.size(); 32 | for (int i = size - 1; i >= 0; i--) { 33 | // processes the `Dup`, index, element and `ArrayStore` 34 | node = elements.get(i).process(node, op); 35 | } 36 | node = newEmptyArray.process(node, op); 37 | return node; 38 | } 39 | 40 | public Node pop(Node ourNode) { 41 | Node node = ourNode.prev(); 42 | remove(ourNode); 43 | int size = elements.size(); 44 | for (int i = size - 1; i >= 0; i--) { 45 | // delete the array store and pop the things being stored 46 | node = elements.get(i).revoke(node); 47 | } 48 | node = newEmptyArray.pop(node); 49 | return node; 50 | } 51 | 52 | @Override 53 | public void writeCode(CodeBuilder cb, BlockCreatorImpl block) { 54 | // nothing 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/NewEmptyArray.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.quarkus.gizmo2.impl.Conversions.convert; 4 | import static java.lang.constant.ConstantDescs.CD_int; 5 | 6 | import java.lang.constant.ClassDesc; 7 | import java.util.function.BiFunction; 8 | 9 | import io.github.dmlloyd.classfile.CodeBuilder; 10 | import io.github.dmlloyd.classfile.TypeKind; 11 | import io.quarkus.gizmo2.Expr; 12 | import io.quarkus.gizmo2.impl.constant.IntConst; 13 | 14 | final class NewEmptyArray extends Item { 15 | private final ClassDesc arrayType; 16 | private final Item size; 17 | 18 | NewEmptyArray(final ClassDesc componentType, final Item size) { 19 | arrayType = componentType.arrayType(); 20 | this.size = convert(size, CD_int); 21 | } 22 | 23 | @Override 24 | public String itemName() { 25 | return "NewEmptyArray:" + arrayType.displayName(); 26 | } 27 | 28 | protected Node forEachDependency(final Node node, final BiFunction op) { 29 | return size.process(node.prev(), op); 30 | } 31 | 32 | public ClassDesc type() { 33 | return arrayType; 34 | } 35 | 36 | public Expr length() { 37 | return size instanceof IntConst ? size : super.length(); 38 | } 39 | 40 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 41 | ClassDesc componentType = type().componentType(); 42 | TypeKind typeKind = TypeKind.from(componentType); 43 | if (typeKind == TypeKind.REFERENCE) { 44 | cb.anewarray(componentType); 45 | } else { 46 | cb.newarray(typeKind); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/NewResult.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.function.BiFunction; 5 | 6 | import io.github.dmlloyd.classfile.CodeBuilder; 7 | 8 | public class NewResult extends Item { 9 | private final New new_; 10 | private final Invoke invoke; 11 | 12 | NewResult(New new_, Invoke invoke) { 13 | this.new_ = new_; 14 | this.invoke = invoke; 15 | } 16 | 17 | @Override 18 | public String itemName() { 19 | return "NewResult:" + new_.type().displayName(); 20 | } 21 | 22 | @Override 23 | public ClassDesc type() { 24 | return new_.type(); 25 | } 26 | 27 | @Override 28 | protected Node forEachDependency(Node node, BiFunction op) { 29 | node = node.prev(); 30 | // processes the constructor arguments and the `Dup` (which is the target instance of the `Invoke`) 31 | node = invoke.process(node, op); 32 | node = new_.process(node, op); 33 | return node; 34 | } 35 | 36 | @Override 37 | public void writeCode(CodeBuilder cb, BlockCreatorImpl block) { 38 | // nothing 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ParamCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.smallrye.common.constraint.Assert.*; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.constant.ClassDesc; 7 | import java.lang.constant.ConstantDescs; 8 | import java.util.List; 9 | import java.util.function.Consumer; 10 | 11 | import io.quarkus.gizmo2.GenericType; 12 | import io.quarkus.gizmo2.creator.ModifierLocation; 13 | import io.quarkus.gizmo2.creator.ParamCreator; 14 | 15 | public final class ParamCreatorImpl extends ModifiableCreatorImpl implements ParamCreator { 16 | boolean typeEstablished; 17 | GenericType genericType; 18 | 19 | public ParamCreatorImpl(final GizmoImpl gizmo) { 20 | super(gizmo); 21 | } 22 | 23 | public ParamCreatorImpl(final GizmoImpl gizmo, final GenericType type) { 24 | super(gizmo); 25 | this.genericType = type; 26 | typeEstablished = true; 27 | } 28 | 29 | public ModifierLocation modifierLocation() { 30 | return ModifierLocation.PARAMETER; 31 | } 32 | 33 | ParamVarImpl apply(final Consumer builder, final String name, final int index, final int slot) { 34 | builder.accept(this); 35 | if (genericType == null) { 36 | throw new IllegalStateException("Parameter type was not set"); 37 | } 38 | typeEstablished = true; 39 | return new ParamVarImpl(genericType, name, index, slot, modifiers, List.copyOf(invisible.values()), 40 | List.copyOf(visible.values())); 41 | } 42 | 43 | public void setType(final GenericType genericType) { 44 | checkNotNullParam("type", genericType); 45 | if (genericType.desc().equals(ConstantDescs.CD_void)) { 46 | throw new IllegalArgumentException("Bad genericType for parameter: " + genericType); 47 | } 48 | if (typeEstablished && !genericType.equals(this.genericType)) { 49 | throw new IllegalArgumentException( 50 | "Given type " + genericType + " differs from established type " + this.genericType); 51 | } 52 | this.genericType = genericType; 53 | } 54 | 55 | public void setType(final ClassDesc type) { 56 | checkNotNullParam("type", type); 57 | setType(GenericType.of(type)); 58 | } 59 | 60 | public ClassDesc type() { 61 | return genericType.desc(); 62 | } 63 | 64 | public GenericType genericType() { 65 | return genericType; 66 | } 67 | 68 | public ElementType annotationTargetType() { 69 | return ElementType.PARAMETER; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ParamSet.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.BiFunction; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | 7 | final class ParamSet extends Item { 8 | private final ParamVarImpl paramVar; 9 | private final Item value; 10 | 11 | ParamSet(final ParamVarImpl paramVar, final Item value) { 12 | this.paramVar = paramVar; 13 | this.value = value; 14 | } 15 | 16 | protected Node forEachDependency(final Node node, final BiFunction op) { 17 | return value.process(node.prev(), op); 18 | } 19 | 20 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 21 | cb.storeLocal(Util.actualKindOf(paramVar.typeKind()), paramVar.slot()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ParamVarImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.List; 5 | 6 | import io.github.dmlloyd.classfile.Annotation; 7 | import io.github.dmlloyd.classfile.CodeBuilder; 8 | import io.quarkus.gizmo2.GenericType; 9 | import io.quarkus.gizmo2.MemoryOrder; 10 | import io.quarkus.gizmo2.ParamVar; 11 | 12 | public final class ParamVarImpl extends AssignableImpl implements ParamVar { 13 | private final GenericType type; 14 | private final String name; 15 | private final int index; 16 | private final int slot; 17 | final List invisible; 18 | final List visible; 19 | private final int flags; 20 | 21 | public ParamVarImpl(final GenericType type, final String name, final int index, final int slot, final int flags, 22 | final List invisible, final List visible) { 23 | this.type = type; 24 | this.name = name; 25 | this.index = index; 26 | this.slot = slot; 27 | this.flags = flags; 28 | this.invisible = invisible; 29 | this.visible = visible; 30 | } 31 | 32 | @Override 33 | public String itemName() { 34 | return "ParamVar:" + name; 35 | } 36 | 37 | int flags() { 38 | return flags; 39 | } 40 | 41 | public int slot() { 42 | return slot; 43 | } 44 | 45 | public int index() { 46 | return index; 47 | } 48 | 49 | Item emitGet(final BlockCreatorImpl block, final MemoryOrder mode) { 50 | return asBound(); 51 | } 52 | 53 | Item emitSet(final BlockCreatorImpl block, final Item value, final MemoryOrder mode) { 54 | return new ParamSet(this, value); 55 | } 56 | 57 | public ClassDesc type() { 58 | return type.desc(); 59 | } 60 | 61 | public GenericType genericType() { 62 | return type; 63 | } 64 | 65 | public boolean bound() { 66 | return false; 67 | } 68 | 69 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 70 | cb.loadLocal(Util.actualKindOf(typeKind()), slot); 71 | } 72 | 73 | public String name() { 74 | return name; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/PerfectHashSwitchCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.Comparator; 5 | import java.util.List; 6 | 7 | import io.github.dmlloyd.classfile.CodeBuilder; 8 | import io.github.dmlloyd.classfile.Label; 9 | import io.github.dmlloyd.classfile.instruction.SwitchCase; 10 | import io.quarkus.gizmo2.Expr; 11 | import io.quarkus.gizmo2.impl.constant.ConstImpl; 12 | 13 | sealed abstract class PerfectHashSwitchCreatorImpl extends SwitchCreatorImpl 14 | permits EnumOrdinalSwitchCreatorImpl, IntSwitchCreatorImpl { 15 | 16 | PerfectHashSwitchCreatorImpl(final BlockCreatorImpl enclosing, final Expr switchVal, final ClassDesc type, 17 | final Class constantType) { 18 | super(enclosing, switchVal, type, constantType); 19 | } 20 | 21 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 22 | Label fallOut, nonMatching; 23 | if (default_ == null) { 24 | fallOut = nonMatching = block.newLabel(); 25 | } else { 26 | fallOut = default_.endLabel(); 27 | nonMatching = default_.startLabel(); 28 | } 29 | 30 | List switchCases = casesByConstant.entrySet().stream() 31 | .map(c -> SwitchCase.of(staticHash(c.getKey()), c.getValue().body.startLabel())) 32 | .sorted(Comparator.comparingInt(SwitchCase::caseValue)) 33 | .toList(); 34 | 35 | hash(cb); 36 | if ((double) casesByConstant.size() / ((double) (max - min)) >= TABLESWITCH_DENSITY) { 37 | cb.tableswitch(min, max, nonMatching, switchCases); 38 | } else { 39 | cb.lookupswitch(nonMatching, switchCases); 40 | } 41 | 42 | // now write the cases 43 | for (CaseCreatorImpl case_ : casesByConstant.values()) { 44 | // write body 45 | case_.body.writeCode(cb, block); 46 | if (case_.body.mayFallThrough()) { 47 | cb.goto_(fallOut); 48 | } 49 | } 50 | // finally, the default block 51 | if (default_ == null) { 52 | cb.labelBinding(fallOut); 53 | cb.labelBinding(nonMatching); 54 | } else { 55 | default_.writeCode(cb, block); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Pop.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.BiFunction; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | 7 | public final class Pop extends Item { 8 | private final Item expr; 9 | 10 | public Pop(final Item expr) { 11 | this.expr = expr; 12 | } 13 | 14 | protected Node forEachDependency(final Node node, final BiFunction op) { 15 | return expr.process(node.prev(), op); 16 | } 17 | 18 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 19 | if (expr.typeKind().slotSize() == 2) { 20 | cb.pop2(); 21 | } else { 22 | cb.pop(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Preconditions.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.github.dmlloyd.classfile.TypeKind; 6 | import io.quarkus.gizmo2.Expr; 7 | 8 | public class Preconditions { 9 | private Preconditions() { 10 | } 11 | 12 | public static void requireSameType(final Expr a, final Expr b) { 13 | if (!a.type().equals(b.type())) { 14 | throw new IllegalArgumentException( 15 | "Type mismatch between " + a.type().displayName() + " and " + b.type().displayName()); 16 | } 17 | } 18 | 19 | public static void requireSameTypeKind(final Expr a, final Expr b) { 20 | if (a.typeKind() != b.typeKind()) { 21 | throw new IllegalArgumentException( 22 | "Type mismatch between " + a.type().displayName() + " and " + b.type().displayName()); 23 | } 24 | } 25 | 26 | public static void requireSameTypeKind(final ClassDesc a, final ClassDesc b) { 27 | if (TypeKind.from(a) != TypeKind.from(b)) { 28 | throw new IllegalArgumentException("Type mismatch between " + a.displayName() + " and " + b.displayName()); 29 | } 30 | } 31 | 32 | public static void requireSameLoadableTypeKind(final Expr a, final Expr b) { 33 | if (a.typeKind().asLoadable() != b.typeKind().asLoadable()) { 34 | throw new IllegalArgumentException( 35 | "Type mismatch between " + a.type().displayName() + " and " + b.type().displayName()); 36 | } 37 | } 38 | 39 | public static void requireSameLoadableTypeKind(final ClassDesc a, final ClassDesc b) { 40 | if (TypeKind.from(a).asLoadable() != TypeKind.from(b).asLoadable()) { 41 | throw new IllegalArgumentException("Type mismatch between " + a.displayName() + " and " + b.displayName()); 42 | } 43 | } 44 | 45 | public static void requireArray(Expr expr) { 46 | if (!expr.type().isArray()) { 47 | throw new IllegalArgumentException("Array expected: " + expr.type().displayName()); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/PrimitiveCast.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import io.github.dmlloyd.classfile.CodeBuilder; 4 | import io.github.dmlloyd.classfile.TypeKind; 5 | import io.quarkus.gizmo2.Expr; 6 | import io.quarkus.gizmo2.GenericType; 7 | 8 | final class PrimitiveCast extends Cast { 9 | 10 | PrimitiveCast(final Expr a, final GenericType toType) { 11 | super(a, toType); 12 | } 13 | 14 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 15 | cb.conversion(Util.actualKindOf(a.typeKind()), TypeKind.from(toType.desc())); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/PrivateInterfaceMethodCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import io.quarkus.gizmo2.creator.BlockCreator; 6 | import io.quarkus.gizmo2.creator.InstanceMethodCreator; 7 | import io.quarkus.gizmo2.creator.ModifierLocation; 8 | 9 | public final class PrivateInterfaceMethodCreatorImpl extends MethodCreatorImpl implements InstanceMethodCreator { 10 | PrivateInterfaceMethodCreatorImpl(final TypeCreatorImpl owner, final String name) { 11 | super(owner, name); 12 | } 13 | 14 | public ModifierLocation modifierLocation() { 15 | return ModifierLocation.INTERFACE_PRIVATE_INSTANCE_METHOD; 16 | } 17 | 18 | public void body(final Consumer builder) { 19 | super.body(builder); 20 | } 21 | 22 | void accept(final Consumer builder) { 23 | builder.accept(this); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Rel.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.quarkus.gizmo2.impl.Preconditions.requireSameTypeKind; 4 | import static io.smallrye.common.constraint.Assert.impossibleSwitchCase; 5 | import static java.lang.constant.ConstantDescs.CD_boolean; 6 | 7 | import java.lang.constant.ClassDesc; 8 | import java.util.function.BiFunction; 9 | 10 | import io.github.dmlloyd.classfile.CodeBuilder; 11 | import io.github.dmlloyd.classfile.Label; 12 | import io.quarkus.gizmo2.Expr; 13 | import io.quarkus.gizmo2.TypeKind; 14 | 15 | final class Rel extends Item { 16 | private final Item a; 17 | private final Item b; 18 | private final If.Kind kind; 19 | 20 | Rel(final Expr a, final Expr b, final If.Kind kind) { 21 | this.kind = kind; 22 | requireSameTypeKind(a, b); 23 | this.a = (Item) a; 24 | this.b = (Item) b; 25 | if (a.typeKind() == TypeKind.REFERENCE) { 26 | if (kind.if_acmp == null) { 27 | throw new IllegalStateException("Invalid comparison for reference types"); 28 | } 29 | } else if (a.typeKind().asLoadable() != TypeKind.INT) { 30 | throw new UnsupportedOperationException("Only supported on int and reference types"); 31 | } 32 | } 33 | 34 | protected Node forEachDependency(final Node node, final BiFunction op) { 35 | return a.process(b.process(node.prev(), op), op); 36 | } 37 | 38 | Item left() { 39 | return a; 40 | } 41 | 42 | Item right() { 43 | return b; 44 | } 45 | 46 | public ClassDesc type() { 47 | return CD_boolean; 48 | } 49 | 50 | If.Kind kind() { 51 | return kind; 52 | } 53 | 54 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 55 | Label true_ = cb.newLabel(); 56 | Label end = cb.newLabel(); 57 | switch (a.typeKind().asLoadable()) { 58 | case INT -> kind.if_icmp.accept(cb, true_); 59 | case REFERENCE -> kind.if_acmp.accept(cb, true_); 60 | default -> throw impossibleSwitchCase(typeKind().asLoadable()); 61 | } 62 | cb.iconst_0(); 63 | cb.goto_(end); 64 | cb.labelBinding(true_); 65 | cb.iconst_1(); 66 | cb.labelBinding(end); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/RelZero.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static java.lang.constant.ConstantDescs.CD_boolean; 4 | 5 | import java.lang.constant.ClassDesc; 6 | import java.util.function.BiFunction; 7 | 8 | import io.github.dmlloyd.classfile.CodeBuilder; 9 | import io.github.dmlloyd.classfile.Label; 10 | import io.quarkus.gizmo2.Expr; 11 | import io.quarkus.gizmo2.TypeKind; 12 | 13 | final class RelZero extends Item { 14 | private final Item a; 15 | private final If.Kind kind; 16 | 17 | RelZero(final Expr a, final If.Kind kind) { 18 | this.kind = kind; 19 | this.a = (Item) a; 20 | if (a.typeKind() == TypeKind.REFERENCE) { 21 | if (kind.if_acmp == null) { 22 | throw new IllegalStateException("Invalid comparison for reference types"); 23 | } 24 | } 25 | } 26 | 27 | Item input() { 28 | return a; 29 | } 30 | 31 | protected Node forEachDependency(final Node node, final BiFunction op) { 32 | return a.process(node.prev(), op); 33 | } 34 | 35 | public ClassDesc type() { 36 | return CD_boolean; 37 | } 38 | 39 | If.Kind kind() { 40 | return kind; 41 | } 42 | 43 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 44 | Label true_ = cb.newLabel(); 45 | Label end = cb.newLabel(); 46 | switch (a.typeKind().asLoadable()) { 47 | case INT -> kind.if_.accept(cb, true_); 48 | case REFERENCE -> kind.if_acmpnull.accept(cb, true_); 49 | case LONG -> { 50 | cb.lconst_0(); 51 | cb.lcmp(); 52 | cb.iconst_1(); 53 | cb.iand(); 54 | return; 55 | } 56 | case FLOAT -> { 57 | cb.fconst_0(); 58 | cb.fcmpg(); 59 | cb.iconst_1(); 60 | cb.iand(); 61 | return; 62 | } 63 | case DOUBLE -> { 64 | cb.dconst_0(); 65 | cb.dcmpg(); 66 | cb.iconst_1(); 67 | cb.iand(); 68 | return; 69 | } 70 | default -> throw new IllegalStateException(); 71 | } 72 | cb.iconst_0(); 73 | cb.goto_(end); 74 | cb.labelBinding(true_); 75 | cb.iconst_1(); 76 | cb.labelBinding(end); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Return.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.util.Objects; 5 | import java.util.function.BiFunction; 6 | 7 | import io.github.dmlloyd.classfile.CodeBuilder; 8 | import io.github.dmlloyd.classfile.TypeKind; 9 | import io.quarkus.gizmo2.Expr; 10 | import io.quarkus.gizmo2.impl.constant.ConstImpl; 11 | 12 | final class Return extends Item { 13 | static final Return RETURN_VOID = new Return(ConstImpl.ofVoid()); 14 | 15 | private final Item returnValue; 16 | 17 | Return(final Expr returnValue) { 18 | this.returnValue = (Item) returnValue; 19 | } 20 | 21 | public boolean mayFallThrough() { 22 | return false; 23 | } 24 | 25 | protected Node forEachDependency(final Node node, final BiFunction op) { 26 | return returnValue.process(node.prev(), op); 27 | } 28 | 29 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl from) { 30 | TryFinally tryFinally = from.tryFinally; 31 | ClassDesc returnType = from.returnType(); 32 | if (tryFinally != null) { 33 | cb.goto_(tryFinally.cleanup(new ReturnKey(returnType))); 34 | } else { 35 | cb.return_(TypeKind.from(returnType)); 36 | } 37 | } 38 | 39 | static final class ReturnKey extends TryFinally.CleanupKey { 40 | private final ClassDesc returnType; 41 | 42 | ReturnKey(final ClassDesc returnType) { 43 | this.returnType = returnType; 44 | } 45 | 46 | ClassDesc type() { 47 | return returnType; 48 | } 49 | 50 | void terminate(final BlockCreatorImpl bci, final Expr input) { 51 | bci.return_(input); 52 | } 53 | 54 | public boolean equals(final Object obj) { 55 | return obj instanceof ReturnKey rk && equals(rk); 56 | } 57 | 58 | public boolean equals(final ReturnKey other) { 59 | return this == other || other != null && returnType.equals(other.returnType); 60 | } 61 | 62 | public int hashCode() { 63 | return Objects.hash(ReturnKey.class, returnType); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/StaticFieldCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static java.lang.constant.ConstantDescs.*; 4 | 5 | import java.lang.constant.ClassDesc; 6 | import java.util.function.Consumer; 7 | 8 | import io.github.dmlloyd.classfile.attribute.ConstantValueAttribute; 9 | import io.github.dmlloyd.classfile.attribute.SignatureAttribute; 10 | import io.quarkus.gizmo2.Const; 11 | import io.quarkus.gizmo2.creator.BlockCreator; 12 | import io.quarkus.gizmo2.creator.StaticFieldCreator; 13 | import io.quarkus.gizmo2.desc.FieldDesc; 14 | import io.smallrye.common.constraint.Assert; 15 | 16 | public sealed abstract class StaticFieldCreatorImpl extends FieldCreatorImpl implements StaticFieldCreator 17 | permits ClassStaticFieldCreatorImpl, InterfaceStaticFieldCreatorImpl { 18 | private Const initial; 19 | private Consumer initializer; 20 | 21 | protected StaticFieldCreatorImpl(final TypeCreatorImpl tc, final ClassDesc owner, final String name) { 22 | super(owner, name, tc); 23 | } 24 | 25 | public void setInitial(final Const initial) { 26 | Assert.checkNotNullParam("initial", initial); 27 | checkOneInit(); 28 | setType(initial.type()); 29 | if (initial.type().isPrimitive() || initial.type().equals(CD_String)) { 30 | this.initial = initial; 31 | } else { 32 | initializer = bc -> bc.setStaticField(desc(), initial); 33 | } 34 | } 35 | 36 | public void setInitializer(final Consumer init) { 37 | Assert.checkNotNullParam("init", init); 38 | checkOneInit(); 39 | initializer = (b0 -> { 40 | FieldDesc desc = desc(); 41 | b0.setStaticField(desc, b0.blockExpr(desc.type(), init)); 42 | }); 43 | } 44 | 45 | private void checkOneInit() { 46 | if (initial != null || initializer != null) { 47 | throw new IllegalStateException("A static field may have only one initializer"); 48 | } 49 | } 50 | 51 | void accept(Consumer builder) { 52 | builder.accept(this); 53 | if (initializer != null) { 54 | tc.staticInitializer(initializer); 55 | } 56 | tc.zb.withField(name(), desc().type(), fb -> { 57 | fb.withFlags(modifiers); 58 | fb.with(SignatureAttribute.of(Util.signatureOf(genericType()))); 59 | addVisible(fb); 60 | addInvisible(fb); 61 | if (initial != null) { 62 | fb.with(ConstantValueAttribute.of(initial.desc())); 63 | } 64 | }); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/StaticFieldGetViaHandle.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.smallrye.common.constraint.Assert.impossibleSwitchCase; 4 | import static java.lang.constant.ConstantDescs.*; 5 | 6 | import java.lang.constant.ClassDesc; 7 | import java.lang.constant.MethodTypeDesc; 8 | import java.util.function.BiFunction; 9 | 10 | import io.github.dmlloyd.classfile.CodeBuilder; 11 | import io.quarkus.gizmo2.MemoryOrder; 12 | import io.quarkus.gizmo2.impl.constant.ConstImpl; 13 | 14 | final class StaticFieldGetViaHandle extends Item { 15 | private final StaticFieldVarImpl staticFieldVar; 16 | private final MemoryOrder mode; 17 | 18 | StaticFieldGetViaHandle(final StaticFieldVarImpl staticFieldVar, final MemoryOrder mode) { 19 | this.staticFieldVar = staticFieldVar; 20 | this.mode = mode; 21 | } 22 | 23 | public ClassDesc type() { 24 | return staticFieldVar.type(); 25 | } 26 | 27 | protected Node forEachDependency(final Node node, final BiFunction op) { 28 | return ConstImpl.ofStaticFieldVarHandle(staticFieldVar.desc()).process(node.prev(), op); 29 | } 30 | 31 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 32 | cb.invokevirtual(CD_VarHandle, switch (mode) { 33 | case Plain -> "get"; 34 | case Opaque -> "getOpaque"; 35 | case Acquire -> "getAcquire"; 36 | case Volatile -> "getVolatile"; 37 | default -> throw impossibleSwitchCase(mode); 38 | }, MethodTypeDesc.of(type())); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/StaticFieldSet.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.BiFunction; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | 7 | final class StaticFieldSet extends Item { 8 | private final StaticFieldVarImpl staticFieldVar; 9 | private final Item value; 10 | 11 | StaticFieldSet(final StaticFieldVarImpl staticFieldVar, final Item value) { 12 | this.staticFieldVar = staticFieldVar; 13 | this.value = value; 14 | } 15 | 16 | protected Node forEachDependency(Node node, final BiFunction op) { 17 | return value.process(node.prev(), op); 18 | } 19 | 20 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 21 | cb.putstatic(staticFieldVar.owner(), staticFieldVar.name(), staticFieldVar.desc().type()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/StaticFieldSetViaHandle.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.smallrye.common.constraint.Assert.impossibleSwitchCase; 4 | import static java.lang.constant.ConstantDescs.*; 5 | 6 | import java.lang.constant.MethodTypeDesc; 7 | import java.util.function.BiFunction; 8 | 9 | import io.github.dmlloyd.classfile.CodeBuilder; 10 | import io.quarkus.gizmo2.MemoryOrder; 11 | import io.quarkus.gizmo2.impl.constant.ConstImpl; 12 | 13 | final class StaticFieldSetViaHandle extends Item { 14 | private final StaticFieldVarImpl staticFieldVar; 15 | private final MemoryOrder mode; 16 | private final Item value; 17 | 18 | StaticFieldSetViaHandle(final StaticFieldVarImpl staticFieldVar, final MemoryOrder mode, final Item value) { 19 | this.staticFieldVar = staticFieldVar; 20 | this.mode = mode; 21 | this.value = value; 22 | } 23 | 24 | protected Node forEachDependency(Node node, final BiFunction op) { 25 | return ConstImpl.ofStaticFieldVarHandle(staticFieldVar.desc()).process(value.process(node.prev(), op), op); 26 | } 27 | 28 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 29 | cb.invokevirtual(CD_VarHandle, switch (mode) { 30 | case Plain -> "set"; 31 | case Opaque -> "setOpaque"; 32 | case Release -> "setRelease"; 33 | case Volatile -> "setVolatile"; 34 | default -> throw impossibleSwitchCase(mode); 35 | }, MethodTypeDesc.of(CD_void, staticFieldVar.desc().type())); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/StaticFieldVarImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | import io.quarkus.gizmo2.GenericType; 7 | import io.quarkus.gizmo2.MemoryOrder; 8 | import io.quarkus.gizmo2.StaticFieldVar; 9 | import io.quarkus.gizmo2.desc.FieldDesc; 10 | 11 | public final class StaticFieldVarImpl extends AssignableImpl implements StaticFieldVar { 12 | private final FieldDesc desc; 13 | private final GenericType genericType; 14 | 15 | public StaticFieldVarImpl(FieldDesc desc, final GenericType genericType) { 16 | this.desc = desc; 17 | this.genericType = genericType; 18 | } 19 | 20 | public FieldDesc desc() { 21 | return desc; 22 | } 23 | 24 | public ClassDesc type() { 25 | return desc.type(); 26 | } 27 | 28 | public GenericType genericType() { 29 | return genericType; 30 | } 31 | 32 | public boolean bound() { 33 | return false; 34 | } 35 | 36 | Item emitGet(final BlockCreatorImpl block, final MemoryOrder mode) { 37 | return switch (mode) { 38 | case AsDeclared -> asBound(); 39 | default -> new StaticFieldGetViaHandle(this, mode); 40 | }; 41 | } 42 | 43 | Item emitSet(final BlockCreatorImpl block, final Item value, final MemoryOrder mode) { 44 | return switch (mode) { 45 | case AsDeclared -> new StaticFieldSet(this, value); 46 | default -> new StaticFieldSetViaHandle(this, mode, value); 47 | }; 48 | } 49 | 50 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 51 | cb.getstatic(owner(), name(), type()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/StaticInterfaceMethodCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import io.quarkus.gizmo2.creator.BlockCreator; 6 | import io.quarkus.gizmo2.creator.ModifierLocation; 7 | import io.quarkus.gizmo2.creator.StaticMethodCreator; 8 | 9 | public final class StaticInterfaceMethodCreatorImpl extends MethodCreatorImpl implements StaticMethodCreator { 10 | StaticInterfaceMethodCreatorImpl(final TypeCreatorImpl owner, final String name) { 11 | super(owner, name); 12 | } 13 | 14 | public ModifierLocation modifierLocation() { 15 | return ModifierLocation.INTERFACE_STATIC_METHOD; 16 | } 17 | 18 | public void body(final Consumer builder) { 19 | super.body(builder); 20 | } 21 | 22 | int firstSlot() { 23 | return 0; 24 | } 25 | 26 | void accept(final Consumer builder) { 27 | builder.accept(this); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/StaticMethodCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import io.quarkus.gizmo2.creator.BlockCreator; 6 | import io.quarkus.gizmo2.creator.ModifierLocation; 7 | import io.quarkus.gizmo2.creator.StaticMethodCreator; 8 | 9 | public final class StaticMethodCreatorImpl extends MethodCreatorImpl implements StaticMethodCreator { 10 | StaticMethodCreatorImpl(final TypeCreatorImpl owner, final String name) { 11 | super(owner, name); 12 | } 13 | 14 | public ModifierLocation modifierLocation() { 15 | return ModifierLocation.CLASS_STATIC_METHOD; 16 | } 17 | 18 | public void body(final Consumer builder) { 19 | super.body(builder); 20 | } 21 | 22 | int firstSlot() { 23 | return 0; 24 | } 25 | 26 | void accept(final Consumer builder) { 27 | builder.accept(this); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/StringSwitchCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static java.lang.constant.ConstantDescs.*; 4 | 5 | import java.lang.constant.ClassDesc; 6 | import java.lang.constant.MethodTypeDesc; 7 | 8 | import io.github.dmlloyd.classfile.CodeBuilder; 9 | import io.github.dmlloyd.classfile.Label; 10 | import io.quarkus.gizmo2.Expr; 11 | import io.quarkus.gizmo2.impl.constant.StringConst; 12 | 13 | /** 14 | * A switch over {@code String} objects. 15 | */ 16 | public final class StringSwitchCreatorImpl extends HashSwitchCreatorImpl { 17 | StringSwitchCreatorImpl(final BlockCreatorImpl enclosing, final Expr switchVal, final ClassDesc type) { 18 | super(enclosing, switchVal, type, StringConst.class); 19 | } 20 | 21 | boolean staticEquals(final StringConst a, final StringConst b) { 22 | return a.desc().equals(b.desc()); 23 | } 24 | 25 | void equaller(final CodeBuilder cb, final StringConst value, final Label ifEq) { 26 | value.writeCode(cb, enclosing); 27 | cb.invokevirtual(CD_String, "equals", MethodTypeDesc.of(CD_boolean, CD_Object)); 28 | // returns 1 if equal 29 | cb.ifne(ifEq); 30 | } 31 | 32 | int staticHash(final StringConst val) { 33 | return val.desc().hashCode(); 34 | } 35 | 36 | void hash(final CodeBuilder cb) { 37 | cb.invokevirtual(CD_String, "hashCode", MethodTypeDesc.of(CD_int)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/ThisExpr.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | import io.quarkus.gizmo2.GenericType; 7 | import io.quarkus.gizmo2.This; 8 | 9 | public final class ThisExpr extends Item implements This { 10 | private final GenericType type; 11 | 12 | public ThisExpr(final GenericType type) { 13 | this.type = type; 14 | } 15 | 16 | public boolean bound() { 17 | return false; 18 | } 19 | 20 | public ClassDesc type() { 21 | return type.desc(); 22 | } 23 | 24 | public GenericType genericType() { 25 | return type; 26 | } 27 | 28 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 29 | cb.aload(0); 30 | } 31 | 32 | public String name() { 33 | return "this"; 34 | } 35 | 36 | public String itemName() { 37 | return "this"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Throw.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.BiFunction; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | import io.quarkus.gizmo2.Expr; 7 | 8 | final class Throw extends Item { 9 | final Item thrown; 10 | 11 | Throw(final Expr val) { 12 | thrown = (Item) val; 13 | } 14 | 15 | protected Node forEachDependency(final Node node, final BiFunction op) { 16 | return thrown.process(node.prev(), op); 17 | } 18 | 19 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 20 | // no cleanup blobs here 21 | cb.athrow(); 22 | } 23 | 24 | public boolean mayFallThrough() { 25 | return false; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/TypeAnnotatableCreatorImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.util.List; 5 | 6 | import io.github.dmlloyd.classfile.Annotation; 7 | 8 | public final class TypeAnnotatableCreatorImpl extends AnnotatableCreatorImpl { 9 | 10 | public TypeAnnotatableCreatorImpl() { 11 | } 12 | 13 | public TypeAnnotatableCreatorImpl(final List visible, final List invisible) { 14 | super(visible, invisible); 15 | } 16 | 17 | public ElementType annotationTargetType() { 18 | return ElementType.TYPE_USE; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Unbox.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.smallrye.common.constraint.Assert.*; 4 | import static java.lang.constant.ConstantDescs.*; 5 | 6 | import java.lang.constant.ClassDesc; 7 | import java.lang.constant.MethodTypeDesc; 8 | 9 | import io.github.dmlloyd.classfile.CodeBuilder; 10 | import io.github.dmlloyd.classfile.Opcode; 11 | import io.quarkus.gizmo2.Expr; 12 | import io.quarkus.gizmo2.GenericType; 13 | import io.quarkus.gizmo2.TypeKind; 14 | 15 | final class Unbox extends Cast { 16 | private boolean bound; 17 | 18 | private static ClassDesc unboxing(ClassDesc boxType) { 19 | ClassDesc unboxType = Conversions.unboxingConversion(boxType) 20 | .orElseThrow(() -> new IllegalArgumentException("No unbox type for " + boxType.displayName())); 21 | if (unboxType.equals(CD_void)) { 22 | throw new IllegalArgumentException("Cannot unbox void"); 23 | } 24 | return unboxType; 25 | } 26 | 27 | Unbox(Expr a) { 28 | super(a, GenericType.of(unboxing(a.type()))); 29 | } 30 | 31 | @Override 32 | public boolean bound() { 33 | return bound; 34 | } 35 | 36 | @Override 37 | protected void bind() { 38 | bound = true; 39 | } 40 | 41 | @Override 42 | public void writeCode(CodeBuilder cb, BlockCreatorImpl block) { 43 | cb.invoke(Opcode.INVOKEVIRTUAL, a.type(), switch (TypeKind.from(toType.desc())) { 44 | case BOOLEAN -> "booleanValue"; 45 | case BYTE -> "byteValue"; 46 | case CHAR -> "charValue"; 47 | case SHORT -> "shortValue"; 48 | case INT -> "intValue"; 49 | case LONG -> "longValue"; 50 | case FLOAT -> "floatValue"; 51 | case DOUBLE -> "doubleValue"; 52 | default -> throw impossibleSwitchCase(TypeKind.from(toType.desc())); 53 | }, MethodTypeDesc.of(toType.desc()), false); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/UncheckedCast.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import io.github.dmlloyd.classfile.CodeBuilder; 4 | import io.quarkus.gizmo2.Expr; 5 | import io.quarkus.gizmo2.GenericType; 6 | 7 | final class UncheckedCast extends Cast { 8 | 9 | UncheckedCast(final Expr a, final GenericType toType) { 10 | super(a, toType); 11 | } 12 | 13 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 14 | // nothing 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/WidenPrimitive.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import static io.quarkus.gizmo2.impl.Conversions.primitiveWideningExists; 4 | 5 | import java.lang.constant.ClassDesc; 6 | 7 | import io.github.dmlloyd.classfile.CodeBuilder; 8 | import io.quarkus.gizmo2.Expr; 9 | import io.quarkus.gizmo2.GenericType; 10 | 11 | // variant of `PrimitiveCast` that: 12 | // - only does widening conversions 13 | // - is not bound initially 14 | final class WidenPrimitive extends Cast { 15 | private final PrimitiveCast widening; 16 | private boolean bound; 17 | 18 | WidenPrimitive(Expr a, ClassDesc toType) { 19 | super(a, GenericType.of(toType)); 20 | if (!primitiveWideningExists(a.type(), toType)) { 21 | throw new IllegalArgumentException("No primitive widening conversion from " + a.type().displayName() 22 | + " to " + toType.displayName()); 23 | } 24 | this.widening = new PrimitiveCast(a, GenericType.of(toType)); 25 | } 26 | 27 | @Override 28 | public boolean bound() { 29 | return bound; 30 | } 31 | 32 | @Override 33 | protected void bind() { 34 | bound = true; 35 | } 36 | 37 | @Override 38 | public void writeCode(CodeBuilder cb, BlockCreatorImpl block) { 39 | widening.writeCode(cb, block); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/Yield.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl; 2 | 3 | import java.util.function.BiFunction; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | import io.quarkus.gizmo2.Expr; 7 | import io.quarkus.gizmo2.impl.constant.ConstImpl; 8 | 9 | /** 10 | * A node that yields a result value to the enclosing block. 11 | */ 12 | final class Yield extends Item { 13 | static final Yield YIELD_VOID = new Yield(ConstImpl.ofVoid()); 14 | 15 | private final Item value; 16 | 17 | Yield(final Expr value) { 18 | this.value = (Item) value; 19 | } 20 | 21 | protected Node forEachDependency(Node node, final BiFunction op) { 22 | node = node.prev(); 23 | node = value.isVoid() ? node : value.process(node, op); 24 | return node; 25 | } 26 | 27 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 28 | // no operation 29 | } 30 | 31 | Expr value() { 32 | return value; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/ArrayVarHandleConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.invoke.VarHandle; 5 | 6 | import io.quarkus.gizmo2.impl.Util; 7 | 8 | public final class ArrayVarHandleConst extends VarHandleConst { 9 | private final ClassDesc arrayType; 10 | 11 | public ArrayVarHandleConst(final ClassDesc arrayType) { 12 | super(VarHandle.VarHandleDesc.ofArray(arrayType)); 13 | this.arrayType = arrayType; 14 | } 15 | 16 | public boolean equals(final VarHandleConst obj) { 17 | return obj instanceof ArrayVarHandleConst other && equals(other); 18 | } 19 | 20 | public boolean equals(final ArrayVarHandleConst other) { 21 | return this == other || other != null && arrayType.equals(other.arrayType); 22 | } 23 | 24 | public int hashCode() { 25 | return arrayType.hashCode(); 26 | } 27 | 28 | public StringBuilder toShortString(final StringBuilder b) { 29 | return Util.descName(b.append("VarHandle["), arrayType).append(']'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/BooleanConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ConstantDescs; 4 | import java.lang.constant.DynamicConstantDesc; 5 | import java.util.Optional; 6 | 7 | import io.github.dmlloyd.classfile.CodeBuilder; 8 | import io.quarkus.gizmo2.impl.BlockCreatorImpl; 9 | 10 | public final class BooleanConst extends ConstImpl { 11 | private final boolean value; 12 | 13 | private BooleanConst(final boolean value) { 14 | super(ConstantDescs.CD_boolean); 15 | this.value = value; 16 | } 17 | 18 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 19 | if (value) { 20 | cb.iconst_1(); 21 | } else { 22 | cb.iconst_0(); 23 | } 24 | } 25 | 26 | public static final BooleanConst FALSE = new BooleanConst(false); 27 | public static final BooleanConst TRUE = new BooleanConst(true); 28 | 29 | public DynamicConstantDesc desc() { 30 | return value ? ConstantDescs.TRUE : ConstantDescs.FALSE; 31 | } 32 | 33 | public Optional> describeConstable() { 34 | return Optional.of(desc()); 35 | } 36 | 37 | public boolean isZero() { 38 | return !value; 39 | } 40 | 41 | public boolean isNonZero() { 42 | return value; 43 | } 44 | 45 | public boolean equals(final ConstImpl other) { 46 | return this == other; 47 | } 48 | 49 | public String toString() { 50 | return Boolean.toString(value); 51 | } 52 | 53 | public StringBuilder toShortString(final StringBuilder b) { 54 | return b.append(value); 55 | } 56 | 57 | public int hashCode() { 58 | return Boolean.hashCode(value); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/ByteConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import static java.lang.constant.ConstantDescs.CD_byte; 4 | 5 | import java.lang.constant.DynamicConstantDesc; 6 | import java.util.Optional; 7 | 8 | public final class ByteConst extends IntBasedConst { 9 | private final Byte value; 10 | 11 | public ByteConst(Byte value) { 12 | super(CD_byte); 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public int intValue() { 18 | return value.intValue(); 19 | } 20 | 21 | public boolean equals(final ConstImpl obj) { 22 | return obj instanceof ByteConst other && equals(other); 23 | } 24 | 25 | public boolean equals(final ByteConst other) { 26 | return this == other || other != null && value.equals(other.value); 27 | } 28 | 29 | public int hashCode() { 30 | return value.hashCode(); 31 | } 32 | 33 | public DynamicConstantDesc desc() { 34 | return describeConstable().orElseThrow(); 35 | } 36 | 37 | public Optional> describeConstable() { 38 | return value.describeConstable(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/CharConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import static java.lang.constant.ConstantDescs.CD_char; 4 | 5 | import java.lang.constant.DynamicConstantDesc; 6 | import java.util.Optional; 7 | 8 | public final class CharConst extends IntBasedConst { 9 | private final Character value; 10 | 11 | public CharConst(Character value) { 12 | super(CD_char); 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public int intValue() { 18 | return value.charValue(); 19 | } 20 | 21 | public boolean equals(final ConstImpl obj) { 22 | return obj instanceof CharConst other && equals(other); 23 | } 24 | 25 | public boolean equals(final CharConst other) { 26 | return this == other || other != null && value.equals(other.value); 27 | } 28 | 29 | public int hashCode() { 30 | return value.hashCode(); 31 | } 32 | 33 | public DynamicConstantDesc desc() { 34 | return describeConstable().orElseThrow(); 35 | } 36 | 37 | public Optional> describeConstable() { 38 | return value.describeConstable(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/ClassConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.constant.ConstantDesc; 5 | import java.lang.constant.ConstantDescs; 6 | import java.util.Optional; 7 | 8 | import io.quarkus.gizmo2.impl.Util; 9 | 10 | public final class ClassConst extends ConstImpl { 11 | 12 | private final ClassDesc value; 13 | 14 | public ClassConst(ClassDesc value) { 15 | super(ConstantDescs.CD_Class); 16 | this.value = value; 17 | } 18 | 19 | public boolean isNonZero() { 20 | return true; 21 | } 22 | 23 | public ClassConst(final ConstantDesc constantDesc) { 24 | this((ClassDesc) constantDesc); 25 | } 26 | 27 | public ClassDesc desc() { 28 | return value; 29 | } 30 | 31 | public Optional describeConstable() { 32 | return Optional.of(desc()); 33 | } 34 | 35 | public boolean equals(final ConstImpl obj) { 36 | return obj instanceof ClassConst other && equals(other); 37 | } 38 | 39 | public boolean equals(final ClassConst other) { 40 | return this == other || other != null && value.equals(other.value); 41 | } 42 | 43 | public int hashCode() { 44 | return value.hashCode(); 45 | } 46 | 47 | public StringBuilder toShortString(final StringBuilder b) { 48 | return Util.descName(b.append("Class["), value).append(']'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/DynamicConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ConstantDesc; 4 | import java.lang.constant.DynamicConstantDesc; 5 | import java.util.Optional; 6 | 7 | public final class DynamicConst extends ConstImpl { 8 | 9 | private final DynamicConstantDesc desc; 10 | 11 | public DynamicConst(final DynamicConstantDesc desc) { 12 | super(desc.constantType()); 13 | this.desc = desc; 14 | } 15 | 16 | public DynamicConst(final ConstantDesc constantDesc) { 17 | this((DynamicConstantDesc) constantDesc); 18 | } 19 | 20 | public boolean equals(final ConstImpl obj) { 21 | return obj instanceof DynamicConst other && equals(other); 22 | } 23 | 24 | public boolean equals(final DynamicConst other) { 25 | return this == other || other != null && desc.equals(other.desc); 26 | } 27 | 28 | public int hashCode() { 29 | return desc.hashCode(); 30 | } 31 | 32 | public DynamicConstantDesc desc() { 33 | return desc; 34 | } 35 | 36 | public Optional> describeConstable() { 37 | return Optional.of(desc); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/EnumConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.util.Objects; 4 | import java.util.Optional; 5 | 6 | import io.github.dmlloyd.classfile.CodeBuilder; 7 | import io.quarkus.gizmo2.impl.BlockCreatorImpl; 8 | import io.quarkus.gizmo2.impl.Util; 9 | 10 | public final class EnumConst extends ConstImpl { 11 | private final Enum.EnumDesc desc; 12 | private final int hashCode; 13 | 14 | public EnumConst(final Enum.EnumDesc desc) { 15 | super(desc.constantType()); 16 | this.desc = desc; 17 | this.hashCode = Objects.hash(desc.constantName(), desc.constantType()); 18 | } 19 | 20 | /** 21 | * {@return the name of the enum constant} 22 | */ 23 | public String name() { 24 | return desc.constantName(); 25 | } 26 | 27 | public Enum.EnumDesc desc() { 28 | return desc; 29 | } 30 | 31 | public boolean isNonZero() { 32 | return true; 33 | } 34 | 35 | public boolean equals(final ConstImpl obj) { 36 | return obj instanceof EnumConst other && equals(other); 37 | } 38 | 39 | public boolean equals(final EnumConst other) { 40 | return this == other || other != null && name().equals(other.name()) && type().equals(other.type()); 41 | } 42 | 43 | public int hashCode() { 44 | return hashCode; 45 | } 46 | 47 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 48 | cb.getstatic(desc.constantType(), desc.constantName(), desc.constantType()); 49 | } 50 | 51 | public Optional> describeConstable() { 52 | return Optional.of(desc()); 53 | } 54 | 55 | public StringBuilder toShortString(final StringBuilder b) { 56 | return Util.descName(b, desc.constantType()).append('#').append(desc.constantName()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/FieldVarHandleConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.invoke.VarHandle; 4 | 5 | import io.quarkus.gizmo2.desc.FieldDesc; 6 | 7 | public final class FieldVarHandleConst extends VarHandleConst { 8 | private final FieldDesc field; 9 | 10 | public FieldVarHandleConst(final FieldDesc field) { 11 | super(VarHandle.VarHandleDesc.ofField(field.owner(), field.name(), field.type())); 12 | this.field = field; 13 | } 14 | 15 | public boolean equals(final VarHandleConst obj) { 16 | return obj instanceof FieldVarHandleConst other && equals(other); 17 | } 18 | 19 | public boolean equals(final FieldVarHandleConst other) { 20 | return this == other || other != null && field.equals(other.field); 21 | } 22 | 23 | public int hashCode() { 24 | return field.hashCode(); 25 | } 26 | 27 | public StringBuilder toShortString(final StringBuilder b) { 28 | b.append("VarHandle["); 29 | field.toString(b); 30 | return b.append(']'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/IntBasedConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ClassDesc; 4 | 5 | import io.github.dmlloyd.classfile.CodeBuilder; 6 | import io.quarkus.gizmo2.impl.BlockCreatorImpl; 7 | 8 | public abstract class IntBasedConst extends ConstImpl { 9 | IntBasedConst(ClassDesc type) { 10 | super(type); 11 | } 12 | 13 | public abstract int intValue(); 14 | 15 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 16 | int i = intValue(); 17 | switch (i) { 18 | case -5 -> { 19 | cb.iconst_5(); 20 | cb.ineg(); 21 | } 22 | case -4 -> { 23 | cb.iconst_4(); 24 | cb.ineg(); 25 | } 26 | case -3 -> { 27 | cb.iconst_3(); 28 | cb.ineg(); 29 | } 30 | case -2 -> { 31 | cb.iconst_2(); 32 | cb.ineg(); 33 | } 34 | default -> cb.loadConstant(i); 35 | } 36 | } 37 | 38 | public boolean isZero() { 39 | return intValue() == 0; 40 | } 41 | 42 | public boolean isNonZero() { 43 | return intValue() != 0; 44 | } 45 | 46 | public StringBuilder toShortString(final StringBuilder b) { 47 | int i = intValue(); 48 | return b.append(i).append(" (0x").append(Integer.toHexString(i)).append(')'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/IntConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ConstantDesc; 4 | import java.lang.constant.ConstantDescs; 5 | import java.util.Optional; 6 | 7 | public final class IntConst extends IntBasedConst { 8 | private final Integer value; 9 | 10 | public IntConst(Integer value) { 11 | super(ConstantDescs.CD_int); 12 | this.value = value; 13 | } 14 | 15 | public IntConst(final ConstantDesc constantDesc) { 16 | this((Integer) constantDesc); 17 | } 18 | 19 | public int intValue() { 20 | return value.intValue(); 21 | } 22 | 23 | public boolean equals(final ConstImpl obj) { 24 | return obj instanceof IntConst other && equals(other); 25 | } 26 | 27 | public boolean equals(final IntConst other) { 28 | return this == other || other != null && value.equals(other.value); 29 | } 30 | 31 | public int hashCode() { 32 | return value.hashCode(); 33 | } 34 | 35 | public Integer desc() { 36 | return value; 37 | } 38 | 39 | public Optional describeConstable() { 40 | return Optional.of(value); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/InvokeConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ConstantDesc; 4 | import java.lang.constant.ConstantDescs; 5 | import java.lang.constant.DynamicConstantDesc; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | import java.util.Optional; 9 | import java.util.stream.Stream; 10 | 11 | public final class InvokeConst extends ConstImpl { 12 | private final MethodHandleConst handleConstant; 13 | private final List args; 14 | 15 | InvokeConst(final MethodHandleConst handleConstant, final List args) { 16 | super(handleConstant.desc().invocationType().returnType()); 17 | this.handleConstant = handleConstant; 18 | this.args = args; 19 | } 20 | 21 | public boolean equals(final ConstImpl obj) { 22 | return obj instanceof InvokeConst other && equals(other); 23 | } 24 | 25 | public boolean equals(final InvokeConst other) { 26 | return this == other || other != null && handleConstant.equals(other.handleConstant) && args.equals(other.args); 27 | } 28 | 29 | public int hashCode() { 30 | return handleConstant.hashCode() * 19 + args.hashCode(); 31 | } 32 | 33 | public ConstantDesc desc() { 34 | return DynamicConstantDesc.of( 35 | ConstantDescs.BSM_INVOKE, 36 | Stream.concat( 37 | Stream.of(handleConstant.desc()), 38 | args.stream().map(ConstImpl::describeConstable).map(Optional::orElseThrow)) 39 | .toArray(ConstantDesc[]::new)); 40 | } 41 | 42 | public Optional describeConstable() { 43 | return Optional.of(desc()); 44 | } 45 | 46 | public StringBuilder toShortString(final StringBuilder b) { 47 | b.append("Invoke["); 48 | handleConstant.toShortString(b).append("]("); 49 | Iterator iterator = args.iterator(); 50 | if (iterator.hasNext()) { 51 | handleConstant.toShortString(b); 52 | while (iterator.hasNext()) { 53 | b.append(','); 54 | handleConstant.toShortString(b); 55 | } 56 | } 57 | return b.append(')'); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/MethodTypeConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ConstantDesc; 4 | import java.lang.constant.ConstantDescs; 5 | import java.lang.constant.MethodTypeDesc; 6 | import java.util.Optional; 7 | 8 | public final class MethodTypeConst extends ConstImpl { 9 | private final MethodTypeDesc desc; 10 | 11 | MethodTypeConst(final MethodTypeDesc desc) { 12 | super(ConstantDescs.CD_MethodType); 13 | this.desc = desc; 14 | } 15 | 16 | public boolean isNonZero() { 17 | return true; 18 | } 19 | 20 | public boolean equals(final ConstImpl obj) { 21 | return obj instanceof MethodTypeConst other && equals(other); 22 | } 23 | 24 | public boolean equals(final MethodTypeConst other) { 25 | return this == other || other != null && desc.equals(other.desc); 26 | } 27 | 28 | public int hashCode() { 29 | return desc.hashCode(); 30 | } 31 | 32 | public ConstantDesc desc() { 33 | return desc; 34 | } 35 | 36 | public Optional describeConstable() { 37 | return Optional.of(desc); 38 | } 39 | 40 | public StringBuilder toShortString(final StringBuilder b) { 41 | b.append('('); 42 | int pc = desc.parameterCount(); 43 | for (int i = 0; i < pc; i++) { 44 | b.append(desc.parameterType(i).descriptorString()); 45 | } 46 | return b.append(')').append(desc.returnType().descriptorString()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/NullConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ClassDesc; 4 | import java.lang.constant.ConstantDesc; 5 | import java.lang.constant.ConstantDescs; 6 | import java.lang.constant.DynamicConstantDesc; 7 | import java.util.Optional; 8 | 9 | import io.github.dmlloyd.classfile.CodeBuilder; 10 | import io.quarkus.gizmo2.impl.BlockCreatorImpl; 11 | import io.quarkus.gizmo2.impl.Util; 12 | 13 | public final class NullConst extends ConstImpl { 14 | 15 | private final DynamicConstantDesc desc = DynamicConstantDesc.of(ConstantDescs.BSM_NULL_CONSTANT, "_", type()); 16 | 17 | public NullConst(final ClassDesc type) { 18 | super(type); 19 | } 20 | 21 | public boolean isZero() { 22 | return true; 23 | } 24 | 25 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 26 | cb.aconst_null(); 27 | } 28 | 29 | public ConstantDesc desc() { 30 | return desc; 31 | } 32 | 33 | public Optional describeConstable() { 34 | return Optional.of(desc()); 35 | } 36 | 37 | public boolean equals(final ConstImpl obj) { 38 | return obj instanceof NullConst other && equals(other); 39 | } 40 | 41 | public boolean equals(final NullConst other) { 42 | return this == other || other != null && type().equals(other.type()); 43 | } 44 | 45 | public int hashCode() { 46 | return type().hashCode() + 19; 47 | } 48 | 49 | public String toString() { 50 | return "null"; 51 | } 52 | 53 | public StringBuilder toShortString(final StringBuilder b) { 54 | return Util.descName(b.append('('), type()).append(")null"); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/ShortConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import static java.lang.constant.ConstantDescs.CD_short; 4 | 5 | import java.lang.constant.DynamicConstantDesc; 6 | import java.util.Optional; 7 | 8 | public final class ShortConst extends IntBasedConst { 9 | private final Short value; 10 | 11 | public ShortConst(Short value) { 12 | super(CD_short); 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public int intValue() { 18 | return value.intValue(); 19 | } 20 | 21 | public boolean equals(final ConstImpl obj) { 22 | return obj instanceof ShortConst other && equals(other); 23 | } 24 | 25 | public boolean equals(final ShortConst other) { 26 | return this == other || other != null && value.equals(other.value); 27 | } 28 | 29 | public int hashCode() { 30 | return value.hashCode(); 31 | } 32 | 33 | public DynamicConstantDesc desc() { 34 | return describeConstable().orElseThrow(); 35 | } 36 | 37 | public Optional> describeConstable() { 38 | return value.describeConstable(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/StaticFieldVarHandleConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.invoke.VarHandle; 4 | 5 | import io.quarkus.gizmo2.desc.FieldDesc; 6 | 7 | public final class StaticFieldVarHandleConst extends VarHandleConst { 8 | private final FieldDesc field; 9 | 10 | public StaticFieldVarHandleConst(final FieldDesc field) { 11 | super(VarHandle.VarHandleDesc.ofStaticField(field.owner(), field.name(), field.type())); 12 | this.field = field; 13 | } 14 | 15 | public boolean equals(final VarHandleConst obj) { 16 | return obj instanceof StaticFieldVarHandleConst other && equals(other); 17 | } 18 | 19 | public boolean equals(final StaticFieldVarHandleConst other) { 20 | return this == other || other != null && field.equals(other.field); 21 | } 22 | 23 | public int hashCode() { 24 | return field.hashCode(); 25 | } 26 | 27 | public StringBuilder toShortString(final StringBuilder b) { 28 | b.append("VarHandle[static "); 29 | field.toString(b); 30 | return b.append(']'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/StringConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ConstantDesc; 4 | import java.lang.constant.ConstantDescs; 5 | import java.util.Optional; 6 | 7 | public final class StringConst extends ConstImpl { 8 | 9 | private final String value; 10 | 11 | public StringConst(String value) { 12 | super(ConstantDescs.CD_String); 13 | this.value = value; 14 | } 15 | 16 | public StringConst(final ConstantDesc constantDesc) { 17 | this((String) constantDesc); 18 | } 19 | 20 | public String desc() { 21 | return value; 22 | } 23 | 24 | public Optional describeConstable() { 25 | return Optional.of(desc()); 26 | } 27 | 28 | public boolean isNonZero() { 29 | return true; 30 | } 31 | 32 | public boolean equals(final ConstImpl obj) { 33 | return obj instanceof StringConst other && equals(other); 34 | } 35 | 36 | public boolean equals(final StringConst other) { 37 | return this == other || other != null && value.equals(other.value); 38 | } 39 | 40 | public int hashCode() { 41 | return value.hashCode(); 42 | } 43 | 44 | private static final char[] hexDigits = "0123456789abcdef".toCharArray(); 45 | 46 | public StringBuilder toShortString(final StringBuilder b) { 47 | b.append('"'); 48 | int cp; 49 | for (int i = 0; i < value.length(); i += Character.charCount(cp)) { 50 | cp = value.codePointAt(i); 51 | switch (cp) { 52 | case '\b' -> b.append("\\b"); 53 | case '\f' -> b.append("\\f"); 54 | case '\n' -> b.append("\\n"); 55 | case '\r' -> b.append("\\r"); 56 | case '\t' -> b.append("\\t"); 57 | case '"', '\\' -> b.append('\\').appendCodePoint(cp); 58 | default -> { 59 | if (Character.isISOControl(cp)) { 60 | assert cp < 256; 61 | b.append('\\').append('u').append("00") 62 | .append(hexDigits[cp >>> 4]) 63 | .append(hexDigits[cp & 0x0f]); 64 | } else { 65 | b.appendCodePoint(cp); 66 | } 67 | } 68 | } 69 | } 70 | b.append('"'); 71 | return b; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/VarHandleConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ConstantDesc; 4 | import java.lang.invoke.VarHandle; 5 | import java.util.Optional; 6 | 7 | import io.quarkus.gizmo2.impl.Util; 8 | 9 | public abstract class VarHandleConst extends ConstImpl { 10 | final VarHandle.VarHandleDesc desc; 11 | 12 | VarHandleConst(final VarHandle.VarHandleDesc desc) { 13 | super(Util.classDesc(VarHandle.class)); 14 | this.desc = desc; 15 | } 16 | 17 | public boolean isNonZero() { 18 | return true; 19 | } 20 | 21 | public final boolean equals(final ConstImpl obj) { 22 | return obj instanceof VarHandleConst other && equals(other); 23 | } 24 | 25 | public abstract boolean equals(final VarHandleConst obj); 26 | 27 | public ConstantDesc desc() { 28 | return desc; 29 | } 30 | 31 | public Optional describeConstable() { 32 | return Optional.of(desc); 33 | } 34 | 35 | public StringBuilder toShortString(final StringBuilder b) { 36 | return b.append(desc); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/quarkus/gizmo2/impl/constant/VoidConst.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.impl.constant; 2 | 3 | import java.lang.constant.ConstantDesc; 4 | import java.lang.constant.ConstantDescs; 5 | import java.util.Optional; 6 | 7 | import io.github.dmlloyd.classfile.CodeBuilder; 8 | import io.quarkus.gizmo2.impl.BlockCreatorImpl; 9 | 10 | public final class VoidConst extends ConstImpl { 11 | public static final VoidConst INSTANCE = new VoidConst(); 12 | 13 | private VoidConst() { 14 | super(ConstantDescs.CD_void); 15 | } 16 | 17 | public boolean equals(final ConstImpl other) { 18 | return other == this; 19 | } 20 | 21 | public int hashCode() { 22 | return 0; 23 | } 24 | 25 | public ConstantDesc desc() { 26 | throw new IllegalArgumentException("No constant description for void"); 27 | } 28 | 29 | public void writeCode(final CodeBuilder cb, final BlockCreatorImpl block) { 30 | // no operation (invisible) 31 | } 32 | 33 | public Optional describeConstable() { 34 | return Optional.empty(); 35 | } 36 | 37 | public String toString() { 38 | return "void"; 39 | } 40 | 41 | public StringBuilder toShortString(final StringBuilder b) { 42 | return b.append("void"); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * A simplified bytecode generator. 3 | */ 4 | module io.quarkus.gizmo2 { 5 | requires io.github.dmlloyd.classfile; 6 | requires io.smallrye.common.constraint; 7 | 8 | // for accessing serializable lambdas via ReflectionFactory 9 | requires jdk.unsupported; 10 | 11 | exports io.quarkus.gizmo2; 12 | exports io.quarkus.gizmo2.creator; 13 | exports io.quarkus.gizmo2.creator.ops; 14 | exports io.quarkus.gizmo2.desc; 15 | } -------------------------------------------------------------------------------- /src/test/java/io/quarkus/gizmo2/InstanceExecutableCreatorTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import static org.junit.jupiter.api.Assertions.*; 4 | 5 | import java.lang.constant.ClassDesc; 6 | import java.util.List; 7 | import java.util.function.Function; 8 | 9 | import org.junit.jupiter.api.Test; 10 | 11 | import io.quarkus.gizmo2.desc.ConstructorDesc; 12 | import io.quarkus.gizmo2.desc.MethodDesc; 13 | 14 | public class InstanceExecutableCreatorTest { 15 | 16 | @SuppressWarnings("unchecked") 17 | @Test 18 | public void testThis() { 19 | TestClassMaker tcm = new TestClassMaker(); 20 | Gizmo g = Gizmo.create(tcm); 21 | g.class_(ClassDesc.of("io.quarkus.gizmo2.TestFun"), cc -> { 22 | cc.implements_( 23 | (GenericType.OfClass) GenericType.of(Function.class, 24 | List.of(TypeArgument.of(String.class), TypeArgument.of(String.class)))); 25 | cc.constructor(con -> { 26 | con.public_(); 27 | con.body(bc -> { 28 | bc.invokeSpecial(ConstructorDesc.of(Object.class), cc.this_()); 29 | bc.return_(); 30 | }); 31 | }); 32 | MethodDesc convert = cc.method("convert", mc -> { 33 | ParamVar p = mc.parameter("value", String.class); 34 | mc.returning(String.class); 35 | mc.body(bc -> { 36 | // return val.toLowerCase(); 37 | Expr ret = bc.invokeVirtual(MethodDesc.of(String.class, "toLowerCase", String.class), p); 38 | bc.return_(ret); 39 | }); 40 | }); 41 | cc.method("apply", mc -> { 42 | ParamVar p = mc.parameter("t", Object.class); 43 | mc.returning(Object.class); 44 | mc.public_(); 45 | mc.body(bc -> { 46 | // return convert((String)t); 47 | Expr strVal = bc.cast(p, String.class); 48 | bc.return_(bc.invokeVirtual(convert, cc.this_(), strVal)); 49 | }); 50 | }); 51 | }); 52 | assertEquals("foo", tcm.noArgsConstructor(Function.class).apply("Foo")); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/io/quarkus/gizmo2/MethodThrowsTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2; 2 | 3 | import static org.junit.jupiter.api.Assertions.*; 4 | 5 | import java.lang.constant.ClassDesc; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import io.quarkus.gizmo2.creator.BlockCreator; 10 | 11 | public final class MethodThrowsTest { 12 | @Test 13 | public void testThrowsDecl() throws NoSuchMethodException { 14 | TestClassMaker tcm = new TestClassMaker(); 15 | Gizmo g = Gizmo.create(tcm); 16 | g.class_(ClassDesc.of("io.quarkus.gizmo2.TestThrowsDecl"), zc -> { 17 | zc.staticMethod("test", mc -> { 18 | mc.throws_(RuntimeException.class); 19 | mc.throws_(ClassNotFoundException.class); 20 | mc.body(BlockCreator::return_); 21 | }); 22 | }); 23 | Class[] types = tcm.definedClass().getDeclaredMethod("test").getExceptionTypes(); 24 | assertArrayEquals(new Class[] { RuntimeException.class, ClassNotFoundException.class }, types); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/io/quarkus/gizmo2/ops/ListOpsTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.ops; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import java.util.List; 6 | import java.util.function.Function; 7 | 8 | import org.junit.jupiter.api.Test; 9 | 10 | import io.quarkus.gizmo2.Const; 11 | import io.quarkus.gizmo2.Gizmo; 12 | import io.quarkus.gizmo2.ParamVar; 13 | import io.quarkus.gizmo2.TestClassMaker; 14 | import io.quarkus.gizmo2.creator.ops.ListOps; 15 | 16 | public class ListOpsTest { 17 | 18 | @SuppressWarnings("unchecked") 19 | @Test 20 | public void testListGet() { 21 | TestClassMaker tcm = new TestClassMaker(); 22 | Gizmo g = Gizmo.create(tcm); 23 | g.class_("io.quarkus.gizmo2.ListGet", cc -> { 24 | cc.staticMethod("test", mc -> { 25 | // static Object test(Object t) { 26 | // List list = (List)t; 27 | // if (list.size() > 1) { 28 | // return list.get(list.size() - 1); 29 | // } 30 | // return list.get(0); 31 | // } 32 | ParamVar t = mc.parameter("t", Object.class); 33 | mc.returning(Object.class); 34 | mc.body(bc -> { 35 | var list = bc.localVar("list", bc.cast(t, List.class)); 36 | ListOps listOps = bc.withList(list); 37 | var size = bc.localVar("size", listOps.size()); 38 | bc.if_(bc.gt(size, 1), gt1 -> { 39 | gt1.return_(gt1.withList(list).get(gt1.sub(size, Const.of(1)))); 40 | }); 41 | bc.return_(listOps.get(0)); 42 | }); 43 | }); 44 | }); 45 | assertEquals("bar", tcm.staticMethod("test", Function.class).apply(List.of("foo", "bar"))); 46 | assertEquals("foo", tcm.staticMethod("test", Function.class).apply(List.of("foo"))); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/io/quarkus/gizmo2/ops/ThrowableOpsTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkus.gizmo2.ops; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertThrows; 5 | 6 | import org.junit.jupiter.api.Test; 7 | 8 | import io.quarkus.gizmo2.Const; 9 | import io.quarkus.gizmo2.Gizmo; 10 | import io.quarkus.gizmo2.TestClassMaker; 11 | import io.quarkus.gizmo2.creator.ops.ThrowableOps; 12 | 13 | public class ThrowableOpsTest { 14 | 15 | @Test 16 | public void testThrowableAddSuppressed() { 17 | TestClassMaker tcm = new TestClassMaker(); 18 | Gizmo g = Gizmo.create(tcm); 19 | g.class_("io.quarkus.gizmo2.Throwables", cc -> { 20 | cc.staticMethod("test", mc -> { 21 | // static void test() { 22 | // Exception e = new IllegalStateException("foo"); 23 | // e.addSuppressed(new NullPointerException("npe")); 24 | // e.addSuppressed(new IllegalArgumentException("iae")); 25 | // throw e; 26 | // } 27 | mc.body(bc -> { 28 | var e = bc.localVar("e", bc.new_(IllegalStateException.class, Const.of("foo"))); 29 | ThrowableOps throwableOps = bc.withThrowable(e); 30 | throwableOps.addSuppressed(bc.new_(NullPointerException.class, Const.of("npe"))); 31 | throwableOps.addSuppressed(bc.new_(IllegalArgumentException.class, Const.of("iae"))); 32 | bc.throw_(e); 33 | }); 34 | }); 35 | }); 36 | IllegalStateException ise = assertThrows(IllegalStateException.class, 37 | () -> tcm.staticMethod("test", Runnable.class).run()); 38 | Throwable[] suppressed = ise.getSuppressed(); 39 | assertEquals(2, suppressed.length); 40 | assertEquals("npe", suppressed[0].getMessage()); 41 | assertEquals("iae", suppressed[1].getMessage()); 42 | } 43 | 44 | } 45 | --------------------------------------------------------------------------------