8227046: compiler implementation for sealed classes

8225056: VM support for sealed classes
8227044: javax.lang.model for sealed classes
8227045: Preview APIs support for sealed classes
8227047: Javadoc for sealed types
8245854: JVM TI Specification for sealed classes

Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Reviewed-by: mcimadamore, forax, darcy, dholmes, jlahoda, lfoltan, mchung, sspitsyn, vromero
This commit is contained in:
Vicente Romero 2020-06-01 17:00:40 -04:00
parent 567692e4ae
commit d42bfef8a4
139 changed files with 6877 additions and 192 deletions

View File

@ -650,6 +650,7 @@ INTERIM_LANGTOOLS_ADD_EXPORTS := \
--add-exports java.base/sun.reflect.annotation=jdk.compiler.interim \
--add-exports java.base/jdk.internal.jmod=jdk.compiler.interim \
--add-exports java.base/jdk.internal.misc=jdk.compiler.interim \
--add-exports java.base/sun.invoke.util=jdk.compiler.interim \
#
INTERIM_LANGTOOLS_MODULES_COMMA := $(strip $(subst $(SPACE),$(COMMA),$(strip \
$(INTERIM_LANGTOOLS_MODULES))))

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 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
@ -3160,8 +3160,8 @@ JDWP "Java(tm) Debug Wire Protocol"
"canUnrestrictedlyRedefineClasses is false.")
(Constant CLASS_ATTRIBUTE_CHANGE_NOT_IMPLEMENTED
=72 "The new class version has a different NestHost, "
"NestMembers, or Record class attribute and "
"canUnrestrictedlyRedefineClasses is false.")
"NestMembers, PermittedSubclasses, or Record class attribute "
"and canUnrestrictedlyRedefineClasses is false.")
(Constant NOT_IMPLEMENTED =99 "The functionality is not implemented in "
"this virtual machine.")
(Constant NULL_POINTER =100 "Invalid pointer.")

View File

@ -119,6 +119,7 @@ JVM_GetMethodTypeAnnotations
JVM_GetNanoTimeAdjustment
JVM_GetNestHost
JVM_GetNestMembers
JVM_GetPermittedSubclasses
JVM_GetPrimitiveArrayElement
JVM_GetProperties
JVM_GetProtectionDomain

View File

@ -3212,6 +3212,41 @@ u2 ClassFileParser::parse_classfile_nest_members_attribute(const ClassFileStream
return length;
}
u2 ClassFileParser::parse_classfile_permitted_subclasses_attribute(const ClassFileStream* const cfs,
const u1* const permitted_subclasses_attribute_start,
TRAPS) {
const u1* const current_mark = cfs->current();
u2 length = 0;
if (permitted_subclasses_attribute_start != NULL) {
cfs->set_current(permitted_subclasses_attribute_start);
cfs->guarantee_more(2, CHECK_0); // length
length = cfs->get_u2_fast();
}
if (length < 1) {
classfile_parse_error("PermittedSubclasses attribute is empty in class file %s", CHECK_0);
}
const int size = length;
Array<u2>* const permitted_subclasses = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0);
_permitted_subclasses = permitted_subclasses;
int index = 0;
cfs->guarantee_more(2 * length, CHECK_0);
for (int n = 0; n < length; n++) {
const u2 class_info_index = cfs->get_u2_fast();
check_property(
valid_klass_reference_at(class_info_index),
"Permitted subclass class_info_index %u has bad constant type in class file %s",
class_info_index, CHECK_0);
permitted_subclasses->at_put(index++, class_info_index);
}
assert(index == size, "wrong size");
// Restore buffer's current position.
cfs->set_current(current_mark);
return length;
}
// Record {
// u2 attribute_name_index;
// u4 attribute_length;
@ -3476,10 +3511,16 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
CHECK);
}
bool ClassFileParser::supports_sealed_types() {
return _major_version == JVM_CLASSFILE_MAJOR_VERSION &&
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
Arguments::enable_preview();
}
bool ClassFileParser::supports_records() {
return _major_version == JVM_CLASSFILE_MAJOR_VERSION &&
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
Arguments::enable_preview();
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
Arguments::enable_preview();
}
void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs,
@ -3494,11 +3535,14 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
_inner_classes = Universe::the_empty_short_array();
// Set nest members attribute to default sentinel
_nest_members = Universe::the_empty_short_array();
// Set _permitted_subclasses attribute to default sentinel
_permitted_subclasses = Universe::the_empty_short_array();
cfs->guarantee_more(2, CHECK); // attributes_count
u2 attributes_count = cfs->get_u2_fast();
bool parsed_sourcefile_attribute = false;
bool parsed_innerclasses_attribute = false;
bool parsed_nest_members_attribute = false;
bool parsed_permitted_subclasses_attribute = false;
bool parsed_nest_host_attribute = false;
bool parsed_record_attribute = false;
bool parsed_enclosingmethod_attribute = false;
@ -3522,6 +3566,8 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
u4 nest_members_attribute_length = 0;
const u1* record_attribute_start = NULL;
u4 record_attribute_length = 0;
const u1* permitted_subclasses_attribute_start = NULL;
u4 permitted_subclasses_attribute_length = 0;
// Iterate over attributes
while (attributes_count--) {
@ -3738,6 +3784,26 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
}
}
cfs->skip_u1(attribute_length, CHECK);
} else if (_major_version >= JAVA_15_VERSION) {
// Check for PermittedSubclasses tag
if (tag == vmSymbols::tag_permitted_subclasses()) {
if (supports_sealed_types()) {
if (parsed_permitted_subclasses_attribute) {
classfile_parse_error("Multiple PermittedSubclasses attributes in class file %s", CHECK);
}
// Classes marked ACC_FINAL cannot have a PermittedSubclasses attribute.
if (_access_flags.is_final()) {
classfile_parse_error("PermittedSubclasses attribute in final class file %s", CHECK);
}
parsed_permitted_subclasses_attribute = true;
permitted_subclasses_attribute_start = cfs->current();
permitted_subclasses_attribute_length = attribute_length;
}
cfs->skip_u1(attribute_length, CHECK);
} else {
// Unknown attribute
cfs->skip_u1(attribute_length, CHECK);
}
} else {
// Unknown attribute
cfs->skip_u1(attribute_length, CHECK);
@ -3806,6 +3872,18 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
}
}
if (parsed_permitted_subclasses_attribute) {
const u2 num_subclasses = parse_classfile_permitted_subclasses_attribute(
cfs,
permitted_subclasses_attribute_start,
CHECK);
if (_need_verify) {
guarantee_property(
permitted_subclasses_attribute_length == sizeof(num_subclasses) + sizeof(u2) * num_subclasses,
"Wrong PermittedSubclasses attribute length in class file %s", CHECK);
}
}
if (_max_bootstrap_specifier_index >= 0) {
guarantee_property(parsed_bootstrap_methods_attribute,
"Missing BootstrapMethods attribute in class file %s", CHECK);
@ -3873,6 +3951,7 @@ void ClassFileParser::apply_parsed_class_metadata(
this_klass->set_nest_host_index(_nest_host);
this_klass->set_local_interfaces(_local_interfaces);
this_klass->set_annotations(_combined_annotations);
this_klass->set_permitted_subclasses(_permitted_subclasses);
this_klass->set_record_components(_record_components);
// Delay the setting of _transitive_interfaces until after initialize_supers() in
// fill_instance_klass(). It is because the _transitive_interfaces may be shared with
@ -4681,12 +4760,34 @@ static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
const Klass* const super = this_klass->super();
if (super != NULL) {
const InstanceKlass* super_ik = InstanceKlass::cast(super);
if (super->is_final()) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_VerifyError(),
"class %s cannot inherit from final class %s",
this_klass->external_name(),
super_ik->external_name());
return;
}
if (super_ik->is_sealed() && !super_ik->has_as_permitted_subclass(this_klass)) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IncompatibleClassChangeError(),
"class %s cannot inherit from sealed class %s",
this_klass->external_name(),
super_ik->external_name());
return;
}
// If the loader is not the boot loader then throw an exception if its
// superclass is in package jdk.internal.reflect and its loader is not a
// special reflection class loader
if (!this_klass->class_loader_data()->is_the_null_class_loader_data()) {
assert(super->is_instance_klass(), "super is not instance klass");
PackageEntry* super_package = super->package();
if (super_package != NULL &&
super_package->name()->fast_compare(vmSymbols::jdk_internal_reflect()) == 0 &&
@ -4742,6 +4843,19 @@ static void check_super_interface_access(const InstanceKlass* this_klass, TRAPS)
for (int i = lng - 1; i >= 0; i--) {
InstanceKlass* const k = local_interfaces->at(i);
assert (k != NULL && k->is_interface(), "invalid interface");
if (k->is_sealed() && !k->has_as_permitted_subclass(this_klass)) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IncompatibleClassChangeError(),
"class %s cannot %s sealed interface %s",
this_klass->external_name(),
this_klass->is_interface() ? "extend" : "implement",
k->external_name());
return;
}
Reflection::VerifyClassAccessResults vca_result =
Reflection::verify_class_access(this_klass, k, false);
if (vca_result != Reflection::ACCESS_OK) {
@ -5677,6 +5791,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
assert(NULL == _local_interfaces, "invariant");
assert(NULL == _combined_annotations, "invariant");
assert(NULL == _record_components, "invariant");
assert(NULL == _permitted_subclasses, "invariant");
if (_has_final_method) {
ik->set_has_final_method();
@ -5965,6 +6080,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_inner_classes(NULL),
_nest_members(NULL),
_nest_host(0),
_permitted_subclasses(NULL),
_record_components(NULL),
_local_interfaces(NULL),
_transitive_interfaces(NULL),
@ -6073,6 +6189,7 @@ void ClassFileParser::clear_class_metadata() {
_methods = NULL;
_inner_classes = NULL;
_nest_members = NULL;
_permitted_subclasses = NULL;
_local_interfaces = NULL;
_combined_annotations = NULL;
_class_annotations = _class_type_annotations = NULL;
@ -6109,6 +6226,10 @@ ClassFileParser::~ClassFileParser() {
InstanceKlass::deallocate_record_components(_loader_data, _record_components);
}
if (_permitted_subclasses != NULL && _permitted_subclasses != Universe::the_empty_short_array()) {
MetadataFactory::free_array<u2>(_loader_data, _permitted_subclasses);
}
// Free interfaces
InstanceKlass::deallocate_interfaces(_loader_data, _super_klass,
_local_interfaces, _transitive_interfaces);
@ -6507,10 +6628,6 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st
);
return;
}
// Make sure super class is not final
if (_super_klass->is_final()) {
THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class");
}
}
// Compute the transitive list of all unique interfaces implemented by this class

View File

@ -132,6 +132,7 @@ class ClassFileParser {
Array<u2>* _inner_classes;
Array<u2>* _nest_members;
u2 _nest_host;
Array<u2>* _permitted_subclasses;
Array<RecordComponent*>* _record_components;
Array<InstanceKlass*>* _local_interfaces;
Array<InstanceKlass*>* _transitive_interfaces;
@ -327,11 +328,16 @@ class ClassFileParser {
const u1* const nest_members_attribute_start,
TRAPS);
u2 parse_classfile_permitted_subclasses_attribute(const ClassFileStream* const cfs,
const u1* const permitted_subclasses_attribute_start,
TRAPS);
u2 parse_classfile_record_attribute(const ClassFileStream* const cfs,
const ConstantPool* cp,
const u1* const record_attribute_start,
TRAPS);
bool supports_sealed_types();
bool supports_records();
void parse_classfile_attributes(const ClassFileStream* const cfs,

View File

@ -173,6 +173,7 @@
template(tag_runtime_invisible_type_annotations, "RuntimeInvisibleTypeAnnotations") \
template(tag_enclosing_method, "EnclosingMethod") \
template(tag_bootstrap_methods, "BootstrapMethods") \
template(tag_permitted_subclasses, "PermittedSubclasses") \
\
/* exception klasses: at least all exceptions thrown by the VM have entries here */ \
template(java_lang_ArithmeticException, "java/lang/ArithmeticException") \

View File

@ -567,6 +567,11 @@ JVM_IsRecord(JNIEnv *env, jclass cls);
JNIEXPORT jobjectArray JNICALL
JVM_GetRecordComponents(JNIEnv *env, jclass ofClass);
/* Sealed types - since JDK 15 */
JNIEXPORT jobjectArray JNICALL
JVM_GetPermittedSubclasses(JNIEnv *env, jclass current);
/* The following two reflection routines are still needed due to startup time issues */
/*
* java.lang.reflect.Method

View File

@ -147,6 +147,7 @@
LOG_TAG(safepoint) \
LOG_TAG(sampling) \
LOG_TAG(scavenge) \
LOG_TAG(sealed) \
LOG_TAG(setting) \
LOG_TAG(smr) \
LOG_TAG(stacktrace) \

View File

@ -218,6 +218,57 @@ bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const {
return false;
}
// Called to verify that k is a permitted subclass of this class
bool InstanceKlass::has_as_permitted_subclass(const InstanceKlass* k) const {
Thread* THREAD = Thread::current();
assert(k != NULL, "sanity check");
assert(_permitted_subclasses != NULL && _permitted_subclasses != Universe::the_empty_short_array(),
"unexpected empty _permitted_subclasses array");
if (log_is_enabled(Trace, class, sealed)) {
ResourceMark rm(THREAD);
log_trace(class, sealed)("Checking for permitted subclass of %s in %s",
k->external_name(), this->external_name());
}
// Check that the class and its super are in the same module.
if (k->module() != this->module()) {
ResourceMark rm(THREAD);
log_trace(class, sealed)("Check failed for same module of permitted subclass %s and sealed class %s",
k->external_name(), this->external_name());
return false;
}
if (!k->is_public() && !is_same_class_package(k)) {
ResourceMark rm(THREAD);
log_trace(class, sealed)("Check failed, subclass %s not public and not in the same package as sealed class %s",
k->external_name(), this->external_name());
return false;
}
// Check for a resolved cp entry, else fall back to a name check.
// We don't want to resolve any class other than the one being checked.
for (int i = 0; i < _permitted_subclasses->length(); i++) {
int cp_index = _permitted_subclasses->at(i);
if (_constants->tag_at(cp_index).is_klass()) {
Klass* k2 = _constants->klass_at(cp_index, THREAD);
assert(!HAS_PENDING_EXCEPTION, "Unexpected exception");
if (k2 == k) {
log_trace(class, sealed)("- class is listed at permitted_subclasses[%d] => cp[%d]", i, cp_index);
return true;
}
} else {
Symbol* name = _constants->klass_name_at(cp_index);
if (name == k->name()) {
log_trace(class, sealed)("- Found it at permitted_subclasses[%d] => cp[%d]", i, cp_index);
return true;
}
}
}
log_trace(class, sealed)("- class is NOT a permitted subclass!");
return false;
}
// Return nest-host class, resolving, validating and saving it if needed.
// In cases where this is called from a thread that cannot do classloading
// (such as a native JIT thread) then we simply return NULL, which in turn
@ -484,6 +535,7 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, Klass
Klass(id),
_nest_members(NULL),
_nest_host(NULL),
_permitted_subclasses(NULL),
_record_components(NULL),
_static_field_size(parser.static_field_size()),
_nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
@ -665,6 +717,13 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
}
set_nest_members(NULL);
if (permitted_subclasses() != NULL &&
permitted_subclasses() != Universe::the_empty_short_array() &&
!permitted_subclasses()->is_shared()) {
MetadataFactory::free_array<jushort>(loader_data, permitted_subclasses());
}
set_permitted_subclasses(NULL);
// We should deallocate the Annotations instance if it's not in shared spaces.
if (annotations() != NULL && !annotations()->is_shared()) {
MetadataFactory::free_metadata(loader_data, annotations());
@ -676,6 +735,12 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
}
}
bool InstanceKlass::is_sealed() const {
return _permitted_subclasses != NULL &&
_permitted_subclasses != Universe::the_empty_short_array() &&
_permitted_subclasses->length() > 0;
}
bool InstanceKlass::should_be_initialized() const {
return !is_initialized();
}
@ -2414,6 +2479,7 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) {
}
it->push(&_nest_members);
it->push(&_permitted_subclasses);
it->push(&_record_components);
}
@ -3342,6 +3408,7 @@ void InstanceKlass::print_on(outputStream* st) const {
if (record_components() != NULL) {
st->print(BULLET"record components: "); record_components()->print_value_on(st); st->cr();
}
st->print(BULLET"permitted subclasses: "); permitted_subclasses()->print_value_on(st); st->cr();
if (java_mirror() != NULL) {
st->print(BULLET"java mirror: ");
java_mirror()->print_value_on(st);

View File

@ -198,6 +198,10 @@ class InstanceKlass: public Klass {
// By always being set it makes nest-member access checks simpler.
InstanceKlass* _nest_host;
// The PermittedSubclasses attribute. An array of shorts, where each is a
// class info index for the class that is a permitted subclass.
Array<jushort>* _permitted_subclasses;
// The contents of the Record attribute.
Array<RecordComponent*>* _record_components;
@ -469,6 +473,10 @@ class InstanceKlass: public Klass {
}
bool is_record() const { return _record_components != NULL; }
// permitted subclasses
Array<u2>* permitted_subclasses() const { return _permitted_subclasses; }
void set_permitted_subclasses(Array<u2>* s) { _permitted_subclasses = s; }
private:
// Called to verify that k is a member of this nest - does not look at k's nest-host
bool has_nest_member(InstanceKlass* k, TRAPS) const;
@ -484,6 +492,9 @@ public:
// Check if this klass is a nestmate of k - resolves this nest-host and k's
bool has_nestmate_access_to(InstanceKlass* k, TRAPS);
// Called to verify that k is a permitted subclass of this class
bool has_as_permitted_subclass(const InstanceKlass* k) const;
enum InnerClassAttributeOffset {
// From http://mirror.eng/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc10.html#18814
inner_class_inner_class_info_offset = 0,
@ -541,6 +552,9 @@ public:
ClassState init_state() { return (ClassState)_init_state; }
bool is_rewritten() const { return (_misc_flags & _misc_rewritten) != 0; }
// is this a sealed class
bool is_sealed() const;
// defineClass specified verification
bool should_verify_class() const {
return (_misc_flags & _misc_should_verify_class) != 0;

View File

@ -2101,6 +2101,33 @@ JVM_ENTRY(jobjectArray, JVM_GetNestMembers(JNIEnv* env, jclass current))
}
JVM_END
JVM_ENTRY(jobjectArray, JVM_GetPermittedSubclasses(JNIEnv* env, jclass current))
{
JVMWrapper("JVM_GetPermittedSubclasses");
assert(!java_lang_Class::is_primitive(JNIHandles::resolve_non_null(current)), "should not be");
Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current));
assert(c->is_instance_klass(), "must be");
InstanceKlass* ik = InstanceKlass::cast(c);
{
JvmtiVMObjectAllocEventCollector oam;
Array<u2>* subclasses = ik->permitted_subclasses();
int length = subclasses == NULL ? 0 : subclasses->length();
objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(),
length, CHECK_NULL);
objArrayHandle result(THREAD, r);
for (int i = 0; i < length; i++) {
int cp_index = subclasses->at(i);
// This returns <package-name>/<class-name>.
Symbol* klass_name = ik->constants()->klass_name_at(cp_index);
assert(klass_name != NULL, "Unexpected null klass_name");
Handle perm_subtype_h = java_lang_String::create_from_symbol(klass_name, CHECK_NULL);
result->obj_at_put(i, perm_subtype_h());
}
return (jobjectArray)JNIHandles::make_local(THREAD, result());
}
}
JVM_END
// Constant pool access //////////////////////////////////////////////////////////
JVM_ENTRY(jobject, JVM_GetClassConstantPool(JNIEnv *env, jclass cls))

View File

@ -6900,7 +6900,7 @@ class C2 extends C1 implements I2 {
<synopsis>Get Classloader Classes</synopsis>
<description>
Returns an array of all classes which this class loader
can find by name via
can find by name via
<externallink id="../api/java.base/java/lang/ClassLoader.html#loadClass(java.lang.String,boolean)">ClassLoader::loadClass</externallink>,
<externallink id="../api/java.base/java/lang/Class.html#forName(java.lang.String,boolean,java.lang.ClassLoader)">Class::forName</externallink> and bytecode linkage.
That is, all classes for which <code>initiating_loader</code>
@ -7680,7 +7680,8 @@ class C2 extends C1 implements I2 {
The retransformation must not add, remove or rename fields or methods, change the
signatures of methods, change modifiers, or change inheritance.
The retransformation must not change the <code>NestHost</code>,
<code>NestMembers</code>, or <code>Record</code> attributes.
<code>NestMembers</code>, <code>Record</code>, or <code>PermittedSubclasses</code>
attributes.
These restrictions may be lifted in future versions.
See the error return description below for information on error codes
returned if an unsupported retransformation is attempted.
@ -7833,7 +7834,8 @@ class C2 extends C1 implements I2 {
The redefinition must not add, remove or rename fields or methods, change the
signatures of methods, change modifiers, or change inheritance.
The redefinition must not change the <code>NestHost</code>,
<code>NestMembers</code>, or <code>Record</code> attributes.
<code>NestMembers</code>, <code>Record</code>, or <code>PermittedSubclasses</code>
attributes.
These restrictions may be lifted in future versions.
See the error return description below for information on error codes
returned if an unsupported redefinition is attempted.
@ -15028,6 +15030,11 @@ typedef void (JNICALL *jvmtiEventVMInit)
- Specify that RedefineClasses and RetransformClasses are not allowed
to change the class file Record attribute.
</change>
<change date="13 May 2020" version="15.0.0">
Minor update for new class file PermittedSubclasses attribute:
- Specify that RedefineClasses and RetransformClasses are not allowed
to change the class file PermittedSubclasses attribute.
</change>
</changehistory>
</specification>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -424,6 +424,26 @@ void JvmtiClassFileReconstituter::write_nest_members_attribute() {
}
}
// PermittedSubclasses {
// u2 attribute_name_index;
// u4 attribute_length;
// u2 number_of_classes;
// u2 classes[number_of_classes];
// }
void JvmtiClassFileReconstituter::write_permitted_subclasses_attribute() {
Array<u2>* permitted_subclasses = ik()->permitted_subclasses();
int number_of_classes = permitted_subclasses->length();
int length = sizeof(u2) * (1 + number_of_classes); // '1 +' is for number_of_classes field
write_attribute_name_index("PermittedSubclasses");
write_u4(length);
write_u2(number_of_classes);
for (int i = 0; i < number_of_classes; i++) {
u2 class_cp_index = permitted_subclasses->at(i);
write_u2(class_cp_index);
}
}
// Record {
// u2 attribute_name_index;
// u4 attribute_length;
@ -751,6 +771,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
if (ik()->nest_members() != Universe::the_empty_short_array()) {
++attr_count;
}
if (ik()->permitted_subclasses() != Universe::the_empty_short_array()) {
++attr_count;
}
if (ik()->record_components() != NULL) {
++attr_count;
}
@ -784,6 +807,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
if (ik()->nest_members() != Universe::the_empty_short_array()) {
write_nest_members_attribute();
}
if (ik()->permitted_subclasses() != Universe::the_empty_short_array()) {
write_permitted_subclasses_attribute();
}
if (ik()->record_components() != NULL) {
write_record_attribute();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -118,6 +118,7 @@ class JvmtiClassFileReconstituter : public JvmtiConstantPoolReconstituter {
void write_bootstrapmethod_attribute();
void write_nest_host_attribute();
void write_nest_members_attribute();
void write_permitted_subclasses_attribute();
void write_record_attribute();
address writeable_address(size_t size);

View File

@ -854,6 +854,65 @@ static jvmtiError check_record_attribute(InstanceKlass* the_class, InstanceKlass
}
static jvmtiError check_permitted_subclasses_attribute(InstanceKlass* the_class,
InstanceKlass* scratch_class) {
// Check whether the class PermittedSubclasses attribute has been changed.
Thread* thread = Thread::current();
ResourceMark rm(thread);
Array<u2>* the_permitted_subclasses = the_class->permitted_subclasses();
Array<u2>* scr_permitted_subclasses = scratch_class->permitted_subclasses();
bool the_subclasses_exist = the_permitted_subclasses != Universe::the_empty_short_array();
bool scr_subclasses_exist = scr_permitted_subclasses != Universe::the_empty_short_array();
int subclasses_len = the_permitted_subclasses->length();
if (the_subclasses_exist && scr_subclasses_exist) {
if (subclasses_len != scr_permitted_subclasses->length()) {
log_trace(redefine, class, sealed)
("redefined class %s attribute change error: PermittedSubclasses len=%d changed to len=%d",
the_class->external_name(), subclasses_len, scr_permitted_subclasses->length());
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
}
// The order of entries in the PermittedSubclasses array is not specified so
// we have to explicitly check for the same contents. We do this by copying
// the referenced symbols into their own arrays, sorting them and then
// comparing each element pair.
Symbol** the_syms = NEW_RESOURCE_ARRAY_RETURN_NULL(Symbol*, subclasses_len);
Symbol** scr_syms = NEW_RESOURCE_ARRAY_RETURN_NULL(Symbol*, subclasses_len);
if (the_syms == NULL || scr_syms == NULL) {
return JVMTI_ERROR_OUT_OF_MEMORY;
}
for (int i = 0; i < subclasses_len; i++) {
int the_cp_index = the_permitted_subclasses->at(i);
int scr_cp_index = scr_permitted_subclasses->at(i);
the_syms[i] = the_class->constants()->klass_name_at(the_cp_index);
scr_syms[i] = scratch_class->constants()->klass_name_at(scr_cp_index);
}
qsort(the_syms, subclasses_len, sizeof(Symbol*), symcmp);
qsort(scr_syms, subclasses_len, sizeof(Symbol*), symcmp);
for (int i = 0; i < subclasses_len; i++) {
if (the_syms[i] != scr_syms[i]) {
log_trace(redefine, class, sealed)
("redefined class %s attribute change error: PermittedSubclasses[%d]: %s changed to %s",
the_class->external_name(), i, the_syms[i]->as_C_string(), scr_syms[i]->as_C_string());
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
}
}
} else if (the_subclasses_exist ^ scr_subclasses_exist) {
const char* action_str = (the_subclasses_exist) ? "removed" : "added";
log_trace(redefine, class, sealed)
("redefined class %s attribute change error: PermittedSubclasses attribute %s",
the_class->external_name(), action_str);
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
}
return JVMTI_ERROR_NONE;
}
static bool can_add_or_delete(Method* m) {
// Compatibility mode
return (AllowRedefinitionToAddDeleteMethods &&
@ -913,6 +972,12 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
return err;
}
// Check whether the PermittedSubclasses attribute has been changed.
err = check_permitted_subclasses_attribute(the_class, scratch_class);
if (err != JVMTI_ERROR_NONE) {
return err;
}
// Check whether class modifiers are the same.
jushort old_flags = (jushort) the_class->access_flags().get_flags();
jushort new_flags = (jushort) scratch_class->access_flags().get_flags();
@ -1792,6 +1857,12 @@ bool VM_RedefineClasses::rewrite_cp_refs(InstanceKlass* scratch_class,
return false;
}
// rewrite constant pool references in the PermittedSubclasses attribute:
if (!rewrite_cp_refs_in_permitted_subclasses_attribute(scratch_class)) {
// propagate failure back to caller
return false;
}
// rewrite constant pool references in the methods:
if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) {
// propagate failure back to caller
@ -1930,6 +2001,19 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_record_attribute(
return true;
}
// Rewrite constant pool references in the PermittedSubclasses attribute.
bool VM_RedefineClasses::rewrite_cp_refs_in_permitted_subclasses_attribute(
InstanceKlass* scratch_class) {
Array<u2>* permitted_subclasses = scratch_class->permitted_subclasses();
assert(permitted_subclasses != NULL, "unexpected null permitted_subclasses");
for (int i = 0; i < permitted_subclasses->length(); i++) {
u2 cp_index = permitted_subclasses->at(i);
permitted_subclasses->at_put(i, find_new_index(cp_index));
}
return true;
}
// Rewrite constant pool references in the methods.
bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
InstanceKlass* scratch_class, TRAPS) {

View File

@ -479,6 +479,7 @@ class VM_RedefineClasses: public VM_Operation {
InstanceKlass* scratch_class, TRAPS);
bool rewrite_cp_refs_in_nest_attributes(InstanceKlass* scratch_class);
bool rewrite_cp_refs_in_record_attribute(InstanceKlass* scratch_class, TRAPS);
bool rewrite_cp_refs_in_permitted_subclasses_attribute(InstanceKlass* scratch_class);
void rewrite_cp_refs_in_method(methodHandle method,
methodHandle * new_method_p, TRAPS);
bool rewrite_cp_refs_in_methods(InstanceKlass* scratch_class, TRAPS);

View File

@ -201,6 +201,8 @@ public final class Class<T> implements java.io.Serializable,
private static final int ENUM = 0x00004000;
private static final int SYNTHETIC = 0x00001000;
private static final ClassDesc[] EMPTY_CLASS_DESC_ARRAY = new ClassDesc[0];
private static native void registerNatives();
static {
registerNatives();
@ -4382,4 +4384,69 @@ public final class Class<T> implements java.io.Serializable,
@HotSpotIntrinsicCandidate
public native boolean isHidden();
/**
* {@preview Associated with sealed classes, a preview feature of the Java language.
*
* This method is associated with <i>sealed classes</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Returns an array containing {@code ClassDesc} objects representing all the
* direct subclasses or direct implementation classes permitted to extend or implement this class or interface
* if it is sealed. If this {@code Class} object represents a primitive type, {@code void}, an array type,
* or a class or interface that is not sealed, an empty array is returned.
*
* @return an array of class descriptors of all the permitted subclasses of this class or interface
*
* @jls 8.1 Class Declarations
* @jls 9.1 Interface Declarations
* @since 15
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES, essentialAPI=false)
public ClassDesc[] permittedSubclasses() {
String[] subclassNames;
if (isArray() || isPrimitive() || (subclassNames = getPermittedSubclasses0()).length == 0) {
return EMPTY_CLASS_DESC_ARRAY;
}
ClassDesc[] constants = new ClassDesc[subclassNames.length];
int i = 0;
for (String subclassName : subclassNames) {
try {
constants[i++] = ClassDesc.of(subclassName.replace('/', '.'));
} catch (IllegalArgumentException iae) {
throw new InternalError("Invalid type in permitted subclasses information: " + subclassName, iae);
}
}
return constants;
}
/**
* * {@preview Associated with sealed classes, a preview feature of the Java language.
*
* This method is associated with <i>sealed classes</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Returns {@code true} if and only if this {@code Class} object represents a sealed class or interface.
* If this {@code Class} object represents a primitive type, {@code void}, or an array type, this method returns
* {@code false}.
*
* @return {@code true} if and only if this {@code Class} object represents a sealed class or interface.
*
* @jls 8.1 Class Declarations
* @jls 9.1 Interface Declarations
* @since 15
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES, essentialAPI=false)
@SuppressWarnings("preview")
public boolean isSealed() {
if (isArray() || isPrimitive()) {
return false;
}
return permittedSubclasses().length != 0;
}
private native String[] getPermittedSubclasses0();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 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
@ -63,6 +63,7 @@ public @interface PreviewFeature {
// necessary for PreviewFeature in JDK 15 to declare the enum constant.
TEXT_BLOCKS,
RECORDS,
SEALED_CLASSES,
;
}
}

View File

@ -499,8 +499,8 @@ public class ClassReader {
String nestHostClass = null;
// - The offset of the NestMembers attribute, or 0.
int nestMembersOffset = 0;
// - The offset of the PermittedSubtypes attribute, or 0
int permittedSubtypesOffset = 0;
// - The offset of the PermittedSubclasses attribute, or 0
int permittedSubclassesOffset = 0;
// - The offset of the Record attribute, or 0.
int recordOffset = 0;
// - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
@ -525,8 +525,8 @@ public class ClassReader {
nestHostClass = readClass(currentAttributeOffset, charBuffer);
} else if (Constants.NEST_MEMBERS.equals(attributeName)) {
nestMembersOffset = currentAttributeOffset;
} else if (Constants.PERMITTED_SUBTYPES.equals(attributeName)) {
permittedSubtypesOffset = currentAttributeOffset;
} else if (Constants.PERMITTED_SUBCLASSES.equals(attributeName)) {
permittedSubclassesOffset = currentAttributeOffset;
} else if (Constants.SIGNATURE.equals(attributeName)) {
signature = readUTF8(currentAttributeOffset, charBuffer);
} else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
@ -704,14 +704,14 @@ public class ClassReader {
}
}
// Visit the PermittedSubtypes attribute.
if (permittedSubtypesOffset != 0) {
int numberOfPermittedSubtypes = readUnsignedShort(permittedSubtypesOffset);
int currentPermittedSubtypeOffset = permittedSubtypesOffset + 2;
while (numberOfPermittedSubtypes-- > 0) {
classVisitor.visitPermittedSubtypeExperimental(
readClass(currentPermittedSubtypeOffset, charBuffer));
currentPermittedSubtypeOffset += 2;
// Visit the PermittedSubclasses attribute.
if (permittedSubclassesOffset != 0) {
int numberOfPermittedSubclasses = readUnsignedShort(permittedSubclassesOffset);
int currentPermittedSubclassOffset = permittedSubclassesOffset + 2;
while (numberOfPermittedSubclasses-- > 0) {
classVisitor.visitPermittedSubclassExperimental(
readClass(currentPermittedSubclassOffset, charBuffer));
currentPermittedSubclassOffset += 2;
}
}

View File

@ -61,7 +61,7 @@ package jdk.internal.org.objectweb.asm;
/**
* A visitor to visit a Java class. The methods of this class must be called in the following order:
* {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
* visitPermittedSubtype} ][ {@code visitOuterClass} ] ( {@code visitAnnotation} | {@code
* visitPermittedSubclass} ][ {@code visitOuterClass} ] ( {@code visitAnnotation} | {@code
* visitTypeAnnotation} | {@code visitAttribute} )* ( {@code visitNestMember} | {@code
* visitInnerClass} | {@code visitField} | {@code visitMethod} )* {@code visitEnd}.
*
@ -287,19 +287,19 @@ public abstract class ClassVisitor {
/**
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
* will break existing code using it</b>. Visits a permitted subtypes. A permitted subtypes is one
* of the allowed subtypes of the current class.
* will break existing code using it</b>. Visits a permitted subclass. A permitted subclass is one
* of the allowed subclasses of the current class.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @param permittedSubclass the internal name of a permitted subclass.
* @deprecated this API is experimental.
*/
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
if (api != Opcodes.ASM9_EXPERIMENTAL) {
throw new UnsupportedOperationException("This feature requires ASM9_EXPERIMENTAL");
}
if (cv != null) {
cv.visitPermittedSubtypeExperimental(permittedSubtype);
cv.visitPermittedSubclassExperimental(permittedSubclass);
}
}

View File

@ -208,11 +208,11 @@ public class ClassWriter extends ClassVisitor {
/** The 'classes' array of the NestMembers attribute, or {@literal null}. */
private ByteVector nestMemberClasses;
/** The number_of_classes field of the PermittedSubtypes attribute, or 0. */
private int numberOfPermittedSubtypeClasses;
/** The number_of_classes field of the PermittedSubclasses attribute, or 0. */
private int numberOfPermittedSubclassClasses;
/** The 'classes' array of the PermittedSubtypes attribute, or {@literal null}. */
private ByteVector permittedSubtypeClasses;
/** The 'classes' array of the PermittedSubclasses attribute, or {@literal null}. */
private ByteVector permittedSubclassClasses;
/**
* The record components of this class, stored in a linked list of {@link RecordComponentWriter}
@ -406,17 +406,17 @@ public class ClassWriter extends ClassVisitor {
/**
* <b>Experimental, use at your own risk.</b>
*
* @param permittedSubtype the internal name of a permitted subtype.
* @param permittedSubclass the internal name of a permitted subclass.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public final void visitPermittedSubtypeExperimental(final String permittedSubtype) {
if (permittedSubtypeClasses == null) {
permittedSubtypeClasses = new ByteVector();
public final void visitPermittedSubclassExperimental(final String permittedSubclass) {
if (permittedSubclassClasses == null) {
permittedSubclassClasses = new ByteVector();
}
++numberOfPermittedSubtypeClasses;
permittedSubtypeClasses.putShort(symbolTable.addConstantClass(permittedSubtype).index);
++numberOfPermittedSubclassClasses;
permittedSubclassClasses.putShort(symbolTable.addConstantClass(permittedSubclass).index);
}
@Override
@ -607,10 +607,10 @@ public class ClassWriter extends ClassVisitor {
size += 8 + nestMemberClasses.length;
symbolTable.addConstantUtf8(Constants.NEST_MEMBERS);
}
if (permittedSubtypeClasses != null) {
if (permittedSubclassClasses != null) {
++attributesCount;
size += 8 + permittedSubtypeClasses.length;
symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES);
size += 8 + permittedSubclassClasses.length;
symbolTable.addConstantUtf8(Constants.PERMITTED_SUBCLASSES);
}
int recordComponentCount = 0;
int recordSize = 0;
@ -729,12 +729,12 @@ public class ClassWriter extends ClassVisitor {
.putShort(numberOfNestMemberClasses)
.putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length);
}
if (permittedSubtypeClasses != null) {
if (permittedSubclassClasses != null) {
result
.putShort(symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES))
.putInt(permittedSubtypeClasses.length + 2)
.putShort(numberOfPermittedSubtypeClasses)
.putByteArray(permittedSubtypeClasses.data, 0, permittedSubtypeClasses.length);
.putShort(symbolTable.addConstantUtf8(Constants.PERMITTED_SUBCLASSES))
.putInt(permittedSubclassClasses.length + 2)
.putShort(numberOfPermittedSubclassClasses)
.putByteArray(permittedSubclassClasses.data, 0, permittedSubclassClasses.length);
}
if ((accessFlags & Opcodes.ACC_RECORD) != 0 || firstRecordComponent != null) {
result
@ -783,8 +783,8 @@ public class ClassWriter extends ClassVisitor {
nestHostClassIndex = 0;
numberOfNestMemberClasses = 0;
nestMemberClasses = null;
numberOfPermittedSubtypeClasses = 0;
permittedSubtypeClasses = null;
numberOfPermittedSubclassClasses = 0;
permittedSubclassClasses = null;
firstRecordComponent = null;
lastRecordComponent = null;
firstAttribute = null;

View File

@ -104,7 +104,7 @@ final class Constants {
static final String MODULE_MAIN_CLASS = "ModuleMainClass";
static final String NEST_HOST = "NestHost";
static final String NEST_MEMBERS = "NestMembers";
static final String PERMITTED_SUBTYPES = "PermittedSubtypes";
static final String PERMITTED_SUBCLASSES = "PermittedSubclasses";
static final String RECORD = "Record";
// ASM specific access flags.

View File

@ -252,13 +252,13 @@ public class ClassRemapper extends ClassVisitor {
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @param permittedSubclass the internal name of a permitted subclass.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
super.visitPermittedSubtypeExperimental(remapper.mapType(permittedSubtype));
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
super.visitPermittedSubclassExperimental(remapper.mapType(permittedSubclass));
}
/**

View File

@ -160,12 +160,12 @@ public class ClassNode extends ClassVisitor {
/**
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
* will break existing code using it</b>. The internal names of the permitted subtypes of this
* will break existing code using it</b>. The internal names of the permitted subclasses of this
* class. May be {@literal null}.
*
* @deprecated this API is experimental.
*/
@Deprecated public List<String> permittedSubtypesExperimental;
@Deprecated public List<String> permittedSubclassesExperimental;
/** The record components of this class. May be {@literal null}. */
public List<RecordComponentNode> recordComponents;
@ -284,13 +284,13 @@ public class ClassNode extends ClassVisitor {
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @param permittedSubclass the internal name of a permitted subclass.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
permittedSubtypesExperimental = Util.add(permittedSubtypesExperimental, permittedSubtype);
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
permittedSubclassesExperimental = Util.add(permittedSubclassesExperimental, permittedSubclass);
}
@Override
@ -351,7 +351,7 @@ public class ClassNode extends ClassVisitor {
*/
@SuppressWarnings("deprecation")
public void check(final int api) {
if (api != Opcodes.ASM9_EXPERIMENTAL && permittedSubtypesExperimental != null) {
if (api != Opcodes.ASM9_EXPERIMENTAL && permittedSubclassesExperimental != null) {
throw new UnsupportedClassVersionException();
}
if (api < Opcodes.ASM8 && ((access & Opcodes.ACC_RECORD) != 0 || recordComponents != null)) {
@ -473,10 +473,10 @@ public class ClassNode extends ClassVisitor {
classVisitor.visitNestMember(nestMembers.get(i));
}
}
// Visit the permitted subtypes.
if (permittedSubtypesExperimental != null) {
for (int i = 0, n = permittedSubtypesExperimental.size(); i < n; ++i) {
classVisitor.visitPermittedSubtypeExperimental(permittedSubtypesExperimental.get(i));
// Visit the permitted subclass.
if (permittedSubclassesExperimental != null) {
for (int i = 0, n = permittedSubclassesExperimental.size(); i < n; ++i) {
classVisitor.visitPermittedSubclassExperimental(permittedSubclassesExperimental.get(i));
}
}
// Visit the inner classes.

View File

@ -357,15 +357,15 @@ public class ASMifier extends Printer {
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @param permittedSubclass the internal name of a permitted subclass.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
stringBuilder.setLength(0);
stringBuilder.append("classWriter.visitPermittedSubtypeExperimental(");
appendConstant(permittedSubtype);
stringBuilder.append("classWriter.visitPermittedSubclassExperimental(");
appendConstant(permittedSubclass);
stringBuilder.append(END_PARAMETERS);
text.add(stringBuilder.toString());
}

View File

@ -356,15 +356,15 @@ public class CheckClassAdapter extends ClassVisitor {
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @param permittedSubclass the internal name of a permitted subclass.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
checkState();
CheckMethodAdapter.checkInternalName(version, permittedSubtype, "permittedSubtype");
super.visitPermittedSubtypeExperimental(permittedSubtype);
CheckMethodAdapter.checkInternalName(version, permittedSubclass, "permittedSubclass");
super.visitPermittedSubclassExperimental(permittedSubclass);
}
@Override

View File

@ -488,15 +488,15 @@ public abstract class Printer {
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
* will break existing code using it</b>.
*
* <p>Visits a permitted subtypes. A permitted subtypes is one of the allowed subtypes of the
* <p>Visits a permitted subclass. A permitted subtclass is one of the allowed subclasses of the
* current class. See {@link
* jdk.internal.org.objectweb.asm.ClassVisitor#visitPermittedSubtypeExperimental(String)}.
* jdk.internal.org.objectweb.asm.ClassVisitor#visitPermittedSubclassExperimental(String)}.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @param permittedSubclass the internal name of a permitted subclass.
* @deprecated this API is experimental.
*/
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
}

View File

@ -340,15 +340,15 @@ public class Textifier extends Printer {
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @param permittedSubclass the internal name of a permitted subclass.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
stringBuilder.setLength(0);
stringBuilder.append(tab).append("PERMITTEDSUBTYPE ");
appendDescriptor(INTERNAL_NAME, permittedSubtype);
stringBuilder.append(tab).append("PERMITTEDSUBCLASS ");
appendDescriptor(INTERNAL_NAME, permittedSubclass);
stringBuilder.append('\n');
text.add(stringBuilder.toString());
}

View File

@ -222,14 +222,14 @@ public final class TraceClassVisitor extends ClassVisitor {
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @param permittedSubclass the internal name of a permitted subclass.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
p.visitPermittedSubtypeExperimental(permittedSubtype);
super.visitPermittedSubtypeExperimental(permittedSubtype);
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
p.visitPermittedSubclassExperimental(permittedSubclass);
super.visitPermittedSubclassExperimental(permittedSubclass);
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 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
@ -81,6 +81,7 @@ static JNINativeMethod methods[] = {
{"getNestMembers0", "()[" CLS, (void *)&JVM_GetNestMembers},
{"getRecordComponents0", "()[" RC, (void *)&JVM_GetRecordComponents},
{"isRecord0", "()Z", (void *)&JVM_IsRecord},
{"getPermittedSubclasses0", "()[" STR, (void *)&JVM_GetPermittedSubclasses},
};
#undef OBJ

View File

@ -421,6 +421,10 @@ public enum SourceVersion {
case "_":
return version.compareTo(RELEASE_9) >= 0;
// case "non-sealed": can be added once it is a keyword only
// dependent on release and not also preview features being
// enabled.
// Keywords common across versions
// Modifiers

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -59,6 +59,40 @@ public enum Modifier {
*/
DEFAULT,
/** The modifier {@code static} */ STATIC,
/**
* {@preview Associated with sealed classes, a preview feature of the Java language.
*
* This enum constant is associated with <i>sealed classes</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* The modifier {@code sealed}
* @since 15
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
essentialAPI=false)
SEALED,
/**
* {@preview Associated with sealed classes, a preview feature of the Java language.
*
* This enum constant is associated with <i>sealed classes</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* The modifier {@code non-sealed}
* @since 15
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
essentialAPI=false)
NON_SEALED {
public String toString() {
return "non-sealed";
}
},
/** The modifier {@code final} */ FINAL,
/** The modifier {@code transient} */ TRANSIENT,
/** The modifier {@code volatile} */ VOLATILE,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -204,6 +204,29 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
return List.of();
}
/**
* {@preview Associated with sealed classes, a preview feature of the Java language.
*
* This method is associated with <i>sealed classes</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
* Returns the permitted classes of this type element in
* declaration order.
*
* @implSpec The default implementations of this method returns an
* empty and unmodifiable list.
*
* @return the permitted classes, or an empty list if there are none
*
* @since 15
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
essentialAPI=false)
default List<? extends TypeMirror> getPermittedSubclasses() {
return List.of();
}
/**
* Returns the package of a top-level type and returns the
* immediately lexically enclosing element for a {@linkplain

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -216,7 +216,7 @@ createThrowableFromJVMTIErrorCode(JNIEnv * jnienv, jvmtiError errorCode) {
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED:
throwableClassName = "java/lang/UnsupportedOperationException";
message = "class redefinition failed: attempted to change the class NestHost, NestMembers, or Record attribute";
message = "class redefinition failed: attempted to change the class NestHost, NestMembers, Record, or PermittedSubclasses attribute";
break;
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -25,6 +25,7 @@
package com.sun.source.tree;
import java.util.Collections;
import java.util.List;
import javax.lang.model.element.Name;
@ -85,6 +86,28 @@ public interface ClassTree extends StatementTree {
*/
List<? extends Tree> getImplementsClause();
/**
* {@preview Associated with sealed classes, a preview feature of the Java language.
*
* This method is associated with <i>sealed classes</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Returns the subclasses permitted by this type declaration.
*
* @implSpec this implementation returns an empty list
*
* @return the subclasses
*
* @since 15
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
essentialAPI=false)
default List<? extends Tree> getPermitsClause() {
return List.of();
}
/**
* Returns the members declared in this type declaration.
* @return the members

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -178,12 +178,14 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
* @param p {@inheritDoc}
* @return the result of scanning
*/
@SuppressWarnings("preview")
@Override
public R visitClass(ClassTree node, P p) {
R r = scan(node.getModifiers(), p);
r = scanAndReduce(node.getTypeParameters(), p, r);
r = scanAndReduce(node.getExtendsClause(), p, r);
r = scanAndReduce(node.getImplementsClause(), p, r);
r = scanAndReduce(node.getPermitsClause(), p, r);
r = scanAndReduce(node.getMembers(), p, r);
return r;
}

View File

@ -366,6 +366,16 @@ public class Flags {
*/
public static final int GENERATED_MEMBER = 1<<24; // MethodSymbols and VarSymbols
/**
* Flag to indicate sealed class/interface declaration.
*/
public static final long SEALED = 1L<<62; // ClassSymbols
/**
* Flag to indicate that the class/interface was declared with the non-sealed modifier.
*/
public static final long NON_SEALED = 1L<<63; // ClassSymbols
/** Modifier masks.
*/
public static final int
@ -385,14 +395,16 @@ public class Flags {
RecordMethodFlags = AccessFlags | ABSTRACT | STATIC |
SYNCHRONIZED | FINAL | STRICTFP;
public static final long
ExtendedStandardFlags = (long)StandardFlags | DEFAULT,
ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT,
ExtendedStandardFlags = (long)StandardFlags | DEFAULT | SEALED | NON_SEALED,
ExtendedMemberClassFlags = (long)MemberClassFlags | SEALED | NON_SEALED,
ExtendedClassFlags = (long)ClassFlags | SEALED | NON_SEALED,
ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT | SEALED | NON_SEALED,
InterfaceMethodMask = ABSTRACT | PRIVATE | STATIC | PUBLIC | STRICTFP | DEFAULT,
AnnotationTypeElementMask = ABSTRACT | PUBLIC,
LocalVarFlags = FINAL | PARAMETER,
ReceiverParamFlags = PARAMETER;
@SuppressWarnings("preview")
public static Set<Modifier> asModifierSet(long flags) {
Set<Modifier> modifiers = modifierSets.get(flags);
if (modifiers == null) {
@ -402,6 +414,9 @@ public class Flags {
if (0 != (flags & PRIVATE)) modifiers.add(Modifier.PRIVATE);
if (0 != (flags & ABSTRACT)) modifiers.add(Modifier.ABSTRACT);
if (0 != (flags & STATIC)) modifiers.add(Modifier.STATIC);
if (0 != (flags & SEALED)) modifiers.add(Modifier.SEALED);
if (0 != (flags & NON_SEALED))
modifiers.add(Modifier.NON_SEALED);
if (0 != (flags & FINAL)) modifiers.add(Modifier.FINAL);
if (0 != (flags & TRANSIENT)) modifiers.add(Modifier.TRANSIENT);
if (0 != (flags & VOLATILE)) modifiers.add(Modifier.VOLATILE);
@ -492,7 +507,14 @@ public class Flags {
PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API),
MATCH_BINDING(Flags.MATCH_BINDING),
MATCH_BINDING_TO_OUTER(Flags.MATCH_BINDING_TO_OUTER),
RECORD(Flags.RECORD);
RECORD(Flags.RECORD),
SEALED(Flags.SEALED),
NON_SEALED(Flags.NON_SEALED) {
@Override
public String toString() {
return "non-sealed";
}
};
Flag(long flag) {
this.value = flag;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 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
@ -167,7 +167,8 @@ public class Preview {
public boolean isPreview(Feature feature) {
if (feature == Feature.PATTERN_MATCHING_IN_INSTANCEOF ||
feature == Feature.REIFIABLE_TYPES_INSTANCEOF ||
feature == Feature.RECORDS)
feature == Feature.RECORDS ||
feature == Feature.SEALED_CLASSES)
return true;
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
//When real preview features will be added, this method can be implemented to return 'true'

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 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
@ -209,6 +209,7 @@ public enum Source {
PATTERN_MATCHING_IN_INSTANCEOF(JDK15, Fragments.FeaturePatternMatchingInstanceof, DiagKind.NORMAL),
REIFIABLE_TYPES_INSTANCEOF(JDK15, Fragments.FeatureReifiableTypesInstanceof, DiagKind.PLURAL),
RECORDS(JDK15, Fragments.FeatureRecords, DiagKind.PLURAL),
SEALED_CLASSES(JDK15, Fragments.FeatureSealedClasses, DiagKind.PLURAL),
;
enum DiagKind {

View File

@ -422,6 +422,14 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
return (flags() & ENUM) != 0;
}
public boolean isSealed() {
return (flags_field & SEALED) != 0;
}
public boolean isNonSealed() {
return (flags_field & NON_SEALED) != 0;
}
public boolean isFinal() {
return (flags_field & FINAL) != 0;
}
@ -1285,6 +1293,13 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
*/
private List<RecordComponent> recordComponents = List.nil();
// sealed classes related fields
/** The classes, or interfaces, permitted to extend this class, or interface
*/
public List<Symbol> permitted;
public boolean isPermittedExplicit = false;
public ClassSymbol(long flags, Name name, Type type, Symbol owner) {
super(TYP, flags, name, type, owner);
this.members_field = null;
@ -1293,6 +1308,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
this.sourcefile = null;
this.classfile = null;
this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
this.permitted = List.nil();
}
public ClassSymbol(long flags, Name name, Symbol owner) {
@ -1601,6 +1617,11 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
public boolean isRecord() {
return (flags_field & RECORD) != 0;
}
@DefinedBy(Api.LANGUAGE_MODEL)
public List<Type> getPermittedSubclasses() {
return permitted.map(s -> s.type);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -730,7 +730,7 @@ public class Types {
*/
public FunctionDescriptor findDescriptorInternal(TypeSymbol origin,
CompoundScope membersCache) throws FunctionDescriptorLookupError {
if (!origin.isInterface() || (origin.flags() & ANNOTATION) != 0) {
if (!origin.isInterface() || (origin.flags() & ANNOTATION) != 0 || origin.isSealed()) {
//t must be an interface
throw failure("not.a.functional.intf", origin);
}

View File

@ -5027,6 +5027,90 @@ public class Attr extends JCTree.Visitor {
// Get environment current at the point of class definition.
Env<AttrContext> env = typeEnvs.get(c);
if (c.isSealed() &&
!c.isEnum() &&
!c.isPermittedExplicit &&
c.permitted.isEmpty()) {
log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.SealedClassMustHaveSubclasses);
}
if (c.isSealed()) {
Set<Symbol> permittedTypes = new HashSet<>();
boolean sealedInUnnamed = c.packge().modle == syms.unnamedModule || c.packge().modle == syms.noModule;
for (Symbol subTypeSym : c.permitted) {
boolean isTypeVar = false;
if (subTypeSym.type.getTag() == TYPEVAR) {
isTypeVar = true; //error recovery
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree),
Errors.InvalidPermitsClause(Fragments.IsATypeVariable(subTypeSym.type)));
}
if (subTypeSym.isAnonymous() && !c.isEnum()) {
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), Errors.CantInheritFromSealed(c));
}
if (permittedTypes.contains(subTypeSym)) {
DiagnosticPosition pos =
env.enclClass.permitting.stream()
.filter(permittedExpr -> TreeInfo.diagnosticPositionFor(subTypeSym, permittedExpr, true) != null)
.limit(2).collect(List.collector()).get(1);
log.error(pos, Errors.InvalidPermitsClause(Fragments.IsDuplicated(subTypeSym.type)));
} else {
permittedTypes.add(subTypeSym);
}
if (sealedInUnnamed) {
if (subTypeSym.packge() != c.packge()) {
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), Errors.CantInheritFromSealed(c));
}
} else if (subTypeSym.packge().modle != c.packge().modle) {
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), Errors.CantInheritFromSealed(c));
}
if (subTypeSym == c.type.tsym || types.isSuperType(subTypeSym.type, c.type)) {
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, ((JCClassDecl)env.tree).permitting),
Errors.InvalidPermitsClause(
subTypeSym == c.type.tsym ?
Fragments.MustNotBeSameClass :
Fragments.MustNotBeSupertype(subTypeSym.type)
)
);
} else if (!isTypeVar) {
boolean thisIsASuper = types.directSupertypes(subTypeSym.type)
.stream()
.anyMatch(d -> d.tsym == c);
if (!thisIsASuper) {
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree),
Errors.InvalidPermitsClause(Fragments.DoesntExtendSealed(subTypeSym.type)));
}
}
}
}
List<ClassSymbol> sealedSupers = types.directSupertypes(c.type)
.stream()
.filter(s -> s.tsym.isSealed())
.map(s -> (ClassSymbol) s.tsym)
.collect(List.collector());
if (sealedSupers.isEmpty()) {
if ((c.flags_field & Flags.NON_SEALED) != 0) {
log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.NonSealedWithNoSealedSupertype(c));
}
} else {
if (c.isLocal() && !c.isEnum()) {
log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.LocalClassesCantExtendSealed);
}
for (ClassSymbol supertypeSym : sealedSupers) {
if (!supertypeSym.permitted.contains(c.type.tsym)) {
log.error(TreeInfo.diagnosticPositionFor(c.type.tsym, env.tree), Errors.CantInheritFromSealed(supertypeSym));
}
}
if (!c.isNonSealed() && !c.isFinal() && !c.isSealed()) {
log.error(TreeInfo.diagnosticPositionFor(c, env.tree),
c.isInterface() ?
Errors.NonSealedOrSealedExpected :
Errors.NonSealedSealedOrFinalExpected);
}
}
// The info.lint field in the envs stored in typeEnvs is deliberately uninitialized,
// because the annotations were not available at the time the env was created. Therefore,
// we look up the environment chain for the first enclosing environment for which the

View File

@ -160,6 +160,8 @@ public class Check {
allowRecords = (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) &&
Feature.RECORDS.allowedInSource(source);
allowSealed = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
Feature.SEALED_CLASSES.allowedInSource(source);
}
/** Character for synthetic names
@ -195,6 +197,10 @@ public class Check {
*/
private final boolean allowRecords;
/** Are sealed classes allowed
*/
private final boolean allowSealed;
/* *************************************************************************
* Errors and Warnings
**************************************************************************/
@ -1222,7 +1228,7 @@ public class Check {
}
}
} else if (sym.owner.kind == TYP) {
mask = (flags & RECORD) != 0 ? MemberRecordFlags : MemberClassFlags;
mask = (flags & RECORD) != 0 ? MemberRecordFlags : ExtendedMemberClassFlags;
if (sym.owner.owner.kind == PCK ||
(sym.owner.flags_field & STATIC) != 0)
mask |= STATIC;
@ -1232,14 +1238,14 @@ public class Check {
// Nested interfaces and enums are always STATIC (Spec ???)
if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
} else {
mask = ClassFlags;
mask = ExtendedClassFlags;
}
// Interfaces are always ABSTRACT
if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
if ((flags & ENUM) != 0) {
// enums can't be declared abstract or final
mask &= ~(ABSTRACT | FINAL);
// enums can't be declared abstract, final, sealed or non-sealed
mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED);
implicit |= implicitEnumFinalFlag(tree);
}
if ((flags & RECORD) != 0) {
@ -1294,7 +1300,13 @@ public class Check {
(sym.kind == TYP ||
checkDisjoint(pos, flags,
ABSTRACT | NATIVE,
STRICTFP))) {
STRICTFP))
&& checkDisjoint(pos, flags,
FINAL,
SEALED | NON_SEALED)
&& checkDisjoint(pos, flags,
SEALED,
FINAL | NON_SEALED)) {
// skip
}
return flags & (mask | ~ExtendedStandardFlags) | implicit;
@ -1334,7 +1346,7 @@ public class Check {
JCClassDecl cdef = (JCClassDecl) tree;
for (JCTree defs: cdef.defs) {
defs.accept(sts);
if (sts.specialized) return 0;
if (sts.specialized) return allowSealed ? SEALED : 0;
}
return FINAL;
}

View File

@ -25,9 +25,11 @@
package com.sun.tools.javac.comp;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import javax.tools.JavaFileObject;
@ -711,6 +713,15 @@ public class TypeEnter implements Completer {
}
}
// Determine permits.
ListBuffer<Symbol> permittedSubtypeSymbols = new ListBuffer<>();
List<JCExpression> permittedTrees = tree.permitting;
for (JCExpression permitted : permittedTrees) {
permitted = clearTypeParams(permitted);
Type pt = attr.attribBase(permitted, baseEnv, false, false, false);
permittedSubtypeSymbols.append(pt.tsym);
}
if ((sym.flags_field & ANNOTATION) != 0) {
ct.interfaces_field = List.of(syms.annotationType);
ct.all_interfaces_field = ct.interfaces_field;
@ -719,6 +730,9 @@ public class TypeEnter implements Completer {
ct.all_interfaces_field = (all_interfaces == null)
? ct.interfaces_field : all_interfaces.toList();
}
sym.permitted = permittedSubtypeSymbols.toList();
sym.isPermittedExplicit = !permittedSubtypeSymbols.isEmpty();
}
//where:
protected JCExpression clearTypeParams(JCExpression superType) {
@ -729,7 +743,7 @@ public class TypeEnter implements Completer {
private final class HierarchyPhase extends AbstractHeaderPhase implements Completer {
public HierarchyPhase() {
super(CompletionCause.HIERARCHY_PHASE, new HeaderPhase());
super(CompletionCause.HIERARCHY_PHASE, new PermitsPhase());
}
@Override
@ -803,6 +817,33 @@ public class TypeEnter implements Completer {
}
private final class PermitsPhase extends AbstractHeaderPhase {
public PermitsPhase() {
super(CompletionCause.HIERARCHY_PHASE, new HeaderPhase());
}
@Override
protected void runPhase(Env<AttrContext> env) {
JCClassDecl tree = env.enclClass;
if (!tree.sym.isAnonymous() || tree.sym.isEnum()) {
for (Type supertype : types.directSupertypes(tree.sym.type)) {
if (supertype.tsym.kind == TYP) {
ClassSymbol supClass = (ClassSymbol) supertype.tsym;
Env<AttrContext> supClassEnv = enter.getEnv(supClass);
if (supClass.isSealed() &&
!supClass.isPermittedExplicit &&
supClassEnv != null &&
supClassEnv.toplevel == env.toplevel) {
supClass.permitted = supClass.permitted.append(tree.sym);
}
}
}
}
}
}
private final class HeaderPhase extends AbstractHeaderPhase {
public HeaderPhase() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 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
@ -105,6 +105,10 @@ public class ClassReader {
*/
boolean allowModules;
/** Switch: allow sealed
*/
boolean allowSealedTypes;
/** Switch: allow records
*/
boolean allowRecords;
@ -270,6 +274,8 @@ public class ClassReader {
allowModules = Feature.MODULES.allowedInSource(source);
allowRecords = (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) &&
Feature.RECORDS.allowedInSource(source);
allowSealedTypes = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
Feature.SEALED_CLASSES.allowedInSource(source);
saveParameterNames = options.isSet(PARAMETERS);
@ -1202,7 +1208,23 @@ public class ClassReader {
}
bp = bp + attrLen;
}
}
},
new AttributeReader(names.PermittedSubclasses, V59, CLASS_ATTRIBUTE) {
@Override
protected boolean accepts(AttributeKind kind) {
return super.accepts(kind) && allowSealedTypes;
}
protected void read(Symbol sym, int attrLen) {
if (sym.kind == TYP) {
ListBuffer<Symbol> subtypes = new ListBuffer<>();
int numberOfPermittedSubtypes = nextChar();
for (int i = 0; i < numberOfPermittedSubtypes; i++) {
subtypes.add(poolReader.getClass(nextChar()));
}
((ClassSymbol)sym).permitted = subtypes.toList();
}
}
},
};
for (AttributeReader r: readers)
@ -2470,6 +2492,10 @@ public class ClassReader {
for (int i = 0; i < methodCount; i++) skipMember();
readClassAttrs(c);
if (c.permitted != null && !c.permitted.isEmpty()) {
c.flags_field |= SEALED;
}
// reset and read rest of classinfo
bp = startbp;
int n = nextChar();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 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
@ -909,6 +909,21 @@ public class ClassWriter extends ClassFile {
}
}
/** Write "PermittedSubclasses" attribute.
*/
int writePermittedSubclassesIfNeeded(ClassSymbol csym) {
if (csym.permitted.nonEmpty()) {
int alenIdx = writeAttr(names.PermittedSubclasses);
databuf.appendChar(csym.permitted.size());
for (Symbol c : csym.permitted) {
databuf.appendChar(poolWriter.putClass((ClassSymbol) c));
}
endAttr(alenIdx);
return 1;
}
return 0;
}
/** Write "bootstrapMethods" attribute.
*/
void writeBootstrapMethods() {
@ -1635,6 +1650,10 @@ public class ClassWriter extends ClassFile {
acount += writeRecordAttribute(c);
}
if (target.hasSealedClasses()) {
acount += writePermittedSubclassesIfNeeded(c);
}
if (!poolWriter.bootstrapMethods.isEmpty()) {
writeBootstrapMethods();
acount++;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 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
@ -183,4 +183,9 @@ public enum Target {
return compareTo(JDK1_11) >= 0;
}
/** Does the target VM support sealed types
*/
public boolean hasSealedClasses() {
return compareTo(JDK1_15) >= 0;
}
}

View File

@ -186,6 +186,8 @@ public class JavacParser implements Parser {
Feature.SWITCH_EXPRESSION.allowedInSource(source);
this.allowRecords = (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) &&
Feature.RECORDS.allowedInSource(source);
this.allowSealedTypes = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
Feature.SEALED_CLASSES.allowedInSource(source);
}
protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
@ -223,6 +225,10 @@ public class JavacParser implements Parser {
*/
boolean allowRecords;
/** Switch: are sealed types allowed in this source level?
*/
boolean allowSealedTypes;
/** The type of the method receiver, as specified by a first "this" parameter.
*/
JCVariableDecl receiverParam;
@ -2623,6 +2629,19 @@ public class JavacParser implements Parser {
}
//else intentional fall-through
} else {
if (isNonSealedClassStart(true)) {
log.error(token.pos, Errors.SealedOrNonSealedLocalClassesNotAllowed);
nextToken();
nextToken();
nextToken();
return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), token.comment(CommentStyle.JAVADOC)));
} else if (isSealedClassStart(true)) {
checkSourceLevel(Feature.SEALED_CLASSES);
log.error(token.pos, Errors.SealedOrNonSealedLocalClassesNotAllowed);
nextToken();
return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), token.comment(CommentStyle.JAVADOC)));
}
}
}
if (isRecordStart() && allowRecords) {
@ -3072,6 +3091,20 @@ public class JavacParser implements Parser {
case MONKEYS_AT : flag = Flags.ANNOTATION; break;
case DEFAULT : checkSourceLevel(Feature.DEFAULT_METHODS); flag = Flags.DEFAULT; break;
case ERROR : flag = 0; nextToken(); break;
case IDENTIFIER : {
if (isNonSealedClassStart(false)) {
flag = Flags.NON_SEALED;
nextToken();
nextToken();
break;
}
if (isSealedClassStart(false)) {
checkSourceLevel(Feature.SEALED_CLASSES);
flag = Flags.SEALED;
break;
}
break loop;
}
default: break loop;
}
if ((flags & flag) != 0) log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.RepeatedModifier);
@ -3320,6 +3353,13 @@ public class JavacParser implements Parser {
log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK14));
}
}
if (name == names.sealed) {
if (allowSealedTypes) {
return Source.JDK15;
} else if (shouldWarn) {
log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));
}
}
return null;
}
@ -3714,9 +3754,18 @@ public class JavacParser implements Parser {
nextToken();
implementing = typeList();
}
List<JCExpression> permitting = List.nil();
if (allowSealedTypes && token.kind == IDENTIFIER && token.name() == names.permits) {
checkSourceLevel(Feature.SEALED_CLASSES);
if ((mods.flags & Flags.SEALED) == 0) {
log.error(token.pos, Errors.InvalidPermitsClause(Fragments.ClassIsNotSealed("class")));
}
nextToken();
permitting = qualidentList(false);
}
List<JCTree> defs = classInterfaceOrRecordBody(name, false, false);
JCClassDecl result = toP(F.at(pos).ClassDef(
mods, name, typarams, extending, implementing, defs));
mods, name, typarams, extending, implementing, permitting, defs));
attach(result, dc);
return result;
}
@ -3793,9 +3842,19 @@ public class JavacParser implements Parser {
nextToken();
extending = typeList();
}
List<JCTree> defs = classInterfaceOrRecordBody(name, true, false);
List<JCExpression> permitting = List.nil();
if (allowSealedTypes && token.kind == IDENTIFIER && token.name() == names.permits) {
checkSourceLevel(Feature.SEALED_CLASSES);
if ((mods.flags & Flags.SEALED) == 0) {
log.error(token.pos, Errors.InvalidPermitsClause(Fragments.ClassIsNotSealed("interface")));
}
nextToken();
permitting = typeList();
}
List<JCTree> defs;
defs = classInterfaceOrRecordBody(name, true, false);
JCClassDecl result = toP(F.at(pos).ClassDef(
mods, name, typarams, null, extending, defs));
mods, name, typarams, null, extending, permitting, defs));
attach(result, dc);
return result;
}
@ -4141,16 +4200,62 @@ public class JavacParser implements Parser {
}
protected boolean isRecordStart() {
if (token.kind == IDENTIFIER && token.name() == names.record &&
if (token.kind == IDENTIFIER && token.name() == names.record &&
(peekToken(TokenKind.IDENTIFIER, TokenKind.LPAREN) ||
peekToken(TokenKind.IDENTIFIER, TokenKind.EOF) ||
peekToken(TokenKind.IDENTIFIER, TokenKind.LT))) {
checkSourceLevel(Feature.RECORDS);
return true;
} else {
return false;
}
}
checkSourceLevel(Feature.RECORDS);
return true;
} else {
return false;
}
}
protected boolean isNonSealedClassStart(boolean local) {
if (isNonSealedIdentifier(token, 0)) {
Token next = S.token(3);
return allowedAfterSealedOrNonSealed(next, local, true);
}
return false;
}
protected boolean isNonSealedIdentifier(Token someToken, int lookAheadOffset) {
if (someToken.name() == names.non && peekToken(lookAheadOffset, TokenKind.SUB, TokenKind.IDENTIFIER)) {
Token tokenSub = S.token(lookAheadOffset + 1);
Token tokenSealed = S.token(lookAheadOffset + 2);
if (someToken.endPos == tokenSub.pos &&
tokenSub.endPos == tokenSealed.pos &&
tokenSealed.name() == names.sealed) {
checkSourceLevel(Feature.SEALED_CLASSES);
return true;
}
}
return false;
}
protected boolean isSealedClassStart(boolean local) {
if (token.name() == names.sealed) {
Token next = S.token(1);
if (allowedAfterSealedOrNonSealed(next, local, false)) {
checkSourceLevel(Feature.SEALED_CLASSES);
return true;
}
}
return false;
}
private boolean allowedAfterSealedOrNonSealed(Token next, boolean local, boolean currentIsNonSealed) {
return local ?
switch (next.kind) {
case MONKEYS_AT, ABSTRACT, FINAL, STRICTFP, CLASS, INTERFACE, ENUM -> true;
default -> false;
} :
switch (next.kind) {
case MONKEYS_AT, PUBLIC, PROTECTED, PRIVATE, ABSTRACT, STATIC, FINAL, STRICTFP, CLASS, INTERFACE, ENUM -> true;
case IDENTIFIER -> isNonSealedIdentifier(next, currentIsNonSealed ? 3 : 1) || next.name() == names.sealed;
default -> false;
};
}
/** MethodDeclaratorRest =
* FormalParameters BracketsOpt [THROWS TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -30,7 +30,6 @@ import javax.lang.model.*;
import javax.lang.model.element.*;
import static javax.lang.model.element.ElementKind.*;
import static javax.lang.model.element.NestingKind.*;
import static javax.lang.model.element.ModuleElement.DirectiveKind.*;
import static javax.lang.model.element.ModuleElement.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;
@ -39,7 +38,6 @@ import java.io.PrintWriter;
import java.io.Writer;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.sun.tools.javac.util.DefinedBy;
@ -248,6 +246,7 @@ public class PrintingProcessor extends AbstractProcessor {
}
printInterfaces(e);
printPermittedSubclasses(e);
}
writer.println(" {");
indentation++;
@ -472,6 +471,7 @@ public class PrintingProcessor extends AbstractProcessor {
case ENUM:
modifiers.remove(Modifier.FINAL);
modifiers.remove(Modifier.ABSTRACT);
modifiers.remove(Modifier.SEALED);
break;
case RECORD:
@ -602,6 +602,17 @@ public class PrintingProcessor extends AbstractProcessor {
}
}
private void printPermittedSubclasses(TypeElement e) {
List<? extends TypeMirror> subtypes = e.getPermittedSubclasses();
if (!subtypes.isEmpty()) { // could remove this check with more complicated joining call
writer.print(" permits ");
writer.print(subtypes
.stream()
.map(subtype -> subtype.toString())
.collect(Collectors.joining(", ")));
}
}
private void printThrows(ExecutableElement e) {
List<? extends TypeMirror> thrownTypes = e.getThrownTypes();
final int size = thrownTypes.size();

View File

@ -2933,6 +2933,9 @@ compiler.misc.feature.reifiable.types.instanceof=\
compiler.misc.feature.records=\
records
compiler.misc.feature.sealed.classes=\
sealed classes
compiler.warn.underscore.as.identifier=\
as of release 9, ''_'' is a keyword, and may not be used as an identifier
@ -3435,6 +3438,65 @@ compiler.err.switch.case.unexpected.statement=\
compiler.err.switch.mixing.case.types=\
different case kinds used in the switch
###
# errors related to sealed classes
# permits clause
# 0: fragment
compiler.err.invalid.permits.clause=\
invalid permits clause\n\
({0})
# 0: string
compiler.misc.class.is.not.sealed=\
{0} must be sealed
# 0: type
compiler.misc.is.a.type.variable=\
must not include type variables: {0}
# 0: type
compiler.misc.is.duplicated=\
must not contain duplicates: {0}
# 0: type
compiler.misc.doesnt.extend.sealed=\
subclass {0} must extend sealed class
compiler.misc.must.not.be.same.class=\
illegal self-reference in permits clause
# 0: type
compiler.misc.must.not.be.supertype=\
illegal reference to supertype {0}
# other sealed types related errors
compiler.err.sealed.class.must.have.subclasses=\
sealed class must have subclasses
# errors in subclasses of sealed classes
# 0: symbol
compiler.err.cant.inherit.from.sealed=\
class is not allowed to extend sealed class: {0}
# 0: symbol
compiler.err.non.sealed.with.no.sealed.supertype=\
non-sealed modifier not allowed here\n\
(class {0} does not have any sealed supertypes)
compiler.err.non.sealed.sealed.or.final.expected=\
sealed, non-sealed or final modifiers expected
compiler.err.non.sealed.or.sealed.expected=\
sealed or non-sealed modifiers expected
compiler.err.sealed.or.non.sealed.local.classes.not.allowed=\
sealed or non-sealed local classes are not allowed
compiler.err.local.classes.cant.extend.sealed=\
local classes must not extend sealed classes
###
# errors related to records

View File

@ -762,6 +762,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public JCExpression extending;
/** the interfaces implemented by this class */
public List<JCExpression> implementing;
/** the subclasses allowed to extend this class, if sealed */
public List<JCExpression> permitting;
/** all variables and methods defined in this class */
public List<JCTree> defs;
/** the symbol */
@ -771,6 +773,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
List<JCTypeParameter> typarams,
JCExpression extending,
List<JCExpression> implementing,
List<JCExpression> permitting,
List<JCTree> defs,
ClassSymbol sym)
{
@ -779,6 +782,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
this.typarams = typarams;
this.extending = extending;
this.implementing = implementing;
this.permitting = permitting;
this.defs = defs;
this.sym = sym;
}
@ -814,6 +818,11 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public List<JCExpression> getImplementsClause() {
return implementing;
}
@SuppressWarnings("removal")
@DefinedBy(Api.COMPILER_TREE)
public List<JCExpression> getPermitsClause() {
return permitting;
}
@DefinedBy(Api.COMPILER_TREE)
public List<JCTree> getMembers() {
return defs;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 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
@ -564,6 +564,10 @@ public class Pretty extends JCTree.Visitor {
print(" extends ");
printExprs(tree.implementing);
}
if (tree.permitting.nonEmpty()) {
print(" permits ");
printExprs(tree.permitting);
}
} else {
if ((tree.mods.flags & ENUM) != 0)
print("enum " + tree.name);
@ -578,6 +582,10 @@ public class Pretty extends JCTree.Visitor {
print(" implements ");
printExprs(tree.implementing);
}
if (tree.permitting.nonEmpty()) {
print(" permits ");
printExprs(tree.permitting);
}
}
print(" ");
if ((tree.mods.flags & ENUM) != 0) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 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
@ -692,49 +692,81 @@ public class TreeInfo {
/** Find the position for reporting an error about a symbol, where
* that symbol is defined somewhere in the given tree. */
public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree) {
JCTree decl = declarationFor(sym, tree);
return diagnosticPositionFor(sym, tree, false);
}
public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree, boolean returnNullIfNotFound) {
class DiagScanner extends DeclScanner {
DiagScanner(Symbol sym) {
super(sym);
}
public void visitIdent(JCIdent that) {
if (that.sym == sym) result = that;
else super.visitIdent(that);
}
public void visitSelect(JCFieldAccess that) {
if (that.sym == sym) result = that;
else super.visitSelect(that);
}
}
DiagScanner s = new DiagScanner(sym);
tree.accept(s);
JCTree decl = s.result;
if (decl == null && returnNullIfNotFound) { return null; }
return ((decl != null) ? decl : tree).pos();
}
public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final List<? extends JCTree> trees) {
return trees.stream().map(t -> TreeInfo.diagnosticPositionFor(sym, t)).filter(t -> t != null).findFirst().get();
}
private static class DeclScanner extends TreeScanner {
final Symbol sym;
DeclScanner(final Symbol sym) {
this.sym = sym;
}
JCTree result = null;
public void scan(JCTree tree) {
if (tree!=null && result==null)
tree.accept(this);
}
public void visitTopLevel(JCCompilationUnit that) {
if (that.packge == sym) result = that;
else super.visitTopLevel(that);
}
public void visitModuleDef(JCModuleDecl that) {
if (that.sym == sym) result = that;
// no need to scan within module declaration
}
public void visitPackageDef(JCPackageDecl that) {
if (that.packge == sym) result = that;
else super.visitPackageDef(that);
}
public void visitClassDef(JCClassDecl that) {
if (that.sym == sym) result = that;
else super.visitClassDef(that);
}
public void visitMethodDef(JCMethodDecl that) {
if (that.sym == sym) result = that;
else super.visitMethodDef(that);
}
public void visitVarDef(JCVariableDecl that) {
if (that.sym == sym) result = that;
else super.visitVarDef(that);
}
public void visitTypeParameter(JCTypeParameter that) {
if (that.type != null && that.type.tsym == sym) result = that;
else super.visitTypeParameter(that);
}
}
/** Find the declaration for a symbol, where
* that symbol is defined somewhere in the given tree. */
public static JCTree declarationFor(final Symbol sym, final JCTree tree) {
class DeclScanner extends TreeScanner {
JCTree result = null;
public void scan(JCTree tree) {
if (tree!=null && result==null)
tree.accept(this);
}
public void visitTopLevel(JCCompilationUnit that) {
if (that.packge == sym) result = that;
else super.visitTopLevel(that);
}
public void visitModuleDef(JCModuleDecl that) {
if (that.sym == sym) result = that;
// no need to scan within module declaration
}
public void visitPackageDef(JCPackageDecl that) {
if (that.packge == sym) result = that;
else super.visitPackageDef(that);
}
public void visitClassDef(JCClassDecl that) {
if (that.sym == sym) result = that;
else super.visitClassDef(that);
}
public void visitMethodDef(JCMethodDecl that) {
if (that.sym == sym) result = that;
else super.visitMethodDef(that);
}
public void visitVarDef(JCVariableDecl that) {
if (that.sym == sym) result = that;
else super.visitVarDef(that);
}
public void visitTypeParameter(JCTypeParameter that) {
if (that.type != null && that.type.tsym == sym) result = that;
else super.visitTypeParameter(that);
}
}
DeclScanner s = new DeclScanner();
DeclScanner s = new DeclScanner(sym);
tree.accept(s);
return s.result;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 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
@ -160,12 +160,24 @@ public class TreeMaker implements JCTree.Factory {
JCExpression extending,
List<JCExpression> implementing,
List<JCTree> defs)
{
return ClassDef(mods, name, typarams, extending, implementing, List.nil(), defs);
}
public JCClassDecl ClassDef(JCModifiers mods,
Name name,
List<JCTypeParameter> typarams,
JCExpression extending,
List<JCExpression> implementing,
List<JCExpression> permitting,
List<JCTree> defs)
{
JCClassDecl tree = new JCClassDecl(mods,
name,
typarams,
extending,
implementing,
permitting,
defs,
null);
tree.pos = pos;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -115,6 +115,7 @@ public class TreeScanner extends Visitor {
scan(tree.typarams);
scan(tree.extending);
scan(tree.implementing);
scan(tree.permitting);
scan(tree.defs);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -93,6 +93,7 @@ public abstract class Dependencies {
MEMBER_ENTER,
RECORD_PHASE,
MEMBERS_PHASE,
PERMITS_PHASE,
OTHER;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 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
@ -25,8 +25,6 @@
package com.sun.tools.javac.util;
import java.util.Set;
/**
* Access to the compiler's name table. Standard names are defined,
* as well as methods to create new names.
@ -161,6 +159,7 @@ public class Names {
public final Name Synthetic;
public final Name Value;
public final Name Varargs;
public final Name PermittedSubclasses;
// members of java.lang.annotation.ElementType
public final Name ANNOTATION_TYPE;
@ -203,6 +202,7 @@ public class Names {
public final Name bootstrap;
public final Name record;
public final Name non;
// serialization members, used by records too
public final Name serialPersistentFields;
@ -210,6 +210,10 @@ public class Names {
public final Name writeReplace;
public final Name readObjectNoData;
// sealed types
public final Name permits;
public final Name sealed;
public final Name.Table table;
public Names(Context context) {
@ -329,6 +333,7 @@ public class Names {
Synthetic = fromString("Synthetic");
Value = fromString("Value");
Varargs = fromString("Varargs");
PermittedSubclasses = fromString("PermittedSubclasses");
// members of java.lang.annotation.ElementType
ANNOTATION_TYPE = fromString("ANNOTATION_TYPE");
@ -367,11 +372,16 @@ public class Names {
bootstrap = fromString("bootstrap");
record = fromString("record");
non = fromString("non");
serialPersistentFields = fromString("serialPersistentFields");
writeObject = fromString("writeObject");
writeReplace = fromString("writeReplace");
readObjectNoData = fromString("readObjectNoData");
// sealed types
permits = fromString("permits");
sealed = fromString("sealed");
}
protected Name.Table createTable(Options options) {

View File

@ -112,8 +112,7 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite
Content tdSummary) {
ExecutableElement ee = (ExecutableElement)member;
Content memberLink = HtmlTree.SPAN(HtmlStyle.memberNameLink,
writer.getDocLink(context, te, ee,
name(ee), false));
writer.getDocLink(context, te, ee, name(ee), false));
Content code = HtmlTree.CODE(memberLink);
addParameters(ee, code);
tdSummary.add(code);

View File

@ -30,6 +30,7 @@ import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
@ -248,6 +249,32 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
}
}
}
List<? extends TypeMirror> permits = typeElement.getPermittedSubclasses();
List<? extends TypeMirror> linkablePermits = permits.stream()
.filter(t -> utils.isLinkable(utils.asTypeElement(t)))
.collect(Collectors.toList());
if (!linkablePermits.isEmpty()) {
boolean isFirst = true;
for (TypeMirror type : linkablePermits) {
TypeElement tDoc = utils.asTypeElement(type);
if (isFirst) {
pre.add(DocletConstants.NL);
pre.add("permits ");
isFirst = false;
} else {
pre.add(", ");
}
Content link = getLink(new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.PERMITTED_SUBCLASSES,
type));
pre.add(link);
}
if (linkablePermits.size() < permits.size()) {
Content c = new StringContent(resources.getText("doclet.not.exhaustive"));
pre.add(" ");
pre.add(HtmlTree.SPAN(HtmlStyle.permitsNote, c));
}
}
classInfoTree.add(pre);
}

View File

@ -162,6 +162,11 @@ public class LinkInfoImpl extends LinkInfo {
*/
CLASS_SIGNATURE_PARENT_NAME,
/**
* Permitted subclasses of a sealed type.
*/
PERMITTED_SUBCLASSES,
/**
* The header for method documentation copied from parent.
*/
@ -360,6 +365,7 @@ public class LinkInfoImpl extends LinkInfo {
case CLASS_TREE_PARENT:
case TREE:
case CLASS_SIGNATURE_PARENT_NAME:
case PERMITTED_SUBCLASSES:
excludeTypeParameterLinks = true;
excludeTypeBounds = true;
includeTypeInClassLinkLabel = false;

View File

@ -77,6 +77,7 @@ public enum HtmlStyle {
packages,
packageHierarchyLabel,
packageUses,
permitsNote,
searchTagLink,
searchTagResult,
serializedPackageContainer,

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2010, 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
@ -62,6 +62,7 @@ doclet.navProperty=Property
doclet.navEnum=Enum Constants
doclet.navConstructor=Constr
doclet.navMethod=Method
doclet.not.exhaustive=(not exhaustive)
doclet.Index=Index
doclet.Window_Single_Index=Index
doclet.Window_Split_Index={0}-Index

View File

@ -504,8 +504,18 @@ public class Utils {
}
}
void addSealed(TypeElement e) {
if (e.getModifiers().contains(Modifier.SEALED)) {
append("sealed");
} else if (e.getModifiers().contains(Modifier.NON_SEALED)) {
append("non-sealed");
}
}
void addModifiers(Set<Modifier> modifiers) {
modifiers.stream().map(Modifier::toString).forEachOrdered(this::append);
modifiers.stream()
.map(Modifier::toString)
.forEachOrdered(this::append);
}
void append(String s) {
@ -527,6 +537,7 @@ public class Utils {
public String visitTypeAsInterface(TypeElement e, SortedSet<Modifier> mods) {
addVisibilityModifier(mods);
addStatic(mods);
addSealed(e);
return finalString("interface");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
@ -67,6 +67,7 @@ public abstract class Attribute {
public static final String RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations";
public static final String RuntimeVisibleTypeAnnotations = "RuntimeVisibleTypeAnnotations";
public static final String RuntimeInvisibleTypeAnnotations = "RuntimeInvisibleTypeAnnotations";
public static final String PermittedSubclasses = "PermittedSubclasses";
public static final String Signature = "Signature";
public static final String SourceDebugExtension = "SourceDebugExtension";
public static final String SourceFile = "SourceFile";
@ -142,6 +143,7 @@ public abstract class Attribute {
standardAttributes.put(RuntimeVisibleParameterAnnotations, RuntimeVisibleParameterAnnotations_attribute.class);
standardAttributes.put(RuntimeVisibleTypeAnnotations, RuntimeVisibleTypeAnnotations_attribute.class);
standardAttributes.put(RuntimeInvisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations_attribute.class);
standardAttributes.put(PermittedSubclasses, PermittedSubclasses_attribute.class);
standardAttributes.put(Signature, Signature_attribute.class);
standardAttributes.put(SourceDebugExtension, SourceDebugExtension_attribute.class);
standardAttributes.put(SourceFile, SourceFile_attribute.class);
@ -208,6 +210,7 @@ public abstract class Attribute {
R visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, P p);
R visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, P p);
R visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, P p);
R visitPermittedSubclasses(PermittedSubclasses_attribute attr, P p);
R visitSignature(Signature_attribute attr, P p);
R visitSourceDebugExtension(SourceDebugExtension_attribute attr, P p);
R visitSourceFile(SourceFile_attribute attr, P p);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 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
@ -695,6 +695,16 @@ public class ClassWriter {
return null;
}
@Override
public Void visitPermittedSubclasses(PermittedSubclasses_attribute attr, ClassOutputStream out) {
int n = attr.subtypes.length;
out.writeShort(n);
for (int i = 0 ; i < n ; i++) {
out.writeShort(attr.subtypes[i]);
}
return null;
}
@Override
public Void visitSignature(Signature_attribute attr, ClassOutputStream out) {
out.writeShort(attr.signature_index);

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2019, 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 com.sun.tools.classfile;
import java.io.IOException;
import java.util.stream.IntStream;
import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
public class PermittedSubclasses_attribute extends Attribute {
public int[] subtypes;
PermittedSubclasses_attribute(ClassReader cr, int name_index, int length) throws IOException {
super(name_index, length);
int number_of_classes = cr.readUnsignedShort();
subtypes = new int[number_of_classes];
for (int i = 0; i < number_of_classes; i++)
subtypes[i] = cr.readUnsignedShort();
}
public PermittedSubclasses_attribute(int name_index, int[] subtypes) {
super(name_index, 2);
this.subtypes = subtypes;
}
public CONSTANT_Class_info[] getSubtypes(ConstantPool constant_pool) throws ConstantPoolException {
return IntStream.of(subtypes)
.mapToObj(i -> {
try {
return constant_pool.getClassInfo(i);
} catch (ConstantPoolException ex) {
throw new AssertionError(ex);
}
}).toArray(CONSTANT_Class_info[]::new);
}
@Override
public <R, D> R accept(Visitor<R, D> visitor, D data) {
return visitor.visitPermittedSubclasses(this, data);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
@ -68,7 +68,7 @@ import com.sun.tools.classfile.RuntimeParameterAnnotations_attribute;
import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
import com.sun.tools.classfile.RuntimeVisibleTypeAnnotations_attribute;
import com.sun.tools.classfile.Signature;
import com.sun.tools.classfile.PermittedSubclasses_attribute;
import com.sun.tools.classfile.Signature_attribute;
import com.sun.tools.classfile.SourceDebugExtension_attribute;
import com.sun.tools.classfile.SourceFile_attribute;
@ -83,10 +83,6 @@ import static com.sun.tools.classfile.AccessFlags.*;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.StringUtils;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/*
* A writer for writing Attributes as text.
*
@ -885,6 +881,22 @@ public class AttributeWriter extends BasicWriter
return null;
}
@Override
public Void visitPermittedSubclasses(PermittedSubclasses_attribute attr, Void ignore) {
println("PermittedSubclasses:");
indent(+1);
try {
CONSTANT_Class_info[] subtypes = attr.getSubtypes(constant_pool);
for (int i = 0; i < subtypes.length; i++) {
println(constantWriter.stringValue(subtypes[i]));
}
indent(-1);
} catch (ConstantPoolException ex) {
throw new AssertionError(ex);
}
return null;
}
@Override
public Void visitSignature(Signature_attribute attr, Void ignore) {
print("Signature: #" + attr.signature_index);

View File

@ -0,0 +1,95 @@
/*
* 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.
*
* 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 8225056
* @modules java.base/jdk.internal.misc
* @library /test/lib ..
* @compile sealedP1/SuperClass.jcod
* @compile --enable-preview --source ${jdk.version} sealedP1/C1.java sealedP2/C2.java sealedP3/C3.java
* @build sun.hotspot.WhiteBox
* @compile/module=java.base java/lang/ModuleHelper.java
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. --enable-preview -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SealedModuleTest
*/
public class SealedModuleTest {
// Test sub-classing a sealed super class in a named module. In this test,
// sealed class sealedP1/SuperClass permits sealedP1.C1, sealedP2.C2, and
// sealedP3.C3. All three of those classes extend sealedP1/SuperClass.
public static void main(String args[]) throws Throwable {
Object m1x, m2x;
// Get the class loader for SealedModuleTest and assume it's also used
// to load the other classes.
ClassLoader this_cldr = AccessCheckRead.class.getClassLoader();
// Define a module for packages sealedP1 and sealedP2.
m1x = ModuleHelper.ModuleObject("module_one", this_cldr,
new String[] { "sealedP1", "sealedP2" });
ModuleHelper.DefineModule(m1x, false, "9.0", "m1x/here",
new String[] { "sealedP1", "sealedP2" });
// Define a module for package sealedP3 with the same class loader.
m2x = ModuleHelper.ModuleObject("module_two", this_cldr, new String[] { "sealedP3" });
ModuleHelper.DefineModule(m2x, false, "9.0", "m2x/there", new String[] { "sealedP3" });
// Make package sealedP1 in m1x visible to everyone because it contains
// the super class for C1, C2, and C3.
ModuleHelper.AddModuleExportsToAll(m1x, "sealedP1");
ModuleHelper.AddReadsModule(m2x, m1x);
// Test subtype in the same named package and named module as its super
// class. This should succeed.
// Class sealedP1.C1 extends class sealedP1.SuperClass.
Class p1_C1_class = Class.forName("sealedP1.C1");
// Test non-public class in same module but different package than its
// super class. This should throw ICCE.
// Class sealedP2.C2 extends class sealedP1.SuperClass.
try {
Class p2_C2_class = Class.forName("sealedP2.C2");
throw new RuntimeException("Expected IncompatibleClassChangeError exception not thrown");
} catch (IncompatibleClassChangeError e) {
if (!e.getMessage().contains("cannot inherit from sealed class")) {
throw new RuntimeException("Wrong IncompatibleClassChangeError exception thrown: " + e.getMessage());
}
}
// Test subtype in a different module than its super type. This should
// fail even though they have the same class loader.
// Class sealedP3.C3 extends class sealedP1.SuperClass.
try {
Class p3_C3_class = Class.forName("sealedP3.C3");
throw new RuntimeException("Expected IncompatibleClassChangeError exception not thrown");
} catch (IncompatibleClassChangeError e) {
if (!e.getMessage().contains("cannot inherit from sealed class")) {
throw new RuntimeException("Wrong IncompatibleClassChangeError exception thrown: " + e.getMessage());
}
}
}
}

View File

@ -0,0 +1,23 @@
#
# 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.
#
# 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.
#
allowSmartActionArgs=true

View File

@ -0,0 +1,30 @@
/*
* 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.
*
* 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.
*/
// Small class used by SealedModuleTest
package sealedP1;
public final class C1 extends sealedP1.SuperClass {
public C1() { }
}

View File

@ -0,0 +1,105 @@
/*
* 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.
*
* 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.
*/
// This sealed class cannot be a java file because its permits clause names
// a class in another package causing javac to issue a compilation error.
//
// Sealed super class used by SealedModuleTest.
//
// package sealedP1;
//
// public sealed class SuperClass permits sealedP1.C1, sealedP2.C2, sealedP3.C3 { }
class sealedP1/SuperClass {
0xCAFEBABE;
65535; // minor version
59; // version
[20] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()V"; // #6 at 0x33
class #8; // #7 at 0x39
Utf8 "sealedP1/SuperClass"; // #8 at 0x3C
Utf8 "Code"; // #9 at 0x52
Utf8 "LineNumberTable"; // #10 at 0x59
Utf8 "SourceFile"; // #11 at 0x6B
Utf8 "SuperClass.java"; // #12 at 0x78
Utf8 "PermittedSubclasses"; // #13 at 0x8A
class #15; // #14 at 0x9E
Utf8 "sealedP1/C1"; // #15 at 0xA1
class #17; // #16 at 0xAF
Utf8 "sealedP2/C2"; // #17 at 0xB2
class #19; // #18 at 0xC0
Utf8 "sealedP3/C3"; // #19 at 0xC3
} // Constant Pool
0x0021; // access [ ACC_PUBLIC ACC_SUPER ]
#7;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // fields
} // fields
[1] { // methods
{ // Member at 0xDD
0x0001; // access
#5; // name_cpx
#6; // sig_cpx
[1] { // Attributes
Attr(#9, 29) { // Code at 0xE5
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#10, 6) { // LineNumberTable at 0xFC
[1] { // LineNumberTable
0 28; // at 0x0108
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[2] { // Attributes
Attr(#11, 2) { // SourceFile at 0x010A
#12;
} // end SourceFile
;
Attr(#13, 8) { // PermittedSubclasses at 0x0112
0x0003000E00100012;
} // end PermittedSubclasses
} // Attributes
} // end class sealedP1/SuperClass

View File

@ -0,0 +1,29 @@
/*
* 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.
*
* 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.
*/
// Small class used by SealedModuleTest
package sealedP2;
final class C2 extends sealedP1.SuperClass {
public void method2() { }
}

View File

@ -0,0 +1,29 @@
/*
* 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.
*
* 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.
*/
// Small class used by SealedModuleTest
package sealedP3;
public final class C3 extends sealedP1.SuperClass {
public void method3() { }
}

View File

@ -0,0 +1,45 @@
/*
* 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.
*
* 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 8225056
* @compile --enable-preview -source ${jdk.version} AbstractSealedTest.java
* @run main/othervm --enable-preview AbstractSealedTest
*/
// Test that a sealed class can be abstract
public class AbstractSealedTest {
abstract sealed class AbstractShape permits Circle {
abstract void draw();
}
final class Circle extends AbstractShape {
void draw() {}
}
Circle circle = new Circle();
public static void main(String... args) { }
}

View File

@ -0,0 +1,560 @@
/*
* 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.
*
* 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.
*/
// This class has entries in its PermittedSubclasses attribute that do not exist.
// Test that this does not prevent JVM_GetPermittedSubclasses() from returning
// their names.
//
// sealed class NoLoadSubclasses permits iDontExist, I/Dont/Exist/Either { }
//
class NoLoadSubclasses {
0xCAFEBABE;
65535; // minor version
59; // version
[18] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()V"; // #6 at 0x33
class #8; // #7 at 0x39
Utf8 "NoLoadSubclasses"; // #8 at 0x3C
Utf8 "Code"; // #9 at 0x4D
Utf8 "LineNumberTable"; // #10 at 0x54
Utf8 "SourceFile"; // #11 at 0x66
Utf8 "NoLoadSubclasses.java"; // #12 at 0x73
Utf8 "PermittedSubclasses"; // #13 at 0x89
class #15; // #14 at 0x9D
Utf8 "iDontExist"; // #15 at 0xA0
class #17; // #16 at 0xAA
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
} // Constant Pool
0x0020; // access [ ACC_SUPER ]
#7;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // fields
} // fields
[1] { // methods
{ // Member at 0xC1
0x0000; // access
#5; // name_cpx
#6; // sig_cpx
[1] { // Attributes
Attr(#9, 29) { // Code at 0xC9
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#10, 6) { // LineNumberTable at 0xE0
[1] { // LineNumberTable
0 1; // at 0xEC
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[2] { // Attributes
Attr(#13, 6) { // PermittedSubclasses at 0xF6
0x0002000E0010;
} // end PermittedSubclasses
;
Attr(#11, 2) { // SourceFile at 0xEE
#12;
} // end SourceFile
} // Attributes
} // end class NoLoadSubclasses
// This class contains an empty PermittedSubclasses attribute. Test that
// this causes an exception to get thrown.
class NoSubclasses {
0xCAFEBABE;
65535; // minor version
59; // version
[14] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()V"; // #6 at 0x33
class #8; // #7 at 0x39
Utf8 "NoSubclasses"; // #8 at 0x3C
Utf8 "Code"; // #9 at 0x49
Utf8 "LineNumberTable"; // #10 at 0x50
Utf8 "SourceFile"; // #11 at 0x62
Utf8 "NoSubclasses.java"; // #12 at 0x6F
Utf8 "PermittedSubclasses"; // #13 at 0x81
} // Constant Pool
0x0020; // access [ ACC_SUPER ]
#7;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // fields
} // fields
[1] { // methods
{ // Member at 0xAB
0x0000; // access
#5; // name_cpx
#6; // sig_cpx
[1] { // Attributes
Attr(#9, 29) { // Code at 0xB3
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#10, 6) { // LineNumberTable at 0xCA
[1] { // LineNumberTable
0 1; // at 0xD6
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[2] { // Attributes
Attr(#11, 2) { // SourceFile at 0xD8
#12;
} // end SourceFile
;
Attr(#13, 2) { // PermittedSubclasses at 0xE0
0x0000;
} // end PermittedSubclasses
} // Attributes
} // end class NoSubclasses
// This class has a PermittedSubclasses attribute but an old class file version.
// The PermittedSubclasses attribute should be ignored.
//
// sealed class OldClassFile permits iDontExist, I/Dont/Exist/Either { }
//
class OldClassFile {
0xCAFEBABE;
0; // minor version
57; // version
[18] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()V"; // #6 at 0x33
class #8; // #7 at 0x39
Utf8 "OldClassFile"; // #8 at 0x3C
Utf8 "Code"; // #9 at 0x4D
Utf8 "LineNumberTable"; // #10 at 0x54
Utf8 "SourceFile"; // #11 at 0x66
Utf8 "OldClassFile.java"; // #12 at 0x73
Utf8 "PermittedSubclasses"; // #13 at 0x89
class #15; // #14 at 0x9D
Utf8 "iDontExist"; // #15 at 0xA0
class #17; // #16 at 0xAA
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
} // Constant Pool
0x0030; // access [ ACC_SUPER ACC_FINAL ]
#7;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // fields
} // fields
[1] { // methods
{ // Member at 0xC1
0x0000; // access
#5; // name_cpx
#6; // sig_cpx
[1] { // Attributes
Attr(#9, 29) { // Code at 0xC9
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#10, 6) { // LineNumberTable at 0xE0
[1] { // LineNumberTable
0 1; // at 0xEC
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[2] { // Attributes
Attr(#11, 2) { // SourceFile at 0xEE
#12;
} // end SourceFile
;
Attr(#13, 6) { // PermittedSubclasses at 0xF6
0x0002000E0010;
} // end PermittedSubclasses
} // Attributes
} // end class OldClassFile
// This class has a corrupted PermittedSubclasses attribute. Attempts to load it
// should throw ClassFormatError.
class BadPermittedAttr {
0xCAFEBABE;
65535; // minor version
59; // version
[18] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()V"; // #6 at 0x33
class #8; // #7 at 0x39
Utf8 "BadPermittedAttr"; // #8 at 0x3C
Utf8 "Code"; // #9 at 0x4D
Utf8 "LineNumberTable"; // #10 at 0x54
Utf8 "SourceFile"; // #11 at 0x66
Utf8 "BadPermittedAttr.java"; // #12 at 0x73
Utf8 "PermittedSubclasses"; // #13 at 0x89
class #15; // #14 at 0x9D
Utf8 "iDontExist"; // #15 at 0xA0
class #17; // #16 at 0xAA
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
} // Constant Pool
0x0020; // access [ ACC_SUPER ]
#7;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // fields
} // fields
[1] { // methods
{ // Member at 0xC1
0x0000; // access
#5; // name_cpx
#6; // sig_cpx
[1] { // Attributes
Attr(#9, 29) { // Code at 0xC9
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#10, 6) { // LineNumberTable at 0xE0
[1] { // LineNumberTable
0 1; // at 0xEC
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[2] { // Attributes
Attr(#11, 2) { // SourceFile at 0xEE
#12;
} // end SourceFile
;
Attr(#13, 6) { // PermittedSubclasses at 0xF6
0x0002000F0010;
} // end PermittedSubclasses
} // Attributes
} // end class BadPermittedAttr
// This class has a PermittedSubclasses attribute and is marked Final.
// Loading this class should throw a ClassFormatError exception.
//
// sealed class SealedButFinal permits iDontExist, I/Dont/Exist/Either { }
//
class SealedButFinal {
0xCAFEBABE;
65535; // minor version
59; // version
[18] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()V"; // #6 at 0x33
class #8; // #7 at 0x39
Utf8 "SealedButFinal"; // #8 at 0x3C
Utf8 "Code"; // #9 at 0x4D
Utf8 "LineNumberTable"; // #10 at 0x54
Utf8 "SourceFile"; // #11 at 0x66
Utf8 "SealedButFinal.java"; // #12 at 0x73
Utf8 "PermittedSubclasses"; // #13 at 0x89
class #15; // #14 at 0x9D
Utf8 "iDontExist"; // #15 at 0xA0
class #17; // #16 at 0xAA
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
} // Constant Pool
0x0030; // access [ ACC_SUPER ACC_FINAL ]
#7;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // fields
} // fields
[1] { // methods
{ // Member at 0xC1
0x0000; // access
#5; // name_cpx
#6; // sig_cpx
[1] { // Attributes
Attr(#9, 29) { // Code at 0xC9
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#10, 6) { // LineNumberTable at 0xE0
[1] { // LineNumberTable
0 1; // at 0xEC
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[2] { // Attributes
Attr(#11, 2) { // SourceFile at 0xEE
#12;
} // end SourceFile
;
Attr(#13, 6) { // PermittedSubclasses at 0xF6
0x0002000E0010;
} // end PermittedSubclasses
} // Attributes
} // end class SealedButFinal
// This class contains a PermittedSubclasses attribute with an invalid class
// name. Test that this causes a ClassFormatError exception to get thrown.
//
// sealed class BadPermittedSubclassEntry permits iDont;;Exist, I/Dont/Exist/Either { }
//
class BadPermittedSubclassEntry {
0xCAFEBABE;
65535; // minor version
59; // version
[18] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()V"; // #6 at 0x33
class #8; // #7 at 0x39
Utf8 "BadPermittedSubclassEntry"; // #8 at 0x3C
Utf8 "Code"; // #9 at 0x4D
Utf8 "LineNumberTable"; // #10 at 0x54
Utf8 "SourceFile"; // #11 at 0x66
Utf8 "BadPermittedSubclassEntry.java"; // #12 at 0x73
Utf8 "PermittedSubclasses"; // #13 at 0x89
class #15; // #14 at 0x9D
Utf8 "iDont;;Exist"; // #15 at 0xA0
class #17; // #16 at 0xAA
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
} // Constant Pool
0x0020; // access [ ACC_SUPER ]
#7;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // fields
} // fields
[1] { // methods
{ // Member at 0xC1
0x0000; // access
#5; // name_cpx
#6; // sig_cpx
[1] { // Attributes
Attr(#9, 29) { // Code at 0xC9
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#10, 6) { // LineNumberTable at 0xE0
[1] { // LineNumberTable
0 1; // at 0xEC
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[2] { // Attributes
Attr(#13, 6) { // PermittedSubclasses at 0xF6
0x0002000E0010;
} // end PermittedSubclasses
;
Attr(#11, 2) { // SourceFile at 0xEE
#12;
} // end SourceFile
} // Attributes
}
// This class contains a PermittedSubclasses attribute with an empty class
// name. Test that this causes a ClassFormatError exception to get thrown.
//
// sealed class EmptyPermittedSubclassEntry permits "", I/Dont/Exist/Either { }
//
class EmptyPermittedSubclassEntry {
0xCAFEBABE;
65535; // minor version
59; // version
[18] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()V"; // #6 at 0x33
class #8; // #7 at 0x39
Utf8 "EmptyPermittedSubclassEntry"; // #8 at 0x3C
Utf8 "Code"; // #9 at 0x4D
Utf8 "LineNumberTable"; // #10 at 0x54
Utf8 "SourceFile"; // #11 at 0x66
Utf8 "EmptyPermittedSubclassEntry.java"; // #12 at 0x73
Utf8 "PermittedSubclasses"; // #13 at 0x89
class #15; // #14 at 0x9D
Utf8 ""; // #15 at 0xA0
class #17; // #16 at 0xAA
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
} // Constant Pool
0x0020; // access [ ACC_SUPER ]
#7;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // fields
} // fields
[1] { // methods
{ // Member at 0xC1
0x0000; // access
#5; // name_cpx
#6; // sig_cpx
[1] { // Attributes
Attr(#9, 29) { // Code at 0xC9
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#10, 6) { // LineNumberTable at 0xE0
[1] { // LineNumberTable
0 1; // at 0xEC
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[2] { // Attributes
Attr(#13, 6) { // PermittedSubclasses at 0xF6
0x0002000E0010;
} // end PermittedSubclasses
;
Attr(#11, 2) { // SourceFile at 0xEE
#12;
} // end SourceFile
} // Attributes
}

View File

@ -0,0 +1,138 @@
/*
* 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.
*
* 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 8225056
* @compile GetPermittedSubclasses.jcod
* @compile --enable-preview -source ${jdk.version} GetPermittedSubclassesTest.java
* @run main/othervm --enable-preview GetPermittedSubclassesTest
*/
import java.lang.constant.ClassDesc;
import java.util.ArrayList;
// Test Class GetPermittedSubtpes() and Class.isSealed() APIs.
public class GetPermittedSubclassesTest {
sealed class Sealed1 permits Sub1 {}
final class Sub1 extends Sealed1 implements SealedI1 {}
sealed interface SealedI1 permits NotSealed, Sub1, Extender {}
non-sealed interface Extender extends SealedI1 { }
final class FinalC implements Extender {}
final class NotSealed implements SealedI1 {}
final class Final4 {}
public static void testSealedInfo(Class<?> c, String[] expected) {
Object[] permitted = c.permittedSubclasses();
if (permitted.length != expected.length) {
throw new RuntimeException(
"Unexpected number of permitted subclasses for: " + c.toString());
}
if (permitted.length > 0) {
if (!c.isSealed()) {
throw new RuntimeException("Expected sealed class: " + c.toString());
}
// Create ArrayList of permitted subclasses class names.
ArrayList<String> permittedNames = new ArrayList<String>();
for (int i = 0; i < permitted.length; i++) {
permittedNames.add(((ClassDesc)permitted[i]).descriptorString());
}
if (permittedNames.size() != expected.length) {
throw new RuntimeException(
"Unexpected number of permitted names for: " + c.toString());
}
// Check that expected class names are in the permitted subclasses list.
for (int i = 0; i < expected.length; i++) {
if (!permittedNames.contains(expected[i])) {
throw new RuntimeException(
"Expected class not found in permitted subclases list, super class: " +
c.getName() + ", expected class: " + expected[i]);
}
}
} else {
// Must not be sealed if no permitted subclasses.
if (c.isSealed()) {
throw new RuntimeException("Unexpected sealed class: " + c.toString());
}
}
}
public static void testBadSealedClass(String className, String expectedCFEMessage) throws Throwable {
try {
Class.forName(className);
throw new RuntimeException("Expected ClassFormatError exception not thrown for " + className);
} catch (ClassFormatError cfe) {
if (!cfe.getMessage().contains(expectedCFEMessage)) {
throw new RuntimeException(
"Class " + className + " got unexpected ClassFormatError exception: " + cfe.getMessage());
}
}
}
public static void main(String... args) throws Throwable {
testSealedInfo(SealedI1.class, new String[] {"LGetPermittedSubclassesTest$NotSealed;",
"LGetPermittedSubclassesTest$Sub1;",
"LGetPermittedSubclassesTest$Extender;"});
testSealedInfo(Sealed1.class, new String[] {"LGetPermittedSubclassesTest$Sub1;"});
testSealedInfo(Final4.class, new String[] { });
testSealedInfo(NotSealed.class, new String[] { });
// Test class with PermittedSubclasses attribute but old class file version.
testSealedInfo(OldClassFile.class, new String[] { });
// Test class with an empty PermittedSubclasses attribute.
testBadSealedClass("NoSubclasses", "PermittedSubclasses attribute is empty");
// Test returning names of non-existing classes.
testSealedInfo(NoLoadSubclasses.class, new String[]{"LiDontExist;", "LI/Dont/Exist/Either;"});
// Test that loading a class with a corrupted PermittedSubclasses attribute
// causes a ClassFormatError.
testBadSealedClass("BadPermittedAttr",
"Permitted subclass class_info_index 15 has bad constant type");
// Test that loading a sealed final class with a PermittedSubclasses
// attribute causes a ClassFormatError.
testBadSealedClass("SealedButFinal", "PermittedSubclasses attribute in final class");
// Test that loading a sealed class with a bad class name in its PermittedSubclasses
// attribute causes a ClassFormatError.
testBadSealedClass("BadPermittedSubclassEntry", "Illegal class name \"iDont;;Exist\" in class file");
// Test that loading a sealed class with an empty class name in its PermittedSubclasses
// attribute causes a ClassFormatError.
testBadSealedClass("EmptyPermittedSubclassEntry", "Illegal class name \"\" in class file");
}
}

View File

@ -0,0 +1,73 @@
/*
* 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.
*
* 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 8225056
* @compile --enable-preview -source ${jdk.version} OverrideSealedTest.java
* @run main/othervm --enable-preview OverrideSealedTest
*/
// Test that a method in a sealed class or interface can be overridden.
public class OverrideSealedTest {
sealed class Rectangle permits Square {
public String draw() { return "rectangle"; }
}
final class Square extends Rectangle {
public String draw() { return "square"; }
}
Rectangle r = new Rectangle();
Rectangle rs = new Square();
Square s = new Square();
public sealed interface Shape permits Circle {
default String name() { return "shape"; }
}
final class Circle implements Shape {
public String name() { return "circle"; }
}
Shape sc = new Circle();
Circle c = new Circle();
public static void main(String... args) {
OverrideSealedTest ost = new OverrideSealedTest();
if (ost.r.draw() != "rectangle")
throw new RuntimeException("Bad value returned by draw(): " + ost.r.draw());
if (ost.rs.draw() != "square")
throw new RuntimeException("Bad value returned by draw(): " + ost.rs.draw());
if (ost.s.draw() != "square")
throw new RuntimeException("Bad value returned by draw(): " + ost.s.draw());
if (ost.sc.name() != "circle")
throw new RuntimeException("Bad value returned by name(): " + ost.sc.name());
if (ost.c.name() != "circle")
throw new RuntimeException("Bad value returned by name(): " + ost.c.name());
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.
*
* 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.
*/
// This class was written using jcod because it implements sealed interface
// SealedInterface but is not listed in its PermittedSubclasses attribute.
// It consists of the following:
//
// package Pkg;
// public class NotPermitted implements SealedInterface { }
//
class Pkg/NotPermitted {
0xCAFEBABE;
0; // minor version
59; // version
[15] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()V"; // #6 at 0x33
class #8; // #7 at 0x39
Utf8 "Pkg/NotPermitted"; // #8 at 0x3C
class #10; // #9 at 0x4C
Utf8 "Pkg/SealedInterface"; // #10 at 0x4F
Utf8 "Code"; // #11 at 0x65
Utf8 "LineNumberTable"; // #12 at 0x6C
Utf8 "SourceFile"; // #13 at 0x7E
Utf8 "NotPermitted.java"; // #14 at 0x8B
} // Constant Pool
0x0031; // access [ ACC_PUBLIC ACC_SUPER ACC_FINAL ]
#7;// this_cpx
#2;// super_cpx
[1] { // Interfaces
#9;
} // Interfaces
[0] { // fields
} // fields
[1] { // methods
{ // Member at 0xAA
0x0001; // access
#5; // name_cpx
#6; // sig_cpx
[1] { // Attributes
Attr(#11, 29) { // Code at 0xB2
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
};
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#12, 6) { // LineNumberTable at 0xC9
[1] { // LineNumberTable
0 26; // at 0xD5
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[1] { // Attributes
Attr(#13, 2) { // SourceFile at 0xD7
#14;
} // end SourceFile
} // Attributes
} // end class Pkg/NotPermitted

View File

@ -0,0 +1,26 @@
/*
* 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.
*
* 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 Pkg;
final class Permitted implements SealedInterface { }

View File

@ -0,0 +1,72 @@
/*
* 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.
*
* 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.
*/
// This sealed class cannot be a java file because its permits clause names
// a class in another package causing javac to issue a compilation error.
//
// package Pkg;
//
// sealed public interface SealedInterface permits Permitted, otherPkg.WrongPackage { }
class Pkg/SealedInterface {
0xCAFEBABE;
65535; // minor version
59; // version
[12] { // Constant Pool
; // first element is empty
class #2; // #1 at 0x0A
Utf8 "Pkg/SealedInterface"; // #2 at 0x0D
class #4; // #3 at 0x23
Utf8 "java/lang/Object"; // #4 at 0x26
Utf8 "SourceFile"; // #5 at 0x39
Utf8 "SealedInterface.java"; // #6 at 0x46
Utf8 "PermittedSubclasses"; // #7 at 0x5D
class #9; // #8 at 0x71
Utf8 "Pkg/Permitted"; // #9 at 0x74
class #11; // #10 at 0x84
Utf8 "otherPkg/WrongPackage"; // #11 at 0x87
} // Constant Pool
0x0601; // access [ ACC_PUBLIC ACC_INTERFACE ]
#1;// this_cpx
#3;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // fields
} // fields
[0] { // methods
} // methods
[2] { // Attributes
Attr(#5, 2) { // SourceFile at 0xAD
#6;
} // end SourceFile
;
Attr(#7, 6) { // PermittedSubtclasses at 0xB5
0x00020008000A;
} // end PermittedSubclasses
} // Attributes
} // end class Pkg/SealedInterface

View File

@ -0,0 +1,112 @@
/*
* 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.
*
* 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 8225056
* @library /test/lib
* @summary Test that a class that is a sealed class can be redefined.
* @modules java.base/jdk.internal.misc
* @modules java.instrument
* jdk.jartool/sun.tools.jar
* @compile --enable-preview -source ${jdk.version} RedefineSealedClass.java
* @run main/othervm --enable-preview RedefineSealedClass buildagent
* @run main/othervm/timeout=6000 --enable-preview RedefineSealedClass runtest
*/
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.lang.RuntimeException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.lang.instrument.IllegalClassFormatException;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
public class RedefineSealedClass {
final class A extends Tester { }
final class B extends Tester { }
sealed static class Tester permits A, B {}
static class LoggingTransformer implements ClassFileTransformer {
public LoggingTransformer() {}
public byte[] transform(ClassLoader loader, String className,
Class classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
return null;
}
}
public static void premain(String agentArgs, Instrumentation inst) throws Exception {
LoggingTransformer t = new LoggingTransformer();
inst.addTransformer(t, true);
{
Class demoClass = Class.forName("RedefineSealedClass$Tester");
inst.retransformClasses(demoClass);
}
}
private static void buildAgent() {
try {
ClassFileInstaller.main("RedefineSealedClass");
} catch (Exception e) {
throw new RuntimeException("Could not write agent classfile", e);
}
try {
PrintWriter pw = new PrintWriter("MANIFEST.MF");
pw.println("Premain-Class: RedefineSealedClass");
pw.println("Agent-Class: RedefineSealedClass");
pw.println("Can-Redefine-Classes: true");
pw.println("Can-Retransform-Classes: true");
pw.close();
} catch (FileNotFoundException e) {
throw new RuntimeException("Could not write manifest file for the agent", e);
}
sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "RedefineSealedClass.class" })) {
throw new RuntimeException("Could not write the agent jar file");
}
}
public static void main(String argv[]) throws Exception {
if (argv.length == 1 && argv[0].equals("buildagent")) {
buildAgent();
return;
}
if (argv.length == 1 && argv[0].equals("runtest")) {
String[] javaArgs1 = { "-XX:MetaspaceSize=12m", "-XX:MaxMetaspaceSize=12m",
"-javaagent:redefineagent.jar", "--enable-preview",
"RedefineSealedClass"};
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(javaArgs1);
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldNotContain("processing of -javaagent failed");
}
}
}

View File

@ -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.
*
* 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 8225056
* @compile --enable-preview -source ${jdk.version} SealedTest.java
* @run main/othervm --enable-preview SealedTest
*/
public class SealedTest {
sealed class Sealed1 permits Sub1 {}
final class Sub1 extends Sealed1 {}
sealed interface SealedI1 permits Sub2 {}
final class Sub2 extends Sealed2 implements SealedI1 {}
sealed class Sealed2 permits Sub2 {}
Sub1 sub1 = new Sub1();
Sub2 sub2 = new Sub2();
public static void main(String... args) {
System.out.println("Basic testing of sealed types");
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.
*
* 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 8225056
* @compile Pkg/SealedInterface.jcod Pkg/NotPermitted.jcod
* @compile --enable-preview -source ${jdk.version} Pkg/Permitted.java otherPkg/WrongPackage.java
* @run main/othervm --enable-preview SealedUnnamedModuleIntfTest
*/
public class SealedUnnamedModuleIntfTest {
public static void main(String args[]) throws Throwable {
// Classes Permitted, NotPermitted, and WrongPackage all try to implement
// sealed interface SealedInterface.
// Interface SealedInterface permits classes Permitted and WrongPackage.
// Test non-public permitted subclass and superclass in unnamed module and
// same package. This should succeed.
Class permitted = Class.forName("Pkg.Permitted");
// Test unpermitted subclass and superclass in unnamed module and same package.
// This should throw an exception.
try {
Class notPermitted = Class.forName("Pkg.NotPermitted");
throw new RuntimeException("Expected IncompatibleClassChangeError exception not thrown");
} catch (IncompatibleClassChangeError e) {
if (!e.getMessage().contains("cannot implement sealed interface")) {
throw new RuntimeException("Wrong IncompatibleClassChangeError exception thrown: " + e.getMessage());
}
}
// Test public permitted subclass and superclass in same unnamed module but in
// different packages. This should not throw an exception.
Class wrongPkg = Class.forName("otherPkg.WrongPackage");
}
}

View File

@ -0,0 +1,65 @@
/*
* 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.
*
* 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 8225056
* @compile planets/OuterPlanets.jcod planets/Mars.jcod
* @compile --enable-preview -source ${jdk.version} planets/Neptune.java asteroids/Pluto.java
* @run main/othervm --enable-preview SealedUnnamedModuleTest
*/
public class SealedUnnamedModuleTest {
public static void main(String args[]) throws Throwable {
// Classes Neptune, Mars, and Pluto all try to extend sealed class OuterPlanets.
// Class OuterPlanets permits Nepturn and Pluto.
// Test permitted subclass and superclass in unnamed module and same package.
// This should succeed.
Class neptune = Class.forName("planets.Neptune");
// Test unpermitted subclass and superclass in unnamed module and same package.
// This should fail.
try {
Class mars = Class.forName("planets.Mars");
throw new RuntimeException("Expected IncompatibleClassChangeError exception not thrown");
} catch (IncompatibleClassChangeError e) {
if (!e.getMessage().contains("cannot inherit from sealed class")) {
throw new RuntimeException("Wrong IncompatibleClassChangeError exception thrown: " + e.getMessage());
}
}
// Test non-public permitted subclass and superclass in same unnamed module but
// in different packages. This should fail.
try {
Class pluto = Class.forName("asteroids.Pluto");
throw new RuntimeException("Expected IncompatibleClassChangeError exception not thrown");
} catch (IncompatibleClassChangeError e) {
if (!e.getMessage().contains("cannot inherit from sealed class")) {
throw new RuntimeException("Wrong IncompatibleClassChangeError exception thrown: " + e.getMessage());
}
}
}
}

View File

@ -0,0 +1,23 @@
#
# 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.
#
# 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.
#
allowSmartActionArgs=true

View File

@ -0,0 +1,27 @@
/*
* 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.
*
* 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 asteroids;
final class Pluto extends planets.OuterPlanets { }

View File

@ -0,0 +1,26 @@
/*
* 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.
*
* 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 otherPkg;
public final class WrongPackage implements Pkg.SealedInterface { }

View File

@ -0,0 +1,92 @@
/*
* 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.
*
* 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.
*/
// This class was written using jcod because it extends sealed class
// planets.OuterPlanets but is not listed in its PermittedSubclasses
// attribute. It consists of the following:
//
// package planets;
// public class Mars extends OuterPlanets { }
//
class planets/Mars {
0xCAFEBABE;
0; // minor version
59; // version
[13] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "planets/OuterPlanets"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2E
Utf8 "()V"; // #6 at 0x37
class #8; // #7 at 0x3D
Utf8 "planets/Mars"; // #8 at 0x40
Utf8 "Code"; // #9 at 0x52
Utf8 "LineNumberTable"; // #10 at 0x59
Utf8 "SourceFile"; // #11 at 0x6B
Utf8 "Mars.java"; // #12 at 0x78
} // Constant Pool
0x0031; // access [ ACC_PUBLIC ACC_SUPER ACC_FINAL ]
#7;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // fields
} // fields
[1] { // methods
{ // Member at 0x93
0x0001; // access
#5; // name_cpx
#6; // sig_cpx
[1] { // Attributes
Attr(#9, 29) { // Code at 0x9B
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
};
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#10, 6) { // LineNumberTable at 0xB2
[1] { // LineNumberTable
0 3; // at 0xBE
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[1] { // Attributes
Attr(#11, 2) { // SourceFile at 0xC0
#12;
} // end SourceFile
} // Attributes
} // end class planets/Mars

View File

@ -0,0 +1,26 @@
/*
* 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.
*
* 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 planets;
public final class Neptune extends OuterPlanets { }

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2019, 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.
*
* 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 planets;
//
// sealed public class OuterPlanets permits Neptune, asteroids.Pluto { }
class planets/OuterPlanets {
0xCAFEBABE;
65535; // minor version
59; // version
[18] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()V"; // #6 at 0x33
class #8; // #7 at 0x39
Utf8 "planets/OuterPlanets"; // #8 at 0x3C
Utf8 "Code"; // #9 at 0x53
Utf8 "LineNumberTable"; // #10 at 0x5A
Utf8 "SourceFile"; // #11 at 0x6C
Utf8 "OuterPlanets.java"; // #12 at 0x79
Utf8 "PermittedSubclasses"; // #13 at 0x8D
class #15; // #14 at 0xA1
Utf8 "planets/Neptune"; // #15 at 0xA4
class #17; // #16 at 0xB6
Utf8 "asteroids/Pluto"; // #17 at 0xB9
} // Constant Pool
0x0021; // access [ ACC_PUBLIC ACC_SUPER ]
#7;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // fields
} // fields
[1] { // methods
{ // Member at 0xD7
0x0001; // access
#5; // name_cpx
#6; // sig_cpx
[1] { // Attributes
Attr(#9, 29) { // Code at 0xDF
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#10, 6) { // LineNumberTable at 0xF6
[1] { // LineNumberTable
0 26; // at 0x0102
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[2] { // Attributes
Attr(#11, 2) { // SourceFile at 0x0104
#12;
} // end SourceFile
;
Attr(#13, 6) { // PermittedSubclasses at 0x010C
0x0002000E0010;
} // end PermittedSubclasses
} // Attributes
} // end class planets/OuterPlanets

View File

@ -0,0 +1,24 @@
/*
* 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.
*
* 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.
*/
final public class ClassFour extends Host { }

View File

@ -0,0 +1,24 @@
/*
* 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.
*
* 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.
*/
final public class ClassOne extends Host { }

View File

@ -0,0 +1,24 @@
/*
* 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.
*
* 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.
*/
final public class ClassThree extends Host { }

View File

@ -0,0 +1,24 @@
/*
* 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.
*
* 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.
*/
final public class ClassTwo extends Host { }

View File

@ -0,0 +1,29 @@
/*
* 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.
*
* 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.
*/
public class Host {
public static String getID() { return "Host/Host.java";}
public int m() {
return 1; // original class
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.
*
* 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.
*/
public class Host {
public static String getID() { return "Host/redef/Host.java";}
public int m() {
return 2; // redefined class
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.
*
* 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.
*/
public sealed class Host permits ClassOne {
public static String getID() { return "HostA/Host.java";}
public int m() {
return 1; // original class
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.
*
* 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.
*/
public sealed class Host permits ClassOne {
public static String getID() { return "HostA/redef/Host.java"; }
public int m() {
return 2; // redefined class
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.
*
* 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.
*/
public sealed class Host permits ClassOne,ClassTwo {
public static String getID() { return "HostAB/Host.java";}
public int m() {
return 1; // original class
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.
*
* 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.
*/
public sealed class Host permits ClassOne,ClassTwo {
public static String getID() { return "HostAB/redef/Host.java"; }
public int m() {
return 2; // redefined class
}
}

Some files were not shown because too many files have changed in this diff Show More