diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 8320ddc36bf..dd6174bde99 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -961,7 +961,6 @@ static bool put_after_lookup(const Symbol* name, const Symbol* sig, NameSigHash* void ClassFileParser::parse_interfaces(const ClassFileStream* stream, int itfs_len, ConstantPool* cp, - bool is_inline_type, bool* const has_nonstatic_concrete_methods, // FIXME: lots of these functions // declare their parameters as const, @@ -1017,7 +1016,7 @@ void ClassFileParser::parse_interfaces(const ClassFileStream* stream, } InstanceKlass* ik = InstanceKlass::cast(interf); - if (is_inline_type && ik->invalid_inline_super()) { + if (is_inline_type() && ik->invalid_inline_super()) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, @@ -1038,6 +1037,11 @@ void ClassFileParser::parse_interfaces(const ClassFileStream* stream, if (ik->name() == vmSymbols::java_lang_IdentityObject()) { _implements_identityObject = true; } + if (ik->name() == vmSymbols::java_lang_PrimitiveObject()) { + // further checks for "is_invalid_super_for_inline_type()" needed later + // needs field parsing, delay unitl post_process_parse_stream() + _implements_primitiveObject = true; + } _temp_local_interfaces->append(ik); } @@ -4601,6 +4605,9 @@ static Array* compute_transitive_interfaces(const InstanceKlass* if (length == 1 && result->at(0) == vmClasses::IdentityObject_klass()) { return Universe::the_single_IdentityObject_klass_array(); } + if (length == 1 && result->at(0) == vmClasses::PrimitiveObject_klass()) { + return Universe::the_single_PrimitiveObject_klass_array(); + } Array* const new_result = MetadataFactory::new_array(loader_data, length, CHECK_NULL); @@ -5719,6 +5726,9 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, if (_has_injected_identityObject) { ik->set_has_injected_identityObject(); } + if (_has_injected_primitiveObject) { + ik->set_has_injected_primitiveObject(); + } assert(_fac != NULL, "invariant"); ik->set_static_oop_field_count(_fac->count[STATIC_OOP] + _fac->count[STATIC_INLINE]); @@ -5967,9 +5977,15 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, // it's official set_klass(ik); + // the common single interface arrays need setup here to provide the + // correct answer to "compute_transitive_interfaces()", during + // "SystemDictionary::initialize()" if (ik->name() == vmSymbols::java_lang_IdentityObject()) { Universe::initialize_the_single_IdentityObject_klass_array(ik, CHECK); } + if (ik->name() == vmSymbols::java_lang_PrimitiveObject()) { + Universe::initialize_the_single_PrimitiveObject_klass_array(ik, CHECK); + } debug_only(ik->verify();) } @@ -6122,6 +6138,8 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, _invalid_identity_super(false), _implements_identityObject(false), _has_injected_identityObject(false), + _implements_primitiveObject(false), + _has_injected_primitiveObject(false), _has_finalizer(false), _has_empty_finalizer(false), _has_vanilla_constructor(false), @@ -6465,7 +6483,6 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream, parse_interfaces(stream, _itfs_len, cp, - is_inline_type(), &_has_nonstatic_concrete_methods, &_is_declared_atomic, CHECK); @@ -6613,13 +6630,7 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st if (is_inline_type()) { const InstanceKlass* super_ik = _super_klass; if (super_ik->invalid_inline_super()) { - ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_IncompatibleClassChangeError(), - "inline class %s has an invalid super class %s", - _class_name->as_klass_external_name(), - _super_klass->external_name()); + classfile_icce_error("inline class %s has an invalid super class %s", _super_klass, THREAD); return; } } @@ -6651,11 +6662,25 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st _temp_local_interfaces->append(vmClasses::IdentityObject_klass()); _has_injected_identityObject = true; } + // Check if declared as PrimitiveObject...else add if needed + if (_implements_primitiveObject) { + if (!is_inline_type() && invalid_inline_super()) { + classfile_icce_error("class %s can not implement %s, neither valid inline classes or valid supertype", + vmClasses::PrimitiveObject_klass(), THREAD); + return; + } + } else if (is_inline_type()) { + _temp_local_interfaces->append(vmClasses::PrimitiveObject_klass()); + _has_injected_primitiveObject = true; + } + int itfs_len = _temp_local_interfaces->length(); if (itfs_len == 0) { _local_interfaces = Universe::the_empty_instance_klass_array(); } else if (itfs_len == 1 && _temp_local_interfaces->at(0) == vmClasses::IdentityObject_klass()) { _local_interfaces = Universe::the_single_IdentityObject_klass_array(); + } else if (itfs_len == 1 && _temp_local_interfaces->at(0) == vmClasses::PrimitiveObject_klass()) { + _local_interfaces = Universe::the_single_PrimitiveObject_klass_array(); } else { _local_interfaces = MetadataFactory::new_array(_loader_data, itfs_len, NULL, CHECK); for (int i = 0; i < itfs_len; i++) { diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index 6ba4f7d10c7..55aa24199b0 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -213,6 +213,8 @@ class ClassFileParser { bool _invalid_identity_super; // if true, invalid super type for an identity type. bool _implements_identityObject; bool _has_injected_identityObject; + bool _implements_primitiveObject; + bool _has_injected_primitiveObject; // precomputed flags bool _has_finalizer; @@ -263,7 +265,6 @@ class ClassFileParser { void parse_interfaces(const ClassFileStream* const stream, const int itfs_len, ConstantPool* const cp, - bool is_inline_type, bool* has_nonstatic_concrete_methods, bool* is_declared_atomic, TRAPS); diff --git a/src/hotspot/share/classfile/classListParser.cpp b/src/hotspot/share/classfile/classListParser.cpp index 64e0e5d5046..a7acd138eb6 100644 --- a/src/hotspot/share/classfile/classListParser.cpp +++ b/src/hotspot/share/classfile/classListParser.cpp @@ -400,26 +400,36 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS bool identity_object_implemented = false; bool identity_object_specified = false; + bool primitive_object_implemented = false; + bool primitive_object_specified = false; for (i = 0; i < actual_num_interfaces; i++) { if (k->local_interfaces()->at(i) == vmClasses::IdentityObject_klass()) { identity_object_implemented = true; break; } + if (k->local_interfaces()->at(i) == vmClasses::PrimitiveObject_klass()) { + primitive_object_implemented = true; + break; + } } for (i = 0; i < specified_num_interfaces; i++) { if (lookup_class_by_id(_interfaces->at(i)) == vmClasses::IdentityObject_klass()) { identity_object_specified = true; break; } + if (lookup_class_by_id(_interfaces->at(i)) == vmClasses::PrimitiveObject_klass()) { + primitive_object_specified = true; + break; + } } expected_num_interfaces = actual_num_interfaces; - if (identity_object_implemented && !identity_object_specified) { + if ( (identity_object_implemented && !identity_object_specified) || + (primitive_object_implemented && !primitive_object_specified) ){ // Backwards compatibility -- older classlists do not know about - // java.lang.IdentityObject. + // java.lang.IdentityObject or java.lang.PrimitiveObject expected_num_interfaces--; } - if (specified_num_interfaces != expected_num_interfaces) { print_specified_interfaces(); print_actual_interfaces(k); @@ -684,6 +694,11 @@ InstanceKlass* ClassListParser::lookup_interface_for_current_class(Symbol* inter // java.lang.IdentityObject. return vmClasses::IdentityObject_klass(); } + if (interface_name == vmSymbols::java_lang_PrimitiveObject()) { + // Backwards compatibility -- older classlists do not know about + // java.lang.PrimitiveObject. + return vmClasses::PrimitiveObject_klass(); + } const int n = _interfaces->length(); if (n == 0) { diff --git a/src/hotspot/share/classfile/vmClassMacros.hpp b/src/hotspot/share/classfile/vmClassMacros.hpp index ba3341c9fd4..17a9279bb80 100644 --- a/src/hotspot/share/classfile/vmClassMacros.hpp +++ b/src/hotspot/share/classfile/vmClassMacros.hpp @@ -51,6 +51,7 @@ /* well-known classes */ \ do_klass(Object_klass, java_lang_Object ) \ do_klass(IdentityObject_klass, java_lang_IdentityObject ) \ + do_klass(PrimitiveObject_klass, java_lang_PrimitiveObject ) \ do_klass(String_klass, java_lang_String ) \ do_klass(Class_klass, java_lang_Class ) \ do_klass(Cloneable_klass, java_lang_Cloneable ) \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 11c941a10ea..5a20d0596e0 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -56,6 +56,7 @@ template(java_lang_System, "java/lang/System") \ template(java_lang_Object, "java/lang/Object") \ template(java_lang_IdentityObject, "java/lang/IdentityObject") \ + template(java_lang_PrimitiveObject, "java/lang/PrimitiveObject") \ template(java_lang_Class, "java/lang/Class") \ template(java_lang_Package, "java/lang/Package") \ template(java_lang_Module, "java/lang/Module") \ diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 968f44e324f..c258896f777 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -130,6 +130,7 @@ Array* Universe::_the_empty_short_array = NULL; Array* Universe::_the_empty_klass_array = NULL; Array* Universe::_the_empty_instance_klass_array = NULL; Array* Universe::_the_single_IdentityObject_klass_array = NULL; +Array* Universe::_the_single_PrimitiveObject_klass_array = NULL; Array* Universe::_the_empty_method_array = NULL; // These variables are guarded by FullGCALot_lock. @@ -221,6 +222,7 @@ void Universe::metaspace_pointers_do(MetaspaceClosure* it) { it->push(&_the_empty_method_array); it->push(&_the_array_interfaces_array); it->push(&_the_single_IdentityObject_klass_array); + it->push(&_the_single_PrimitiveObject_klass_array); _finalizer_register_cache->metaspace_pointers_do(it); _loader_addClass_cache->metaspace_pointers_do(it); @@ -272,6 +274,7 @@ void Universe::serialize(SerializeClosure* f) { f->do_ptr((void**)&_the_empty_klass_array); f->do_ptr((void**)&_the_empty_instance_klass_array); f->do_ptr((void**)&_the_single_IdentityObject_klass_array); + f->do_ptr((void**)&_the_single_PrimitiveObject_klass_array); _finalizer_register_cache->serialize(f); _loader_addClass_cache->serialize(f); _throw_illegal_access_error_cache->serialize(f); @@ -360,6 +363,8 @@ void Universe::genesis(TRAPS) { assert(_the_single_IdentityObject_klass_array->at(0) == vmClasses::IdentityObject_klass(), "u3"); + assert(_the_single_PrimitiveObject_klass_array->at(0) == + vmClasses::PrimitiveObject_klass(), "u3"); } else #endif { @@ -477,7 +482,16 @@ void Universe::initialize_the_single_IdentityObject_klass_array(InstanceKlass* i Array* array = MetadataFactory::new_array(ik->class_loader_data(), 1, NULL, CHECK); array->at_put(0, ik); _the_single_IdentityObject_klass_array = array; - } +} + +void Universe::initialize_the_single_PrimitiveObject_klass_array(InstanceKlass* ik, TRAPS) { + assert(_the_single_PrimitiveObject_klass_array == NULL, "Must not be initialized twice"); + assert(ik->name() == vmSymbols::java_lang_PrimitiveObject(), "Must be"); + Array* array = MetadataFactory::new_array(ik->class_loader_data(), 1, NULL, CHECK); + array->at_put(0, ik); + _the_single_PrimitiveObject_klass_array = array; +} + void Universe::fixup_mirrors(TRAPS) { // Bootstrap problem: all classes gets a mirror (java.lang.Class instance) assigned eagerly, diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp index 014dd4ea1a6..13fa1f843fe 100644 --- a/src/hotspot/share/memory/universe.hpp +++ b/src/hotspot/share/memory/universe.hpp @@ -123,7 +123,8 @@ class Universe: AllStatic { static Array* _the_empty_short_array; // Canonicalized short array static Array* _the_empty_klass_array; // Canonicalized klass array static Array* _the_empty_instance_klass_array; // Canonicalized instance klass array - static Array* _the_single_IdentityObject_klass_array; + static Array* _the_single_IdentityObject_klass_array; // Common single interface array for IdentityObjects + static Array* _the_single_PrimitiveObject_klass_array; // Common single interface array for PrimitiveObjects static Array* _the_empty_method_array; // Canonicalized method array static Array* _the_array_interfaces_array; @@ -296,6 +297,12 @@ class Universe: AllStatic { return _the_single_IdentityObject_klass_array; } static void initialize_the_single_IdentityObject_klass_array(InstanceKlass* ik, TRAPS); + static Array* the_single_PrimitiveObject_klass_array() { + assert(_the_single_PrimitiveObject_klass_array != NULL, "Must be initialized before use"); + assert(_the_single_PrimitiveObject_klass_array->length() == 1, "Sanity check"); + return _the_single_PrimitiveObject_klass_array; + } + static void initialize_the_single_PrimitiveObject_klass_array(InstanceKlass* ik, TRAPS); // OutOfMemoryError support. Returns an error with the required message. The returned error // may or may not have a backtrace. If error has a backtrace then the stack trace is already diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index ad0580ae8dd..af69193f41b 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -633,7 +633,8 @@ void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, Array* sti = (super_klass == NULL) ? NULL : InstanceKlass::cast(super_klass)->transitive_interfaces(); if (ti != sti && ti != NULL && !ti->is_shared() && - ti != Universe::the_single_IdentityObject_klass_array()) { + ti != Universe::the_single_IdentityObject_klass_array() && + ti != Universe::the_single_PrimitiveObject_klass_array()) { MetadataFactory::free_array(loader_data, ti); } } @@ -641,7 +642,8 @@ void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, // local interfaces can be empty if (local_interfaces != Universe::the_empty_instance_klass_array() && local_interfaces != NULL && !local_interfaces->is_shared() && - local_interfaces != Universe::the_single_IdentityObject_klass_array()) { + local_interfaces != Universe::the_single_IdentityObject_klass_array() && + local_interfaces != Universe::the_single_PrimitiveObject_klass_array()) { MetadataFactory::free_array(loader_data, local_interfaces); } } diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index e875b9884ee..17bd6f58d41 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -292,7 +292,8 @@ class InstanceKlass: public Klass { _misc_is_declared_atomic = 1 << 19, // implements jl.NonTearable _misc_invalid_inline_super = 1 << 20, // invalid super type for an inline type _misc_invalid_identity_super = 1 << 21, // invalid super type for an identity type - _misc_has_injected_identityObject = 1 << 22 // IdentityObject has been injected by the JVM + _misc_has_injected_identityObject = 1 << 22, // IdentityObject has been injected by the JVM + _misc_has_injected_primitiveObject = 1 << 23 // PrimitiveObject has been injected by the JVM }; // (*) An inline type is considered empty if it contains no non-static fields or @@ -483,6 +484,14 @@ class InstanceKlass: public Klass { _misc_flags |= _misc_has_injected_identityObject; } + bool has_injected_primitiveObject() const { + return (_misc_flags & _misc_has_injected_primitiveObject); + } + + void set_has_injected_primitiveObject() { + _misc_flags |= _misc_has_injected_primitiveObject; + } + // field sizes int nonstatic_field_size() const { return _nonstatic_field_size; } void set_nonstatic_field_size(int size) { _nonstatic_field_size = size; } diff --git a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp index 59a68eedc31..341c8c6175d 100644 --- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp +++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp @@ -896,11 +896,14 @@ void JvmtiClassFileReconstituter::write_class_file_format() { // JVMSpec| u2 interfaces[interfaces_count]; Array* interfaces = ik()->local_interfaces(); int num_interfaces = interfaces->length(); - write_u2(num_interfaces - (ik()->has_injected_identityObject() ? 1 : 0) ); + write_u2(num_interfaces - + (ik()->has_injected_identityObject() || ik()->has_injected_primitiveObject() ? 1 : 0)); + for (int index = 0; index < num_interfaces; index++) { HandleMark hm(thread()); InstanceKlass* iik = interfaces->at(index); - if (!ik()->has_injected_identityObject() || iik != vmClasses::IdentityObject_klass()) { + if ( (!ik()->has_injected_identityObject() || iik != vmClasses::IdentityObject_klass()) && + (!ik()->has_injected_primitiveObject() || iik != vmClasses::PrimitiveObject_klass())) { write_u2(class_symbol_to_cpool_index(iik->name())); } } diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index 048b1299d5f..dd5751e5df5 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -338,6 +338,10 @@ bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) { if (k->name() == vmSymbols::java_lang_IdentityObject()) { return false; } + // Cannot redefine or retransform interface java.lang.PrimitiveObject. + if (k->name() == vmSymbols::java_lang_PrimitiveObject()) { + return false; + } // Cannot redefine or retransform a hidden or an unsafe anonymous class. if (InstanceKlass::cast(k)->is_hidden() || diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/AbstractSpecified.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/AbstractSpecified.java new file mode 100644 index 00000000000..27547d02d40 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/AbstractSpecified.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 abstract class AbstractSpecified implements PrimitiveObject { + +} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/InterfaceSpecified.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/InterfaceSpecified.java new file mode 100644 index 00000000000..8242d767cfe --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/InterfaceSpecified.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 interface InterfaceSpecified extends PrimitiveObject { + +} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveType.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveType.java new file mode 100644 index 00000000000..9ae07418e35 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveType.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 primitive class PrimitiveType { + +} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveTypeSpecified.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveTypeSpecified.java new file mode 100644 index 00000000000..9e967310f06 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveTypeSpecified.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 primitive class PrimitiveTypeSpecified implements PrimitiveObject { + +} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveWithInterface.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveWithInterface.java new file mode 100644 index 00000000000..847b43dba7a --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveWithInterface.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 primitive class PrimitiveWithInterface implements InterfaceSpecified { + +} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveWithSuper.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveWithSuper.java new file mode 100644 index 00000000000..2807a2d790c --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveWithSuper.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 primitive class PrimitiveWithSuper extends AbstractSpecified { + +} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/TestPrimitiveObject.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/TestPrimitiveObject.java new file mode 100644 index 00000000000..048e59cfa97 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/TestPrimitiveObject.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 + * @summary test that PrimitiveObject interface is injected correctly + * @library /test/lib /test/jdk/lib/testlibrary/bytecode /test/jdk/java/lang/invoke/common + * @build jdk.experimental.bytecode.BasicClassBuilder + * @compile TestPrimitiveObject.java + * @compile PrimitiveType.java PrimitiveTypeSpecified.java + * @compile AbstractSpecified.java InterfaceSpecified.java + * @compile PrimitiveWithSuper.java PrimitiveWithInterface.java + * @run main/othervm -verify TestPrimitiveObject + */ + +import java.lang.invoke.*; +import jdk.experimental.bytecode.*; + +public class TestPrimitiveObject { + + public static void main(String[] args) { + checkNegativePrimitiveObjects(); + checkPositivePrimitiveObjects(); + checkIcceOnInvalidSupers(); + } + + static void checkNegativePrimitiveObjects() { + Class[] clazzes = new Class[] { + String.class, Comparable.class, Number.class + }; + for (Class clazz : clazzes) { + checkPrimitiveObject(clazz, false); + } + } + + static void checkPositivePrimitiveObjects() { + Class[] clazzes = new Class[] { + PrimitiveType.class, PrimitiveTypeSpecified.class, + AbstractSpecified.class, InterfaceSpecified.class, + PrimitiveWithSuper.class, PrimitiveWithInterface.class + }; + for (Class clazz : clazzes) { + checkPrimitiveObject(clazz, true); + } + } + + static void checkPrimitiveObject(Class c, boolean subtype) { + boolean s; + try { + c.asSubclass(PrimitiveObject.class); + s = true; + } catch(ClassCastException e) { + s = false; + } + if (subtype != s) { + if (subtype) { + throw new RuntimeException("Type " + c.getName() + " is missing PrimitiveObject"); + } else { + throw new RuntimeException("Type " + c.getName() + " should not implement PrimitiveObject"); + } + } + } + + // Define classes that implement PrimitiveObject but are invalid supers + static void checkIcceOnInvalidSupers() { + MethodHandles.Lookup mhLookup = MethodHandles.lookup(); + checkIcce(mhLookup, createClass().build()); + checkIcce(mhLookup, createAbstractWithField().build()); + checkIcce(mhLookup, createAbstractIdentity().build()); + checkIcce(mhLookup, createIdentity().build()); + } + + static ClassBuilder createClass() { + return new BasicClassBuilder("ANormalClass", 61, 0) + .withSuperclass("java/lang/Object") + .withSuperinterface("java/lang/PrimitiveObject"); + } + + static ClassBuilder createAbstractWithField() { + return new BasicClassBuilder("AbstractWithField", 61, 0) + .withSuperclass("java/lang/Object") + .withFlags(Flag.ACC_ABSTRACT) + .withField("aFieldWhichIsIllegalAsAnAbstractSuperToPrimitiveObject", "I") + .withSuperinterface("java/lang/PrimitiveObject"); + } + + static ClassBuilder createAbstractIdentity() { + return new BasicClassBuilder("AbstractIdentity", 61, 0) + .withSuperclass("java/lang/Object") + .withFlags(Flag.ACC_ABSTRACT) + .withSuperinterface("java/lang/IdentityObject") + .withSuperinterface("java/lang/PrimitiveObject"); + } + + static ClassBuilder createIdentity() { + return new BasicClassBuilder("Identity", 61, 0) + .withSuperclass("java/lang/Object") + .withSuperinterface("java/lang/IdentityObject") + .withSuperinterface("java/lang/PrimitiveObject"); + } + + static void checkIcce(MethodHandles.Lookup mhLookup, byte[] clazzBytes) { + try { + mhLookup.defineClass(clazzBytes); + throw new RuntimeException("Expected IncompatibleClassChangeError"); + } + catch (IllegalAccessException ill) { throw new RuntimeException(ill); } + catch (IncompatibleClassChangeError icce) { System.out.println(icce); } + } + +} diff --git a/test/langtools/tools/javac/valhalla/lworld-values/InstanceOfTopTypeTest.java b/test/langtools/tools/javac/valhalla/lworld-values/InstanceOfTopTypeTest.java index 084f31c4d25..c3c0b1458bc 100644 --- a/test/langtools/tools/javac/valhalla/lworld-values/InstanceOfTopTypeTest.java +++ b/test/langtools/tools/javac/valhalla/lworld-values/InstanceOfTopTypeTest.java @@ -58,8 +58,8 @@ public static void main(String [] args) { if (oa[0] instanceof IdentityObject) throw new AssertionError("Broken"); if (oa[0] instanceof PrimitiveObject) - points++; - if (points != 4) + points++; // 6 + if (points != 6) throw new AssertionError("Broken top type set up " + points); } } diff --git a/test/langtools/tools/javac/valhalla/lworld-values/TopInterfaceTest.java b/test/langtools/tools/javac/valhalla/lworld-values/TopInterfaceTest.java index 24a98bdd1a3..571f716d813 100644 --- a/test/langtools/tools/javac/valhalla/lworld-values/TopInterfaceTest.java +++ b/test/langtools/tools/javac/valhalla/lworld-values/TopInterfaceTest.java @@ -49,7 +49,7 @@ public static void main(String args[]) { Class [] ca = inln_o.getClass().getInterfaces(); - if (ca.length != 0) + if (ca.length != 1 || !ca[0].getCanonicalName().equals("java.lang.PrimitiveObject")) throw new AssertionError("Found wrong super interfaces");