diff --git a/tests/test_data/std/jdk/internal/ValueBased.class b/tests/test_data/std/jdk/internal/ValueBased.class
new file mode 100644
index 00000000..3c220a66
Binary files /dev/null and b/tests/test_data/std/jdk/internal/ValueBased.class differ
diff --git a/tests/test_data/std/jdk/internal/ValueBased.java b/tests/test_data/std/jdk/internal/ValueBased.java
new file mode 100644
index 00000000..d27ab73c
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/ValueBased.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+/**
+ * Indicates the API declaration in question is associated with a Value Based class.
+ * References to value-based classes
+ * should produce warnings about behavior that is inconsistent with value based semantics.
+ *
+ * Note this internal annotation is handled specially by the javac compiler.
+ * To work properly with {@code --release older-release}, it requires special
+ * handling in {@code make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java}
+ * and {@code src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java}.
+ *
+ * @since 16
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value={TYPE})
+public @interface ValueBased {
+}
+
diff --git a/tests/test_data/std/jdk/internal/access/JavaAWTAccess.class b/tests/test_data/std/jdk/internal/access/JavaAWTAccess.class
new file mode 100644
index 00000000..bf95dad1
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaAWTAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaAWTAccess.java b/tests/test_data/std/jdk/internal/access/JavaAWTAccess.java
new file mode 100644
index 00000000..a4c170ca
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaAWTAccess.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+public interface JavaAWTAccess {
+
+ // Returns the AppContext used for applet logging isolation, or null if
+ // no isolation is required.
+ // If there's no applet, or if the caller is a stand alone application,
+ // or running in the main app context, returns null.
+ // Otherwise, returns the AppContext of the calling applet.
+ public Object getAppletContext();
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.class b/tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.class
new file mode 100644
index 00000000..c94de1d7
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.java b/tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.java
new file mode 100644
index 00000000..139f0245
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+/**
+ * SharedSecrets interface used for the access from java.text.Bidi
+ */
+
+public interface JavaAWTFontAccess {
+
+ // java.awt.font.TextAttribute constants
+ public Object getTextAttributeConstant(String name);
+
+ // java.awt.font.NumericShaper
+ public void shape(Object shaper, char[] text, int start, int count);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaBeansAccess.class b/tests/test_data/std/jdk/internal/access/JavaBeansAccess.class
new file mode 100644
index 00000000..8ede588e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaBeansAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaBeansAccess.java b/tests/test_data/std/jdk/internal/access/JavaBeansAccess.java
new file mode 100644
index 00000000..bcde7323
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaBeansAccess.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+public interface JavaBeansAccess {
+ /**
+ * Returns the getter method for a property of the given name
+ * @param clazz The JavaBeans class
+ * @param property The property name
+ * @return The resolved property getter method
+ * @throws Exception
+ */
+ Method getReadMethod(Class> clazz, String property) throws Exception;
+
+ /**
+ * Return the value attribute of the associated
+ * @ConstructorProperties
annotation if that is present.
+ * @param ctr The constructor to extract the annotation value from
+ * @return The {@code value} attribute of the @ConstructorProperties
+ * annotation or {@code null} if the constructor is not annotated by
+ * this annotation or the annotation is not accessible.
+ */
+ String[] getConstructorPropertiesValue(Constructor> ctr);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaIOAccess.class b/tests/test_data/std/jdk/internal/access/JavaIOAccess.class
new file mode 100644
index 00000000..3647ab4f
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaIOAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaIOAccess.java b/tests/test_data/std/jdk/internal/access/JavaIOAccess.java
new file mode 100644
index 00000000..532c1f25
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaIOAccess.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2005, 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.io.Console;
+
+public interface JavaIOAccess {
+ Console console();
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.class b/tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.class
new file mode 100644
index 00000000..4ae3aded
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.java b/tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.java
new file mode 100644
index 00000000..5e627abc
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2007, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.access;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+import jdk.internal.ref.PhantomCleanable;
+
+/*
+ * @author Chris Hegarty
+ */
+
+public interface JavaIOFileDescriptorAccess {
+ public void set(FileDescriptor fdo, int fd);
+ public int get(FileDescriptor fdo);
+ public void setAppend(FileDescriptor fdo, boolean append);
+ public boolean getAppend(FileDescriptor fdo);
+ public void close(FileDescriptor fdo) throws IOException;
+ public void registerCleanup(FileDescriptor fdo);
+ public void registerCleanup(FileDescriptor fdo, PhantomCleanable cleanable);
+ public void unregisterCleanup(FileDescriptor fdo);
+
+ // Only valid on Windows
+ public void setHandle(FileDescriptor fdo, long handle);
+ public long getHandle(FileDescriptor fdo);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.class b/tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.class
new file mode 100644
index 00000000..3311e266
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.java b/tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.java
new file mode 100644
index 00000000..48a80ec7
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.access;
+
+import java.io.FilePermission;
+
+public interface JavaIOFilePermissionAccess {
+
+ /**
+ * Returns a new FilePermission plus an alternative path.
+ *
+ * @param input the input
+ * @return the new FilePermission plus the alt path (as npath2)
+ * or the input itself if no alt path is available.
+ */
+ FilePermission newPermPlusAltPath(FilePermission input);
+
+ /**
+ * Returns a new FilePermission using an alternative path.
+ *
+ * @param input the input
+ * @return the new FilePermission using the alt path (as npath)
+ * or null if no alt path is available
+ */
+ FilePermission newPermUsingAltPath(FilePermission input);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.class b/tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.class
new file mode 100644
index 00000000..20538b61
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.java b/tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.java
new file mode 100644
index 00000000..ec205e27
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020, 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.access;
+
+import java.io.PrintStream;
+
+public interface JavaIOPrintStreamAccess {
+ Object lock(PrintStream ps);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaIOPrintWriterAccess.class b/tests/test_data/std/jdk/internal/access/JavaIOPrintWriterAccess.class
new file mode 100644
index 00000000..c7f9370d
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaIOPrintWriterAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaIOPrintWriterAccess.java b/tests/test_data/std/jdk/internal/access/JavaIOPrintWriterAccess.java
new file mode 100644
index 00000000..8be54a76
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaIOPrintWriterAccess.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020, 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.access;
+
+import java.io.PrintWriter;
+
+public interface JavaIOPrintWriterAccess {
+ Object lock(PrintWriter pw);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaIORandomAccessFileAccess.class b/tests/test_data/std/jdk/internal/access/JavaIORandomAccessFileAccess.class
new file mode 100644
index 00000000..a78ccedf
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaIORandomAccessFileAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaIORandomAccessFileAccess.java b/tests/test_data/std/jdk/internal/access/JavaIORandomAccessFileAccess.java
new file mode 100644
index 00000000..f6c59908
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaIORandomAccessFileAccess.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+public interface JavaIORandomAccessFileAccess {
+ public RandomAccessFile openAndDelete(File file, String mode)
+ throws IOException;
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaLangAccess.class b/tests/test_data/std/jdk/internal/access/JavaLangAccess.class
new file mode 100644
index 00000000..0bc0dcae
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaLangAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaLangAccess.java b/tests/test_data/std/jdk/internal/access/JavaLangAccess.java
new file mode 100644
index 00000000..c31e745c
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaLangAccess.java
@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 2003, 2024, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.lang.annotation.Annotation;
+import java.lang.foreign.MemorySegment;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.stream.Stream;
+
+import jdk.internal.misc.CarrierThreadLocal;
+import jdk.internal.module.ServicesCatalog;
+import jdk.internal.reflect.ConstantPool;
+import jdk.internal.vm.Continuation;
+import jdk.internal.vm.ContinuationScope;
+import jdk.internal.vm.StackableScope;
+import jdk.internal.vm.ThreadContainer;
+import sun.reflect.annotation.AnnotationType;
+import sun.nio.ch.Interruptible;
+
+public interface JavaLangAccess {
+
+ /**
+ * Returns the list of {@code Method} objects for the declared public
+ * methods of this class or interface that have the specified method name
+ * and parameter types.
+ */
+ List getDeclaredPublicMethods(Class> klass, String name, Class>... parameterTypes);
+
+ /**
+ * Return most specific method that matches name and parameterTypes.
+ */
+ Method findMethod(Class> klass, boolean publicOnly, String name, Class>... parameterTypes);
+
+ /**
+ * Return the constant pool for a class.
+ */
+ ConstantPool getConstantPool(Class> klass);
+
+ /**
+ * Compare-And-Set the AnnotationType instance corresponding to this class.
+ * (This method only applies to annotation types.)
+ */
+ boolean casAnnotationType(Class> klass, AnnotationType oldType, AnnotationType newType);
+
+ /**
+ * Get the AnnotationType instance corresponding to this class.
+ * (This method only applies to annotation types.)
+ */
+ AnnotationType getAnnotationType(Class> klass);
+
+ /**
+ * Get the declared annotations for a given class, indexed by their types.
+ */
+ Map, Annotation> getDeclaredAnnotationMap(Class> klass);
+
+ /**
+ * Get the array of bytes that is the class-file representation
+ * of this Class' annotations.
+ */
+ byte[] getRawClassAnnotations(Class> klass);
+
+ /**
+ * Get the array of bytes that is the class-file representation
+ * of this Class' type annotations.
+ */
+ byte[] getRawClassTypeAnnotations(Class> klass);
+
+ /**
+ * Get the array of bytes that is the class-file representation
+ * of this Executable's type annotations.
+ */
+ byte[] getRawExecutableTypeAnnotations(Executable executable);
+
+ /**
+ * Returns the elements of an enum class or null if the
+ * Class object does not represent an enum type;
+ * the result is uncloned, cached, and shared by all callers.
+ */
+ > E[] getEnumConstantsShared(Class klass);
+
+ /**
+ * Set current thread's blocker field.
+ */
+ void blockedOn(Interruptible b);
+
+ /**
+ * Registers a shutdown hook.
+ *
+ * It is expected that this method with registerShutdownInProgress=true
+ * is only used to register DeleteOnExitHook since the first file
+ * may be added to the delete on exit list by the application shutdown
+ * hooks.
+ *
+ * @param slot the slot in the shutdown hook array, whose element
+ * will be invoked in order during shutdown
+ * @param registerShutdownInProgress true to allow the hook
+ * to be registered even if the shutdown is in progress.
+ * @param hook the hook to be registered
+ *
+ * @throws IllegalStateException if shutdown is in progress and
+ * the slot is not valid to register.
+ */
+ void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook);
+
+ /**
+ * Returns a new Thread with the given Runnable and an
+ * inherited AccessControlContext.
+ */
+ Thread newThreadWithAcc(Runnable target, @SuppressWarnings("removal") AccessControlContext acc);
+
+ /**
+ * Invokes the finalize method of the given object.
+ */
+ void invokeFinalize(Object o) throws Throwable;
+
+ /**
+ * Returns the ConcurrentHashMap used as a storage for ClassLoaderValue(s)
+ * associated with the given class loader, creating it if it doesn't already exist.
+ */
+ ConcurrentHashMap, ?> createOrGetClassLoaderValueMap(ClassLoader cl);
+
+ /**
+ * Defines a class with the given name to a class loader.
+ */
+ Class> defineClass(ClassLoader cl, String name, byte[] b, ProtectionDomain pd, String source);
+
+ /**
+ * Defines a class with the given name to a class loader with
+ * the given flags and class data.
+ *
+ * @see java.lang.invoke.MethodHandles.Lookup#defineClass
+ */
+ Class> defineClass(ClassLoader cl, Class> lookup, String name, byte[] b, ProtectionDomain pd, boolean initialize, int flags, Object classData);
+
+ /**
+ * Returns a class loaded by the bootstrap class loader.
+ */
+ Class> findBootstrapClassOrNull(String name);
+
+ /**
+ * Define a Package of the given name and module by the given class loader.
+ */
+ Package definePackage(ClassLoader cl, String name, Module module);
+
+ /**
+ * Record the non-exported packages of the modules in the given layer
+ */
+ void addNonExportedPackages(ModuleLayer layer);
+
+ /**
+ * Invalidate package access cache
+ */
+ void invalidatePackageAccessCache();
+
+ /**
+ * Defines a new module to the Java virtual machine. The module
+ * is defined to the given class loader.
+ *
+ * The URI is for information purposes only, it can be {@code null}.
+ */
+ Module defineModule(ClassLoader loader, ModuleDescriptor descriptor, URI uri);
+
+ /**
+ * Defines the unnamed module for the given class loader.
+ */
+ Module defineUnnamedModule(ClassLoader loader);
+
+ /**
+ * Updates the readability so that module m1 reads m2. The new read edge
+ * does not result in a strong reference to m2 (m2 can be GC'ed).
+ *
+ * This method is the same as m1.addReads(m2) but without a permission check.
+ */
+ void addReads(Module m1, Module m2);
+
+ /**
+ * Updates module m to read all unnamed modules.
+ */
+ void addReadsAllUnnamed(Module m);
+
+ /**
+ * Updates module m1 to export a package unconditionally.
+ */
+ void addExports(Module m1, String pkg);
+
+ /**
+ * Updates module m1 to export a package to module m2. The export does
+ * not result in a strong reference to m2 (m2 can be GC'ed).
+ */
+ void addExports(Module m1, String pkg, Module m2);
+
+ /**
+ * Updates a module m to export a package to all unnamed modules.
+ */
+ void addExportsToAllUnnamed(Module m, String pkg);
+
+ /**
+ * Updates module m1 to open a package to module m2. Opening the
+ * package does not result in a strong reference to m2 (m2 can be GC'ed).
+ */
+ void addOpens(Module m1, String pkg, Module m2);
+
+ /**
+ * Updates module m to open a package to all unnamed modules.
+ */
+ void addOpensToAllUnnamed(Module m, String pkg);
+
+ /**
+ * Updates module m to open all packages in the given sets.
+ */
+ void addOpensToAllUnnamed(Module m, Set concealedPkgs, Set exportedPkgs);
+
+ /**
+ * Updates module m to use a service.
+ */
+ void addUses(Module m, Class> service);
+
+ /**
+ * Returns true if module m reflectively exports a package to other
+ */
+ boolean isReflectivelyExported(Module module, String pn, Module other);
+
+ /**
+ * Returns true if module m reflectively opens a package to other
+ */
+ boolean isReflectivelyOpened(Module module, String pn, Module other);
+
+ /**
+ * Updates module m to allow access to restricted methods.
+ */
+ Module addEnableNativeAccess(Module m);
+
+ /**
+ * Updates module named {@code name} in layer {@code layer} to allow access to restricted methods.
+ * Returns true iff the given module exists in the given layer.
+ */
+ boolean addEnableNativeAccess(ModuleLayer layer, String name);
+
+ /**
+ * Updates all unnamed modules to allow access to restricted methods.
+ */
+ void addEnableNativeAccessToAllUnnamed();
+
+ /**
+ * Ensure that the given module has native access. If not, warn or
+ * throw exception depending on the configuration.
+ */
+ void ensureNativeAccess(Module m, Class> owner, String methodName, Class> currentClass);
+
+ /**
+ * Returns the ServicesCatalog for the given Layer.
+ */
+ ServicesCatalog getServicesCatalog(ModuleLayer layer);
+
+ /**
+ * Record that this layer has at least one module defined to the given
+ * class loader.
+ */
+ void bindToLoader(ModuleLayer layer, ClassLoader loader);
+
+ /**
+ * Returns an ordered stream of layers. The first element is the
+ * given layer, the remaining elements are its parents, in DFS order.
+ */
+ Stream layers(ModuleLayer layer);
+
+ /**
+ * Returns a stream of the layers that have modules defined to the
+ * given class loader.
+ */
+ Stream layers(ClassLoader loader);
+
+ /**
+ * Count the number of leading positive bytes in the range.
+ */
+ int countPositives(byte[] ba, int off, int len);
+
+ /**
+ * Constructs a new {@code String} by decoding the specified subarray of
+ * bytes using the specified {@linkplain java.nio.charset.Charset charset}.
+ *
+ * The caller of this method shall relinquish and transfer the ownership of
+ * the byte array to the callee since the later will not make a copy.
+ *
+ * @param bytes the byte array source
+ * @param cs the Charset
+ * @return the newly created string
+ * @throws CharacterCodingException for malformed or unmappable bytes
+ */
+ String newStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException;
+
+ /**
+ * Encode the given string into a sequence of bytes using the specified Charset.
+ *
+ * This method avoids copying the String's internal representation if the input
+ * is ASCII.
+ *
+ * This method throws CharacterCodingException instead of replacing when
+ * malformed input or unmappable characters are encountered.
+ *
+ * @param s the string to encode
+ * @param cs the charset
+ * @return the encoded bytes
+ * @throws CharacterCodingException for malformed input or unmappable characters
+ */
+ byte[] getBytesNoRepl(String s, Charset cs) throws CharacterCodingException;
+
+ /**
+ * Returns a new string by decoding from the given utf8 bytes array.
+ *
+ * @param off the index of the first byte to decode
+ * @param len the number of bytes to decode
+ * @return the newly created string
+ * @throws IllegalArgumentException for malformed or unmappable bytes.
+ */
+ String newStringUTF8NoRepl(byte[] bytes, int off, int len);
+
+ /**
+ * Get the char at index in a byte[] in internal UTF-16 representation,
+ * with no bounds checks.
+ *
+ * @param bytes the UTF-16 encoded bytes
+ * @param index of the char to retrieve, 0 <= index < (bytes.length >> 1)
+ * @return the char value
+ */
+ char getUTF16Char(byte[] bytes, int index);
+
+ /**
+ * Put the char at index in a byte[] in internal UTF-16 representation,
+ * with no bounds checks.
+ *
+ * @param bytes the UTF-16 encoded bytes
+ * @param index of the char to retrieve, 0 <= index < (bytes.length >> 1)
+ */
+ void putCharUTF16(byte[] bytes, int index, int ch);
+
+ /**
+ * Encode the given string into a sequence of bytes using utf8.
+ *
+ * @param s the string to encode
+ * @return the encoded bytes in utf8
+ * @throws IllegalArgumentException for malformed surrogates
+ */
+ byte[] getBytesUTF8NoRepl(String s);
+
+ /**
+ * Inflated copy from byte[] to char[], as defined by StringLatin1.inflate
+ */
+ void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len);
+
+ /**
+ * Decodes ASCII from the source byte array into the destination
+ * char array.
+ *
+ * @return the number of bytes successfully decoded, at most len
+ */
+ int decodeASCII(byte[] src, int srcOff, char[] dst, int dstOff, int len);
+
+ /**
+ * Returns the initial `System.in` to determine if it is replaced
+ * with `System.setIn(newIn)` method
+ */
+ InputStream initialSystemIn();
+
+ /**
+ * Returns the initial value of System.err.
+ */
+ PrintStream initialSystemErr();
+
+ /**
+ * Encodes ASCII codepoints as possible from the source array into
+ * the destination byte array, assuming that the encoding is ASCII
+ * compatible
+ *
+ * @return the number of bytes successfully encoded, or 0 if none
+ */
+ int encodeASCII(char[] src, int srcOff, byte[] dst, int dstOff, int len);
+
+ /**
+ * Set the cause of Throwable
+ * @param cause set t's cause to new value
+ */
+ void setCause(Throwable t, Throwable cause);
+
+ /**
+ * Get protection domain of the given Class
+ */
+ ProtectionDomain protectionDomain(Class> c);
+
+ /**
+ * Get a method handle of string concat helper method
+ */
+ MethodHandle stringConcatHelper(String name, MethodType methodType);
+
+ /**
+ * Prepends constant and the stringly representation of value into buffer,
+ * given the coder and final index. Index is measured in chars, not in bytes!
+ */
+ long stringConcatHelperPrepend(long indexCoder, byte[] buf, String value);
+
+ /**
+ * Get the string concat initial coder
+ */
+ long stringConcatInitialCoder();
+
+ /**
+ * Update lengthCoder for constant
+ */
+ long stringConcatMix(long lengthCoder, String constant);
+
+ /**
+ * Mix value length and coder into current length and coder.
+ */
+ long stringConcatMix(long lengthCoder, char value);
+
+ /**
+ * Join strings
+ */
+ String join(String prefix, String suffix, String delimiter, String[] elements, int size);
+
+ /*
+ * Get the class data associated with the given class.
+ * @param c the class
+ * @see java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
+ */
+ Object classData(Class> c);
+
+ int stringSize(long i);
+
+ int getCharsLatin1(long i, int index, byte[] buf);
+
+ int getCharsUTF16(long i, int index, byte[] buf);
+
+ long findNative(ClassLoader loader, String entry);
+
+ /**
+ * Direct access to Shutdown.exit to avoid security manager checks
+ * @param statusCode the status code
+ */
+ void exit(int statusCode);
+
+ /**
+ * Returns an array of all platform threads.
+ */
+ Thread[] getAllThreads();
+
+ /**
+ * Returns the ThreadContainer for a thread, may be null.
+ */
+ ThreadContainer threadContainer(Thread thread);
+
+ /**
+ * Starts a thread in the given ThreadContainer.
+ */
+ void start(Thread thread, ThreadContainer container);
+
+ /**
+ * Returns the top of the given thread's stackable scope stack.
+ */
+ StackableScope headStackableScope(Thread thread);
+
+ /**
+ * Sets the top of the current thread's stackable scope stack.
+ */
+ void setHeadStackableScope(StackableScope scope);
+
+ /**
+ * Returns the Thread object for the current platform thread. If the
+ * current thread is a virtual thread then this method returns the carrier.
+ */
+ Thread currentCarrierThread();
+
+ /**
+ * Executes the given value returning task on the current carrier thread.
+ */
+ V executeOnCarrierThread(Callable task) throws Exception;
+
+ /**
+ * Returns the value of the current carrier thread's copy of a thread-local.
+ */
+ T getCarrierThreadLocal(CarrierThreadLocal local);
+
+ /**
+ * Sets the value of the current carrier thread's copy of a thread-local.
+ */
+ void setCarrierThreadLocal(CarrierThreadLocal local, T value);
+
+ /**
+ * Removes the value of the current carrier thread's copy of a thread-local.
+ */
+ void removeCarrierThreadLocal(CarrierThreadLocal> local);
+
+ /**
+ * Returns {@code true} if there is a value in the current carrier thread's copy of
+ * thread-local, even if that values is {@code null}.
+ */
+ boolean isCarrierThreadLocalPresent(CarrierThreadLocal> local);
+
+ /**
+ * Returns the current thread's scoped values cache
+ */
+ Object[] scopedValueCache();
+
+ /**
+ * Sets the current thread's scoped values cache
+ */
+ void setScopedValueCache(Object[] cache);
+
+ /**
+ * Return the current thread's scoped value bindings.
+ */
+ Object scopedValueBindings();
+
+ /**
+ * Returns the innermost mounted continuation
+ */
+ Continuation getContinuation(Thread thread);
+
+ /**
+ * Sets the innermost mounted continuation
+ */
+ void setContinuation(Thread thread, Continuation continuation);
+
+ /**
+ * The ContinuationScope of virtual thread continuations
+ */
+ ContinuationScope virtualThreadContinuationScope();
+
+ /**
+ * Parks the current virtual thread.
+ * @throws WrongThreadException if the current thread is not a virtual thread
+ */
+ void parkVirtualThread();
+
+ /**
+ * Parks the current virtual thread for up to the given waiting time.
+ * @param nanos the maximum number of nanoseconds to wait
+ * @throws WrongThreadException if the current thread is not a virtual thread
+ */
+ void parkVirtualThread(long nanos);
+
+ /**
+ * Re-enables a virtual thread for scheduling. If the thread was parked then
+ * it will be unblocked, otherwise its next attempt to park will not block
+ * @param thread the virtual thread to unpark
+ * @throws IllegalArgumentException if the thread is not a virtual thread
+ * @throws RejectedExecutionException if the scheduler cannot accept a task
+ */
+ void unparkVirtualThread(Thread thread);
+
+ /**
+ * Creates a new StackWalker
+ */
+ StackWalker newStackWalkerInstance(Set options,
+ ContinuationScope contScope,
+ Continuation continuation);
+ /**
+ * Returns '' @ if classloader has a name
+ * explicitly set otherwise @
+ */
+ String getLoaderNameID(ClassLoader loader);
+
+ /**
+ * Copy the string bytes to an existing segment, avoiding intermediate copies.
+ */
+ void copyToSegmentRaw(String string, MemorySegment segment, long offset);
+
+ /**
+ * Are the string bytes compatible with the given charset?
+ */
+ boolean bytesCompatible(String string, Charset charset);
+
+ /**
+ * Is a security manager already set or allowed to be set
+ * (using -Djava.security.manager=allow)?
+ */
+ boolean allowSecurityManager();
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.class b/tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.class
new file mode 100644
index 00000000..d50bc259
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.java b/tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.java
new file mode 100644
index 00000000..56387038
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015, 2023, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import jdk.internal.foreign.abi.NativeEntryPoint;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.VarHandle;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.nio.ByteOrder;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+public interface JavaLangInvokeAccess {
+ /**
+ * Returns the declaring class for the given ResolvedMethodName.
+ * Used by {@code StackFrameInfo}.
+ */
+ Class> getDeclaringClass(Object rmname);
+
+ /**
+ * Returns the {@code MethodType} for the given method descriptor
+ * and class loader.
+ * Used by {@code StackFrameInfo}.
+ */
+ MethodType getMethodType(String descriptor, ClassLoader loader);
+
+ /**
+ * Returns true if the given flags has MN_CALLER_SENSITIVE flag set.
+ */
+ boolean isCallerSensitive(int flags);
+
+ /**
+ * Returns true if the given flags has MN_HIDDEN_MEMBER flag set.
+ */
+ boolean isHiddenMember(int flags);
+
+ /**
+ * Returns a map of class name in internal forms to its corresponding
+ * class bytes per the given stream of LF_RESOLVE and SPECIES_RESOLVE
+ * trace logs. Used by GenerateJLIClassesPlugin to enable generation
+ * of such classes during the jlink phase.
+ */
+ Map generateHolderClasses(Stream traces);
+
+ /**
+ * Returns a var handle view of a given memory segment.
+ * Used by {@code jdk.internal.foreign.LayoutPath} and
+ * {@code java.lang.invoke.MethodHandles}.
+ */
+ VarHandle memorySegmentViewHandle(Class> carrier, long alignmentMask, ByteOrder order);
+
+ /**
+ * Var handle carrier combinator.
+ * Used by {@code java.lang.invoke.MethodHandles}.
+ */
+ VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget);
+
+ /**
+ * Var handle filter coordinates combinator.
+ * Used by {@code java.lang.invoke.MethodHandles}.
+ */
+ VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters);
+
+ /**
+ * Var handle drop coordinates combinator.
+ * Used by {@code java.lang.invoke.MethodHandles}.
+ */
+ VarHandle dropCoordinates(VarHandle target, int pos, Class>... valueTypes);
+
+ /**
+ * Var handle permute coordinates combinator.
+ * Used by {@code java.lang.invoke.MethodHandles}.
+ */
+ VarHandle permuteCoordinates(VarHandle target, List> newCoordinates, int... reorder);
+
+ /**
+ * Var handle collect coordinates combinator.
+ * Used by {@code java.lang.invoke.MethodHandles}.
+ */
+ VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter);
+
+ /**
+ * Var handle insert coordinates combinator.
+ * Used by {@code java.lang.invoke.MethodHandles}.
+ */
+ VarHandle insertCoordinates(VarHandle target, int pos, Object... values);
+
+ /**
+ * Returns a native method handle with given arguments as fallback and steering info.
+ *
+ * Will allow JIT to intrinsify.
+ *
+ * @param nep the native entry point
+ * @return the native method handle
+ */
+ MethodHandle nativeMethodHandle(NativeEntryPoint nep);
+
+ /**
+ * Produces a method handle unreflecting from a {@code Constructor} with
+ * the trusted lookup
+ */
+ MethodHandle unreflectConstructor(Constructor> ctor) throws IllegalAccessException;
+
+ /**
+ * Produces a method handle unreflecting from a {@code Field} with
+ * the trusted lookup
+ */
+ MethodHandle unreflectField(Field field, boolean isSetter) throws IllegalAccessException;
+
+ /**
+ * Produces a method handle of a virtual method with the trusted lookup.
+ */
+ MethodHandle findVirtual(Class> defc, String name, MethodType type) throws IllegalAccessException;
+
+ /**
+ * Produces a method handle of a static method with the trusted lookup.
+ */
+ MethodHandle findStatic(Class> defc, String name, MethodType type) throws IllegalAccessException;
+
+ /**
+ * Returns a method handle of an invoker class injected for core reflection
+ * implementation with the following signature:
+ * reflect_invoke_V(MethodHandle mh, Object target, Object[] args)
+ *
+ * The invoker class is a hidden class which has the same
+ * defining class loader, runtime package, and protection domain
+ * as the given caller class.
+ */
+ MethodHandle reflectiveInvoker(Class> caller);
+
+ /**
+ * A best-effort method that tries to find any exceptions thrown by the given method handle.
+ * @param handle the handle to check
+ * @return an array of exceptions, or {@code null}.
+ */
+ Class>[] exceptionTypes(MethodHandle handle);
+
+ /**
+ * Returns a method handle that allocates an instance of the given class
+ * and then invoke the given constructor of one of its superclasses.
+ *
+ * This method should only be used by ReflectionFactory::newConstructorForSerialization.
+ */
+ MethodHandle serializableConstructor(Class> decl, Constructor> ctorToCall) throws IllegalAccessException;
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaLangModuleAccess.class b/tests/test_data/std/jdk/internal/access/JavaLangModuleAccess.class
new file mode 100644
index 00000000..a7068213
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaLangModuleAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaLangModuleAccess.java b/tests/test_data/std/jdk/internal/access/JavaLangModuleAccess.java
new file mode 100644
index 00000000..608dfb84
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaLangModuleAccess.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2015, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.io.PrintStream;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Version;
+import java.lang.module.ModuleFinder;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Provides access to non-public methods in java.lang.module.
+ */
+
+public interface JavaLangModuleAccess {
+
+ /**
+ * Creates a builder for building a module with the given module name.
+ *
+ * @param strict
+ * Indicates whether module names are checked or not
+ */
+ ModuleDescriptor.Builder newModuleBuilder(String mn,
+ boolean strict,
+ Set ms);
+
+ /**
+ * Returns a snapshot of the packages in the module.
+ */
+ Set packages(ModuleDescriptor.Builder builder);
+
+ /**
+ * Adds a dependence on a module with the given (possibly un-parsable)
+ * version string.
+ */
+ void requires(ModuleDescriptor.Builder builder,
+ Set ms,
+ String mn,
+ String rawCompiledVersion);
+
+ /**
+ * Returns a {@code ModuleDescriptor.Requires} of the given modifiers
+ * and module name.
+ */
+ Requires newRequires(Set ms, String mn, Version v);
+
+ /**
+ * Returns an unqualified {@code ModuleDescriptor.Exports}
+ * of the given modifiers and package name source.
+ */
+ Exports newExports(Set ms,
+ String source);
+
+ /**
+ * Returns a qualified {@code ModuleDescriptor.Exports}
+ * of the given modifiers, package name source and targets.
+ */
+ Exports newExports(Set ms,
+ String source,
+ Set targets);
+
+ /**
+ * Returns an unqualified {@code ModuleDescriptor.Opens}
+ * of the given modifiers and package name source.
+ */
+ Opens newOpens(Set ms, String source);
+
+ /**
+ * Returns a qualified {@code ModuleDescriptor.Opens}
+ * of the given modifiers, package name source and targets.
+ */
+ Opens newOpens(Set ms, String source, Set targets);
+
+ /**
+ * Returns a {@code ModuleDescriptor.Provides}
+ * of the given service name and providers.
+ */
+ Provides newProvides(String service, List providers);
+
+ /**
+ * Returns a new {@code ModuleDescriptor} instance.
+ */
+ ModuleDescriptor newModuleDescriptor(String name,
+ Version version,
+ Set ms,
+ Set requires,
+ Set exports,
+ Set opens,
+ Set uses,
+ Set provides,
+ Set packages,
+ String mainClass,
+ int hashCode);
+
+ /**
+ * Resolves a collection of root modules, with service binding
+ * and the empty configuration as the parent.
+ */
+ Configuration resolveAndBind(ModuleFinder finder,
+ Collection roots,
+ PrintStream traceOutput);
+
+ /**
+ * Creates a configuration from a pre-generated readability graph.
+ */
+ Configuration newConfiguration(ModuleFinder finder,
+ Map> graph);
+
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaLangRefAccess.class b/tests/test_data/std/jdk/internal/access/JavaLangRefAccess.class
new file mode 100644
index 00000000..209408f7
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaLangRefAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaLangRefAccess.java b/tests/test_data/std/jdk/internal/access/JavaLangRefAccess.java
new file mode 100644
index 00000000..ed9967ec
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaLangRefAccess.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.lang.ref.ReferenceQueue;
+
+public interface JavaLangRefAccess {
+
+ /**
+ * Starts the Finalizer and Reference Handler threads.
+ */
+ void startThreads();
+
+ /**
+ * Wait for progress in {@link java.lang.ref.Reference}
+ * processing. If there aren't any pending {@link
+ * java.lang.ref.Reference}s, return immediately.
+ *
+ * @return {@code true} if there were any pending
+ * {@link java.lang.ref.Reference}s, {@code false} otherwise.
+ */
+ boolean waitForReferenceProcessing() throws InterruptedException;
+
+ /**
+ * Runs the finalization methods of any objects pending finalization.
+ *
+ * Invoked by Runtime.runFinalization()
+ */
+ void runFinalization();
+
+ /**
+ * Constructs a new NativeReferenceQueue.
+ *
+ * Invoked by jdk.internal.util.ReferencedKeyMap
+ */
+ ReferenceQueue newNativeReferenceQueue();
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.class b/tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.class
new file mode 100644
index 00000000..2c558e5b
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.java b/tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.java
new file mode 100644
index 00000000..f49221e4
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2001, 2023, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.lang.reflect.*;
+import jdk.internal.reflect.*;
+
+/** An interface which gives privileged packages Java-level access to
+ internals of java.lang.reflect. */
+
+public interface JavaLangReflectAccess {
+ /** Creates a new java.lang.reflect.Constructor. Access checks as
+ per java.lang.reflect.AccessibleObject are not overridden. */
+ public Constructor newConstructor(Class declaringClass,
+ Class>[] parameterTypes,
+ Class>[] checkedExceptions,
+ int modifiers,
+ int slot,
+ String signature,
+ byte[] annotations,
+ byte[] parameterAnnotations);
+
+ /** Gets the MethodAccessor object for a java.lang.reflect.Method */
+ public MethodAccessor getMethodAccessor(Method m);
+
+ /** Sets the MethodAccessor object for a java.lang.reflect.Method */
+ public void setMethodAccessor(Method m, MethodAccessor accessor);
+
+ /** Gets the ConstructorAccessor object for a
+ java.lang.reflect.Constructor */
+ public ConstructorAccessor getConstructorAccessor(Constructor> c);
+
+ /** Sets the ConstructorAccessor object for a
+ java.lang.reflect.Constructor */
+ public void setConstructorAccessor(Constructor> c,
+ ConstructorAccessor accessor);
+
+ /** Gets the byte[] that encodes TypeAnnotations on an Executable. */
+ public byte[] getExecutableTypeAnnotationBytes(Executable ex);
+
+ /** Gets the "slot" field from a Constructor (used for serialization) */
+ public int getConstructorSlot(Constructor> c);
+
+ /** Gets the "signature" field from a Constructor (used for serialization) */
+ public String getConstructorSignature(Constructor> c);
+
+ /** Gets the "annotations" field from a Constructor (used for serialization) */
+ public byte[] getConstructorAnnotations(Constructor> c);
+
+ /** Gets the "parameterAnnotations" field from a Constructor (used for serialization) */
+ public byte[] getConstructorParameterAnnotations(Constructor> c);
+
+ /** Gets the shared array of parameter types of an Executable. */
+ public Class>[] getExecutableSharedParameterTypes(Executable ex);
+
+ /** Gets the shared array of exception types of an Executable. */
+ public Class>[] getExecutableSharedExceptionTypes(Executable ex);
+
+ //
+ // Copying routines, needed to quickly fabricate new Field,
+ // Method, and Constructor objects from templates
+ //
+
+ /** Makes a "child" copy of a Method */
+ public Method copyMethod(Method arg);
+
+ /** Makes a copy of this non-root a Method */
+ public Method leafCopyMethod(Method arg);
+
+ /** Makes a "child" copy of a Field */
+ public Field copyField(Field arg);
+
+ /** Makes a "child" copy of a Constructor */
+ public Constructor copyConstructor(Constructor arg);
+
+ /** Gets the root of the given AccessibleObject object; null if arg is the root */
+ public T getRoot(T obj);
+
+ /** Tests if this is a trusted final field */
+ public boolean isTrustedFinalField(Field f);
+
+ /** Returns a new instance created by the given constructor with access check */
+ public T newInstance(Constructor ctor, Object[] args, Class> caller)
+ throws IllegalAccessException, InstantiationException, InvocationTargetException;
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.class b/tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.class
new file mode 100644
index 00000000..7ae0b1bd
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.java b/tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.java
new file mode 100644
index 00000000..b76dbf33
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.net.HttpCookie;
+import java.util.List;
+
+public interface JavaNetHttpCookieAccess {
+ /*
+ * Constructs cookies from Set-Cookie or Set-Cookie2 header string,
+ * retaining the original header String in the cookie itself.
+ */
+ public List parse(String header);
+
+ /*
+ * Returns the original header this cookie was constructed from, if it was
+ * constructed by parsing a header, otherwise null.
+ */
+ public String header(HttpCookie cookie);
+}
+
diff --git a/tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.class b/tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.class
new file mode 100644
index 00000000..d9e1f147
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.java b/tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.java
new file mode 100644
index 00000000..d3e0e658
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 2021, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+
+public interface JavaNetInetAddressAccess {
+ /**
+ * Return the original application specified hostname of
+ * the given InetAddress object.
+ */
+ String getOriginalHostName(InetAddress ia);
+
+ /**
+ * Returns the 32-bit IPv4 address.
+ */
+ int addressValue(Inet4Address inet4Address);
+
+ /**
+ * Returns a reference to the byte[] with the IPv6 address.
+ */
+ byte[] addressBytes(Inet6Address inet6Address);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaNetURLAccess.class b/tests/test_data/std/jdk/internal/access/JavaNetURLAccess.class
new file mode 100644
index 00000000..7b1faf8e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaNetURLAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaNetURLAccess.java b/tests/test_data/std/jdk/internal/access/JavaNetURLAccess.java
new file mode 100644
index 00000000..0ad25d80
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaNetURLAccess.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.access;
+
+import java.net.URL;
+import java.net.URLStreamHandler;
+
+public interface JavaNetURLAccess {
+ URLStreamHandler getHandler(URL u);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaNetUriAccess.class b/tests/test_data/std/jdk/internal/access/JavaNetUriAccess.class
new file mode 100644
index 00000000..730b18d7
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaNetUriAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaNetUriAccess.java b/tests/test_data/std/jdk/internal/access/JavaNetUriAccess.java
new file mode 100644
index 00000000..8eb95a21
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaNetUriAccess.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2006, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.net.URI;
+
+public interface JavaNetUriAccess {
+ /**
+ * Create a URI of pre-validated scheme and path.
+ */
+ URI create(String scheme, String path);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaNioAccess.class b/tests/test_data/std/jdk/internal/access/JavaNioAccess.class
new file mode 100644
index 00000000..63ac2054
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaNioAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaNioAccess.java b/tests/test_data/std/jdk/internal/access/JavaNioAccess.java
new file mode 100644
index 00000000..b34a0d42
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaNioAccess.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2007, 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import jdk.internal.access.foreign.UnmapperProxy;
+import jdk.internal.misc.VM.BufferPool;
+
+import java.lang.foreign.MemorySegment;
+import java.io.FileDescriptor;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+
+public interface JavaNioAccess {
+
+ /**
+ * Used by {@code jdk.internal.misc.VM}.
+ */
+ BufferPool getDirectBufferPool();
+
+ /**
+ * Constructs a direct ByteBuffer referring to the block of memory starting
+ * at the given memory address and extending {@code cap} bytes.
+ * The {@code ob} parameter is an arbitrary object that is attached
+ * to the resulting buffer.
+ * Used by {@code jdk.internal.foreignMemorySegmentImpl}.
+ */
+ ByteBuffer newDirectByteBuffer(long addr, int cap, Object obj, MemorySegment segment);
+
+ /**
+ * Constructs a mapped ByteBuffer referring to the block of memory starting
+ * at the given memory address and extending {@code cap} bytes.
+ * The {@code ob} parameter is an arbitrary object that is attached
+ * to the resulting buffer. The {@code sync} and {@code fd} parameters of the mapped
+ * buffer are derived from the {@code UnmapperProxy}.
+ * Used by {@code jdk.internal.foreignMemorySegmentImpl}.
+ */
+ ByteBuffer newMappedByteBuffer(UnmapperProxy unmapperProxy, long addr, int cap, Object obj, MemorySegment segment);
+
+ /**
+ * Constructs an heap ByteBuffer with given backing array, offset, capacity and segment.
+ * Used by {@code jdk.internal.foreignMemorySegmentImpl}.
+ */
+ ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegment segment);
+
+ /**
+ * Used by {@code jdk.internal.foreign.Utils}.
+ */
+ Object getBufferBase(Buffer bb);
+
+ /**
+ * Used by {@code jdk.internal.foreign.Utils}.
+ */
+ long getBufferAddress(Buffer buffer);
+
+ /**
+ * Used by {@code jdk.internal.foreign.Utils}.
+ */
+ UnmapperProxy unmapper(Buffer buffer);
+
+ /**
+ * Used by {@code jdk.internal.foreign.AbstractMemorySegmentImpl} and byte buffer var handle views.
+ */
+ MemorySegment bufferSegment(Buffer buffer);
+
+ /**
+ * Used by operations to make a buffer's session non-closeable
+ * (for the duration of the operation) by acquiring the session.
+ * {@snippet lang = java:
+ * acquireSession(buffer);
+ * try {
+ * performOperation(buffer);
+ * } finally {
+ * releaseSession(buffer);
+ * }
+ *}
+ *
+ * @see #releaseSession(Buffer)
+ */
+ void acquireSession(Buffer buffer);
+
+ void releaseSession(Buffer buffer);
+
+ boolean isThreadConfined(Buffer buffer);
+
+ boolean hasSession(Buffer buffer);
+
+ /**
+ * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views.
+ */
+ void force(FileDescriptor fd, long address, boolean isSync, long offset, long size);
+
+ /**
+ * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views.
+ */
+ void load(long address, boolean isSync, long size);
+
+ /**
+ * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl}.
+ */
+ void unload(long address, boolean isSync, long size);
+
+ /**
+ * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views.
+ */
+ boolean isLoaded(long address, boolean isSync, long size);
+
+ /**
+ * Used by {@code jdk.internal.foreign.NativeMemorySegmentImpl}.
+ */
+ void reserveMemory(long size, long cap);
+
+ /**
+ * Used by {@code jdk.internal.foreign.NativeMemorySegmentImpl}.
+ */
+ void unreserveMemory(long size, long cap);
+
+ /**
+ * Used by {@code jdk.internal.foreign.NativeMemorySegmentImpl}.
+ */
+ int pageSize();
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.class b/tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.class
new file mode 100644
index 00000000..8a5242e4
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.java b/tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.java
new file mode 100644
index 00000000..bc60cbbb
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.io.ObjectInputFilter;
+
+/**
+ * Access to the alternative ObjectInputFilter.Config.createFilter2 for RMI.
+ */
+public interface JavaObjectInputFilterAccess {
+ /**
+ * Creates a filter from the pattern.
+ */
+ ObjectInputFilter createFilter2(String pattern);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.class b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.class
new file mode 100644
index 00000000..85420383
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.java b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.java
new file mode 100644
index 00000000..a47add47
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.io.ObjectStreamException;
+import java.io.ObjectInputStream;
+
+/**
+ * Interface to specify methods for accessing {@code ObjectInputStream}.
+ */
+@FunctionalInterface
+public interface JavaObjectInputStreamAccess {
+ void checkArray(ObjectInputStream ois, Class> arrayType, int arrayLength)
+ throws ObjectStreamException;
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.class b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.class
new file mode 100644
index 00000000..9366ed49
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.java b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.java
new file mode 100644
index 00000000..1ae489b7
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+/**
+ * Interface to specify methods for accessing {@code ObjectInputStream}.
+ */
+@FunctionalInterface
+public interface JavaObjectInputStreamReadString {
+ String readString(ObjectInputStream ois) throws IOException;
+}
+
diff --git a/tests/test_data/std/jdk/internal/access/JavaSecurityAccess$ProtectionDomainCache.class b/tests/test_data/std/jdk/internal/access/JavaSecurityAccess$ProtectionDomainCache.class
new file mode 100644
index 00000000..66dcadec
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaSecurityAccess$ProtectionDomainCache.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaSecurityAccess.class b/tests/test_data/std/jdk/internal/access/JavaSecurityAccess.class
new file mode 100644
index 00000000..2dce637e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaSecurityAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaSecurityAccess.java b/tests/test_data/std/jdk/internal/access/JavaSecurityAccess.java
new file mode 100644
index 00000000..cb1fd49c
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaSecurityAccess.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2010, 2021, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.security.AccessControlContext;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+
+public interface JavaSecurityAccess {
+
+ T doIntersectionPrivilege(PrivilegedAction action,
+ @SuppressWarnings("removal") AccessControlContext stack,
+ @SuppressWarnings("removal") AccessControlContext context);
+
+ T doIntersectionPrivilege(PrivilegedAction action,
+ @SuppressWarnings("removal") AccessControlContext context);
+
+ ProtectionDomain[] getProtectDomains(@SuppressWarnings("removal") AccessControlContext context);
+
+ interface ProtectionDomainCache {
+ void put(ProtectionDomain pd, PermissionCollection pc);
+ PermissionCollection get(ProtectionDomain pd);
+ }
+
+ /**
+ * Returns the ProtectionDomainCache.
+ */
+ ProtectionDomainCache getProtectionDomainCache();
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaSecurityPropertiesAccess.class b/tests/test_data/std/jdk/internal/access/JavaSecurityPropertiesAccess.class
new file mode 100644
index 00000000..2a8d1771
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaSecurityPropertiesAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaSecurityPropertiesAccess.java b/tests/test_data/std/jdk/internal/access/JavaSecurityPropertiesAccess.java
new file mode 100644
index 00000000..a4875f35
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaSecurityPropertiesAccess.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.util.Properties;
+
+public interface JavaSecurityPropertiesAccess {
+ Properties getInitialProperties();
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaSecuritySignatureAccess.class b/tests/test_data/std/jdk/internal/access/JavaSecuritySignatureAccess.class
new file mode 100644
index 00000000..be5097ce
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaSecuritySignatureAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaSecuritySignatureAccess.java b/tests/test_data/std/jdk/internal/access/JavaSecuritySignatureAccess.java
new file mode 100644
index 00000000..28adeaff
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaSecuritySignatureAccess.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+
+public interface JavaSecuritySignatureAccess {
+
+ void initVerify(Signature s, PublicKey publicKey, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ void initVerify(Signature s, java.security.cert.Certificate certificate,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ void initSign(Signature s, PrivateKey privateKey,
+ AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaSecuritySpecAccess.class b/tests/test_data/std/jdk/internal/access/JavaSecuritySpecAccess.class
new file mode 100644
index 00000000..07a3a204
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaSecuritySpecAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaSecuritySpecAccess.java b/tests/test_data/std/jdk/internal/access/JavaSecuritySpecAccess.java
new file mode 100644
index 00000000..c370074a
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaSecuritySpecAccess.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.security.spec.EncodedKeySpec;
+
+public interface JavaSecuritySpecAccess {
+ void clearEncodedKeySpec(EncodedKeySpec keySpec);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilCollectionAccess.class b/tests/test_data/std/jdk/internal/access/JavaUtilCollectionAccess.class
new file mode 100644
index 00000000..7dff52aa
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaUtilCollectionAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilCollectionAccess.java b/tests/test_data/std/jdk/internal/access/JavaUtilCollectionAccess.java
new file mode 100644
index 00000000..f88d5752
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaUtilCollectionAccess.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.util.List;
+
+public interface JavaUtilCollectionAccess {
+ List listFromTrustedArray(Object[] array);
+ List listFromTrustedArrayNullsAllowed(Object[] array);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentFJPAccess.class b/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentFJPAccess.class
new file mode 100644
index 00000000..ece63068
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentFJPAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentFJPAccess.java b/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentFJPAccess.java
new file mode 100644
index 00000000..28c1b7fd
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentFJPAccess.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.access;
+
+import java.util.concurrent.ForkJoinPool;
+
+public interface JavaUtilConcurrentFJPAccess {
+ long beginCompensatedBlock(ForkJoinPool pool);
+ void endCompensatedBlock(ForkJoinPool pool, long post);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentTLRAccess.class b/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentTLRAccess.class
new file mode 100644
index 00000000..68c4213e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentTLRAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentTLRAccess.java b/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentTLRAccess.java
new file mode 100644
index 00000000..5683146e
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentTLRAccess.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+public interface JavaUtilConcurrentTLRAccess {
+ int nextSecondaryThreadLocalRandomSeed();
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilJarAccess.class b/tests/test_data/std/jdk/internal/access/JavaUtilJarAccess.class
new file mode 100644
index 00000000..dcfaab98
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaUtilJarAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilJarAccess.java b/tests/test_data/std/jdk/internal/access/JavaUtilJarAccess.java
new file mode 100644
index 00000000..fb266330
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaUtilJarAccess.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2002, 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.io.IOException;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+public interface JavaUtilJarAccess {
+ public boolean jarFileHasClassPathAttribute(JarFile jar) throws IOException;
+ public Attributes getTrustedAttributes(Manifest man, String name);
+ public void ensureInitialization(JarFile jar);
+ public boolean isInitializing();
+ public JarEntry entryFor(JarFile file, String name);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilResourceBundleAccess.class b/tests/test_data/std/jdk/internal/access/JavaUtilResourceBundleAccess.class
new file mode 100644
index 00000000..ffd55232
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaUtilResourceBundleAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilResourceBundleAccess.java b/tests/test_data/std/jdk/internal/access/JavaUtilResourceBundleAccess.java
new file mode 100644
index 00000000..fb8fda8f
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaUtilResourceBundleAccess.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * Provides access to non-public methods in java.util.ResourceBundle.
+ */
+public interface JavaUtilResourceBundleAccess {
+ /**
+ * Sets the bundle's parent to the given parent.
+ */
+ void setParent(ResourceBundle bundle, ResourceBundle parent);
+
+ /**
+ * Returns the parent of the given bundle or null if the bundle has no parent.
+ */
+ ResourceBundle getParent(ResourceBundle bundle);
+
+ /**
+ * Sets the bundle's locale to the given locale.
+ */
+ void setLocale(ResourceBundle bundle, Locale locale);
+
+ /**
+ * Sets the bundle's base name to the given name.
+ */
+ void setName(ResourceBundle bundle, String name);
+
+ /**
+ * Returns a {@code ResourceBundle} of the given baseName and locale
+ * loaded on behalf of the given module with no caller module
+ * access check.
+ */
+ ResourceBundle getBundle(String baseName, Locale locale, Module module);
+
+ /**
+ * Instantiates a {@code ResourceBundle} of the given bundle class.
+ */
+ ResourceBundle newResourceBundle(Class extends ResourceBundle> bundleClass);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilZipFileAccess.class b/tests/test_data/std/jdk/internal/access/JavaUtilZipFileAccess.class
new file mode 100644
index 00000000..b645b19c
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaUtilZipFileAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilZipFileAccess.java b/tests/test_data/std/jdk/internal/access/JavaUtilZipFileAccess.java
new file mode 100644
index 00000000..3728a6c7
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaUtilZipFileAccess.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, 2021, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public interface JavaUtilZipFileAccess {
+ public boolean startsWithLocHeader(ZipFile zip);
+ public List getManifestAndSignatureRelatedFiles(JarFile zip);
+ public String getManifestName(JarFile zip, boolean onlyIfSignatureRelatedFiles);
+ public int getManifestNum(JarFile zip);
+ public int[] getMetaInfVersions(JarFile zip);
+ public Enumeration entries(ZipFile zip);
+ public Stream stream(ZipFile zip);
+ public Stream entryNameStream(ZipFile zip);
+ public void setExtraAttributes(ZipEntry ze, int extraAttrs);
+ public int getExtraAttributes(ZipEntry ze);
+}
+
diff --git a/tests/test_data/std/jdk/internal/access/JavaxCryptoSealedObjectAccess.class b/tests/test_data/std/jdk/internal/access/JavaxCryptoSealedObjectAccess.class
new file mode 100644
index 00000000..ae2865cf
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaxCryptoSealedObjectAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaxCryptoSealedObjectAccess.java b/tests/test_data/std/jdk/internal/access/JavaxCryptoSealedObjectAccess.java
new file mode 100644
index 00000000..0ab3c139
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaxCryptoSealedObjectAccess.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.access;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.SealedObject;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+public interface JavaxCryptoSealedObjectAccess {
+ ObjectInputStream getExtObjectInputStream(
+ SealedObject sealed, Cipher cipher)
+ throws BadPaddingException, IllegalBlockSizeException, IOException;
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaxCryptoSpecAccess.class b/tests/test_data/std/jdk/internal/access/JavaxCryptoSpecAccess.class
new file mode 100644
index 00000000..51853c3b
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaxCryptoSpecAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaxCryptoSpecAccess.java b/tests/test_data/std/jdk/internal/access/JavaxCryptoSpecAccess.java
new file mode 100644
index 00000000..f8904cae
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaxCryptoSpecAccess.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import javax.crypto.spec.SecretKeySpec;
+
+public interface JavaxCryptoSpecAccess {
+ void clearSecretKeySpec(SecretKeySpec keySpec);
+}
diff --git a/tests/test_data/std/jdk/internal/access/JavaxSecurityAccess.class b/tests/test_data/std/jdk/internal/access/JavaxSecurityAccess.class
new file mode 100644
index 00000000..387f09ee
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/JavaxSecurityAccess.class differ
diff --git a/tests/test_data/std/jdk/internal/access/JavaxSecurityAccess.java b/tests/test_data/std/jdk/internal/access/JavaxSecurityAccess.java
new file mode 100644
index 00000000..004b6db3
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/JavaxSecurityAccess.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2024, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import javax.security.auth.x500.X500Principal;
+import sun.security.x509.X500Name;
+
+public interface JavaxSecurityAccess {
+ X500Name asX500Name(X500Principal p);
+ X500Principal asX500Principal(X500Name n);
+}
diff --git a/tests/test_data/std/jdk/internal/access/SharedSecrets.class b/tests/test_data/std/jdk/internal/access/SharedSecrets.class
new file mode 100644
index 00000000..04123e79
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/SharedSecrets.class differ
diff --git a/tests/test_data/std/jdk/internal/access/SharedSecrets.java b/tests/test_data/std/jdk/internal/access/SharedSecrets.java
new file mode 100644
index 00000000..0dacbef9
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/SharedSecrets.java
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 2002, 2024, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.access;
+
+import javax.crypto.SealedObject;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.ObjectInputFilter;
+import java.lang.invoke.MethodHandles;
+import java.lang.module.ModuleDescriptor;
+import java.security.Security;
+import java.security.spec.EncodedKeySpec;
+import java.util.ResourceBundle;
+import java.util.concurrent.ForkJoinPool;
+import java.util.jar.JarFile;
+import java.io.Console;
+import java.io.FileDescriptor;
+import java.io.FilePermission;
+import java.io.ObjectInputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.RandomAccessFile;
+import java.security.ProtectionDomain;
+import java.security.Signature;
+import javax.security.auth.x500.X500Principal;
+
+/** A repository of "shared secrets", which are a mechanism for
+ calling implementation-private methods in another package without
+ using reflection. A package-private class implements a public
+ interface and provides the ability to call package-private methods
+ within that package; the object implementing that interface is
+ provided through a third package to which access is restricted.
+ This framework avoids the primary disadvantage of using reflection
+ for this purpose, namely the loss of compile-time checking. */
+
+public class SharedSecrets {
+ private static JavaAWTAccess javaAWTAccess;
+ private static JavaAWTFontAccess javaAWTFontAccess;
+ private static JavaBeansAccess javaBeansAccess;
+ private static JavaLangAccess javaLangAccess;
+ private static JavaLangInvokeAccess javaLangInvokeAccess;
+ private static JavaLangModuleAccess javaLangModuleAccess;
+ private static JavaLangRefAccess javaLangRefAccess;
+ private static JavaLangReflectAccess javaLangReflectAccess;
+ private static JavaIOAccess javaIOAccess;
+ private static JavaIOPrintStreamAccess javaIOPrintStreamAccess;
+ private static JavaIOPrintWriterAccess javaIOPrintWriterAccess;
+ private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
+ private static JavaIOFilePermissionAccess javaIOFilePermissionAccess;
+ private static JavaIORandomAccessFileAccess javaIORandomAccessFileAccess;
+ private static JavaObjectInputStreamReadString javaObjectInputStreamReadString;
+ private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
+ private static JavaObjectInputFilterAccess javaObjectInputFilterAccess;
+ private static JavaNetInetAddressAccess javaNetInetAddressAccess;
+ private static JavaNetHttpCookieAccess javaNetHttpCookieAccess;
+ private static JavaNetUriAccess javaNetUriAccess;
+ private static JavaNetURLAccess javaNetURLAccess;
+ private static JavaNioAccess javaNioAccess;
+ private static JavaUtilCollectionAccess javaUtilCollectionAccess;
+ private static JavaUtilConcurrentTLRAccess javaUtilConcurrentTLRAccess;
+ private static JavaUtilConcurrentFJPAccess javaUtilConcurrentFJPAccess;
+ private static JavaUtilJarAccess javaUtilJarAccess;
+ private static JavaUtilZipFileAccess javaUtilZipFileAccess;
+ private static JavaUtilResourceBundleAccess javaUtilResourceBundleAccess;
+ private static JavaSecurityAccess javaSecurityAccess;
+ private static JavaSecurityPropertiesAccess javaSecurityPropertiesAccess;
+ private static JavaSecuritySignatureAccess javaSecuritySignatureAccess;
+ private static JavaSecuritySpecAccess javaSecuritySpecAccess;
+ private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess;
+ private static JavaxCryptoSpecAccess javaxCryptoSpecAccess;
+ private static JavaxSecurityAccess javaxSecurityAccess;
+
+ public static void setJavaUtilCollectionAccess(JavaUtilCollectionAccess juca) {
+ javaUtilCollectionAccess = juca;
+ }
+
+ public static JavaUtilCollectionAccess getJavaUtilCollectionAccess() {
+ var access = javaUtilCollectionAccess;
+ if (access == null) {
+ try {
+ Class.forName("java.util.ImmutableCollections$Access", true, null);
+ access = javaUtilCollectionAccess;
+ } catch (ClassNotFoundException e) {}
+ }
+ return access;
+ }
+
+ public static void setJavaUtilConcurrentTLRAccess(JavaUtilConcurrentTLRAccess access) {
+ javaUtilConcurrentTLRAccess = access;
+ }
+
+ public static JavaUtilConcurrentTLRAccess getJavaUtilConcurrentTLRAccess() {
+ var access = javaUtilConcurrentTLRAccess;
+ if (access == null) {
+ try {
+ Class.forName("java.util.concurrent.ThreadLocalRandom$Access", true, null);
+ access = javaUtilConcurrentTLRAccess;
+ } catch (ClassNotFoundException e) {}
+ }
+ return access;
+ }
+
+ public static void setJavaUtilConcurrentFJPAccess(JavaUtilConcurrentFJPAccess access) {
+ javaUtilConcurrentFJPAccess = access;
+ }
+
+ public static JavaUtilConcurrentFJPAccess getJavaUtilConcurrentFJPAccess() {
+ var access = javaUtilConcurrentFJPAccess;
+ if (access == null) {
+ ensureClassInitialized(ForkJoinPool.class);
+ access = javaUtilConcurrentFJPAccess;
+ }
+ return access;
+ }
+
+ public static JavaUtilJarAccess javaUtilJarAccess() {
+ var access = javaUtilJarAccess;
+ if (access == null) {
+ // Ensure JarFile is initialized; we know that this class
+ // provides the shared secret
+ ensureClassInitialized(JarFile.class);
+ access = javaUtilJarAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaUtilJarAccess(JavaUtilJarAccess access) {
+ javaUtilJarAccess = access;
+ }
+
+ public static void setJavaLangAccess(JavaLangAccess jla) {
+ javaLangAccess = jla;
+ }
+
+ public static JavaLangAccess getJavaLangAccess() {
+ return javaLangAccess;
+ }
+
+ public static void setJavaLangInvokeAccess(JavaLangInvokeAccess jlia) {
+ javaLangInvokeAccess = jlia;
+ }
+
+ public static JavaLangInvokeAccess getJavaLangInvokeAccess() {
+ var access = javaLangInvokeAccess;
+ if (access == null) {
+ try {
+ Class.forName("java.lang.invoke.MethodHandleImpl", true, null);
+ access = javaLangInvokeAccess;
+ } catch (ClassNotFoundException e) {}
+ }
+ return access;
+ }
+
+ public static void setJavaLangModuleAccess(JavaLangModuleAccess jlrma) {
+ javaLangModuleAccess = jlrma;
+ }
+
+ public static JavaLangModuleAccess getJavaLangModuleAccess() {
+ var access = javaLangModuleAccess;
+ if (access == null) {
+ ensureClassInitialized(ModuleDescriptor.class);
+ access = javaLangModuleAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaLangRefAccess(JavaLangRefAccess jlra) {
+ javaLangRefAccess = jlra;
+ }
+
+ public static JavaLangRefAccess getJavaLangRefAccess() {
+ return javaLangRefAccess;
+ }
+
+ public static void setJavaLangReflectAccess(JavaLangReflectAccess jlra) {
+ javaLangReflectAccess = jlra;
+ }
+
+ public static JavaLangReflectAccess getJavaLangReflectAccess() {
+ return javaLangReflectAccess;
+ }
+
+ public static void setJavaNetUriAccess(JavaNetUriAccess jnua) {
+ javaNetUriAccess = jnua;
+ }
+
+ public static JavaNetUriAccess getJavaNetUriAccess() {
+ var access = javaNetUriAccess;
+ if (access == null) {
+ ensureClassInitialized(java.net.URI.class);
+ access = javaNetUriAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaNetURLAccess(JavaNetURLAccess jnua) {
+ javaNetURLAccess = jnua;
+ }
+
+ public static JavaNetURLAccess getJavaNetURLAccess() {
+ var access = javaNetURLAccess;
+ if (access == null) {
+ ensureClassInitialized(java.net.URL.class);
+ access = javaNetURLAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaNetInetAddressAccess(JavaNetInetAddressAccess jna) {
+ javaNetInetAddressAccess = jna;
+ }
+
+ public static JavaNetInetAddressAccess getJavaNetInetAddressAccess() {
+ var access = javaNetInetAddressAccess;
+ if (access == null) {
+ ensureClassInitialized(java.net.InetAddress.class);
+ access = javaNetInetAddressAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaNetHttpCookieAccess(JavaNetHttpCookieAccess a) {
+ javaNetHttpCookieAccess = a;
+ }
+
+ public static JavaNetHttpCookieAccess getJavaNetHttpCookieAccess() {
+ var access = javaNetHttpCookieAccess;
+ if (access == null) {
+ ensureClassInitialized(java.net.HttpCookie.class);
+ access = javaNetHttpCookieAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaNioAccess(JavaNioAccess jna) {
+ javaNioAccess = jna;
+ }
+
+ public static JavaNioAccess getJavaNioAccess() {
+ var access = javaNioAccess;
+ if (access == null) {
+ // Ensure java.nio.Buffer is initialized, which provides the
+ // shared secret.
+ ensureClassInitialized(java.nio.Buffer.class);
+ access = javaNioAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaIOAccess(JavaIOAccess jia) {
+ javaIOAccess = jia;
+ }
+
+ public static JavaIOAccess getJavaIOAccess() {
+ var access = javaIOAccess;
+ if (access == null) {
+ ensureClassInitialized(Console.class);
+ access = javaIOAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaIOCPrintWriterAccess(JavaIOPrintWriterAccess a) {
+ javaIOPrintWriterAccess = a;
+ }
+
+ public static JavaIOPrintWriterAccess getJavaIOPrintWriterAccess() {
+ var access = javaIOPrintWriterAccess;
+ if (access == null) {
+ ensureClassInitialized(PrintWriter.class);
+ access = javaIOPrintWriterAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaIOCPrintStreamAccess(JavaIOPrintStreamAccess a) {
+ javaIOPrintStreamAccess = a;
+ }
+
+ public static JavaIOPrintStreamAccess getJavaIOPrintStreamAccess() {
+ var access = javaIOPrintStreamAccess;
+ if (access == null) {
+ ensureClassInitialized(PrintStream.class);
+ access = javaIOPrintStreamAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaIOFileDescriptorAccess(JavaIOFileDescriptorAccess jiofda) {
+ javaIOFileDescriptorAccess = jiofda;
+ }
+
+ public static JavaIOFilePermissionAccess getJavaIOFilePermissionAccess() {
+ var access = javaIOFilePermissionAccess;
+ if (access == null) {
+ ensureClassInitialized(FilePermission.class);
+ access = javaIOFilePermissionAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaIOFilePermissionAccess(JavaIOFilePermissionAccess jiofpa) {
+ javaIOFilePermissionAccess = jiofpa;
+ }
+
+ public static JavaIOFileDescriptorAccess getJavaIOFileDescriptorAccess() {
+ var access = javaIOFileDescriptorAccess;
+ if (access == null) {
+ ensureClassInitialized(FileDescriptor.class);
+ access = javaIOFileDescriptorAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaSecurityAccess(JavaSecurityAccess jsa) {
+ javaSecurityAccess = jsa;
+ }
+
+ public static JavaSecurityAccess getJavaSecurityAccess() {
+ var access = javaSecurityAccess;
+ if (access == null) {
+ ensureClassInitialized(ProtectionDomain.class);
+ access = javaSecurityAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaSecurityPropertiesAccess(JavaSecurityPropertiesAccess jspa) {
+ javaSecurityPropertiesAccess = jspa;
+ }
+
+ public static JavaSecurityPropertiesAccess getJavaSecurityPropertiesAccess() {
+ var access = javaSecurityPropertiesAccess;
+ if (access == null) {
+ ensureClassInitialized(Security.class);
+ access = javaSecurityPropertiesAccess;
+ }
+ return access;
+ }
+
+ public static JavaUtilZipFileAccess getJavaUtilZipFileAccess() {
+ var access = javaUtilZipFileAccess;
+ if (access == null) {
+ ensureClassInitialized(java.util.zip.ZipFile.class);
+ access = javaUtilZipFileAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaUtilZipFileAccess(JavaUtilZipFileAccess access) {
+ javaUtilZipFileAccess = access;
+ }
+
+ public static void setJavaAWTAccess(JavaAWTAccess jaa) {
+ javaAWTAccess = jaa;
+ }
+
+ public static JavaAWTAccess getJavaAWTAccess() {
+ // this may return null in which case calling code needs to
+ // provision for.
+ return javaAWTAccess;
+ }
+
+ public static void setJavaAWTFontAccess(JavaAWTFontAccess jafa) {
+ javaAWTFontAccess = jafa;
+ }
+
+ public static JavaAWTFontAccess getJavaAWTFontAccess() {
+ // this may return null in which case calling code needs to
+ // provision for.
+ return javaAWTFontAccess;
+ }
+
+ public static JavaBeansAccess getJavaBeansAccess() {
+ return javaBeansAccess;
+ }
+
+ public static void setJavaBeansAccess(JavaBeansAccess access) {
+ javaBeansAccess = access;
+ }
+
+ public static JavaUtilResourceBundleAccess getJavaUtilResourceBundleAccess() {
+ var access = javaUtilResourceBundleAccess;
+ if (access == null) {
+ ensureClassInitialized(ResourceBundle.class);
+ access = javaUtilResourceBundleAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaUtilResourceBundleAccess(JavaUtilResourceBundleAccess access) {
+ javaUtilResourceBundleAccess = access;
+ }
+
+ public static JavaObjectInputStreamReadString getJavaObjectInputStreamReadString() {
+ var access = javaObjectInputStreamReadString;
+ if (access == null) {
+ ensureClassInitialized(ObjectInputStream.class);
+ access = javaObjectInputStreamReadString;
+ }
+ return access;
+ }
+
+ public static void setJavaObjectInputStreamReadString(JavaObjectInputStreamReadString access) {
+ javaObjectInputStreamReadString = access;
+ }
+
+ public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() {
+ var access = javaObjectInputStreamAccess;
+ if (access == null) {
+ ensureClassInitialized(ObjectInputStream.class);
+ access = javaObjectInputStreamAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) {
+ javaObjectInputStreamAccess = access;
+ }
+
+ public static JavaObjectInputFilterAccess getJavaObjectInputFilterAccess() {
+ var access = javaObjectInputFilterAccess;
+ if (access == null) {
+ ensureClassInitialized(ObjectInputFilter.Config.class);
+ access = javaObjectInputFilterAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaObjectInputFilterAccess(JavaObjectInputFilterAccess access) {
+ javaObjectInputFilterAccess = access;
+ }
+
+ public static void setJavaIORandomAccessFileAccess(JavaIORandomAccessFileAccess jirafa) {
+ javaIORandomAccessFileAccess = jirafa;
+ }
+
+ public static JavaIORandomAccessFileAccess getJavaIORandomAccessFileAccess() {
+ var access = javaIORandomAccessFileAccess;
+ if (access == null) {
+ ensureClassInitialized(RandomAccessFile.class);
+ access = javaIORandomAccessFileAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaSecuritySignatureAccess(JavaSecuritySignatureAccess jssa) {
+ javaSecuritySignatureAccess = jssa;
+ }
+
+ public static JavaSecuritySignatureAccess getJavaSecuritySignatureAccess() {
+ var access = javaSecuritySignatureAccess;
+ if (access == null) {
+ ensureClassInitialized(Signature.class);
+ access = javaSecuritySignatureAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaSecuritySpecAccess(JavaSecuritySpecAccess jssa) {
+ javaSecuritySpecAccess = jssa;
+ }
+
+ public static JavaSecuritySpecAccess getJavaSecuritySpecAccess() {
+ var access = javaSecuritySpecAccess;
+ if (access == null) {
+ ensureClassInitialized(EncodedKeySpec.class);
+ access = javaSecuritySpecAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaxCryptoSpecAccess(JavaxCryptoSpecAccess jcsa) {
+ javaxCryptoSpecAccess = jcsa;
+ }
+
+ public static JavaxCryptoSpecAccess getJavaxCryptoSpecAccess() {
+ var access = javaxCryptoSpecAccess;
+ if (access == null) {
+ ensureClassInitialized(SecretKeySpec.class);
+ access = javaxCryptoSpecAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaxCryptoSealedObjectAccess(JavaxCryptoSealedObjectAccess jcsoa) {
+ javaxCryptoSealedObjectAccess = jcsoa;
+ }
+
+ public static JavaxCryptoSealedObjectAccess getJavaxCryptoSealedObjectAccess() {
+ var access = javaxCryptoSealedObjectAccess;
+ if (access == null) {
+ ensureClassInitialized(SealedObject.class);
+ access = javaxCryptoSealedObjectAccess;
+ }
+ return access;
+ }
+
+ public static void setJavaxSecurityAccess(JavaxSecurityAccess jsa) {
+ javaxSecurityAccess = jsa;
+ }
+
+ public static JavaxSecurityAccess getJavaxSecurityAccess() {
+ var access = javaxSecurityAccess;
+ if (access == null) {
+ ensureClassInitialized(X500Principal.class);
+ access = javaxSecurityAccess;
+ }
+ return access;
+ }
+
+ private static void ensureClassInitialized(Class> c) {
+ try {
+ MethodHandles.lookup().ensureInitialized(c);
+ } catch (IllegalAccessException e) {}
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.class b/tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.class
new file mode 100644
index 00000000..1235d5a9
Binary files /dev/null and b/tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.class differ
diff --git a/tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.java b/tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.java
new file mode 100644
index 00000000..23781301
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package jdk.internal.access.foreign;
+
+import java.io.FileDescriptor;
+
+/**
+ * This proxy interface is required to allow instances of the {@code FileChannelImpl.Unmapper} interface (which is a non-public class
+ * inside the {@code sun.nio.ch} package) to be accessed from the mapped memory segment factory.
+ */
+public interface UnmapperProxy {
+ long address();
+ FileDescriptor fileDescriptor();
+ boolean isSync();
+ void unmap();
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$AnnotationDefaultMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$AnnotationDefaultMapper.class
new file mode 100644
index 00000000..cfd4b86d
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$AnnotationDefaultMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$BootstrapMethodsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$BootstrapMethodsMapper.class
new file mode 100644
index 00000000..760cefc7
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$BootstrapMethodsMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CharacterRangeTableMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CharacterRangeTableMapper.class
new file mode 100644
index 00000000..8d4f4977
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CharacterRangeTableMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CodeMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CodeMapper.class
new file mode 100644
index 00000000..670be80d
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CodeMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CompilationIDMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CompilationIDMapper.class
new file mode 100644
index 00000000..b47bf758
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CompilationIDMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ConstantValueMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ConstantValueMapper.class
new file mode 100644
index 00000000..a4460d93
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ConstantValueMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$DeprecatedMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$DeprecatedMapper.class
new file mode 100644
index 00000000..98d08255
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$DeprecatedMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$EnclosingMethodMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$EnclosingMethodMapper.class
new file mode 100644
index 00000000..bbbd1b8c
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$EnclosingMethodMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ExceptionsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ExceptionsMapper.class
new file mode 100644
index 00000000..2e2337cd
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ExceptionsMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$InnerClassesMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$InnerClassesMapper.class
new file mode 100644
index 00000000..3b4ad38f
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$InnerClassesMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LineNumberTableMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LineNumberTableMapper.class
new file mode 100644
index 00000000..1b4392a5
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LineNumberTableMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTableMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTableMapper.class
new file mode 100644
index 00000000..a848e331
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTableMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTypeTableMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTypeTableMapper.class
new file mode 100644
index 00000000..451fe0c8
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTypeTableMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$MethodParametersMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$MethodParametersMapper.class
new file mode 100644
index 00000000..93352106
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$MethodParametersMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleHashesMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleHashesMapper.class
new file mode 100644
index 00000000..9aae69a0
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleHashesMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleMainClassMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleMainClassMapper.class
new file mode 100644
index 00000000..77ef437a
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleMainClassMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleMapper.class
new file mode 100644
index 00000000..a1592ae3
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModulePackagesMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModulePackagesMapper.class
new file mode 100644
index 00000000..7e1b40ed
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModulePackagesMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleResolutionMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleResolutionMapper.class
new file mode 100644
index 00000000..2df8afa9
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleResolutionMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleTargetMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleTargetMapper.class
new file mode 100644
index 00000000..1a904ff4
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleTargetMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$NestHostMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$NestHostMapper.class
new file mode 100644
index 00000000..63649e5e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$NestHostMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$NestMembersMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$NestMembersMapper.class
new file mode 100644
index 00000000..207421e1
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$NestMembersMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$PermittedSubclassesMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$PermittedSubclassesMapper.class
new file mode 100644
index 00000000..50e4d92a
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$PermittedSubclassesMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RecordMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RecordMapper.class
new file mode 100644
index 00000000..b1ce3396
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RecordMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleAnnotationsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleAnnotationsMapper.class
new file mode 100644
index 00000000..e17ff7c2
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleAnnotationsMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleParameterAnnotationsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleParameterAnnotationsMapper.class
new file mode 100644
index 00000000..80285e78
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleParameterAnnotationsMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleTypeAnnotationsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleTypeAnnotationsMapper.class
new file mode 100644
index 00000000..ca72f516
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleTypeAnnotationsMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleAnnotationsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleAnnotationsMapper.class
new file mode 100644
index 00000000..43e8fb05
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleAnnotationsMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleParameterAnnotationsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleParameterAnnotationsMapper.class
new file mode 100644
index 00000000..aaaa8d5d
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleParameterAnnotationsMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleTypeAnnotationsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleTypeAnnotationsMapper.class
new file mode 100644
index 00000000..237bfd59
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleTypeAnnotationsMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SignatureMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SignatureMapper.class
new file mode 100644
index 00000000..9a1dc0bf
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SignatureMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceDebugExtensionMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceDebugExtensionMapper.class
new file mode 100644
index 00000000..593aaeb3
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceDebugExtensionMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceFileMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceFileMapper.class
new file mode 100644
index 00000000..f167cfa3
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceFileMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceIDMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceIDMapper.class
new file mode 100644
index 00000000..32c84eb1
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceIDMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$StackMapTableMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$StackMapTableMapper.class
new file mode 100644
index 00000000..d517bc71
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$StackMapTableMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SyntheticMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SyntheticMapper.class
new file mode 100644
index 00000000..7b1fda37
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SyntheticMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper.class
new file mode 100644
index 00000000..54fb3310
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper.java
new file mode 100644
index 00000000..9bb3f275
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper.java
@@ -0,0 +1,824 @@
+/*
+ * Copyright (c) 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.lang.classfile.Annotation;
+import java.lang.classfile.Attribute;
+import java.lang.classfile.AttributeMapper;
+import java.lang.classfile.AttributedElement;
+import java.lang.classfile.BufWriter;
+import java.lang.classfile.ClassReader;
+import java.lang.classfile.attribute.*;
+import java.util.List;
+
+import static java.lang.classfile.Attributes.*;
+
+public sealed abstract class AbstractAttributeMapper>
+ implements AttributeMapper {
+
+ private final String name;
+ private final AttributeMapper.AttributeStability stability;
+ private final boolean allowMultiple;
+
+ protected abstract void writeBody(BufWriter buf, T attr);
+
+ public AbstractAttributeMapper(String name, AttributeMapper.AttributeStability stability) {
+ this(name, stability, false);
+ }
+
+ public AbstractAttributeMapper(String name,
+ AttributeMapper.AttributeStability stability,
+ boolean allowMultiple) {
+ this.name = name;
+ this.stability = stability;
+ this.allowMultiple = allowMultiple;
+ }
+
+ @Override
+ public final String name() {
+ return name;
+ }
+
+ @Override
+ public final void writeAttribute(BufWriter buf, T attr) {
+ buf.writeIndex(buf.constantPool().utf8Entry(name));
+ buf.writeInt(0);
+ int start = buf.size();
+ writeBody(buf, attr);
+ int written = buf.size() - start;
+ buf.patchInt(start - 4, 4, written);
+ }
+
+ @Override
+ public AttributeMapper.AttributeStability stability() {
+ return stability;
+ }
+
+ @Override
+ public boolean allowMultiple() {
+ return allowMultiple;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("AttributeMapper[name=%s, allowMultiple=%b, stability=%s]",
+ name, allowMultiple, stability());
+ }
+
+ public static final class AnnotationDefaultMapper extends AbstractAttributeMapper {
+ public static final AnnotationDefaultMapper INSTANCE = new AnnotationDefaultMapper();
+
+ private AnnotationDefaultMapper() {
+ super(NAME_ANNOTATION_DEFAULT, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public AnnotationDefaultAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundAnnotationDefaultAttr(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, AnnotationDefaultAttribute attr) {
+ attr.defaultValue().writeTo(buf);
+ }
+ }
+
+ public static final class BootstrapMethodsMapper extends AbstractAttributeMapper {
+ public static final BootstrapMethodsMapper INSTANCE = new BootstrapMethodsMapper();
+
+ private BootstrapMethodsMapper() {
+ super(NAME_BOOTSTRAP_METHODS, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public BootstrapMethodsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundBootstrapMethodsAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, BootstrapMethodsAttribute attr) {
+ buf.writeList(attr.bootstrapMethods());
+ }
+ }
+
+ public static final class CharacterRangeTableMapper extends AbstractAttributeMapper {
+ public static final CharacterRangeTableMapper INSTANCE = new CharacterRangeTableMapper();
+
+ private CharacterRangeTableMapper() {
+ super(NAME_CHARACTER_RANGE_TABLE, AttributeStability.LABELS, true);
+ }
+
+ @Override
+ public CharacterRangeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundCharacterRangeTableAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, CharacterRangeTableAttribute attr) {
+ List ranges = attr.characterRangeTable();
+ buf.writeU2(ranges.size());
+ for (CharacterRangeInfo info : ranges) {
+ buf.writeU2(info.startPc());
+ buf.writeU2(info.endPc());
+ buf.writeInt(info.characterRangeStart());
+ buf.writeInt(info.characterRangeEnd());
+ buf.writeU2(info.flags());
+ }
+ }
+ }
+
+ public static final class CodeMapper extends AbstractAttributeMapper {
+ public static final CodeMapper INSTANCE = new CodeMapper();
+
+ private CodeMapper() {
+ super(NAME_CODE, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public CodeAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new CodeImpl(e, cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, CodeAttribute attr) {
+ throw new UnsupportedOperationException("Code attribute does not support direct write");
+ }
+ }
+
+ public static final class CompilationIDMapper extends AbstractAttributeMapper {
+ public static final CompilationIDMapper INSTANCE = new CompilationIDMapper();
+
+ private CompilationIDMapper() {
+ super(NAME_COMPILATION_ID, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public CompilationIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundCompilationIDAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, CompilationIDAttribute attr) {
+ buf.writeIndex(attr.compilationId());
+ }
+ }
+
+ public static final class ConstantValueMapper extends AbstractAttributeMapper {
+ public static final ConstantValueMapper INSTANCE = new ConstantValueMapper();
+
+ private ConstantValueMapper() {
+ super(NAME_CONSTANT_VALUE, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public ConstantValueAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundConstantValueAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, ConstantValueAttribute attr) {
+ buf.writeIndex(attr.constant());
+ }
+ }
+
+ public static final class DeprecatedMapper extends AbstractAttributeMapper {
+ public static final DeprecatedMapper INSTANCE = new DeprecatedMapper();
+
+ private DeprecatedMapper() {
+ super(NAME_DEPRECATED, AttributeStability.STATELESS, true);
+ }
+
+ @Override
+ public DeprecatedAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundDeprecatedAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, DeprecatedAttribute attr) {
+ // empty
+ }
+ }
+
+ public static final class EnclosingMethodMapper extends AbstractAttributeMapper {
+ public static final EnclosingMethodMapper INSTANCE = new EnclosingMethodMapper();
+
+ private EnclosingMethodMapper() {
+ super(NAME_ENCLOSING_METHOD, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public EnclosingMethodAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundEnclosingMethodAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, EnclosingMethodAttribute attr) {
+ buf.writeIndex(attr.enclosingClass());
+ buf.writeIndexOrZero(attr.enclosingMethod().orElse(null));
+ }
+ }
+
+ public static final class ExceptionsMapper extends AbstractAttributeMapper {
+ public static final ExceptionsMapper INSTANCE = new ExceptionsMapper();
+
+ private ExceptionsMapper() {
+ super(NAME_EXCEPTIONS, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public ExceptionsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundExceptionsAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, ExceptionsAttribute attr) {
+ buf.writeListIndices(attr.exceptions());
+ }
+ }
+
+ public static final class InnerClassesMapper extends AbstractAttributeMapper {
+ public static final InnerClassesMapper INSTANCE = new InnerClassesMapper();
+
+ private InnerClassesMapper() {
+ super(NAME_INNER_CLASSES, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public InnerClassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundInnerClassesAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, InnerClassesAttribute attr) {
+ List classes = attr.classes();
+ buf.writeU2(classes.size());
+ for (InnerClassInfo ic : classes) {
+ buf.writeIndex(ic.innerClass());
+ buf.writeIndexOrZero(ic.outerClass().orElse(null));
+ buf.writeIndexOrZero(ic.innerName().orElse(null));
+ buf.writeU2(ic.flagsMask());
+ }
+ }
+ }
+
+ public static final class LineNumberTableMapper extends AbstractAttributeMapper {
+ public static final LineNumberTableMapper INSTANCE = new LineNumberTableMapper();
+
+ private LineNumberTableMapper() {
+ super(NAME_LINE_NUMBER_TABLE, AttributeStability.LABELS, true);
+ }
+
+ @Override
+ public LineNumberTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundLineNumberTableAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, LineNumberTableAttribute attr) {
+ List lines = attr.lineNumbers();
+ buf.writeU2(lines.size());
+ for (LineNumberInfo line : lines) {
+ buf.writeU2(line.startPc());
+ buf.writeU2(line.lineNumber());
+ }
+ }
+ }
+
+ public static final class LocalVariableTableMapper extends AbstractAttributeMapper {
+ public static final LocalVariableTableMapper INSTANCE = new LocalVariableTableMapper();
+
+ private LocalVariableTableMapper() {
+ super(NAME_LOCAL_VARIABLE_TABLE, AttributeStability.LABELS, true);
+ }
+
+ @Override
+ public LocalVariableTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundLocalVariableTableAttribute(e, cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, LocalVariableTableAttribute attr) {
+ List infos = attr.localVariables();
+ buf.writeU2(infos.size());
+ for (LocalVariableInfo info : infos) {
+ buf.writeU2(info.startPc());
+ buf.writeU2(info.length());
+ buf.writeIndex(info.name());
+ buf.writeIndex(info.type());
+ buf.writeU2(info.slot());
+ }
+ }
+ }
+
+ public static final class LocalVariableTypeTableMapper extends AbstractAttributeMapper {
+ public static final LocalVariableTypeTableMapper INSTANCE = new LocalVariableTypeTableMapper();
+
+ private LocalVariableTypeTableMapper() {
+ super(NAME_LOCAL_VARIABLE_TYPE_TABLE, AttributeStability.LABELS, true);
+ }
+
+ @Override
+ public LocalVariableTypeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundLocalVariableTypeTableAttribute(e, cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, LocalVariableTypeTableAttribute attr) {
+ List infos = attr.localVariableTypes();
+ buf.writeU2(infos.size());
+ for (LocalVariableTypeInfo info : infos) {
+ buf.writeU2(info.startPc());
+ buf.writeU2(info.length());
+ buf.writeIndex(info.name());
+ buf.writeIndex(info.signature());
+ buf.writeU2(info.slot());
+ }
+ }
+ }
+
+ public static final class MethodParametersMapper extends AbstractAttributeMapper {
+ public static final MethodParametersMapper INSTANCE = new MethodParametersMapper();
+
+ private MethodParametersMapper() {
+ super(NAME_METHOD_PARAMETERS, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public MethodParametersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundMethodParametersAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, MethodParametersAttribute attr) {
+ List parameters = attr.parameters();
+ buf.writeU1(parameters.size());
+ for (MethodParameterInfo info : parameters) {
+ buf.writeIndexOrZero(info.name().orElse(null));
+ buf.writeU2(info.flagsMask());
+ }
+ }
+ }
+
+ public static final class ModuleMapper extends AbstractAttributeMapper {
+ public static final ModuleMapper INSTANCE = new ModuleMapper();
+
+ private ModuleMapper() {
+ super(NAME_MODULE, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public ModuleAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundModuleAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, ModuleAttribute attr) {
+ buf.writeIndex(attr.moduleName());
+ buf.writeU2(attr.moduleFlagsMask());
+ buf.writeIndexOrZero(attr.moduleVersion().orElse(null));
+ buf.writeU2(attr.requires().size());
+ for (ModuleRequireInfo require : attr.requires()) {
+ buf.writeIndex(require.requires());
+ buf.writeU2(require.requiresFlagsMask());
+ buf.writeIndexOrZero(require.requiresVersion().orElse(null));
+ }
+ buf.writeU2(attr.exports().size());
+ for (ModuleExportInfo export : attr.exports()) {
+ buf.writeIndex(export.exportedPackage());
+ buf.writeU2(export.exportsFlagsMask());
+ buf.writeListIndices(export.exportsTo());
+ }
+ buf.writeU2(attr.opens().size());
+ for (ModuleOpenInfo open : attr.opens()) {
+ buf.writeIndex(open.openedPackage());
+ buf.writeU2(open.opensFlagsMask());
+ buf.writeListIndices(open.opensTo());
+ }
+ buf.writeListIndices(attr.uses());
+ buf.writeU2(attr.provides().size());
+ for (ModuleProvideInfo provide : attr.provides()) {
+ buf.writeIndex(provide.provides());
+ buf.writeListIndices(provide.providesWith());
+ }
+ }
+ }
+
+ public static final class ModuleHashesMapper extends AbstractAttributeMapper {
+ public static final ModuleHashesMapper INSTANCE = new ModuleHashesMapper();
+
+ private ModuleHashesMapper() {
+ super(NAME_MODULE_HASHES, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public ModuleHashesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundModuleHashesAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, ModuleHashesAttribute attr) {
+ buf.writeIndex(attr.algorithm());
+ List hashes = attr.hashes();
+ buf.writeU2(hashes.size());
+ for (ModuleHashInfo hash : hashes) {
+ buf.writeIndex(hash.moduleName());
+ buf.writeU2(hash.hash().length);
+ buf.writeBytes(hash.hash());
+ }
+ }
+ }
+
+ public static final class ModuleMainClassMapper extends AbstractAttributeMapper {
+ public static final ModuleMainClassMapper INSTANCE = new ModuleMainClassMapper();
+
+ private ModuleMainClassMapper() {
+ super(NAME_MODULE_MAIN_CLASS, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public ModuleMainClassAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundModuleMainClassAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, ModuleMainClassAttribute attr) {
+ buf.writeIndex(attr.mainClass());
+ }
+ }
+
+ public static final class ModulePackagesMapper extends AbstractAttributeMapper {
+ public static final ModulePackagesMapper INSTANCE = new ModulePackagesMapper();
+
+ private ModulePackagesMapper() {
+ super(NAME_MODULE_PACKAGES, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public ModulePackagesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundModulePackagesAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, ModulePackagesAttribute attr) {
+ buf.writeListIndices(attr.packages());
+ }
+ }
+
+ public static final class ModuleResolutionMapper extends AbstractAttributeMapper {
+ public static final ModuleResolutionMapper INSTANCE = new ModuleResolutionMapper();
+
+ private ModuleResolutionMapper() {
+ super(NAME_MODULE_RESOLUTION, AttributeStability.STATELESS);
+ }
+
+ @Override
+ public ModuleResolutionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundModuleResolutionAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, ModuleResolutionAttribute attr) {
+ buf.writeU2(attr.resolutionFlags());
+ }
+ }
+
+ public static final class ModuleTargetMapper extends AbstractAttributeMapper {
+ public static final ModuleTargetMapper INSTANCE = new ModuleTargetMapper();
+
+ private ModuleTargetMapper() {
+ super(NAME_MODULE_TARGET, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public ModuleTargetAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundModuleTargetAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, ModuleTargetAttribute attr) {
+ buf.writeIndex(attr.targetPlatform());
+ }
+ }
+
+ public static final class NestHostMapper extends AbstractAttributeMapper {
+ public static final NestHostMapper INSTANCE = new NestHostMapper();
+
+ private NestHostMapper() {
+ super(NAME_NEST_HOST, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public NestHostAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundNestHostAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, NestHostAttribute attr) {
+ buf.writeIndex(attr.nestHost());
+ }
+ }
+
+ public static final class NestMembersMapper extends AbstractAttributeMapper {
+ public static final NestMembersMapper INSTANCE = new NestMembersMapper();
+
+ private NestMembersMapper() {
+ super(NAME_NEST_MEMBERS, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public NestMembersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundNestMembersAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, NestMembersAttribute attr) {
+ buf.writeListIndices(attr.nestMembers());
+ }
+ }
+
+ public static final class PermittedSubclassesMapper extends AbstractAttributeMapper {
+ public static final PermittedSubclassesMapper INSTANCE = new PermittedSubclassesMapper();
+
+ private PermittedSubclassesMapper() {
+ super(NAME_PERMITTED_SUBCLASSES, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public PermittedSubclassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundPermittedSubclassesAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, PermittedSubclassesAttribute attr) {
+ buf.writeListIndices(attr.permittedSubclasses());
+ }
+ }
+
+ public static final class RecordMapper extends AbstractAttributeMapper {
+ public static final RecordMapper INSTANCE = new RecordMapper();
+
+ private RecordMapper() {
+ super(NAME_RECORD, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public RecordAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundRecordAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, RecordAttribute attr) {
+ List components = attr.components();
+ buf.writeU2(components.size());
+ for (RecordComponentInfo info : components) {
+ buf.writeIndex(info.name());
+ buf.writeIndex(info.descriptor());
+ buf.writeList(info.attributes());
+ }
+ }
+ }
+
+ public static final class RuntimeInvisibleAnnotationsMapper extends AbstractAttributeMapper {
+ public static final RuntimeInvisibleAnnotationsMapper INSTANCE = new RuntimeInvisibleAnnotationsMapper();
+
+ private RuntimeInvisibleAnnotationsMapper() {
+ super(NAME_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public RuntimeInvisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) {
+ return new BoundAttribute.BoundRuntimeInvisibleAnnotationsAttribute(cf, pos);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, RuntimeInvisibleAnnotationsAttribute attr) {
+ buf.writeList(attr.annotations());
+ }
+ }
+
+ public static final class RuntimeInvisibleParameterAnnotationsMapper extends AbstractAttributeMapper {
+ public static final RuntimeInvisibleParameterAnnotationsMapper INSTANCE = new RuntimeInvisibleParameterAnnotationsMapper();
+
+ private RuntimeInvisibleParameterAnnotationsMapper() {
+ super(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public RuntimeInvisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundRuntimeInvisibleParameterAnnotationsAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, RuntimeInvisibleParameterAnnotationsAttribute attr) {
+ List> lists = attr.parameterAnnotations();
+ buf.writeU1(lists.size());
+ for (List list : lists)
+ buf.writeList(list);
+ }
+ }
+
+ public static final class RuntimeInvisibleTypeAnnotationsMapper extends AbstractAttributeMapper {
+ public static final RuntimeInvisibleTypeAnnotationsMapper INSTANCE = new RuntimeInvisibleTypeAnnotationsMapper();
+
+ private RuntimeInvisibleTypeAnnotationsMapper() {
+ super(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, AttributeStability.UNSTABLE);
+ }
+
+ @Override
+ public RuntimeInvisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundRuntimeInvisibleTypeAnnotationsAttribute(e, cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, RuntimeInvisibleTypeAnnotationsAttribute attr) {
+ buf.writeList(attr.annotations());
+ }
+ }
+
+ public static final class RuntimeVisibleAnnotationsMapper extends AbstractAttributeMapper {
+ public static final RuntimeVisibleAnnotationsMapper INSTANCE = new RuntimeVisibleAnnotationsMapper();
+
+ private RuntimeVisibleAnnotationsMapper() {
+ super(NAME_RUNTIME_VISIBLE_ANNOTATIONS, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public RuntimeVisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) {
+ return new BoundAttribute.BoundRuntimeVisibleAnnotationsAttribute(cf, pos);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, RuntimeVisibleAnnotationsAttribute attr) {
+ buf.writeList(attr.annotations());
+ }
+ }
+
+ public static final class RuntimeVisibleParameterAnnotationsMapper extends AbstractAttributeMapper {
+ public static final RuntimeVisibleParameterAnnotationsMapper INSTANCE = new RuntimeVisibleParameterAnnotationsMapper();
+
+ private RuntimeVisibleParameterAnnotationsMapper() {
+ super(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public RuntimeVisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundRuntimeVisibleParameterAnnotationsAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, RuntimeVisibleParameterAnnotationsAttribute attr) {
+ List> lists = attr.parameterAnnotations();
+ buf.writeU1(lists.size());
+ for (List list : lists)
+ buf.writeList(list);
+ }
+ }
+
+ public static final class RuntimeVisibleTypeAnnotationsMapper extends AbstractAttributeMapper {
+ public static final RuntimeVisibleTypeAnnotationsMapper INSTANCE = new RuntimeVisibleTypeAnnotationsMapper();
+
+ private RuntimeVisibleTypeAnnotationsMapper() {
+ super(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS, AttributeStability.UNSTABLE);
+ }
+
+ @Override
+ public RuntimeVisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundRuntimeVisibleTypeAnnotationsAttribute(e, cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, RuntimeVisibleTypeAnnotationsAttribute attr) {
+ buf.writeList(attr.annotations());
+ }
+ }
+
+ public static final class SignatureMapper extends AbstractAttributeMapper {
+ public static final SignatureMapper INSTANCE = new SignatureMapper();
+
+ private SignatureMapper() {
+ super(NAME_SIGNATURE, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public SignatureAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundSignatureAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, SignatureAttribute attr) {
+ buf.writeIndex(attr.signature());
+ }
+ }
+
+ public static final class SourceDebugExtensionMapper extends AbstractAttributeMapper {
+ public static final SourceDebugExtensionMapper INSTANCE = new SourceDebugExtensionMapper();
+
+ private SourceDebugExtensionMapper() {
+ super(NAME_SOURCE_DEBUG_EXTENSION, AttributeStability.STATELESS);
+ }
+
+ @Override
+ public SourceDebugExtensionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundSourceDebugExtensionAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, SourceDebugExtensionAttribute attr) {
+ buf.writeBytes(attr.contents());
+ }
+ }
+
+ public static final class SourceFileMapper extends AbstractAttributeMapper {
+ public static final SourceFileMapper INSTANCE = new SourceFileMapper();
+
+ private SourceFileMapper() {
+ super(NAME_SOURCE_FILE, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public SourceFileAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundSourceFileAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, SourceFileAttribute attr) {
+ buf.writeIndex(attr.sourceFile());
+ }
+ }
+
+ public static final class SourceIDMapper extends AbstractAttributeMapper {
+ public static final SourceIDMapper INSTANCE = new SourceIDMapper();
+
+ private SourceIDMapper() {
+ super(NAME_SOURCE_ID, AttributeStability.CP_REFS);
+ }
+
+ @Override
+ public SourceIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundSourceIDAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, SourceIDAttribute attr) {
+ buf.writeIndex(attr.sourceId());
+ }
+ }
+
+ public static final class StackMapTableMapper extends AbstractAttributeMapper {
+ public static final StackMapTableMapper INSTANCE = new StackMapTableMapper();
+
+ private StackMapTableMapper() {
+ super(NAME_STACK_MAP_TABLE, AttributeStability.LABELS);
+ }
+
+ @Override
+ public StackMapTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundStackMapTableAttribute((CodeImpl)e, cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter b, StackMapTableAttribute attr) {
+ StackMapDecoder.writeFrames(b, attr.entries());
+ }
+ }
+
+ public static final class SyntheticMapper extends AbstractAttributeMapper {
+ public static final SyntheticMapper INSTANCE = new SyntheticMapper();
+
+ private SyntheticMapper() {
+ super(NAME_SYNTHETIC, AttributeStability.STATELESS, true);
+ }
+
+ @Override
+ public SyntheticAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
+ return new BoundAttribute.BoundSyntheticAttribute(cf, this, p);
+ }
+
+ @Override
+ protected void writeBody(BufWriter buf, SyntheticAttribute attr) {
+ // empty
+ }
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.class
new file mode 100644
index 00000000..869e5d6e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java
new file mode 100644
index 00000000..d3f49e31
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2022, 2024, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.lang.classfile.BufWriter;
+import java.lang.classfile.Label;
+import java.lang.classfile.constantpool.Utf8Entry;
+
+public class AbstractBoundLocalVariable
+ extends AbstractElement {
+ protected final CodeImpl code;
+ protected final int offset;
+ private Utf8Entry nameEntry;
+ private Utf8Entry secondaryEntry;
+
+ public AbstractBoundLocalVariable(CodeImpl code, int offset) {
+ this.code = code;
+ this.offset = offset;
+ }
+
+ protected int nameIndex() {
+ return code.classReader.readU2(offset + 4);
+ }
+
+ public Utf8Entry name() {
+ if (nameEntry == null)
+ nameEntry = code.constantPool().entryByIndex(nameIndex(), Utf8Entry.class);
+ return nameEntry;
+ }
+
+ protected int secondaryIndex() {
+ return code.classReader.readU2(offset + 6);
+ }
+
+ protected Utf8Entry secondaryEntry() {
+ if (secondaryEntry == null)
+ secondaryEntry = code.constantPool().entryByIndex(secondaryIndex(), Utf8Entry.class);
+ return secondaryEntry;
+ }
+
+ public Label startScope() {
+ return code.getLabel(startPc());
+ }
+
+ public Label endScope() {
+ return code.getLabel(startPc() + length());
+ }
+
+ public int startPc() {
+ return code.classReader.readU2(offset);
+ }
+
+ public int length() {
+ return code.classReader.readU2(offset+2);
+ }
+
+ public int slot() {
+ return code.classReader.readU2(offset + 8);
+ }
+
+ public boolean writeTo(BufWriter b) {
+ var lc = ((BufWriterImpl)b).labelContext();
+ int startBci = lc.labelToBci(startScope());
+ int endBci = lc.labelToBci(endScope());
+ if (startBci == -1 || endBci == -1) {
+ return false;
+ }
+ int length = endBci - startBci;
+ b.writeU2(startBci);
+ b.writeU2(length);
+ if (b.canWriteDirect(code.constantPool())) {
+ b.writeU2(nameIndex());
+ b.writeU2(secondaryIndex());
+ }
+ else {
+ b.writeIndex(name());
+ b.writeIndex(secondaryEntry());
+ }
+ b.writeU2(slot());
+ return true;
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractDirectBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractDirectBuilder.class
new file mode 100644
index 00000000..6be7f61b
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractDirectBuilder.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractDirectBuilder.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractDirectBuilder.java
new file mode 100644
index 00000000..13c2a5fb
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractDirectBuilder.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.util.Optional;
+
+import java.lang.classfile.Attribute;
+
+public class AbstractDirectBuilder {
+ protected final SplitConstantPool constantPool;
+ protected final ClassFileImpl context;
+ protected final AttributeHolder attributes = new AttributeHolder();
+ protected M original;
+
+ public AbstractDirectBuilder(SplitConstantPool constantPool, ClassFileImpl context) {
+ this.constantPool = constantPool;
+ this.context = context;
+ }
+
+ public SplitConstantPool constantPool() {
+ return constantPool;
+ }
+
+ public Optional original() {
+ return Optional.ofNullable(original);
+ }
+
+ public void setOriginal(M original) {
+ this.original = original;
+ }
+
+ public void writeAttribute(Attribute> a) {
+ if (Util.isAttributeAllowed(a, context.attributesProcessingOption())) {
+ attributes.withAttribute(a);
+ }
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.class
new file mode 100644
index 00000000..580bfe2f
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.java
new file mode 100644
index 00000000..37081ca5
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+public abstract class AbstractElement {
+ public AbstractElement() { }
+
+ public void writeTo(DirectCodeBuilder builder) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void writeTo(DirectClassBuilder builder) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void writeTo(DirectMethodBuilder builder) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void writeTo(DirectFieldBuilder builder) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundArgumentConstantInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundArgumentConstantInstruction.class
new file mode 100644
index 00000000..f8a3cbf5
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundArgumentConstantInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundBranchInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundBranchInstruction.class
new file mode 100644
index 00000000..7c36153e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundBranchInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundFieldInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundFieldInstruction.class
new file mode 100644
index 00000000..901ab76f
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundFieldInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundIncrementInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundIncrementInstruction.class
new file mode 100644
index 00000000..037a3a46
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundIncrementInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInstruction.class
new file mode 100644
index 00000000..dba846f8
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeDynamicInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeDynamicInstruction.class
new file mode 100644
index 00000000..0e4b2139
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeDynamicInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInstruction.class
new file mode 100644
index 00000000..f51ee7d3
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInterfaceInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInterfaceInstruction.class
new file mode 100644
index 00000000..daddeedb
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInterfaceInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundJsrInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundJsrInstruction.class
new file mode 100644
index 00000000..df4181da
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundJsrInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLoadConstantInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLoadConstantInstruction.class
new file mode 100644
index 00000000..4aa33bb6
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLoadConstantInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLoadInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLoadInstruction.class
new file mode 100644
index 00000000..63747de6
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLoadInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLookupSwitchInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLookupSwitchInstruction.class
new file mode 100644
index 00000000..854bbe1b
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLookupSwitchInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewMultidimensionalArrayInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewMultidimensionalArrayInstruction.class
new file mode 100644
index 00000000..c43577d6
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewMultidimensionalArrayInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewObjectInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewObjectInstruction.class
new file mode 100644
index 00000000..247c33f8
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewObjectInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewPrimitiveArrayInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewPrimitiveArrayInstruction.class
new file mode 100644
index 00000000..29504bdd
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewPrimitiveArrayInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewReferenceArrayInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewReferenceArrayInstruction.class
new file mode 100644
index 00000000..4225c19e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewReferenceArrayInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundRetInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundRetInstruction.class
new file mode 100644
index 00000000..55c7f13a
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundRetInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundStoreInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundStoreInstruction.class
new file mode 100644
index 00000000..277d7e6a
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundStoreInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundTableSwitchInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundTableSwitchInstruction.class
new file mode 100644
index 00000000..d122ce58
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundTableSwitchInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundTypeCheckInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundTypeCheckInstruction.class
new file mode 100644
index 00000000..519a3f75
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundTypeCheckInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$SwitchCaseImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$SwitchCaseImpl.class
new file mode 100644
index 00000000..c07aaed7
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$SwitchCaseImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArgumentConstantInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArgumentConstantInstruction.class
new file mode 100644
index 00000000..69f407b3
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArgumentConstantInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArrayLoadInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArrayLoadInstruction.class
new file mode 100644
index 00000000..d7cb7e57
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArrayLoadInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArrayStoreInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArrayStoreInstruction.class
new file mode 100644
index 00000000..39b77471
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArrayStoreInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundBranchInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundBranchInstruction.class
new file mode 100644
index 00000000..4716d8d5
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundBranchInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundConvertInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundConvertInstruction.class
new file mode 100644
index 00000000..91dced49
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundConvertInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundFieldInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundFieldInstruction.class
new file mode 100644
index 00000000..0eaa090f
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundFieldInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIncrementInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIncrementInstruction.class
new file mode 100644
index 00000000..e3c74cf3
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIncrementInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInstruction.class
new file mode 100644
index 00000000..06fead7c
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIntrinsicConstantInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIntrinsicConstantInstruction.class
new file mode 100644
index 00000000..931492e8
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIntrinsicConstantInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeDynamicInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeDynamicInstruction.class
new file mode 100644
index 00000000..ab423bc7
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeDynamicInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeInstruction.class
new file mode 100644
index 00000000..7a55dc92
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundJsrInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundJsrInstruction.class
new file mode 100644
index 00000000..3b4ce3e6
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundJsrInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLoadConstantInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLoadConstantInstruction.class
new file mode 100644
index 00000000..5c30a57a
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLoadConstantInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLoadInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLoadInstruction.class
new file mode 100644
index 00000000..e93d6892
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLoadInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLookupSwitchInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLookupSwitchInstruction.class
new file mode 100644
index 00000000..5ad00808
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLookupSwitchInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundMonitorInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundMonitorInstruction.class
new file mode 100644
index 00000000..bf55c540
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundMonitorInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewMultidimensionalArrayInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewMultidimensionalArrayInstruction.class
new file mode 100644
index 00000000..f4564b7c
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewMultidimensionalArrayInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewObjectInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewObjectInstruction.class
new file mode 100644
index 00000000..1dd295a0
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewObjectInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewPrimitiveArrayInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewPrimitiveArrayInstruction.class
new file mode 100644
index 00000000..9b3b869a
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewPrimitiveArrayInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewReferenceArrayInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewReferenceArrayInstruction.class
new file mode 100644
index 00000000..63cf7da5
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewReferenceArrayInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNopInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNopInstruction.class
new file mode 100644
index 00000000..da252361
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNopInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundOperatorInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundOperatorInstruction.class
new file mode 100644
index 00000000..abfc1bf4
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundOperatorInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundRetInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundRetInstruction.class
new file mode 100644
index 00000000..ddd03c53
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundRetInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundReturnInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundReturnInstruction.class
new file mode 100644
index 00000000..3b1bb650
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundReturnInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStackInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStackInstruction.class
new file mode 100644
index 00000000..f386857d
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStackInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStoreInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStoreInstruction.class
new file mode 100644
index 00000000..da19d550
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStoreInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundTableSwitchInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundTableSwitchInstruction.class
new file mode 100644
index 00000000..764cf992
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundTableSwitchInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundThrowInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundThrowInstruction.class
new file mode 100644
index 00000000..4713fed4
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundThrowInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundTypeCheckInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundTypeCheckInstruction.class
new file mode 100644
index 00000000..f59b7c6b
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundTypeCheckInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.class
new file mode 100644
index 00000000..7dede9e3
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.java
new file mode 100644
index 00000000..0e528cd0
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.java
@@ -0,0 +1,1453 @@
+/*
+ * Copyright (c) 2022, 2024, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.lang.constant.ConstantDesc;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.lang.classfile.ClassFile;
+import java.lang.classfile.Instruction;
+import java.lang.classfile.constantpool.ClassEntry;
+import java.lang.classfile.instruction.SwitchCase;
+import java.lang.classfile.constantpool.FieldRefEntry;
+import java.lang.classfile.constantpool.InterfaceMethodRefEntry;
+import java.lang.classfile.constantpool.InvokeDynamicEntry;
+import java.lang.classfile.constantpool.LoadableConstantEntry;
+import java.lang.classfile.constantpool.MemberRefEntry;
+import java.lang.classfile.instruction.ArrayLoadInstruction;
+import java.lang.classfile.instruction.ArrayStoreInstruction;
+import java.lang.classfile.instruction.BranchInstruction;
+import java.lang.classfile.instruction.ConstantInstruction;
+import java.lang.classfile.instruction.ConvertInstruction;
+import java.lang.classfile.instruction.DiscontinuedInstruction;
+import java.lang.classfile.instruction.FieldInstruction;
+import java.lang.classfile.instruction.IncrementInstruction;
+import java.lang.classfile.instruction.InvokeDynamicInstruction;
+import java.lang.classfile.instruction.InvokeInstruction;
+import java.lang.classfile.instruction.LoadInstruction;
+import java.lang.classfile.instruction.LookupSwitchInstruction;
+import java.lang.classfile.instruction.MonitorInstruction;
+import java.lang.classfile.instruction.NewMultiArrayInstruction;
+import java.lang.classfile.instruction.NewObjectInstruction;
+import java.lang.classfile.instruction.NewPrimitiveArrayInstruction;
+import java.lang.classfile.instruction.NewReferenceArrayInstruction;
+import java.lang.classfile.instruction.NopInstruction;
+import java.lang.classfile.instruction.OperatorInstruction;
+import java.lang.classfile.instruction.ReturnInstruction;
+import java.lang.classfile.instruction.StackInstruction;
+import java.lang.classfile.instruction.StoreInstruction;
+import java.lang.classfile.instruction.TableSwitchInstruction;
+import java.lang.classfile.instruction.ThrowInstruction;
+import java.lang.classfile.instruction.TypeCheckInstruction;
+import java.lang.classfile.Label;
+import java.lang.classfile.Opcode;
+import java.lang.classfile.TypeKind;
+
+public abstract sealed class AbstractInstruction
+ extends AbstractElement
+ implements Instruction {
+
+ private static final String
+ FMT_ArgumentConstant = "ArgumentConstant[OP=%s, val=%s]",
+ FMT_Branch = "Branch[OP=%s]",
+ FMT_Field = "Field[OP=%s, field=%s.%s:%s]",
+ FMT_Increment = "Increment[OP=%s, slot=%d, val=%d]",
+ FMT_Invoke = "Invoke[OP=%s, m=%s.%s%s]",
+ FMT_InvokeDynamic = "InvokeDynamic[OP=%s, bsm=%s %s]",
+ FMT_InvokeInterface = "InvokeInterface[OP=%s, m=%s.%s%s]",
+ FMT_Load = "Load[OP=%s, slot=%d]",
+ FMT_LoadConstant = "LoadConstant[OP=%s, val=%s]",
+ FMT_LookupSwitch = "LookupSwitch[OP=%s]",
+ FMT_NewMultiArray = "NewMultiArray[OP=%s, type=%s[%d]]",
+ FMT_NewObj = "NewObj[OP=%s, type=%s]",
+ FMT_NewPrimitiveArray = "NewPrimitiveArray[OP=%s, type=%s]",
+ FMT_NewRefArray = "NewRefArray[OP=%s, type=%s]",
+ FMT_Return = "Return[OP=%s]",
+ FMT_Store = "Store[OP=%s, slot=%d]",
+ FMT_TableSwitch = "TableSwitch[OP=%s]",
+ FMT_Throw = "Throw[OP=%s]",
+ FMT_TypeCheck = "TypeCheck[OP=%s, type=%s]",
+ FMT_Unbound = "%s[op=%s]",
+ FMT_Discontinued = "Discontinued[OP=%s]";
+
+ final Opcode op;
+ final int size;
+
+ @Override
+ public Opcode opcode() {
+ return op;
+ }
+
+ @Override
+ public int sizeInBytes() {
+ return size;
+ }
+
+ public AbstractInstruction(Opcode op, int size) {
+ this.op = op;
+ this.size = size;
+ }
+
+ @Override
+ public abstract void writeTo(DirectCodeBuilder writer);
+
+ public abstract static sealed class BoundInstruction extends AbstractInstruction {
+ final CodeImpl code;
+ final int pos;
+
+ protected BoundInstruction(Opcode op, int size, CodeImpl code, int pos) {
+ super(op, size);
+ this.code = code;
+ this.pos = pos;
+ }
+
+ protected Label offsetToLabel(int offset) {
+ return code.getLabel(pos - code.codeStart + offset);
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ // Override this if the instruction has any CP references or labels!
+ code.classReader.copyBytesTo(writer.bytecodesBufWriter, pos, size);
+ }
+ }
+
+ public static final class BoundLoadInstruction
+ extends BoundInstruction implements LoadInstruction {
+
+ public BoundLoadInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+
+ @Override
+ public TypeKind typeKind() {
+ return op.primaryTypeKind();
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Load, this.opcode(), slot());
+ }
+
+ @Override
+ public int slot() {
+ return switch (size) {
+ case 2 -> code.classReader.readU1(pos + 1);
+ case 4 -> code.classReader.readU2(pos + 2);
+ default -> throw new IllegalArgumentException("Unexpected op size: " + op.sizeIfFixed() + " -- " + op);
+ };
+ }
+
+ }
+
+ public static final class BoundStoreInstruction
+ extends BoundInstruction implements StoreInstruction {
+
+ public BoundStoreInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public TypeKind typeKind() {
+ return op.primaryTypeKind();
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Store, this.opcode(), slot());
+ }
+
+ @Override
+ public int slot() {
+ return switch (size) {
+ case 2 -> code.classReader.readU1(pos + 1);
+ case 4 -> code.classReader.readU2(pos + 2);
+ default -> throw new IllegalArgumentException("Unexpected op size: " + size + " -- " + op);
+ };
+ }
+
+ }
+
+ public static final class BoundIncrementInstruction
+ extends BoundInstruction implements IncrementInstruction {
+
+ public BoundIncrementInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public int slot() {
+ return size == 6 ? code.classReader.readU2(pos + 2) : code.classReader.readU1(pos + 1);
+ }
+
+ @Override
+ public int constant() {
+ return size == 6 ? code.classReader.readS2(pos + 4) : (byte) code.classReader.readS1(pos + 2);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Increment, this.opcode(), slot(), constant());
+ }
+
+ }
+
+ public static final class BoundBranchInstruction
+ extends BoundInstruction implements BranchInstruction {
+
+ public BoundBranchInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public Label target() {
+ return offsetToLabel(branchByteOffset());
+ }
+
+ public int branchByteOffset() {
+ return size == 3
+ ? (int) (short) code.classReader.readU2(pos + 1)
+ : code.classReader.readInt(pos + 1);
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeBranch(opcode(), target());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Branch, this.opcode());
+ }
+
+ }
+
+ public record SwitchCaseImpl(int caseValue, Label target)
+ implements SwitchCase {
+ }
+
+ public static final class BoundLookupSwitchInstruction
+ extends BoundInstruction implements LookupSwitchInstruction {
+
+ // will always need size, cache everything to there
+ private final int afterPad;
+ private final int npairs;
+
+ BoundLookupSwitchInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, size(code, code.codeStart, pos), code, pos);
+
+ this.afterPad = pos + 1 + ((4 - ((pos + 1 - code.codeStart) & 3)) & 3);
+ this.npairs = code.classReader.readInt(afterPad + 4);
+ if (npairs < 0 || npairs > code.codeLength >> 3) {
+ throw new IllegalArgumentException("Invalid lookupswitch npairs value: " + npairs);
+ }
+ }
+
+ static int size(CodeImpl code, int codeStart, int pos) {
+ int afterPad = pos + 1 + ((4 - ((pos + 1 - codeStart) & 3)) & 3);
+ int pad = afterPad - (pos + 1);
+ int npairs = code.classReader.readInt(afterPad + 4);
+ return 1 + pad + 8 + npairs * 8;
+ }
+
+ private int defaultOffset() {
+ return code.classReader.readInt(afterPad);
+ }
+
+ @Override
+ public List cases() {
+ var cases = new SwitchCase[npairs];
+ for (int i = 0; i < npairs; ++i) {
+ int z = afterPad + 8 + 8 * i;
+ cases[i] = SwitchCase.of(code.classReader.readInt(z), offsetToLabel(code.classReader.readInt(z + 4)));
+ }
+ return List.of(cases);
+ }
+
+ @Override
+ public Label defaultTarget() {
+ return offsetToLabel(defaultOffset());
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeLookupSwitch(defaultTarget(), cases());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_LookupSwitch, this.opcode());
+ }
+
+ }
+
+ public static final class BoundTableSwitchInstruction
+ extends BoundInstruction implements TableSwitchInstruction {
+
+ BoundTableSwitchInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, size(code, code.codeStart, pos), code, pos);
+ }
+
+ static int size(CodeImpl code, int codeStart, int pos) {
+ int ap = pos + 1 + ((4 - ((pos + 1 - codeStart) & 3)) & 3);
+ int pad = ap - (pos + 1);
+ int low = code.classReader.readInt(ap + 4);
+ int high = code.classReader.readInt(ap + 8);
+ if (high < low || high - low > code.codeLength >> 2) {
+ throw new IllegalArgumentException("Invalid tableswitch values low: " + low + " high: " + high);
+ }
+ int cnt = high - low + 1;
+ return 1 + pad + 12 + cnt * 4;
+ }
+
+ private int afterPadding() {
+ int p = pos;
+ return p + 1 + ((4 - ((p + 1 - code.codeStart) & 3)) & 3);
+ }
+
+ @Override
+ public Label defaultTarget() {
+ return offsetToLabel(defaultOffset());
+ }
+
+ @Override
+ public int lowValue() {
+ return code.classReader.readInt(afterPadding() + 4);
+ }
+
+ @Override
+ public int highValue() {
+ return code.classReader.readInt(afterPadding() + 8);
+ }
+
+ @Override
+ public List cases() {
+ int low = lowValue();
+ int high = highValue();
+ int defOff = defaultOffset();
+ var cases = new ArrayList(high - low + 1);
+ int z = afterPadding() + 12;
+ for (int i = lowValue(); i <= high; ++i) {
+ int off = code.classReader.readInt(z);
+ if (defOff != off) {
+ cases.add(SwitchCase.of(i, offsetToLabel(off)));
+ }
+ z += 4;
+ }
+ return Collections.unmodifiableList(cases);
+ }
+
+ private int defaultOffset() {
+ return code.classReader.readInt(afterPadding());
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeTableSwitch(lowValue(), highValue(), defaultTarget(), cases());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_TableSwitch, this.opcode());
+ }
+
+ }
+
+ public static final class BoundFieldInstruction
+ extends BoundInstruction implements FieldInstruction {
+
+ private FieldRefEntry fieldEntry;
+
+ public BoundFieldInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public FieldRefEntry field() {
+ if (fieldEntry == null)
+ fieldEntry = code.classReader.readEntry(pos + 1, FieldRefEntry.class);
+ return fieldEntry;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ if (writer.canWriteDirect(code.constantPool()))
+ super.writeTo(writer);
+ else
+ writer.writeFieldAccess(op, field());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Field, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue());
+ }
+
+ }
+
+ public static final class BoundInvokeInstruction
+ extends BoundInstruction implements InvokeInstruction {
+ MemberRefEntry methodEntry;
+
+ public BoundInvokeInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public MemberRefEntry method() {
+ if (methodEntry == null)
+ methodEntry = code.classReader.readEntry(pos + 1, MemberRefEntry.class);
+ return methodEntry;
+ }
+
+ @Override
+ public boolean isInterface() {
+ return method().tag() == ClassFile.TAG_INTERFACEMETHODREF;
+ }
+
+ @Override
+ public int count() {
+ return 0;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ if (writer.canWriteDirect(code.constantPool()))
+ super.writeTo(writer);
+ else
+ writer.writeInvokeNormal(op, method());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Invoke, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue());
+ }
+
+ }
+
+ public static final class BoundInvokeInterfaceInstruction
+ extends BoundInstruction implements InvokeInstruction {
+ InterfaceMethodRefEntry methodEntry;
+
+ public BoundInvokeInterfaceInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public MemberRefEntry method() {
+ if (methodEntry == null)
+ methodEntry = code.classReader.readEntry(pos + 1, InterfaceMethodRefEntry.class);
+ return methodEntry;
+ }
+
+ @Override
+ public int count() {
+ return code.classReader.readU1(pos + 3);
+ }
+
+ @Override
+ public boolean isInterface() {
+ return true;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ if (writer.canWriteDirect(code.constantPool()))
+ super.writeTo(writer);
+ else
+ writer.writeInvokeInterface(op, (InterfaceMethodRefEntry) method(), count());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_InvokeInterface, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue());
+ }
+
+ }
+
+ public static final class BoundInvokeDynamicInstruction
+ extends BoundInstruction implements InvokeDynamicInstruction {
+ InvokeDynamicEntry indyEntry;
+
+ BoundInvokeDynamicInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public InvokeDynamicEntry invokedynamic() {
+ if (indyEntry == null)
+ indyEntry = code.classReader.readEntry(pos + 1, InvokeDynamicEntry.class);
+ return indyEntry;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ if (writer.canWriteDirect(code.constantPool()))
+ super.writeTo(writer);
+ else
+ writer.writeInvokeDynamic(invokedynamic());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_InvokeDynamic, this.opcode(), bootstrapMethod(), bootstrapArgs());
+ }
+
+ }
+
+ public static final class BoundNewObjectInstruction
+ extends BoundInstruction implements NewObjectInstruction {
+ ClassEntry classEntry;
+
+ BoundNewObjectInstruction(CodeImpl code, int pos) {
+ super(Opcode.NEW, Opcode.NEW.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public ClassEntry className() {
+ if (classEntry == null)
+ classEntry = code.classReader.readClassEntry(pos + 1);
+ return classEntry;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ if (writer.canWriteDirect(code.constantPool()))
+ super.writeTo(writer);
+ else
+ writer.writeNewObject(className());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_NewObj, this.opcode(), className().asInternalName());
+ }
+
+ }
+
+ public static final class BoundNewPrimitiveArrayInstruction
+ extends BoundInstruction implements NewPrimitiveArrayInstruction {
+
+ public BoundNewPrimitiveArrayInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public TypeKind typeKind() {
+ return TypeKind.fromNewarrayCode(code.classReader.readU1(pos + 1));
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_NewPrimitiveArray, this.opcode(), typeKind());
+ }
+
+ }
+
+ public static final class BoundNewReferenceArrayInstruction
+ extends BoundInstruction implements NewReferenceArrayInstruction {
+
+ public BoundNewReferenceArrayInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public ClassEntry componentType() {
+ return code.classReader.readClassEntry(pos + 1);
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ if (writer.canWriteDirect(code.constantPool()))
+ super.writeTo(writer);
+ else
+ writer.writeNewReferenceArray(componentType());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_NewRefArray, this.opcode(), componentType().asInternalName());
+ }
+ }
+
+ public static final class BoundNewMultidimensionalArrayInstruction
+ extends BoundInstruction implements NewMultiArrayInstruction {
+
+ public BoundNewMultidimensionalArrayInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public int dimensions() {
+ return code.classReader.readU1(pos + 3);
+ }
+
+ @Override
+ public ClassEntry arrayType() {
+ return code.classReader.readClassEntry(pos + 1);
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ if (writer.canWriteDirect(code.constantPool()))
+ super.writeTo(writer);
+ else
+ writer.writeNewMultidimensionalArray(dimensions(), arrayType());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_NewMultiArray, this.opcode(), arrayType().asInternalName(), dimensions());
+ }
+
+ }
+
+ public static final class BoundTypeCheckInstruction
+ extends BoundInstruction implements TypeCheckInstruction {
+ ClassEntry typeEntry;
+
+ public BoundTypeCheckInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public ClassEntry type() {
+ if (typeEntry == null)
+ typeEntry = code.classReader.readClassEntry(pos + 1);
+ return typeEntry;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ if (writer.canWriteDirect(code.constantPool()))
+ super.writeTo(writer);
+ else
+ writer.writeTypeCheck(op, type());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_TypeCheck, this.opcode(), type().asInternalName());
+ }
+
+ }
+
+ public static final class BoundArgumentConstantInstruction
+ extends BoundInstruction implements ConstantInstruction.ArgumentConstantInstruction {
+
+ public BoundArgumentConstantInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public Integer constantValue() {
+ return constantInt();
+ }
+
+ public int constantInt() {
+ return size == 3 ? code.classReader.readS2(pos + 1) : code.classReader.readS1(pos + 1);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_ArgumentConstant, this.opcode(), constantValue());
+ }
+
+ }
+
+ public static final class BoundLoadConstantInstruction
+ extends BoundInstruction implements ConstantInstruction.LoadConstantInstruction {
+
+ public BoundLoadConstantInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public LoadableConstantEntry constantEntry() {
+ return code.classReader.entryByIndex(op == Opcode.LDC
+ ? code.classReader.readU1(pos + 1)
+ : code.classReader.readU2(pos + 1),
+ LoadableConstantEntry.class);
+ }
+
+ @Override
+ public ConstantDesc constantValue() {
+ return constantEntry().constantValue();
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ if (writer.canWriteDirect(code.constantPool()))
+ super.writeTo(writer);
+ else
+ writer.writeLoadConstant(op, constantEntry());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_LoadConstant, this.opcode(), constantValue());
+ }
+
+ }
+
+ public static final class BoundJsrInstruction
+ extends BoundInstruction implements DiscontinuedInstruction.JsrInstruction {
+
+ public BoundJsrInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public Label target() {
+ return offsetToLabel(branchByteOffset());
+ }
+
+ public int branchByteOffset() {
+ return size == 3
+ ? code.classReader.readS2(pos + 1)
+ : code.classReader.readInt(pos + 1);
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeBranch(opcode(), target());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Discontinued, this.opcode());
+ }
+
+ }
+
+ public static final class BoundRetInstruction
+ extends BoundInstruction implements DiscontinuedInstruction.RetInstruction {
+
+ public BoundRetInstruction(Opcode op, CodeImpl code, int pos) {
+ super(op, op.sizeIfFixed(), code, pos);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Discontinued, this.opcode());
+ }
+
+ @Override
+ public int slot() {
+ return switch (size) {
+ case 2 -> code.classReader.readU1(pos + 1);
+ case 4 -> code.classReader.readU2(pos + 2);
+ default -> throw new IllegalArgumentException("Unexpected op size: " + op.sizeIfFixed() + " -- " + op);
+ };
+ }
+
+ }
+
+ public abstract static sealed class UnboundInstruction extends AbstractInstruction {
+
+ UnboundInstruction(Opcode op) {
+ super(op, op.sizeIfFixed());
+ }
+
+ @Override
+ // Override this if there is anything more that just the bytecode
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeBytecode(op);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Unbound, this.getClass().getSimpleName(), op);
+ }
+ }
+
+ public static final class UnboundLoadInstruction
+ extends UnboundInstruction implements LoadInstruction {
+ final int slot;
+
+ public UnboundLoadInstruction(Opcode op, int slot) {
+ super(op);
+ this.slot = slot;
+ }
+
+ @Override
+ public int slot() {
+ return slot;
+ }
+
+ @Override
+ public TypeKind typeKind() {
+ return op.primaryTypeKind();
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeLocalVar(op, slot);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Load, this.opcode(), slot());
+ }
+
+ }
+
+ public static final class UnboundStoreInstruction
+ extends UnboundInstruction implements StoreInstruction {
+ final int slot;
+
+ public UnboundStoreInstruction(Opcode op, int slot) {
+ super(op);
+ this.slot = slot;
+ }
+
+ @Override
+ public int slot() {
+ return slot;
+ }
+
+ @Override
+ public TypeKind typeKind() {
+ return op.primaryTypeKind();
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeLocalVar(op, slot);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Store, this.opcode(), slot());
+ }
+
+ }
+
+ public static final class UnboundIncrementInstruction
+ extends UnboundInstruction implements IncrementInstruction {
+ final int slot;
+ final int constant;
+
+ public UnboundIncrementInstruction(int slot, int constant) {
+ super(slot <= 255 && constant < 128 && constant > -127
+ ? Opcode.IINC
+ : Opcode.IINC_W);
+ this.slot = slot;
+ this.constant = constant;
+ }
+
+ @Override
+ public int slot() {
+ return slot;
+ }
+
+ @Override
+ public int constant() {
+ return constant;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeIncrement(slot, constant);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Increment, this.opcode(), slot(), constant());
+ }
+ }
+
+ public static final class UnboundBranchInstruction
+ extends UnboundInstruction implements BranchInstruction {
+ final Label target;
+
+ public UnboundBranchInstruction(Opcode op, Label target) {
+ super(op);
+ this.target = target;
+ }
+
+ @Override
+ public Label target() {
+ return target;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeBranch(op, target);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Branch, this.opcode());
+ }
+ }
+
+ public static final class UnboundLookupSwitchInstruction
+ extends UnboundInstruction implements LookupSwitchInstruction {
+
+ private final Label defaultTarget;
+ private final List cases;
+
+ public UnboundLookupSwitchInstruction(Label defaultTarget, List cases) {
+ super(Opcode.LOOKUPSWITCH);
+ this.defaultTarget = defaultTarget;
+ this.cases = List.copyOf(cases);
+ }
+
+ @Override
+ public List cases() {
+ return cases;
+ }
+
+ @Override
+ public Label defaultTarget() {
+ return defaultTarget;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeLookupSwitch(defaultTarget, cases);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_LookupSwitch, this.opcode());
+ }
+ }
+
+ public static final class UnboundTableSwitchInstruction
+ extends UnboundInstruction implements TableSwitchInstruction {
+
+ private final int lowValue, highValue;
+ private final Label defaultTarget;
+ private final List cases;
+
+ public UnboundTableSwitchInstruction(int lowValue, int highValue, Label defaultTarget, List cases) {
+ super(Opcode.TABLESWITCH);
+ this.lowValue = lowValue;
+ this.highValue = highValue;
+ this.defaultTarget = defaultTarget;
+ this.cases = List.copyOf(cases);
+ }
+
+ @Override
+ public int lowValue() {
+ return lowValue;
+ }
+
+ @Override
+ public int highValue() {
+ return highValue;
+ }
+
+ @Override
+ public Label defaultTarget() {
+ return defaultTarget;
+ }
+
+ @Override
+ public List cases() {
+ return cases;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeTableSwitch(lowValue, highValue, defaultTarget, cases);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_TableSwitch, this.opcode());
+ }
+ }
+
+ public static final class UnboundReturnInstruction
+ extends UnboundInstruction implements ReturnInstruction {
+
+ public UnboundReturnInstruction(Opcode op) {
+ super(op);
+ }
+
+ @Override
+ public TypeKind typeKind() {
+ return op.primaryTypeKind();
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Return, this.opcode());
+ }
+
+ }
+
+ public static final class UnboundThrowInstruction
+ extends UnboundInstruction implements ThrowInstruction {
+
+ public UnboundThrowInstruction() {
+ super(Opcode.ATHROW);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Throw, this.opcode());
+ }
+
+ }
+
+ public static final class UnboundFieldInstruction
+ extends UnboundInstruction implements FieldInstruction {
+ final FieldRefEntry fieldEntry;
+
+ public UnboundFieldInstruction(Opcode op,
+ FieldRefEntry fieldEntry) {
+ super(op);
+ this.fieldEntry = fieldEntry;
+ }
+
+ @Override
+ public FieldRefEntry field() {
+ return fieldEntry;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeFieldAccess(op, fieldEntry);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Field, this.opcode(), this.owner().asInternalName(), this.name().stringValue(), this.type().stringValue());
+ }
+ }
+
+ public static final class UnboundInvokeInstruction
+ extends UnboundInstruction implements InvokeInstruction {
+ final MemberRefEntry methodEntry;
+
+ public UnboundInvokeInstruction(Opcode op, MemberRefEntry methodEntry) {
+ super(op);
+ this.methodEntry = methodEntry;
+ }
+
+ @Override
+ public MemberRefEntry method() {
+ return methodEntry;
+ }
+
+ @Override
+ public boolean isInterface() {
+ return op == Opcode.INVOKEINTERFACE || methodEntry instanceof InterfaceMethodRefEntry;
+ }
+
+ @Override
+ public int count() {
+ return op == Opcode.INVOKEINTERFACE
+ ? Util.parameterSlots(Util.methodTypeSymbol(methodEntry.nameAndType())) + 1
+ : 0;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ if (op == Opcode.INVOKEINTERFACE)
+ writer.writeInvokeInterface(op, (InterfaceMethodRefEntry) method(), count());
+ else
+ writer.writeInvokeNormal(op, method());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Invoke, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue());
+ }
+ }
+
+ public static final class UnboundInvokeDynamicInstruction
+ extends UnboundInstruction implements InvokeDynamicInstruction {
+ final InvokeDynamicEntry indyEntry;
+
+ public UnboundInvokeDynamicInstruction(InvokeDynamicEntry indyEntry) {
+ super(Opcode.INVOKEDYNAMIC);
+ this.indyEntry = indyEntry;
+ }
+
+ @Override
+ public InvokeDynamicEntry invokedynamic() {
+ return indyEntry;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeInvokeDynamic(invokedynamic());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_InvokeDynamic, this.opcode(), bootstrapMethod(), bootstrapArgs());
+ }
+ }
+
+ public static final class UnboundNewObjectInstruction
+ extends UnboundInstruction implements NewObjectInstruction {
+ final ClassEntry classEntry;
+
+ public UnboundNewObjectInstruction(ClassEntry classEntry) {
+ super(Opcode.NEW);
+ this.classEntry = classEntry;
+ }
+
+ @Override
+ public ClassEntry className() {
+ return classEntry;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeNewObject(className());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_NewObj, this.opcode(), className().asInternalName());
+ }
+ }
+
+ public static final class UnboundNewPrimitiveArrayInstruction
+ extends UnboundInstruction implements NewPrimitiveArrayInstruction {
+ final TypeKind typeKind;
+
+ public UnboundNewPrimitiveArrayInstruction(TypeKind typeKind) {
+ super(Opcode.NEWARRAY);
+ this.typeKind = typeKind;
+ }
+
+ @Override
+ public TypeKind typeKind() {
+ return typeKind;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeNewPrimitiveArray(typeKind.newarrayCode());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_NewPrimitiveArray, this.opcode(), typeKind());
+ }
+ }
+
+ public static final class UnboundNewReferenceArrayInstruction
+ extends UnboundInstruction implements NewReferenceArrayInstruction {
+ final ClassEntry componentTypeEntry;
+
+ public UnboundNewReferenceArrayInstruction(ClassEntry componentTypeEntry) {
+ super(Opcode.ANEWARRAY);
+ this.componentTypeEntry = componentTypeEntry;
+ }
+
+ @Override
+ public ClassEntry componentType() {
+ return componentTypeEntry;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeNewReferenceArray(componentType());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_NewRefArray, this.opcode(), componentType().asInternalName());
+ }
+ }
+
+ public static final class UnboundNewMultidimensionalArrayInstruction
+ extends UnboundInstruction implements NewMultiArrayInstruction {
+ final ClassEntry arrayTypeEntry;
+ final int dimensions;
+
+ public UnboundNewMultidimensionalArrayInstruction(ClassEntry arrayTypeEntry,
+ int dimensions) {
+ super(Opcode.MULTIANEWARRAY);
+ this.arrayTypeEntry = arrayTypeEntry;
+ this.dimensions = dimensions;
+ }
+
+ @Override
+ public int dimensions() {
+ return dimensions;
+ }
+
+ @Override
+ public ClassEntry arrayType() {
+ return arrayTypeEntry;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeNewMultidimensionalArray(dimensions(), arrayType());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_NewMultiArray, this.opcode(), arrayType().asInternalName(), dimensions());
+ }
+
+ }
+
+ public static final class UnboundArrayLoadInstruction
+ extends UnboundInstruction implements ArrayLoadInstruction {
+
+ public UnboundArrayLoadInstruction(Opcode op) {
+ super(op);
+ }
+
+ @Override
+ public TypeKind typeKind() {
+ return op.primaryTypeKind();
+ }
+ }
+
+ public static final class UnboundArrayStoreInstruction
+ extends UnboundInstruction implements ArrayStoreInstruction {
+
+ public UnboundArrayStoreInstruction(Opcode op) {
+ super(op);
+ }
+
+ @Override
+ public TypeKind typeKind() {
+ return op.primaryTypeKind();
+ }
+ }
+
+ public static final class UnboundTypeCheckInstruction
+ extends UnboundInstruction implements TypeCheckInstruction {
+ final ClassEntry typeEntry;
+
+ public UnboundTypeCheckInstruction(Opcode op, ClassEntry typeEntry) {
+ super(op);
+ this.typeEntry = typeEntry;
+ }
+
+ @Override
+ public ClassEntry type() {
+ return typeEntry;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeTypeCheck(op, type());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_TypeCheck, this.opcode(), type().asInternalName());
+ }
+ }
+
+ public static final class UnboundStackInstruction
+ extends UnboundInstruction implements StackInstruction {
+
+ public UnboundStackInstruction(Opcode op) {
+ super(op);
+ }
+
+ }
+
+ public static final class UnboundConvertInstruction
+ extends UnboundInstruction implements ConvertInstruction {
+
+ public UnboundConvertInstruction(Opcode op) {
+ super(op);
+ }
+
+ @Override
+ public TypeKind fromType() {
+ return op.primaryTypeKind();
+ }
+
+ @Override
+ public TypeKind toType() {
+ return op.secondaryTypeKind();
+ }
+ }
+
+ public static final class UnboundOperatorInstruction
+ extends UnboundInstruction implements OperatorInstruction {
+
+ public UnboundOperatorInstruction(Opcode op) {
+ super(op);
+ }
+
+ @Override
+ public TypeKind typeKind() {
+ return op.primaryTypeKind();
+ }
+ }
+
+ public static final class UnboundIntrinsicConstantInstruction
+ extends UnboundInstruction implements ConstantInstruction.IntrinsicConstantInstruction {
+ final ConstantDesc constant;
+
+ public UnboundIntrinsicConstantInstruction(Opcode op) {
+ super(op);
+ constant = op.constantValue();
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ super.writeTo(writer);
+ }
+
+ @Override
+ public ConstantDesc constantValue() {
+ return constant;
+ }
+ }
+
+ public static final class UnboundArgumentConstantInstruction
+ extends UnboundInstruction implements ConstantInstruction.ArgumentConstantInstruction {
+ final int value;
+
+ public UnboundArgumentConstantInstruction(Opcode op, int value) {
+ super(op);
+ this.value = value;
+ }
+
+ @Override
+ public Integer constantValue() {
+ return value;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeArgumentConstant(op, value);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_ArgumentConstant, this.opcode(), constantValue());
+ }
+ }
+
+ public static final class UnboundLoadConstantInstruction
+ extends UnboundInstruction implements ConstantInstruction.LoadConstantInstruction {
+ final LoadableConstantEntry constant;
+
+ public UnboundLoadConstantInstruction(Opcode op, LoadableConstantEntry constant) {
+ super(op);
+ this.constant = constant;
+ }
+
+ @Override
+ public LoadableConstantEntry constantEntry() {
+ return constant;
+ }
+
+ @Override
+ public ConstantDesc constantValue() {
+ return constant.constantValue();
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeLoadConstant(op, constant);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_LoadConstant, this.opcode(), constantValue());
+ }
+ }
+
+ public static final class UnboundMonitorInstruction
+ extends UnboundInstruction implements MonitorInstruction {
+
+ public UnboundMonitorInstruction(Opcode op) {
+ super(op);
+ }
+
+ }
+
+ public static final class UnboundNopInstruction
+ extends UnboundInstruction implements NopInstruction {
+
+ public UnboundNopInstruction() {
+ super(Opcode.NOP);
+ }
+
+ }
+
+ public static final class UnboundJsrInstruction
+ extends UnboundInstruction implements DiscontinuedInstruction.JsrInstruction {
+ final Label target;
+
+ public UnboundJsrInstruction(Opcode op, Label target) {
+ super(op);
+ this.target = target;
+ }
+
+ @Override
+ public Label target() {
+ return target;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeBranch(op, target);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Discontinued, this.opcode());
+ }
+ }
+
+ public static final class UnboundRetInstruction
+ extends UnboundInstruction implements DiscontinuedInstruction.RetInstruction {
+ final int slot;
+
+ public UnboundRetInstruction(Opcode op, int slot) {
+ super(op);
+ this.slot = slot;
+ }
+
+ @Override
+ public int slot() {
+ return slot;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.writeLocalVar(op, slot);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(FMT_Discontinued, this.opcode());
+ }
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractDynamicConstantPoolEntry.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractDynamicConstantPoolEntry.class
new file mode 100644
index 00000000..9ca1d4c6
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractDynamicConstantPoolEntry.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractMemberRefEntry.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractMemberRefEntry.class
new file mode 100644
index 00000000..2eb935b9
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractMemberRefEntry.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractNamedEntry.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractNamedEntry.class
new file mode 100644
index 00000000..0476b31a
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractNamedEntry.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefEntry.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefEntry.class
new file mode 100644
index 00000000..61c5739e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefEntry.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefsEntry.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefsEntry.class
new file mode 100644
index 00000000..5f32c608
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefsEntry.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ClassEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ClassEntryImpl.class
new file mode 100644
index 00000000..5aae4dc8
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ClassEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ConstantDynamicEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ConstantDynamicEntryImpl.class
new file mode 100644
index 00000000..789a91f2
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ConstantDynamicEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$CpException.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$CpException.class
new file mode 100644
index 00000000..e279e5ce
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$CpException.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$DoubleEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$DoubleEntryImpl.class
new file mode 100644
index 00000000..89fc4d43
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$DoubleEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$FieldRefEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$FieldRefEntryImpl.class
new file mode 100644
index 00000000..62372405
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$FieldRefEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$FloatEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$FloatEntryImpl.class
new file mode 100644
index 00000000..f62e7e39
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$FloatEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$IntegerEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$IntegerEntryImpl.class
new file mode 100644
index 00000000..67b0e26b
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$IntegerEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$InterfaceMethodRefEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$InterfaceMethodRefEntryImpl.class
new file mode 100644
index 00000000..1d01aa12
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$InterfaceMethodRefEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$InvokeDynamicEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$InvokeDynamicEntryImpl.class
new file mode 100644
index 00000000..5dd87de5
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$InvokeDynamicEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$LongEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$LongEntryImpl.class
new file mode 100644
index 00000000..4d057b80
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$LongEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodHandleEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodHandleEntryImpl.class
new file mode 100644
index 00000000..3d9404a3
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodHandleEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodRefEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodRefEntryImpl.class
new file mode 100644
index 00000000..e0400d66
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodRefEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodTypeEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodTypeEntryImpl.class
new file mode 100644
index 00000000..dbeaa362
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodTypeEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ModuleEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ModuleEntryImpl.class
new file mode 100644
index 00000000..f7e28f30
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ModuleEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$NameAndTypeEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$NameAndTypeEntryImpl.class
new file mode 100644
index 00000000..0d33546e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$NameAndTypeEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$PackageEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$PackageEntryImpl.class
new file mode 100644
index 00000000..7fc482bf
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$PackageEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$PrimitiveEntry.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$PrimitiveEntry.class
new file mode 100644
index 00000000..6a20db80
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$PrimitiveEntry.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$StringEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$StringEntryImpl.class
new file mode 100644
index 00000000..ce238ef3
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$StringEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl$State.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl$State.class
new file mode 100644
index 00000000..7e64a3cd
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl$State.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl.class
new file mode 100644
index 00000000..ef0d83e7
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry.class
new file mode 100644
index 00000000..c7307a9b
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry.java
new file mode 100644
index 00000000..f846ca6f
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry.java
@@ -0,0 +1,1201 @@
+/*
+ * Copyright (c) 2022, 2024, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.lang.constant.*;
+import java.lang.invoke.TypeDescriptor;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+import java.lang.classfile.ClassFile;
+import java.lang.classfile.constantpool.ClassEntry;
+import java.lang.classfile.constantpool.ConstantDynamicEntry;
+import java.lang.classfile.constantpool.ConstantPool;
+import java.lang.classfile.constantpool.ConstantPoolBuilder;
+import java.lang.classfile.BufWriter;
+import java.lang.classfile.constantpool.DoubleEntry;
+import java.lang.classfile.constantpool.FieldRefEntry;
+import java.lang.classfile.constantpool.FloatEntry;
+import java.lang.classfile.constantpool.IntegerEntry;
+import java.lang.classfile.constantpool.InterfaceMethodRefEntry;
+import java.lang.classfile.constantpool.InvokeDynamicEntry;
+import java.lang.classfile.constantpool.LongEntry;
+import java.lang.classfile.constantpool.MemberRefEntry;
+import java.lang.classfile.constantpool.MethodHandleEntry;
+import java.lang.classfile.constantpool.MethodRefEntry;
+import java.lang.classfile.constantpool.MethodTypeEntry;
+import java.lang.classfile.constantpool.ModuleEntry;
+import java.lang.classfile.constantpool.NameAndTypeEntry;
+import java.lang.classfile.constantpool.PackageEntry;
+import java.lang.classfile.constantpool.PoolEntry;
+import java.lang.classfile.constantpool.StringEntry;
+import java.lang.classfile.constantpool.Utf8Entry;
+import jdk.internal.access.JavaLangAccess;
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.util.ArraysSupport;
+
+public abstract sealed class AbstractPoolEntry {
+ /*
+ Invariant: a {CP,BSM} entry for pool P refer only to {CP,BSM} entries
+ from P or P's parent. This is enforced by the various xxxEntry methods
+ in SplitConstantPool. As a result, code in this file can use writeU2
+ instead of writeIndex.
+
+ Cloning of entries may be a no-op if the entry is already on the right pool
+ (which implies that the referenced entries will also be on the right pool.)
+ */
+
+ private static final int TAG_SMEAR = 0x13C4B2D1;
+ static final int NON_ZERO = 0x40000000;
+
+ public static int hash1(int tag, int x1) {
+ return (tag * TAG_SMEAR + x1) | NON_ZERO;
+ }
+
+ public static int hash2(int tag, int x1, int x2) {
+ return (tag * TAG_SMEAR + x1 + 31 * x2) | NON_ZERO;
+ }
+
+ // Ensure that hash is never zero
+ public static int hashString(int stringHash) {
+ return stringHash | NON_ZERO;
+ }
+
+ public static Utf8Entry rawUtf8EntryFromStandardAttributeName(String name) {
+ //assuming standard attribute names are all US_ASCII
+ var raw = name.getBytes(StandardCharsets.US_ASCII);
+ return new Utf8EntryImpl(null, 0, raw, 0, raw.length);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static T maybeClone(ConstantPoolBuilder cp, T entry) {
+ return (T)((AbstractPoolEntry)entry).clone(cp);
+ }
+
+ final ConstantPool constantPool;
+ public final byte tag;
+ private final int index;
+ private final int hash;
+
+ private AbstractPoolEntry(ConstantPool constantPool, int tag, int index, int hash) {
+ this.tag = (byte) tag;
+ this.index = index;
+ this.hash = hash;
+ this.constantPool = constantPool;
+ }
+
+ public ConstantPool constantPool() { return constantPool; }
+
+ public int index() { return index; }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+
+ public byte tag() {
+ return tag;
+ }
+
+ public int width() {
+ return (tag == ClassFile.TAG_LONG || tag == ClassFile.TAG_DOUBLE) ? 2 : 1;
+ }
+
+ abstract PoolEntry clone(ConstantPoolBuilder cp);
+
+ public static final class Utf8EntryImpl extends AbstractPoolEntry implements Utf8Entry {
+ // Processing UTF8 from the constant pool is one of the more expensive
+ // operations, and often, we don't actually need access to the constant
+ // as a string. So there are multiple layers of laziness in UTF8
+ // constants. In the first stage, all we do is record the range of
+ // bytes in the classfile. If the size or hashCode is needed, then we
+ // process the raw bytes into a byte[] or char[], but do not inflate
+ // a String. If a string is needed, it too is inflated lazily.
+ // If we construct a Utf8Entry from a string, we generate the encoding
+ // at write time.
+
+ enum State { RAW, BYTE, CHAR, STRING }
+
+ private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+
+ private State state;
+ private final byte[] rawBytes; // null if initialized directly from a string
+ private final int offset;
+ private final int rawLen;
+ // Set in any state other than RAW
+ private int hash;
+ private int charLen;
+ // Set in CHAR state
+ private char[] chars;
+ // Only set in STRING state
+ private String stringValue;
+
+ Utf8EntryImpl(ConstantPool cpm, int index,
+ byte[] rawBytes, int offset, int rawLen) {
+ super(cpm, ClassFile.TAG_UTF8, index, 0);
+ this.rawBytes = rawBytes;
+ this.offset = offset;
+ this.rawLen = rawLen;
+ this.state = State.RAW;
+ }
+
+ Utf8EntryImpl(ConstantPool cpm, int index, String s) {
+ this(cpm, index, s, hashString(s.hashCode()));
+ }
+
+ Utf8EntryImpl(ConstantPool cpm, int index, String s, int hash) {
+ super(cpm, ClassFile.TAG_UTF8, index, 0);
+ this.rawBytes = null;
+ this.offset = 0;
+ this.rawLen = 0;
+ this.state = State.STRING;
+ this.stringValue = s;
+ this.charLen = s.length();
+ this.hash = hash;
+ }
+
+ Utf8EntryImpl(ConstantPool cpm, int index, Utf8EntryImpl u) {
+ super(cpm, ClassFile.TAG_UTF8, index, 0);
+ this.rawBytes = u.rawBytes;
+ this.offset = u.offset;
+ this.rawLen = u.rawLen;
+ this.state = u.state;
+ this.hash = u.hash;
+ this.charLen = u.charLen;
+ this.chars = u.chars;
+ this.stringValue = u.stringValue;
+ }
+
+ /**
+ * {@jvms 4.4.7} String content is encoded in modified UTF-8.
+ *
+ * Modified UTF-8 strings are encoded so that code point sequences that
+ * contain only non-null ASCII characters can be represented using only 1
+ * byte per code point, but all code points in the Unicode codespace can be
+ * represented.
+ *
+ * Modified UTF-8 strings are not null-terminated.
+ *
+ * Code points in the range '\u0001' to '\u007F' are represented by a single
+ * byte.
+ *
+ * The null code point ('\u0000') and code points in the range '\u0080' to
+ * '\u07FF' are represented by a pair of bytes.
+ *
+ * Code points in the range '\u0800' to '\uFFFF' are represented by 3 bytes.
+ *
+ * Characters with code points above U+FFFF (so-called supplementary
+ * characters) are represented by separately encoding the two surrogate code
+ * units of their UTF-16 representation. Each of the surrogate code units is
+ * represented by three bytes. This means supplementary characters are
+ * represented by six bytes.
+ *
+ * The bytes of multibyte characters are stored in the class file in
+ * big-endian (high byte first) order.
+ *
+ * There are two differences between this format and the "standard" UTF-8
+ * format. First, the null character (char)0 is encoded using the 2-byte
+ * format rather than the 1-byte format, so that modified UTF-8 strings
+ * never have embedded nulls. Second, only the 1-byte, 2-byte, and 3-byte
+ * formats of standard UTF-8 are used. The Java Virtual Machine does not
+ * recognize the four-byte format of standard UTF-8; it uses its own
+ * two-times-three-byte format instead.
+ */
+ private void inflate() {
+ int singleBytes = JLA.countPositives(rawBytes, offset, rawLen);
+ int hash = ArraysSupport.hashCodeOfUnsigned(rawBytes, offset, singleBytes, 0);
+ if (singleBytes == rawLen) {
+ this.hash = hashString(hash);
+ charLen = rawLen;
+ state = State.BYTE;
+ }
+ else {
+ char[] chararr = new char[rawLen];
+ int chararr_count = singleBytes;
+ // Inflate prefix of bytes to characters
+ JLA.inflateBytesToChars(rawBytes, offset, chararr, 0, singleBytes);
+
+ int px = offset + singleBytes;
+ int utfend = offset + rawLen;
+ while (px < utfend) {
+ int c = (int) rawBytes[px] & 0xff;
+ switch (c >> 4) {
+ case 0, 1, 2, 3, 4, 5, 6, 7: {
+ // 0xxx xxxx
+ px++;
+ chararr[chararr_count++] = (char) c;
+ hash = 31 * hash + c;
+ break;
+ }
+ case 12, 13: {
+ // 110x xxxx 10xx xxxx
+ px += 2;
+ if (px > utfend) {
+ throw new CpException("malformed input: partial character at end");
+ }
+ int char2 = rawBytes[px - 1];
+ if ((char2 & 0xC0) != 0x80) {
+ throw new CpException("malformed input around byte " + px);
+ }
+ char v = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
+ chararr[chararr_count++] = v;
+ hash = 31 * hash + v;
+ break;
+ }
+ case 14: {
+ // 1110 xxxx 10xx xxxx 10xx xxxx
+ px += 3;
+ if (px > utfend) {
+ throw new CpException("malformed input: partial character at end");
+ }
+ int char2 = rawBytes[px - 2];
+ int char3 = rawBytes[px - 1];
+ if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) {
+ throw new CpException("malformed input around byte " + (px - 1));
+ }
+ char v = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | (char3 & 0x3F));
+ chararr[chararr_count++] = v;
+ hash = 31 * hash + v;
+ break;
+ }
+ default:
+ // 10xx xxxx, 1111 xxxx
+ throw new CpException("malformed input around byte " + px);
+ }
+ }
+ this.hash = hashString(hash);
+ charLen = chararr_count;
+ this.chars = chararr;
+ state = State.CHAR;
+ }
+
+ }
+
+ @Override
+ public Utf8EntryImpl clone(ConstantPoolBuilder cp) {
+ if (cp.canWriteDirect(constantPool))
+ return this;
+ return (state == State.STRING && rawBytes == null)
+ ? (Utf8EntryImpl) cp.utf8Entry(stringValue)
+ : ((SplitConstantPool) cp).maybeCloneUtf8Entry(this);
+ }
+
+ @Override
+ public int hashCode() {
+ if (state == State.RAW)
+ inflate();
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ if (state == State.RAW)
+ inflate();
+ if (state != State.STRING) {
+ stringValue = (chars != null)
+ ? new String(chars, 0, charLen)
+ : new String(rawBytes, offset, charLen, StandardCharsets.ISO_8859_1);
+ state = State.STRING;
+ }
+ return stringValue;
+ }
+
+ @Override
+ public String stringValue() {
+ return toString();
+ }
+
+ @Override
+ public ConstantDesc constantValue() {
+ return stringValue();
+ }
+
+ @Override
+ public int length() {
+ if (state == State.RAW)
+ inflate();
+ return charLen;
+ }
+
+ @Override
+ public char charAt(int index) {
+ if (state == State.STRING)
+ return stringValue.charAt(index);
+ if (state == State.RAW)
+ inflate();
+ return (chars != null)
+ ? chars[index]
+ : (char) rawBytes[index + offset];
+ }
+
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ return toString().subSequence(start, end);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o instanceof Utf8EntryImpl u) {
+ return equalsUtf8(u);
+ }
+ return false;
+ }
+
+ public boolean equalsUtf8(Utf8EntryImpl u) {
+ if (hashCode() != u.hashCode()
+ || length() != u.length())
+ return false;
+ if (rawBytes != null && u.rawBytes != null)
+ return Arrays.equals(rawBytes, offset, offset + rawLen,
+ u.rawBytes, u.offset, u.offset + u.rawLen);
+ else if ((state == State.STRING && u.state == State.STRING))
+ return stringValue.equals(u.stringValue);
+ else
+ return stringValue().equals(u.stringValue());
+ }
+
+ @Override
+ public boolean equalsString(String s) {
+ if (state == State.RAW)
+ inflate();
+ switch (state) {
+ case STRING:
+ return stringValue.equals(s);
+ case CHAR:
+ if (charLen != s.length() || hash != hashString(s.hashCode()))
+ return false;
+ for (int i=0; i 65535) {
+ throw new IllegalArgumentException("string too long");
+ }
+ pool.writeU1(tag);
+ pool.writeU2(charLen);
+ for (int i = 0; i < charLen; ++i) {
+ char c = stringValue.charAt(i);
+ if (c >= '\001' && c <= '\177') {
+ // Optimistic writing -- hope everything is bytes
+ // If not, we bail out, and alternate path patches the length
+ pool.writeU1((byte) c);
+ }
+ else {
+ int charLength = stringValue.length();
+ int byteLength = i;
+ char c1;
+ for (int j = i; j < charLength; ++j) {
+ c1 = (stringValue).charAt(j);
+ if (c1 >= '\001' && c1 <= '\177') {
+ byteLength++;
+ } else if (c1 > '\u07FF') {
+ byteLength += 3;
+ } else {
+ byteLength += 2;
+ }
+ }
+ if (byteLength > 65535) {
+ throw new IllegalArgumentException();
+ }
+ int byteLengthFinal = byteLength;
+ pool.patchInt(pool.size() - i - 2, 2, byteLengthFinal);
+ for (int j = i; j < charLength; ++j) {
+ c1 = (stringValue).charAt(j);
+ if (c1 >= '\001' && c1 <= '\177') {
+ pool.writeU1((byte) c1);
+ } else if (c1 > '\u07FF') {
+ pool.writeU1((byte) (0xE0 | c1 >> 12 & 0xF));
+ pool.writeU1((byte) (0x80 | c1 >> 6 & 0x3F));
+ pool.writeU1((byte) (0x80 | c1 & 0x3F));
+ } else {
+ pool.writeU1((byte) (0xC0 | c1 >> 6 & 0x1F));
+ pool.writeU1((byte) (0x80 | c1 & 0x3F));
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ abstract static sealed class AbstractRefEntry extends AbstractPoolEntry {
+ protected final T ref1;
+
+ public AbstractRefEntry(ConstantPool constantPool, int tag, int index, T ref1) {
+ super(constantPool, tag, index, hash1(tag, ref1.index()));
+ this.ref1 = ref1;
+ }
+
+ public T ref1() {
+ return ref1;
+ }
+
+ public void writeTo(BufWriter pool) {
+ pool.writeU1(tag);
+ pool.writeU2(ref1.index());
+ }
+
+ @Override
+ public String toString() {
+ return tag() + " " + ref1();
+ }
+ }
+
+ abstract static sealed class AbstractRefsEntry
+ extends AbstractPoolEntry {
+ protected final T ref1;
+ protected final U ref2;
+
+ public AbstractRefsEntry(ConstantPool constantPool, int tag, int index, T ref1, U ref2) {
+ super(constantPool, tag, index, hash2(tag, ref1.index(), ref2.index()));
+ this.ref1 = ref1;
+ this.ref2 = ref2;
+ }
+
+ public T ref1() {
+ return ref1;
+ }
+
+ public U ref2() {
+ return ref2;
+ }
+
+ public void writeTo(BufWriter pool) {
+ pool.writeU1(tag);
+ pool.writeU2(ref1.index());
+ pool.writeU2(ref2.index());
+ }
+
+ @Override
+ public String toString() {
+ return tag() + " " + ref1 + "-" + ref2;
+ }
+ }
+
+ abstract static sealed class AbstractNamedEntry extends AbstractRefEntry {
+
+ public AbstractNamedEntry(ConstantPool constantPool, int tag, int index, Utf8EntryImpl ref1) {
+ super(constantPool, tag, index, ref1);
+ }
+
+ public Utf8Entry name() {
+ return ref1;
+ }
+
+ public String asInternalName() {
+ return ref1.stringValue();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) { return true; }
+ if (o instanceof AbstractNamedEntry ne) {
+ return tag == ne.tag() && name().equals(ref1());
+ }
+ return false;
+ }
+ }
+
+ public static final class ClassEntryImpl extends AbstractNamedEntry implements ClassEntry {
+
+ public ClassDesc sym = null;
+
+ ClassEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl name) {
+ super(cpm, ClassFile.TAG_CLASS, index, name);
+ }
+
+ @Override
+ public ClassEntry clone(ConstantPoolBuilder cp) {
+ if (cp.canWriteDirect(constantPool)) {
+ return this;
+ } else {
+ ClassEntryImpl ret = (ClassEntryImpl)cp.classEntry(ref1);
+ ret.sym = sym;
+ return ret;
+ }
+ }
+
+ @Override
+ public ClassDesc asSymbol() {
+ var sym = this.sym;
+ if (sym != null) {
+ return sym;
+ }
+ return this.sym = Util.toClassDesc(asInternalName());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o instanceof ClassEntryImpl cce) {
+ return cce.name().equals(this.name());
+ } else if (o instanceof ClassEntry c) {
+ return c.asSymbol().equals(this.asSymbol());
+ }
+ return false;
+ }
+ }
+
+ public static final class PackageEntryImpl extends AbstractNamedEntry implements PackageEntry {
+
+ PackageEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl name) {
+ super(cpm, ClassFile.TAG_PACKAGE, index, name);
+ }
+
+ @Override
+ public PackageEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.packageEntry(ref1);
+ }
+
+ @Override
+ public PackageDesc asSymbol() {
+ return PackageDesc.ofInternalName(asInternalName());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o instanceof PackageEntry p) {
+ return name().equals(p.name());
+ }
+ return false;
+ }
+ }
+
+ public static final class ModuleEntryImpl extends AbstractNamedEntry implements ModuleEntry {
+
+ ModuleEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl name) {
+ super(cpm, ClassFile.TAG_MODULE, index, name);
+ }
+
+ @Override
+ public ModuleEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.moduleEntry(ref1);
+ }
+
+ @Override
+ public ModuleDesc asSymbol() {
+ return ModuleDesc.of(asInternalName());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o instanceof ModuleEntryImpl m) {
+ return name().equals(m.name());
+ }
+ return false;
+ }
+ }
+
+ public static final class NameAndTypeEntryImpl extends AbstractRefsEntry
+ implements NameAndTypeEntry {
+
+ public TypeDescriptor typeSym = null;
+
+ NameAndTypeEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl name, Utf8EntryImpl type) {
+ super(cpm, ClassFile.TAG_NAMEANDTYPE, index, name, type);
+ }
+
+ @Override
+ public Utf8Entry name() {
+ return ref1;
+ }
+
+ @Override
+ public Utf8Entry type() {
+ return ref2;
+ }
+
+ public ClassDesc fieldTypeSymbol() {
+ if (typeSym instanceof ClassDesc cd) {
+ return cd;
+ } else {
+ return (ClassDesc)(typeSym = ClassDesc.ofDescriptor(ref2.stringValue()));
+ }
+ }
+
+ public MethodTypeDesc methodTypeSymbol() {
+ if (typeSym instanceof MethodTypeDesc mtd) {
+ return mtd;
+ } else {
+ return (MethodTypeDesc)(typeSym = MethodTypeDesc.ofDescriptor(ref2.stringValue()));
+ }
+ }
+
+ @Override
+ public NameAndTypeEntry clone(ConstantPoolBuilder cp) {
+ if (cp.canWriteDirect(constantPool)) {
+ return this;
+ } else {
+ var ret = (NameAndTypeEntryImpl)cp.nameAndTypeEntry(ref1, ref2);
+ ret.typeSym = typeSym;
+ return ret;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o instanceof NameAndTypeEntryImpl nat) {
+ return name().equals(nat.name()) && type().equals(nat.type());
+ }
+ return false;
+ }
+ }
+
+ public abstract static sealed class AbstractMemberRefEntry
+ extends AbstractRefsEntry
+ implements MemberRefEntry {
+
+ AbstractMemberRefEntry(ConstantPool cpm, int tag, int index, ClassEntryImpl owner,
+ NameAndTypeEntryImpl nameAndType) {
+ super(cpm, tag, index, owner, nameAndType);
+ }
+
+ @Override
+ public ClassEntryImpl owner() {
+ return ref1;
+ }
+
+ @Override
+ public NameAndTypeEntryImpl nameAndType() {
+ return ref2;
+ }
+
+ @Override
+ public String toString() {
+ return tag() + " " + owner().asInternalName() + "." + nameAndType().name().stringValue()
+ + "-" + nameAndType().type().stringValue();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof AbstractMemberRefEntry m) {
+ return tag == m.tag()
+ && owner().equals(m.owner())
+ && nameAndType().equals(m.nameAndType());
+ }
+ return false;
+ }
+ }
+
+ public static final class FieldRefEntryImpl extends AbstractMemberRefEntry implements FieldRefEntry {
+
+ FieldRefEntryImpl(ConstantPool cpm, int index,
+ ClassEntryImpl owner, NameAndTypeEntryImpl nameAndType) {
+ super(cpm, ClassFile.TAG_FIELDREF, index, owner, nameAndType);
+ }
+
+ @Override
+ public FieldRefEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.fieldRefEntry(ref1, ref2);
+ }
+ }
+
+ public static final class MethodRefEntryImpl extends AbstractMemberRefEntry implements MethodRefEntry {
+
+ MethodRefEntryImpl(ConstantPool cpm, int index,
+ ClassEntryImpl owner, NameAndTypeEntryImpl nameAndType) {
+ super(cpm, ClassFile.TAG_METHODREF, index, owner, nameAndType);
+ }
+
+ @Override
+ public MethodRefEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.methodRefEntry(ref1, ref2);
+ }
+ }
+
+ public static final class InterfaceMethodRefEntryImpl extends AbstractMemberRefEntry implements InterfaceMethodRefEntry {
+
+ InterfaceMethodRefEntryImpl(ConstantPool cpm, int index, ClassEntryImpl owner,
+ NameAndTypeEntryImpl nameAndType) {
+ super(cpm, ClassFile.TAG_INTERFACEMETHODREF, index, owner, nameAndType);
+ }
+
+ @Override
+ public InterfaceMethodRefEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.interfaceMethodRefEntry(ref1, ref2);
+ }
+ }
+
+ public abstract static sealed class AbstractDynamicConstantPoolEntry extends AbstractPoolEntry {
+
+ private final int bsmIndex;
+ private BootstrapMethodEntryImpl bootstrapMethod;
+ private final NameAndTypeEntryImpl nameAndType;
+
+ AbstractDynamicConstantPoolEntry(ConstantPool cpm, int tag, int index, int hash, BootstrapMethodEntryImpl bootstrapMethod,
+ NameAndTypeEntryImpl nameAndType) {
+ super(cpm, tag, index, hash);
+ this.bsmIndex = bootstrapMethod.bsmIndex();
+ this.bootstrapMethod = bootstrapMethod;
+ this.nameAndType = nameAndType;
+ }
+
+ AbstractDynamicConstantPoolEntry(ConstantPool cpm, int tag, int index, int hash, int bsmIndex,
+ NameAndTypeEntryImpl nameAndType) {
+ super(cpm, tag, index, hash);
+ this.bsmIndex = bsmIndex;
+ this.bootstrapMethod = null;
+ this.nameAndType = nameAndType;
+ }
+
+ /**
+ * @return the bootstrapMethod
+ */
+ public BootstrapMethodEntryImpl bootstrap() {
+ if (bootstrapMethod == null) {
+ bootstrapMethod = (BootstrapMethodEntryImpl) constantPool.bootstrapMethodEntry(bsmIndex);
+ }
+ return bootstrapMethod;
+ }
+
+ /**
+ * @return the bsmIndex
+ */
+ public int bootstrapMethodIndex() {
+ return bsmIndex;
+ }
+
+ /**
+ * @return the nameAndType
+ */
+ public NameAndTypeEntryImpl nameAndType() {
+ return nameAndType;
+ }
+
+ public void writeTo(BufWriter pool) {
+ pool.writeU1(tag);
+ pool.writeU2(bsmIndex);
+ pool.writeU2(nameAndType.index());
+ }
+
+ @Override
+ public String toString() {
+ return tag() + " " + bootstrap() + "." + nameAndType().name().stringValue()
+ + "-" + nameAndType().type().stringValue();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof AbstractDynamicConstantPoolEntry d) {
+ return this.tag() == d.tag()
+ && bootstrap().equals(d.bootstrap())
+ && nameAndType.equals(d.nameAndType());
+ }
+ return false;
+ }
+ }
+
+ public static final class InvokeDynamicEntryImpl
+ extends AbstractDynamicConstantPoolEntry
+ implements InvokeDynamicEntry {
+
+ InvokeDynamicEntryImpl(ConstantPool cpm, int index, int hash, BootstrapMethodEntryImpl bootstrapMethod,
+ NameAndTypeEntryImpl nameAndType) {
+ super(cpm, ClassFile.TAG_INVOKEDYNAMIC, index, hash, bootstrapMethod, nameAndType);
+ }
+
+ InvokeDynamicEntryImpl(ConstantPool cpm, int index, int bsmIndex,
+ NameAndTypeEntryImpl nameAndType) {
+ super(cpm, ClassFile.TAG_INVOKEDYNAMIC, index, hash2(ClassFile.TAG_INVOKEDYNAMIC, bsmIndex, nameAndType.index()),
+ bsmIndex, nameAndType);
+ }
+
+ @Override
+ public InvokeDynamicEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.invokeDynamicEntry(bootstrap(), nameAndType());
+ }
+ }
+
+ public static final class ConstantDynamicEntryImpl extends AbstractDynamicConstantPoolEntry
+ implements ConstantDynamicEntry {
+
+ ConstantDynamicEntryImpl(ConstantPool cpm, int index, int hash, BootstrapMethodEntryImpl bootstrapMethod,
+ NameAndTypeEntryImpl nameAndType) {
+ super(cpm, ClassFile.TAG_CONSTANTDYNAMIC, index, hash, bootstrapMethod, nameAndType);
+ }
+
+ ConstantDynamicEntryImpl(ConstantPool cpm, int index, int bsmIndex,
+ NameAndTypeEntryImpl nameAndType) {
+ super(cpm, ClassFile.TAG_CONSTANTDYNAMIC, index, hash2(ClassFile.TAG_CONSTANTDYNAMIC, bsmIndex, nameAndType.index()),
+ bsmIndex, nameAndType);
+ }
+
+ @Override
+ public ConstantDynamicEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.constantDynamicEntry(bootstrap(), nameAndType());
+ }
+ }
+
+ public static final class MethodHandleEntryImpl extends AbstractPoolEntry
+ implements MethodHandleEntry {
+
+ private final int refKind;
+ private final AbstractPoolEntry.AbstractMemberRefEntry reference;
+
+ MethodHandleEntryImpl(ConstantPool cpm, int index, int hash, int refKind, AbstractPoolEntry.AbstractMemberRefEntry
+ reference) {
+ super(cpm, ClassFile.TAG_METHODHANDLE, index, hash);
+ this.refKind = refKind;
+ this.reference = reference;
+ }
+
+ MethodHandleEntryImpl(ConstantPool cpm, int index, int refKind, AbstractPoolEntry.AbstractMemberRefEntry
+ reference) {
+ super(cpm, ClassFile.TAG_METHODHANDLE, index, hash2(ClassFile.TAG_METHODHANDLE, refKind, reference.index()));
+ this.refKind = refKind;
+ this.reference = reference;
+ }
+
+ @Override
+ public int kind() {
+ return refKind;
+ }
+
+ @Override
+ public AbstractPoolEntry.AbstractMemberRefEntry reference() {
+ return reference;
+ }
+
+ @Override
+ public DirectMethodHandleDesc asSymbol() {
+ return MethodHandleDesc.of(
+ DirectMethodHandleDesc.Kind.valueOf(kind(), reference() instanceof InterfaceMethodRefEntry),
+ ((MemberRefEntry) reference()).owner().asSymbol(),
+ ((MemberRefEntry) reference()).nameAndType().name().stringValue(),
+ ((MemberRefEntry) reference()).nameAndType().type().stringValue());
+ }
+
+ @Override
+ public void writeTo(BufWriter pool) {
+ pool.writeU1(tag);
+ pool.writeU1(refKind);
+ pool.writeU2(reference.index());
+ }
+
+ @Override
+ public MethodHandleEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.methodHandleEntry(refKind, reference);
+ }
+
+ @Override
+ public String toString() {
+ return tag() + " " + kind() + ":" + ((MemberRefEntry) reference()).owner().asInternalName() + "." + ((MemberRefEntry) reference()).nameAndType().name().stringValue()
+ + "-" + ((MemberRefEntry) reference()).nameAndType().type().stringValue();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof MethodHandleEntryImpl m) {
+ return kind() == m.kind()
+ && reference.equals(m.reference());
+ }
+ return false;
+ }
+ }
+
+ public static final class MethodTypeEntryImpl
+ extends AbstractRefEntry
+ implements MethodTypeEntry {
+
+ public MethodTypeDesc sym = null;
+
+ MethodTypeEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl descriptor) {
+ super(cpm, ClassFile.TAG_METHODTYPE, index, descriptor);
+ }
+
+ @Override
+ public Utf8Entry descriptor() {
+ return ref1;
+ }
+
+ @Override
+ public MethodTypeEntry clone(ConstantPoolBuilder cp) {
+ if (cp.canWriteDirect(constantPool)) {
+ return this;
+ } else {
+ var ret = (MethodTypeEntryImpl)cp.methodTypeEntry(ref1);
+ ret.sym = sym;
+ return ret;
+ }
+ }
+
+ @Override
+ public MethodTypeDesc asSymbol() {
+ var sym = this.sym;
+ if (sym != null) {
+ return sym;
+ }
+ return this.sym = MethodTypeDesc.ofDescriptor(descriptor().stringValue());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o instanceof MethodTypeEntryImpl m) {
+ return descriptor().equals(m.descriptor());
+ }
+ return false;
+ }
+ }
+
+ public static final class StringEntryImpl
+ extends AbstractRefEntry
+ implements StringEntry {
+
+ StringEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl utf8) {
+ super(cpm, ClassFile.TAG_STRING, index, utf8);
+ }
+
+ @Override
+ public Utf8EntryImpl utf8() {
+ return ref1;
+ }
+
+ @Override
+ public String stringValue() {
+ return ref1.toString();
+ }
+
+ @Override
+ public ConstantDesc constantValue() {
+ return stringValue();
+ }
+
+ @Override
+ public StringEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.stringEntry(ref1);
+ }
+
+ @Override
+ public String toString() {
+ return tag() + " \"" + stringValue() + "\"";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o instanceof StringEntryImpl s) {
+ // check utf8 rather allocating a string
+ return utf8().equals(s.utf8());
+ }
+ return false;
+ }
+
+
+ }
+
+ abstract static sealed class PrimitiveEntry
+ extends AbstractPoolEntry {
+ protected final T val;
+
+ public PrimitiveEntry(ConstantPool constantPool, int tag, int index, T val) {
+ super(constantPool, tag, index, hash1(tag, val.hashCode()));
+ this.val = val;
+ }
+
+ public T value() {
+ return val;
+ }
+
+ public ConstantDesc constantValue() {
+ return value();
+ }
+
+ @Override
+ public String toString() {
+ return "" + tag() + value();
+ }
+ }
+
+ public static final class IntegerEntryImpl extends PrimitiveEntry
+ implements IntegerEntry {
+
+ IntegerEntryImpl(ConstantPool cpm, int index, int i) {
+ super(cpm, ClassFile.TAG_INTEGER, index, i);
+ }
+
+ @Override
+ public void writeTo(BufWriter pool) {
+ pool.writeU1(tag);
+ pool.writeInt(val);
+ }
+
+ @Override
+ public IntegerEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.intEntry(val);
+ }
+
+ @Override
+ public int intValue() {
+ return value();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof IntegerEntryImpl e) {
+ return intValue() == e.intValue();
+ }
+ return false;
+ }
+ }
+
+ public static final class FloatEntryImpl extends PrimitiveEntry
+ implements FloatEntry {
+
+ FloatEntryImpl(ConstantPool cpm, int index, float f) {
+ super(cpm, ClassFile.TAG_FLOAT, index, f);
+ }
+
+ @Override
+ public void writeTo(BufWriter pool) {
+ pool.writeU1(tag);
+ pool.writeFloat(val);
+ }
+
+ @Override
+ public FloatEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.floatEntry(val);
+ }
+
+ @Override
+ public float floatValue() {
+ return value();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof FloatEntryImpl e) {
+ return floatValue() == e.floatValue();
+ }
+ return false;
+ }
+ }
+
+ public static final class LongEntryImpl extends PrimitiveEntry implements LongEntry {
+
+ LongEntryImpl(ConstantPool cpm, int index, long l) {
+ super(cpm, ClassFile.TAG_LONG, index, l);
+ }
+
+ @Override
+ public void writeTo(BufWriter pool) {
+ pool.writeU1(tag);
+ pool.writeLong(val);
+ }
+
+ @Override
+ public LongEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.longEntry(val);
+ }
+
+ @Override
+ public long longValue() {
+ return value();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof LongEntryImpl e) {
+ return longValue() == e.longValue();
+ }
+ return false;
+ }
+ }
+
+ public static final class DoubleEntryImpl extends PrimitiveEntry implements DoubleEntry {
+
+ DoubleEntryImpl(ConstantPool cpm, int index, double d) {
+ super(cpm, ClassFile.TAG_DOUBLE, index, d);
+ }
+
+ @Override
+ public void writeTo(BufWriter pool) {
+ pool.writeU1(tag);
+ pool.writeDouble(val);
+ }
+
+ @Override
+ public DoubleEntry clone(ConstantPoolBuilder cp) {
+ return cp.canWriteDirect(constantPool) ? this : cp.doubleEntry(val);
+ }
+
+ @Override
+ public double doubleValue() {
+ return value();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof DoubleEntryImpl e) {
+ return doubleValue() == e.doubleValue();
+ }
+ return false;
+ }
+ }
+
+ static class CpException extends RuntimeException {
+ static final long serialVersionUID = 32L;
+
+ CpException(String s) {
+ super(s);
+ }
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$AbstractLocalPseudo.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$AbstractLocalPseudo.class
new file mode 100644
index 00000000..945e42dd
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$AbstractLocalPseudo.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl.class
new file mode 100644
index 00000000..f556ffc5
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundCharacterRange.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundCharacterRange.class
new file mode 100644
index 00000000..e3b20fef
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundCharacterRange.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariable.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariable.class
new file mode 100644
index 00000000..8a464d8c
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariable.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariableType.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariableType.class
new file mode 100644
index 00000000..08684ee7
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariableType.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction.class
new file mode 100644
index 00000000..904b0201
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction.java
new file mode 100644
index 00000000..ffc36037
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.util.Optional;
+
+import java.lang.classfile.BufWriter;
+import java.lang.classfile.constantpool.ClassEntry;
+import java.lang.classfile.constantpool.Utf8Entry;
+import java.lang.classfile.instruction.CharacterRange;
+import java.lang.classfile.instruction.ExceptionCatch;
+import java.lang.classfile.instruction.LocalVariable;
+import java.lang.classfile.instruction.LocalVariableType;
+import java.lang.classfile.Label;
+import java.lang.classfile.PseudoInstruction;
+
+public abstract sealed class AbstractPseudoInstruction
+ extends AbstractElement
+ implements PseudoInstruction {
+
+ @Override
+ public abstract void writeTo(DirectCodeBuilder writer);
+
+ public static final class ExceptionCatchImpl
+ extends AbstractPseudoInstruction
+ implements ExceptionCatch {
+
+ public final ClassEntry catchTypeEntry;
+ public final Label handler;
+ public final Label tryStart;
+ public final Label tryEnd;
+
+ public ExceptionCatchImpl(Label handler, Label tryStart, Label tryEnd,
+ ClassEntry catchTypeEntry) {
+ this.catchTypeEntry = catchTypeEntry;
+ this.handler = handler;
+ this.tryStart = tryStart;
+ this.tryEnd = tryEnd;
+ }
+
+ public ExceptionCatchImpl(Label handler, Label tryStart, Label tryEnd,
+ Optional catchTypeEntry) {
+ this.catchTypeEntry = catchTypeEntry.orElse(null);
+ this.handler = handler;
+ this.tryStart = tryStart;
+ this.tryEnd = tryEnd;
+ }
+
+ @Override
+ public Label tryStart() {
+ return tryStart;
+ }
+
+ @Override
+ public Label handler() {
+ return handler;
+ }
+
+ @Override
+ public Label tryEnd() {
+ return tryEnd;
+ }
+
+ @Override
+ public Optional catchType() {
+ return Optional.ofNullable(catchTypeEntry);
+ }
+
+ ClassEntry catchTypeEntry() {
+ return catchTypeEntry;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.addHandler(this);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ExceptionCatch[catchType=%s]", catchTypeEntry == null ? "" : catchTypeEntry.name().stringValue());
+ }
+ }
+
+ public static final class UnboundCharacterRange
+ extends AbstractPseudoInstruction
+ implements CharacterRange {
+
+ public final Label startScope;
+ public final Label endScope;
+ public final int characterRangeStart;
+ public final int characterRangeEnd;
+ public final int flags;
+
+ public UnboundCharacterRange(Label startScope, Label endScope, int characterRangeStart,
+ int characterRangeEnd, int flags) {
+ this.startScope = startScope;
+ this.endScope = endScope;
+ this.characterRangeStart = characterRangeStart;
+ this.characterRangeEnd = characterRangeEnd;
+ this.flags = flags;
+ }
+
+ @Override
+ public Label startScope() {
+ return startScope;
+ }
+
+ @Override
+ public Label endScope() {
+ return endScope;
+ }
+
+ @Override
+ public int characterRangeStart() {
+ return characterRangeStart;
+ }
+
+ @Override
+ public int characterRangeEnd() {
+ return characterRangeEnd;
+ }
+
+ @Override
+ public int flags() {
+ return flags;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.addCharacterRange(this);
+ }
+
+ }
+
+ private abstract static sealed class AbstractLocalPseudo extends AbstractPseudoInstruction {
+ protected final int slot;
+ protected final Utf8Entry name;
+ protected final Utf8Entry descriptor;
+ protected final Label startScope;
+ protected final Label endScope;
+
+ public AbstractLocalPseudo(int slot, Utf8Entry name, Utf8Entry descriptor, Label startScope, Label endScope) {
+ this.slot = slot;
+ this.name = name;
+ this.descriptor = descriptor;
+ this.startScope = startScope;
+ this.endScope = endScope;
+ }
+
+ public int slot() {
+ return slot;
+ }
+
+ public Utf8Entry name() {
+ return name;
+ }
+
+ public String nameString() {
+ return name.stringValue();
+ }
+
+ public Label startScope() {
+ return startScope;
+ }
+
+ public Label endScope() {
+ return endScope;
+ }
+
+ public boolean writeTo(BufWriter b) {
+ var lc = ((BufWriterImpl)b).labelContext();
+ int startBci = lc.labelToBci(startScope());
+ int endBci = lc.labelToBci(endScope());
+ if (startBci == -1 || endBci == -1) {
+ return false;
+ }
+ int length = endBci - startBci;
+ b.writeU2(startBci);
+ b.writeU2(length);
+ b.writeIndex(name);
+ b.writeIndex(descriptor);
+ b.writeU2(slot());
+ return true;
+ }
+ }
+
+ public static final class UnboundLocalVariable extends AbstractLocalPseudo
+ implements LocalVariable {
+
+ public UnboundLocalVariable(int slot, Utf8Entry name, Utf8Entry descriptor, Label startScope, Label endScope) {
+ super(slot, name, descriptor, startScope, endScope);
+ }
+
+ @Override
+ public Utf8Entry type() {
+ return descriptor;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.addLocalVariable(this);
+ }
+
+ @Override
+ public String toString() {
+ return "LocalVariable[Slot=" + slot()
+ + ", name=" + nameString()
+ + ", descriptor='" + type().stringValue()
+ + "']";
+ }
+ }
+
+ public static final class UnboundLocalVariableType extends AbstractLocalPseudo
+ implements LocalVariableType {
+
+ public UnboundLocalVariableType(int slot, Utf8Entry name, Utf8Entry signature, Label startScope, Label endScope) {
+ super(slot, name, signature, startScope, endScope);
+ }
+
+ @Override
+ public Utf8Entry signature() {
+ return descriptor;
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder writer) {
+ writer.addLocalVariableType(this);
+ }
+
+ @Override
+ public String toString() {
+ return "LocalVariableType[Slot=" + slot()
+ + ", name=" + nameString()
+ + ", signature='" + signature().stringValue()
+ + "']";
+ }
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.class
new file mode 100644
index 00000000..d699314c
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.java
new file mode 100644
index 00000000..6aa046eb
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import java.lang.classfile.Attribute;
+import java.lang.classfile.AttributedElement;
+import java.lang.classfile.ClassFileElement;
+import java.lang.classfile.CompoundElement;
+
+public abstract sealed class AbstractUnboundModel
+ extends AbstractElement
+ implements CompoundElement, AttributedElement
+ permits BufferedCodeBuilder.Model, BufferedFieldBuilder.Model, BufferedMethodBuilder.Model {
+ private final List elements;
+ private List> attributes;
+
+ public AbstractUnboundModel(List elements) {
+ this.elements = elements;
+ }
+
+ @Override
+ public void forEachElement(Consumer consumer) {
+ elements.forEach(consumer);
+ }
+
+ @Override
+ public Stream elementStream() {
+ return elements.stream();
+ }
+
+ @Override
+ public List elementList() {
+ return elements;
+ }
+
+ @Override
+ public List> attributes() {
+ if (attributes == null)
+ attributes = elements.stream()
+ .filter(e -> e instanceof Attribute)
+ .>map(e -> (Attribute>) e)
+ .toList();
+ return attributes;
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AccessFlagsImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AccessFlagsImpl.class
new file mode 100644
index 00000000..ebf44ce1
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AccessFlagsImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AccessFlagsImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/AccessFlagsImpl.java
new file mode 100644
index 00000000..537110d2
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AccessFlagsImpl.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.util.Set;
+import java.lang.classfile.AccessFlags;
+import java.lang.reflect.AccessFlag;
+
+public final class AccessFlagsImpl extends AbstractElement
+ implements AccessFlags {
+
+ private final AccessFlag.Location location;
+ private final int flagsMask;
+ private Set flags;
+
+ public AccessFlagsImpl(AccessFlag.Location location, AccessFlag... flags) {
+ this.location = location;
+ this.flagsMask = Util.flagsToBits(location, flags);
+ this.flags = Set.of(flags);
+ }
+
+ public AccessFlagsImpl(AccessFlag.Location location, int mask) {
+ this.location = location;
+ this.flagsMask = mask;
+ }
+
+ @Override
+ public int flagsMask() {
+ return flagsMask;
+ }
+
+ @Override
+ public Set flags() {
+ if (flags == null)
+ flags = AccessFlag.maskToAccessFlags(flagsMask, location);
+ return flags;
+ }
+
+ @Override
+ public void writeTo(DirectClassBuilder builder) {
+ builder.setFlags(flagsMask);
+ }
+
+ @Override
+ public void writeTo(DirectMethodBuilder builder) {
+ builder.setFlags(flagsMask);
+ }
+
+ @Override
+ public void writeTo(DirectFieldBuilder builder) {
+ builder.setFlags(flagsMask);
+ }
+
+ @Override
+ public AccessFlag.Location location() {
+ return location;
+ }
+
+ @Override
+ public boolean has(AccessFlag flag) {
+ return Util.has(location, flagsMask, flag);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("AccessFlags[flags=%d]", flagsMask);
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$AnnotationElementImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$AnnotationElementImpl.class
new file mode 100644
index 00000000..fb35665e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$AnnotationElementImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfAnnotationImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfAnnotationImpl.class
new file mode 100644
index 00000000..637cac0b
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfAnnotationImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfArrayImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfArrayImpl.class
new file mode 100644
index 00000000..503b6662
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfArrayImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfBooleanImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfBooleanImpl.class
new file mode 100644
index 00000000..33b0b72c
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfBooleanImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfByteImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfByteImpl.class
new file mode 100644
index 00000000..ec08bb62
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfByteImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfCharacterImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfCharacterImpl.class
new file mode 100644
index 00000000..702e5264
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfCharacterImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfClassImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfClassImpl.class
new file mode 100644
index 00000000..8d980844
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfClassImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfConstantImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfConstantImpl.class
new file mode 100644
index 00000000..2dcbde85
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfConstantImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfDoubleImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfDoubleImpl.class
new file mode 100644
index 00000000..57f6ea2f
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfDoubleImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfEnumImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfEnumImpl.class
new file mode 100644
index 00000000..2855064f
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfEnumImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfFloatImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfFloatImpl.class
new file mode 100644
index 00000000..0907819c
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfFloatImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfIntegerImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfIntegerImpl.class
new file mode 100644
index 00000000..6f2b56c4
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfIntegerImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfLongImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfLongImpl.class
new file mode 100644
index 00000000..9ada7a08
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfLongImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfShortImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfShortImpl.class
new file mode 100644
index 00000000..b1f439b2
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfShortImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfStringImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfStringImpl.class
new file mode 100644
index 00000000..604df986
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfStringImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.class
new file mode 100644
index 00000000..f8fbaeca
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.java
new file mode 100644
index 00000000..4fc2d5cf
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.lang.classfile.*;
+import java.lang.classfile.constantpool.*;
+
+import java.lang.constant.ConstantDesc;
+import java.util.List;
+
+import static java.lang.classfile.ClassFile.*;
+
+public final class AnnotationImpl implements Annotation {
+ private final Utf8Entry className;
+ private final List elements;
+
+ public AnnotationImpl(Utf8Entry className,
+ List elems) {
+ this.className = className;
+ this.elements = List.copyOf(elems);
+ }
+
+ @Override
+ public Utf8Entry className() {
+ return className;
+ }
+
+ @Override
+ public List elements() {
+ return elements;
+ }
+
+ @Override
+ public void writeTo(BufWriter buf) {
+ buf.writeIndex(className());
+ buf.writeList(elements());
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("Annotation[");
+ sb.append(className().stringValue());
+ List evps = elements();
+ if (!evps.isEmpty())
+ sb.append(" [");
+ for (AnnotationElement evp : evps) {
+ sb.append(evp.name().stringValue())
+ .append("=")
+ .append(evp.value().toString())
+ .append(", ");
+ }
+ if (!evps.isEmpty()) {
+ sb.delete(sb.length()-1, sb.length());
+ sb.append("]");
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public record AnnotationElementImpl(Utf8Entry name,
+ AnnotationValue value)
+ implements AnnotationElement {
+
+ @Override
+ public void writeTo(BufWriter buf) {
+ buf.writeIndex(name());
+ value().writeTo(buf);
+ }
+ }
+
+ public sealed interface OfConstantImpl extends AnnotationValue.OfConstant
+ permits AnnotationImpl.OfStringImpl, AnnotationImpl.OfDoubleImpl,
+ AnnotationImpl.OfFloatImpl, AnnotationImpl.OfLongImpl,
+ AnnotationImpl.OfIntegerImpl, AnnotationImpl.OfShortImpl,
+ AnnotationImpl.OfCharacterImpl, AnnotationImpl.OfByteImpl,
+ AnnotationImpl.OfBooleanImpl {
+
+ @Override
+ default void writeTo(BufWriter buf) {
+ buf.writeU1(tag());
+ buf.writeIndex(constant());
+ }
+
+ @Override
+ default ConstantDesc constantValue() {
+ return constant().constantValue();
+ }
+
+ }
+
+ public record OfStringImpl(Utf8Entry constant)
+ implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfString {
+
+ @Override
+ public char tag() {
+ return AEV_STRING;
+ }
+
+ @Override
+ public String stringValue() {
+ return constant().stringValue();
+ }
+ }
+
+ public record OfDoubleImpl(DoubleEntry constant)
+ implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfDouble {
+
+ @Override
+ public char tag() {
+ return AEV_DOUBLE;
+ }
+
+ @Override
+ public double doubleValue() {
+ return constant().doubleValue();
+ }
+ }
+
+ public record OfFloatImpl(FloatEntry constant)
+ implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfFloat {
+
+ @Override
+ public char tag() {
+ return AEV_FLOAT;
+ }
+
+ @Override
+ public float floatValue() {
+ return constant().floatValue();
+ }
+ }
+
+ public record OfLongImpl(LongEntry constant)
+ implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfLong {
+
+ @Override
+ public char tag() {
+ return AEV_LONG;
+ }
+
+ @Override
+ public long longValue() {
+ return constant().longValue();
+ }
+ }
+
+ public record OfIntegerImpl(IntegerEntry constant)
+ implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfInteger {
+
+ @Override
+ public char tag() {
+ return AEV_INT;
+ }
+
+ @Override
+ public int intValue() {
+ return constant().intValue();
+ }
+ }
+
+ public record OfShortImpl(IntegerEntry constant)
+ implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfShort {
+
+ @Override
+ public char tag() {
+ return AEV_SHORT;
+ }
+
+ @Override
+ public short shortValue() {
+ return (short)constant().intValue();
+ }
+ }
+
+ public record OfCharacterImpl(IntegerEntry constant)
+ implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfCharacter {
+
+ @Override
+ public char tag() {
+ return AEV_CHAR;
+ }
+
+ @Override
+ public char charValue() {
+ return (char)constant().intValue();
+ }
+ }
+
+ public record OfByteImpl(IntegerEntry constant)
+ implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfByte {
+
+ @Override
+ public char tag() {
+ return AEV_BYTE;
+ }
+
+ @Override
+ public byte byteValue() {
+ return (byte)constant().intValue();
+ }
+ }
+
+ public record OfBooleanImpl(IntegerEntry constant)
+ implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfBoolean {
+
+ @Override
+ public char tag() {
+ return AEV_BOOLEAN;
+ }
+
+ @Override
+ public boolean booleanValue() {
+ return constant().intValue() == 1;
+ }
+ }
+
+ public record OfArrayImpl(List values)
+ implements AnnotationValue.OfArray {
+
+ public OfArrayImpl(List values) {
+ this.values = List.copyOf(values);
+ }
+
+ @Override
+ public char tag() {
+ return AEV_ARRAY;
+ }
+
+ @Override
+ public void writeTo(BufWriter buf) {
+ buf.writeU1(tag());
+ buf.writeList(values);
+ }
+
+ }
+
+ public record OfEnumImpl(Utf8Entry className, Utf8Entry constantName)
+ implements AnnotationValue.OfEnum {
+ @Override
+ public char tag() {
+ return AEV_ENUM;
+ }
+
+ @Override
+ public void writeTo(BufWriter buf) {
+ buf.writeU1(tag());
+ buf.writeIndex(className);
+ buf.writeIndex(constantName);
+ }
+
+ }
+
+ public record OfAnnotationImpl(Annotation annotation)
+ implements AnnotationValue.OfAnnotation {
+ @Override
+ public char tag() {
+ return AEV_ANNOTATION;
+ }
+
+ @Override
+ public void writeTo(BufWriter buf) {
+ buf.writeU1(tag());
+ annotation.writeTo(buf);
+ }
+
+ }
+
+ public record OfClassImpl(Utf8Entry className)
+ implements AnnotationValue.OfClass {
+ @Override
+ public char tag() {
+ return AEV_CLASS;
+ }
+
+ @Override
+ public void writeTo(BufWriter buf) {
+ buf.writeU1(tag());
+ buf.writeIndex(className);
+ }
+
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationReader.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationReader.class
new file mode 100644
index 00000000..b4033f0b
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationReader.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationReader.java b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationReader.java
new file mode 100644
index 00000000..c082878a
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationReader.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2022, 2024, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.classfile.impl;
+
+import java.lang.classfile.Annotation;
+import java.lang.classfile.AnnotationElement;
+import java.lang.classfile.AnnotationValue;
+import java.lang.classfile.ClassReader;
+import java.lang.classfile.constantpool.*;
+import java.lang.classfile.TypeAnnotation;
+import static java.lang.classfile.ClassFile.*;
+import static java.lang.classfile.TypeAnnotation.TargetInfo.*;
+
+import java.util.List;
+import java.lang.classfile.Label;
+import java.lang.classfile.constantpool.Utf8Entry;
+import jdk.internal.access.SharedSecrets;
+
+class AnnotationReader {
+ private AnnotationReader() { }
+
+ public static List readAnnotations(ClassReader classReader, int p) {
+ int pos = p;
+ int numAnnotations = classReader.readU2(pos);
+ var annos = new Object[numAnnotations];
+ pos += 2;
+ for (int i = 0; i < numAnnotations; ++i) {
+ annos[i] = readAnnotation(classReader, pos);
+ pos = skipAnnotation(classReader, pos);
+ }
+ return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(annos);
+ }
+
+ public static AnnotationValue readElementValue(ClassReader classReader, int p) {
+ char tag = (char) classReader.readU1(p);
+ ++p;
+ return switch (tag) {
+ case AEV_BYTE -> new AnnotationImpl.OfByteImpl(classReader.readEntry(p, IntegerEntry.class));
+ case AEV_CHAR -> new AnnotationImpl.OfCharacterImpl(classReader.readEntry(p, IntegerEntry.class));
+ case AEV_DOUBLE -> new AnnotationImpl.OfDoubleImpl(classReader.readEntry(p, DoubleEntry.class));
+ case AEV_FLOAT -> new AnnotationImpl.OfFloatImpl(classReader.readEntry(p, FloatEntry.class));
+ case AEV_INT -> new AnnotationImpl.OfIntegerImpl(classReader.readEntry(p, IntegerEntry.class));
+ case AEV_LONG -> new AnnotationImpl.OfLongImpl(classReader.readEntry(p, LongEntry.class));
+ case AEV_SHORT -> new AnnotationImpl.OfShortImpl(classReader.readEntry(p, IntegerEntry.class));
+ case AEV_BOOLEAN -> new AnnotationImpl.OfBooleanImpl(classReader.readEntry(p, IntegerEntry.class));
+ case AEV_STRING -> new AnnotationImpl.OfStringImpl(classReader.readUtf8Entry(p));
+ case AEV_ENUM -> new AnnotationImpl.OfEnumImpl(classReader.readUtf8Entry(p), classReader.readUtf8Entry(p + 2));
+ case AEV_CLASS -> new AnnotationImpl.OfClassImpl(classReader.readUtf8Entry(p));
+ case AEV_ANNOTATION -> new AnnotationImpl.OfAnnotationImpl(readAnnotation(classReader, p));
+ case AEV_ARRAY -> {
+ int numValues = classReader.readU2(p);
+ p += 2;
+ var values = new Object[numValues];
+ for (int i = 0; i < numValues; ++i) {
+ values[i] = readElementValue(classReader, p);
+ p = skipElementValue(classReader, p);
+ }
+ yield new AnnotationImpl.OfArrayImpl(SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(values));
+ }
+ default -> throw new IllegalArgumentException(
+ "Unexpected tag '%s' in AnnotationValue, pos = %d".formatted(tag, p - 1));
+ };
+ }
+
+ public static List readTypeAnnotations(ClassReader classReader, int p, LabelContext lc) {
+ int numTypeAnnotations = classReader.readU2(p);
+ p += 2;
+ var annotations = new Object[numTypeAnnotations];
+ for (int i = 0; i < numTypeAnnotations; ++i) {
+ annotations[i] = readTypeAnnotation(classReader, p, lc);
+ p = skipTypeAnnotation(classReader, p);
+ }
+ return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(annotations);
+ }
+
+ public static List> readParameterAnnotations(ClassReader classReader, int p) {
+ int cnt = classReader.readU1(p++);
+ var pas = new Object[cnt];
+ for (int i = 0; i < cnt; ++i) {
+ pas[i] = readAnnotations(classReader, p);
+ p = skipAnnotations(classReader, p);
+ }
+ return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(pas);
+ }
+
+ private static int skipElementValue(ClassReader classReader, int p) {
+ char tag = (char) classReader.readU1(p);
+ ++p;
+ return switch (tag) {
+ case 'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 's', 'c' -> p + 2;
+ case 'e' -> p + 4;
+ case '@' -> skipAnnotation(classReader, p);
+ case '[' -> {
+ int numValues = classReader.readU2(p);
+ p += 2;
+ for (int i = 0; i < numValues; ++i) {
+ p = skipElementValue(classReader, p);
+ }
+ yield p;
+ }
+ default -> throw new IllegalArgumentException(
+ "Unexpected tag '%s' in AnnotationValue, pos = %d".formatted(tag, p - 1));
+ };
+ }
+
+ private static Annotation readAnnotation(ClassReader classReader, int p) {
+ Utf8Entry annotationClass = classReader.entryByIndex(classReader.readU2(p), Utf8Entry.class);
+ p += 2;
+ List elems = readAnnotationElementValuePairs(classReader, p);
+ return new AnnotationImpl(annotationClass, elems);
+ }
+
+ private static int skipAnnotations(ClassReader classReader, int p) {
+ int numAnnotations = classReader.readU2(p);
+ p += 2;
+ for (int i = 0; i < numAnnotations; ++i)
+ p = skipAnnotation(classReader, p);
+ return p;
+ }
+
+ private static int skipAnnotation(ClassReader classReader, int p) {
+ return skipElementValuePairs(classReader, p + 2);
+ }
+
+ private static List readAnnotationElementValuePairs(ClassReader classReader, int p) {
+ int numElementValuePairs = classReader.readU2(p);
+ p += 2;
+ var annotationElements = new Object[numElementValuePairs];
+ for (int i = 0; i < numElementValuePairs; ++i) {
+ Utf8Entry elementName = classReader.readUtf8Entry(p);
+ p += 2;
+ AnnotationValue value = readElementValue(classReader, p);
+ annotationElements[i] = new AnnotationImpl.AnnotationElementImpl(elementName, value);
+ p = skipElementValue(classReader, p);
+ }
+ return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(annotationElements);
+ }
+
+ private static int skipElementValuePairs(ClassReader classReader, int p) {
+ int numElementValuePairs = classReader.readU2(p);
+ p += 2;
+ for (int i = 0; i < numElementValuePairs; ++i) {
+ p = skipElementValue(classReader, p + 2);
+ }
+ return p;
+ }
+
+ private static Label getLabel(LabelContext lc, int bciOffset, int targetType, int p) {
+ //helper method to avoid NPE
+ if (lc == null) throw new IllegalArgumentException("Unexpected targetType '%d' in TypeAnnotation outside of Code attribute, pos = %d".formatted(targetType, p - 1));
+ return lc.getLabel(bciOffset);
+ }
+
+ private static TypeAnnotation readTypeAnnotation(ClassReader classReader, int p, LabelContext lc) {
+ int targetType = classReader.readU1(p++);
+ var targetInfo = switch (targetType) {
+ case TAT_CLASS_TYPE_PARAMETER ->
+ ofClassTypeParameter(classReader.readU1(p));
+ case TAT_METHOD_TYPE_PARAMETER ->
+ ofMethodTypeParameter(classReader.readU1(p));
+ case TAT_CLASS_EXTENDS ->
+ ofClassExtends(classReader.readU2(p));
+ case TAT_CLASS_TYPE_PARAMETER_BOUND ->
+ ofClassTypeParameterBound(classReader.readU1(p), classReader.readU1(p + 1));
+ case TAT_METHOD_TYPE_PARAMETER_BOUND ->
+ ofMethodTypeParameterBound(classReader.readU1(p), classReader.readU1(p + 1));
+ case TAT_FIELD ->
+ ofField();
+ case TAT_METHOD_RETURN ->
+ ofMethodReturn();
+ case TAT_METHOD_RECEIVER ->
+ ofMethodReceiver();
+ case TAT_METHOD_FORMAL_PARAMETER ->
+ ofMethodFormalParameter(classReader.readU1(p));
+ case TAT_THROWS ->
+ ofThrows(classReader.readU2(p));
+ case TAT_LOCAL_VARIABLE ->
+ ofLocalVariable(readLocalVarEntries(classReader, p, lc, targetType));
+ case TAT_RESOURCE_VARIABLE ->
+ ofResourceVariable(readLocalVarEntries(classReader, p, lc, targetType));
+ case TAT_EXCEPTION_PARAMETER ->
+ ofExceptionParameter(classReader.readU2(p));
+ case TAT_INSTANCEOF ->
+ ofInstanceofExpr(getLabel(lc, classReader.readU2(p), targetType, p));
+ case TAT_NEW ->
+ ofNewExpr(getLabel(lc, classReader.readU2(p), targetType, p));
+ case TAT_CONSTRUCTOR_REFERENCE ->
+ ofConstructorReference(getLabel(lc, classReader.readU2(p), targetType, p));
+ case TAT_METHOD_REFERENCE ->
+ ofMethodReference(getLabel(lc, classReader.readU2(p), targetType, p));
+ case TAT_CAST ->
+ ofCastExpr(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2));
+ case TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ->
+ ofConstructorInvocationTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2));
+ case TAT_METHOD_INVOCATION_TYPE_ARGUMENT ->
+ ofMethodInvocationTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2));
+ case TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ->
+ ofConstructorReferenceTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2));
+ case TAT_METHOD_REFERENCE_TYPE_ARGUMENT ->
+ ofMethodReferenceTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2));
+ default ->
+ throw new IllegalArgumentException("Unexpected targetType '%d' in TypeAnnotation, pos = %d".formatted(targetType, p - 1));
+ };
+ p += targetInfo.size();
+ int pathLength = classReader.readU1(p++);
+ TypeAnnotation.TypePathComponent[] typePath = new TypeAnnotation.TypePathComponent[pathLength];
+ for (int i = 0; i < pathLength; ++i) {
+ int typePathKindTag = classReader.readU1(p++);
+ int typeArgumentIndex = classReader.readU1(p++);
+ typePath[i] = switch (typePathKindTag) {
+ case 0 -> TypeAnnotation.TypePathComponent.ARRAY;
+ case 1 -> TypeAnnotation.TypePathComponent.INNER_TYPE;
+ case 2 -> TypeAnnotation.TypePathComponent.WILDCARD;
+ case 3 -> new UnboundAttribute.TypePathComponentImpl(TypeAnnotation.TypePathComponent.Kind.TYPE_ARGUMENT, typeArgumentIndex);
+ default -> throw new IllegalArgumentException("Unknown type annotation path component kind: " + typePathKindTag);
+ };
+ }
+ // the annotation info for this annotation
+ Utf8Entry type = classReader.readUtf8Entry(p);
+ p += 2;
+ return TypeAnnotation.of(targetInfo, List.of(typePath), type,
+ readAnnotationElementValuePairs(classReader, p));
+ }
+
+ private static List readLocalVarEntries(ClassReader classReader, int p, LabelContext lc, int targetType) {
+ int tableLength = classReader.readU2(p);
+ p += 2;
+ var entries = new Object[tableLength];
+ for (int i = 0; i < tableLength; ++i) {
+ int startPc = classReader.readU2(p);
+ entries[i] = TypeAnnotation.LocalVarTargetInfo.of(
+ getLabel(lc, startPc, targetType, p),
+ getLabel(lc, startPc + classReader.readU2(p + 2), targetType, p - 2),
+ classReader.readU2(p + 4));
+ p += 6;
+ }
+ return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries);
+ }
+
+ private static int skipTypeAnnotation(ClassReader classReader, int p) {
+ int targetType = classReader.readU1(p++);
+ p += switch (targetType) {
+ case 0x13, 0x14, 0x15 -> 0;
+ case 0x00, 0x01, 0x16 -> 1;
+ case 0x10, 0x11, 0x12, 0x17, 0x42, 0x43, 0x44, 0x45, 0x46 -> 2;
+ case 0x47, 0x48, 0x49, 0x4A, 0x4B -> 3;
+ case 0x40, 0x41 -> 2 + classReader.readU2(p) * 6;
+ default -> throw new IllegalArgumentException(
+ "Unexpected targetType '%d' in TypeAnnotation, pos = %d".formatted(targetType, p - 1));
+ };
+ int pathLength = classReader.readU1(p++);
+ p += pathLength * 2;
+
+ // the annotation info for this annotation
+ p += 2;
+ p = skipElementValuePairs(classReader, p);
+ return p;
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AttributeHolder.class b/tests/test_data/std/jdk/internal/classfile/impl/AttributeHolder.class
new file mode 100644
index 00000000..a843194e
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/AttributeHolder.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AttributeHolder.java b/tests/test_data/std/jdk/internal/classfile/impl/AttributeHolder.java
new file mode 100644
index 00000000..be5176ad
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/AttributeHolder.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2022, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import java.lang.classfile.Attribute;
+import java.lang.classfile.AttributeMapper;
+import java.lang.classfile.BufWriter;
+
+public class AttributeHolder {
+ private final List> attributes = new ArrayList<>();
+
+ public > void withAttribute(Attribute> a) {
+ if (a == null)
+ return;
+
+ @SuppressWarnings("unchecked")
+ AttributeMapper am = (AttributeMapper) a.attributeMapper();
+ if (!am.allowMultiple() && isPresent(am)) {
+ remove(am);
+ }
+ attributes.add(a);
+ }
+
+ public int size() {
+ return attributes.size();
+ }
+
+ public void writeTo(BufWriter buf) {
+ buf.writeU2(attributes.size());
+ for (Attribute> a : attributes)
+ a.writeTo(buf);
+ }
+
+ boolean isPresent(AttributeMapper> am) {
+ for (Attribute> a : attributes)
+ if (a.attributeMapper() == am)
+ return true;
+ return false;
+ }
+
+ private void remove(AttributeMapper> am) {
+ attributes.removeIf(a -> a.attributeMapper() == am);
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.class
new file mode 100644
index 00000000..8eb8cd0f
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java
new file mode 100644
index 00000000..66e974b4
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2022, 2024, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.lang.classfile.CodeBuilder;
+import java.lang.classfile.CodeElement;
+import java.lang.classfile.Label;
+import java.lang.classfile.TypeKind;
+import java.lang.classfile.instruction.LabelTarget;
+
+import java.util.Objects;
+import java.lang.classfile.Instruction;
+
+public final class BlockCodeBuilderImpl
+ extends NonterminalCodeBuilder
+ implements CodeBuilder.BlockCodeBuilder {
+ private final Label startLabel, endLabel, breakLabel;
+ private boolean reachable = true;
+ private boolean hasInstructions = false;
+ private int topLocal;
+ private int terminalMaxLocals;
+
+ public BlockCodeBuilderImpl(CodeBuilder parent, Label breakLabel) {
+ super(parent);
+ this.startLabel = parent.newLabel();
+ this.endLabel = parent.newLabel();
+ this.breakLabel = Objects.requireNonNull(breakLabel);
+ }
+
+ public void start() {
+ topLocal = topLocal(parent);
+ terminalMaxLocals = terminal.curTopLocal();
+ parent.with((LabelTarget) startLabel);
+ }
+
+ public void end() {
+ parent.with((LabelTarget) endLabel);
+ if (terminalMaxLocals != terminal.curTopLocal()) {
+ throw new IllegalStateException("Interference in local variable slot management");
+ }
+ }
+
+ public boolean reachable() {
+ return reachable;
+ }
+
+ public boolean isEmpty() {
+ return !hasInstructions;
+ }
+
+ private int topLocal(CodeBuilder parent) {
+ return switch (parent) {
+ case BlockCodeBuilderImpl b -> b.topLocal;
+ case ChainedCodeBuilder b -> b.terminal.curTopLocal();
+ case TerminalCodeBuilder b -> b.curTopLocal();
+ };
+ }
+
+ @Override
+ public CodeBuilder with(CodeElement element) {
+ parent.with(element);
+
+ hasInstructions |= element instanceof Instruction;
+
+ if (reachable) {
+ if (element instanceof Instruction i && i.opcode().isUnconditionalBranch())
+ reachable = false;
+ }
+ else if (element instanceof LabelTarget) {
+ reachable = true;
+ }
+ return this;
+ }
+
+ @Override
+ public Label startLabel() {
+ return startLabel;
+ }
+
+ @Override
+ public Label endLabel() {
+ return endLabel;
+ }
+
+ @Override
+ public int allocateLocal(TypeKind typeKind) {
+ int retVal = topLocal;
+ topLocal += typeKind.slotSize();
+ return retVal;
+ }
+
+ @Override
+ public Label breakLabel() {
+ return breakLabel;
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.class
new file mode 100644
index 00000000..da954d19
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java
new file mode 100644
index 00000000..d6876a82
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2022, 2024, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.classfile.impl;
+
+import java.util.List;
+
+import java.lang.classfile.constantpool.ConstantPool;
+import java.lang.classfile.BootstrapMethodEntry;
+import java.lang.classfile.BufWriter;
+import java.lang.classfile.constantpool.LoadableConstantEntry;
+import java.lang.classfile.constantpool.MethodHandleEntry;
+
+import static jdk.internal.classfile.impl.AbstractPoolEntry.MethodHandleEntryImpl;
+
+public final class BootstrapMethodEntryImpl implements BootstrapMethodEntry {
+
+ final int index;
+ final int hash;
+ private final ConstantPool constantPool;
+ private final MethodHandleEntryImpl handle;
+ private final List arguments;
+
+ BootstrapMethodEntryImpl(ConstantPool constantPool, int bsmIndex, int hash,
+ MethodHandleEntryImpl handle,
+ List arguments) {
+ this.index = bsmIndex;
+ this.hash = hash;
+ this.constantPool = constantPool;
+ this.handle = handle;
+ this.arguments = List.copyOf(arguments);
+ }
+
+ @Override
+ public ConstantPool constantPool() {
+ return constantPool;
+ }
+
+ @Override
+ public MethodHandleEntry bootstrapMethod() {
+ return handle;
+ }
+
+ @Override
+ public List arguments() {
+ return arguments;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof BootstrapMethodEntry e
+ && e.bootstrapMethod().equals(handle)
+ && e.arguments().equals(arguments);
+ }
+
+ static int computeHashCode(MethodHandleEntryImpl handle,
+ List extends LoadableConstantEntry> arguments) {
+ return (31 * handle.hashCode() + arguments.hashCode()) | AbstractPoolEntry.NON_ZERO;
+ }
+
+ @Override
+ public int bsmIndex() { return index; }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+
+ @Override
+ public void writeTo(BufWriter writer) {
+ writer.writeIndex(bootstrapMethod());
+ writer.writeListIndices(arguments());
+ }
+}
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$1.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$1.class
new file mode 100644
index 00000000..26a08d40
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$1.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundAnnotationDefaultAttr.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundAnnotationDefaultAttr.class
new file mode 100644
index 00000000..b2fa13ed
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundAnnotationDefaultAttr.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundBootstrapMethodsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundBootstrapMethodsAttribute.class
new file mode 100644
index 00000000..70feb2d0
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundBootstrapMethodsAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCharacterRangeTableAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCharacterRangeTableAttribute.class
new file mode 100644
index 00000000..79946161
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCharacterRangeTableAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCodeAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCodeAttribute.class
new file mode 100644
index 00000000..65331423
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCodeAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCompilationIDAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCompilationIDAttribute.class
new file mode 100644
index 00000000..b02ac40b
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCompilationIDAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundConstantValueAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundConstantValueAttribute.class
new file mode 100644
index 00000000..3e1df984
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundConstantValueAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundDeprecatedAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundDeprecatedAttribute.class
new file mode 100644
index 00000000..27777aef
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundDeprecatedAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundEnclosingMethodAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundEnclosingMethodAttribute.class
new file mode 100644
index 00000000..cdc79927
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundEnclosingMethodAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundExceptionsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundExceptionsAttribute.class
new file mode 100644
index 00000000..d7a32535
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundExceptionsAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundInnerClassesAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundInnerClassesAttribute.class
new file mode 100644
index 00000000..2734764f
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundInnerClassesAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLineNumberTableAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLineNumberTableAttribute.class
new file mode 100644
index 00000000..7ae63126
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLineNumberTableAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLocalVariableTableAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLocalVariableTableAttribute.class
new file mode 100644
index 00000000..5fe49acd
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLocalVariableTableAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLocalVariableTypeTableAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLocalVariableTypeTableAttribute.class
new file mode 100644
index 00000000..aa120925
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLocalVariableTypeTableAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundMethodParametersAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundMethodParametersAttribute.class
new file mode 100644
index 00000000..99037df0
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundMethodParametersAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleAttribute.class
new file mode 100644
index 00000000..233fed31
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleHashesAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleHashesAttribute.class
new file mode 100644
index 00000000..7b9b5d9c
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleHashesAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleMainClassAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleMainClassAttribute.class
new file mode 100644
index 00000000..e1947927
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleMainClassAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModulePackagesAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModulePackagesAttribute.class
new file mode 100644
index 00000000..643fcfa8
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModulePackagesAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleResolutionAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleResolutionAttribute.class
new file mode 100644
index 00000000..886f9d0b
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleResolutionAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleTargetAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleTargetAttribute.class
new file mode 100644
index 00000000..36aa8d61
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleTargetAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundNestHostAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundNestHostAttribute.class
new file mode 100644
index 00000000..819e1bc1
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundNestHostAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundNestMembersAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundNestMembersAttribute.class
new file mode 100644
index 00000000..b243244c
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundNestMembersAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundPermittedSubclassesAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundPermittedSubclassesAttribute.class
new file mode 100644
index 00000000..ee373072
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundPermittedSubclassesAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRecordAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRecordAttribute.class
new file mode 100644
index 00000000..7a7eea7f
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRecordAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleAnnotationsAttribute.class
new file mode 100644
index 00000000..a1ff16e3
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleAnnotationsAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleParameterAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleParameterAnnotationsAttribute.class
new file mode 100644
index 00000000..0a324591
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleParameterAnnotationsAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleTypeAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleTypeAnnotationsAttribute.class
new file mode 100644
index 00000000..ecb528d6
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleTypeAnnotationsAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleAnnotationsAttribute.class
new file mode 100644
index 00000000..157988e0
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleAnnotationsAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleParameterAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleParameterAnnotationsAttribute.class
new file mode 100644
index 00000000..cabdedb1
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleParameterAnnotationsAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleTypeAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleTypeAnnotationsAttribute.class
new file mode 100644
index 00000000..5499f796
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleTypeAnnotationsAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSignatureAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSignatureAttribute.class
new file mode 100644
index 00000000..0847d208
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSignatureAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceDebugExtensionAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceDebugExtensionAttribute.class
new file mode 100644
index 00000000..4e0530c2
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceDebugExtensionAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceFileAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceFileAttribute.class
new file mode 100644
index 00000000..2026d131
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceFileAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceIDAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceIDAttribute.class
new file mode 100644
index 00000000..6767873a
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceIDAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundStackMapTableAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundStackMapTableAttribute.class
new file mode 100644
index 00000000..94d0cd00
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundStackMapTableAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSyntheticAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSyntheticAttribute.class
new file mode 100644
index 00000000..60c2a32c
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSyntheticAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundUnknownAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundUnknownAttribute.class
new file mode 100644
index 00000000..6d3cc577
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundUnknownAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute.class
new file mode 100644
index 00000000..c7dcec75
Binary files /dev/null and b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute.class differ
diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute.java b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute.java
new file mode 100644
index 00000000..6fea4e44
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute.java
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (c) 2022, 2024, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.classfile.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+
+import java.lang.classfile.*;
+import java.lang.classfile.attribute.*;
+import java.lang.classfile.constantpool.ClassEntry;
+import java.lang.classfile.constantpool.ConstantPool;
+import java.lang.classfile.constantpool.ConstantValueEntry;
+import java.lang.classfile.constantpool.LoadableConstantEntry;
+import java.lang.classfile.constantpool.ModuleEntry;
+import java.lang.classfile.constantpool.NameAndTypeEntry;
+import java.lang.classfile.constantpool.PackageEntry;
+import java.lang.classfile.constantpool.Utf8Entry;
+import jdk.internal.access.SharedSecrets;
+
+import static java.lang.classfile.Attributes.*;
+
+public abstract sealed class BoundAttribute>
+ extends AbstractElement
+ implements Attribute {
+
+ static final int NAME_AND_LENGTH_PREFIX = 6;
+ private final AttributeMapper mapper;
+ final ClassReaderImpl classReader;
+ final int payloadStart;
+
+ BoundAttribute(ClassReader classReader, AttributeMapper mapper, int payloadStart) {
+ this.mapper = mapper;
+ this.classReader = (ClassReaderImpl)classReader;
+ this.payloadStart = payloadStart;
+ }
+
+ public int payloadLen() {
+ return classReader.readInt(payloadStart - 4);
+ }
+
+ @Override
+ public String attributeName() {
+ return mapper.name();
+ }
+
+ @Override
+ public AttributeMapper attributeMapper() {
+ return mapper;
+ }
+
+ public byte[] contents() {
+ return classReader.readBytes(payloadStart, payloadLen());
+ }
+
+ @Override
+ public void writeTo(DirectClassBuilder builder) {
+ builder.writeAttribute(this);
+ }
+
+ @Override
+ public void writeTo(DirectCodeBuilder builder) {
+ builder.writeAttribute(this);
+ }
+
+ @Override
+ public void writeTo(DirectMethodBuilder builder) {
+ builder.writeAttribute(this);
+ }
+
+ @Override
+ public void writeTo(DirectFieldBuilder builder) {
+ builder.writeAttribute(this);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void writeTo(BufWriter buf) {
+ if (!buf.canWriteDirect(classReader))
+ attributeMapper().writeAttribute(buf, (T) this);
+ else
+ classReader.copyBytesTo(buf, payloadStart - NAME_AND_LENGTH_PREFIX, payloadLen() + NAME_AND_LENGTH_PREFIX);
+ }
+
+ public ConstantPool constantPool() {
+ return classReader;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Attribute[name=%s]", mapper.name());
+ }
+
+ List readEntryList(int p) {
+ int cnt = classReader.readU2(p);
+ p += 2;
+ var entries = new Object[cnt];
+ int end = p + (cnt * 2);
+ for (int i = 0; p < end; i++, p += 2) {
+ entries[i] = classReader.readEntry(p);
+ }
+ return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries);
+ }
+
+ public static List> readAttributes(AttributedElement enclosing, ClassReader reader, int pos,
+ Function> customAttributes) {
+ int size = reader.readU2(pos);
+ var filled = new ArrayList>(size);
+ int p = pos + 2;
+ int cfLen = reader.classfileLength();
+ var apo = ((ClassReaderImpl)reader).context().attributesProcessingOption();
+ for (int i = 0; i < size; ++i) {
+ Utf8Entry name = reader.readUtf8Entry(p);
+ int len = reader.readInt(p + 2);
+ p += 6;
+ if (len < 0 || len > cfLen - p) {
+ throw new IllegalArgumentException("attribute " + name.stringValue() + " too big to handle");
+ }
+
+ var mapper = standardAttribute(name);
+ if (mapper == null) {
+ mapper = customAttributes.apply(name);
+ }
+ if (mapper != null) {
+ filled.add((Attribute)mapper.readAttribute(enclosing, reader, p));
+ } else {
+ AttributeMapper fakeMapper = new AttributeMapper<>() {
+ @Override
+ public String name() {
+ return name.stringValue();
+ }
+
+ @Override
+ public UnknownAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) {
+ // Will never get called
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void writeAttribute(BufWriter buf, UnknownAttribute attr) {
+ buf.writeIndex(name);
+ var cont = attr.contents();
+ buf.writeInt(cont.length);
+ buf.writeBytes(cont);
+ }
+
+ @Override
+ public boolean allowMultiple() {
+ return true;
+ }
+
+ @Override
+ public AttributeMapper.AttributeStability stability() {
+ return AttributeStability.UNKNOWN;
+ }
+ };
+ filled.add(new BoundUnknownAttribute(reader, fakeMapper, p));
+ }
+ p += len;
+ }
+ return Collections.unmodifiableList(filled);
+ }
+
+ public static final class BoundUnknownAttribute extends BoundAttribute
+ implements UnknownAttribute {
+ public BoundUnknownAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+ }
+
+ public static final class BoundStackMapTableAttribute
+ extends BoundAttribute
+ implements StackMapTableAttribute {
+ final MethodModel method;
+ final LabelContext ctx;
+ List entries = null;
+
+ public BoundStackMapTableAttribute(CodeImpl code, ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ method = code.parent().orElseThrow();
+ ctx = code;
+ }
+
+ @Override
+ public List entries() {
+ if (entries == null) {
+ entries = new StackMapDecoder(classReader, payloadStart, ctx, StackMapDecoder.initFrameLocals(method)).entries();
+ }
+ return entries;
+ }
+ }
+
+ public static final class BoundSyntheticAttribute extends BoundAttribute
+ implements SyntheticAttribute {
+ public BoundSyntheticAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+ }
+
+ public static final class BoundLineNumberTableAttribute
+ extends BoundAttribute
+ implements LineNumberTableAttribute {
+ private List lineNumbers = null;
+
+ public BoundLineNumberTableAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public List lineNumbers() {
+ if (lineNumbers == null) {
+ int nLn = classReader.readU2(payloadStart);
+ LineNumberInfo[] elements = new LineNumberInfo[nLn];
+ int p = payloadStart + 2;
+ int pEnd = p + (nLn * 4);
+ for (int i = 0; p < pEnd; p += 4, i++) {
+ int startPc = classReader.readU2(p);
+ int lineNumber = classReader.readU2(p + 2);
+ elements[i] = LineNumberInfo.of(startPc, lineNumber);
+ }
+ lineNumbers = List.of(elements);
+ }
+ return lineNumbers;
+ }
+ }
+
+ public static final class BoundCharacterRangeTableAttribute extends BoundAttribute implements CharacterRangeTableAttribute {
+ private List characterRangeTable = null;
+
+ public BoundCharacterRangeTableAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public List characterRangeTable() {
+ if (characterRangeTable == null) {
+ int nLn = classReader.readU2(payloadStart);
+ CharacterRangeInfo[] elements = new CharacterRangeInfo[nLn];
+ int p = payloadStart + 2;
+ int pEnd = p + (nLn * 14);
+ for (int i = 0; p < pEnd; p += 14, i++) {
+ int startPc = classReader.readU2(p);
+ int endPc = classReader.readU2(p + 2);
+ int characterRangeStart = classReader.readInt(p + 4);
+ int characterRangeEnd = classReader.readInt(p + 8);
+ int flags = classReader.readU2(p + 12);
+ elements[i] = CharacterRangeInfo.of(startPc, endPc, characterRangeStart, characterRangeEnd, flags);
+ }
+ characterRangeTable = List.of(elements);
+ }
+ return characterRangeTable;
+ }
+ }
+
+ public static final class BoundLocalVariableTableAttribute
+ extends BoundAttribute
+ implements LocalVariableTableAttribute {
+ private final CodeImpl codeAttribute;
+ private List localVars = null;
+
+ public BoundLocalVariableTableAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ codeAttribute = (CodeImpl) enclosing;
+ }
+
+ @Override
+ public List localVariables() {
+ if (localVars == null) {
+ int cnt = classReader.readU2(payloadStart);
+ BoundLocalVariable[] elements = new BoundLocalVariable[cnt];
+ int p = payloadStart + 2;
+ int pEnd = p + (cnt * 10);
+ for (int i = 0; p < pEnd; p += 10, i++) {
+ elements[i] = new BoundLocalVariable(codeAttribute, p);
+ }
+ localVars = List.of(elements);
+ }
+ return localVars;
+ }
+ }
+
+ public static final class BoundLocalVariableTypeTableAttribute
+ extends BoundAttribute
+ implements LocalVariableTypeTableAttribute {
+ private final CodeImpl codeAttribute;
+ private List localVars = null;
+
+ public BoundLocalVariableTypeTableAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ this.codeAttribute = (CodeImpl) enclosing;
+ }
+
+ @Override
+ public List localVariableTypes() {
+ if (localVars == null) {
+ final int cnt = classReader.readU2(payloadStart);
+ BoundLocalVariableType[] elements = new BoundLocalVariableType[cnt];
+ int p = payloadStart + 2;
+ int pEnd = p + (cnt * 10);
+ for (int i = 0; p < pEnd; p += 10, i++) {
+ elements[i] = new BoundLocalVariableType(codeAttribute, p);
+ }
+ localVars = List.of(elements);
+ }
+ return localVars;
+ }
+ }
+
+ public static final class BoundMethodParametersAttribute extends BoundAttribute
+ implements MethodParametersAttribute {
+ private List parameters = null;
+
+ public BoundMethodParametersAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public List parameters() {
+ if (parameters == null) {
+ final int cnt = classReader.readU1(payloadStart);
+ MethodParameterInfo[] elements = new MethodParameterInfo[cnt];
+ int p = payloadStart + 1;
+ int pEnd = p + (cnt * 4);
+ for (int i = 0; p < pEnd; p += 4, i++) {
+ Utf8Entry name = classReader.readUtf8EntryOrNull(p);
+ int accessFlags = classReader.readU2(p + 2);
+ elements[i] = MethodParameterInfo.of(Optional.ofNullable(name), accessFlags);
+ }
+ parameters = List.of(elements);
+ }
+ return parameters;
+ }
+ }
+
+ public static final class BoundModuleHashesAttribute extends BoundAttribute
+ implements ModuleHashesAttribute {
+ private List hashes = null;
+
+ public BoundModuleHashesAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public Utf8Entry algorithm() {
+ return classReader.readUtf8Entry(payloadStart);
+ }
+
+ @Override
+ public List hashes() {
+ if (hashes == null) {
+ final int cnt = classReader.readU2(payloadStart + 2);
+ ModuleHashInfo[] elements = new ModuleHashInfo[cnt];
+ int p = payloadStart + 4;
+ //System.err.printf("%5d: ModuleHashesAttr alg = %s, cnt = %d%n", pos, algorithm(), cnt);
+ for (int i = 0; i < cnt; ++i) {
+ ModuleEntry module = classReader.readModuleEntry(p);
+ int hashLength = classReader.readU2(p + 2);
+ //System.err.printf("%5d: [%d] module = %s, hashLength = %d%n", p, i, module, hashLength);
+ p += 4;
+ elements[i] = ModuleHashInfo.of(module, classReader.readBytes(p, hashLength));
+ p += hashLength;
+ }
+ hashes = List.of(elements);
+ }
+ return hashes;
+ }
+ }
+
+ public static final class BoundRecordAttribute extends BoundAttribute
+ implements RecordAttribute {
+ private List components = null;
+
+ public BoundRecordAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public List components() {
+ if (components == null) {
+ final int cnt = classReader.readU2(payloadStart);
+ RecordComponentInfo[] elements = new RecordComponentInfo[cnt];
+ int p = payloadStart + 2;
+ for (int i = 0; i < cnt; i++) {
+ elements[i] = new BoundRecordComponentInfo(classReader, p);
+ p = classReader.skipAttributeHolder(p + 4);
+ }
+ components = List.of(elements);
+ }
+ return components;
+ }
+ }
+
+ public static final class BoundDeprecatedAttribute extends BoundAttribute
+ implements DeprecatedAttribute {
+ public BoundDeprecatedAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+ }
+
+ public static final class BoundSignatureAttribute extends BoundAttribute
+ implements SignatureAttribute {
+ public BoundSignatureAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public Utf8Entry signature() {
+ return classReader.readUtf8Entry(payloadStart);
+ }
+ }
+
+ public static final class BoundSourceFileAttribute extends BoundAttribute
+ implements SourceFileAttribute {
+ public BoundSourceFileAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public Utf8Entry sourceFile() {
+ return classReader.readUtf8Entry(payloadStart);
+ }
+
+ }
+
+ public static final class BoundModuleMainClassAttribute extends BoundAttribute implements ModuleMainClassAttribute {
+ public BoundModuleMainClassAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public ClassEntry mainClass() {
+ return classReader.readClassEntry(payloadStart);
+ }
+ }
+
+ public static final class BoundNestHostAttribute extends BoundAttribute
+ implements NestHostAttribute {
+ public BoundNestHostAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public ClassEntry nestHost() {
+ return classReader.readClassEntry(payloadStart);
+ }
+ }
+
+ public static final class BoundSourceDebugExtensionAttribute extends BoundAttribute
+ implements SourceDebugExtensionAttribute {
+ public BoundSourceDebugExtensionAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+ }
+
+ public static final class BoundConstantValueAttribute extends BoundAttribute
+ implements ConstantValueAttribute {
+ public BoundConstantValueAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public ConstantValueEntry constant() {
+ return classReader.readEntry(payloadStart, ConstantValueEntry.class);
+ }
+
+ }
+
+ public static final class BoundModuleTargetAttribute extends BoundAttribute
+ implements ModuleTargetAttribute {
+ public BoundModuleTargetAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public Utf8Entry targetPlatform() {
+ return classReader.readUtf8Entry(payloadStart);
+ }
+ }
+
+ public static final class BoundCompilationIDAttribute extends BoundAttribute
+ implements CompilationIDAttribute {
+ public BoundCompilationIDAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public Utf8Entry compilationId() {
+ return classReader.readUtf8Entry(payloadStart);
+ }
+ }
+
+ public static final class BoundSourceIDAttribute extends BoundAttribute
+ implements SourceIDAttribute {
+ public BoundSourceIDAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public Utf8Entry sourceId() {
+ return classReader.readUtf8Entry(payloadStart);
+ }
+ }
+
+ public static final class BoundModuleResolutionAttribute extends BoundAttribute
+ implements ModuleResolutionAttribute {
+ public BoundModuleResolutionAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public int resolutionFlags() {
+ return classReader.readU2(payloadStart);
+ }
+ }
+
+ public static final class BoundExceptionsAttribute extends BoundAttribute
+ implements ExceptionsAttribute {
+ private List exceptions = null;
+
+ public BoundExceptionsAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public List exceptions() {
+ if (exceptions == null) {
+ exceptions = readEntryList(payloadStart);
+ }
+ return exceptions;
+ }
+ }
+
+ public static final class BoundModuleAttribute extends BoundAttribute
+ implements ModuleAttribute {
+ private List requires = null;
+ private List exports = null;
+ private List opens = null;
+ private List uses = null;
+ private List provides = null;
+
+ public BoundModuleAttribute(ClassReader cf, AttributeMapper mapper, int pos) {
+ super(cf, mapper, pos);
+ }
+
+ @Override
+ public ModuleEntry moduleName() {
+ return classReader.readModuleEntry(payloadStart);
+ }
+
+ @Override
+ public int moduleFlagsMask() {
+ return classReader.readU2(payloadStart + 2);
+ }
+
+ @Override
+ public Optional