Skip to content
Permalink
Browse files
8262104: [lworld] Runtime should automagically have primitive classes…
… implement PrimitiveObject

Reviewed-by: fparain
  • Loading branch information
David Simms committed Feb 25, 2021
1 parent 1816db3 commit b5bf7a90ccaeff2040c860ff5e8a4edf52b135e4
Showing with 396 additions and 24 deletions.
  1. +35 −10 src/hotspot/share/classfile/classFileParser.cpp
  2. +2 −1 src/hotspot/share/classfile/classFileParser.hpp
  3. +18 −3 src/hotspot/share/classfile/classListParser.cpp
  4. +1 −0 src/hotspot/share/classfile/vmClassMacros.hpp
  5. +1 −0 src/hotspot/share/classfile/vmSymbols.hpp
  6. +15 −1 src/hotspot/share/memory/universe.cpp
  7. +8 −1 src/hotspot/share/memory/universe.hpp
  8. +4 −2 src/hotspot/share/oops/instanceKlass.cpp
  9. +10 −1 src/hotspot/share/oops/instanceKlass.hpp
  10. +5 −2 src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp
  11. +4 −0 src/hotspot/share/prims/jvmtiRedefineClasses.cpp
  12. +27 −0 test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/AbstractSpecified.java
  13. +26 −0 test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/InterfaceSpecified.java
  14. +26 −0 test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveType.java
  15. +26 −0 test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveTypeSpecified.java
  16. +27 −0 test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveWithInterface.java
  17. +27 −0 test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/PrimitiveWithSuper.java
  18. +131 −0 test/hotspot/jtreg/runtime/valhalla/inlinetypes/primitiveObject/TestPrimitiveObject.java
  19. +2 −2 test/langtools/tools/javac/valhalla/lworld-values/InstanceOfTopTypeTest.java
  20. +1 −1 test/langtools/tools/javac/valhalla/lworld-values/TopInterfaceTest.java
@@ -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<InstanceKlass*>* 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<InstanceKlass*>* const new_result =
MetadataFactory::new_array<InstanceKlass*>(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<InstanceKlass*>(_loader_data, itfs_len, NULL, CHECK);
for (int i = 0; i < itfs_len; i++) {
@@ -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);
@@ -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) {
@@ -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 ) \
@@ -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") \
@@ -130,6 +130,7 @@ Array<u2>* Universe::_the_empty_short_array = NULL;
Array<Klass*>* Universe::_the_empty_klass_array = NULL;
Array<InstanceKlass*>* Universe::_the_empty_instance_klass_array = NULL;
Array<InstanceKlass*>* Universe::_the_single_IdentityObject_klass_array = NULL;
Array<InstanceKlass*>* Universe::_the_single_PrimitiveObject_klass_array = NULL;
Array<Method*>* 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<InstanceKlass*>* array = MetadataFactory::new_array<InstanceKlass*>(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<InstanceKlass*>* array = MetadataFactory::new_array<InstanceKlass*>(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,
@@ -123,7 +123,8 @@ class Universe: AllStatic {
static Array<u2>* _the_empty_short_array; // Canonicalized short array
static Array<Klass*>* _the_empty_klass_array; // Canonicalized klass array
static Array<InstanceKlass*>* _the_empty_instance_klass_array; // Canonicalized instance klass array
static Array<InstanceKlass*>* _the_single_IdentityObject_klass_array;
static Array<InstanceKlass*>* _the_single_IdentityObject_klass_array; // Common single interface array for IdentityObjects
static Array<InstanceKlass*>* _the_single_PrimitiveObject_klass_array; // Common single interface array for PrimitiveObjects
static Array<Method*>* _the_empty_method_array; // Canonicalized method array

static Array<Klass*>* _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<InstanceKlass*>* 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
@@ -633,15 +633,17 @@ void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data,
Array<InstanceKlass*>* 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<InstanceKlass*>(loader_data, ti);
}
}

// 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<InstanceKlass*>(loader_data, local_interfaces);
}
}
@@ -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; }
@@ -896,11 +896,14 @@ void JvmtiClassFileReconstituter::write_class_file_format() {
// JVMSpec| u2 interfaces[interfaces_count];
Array<InstanceKlass*>* 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()));
}
}
@@ -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() ||
@@ -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 {

}

0 comments on commit b5bf7a9

Please sign in to comment.