Skip to content

Commit

Permalink
Merge pull request #12161 from ChengJin01/jep397_sealed_classes_secon…
Browse files Browse the repository at this point in the history
…d_preview_v0.25.0_release

[v0.25.0] Reinforce the check on the sealed classes in JEP397
  • Loading branch information
pshipton authored Mar 9, 2021
2 parents 0283464 + 40f5bda commit 022d654
Show file tree
Hide file tree
Showing 23 changed files with 859 additions and 2 deletions.
20 changes: 19 additions & 1 deletion runtime/nls/j9vm/j9vm.nls
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2000, 2020 IBM Corp. and others
# Copyright (c) 2000, 2021 IBM Corp. and others
#
# This program and the accompanying materials are made available under
# the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -2010,3 +2010,21 @@ J9NLS_VM_ERROR_BYTECODE_OBJECTREF_CANNOT_BE_VALUE_BASED.explanation=The class ha
J9NLS_VM_ERROR_BYTECODE_OBJECTREF_CANNOT_BE_VALUE_BASED.system_action=The JVM will throw an VirtualMachineError.
J9NLS_VM_ERROR_BYTECODE_OBJECTREF_CANNOT_BE_VALUE_BASED.user_response=Contact the provider of the classfile for a corrected version.
# END NON-TRANSLATABLE

# Message to use when class/interface is not in the same module as its sealed super class/interface
# argument 1 is the class name
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_MODULE=The class/interface %2$.*1$s is not in the same module as its sealed super class/interface.
# START NON-TRANSLATABLE
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_MODULE.explanation=The specified class must be in the same module as its sealed super class/interface.
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_MODULE.system_action=The JVM will throw an IncompatibleClassChangeError.
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_MODULE.user_response=Contact the provider of the classfile for a corrected version.
# END NON-TRANSLATABLE

# Message to use when non-public class/interface is not in the same package as its sealed super class/interface
# argument 1 is the class name
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_PACKAGE=The non-public class/interface %2$.*1$s is not in the same package as its sealed super class/interface.
# START NON-TRANSLATABLE
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_PACKAGE.explanation=The specified non-public class must be in the same package as its sealed super class/interface.
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_PACKAGE.system_action=The JVM will throw an IncompatibleClassChangeError.
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_PACKAGE.user_response=Contact the provider of the classfile for a corrected version.
# END NON-TRANSLATABLE
60 changes: 60 additions & 0 deletions runtime/vm/createramclass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1614,6 +1614,48 @@ isClassPermittedBySealedSuper(J9ROMClass *superRomClass, U_8* className, U_16 cl
return result;
}

#if JAVA_SPEC_VERSION >= 16
/**
* JEP 397 (second preview): if super class/interface is sealed, IncompatibleClassChangeError is throw out
* if one of the following conditions is false:
* (1) the inheriting subclass is not in the same module as its super class/interface;
* (2) the inheriting subclass (non-public) is not in the same package as its super class/interface.
*
* @param vmThread the current VM thread
* @param superClass the super class/interface
* @param romClass the ROM class of subclass
* @param module the subclass's module
* @param packageID the subclass's package ID
* @return TRUE if subclass can legally inherit the super, FALSE otherwise.
*/
static VMINLINE BOOLEAN
isClassInTheSameModuleOrPckageAsSealedSuper(J9VMThread *vmThread, J9Class *superClass, J9ROMClass *romClass, J9Module *module, UDATA packageID)
{
if (J9ROMCLASS_IS_SEALED(superClass->romClass)) {
J9JavaVM *vm = vmThread->javaVM;
J9UTF8 *className = J9ROMCLASS_CLASSNAME(romClass);
bool classIsPublic = J9_ARE_ALL_BITS_SET(romClass->modifiers, J9AccPublic);
J9Module * superModule = superClass->module;

if (J9_IS_J9MODULE_UNNAMED(vm, superModule)) {
if (!classIsPublic && (packageID != superClass->packageID)) {
Trc_VM_CreateRAMClassFromROMClass_sealedSuperFromDifferentPackage(vmThread, superClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className));
setCurrentExceptionForBadClass(vmThread, className, J9VMCONSTANTPOOL_JAVALANGINCOMPATIBLECLASSCHANGEERROR, J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_PACKAGE);
return FALSE;
}
} else {
if (module != superModule) {
Trc_VM_CreateRAMClassFromROMClass_sealedSuperFromDifferentModule(vmThread, superClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className));
setCurrentExceptionForBadClass(vmThread, className, J9VMCONSTANTPOOL_JAVALANGINCOMPATIBLECLASSCHANGEERROR, J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_MODULE);
return FALSE;
}
}
}

return TRUE;
}
#endif /* JAVA_SPEC_VERSION >= 16 */

/**
* Attempts to recursively load (if necessary) the required superclass and
* interfaces for the class being loaded.
Expand Down Expand Up @@ -1680,6 +1722,15 @@ loadSuperClassAndInterfaces(J9VMThread *vmThread, J9ClassLoader *classLoader, J9
return FALSE;
}

#if JAVA_SPEC_VERSION >= 16
/* JEP 397 sealed classes: the current class must be in the same module as its superclass
* or in the same package as its superclass if non-public.
*/
if (!isClassInTheSameModuleOrPckageAsSealedSuper(vmThread, superclass, romClass, module, packageID)) {
return FALSE;
}
#endif /* JAVA_SPEC_VERSION >= 16 */

/* JEP 360 sealed classes: if superclass is sealed it must contain the romClass's name in its PermittedSubclasses attribute */
if (! isClassPermittedBySealedSuper(superclass->romClass, J9UTF8_DATA(className), J9UTF8_LENGTH(className))) {
Trc_VM_CreateRAMClassFromROMClass_classIsNotPermittedBySealedSuperclass(vmThread, superclass, J9UTF8_LENGTH(className), J9UTF8_DATA(className));
Expand Down Expand Up @@ -1747,6 +1798,15 @@ loadSuperClassAndInterfaces(J9VMThread *vmThread, J9ClassLoader *classLoader, J9
return FALSE;
}

#if JAVA_SPEC_VERSION >= 16
/* JEP 397 sealed classes: the current interface must be in the same module as its superinterface
* or in the same package as its superinterface if non-public.
*/
if (!isClassInTheSameModuleOrPckageAsSealedSuper(vmThread, interfaceClass, romClass, module, packageID)) {
return FALSE;
}
#endif /* JAVA_SPEC_VERSION >= 16 */

/* JEP 360 sealed classes: if superinterface is sealed it must contain the romClass's name in its PermittedSubclasses attribute */
if (! isClassPermittedBySealedSuper(interfaceClass->romClass, J9UTF8_DATA(className), J9UTF8_LENGTH(className))) {
Trc_VM_CreateRAMClassFromROMClass_classIsNotPermittedBySealedSuperinterface(vmThread, interfaceClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className));
Expand Down
3 changes: 3 additions & 0 deletions runtime/vm/j9vm.tdf
Original file line number Diff line number Diff line change
Expand Up @@ -874,3 +874,6 @@ TraceExit=Trc_VM_resolveInvokeDynamic_Exit Overhead=1 Level=3 Template="resolveI
TraceEntry=Trc_VM_sendResolveOpenJDKInvokeHandle_Entry Overhead=1 Level=2 Template="sendResolveOpenJDKInvokeHandle"
TraceExit=Trc_VM_sendResolveOpenJDKInvokeHandle_Exit Overhead=1 Level=2 Template="sendResolveOpenJDKInvokeHandle"
TraceEntry=Trc_VM_romClassLoadFromCookie_Entry2 Overhead=1 Level=3 Template="romClassLoadFromCookie vmStruct=%p clsNamePtr=%p clsName=%.*s romClassBytes=%p romClassLength=%d"

TraceException=Trc_VM_CreateRAMClassFromROMClass_sealedSuperFromDifferentModule Overhead=1 Level=1 Template="The sealed super class/interface (RAM class=%p) is not in the same module as %.*s"
TraceException=Trc_VM_CreateRAMClassFromROMClass_sealedSuperFromDifferentPackage Overhead=1 Level=1 Template="The sealed super class/interface (RAM class=%p) is not in the same package as %.*s (non-public)"
42 changes: 41 additions & 1 deletion test/functional/Java16andUp/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,46 @@
<!--Properties for this particular build-->
<property name="src" location="./src"/>
<property name="build" location="./bin"/>
<property name="module_src_root" location="./modules"/>
<property name="module_bin_root" location="./module_bin"/>
<property name="dest_module_bin" location="${DEST}/module_bin"/>
<property name="LIB" value="asm,testng,jcommander"/>
<import file="${TEST_ROOT}/TKG/scripts/getDependencies.xml"/>

<target name="init">
<mkdir dir="${DEST}" />
<mkdir dir="${build}"/>
</target>

<property name="MODULE_NAME_ROOT" value="org.openj9test.modularity" />
<property name="MODULE_PATH_ROOT" value="org/openj9/test/modularity"/>

<target name="compile_modules" depends="init" description="Create the base modules for the sealed classes">
<mkdir dir="${module_bin_root}" />
<copy file="${LIB_DIR}/testng.jar" todir="${module_bin_root}" />
<copy file="${LIB_DIR}/jcommander.jar" todir="${module_bin_root}" />
<copy file="${LIB_DIR}/asm.jar" todir="${module_bin_root}" />
<for list="moduleX,moduleY" param="mod">
<sequential>
<var name="module_src_dir" value="${module_src_root}/${MODULE_NAME_ROOT}.@{mod}" />
<var name="module_bin_dir" value="${module_bin_root}/${MODULE_NAME_ROOT}.@{mod}" />
<mkdir dir="${module_bin_dir}" />
<var name="modpath" value="--module-path ${module_bin_root} -d ${module_bin_dir}" />
<javac srcdir="${module_src_dir}" destdir="${module_bin_dir}" debug="true" fork="true" executable="${compiler.javac}" includeAntRuntime="false" encoding="ISO-8859-1">
<src path="${module_src_dir}" />
<compilerarg line='--add-exports java.base/jdk.internal.misc=ALL-UNNAMED' />
<compilerarg line='--enable-preview --source ${JDK_VERSION}' />
<compilerarg line="${modpath}" />
<classpath>
<pathelement location="${LIB_DIR}/testng.jar"/>
<pathelement location="${LIB_DIR}/jcommander.jar"/>
<pathelement location="${LIB_DIR}/asm.jar" />
<pathelement location="${build}" />
</classpath>
</javac>
</sequential>
</for>
</target>

<target name="compile" depends="init,getDependentLibs" description="Using java ${JDK_VERSION} to compile the source" >
<echo>Ant version is ${ant.version}</echo>
Expand All @@ -53,6 +86,7 @@

<javac srcdir="${src}" destdir="${build}" debug="true" fork="true" executable="${compiler.javac}" includeAntRuntime="false" encoding="ISO-8859-1">
<src path="${src}"/>
<exclude name="**/modules/**" />
<compilerarg line='--add-exports java.base/jdk.internal.misc=ALL-UNNAMED' />
<compilerarg line='--enable-preview --source ${JDK_VERSION}' />
<classpath>
Expand All @@ -64,10 +98,16 @@
</javac>
</target>

<target name="dist" depends="compile,dist_functional" description="generate the distribution" >
<target name="dist" depends="compile,dist_functional,compile_modules" description="generate the distribution" >
<echo>copy ${module_bin_root} to ${dest_module_bin}</echo>
<mkdir dir="${dest_module_bin}"/>
<copy todir="${dest_module_bin}">
<fileset dir="${module_bin_root}"/>
</copy>
<mkdir dir="${DEST}"/>
<jar jarfile="${DEST}/GeneralTest.jar" filesonly="true">
<fileset dir="${build}"/>
<fileset dir="${dest_module_bin}"/>
<fileset dir="${src}/../" includes="*.properties,*.xml"/>
</jar>
<copy todir="${DEST}">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

module org.openj9test.modularity.moduleX {
exports org.openj9.test.modularity.pkgA;
exports org.openj9.test.modularity.pkgD;
requires testng;
requires org.objectweb.asm;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.openj9.test.modularity.pkgA;

/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

import org.openj9.test.modularity.pkgD.SubClassPermitted1;

public sealed class SuperClassSealed permits TestSubclass1,SubClassPermitted1 {
}

/* Only used for the placeholder in the PermittedSubclasses attribute of the sealed superclass */
non-sealed class TestSubclass1 extends SuperClassSealed {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.openj9.test.modularity.pkgA;

/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

import org.openj9.test.modularity.pkgD.SubClassPermitted2;

public sealed interface SuperInterfaceSealed permits TestSubclass2, SubClassPermitted2 {
}

/* Only used for the placeholder in the PermittedSubclasses attribute of the sealed superinterface */
non-sealed class TestSubclass2 implements SuperInterfaceSealed {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.openj9.test.modularity.pkgD;

/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

import org.openj9.test.modularity.pkgA.SuperClassSealed;

public non-sealed class SubClassPermitted1 extends SuperClassSealed {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.openj9.test.modularity.pkgD;

/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

import org.openj9.test.modularity.pkgA.SuperInterfaceSealed;
import org.openj9.test.modularity.pkgD.SuperClassInSamePkg;

public non-sealed class SubClassPermitted2 extends SuperClassInSamePkg implements SuperInterfaceSealed {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.openj9.test.modularity.pkgD;

/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

public class SuperClassInSamePkg {}
Loading

0 comments on commit 022d654

Please sign in to comment.