diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index fe82d5d0bf0..c1070bbcc77 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -330,6 +330,11 @@ public sealed interface CodeBuilder /** * A builder to add catch blocks. + *
+ * The order of catch blocks is significant. When an exception is thrown + * by the try block, the first catch block whose exception type is {@linkplain + * Class#isAssignableFrom(Class) the same class as or a superclass of} the + * class of exception thrown is branched to (JVMS {@jvms 2.10}). * * @see #trying * @see ExceptionCatch @@ -348,13 +353,16 @@ public sealed interface CodeBuilder * If the type of exception is {@code null} then the catch block catches * all exceptions. * + * @apiNote + * If the type of exception to catch is already handled by previous + * catch blocks, this block will never be executed. + * * @param exceptionType the type of exception to catch, may be {@code null} * @param catchHandler handler that receives a {@link BlockCodeBuilder} to * generate the body of the catch block * @return this builder - * @throws IllegalArgumentException if an existing catch block catches - * an exception of the given type or {@code exceptionType} - * represents a primitive type + * @throws IllegalArgumentException if {@code exceptionType} represents + * a primitive type * @see #catchingMulti * @see #catchingAll */ @@ -372,12 +380,16 @@ public sealed interface CodeBuilder * If list of exception types is empty then the catch block catches all * exceptions. * + * @apiNote + * If every type of exception to catch is already handled by previous + * catch blocks, this block will never be executed. + * * @param exceptionTypes the types of exception to catch * @param catchHandler handler that receives a {@link BlockCodeBuilder} * to generate the body of the catch block * @return this builder - * @throws IllegalArgumentException if an existing catch block catches - * one or more exceptions of the given types + * @throws IllegalArgumentException if any exception type represents a + * primitive type * @see #catching * @see #catchingAll */ @@ -392,10 +404,12 @@ public sealed interface CodeBuilder * The caught exception will be on top of the operand stack when the * catch block is entered. * + * @apiNote + * Since this block intercepts all exceptions, all subsequent catch + * blocks will never be executed. + * * @param catchAllHandler handler that receives a {@link BlockCodeBuilder} * to generate the body of the catch block - * @throws IllegalArgumentException if an existing catch block catches - * all exceptions * @see #catching * @see #catchingMulti */ diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java index e924ca718e7..b0e5af2941e 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java @@ -39,8 +39,10 @@ import jdk.internal.classfile.impl.AbstractPseudoInstruction; * A pseudo-instruction modeling an entry in the {@code exception_table} array * of a {@link CodeAttribute Code} attribute. Catch (JVMS {@jvms 3.12}) and * finally (JVMS {@jvms 3.14}) blocks in Java source code compile to exception - * table entries. Delivered as a {@link CodeElement} when traversing the - * contents of a {@link CodeModel}. + * table entries. The order of exception table entries is significant: when an + * exception is thrown in a method, execution branches to the first matching + * exception handler if such a handler exists (JVMS {@jvms 2.10}). Delivered as + * a {@link CodeElement} when traversing the contents of a {@link CodeModel}. *
* An exception table entry is composite:
* {@snippet lang=text :
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java
index d520753326e..89d43135551 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,8 +27,9 @@ package jdk.internal.classfile.impl;
import java.lang.classfile.CodeBuilder;
import java.lang.classfile.Label;
import java.lang.classfile.Opcode;
+import java.lang.classfile.constantpool.ClassEntry;
import java.lang.constant.ClassDesc;
-import java.lang.constant.ConstantDesc;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -39,14 +40,12 @@ public final class CatchBuilderImpl implements CodeBuilder.CatchBuilder {
final CodeBuilder b;
final BlockCodeBuilderImpl tryBlock;
final Label tryCatchEnd;
- final Set