mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-30 13:08:24 +00:00
8198908: Add JVM support for preview features
Add new major and minor version checks Reviewed-by: dholmes, lfoltan
This commit is contained in:
parent
14a142ba14
commit
ffc0b90a4e
@ -57,6 +57,7 @@
|
||||
#include "oops/symbol.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "prims/jvmtiThreadState.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/perfData.hpp"
|
||||
@ -89,6 +90,7 @@
|
||||
|
||||
#define JAVA_CLASSFILE_MAGIC 0xCAFEBABE
|
||||
#define JAVA_MIN_SUPPORTED_VERSION 45
|
||||
#define JAVA_PREVIEW_MINOR_VERSION 65535
|
||||
|
||||
// Used for two backward compatibility reasons:
|
||||
// - to check for new additions to the class file format in JDK1.5
|
||||
@ -4700,12 +4702,63 @@ static bool has_illegal_visibility(jint flags) {
|
||||
(is_protected && is_private));
|
||||
}
|
||||
|
||||
static bool is_supported_version(u2 major, u2 minor){
|
||||
// A legal major_version.minor_version must be one of the following:
|
||||
//
|
||||
// Major_version = 45, any minor_version.
|
||||
// Major_version >= 46 and major_version <= current_major_version and minor_version = 0.
|
||||
// Major_version = current_major_version and minor_version = 65535 and --enable-preview is present.
|
||||
//
|
||||
static void verify_class_version(u2 major, u2 minor, Symbol* class_name, TRAPS){
|
||||
const u2 max_version = JVM_CLASSFILE_MAJOR_VERSION;
|
||||
return (major >= JAVA_MIN_SUPPORTED_VERSION) &&
|
||||
(major <= max_version) &&
|
||||
((major != max_version) ||
|
||||
(minor <= JVM_CLASSFILE_MINOR_VERSION));
|
||||
if (major != JAVA_MIN_SUPPORTED_VERSION) { // All 45.* are ok including 45.65535
|
||||
if (minor == JAVA_PREVIEW_MINOR_VERSION) {
|
||||
if (major != max_version) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_UnsupportedClassVersionError(),
|
||||
"%s (class file version %u.%u) was compiled with preview features that are unsupported. "
|
||||
"This version of the Java Runtime only recognizes preview features for class file version %u.%u",
|
||||
class_name->as_C_string(), major, minor, JVM_CLASSFILE_MAJOR_VERSION, JAVA_PREVIEW_MINOR_VERSION);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Arguments::enable_preview()) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_UnsupportedClassVersionError(),
|
||||
"Preview features are not enabled for %s (class file version %u.%u). Try running with '--enable-preview'",
|
||||
class_name->as_C_string(), major, minor);
|
||||
return;
|
||||
}
|
||||
|
||||
} else { // minor != JAVA_PREVIEW_MINOR_VERSION
|
||||
if (major > max_version) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_UnsupportedClassVersionError(),
|
||||
"%s has been compiled by a more recent version of the Java Runtime (class file version %u.%u), "
|
||||
"this version of the Java Runtime only recognizes class file versions up to %u.0",
|
||||
class_name->as_C_string(), major, minor, JVM_CLASSFILE_MAJOR_VERSION);
|
||||
} else if (major < JAVA_MIN_SUPPORTED_VERSION) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_UnsupportedClassVersionError(),
|
||||
"%s (class file version %u.%u) was compiled with an invalid major version",
|
||||
class_name->as_C_string(), major, minor);
|
||||
} else if (minor != 0) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_UnsupportedClassVersionError(),
|
||||
"%s (class file version %u.%u) was compiled with an invalid non-zero minor version",
|
||||
class_name->as_C_string(), major, minor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClassFileParser::verify_legal_field_modifiers(jint flags,
|
||||
@ -5551,6 +5604,13 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
|
||||
ik->print_class_load_logging(_loader_data, module_name, _stream);
|
||||
}
|
||||
|
||||
if (ik->minor_version() == JAVA_PREVIEW_MINOR_VERSION &&
|
||||
ik->major_version() != JAVA_MIN_SUPPORTED_VERSION &&
|
||||
log_is_enabled(Info, class, preview)) {
|
||||
ResourceMark rm;
|
||||
log_info(class, preview)("Loading preview feature type %s", ik->external_name());
|
||||
}
|
||||
|
||||
if (log_is_enabled(Debug, class, resolve)) {
|
||||
ResourceMark rm;
|
||||
// print out the superclass.
|
||||
@ -5866,20 +5926,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
|
||||
}
|
||||
|
||||
// Check version numbers - we check this even with verifier off
|
||||
if (!is_supported_version(_major_version, _minor_version)) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_UnsupportedClassVersionError(),
|
||||
"%s has been compiled by a more recent version of the Java Runtime (class file version %u.%u), "
|
||||
"this version of the Java Runtime only recognizes class file versions up to %u.%u",
|
||||
_class_name->as_C_string(),
|
||||
_major_version,
|
||||
_minor_version,
|
||||
JVM_CLASSFILE_MAJOR_VERSION,
|
||||
JVM_CLASSFILE_MINOR_VERSION);
|
||||
return;
|
||||
}
|
||||
verify_class_version(_major_version, _minor_version, _class_name, CHECK);
|
||||
|
||||
stream->guarantee_more(3, CHECK); // length, first cp tag
|
||||
u2 cp_size = stream->get_u2_fast();
|
||||
|
||||
@ -112,6 +112,7 @@
|
||||
LOG_TAG(perf) \
|
||||
LOG_TAG(phases) \
|
||||
LOG_TAG(plab) \
|
||||
LOG_TAG(preview) /* Trace loading of preview feature types */ \
|
||||
LOG_TAG(promotion) \
|
||||
LOG_TAG(preorder) /* Trace all classes loaded in order referenced (not loaded) */ \
|
||||
LOG_TAG(protectiondomain) /* "Trace protection domain verification" */ \
|
||||
|
||||
@ -96,6 +96,8 @@ bool Arguments::_ClipInlining = ClipInlining;
|
||||
intx Arguments::_Tier3InvokeNotifyFreqLog = Tier3InvokeNotifyFreqLog;
|
||||
intx Arguments::_Tier4InvocationThreshold = Tier4InvocationThreshold;
|
||||
|
||||
bool Arguments::_enable_preview = false;
|
||||
|
||||
char* Arguments::SharedArchivePath = NULL;
|
||||
|
||||
AgentLibraryList Arguments::_libraryList;
|
||||
@ -2739,6 +2741,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m
|
||||
}
|
||||
}
|
||||
#endif // !INCLUDE_JVMTI
|
||||
// --enable_preview
|
||||
} else if (match_option(option, "--enable-preview")) {
|
||||
set_enable_preview();
|
||||
// -Xnoclassgc
|
||||
} else if (match_option(option, "-Xnoclassgc")) {
|
||||
if (FLAG_SET_CMDLINE(bool, ClassUnloading, false) != Flag::SUCCESS) {
|
||||
|
||||
@ -358,6 +358,9 @@ class Arguments : AllStatic {
|
||||
static void set_xdebug_mode(bool arg) { _xdebug_mode = arg; }
|
||||
static bool xdebug_mode() { return _xdebug_mode; }
|
||||
|
||||
// preview features
|
||||
static bool _enable_preview;
|
||||
|
||||
// Used to save default settings
|
||||
static bool _AlwaysCompileLoopMethods;
|
||||
static bool _UseOnStackReplacement;
|
||||
@ -691,6 +694,9 @@ class Arguments : AllStatic {
|
||||
static Mode mode() { return _mode; }
|
||||
static bool is_interpreter_only() { return mode() == _int; }
|
||||
|
||||
// preview features
|
||||
static void set_enable_preview() { _enable_preview = true; }
|
||||
static bool enable_preview() { return _enable_preview; }
|
||||
|
||||
// Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid.
|
||||
static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen);
|
||||
|
||||
116
test/hotspot/jtreg/runtime/ClassFile/PreviewVersion.java
Normal file
116
test/hotspot/jtreg/runtime/ClassFile/PreviewVersion.java
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8198908
|
||||
* @summary Check that preview minor version and --enable-preview are handled
|
||||
* correctly.
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @library /test/lib
|
||||
* @run main PreviewVersion
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import jdk.test.lib.compiler.InMemoryJavaCompiler;
|
||||
import jdk.test.lib.ByteCodeLoader;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
public class PreviewVersion {
|
||||
|
||||
public static void main(String args[]) throws Throwable {
|
||||
System.out.println("Regression test for bug 8198908");
|
||||
|
||||
byte klassbuf[] = InMemoryJavaCompiler.compile("PVTest",
|
||||
"public class PVTest { " +
|
||||
"public static void main(String argv[]) { " +
|
||||
"System.out.println(\"Hi!\"); } }");
|
||||
|
||||
// Set class's minor version to 65535.
|
||||
klassbuf[4] = -1;
|
||||
klassbuf[5] = -1;
|
||||
|
||||
// Run the test. This should fail because --enable-preview is not specified.
|
||||
ClassFileInstaller.writeClassToDisk("PVTest", klassbuf, System.getProperty("test.classes"));
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||
"-cp", "." + File.pathSeparator + System.getProperty("test.classes"), "PVTest");
|
||||
OutputAnalyzer oa = new OutputAnalyzer(pb.start());
|
||||
oa.shouldContain("Preview features are not enabled");
|
||||
oa.shouldHaveExitValue(1);
|
||||
|
||||
// This should be successful because --enable-preview is specified.
|
||||
pb = ProcessTools.createJavaProcessBuilder("--enable-preview",
|
||||
"-cp", "." + File.pathSeparator + System.getProperty("test.classes"), "PVTest");
|
||||
oa = new OutputAnalyzer(pb.start());
|
||||
oa.shouldContain("Hi!");
|
||||
|
||||
// Test -Xlog:class+preview
|
||||
pb = ProcessTools.createJavaProcessBuilder("--enable-preview", "-Xlog:class+preview",
|
||||
"-cp", "." + File.pathSeparator + System.getProperty("test.classes"), "PVTest");
|
||||
oa = new OutputAnalyzer(pb.start());
|
||||
oa.shouldContain("[info][class,preview] Loading preview feature type PVTest");
|
||||
|
||||
// Subtract 1 from class's major version. The class should fail to load
|
||||
// because its major_version does not match the JVM current version.
|
||||
int prev_major_version = Runtime.version().feature() - 1;
|
||||
klassbuf[6] = (byte)((prev_major_version >> 8) & 0xff);
|
||||
klassbuf[7] = (byte)(prev_major_version & 0xff);
|
||||
try {
|
||||
ByteCodeLoader.load("PVTest", klassbuf);
|
||||
throw new RuntimeException("UnsupportedClassVersionError exception not thrown");
|
||||
} catch (java.lang.UnsupportedClassVersionError e) {
|
||||
if (!e.getMessage().contains("compiled with preview features that are unsupported")) {
|
||||
throw new RuntimeException(
|
||||
"Wrong UnsupportedClassVersionError exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Set class's major version to 45. The class should load because class
|
||||
// version 45.65535 is valid.
|
||||
klassbuf[6] = 0;
|
||||
klassbuf[7] = 45;
|
||||
try {
|
||||
ByteCodeLoader.load("PVTest", klassbuf);
|
||||
} catch (java.lang.UnsupportedClassVersionError e) {
|
||||
throw new RuntimeException(
|
||||
"Unexpected UnsupportedClassVersionError exception thrown: " + e.getMessage());
|
||||
}
|
||||
|
||||
// Check that a class with a recent older major version and a non-zero
|
||||
// minor version fails to load.
|
||||
klassbuf[6] = 0;
|
||||
klassbuf[7] = 53;
|
||||
klassbuf[4] = 0;
|
||||
klassbuf[5] = 2;
|
||||
try {
|
||||
ByteCodeLoader.load("PVTest", klassbuf);
|
||||
throw new RuntimeException("UnsupportedClassVersionError exception not thrown");
|
||||
} catch (java.lang.UnsupportedClassVersionError e) {
|
||||
if (!e.getMessage().contains("was compiled with an invalid non-zero minor version")) {
|
||||
throw new RuntimeException(
|
||||
"Wrong UnsupportedClassVersionError exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user