8237766: Enhance signature API to include ResolvingSignatureStream

New ResolvingSignatureStream class provides the capability to easily walk through the differing parts of a signature while resolving or querying its underlying types.

Co-authored-by: John Rose <john.r.rose@oracle.com>
Reviewed-by: coleenp, fparain, hseigel
This commit is contained in:
Lois Foltan 2020-03-02 18:42:22 +00:00
parent e455d382e7
commit c280d98e80
5 changed files with 146 additions and 116 deletions

View File

@ -969,8 +969,7 @@ Klass* SystemDictionary::find_instance_or_array_klass(Symbol* class_name,
if (t != T_OBJECT) {
k = Universe::typeArrayKlassObj(t);
} else {
Symbol* obj_class = ss.as_symbol();
k = SystemDictionary::find(obj_class, class_loader, protection_domain, THREAD);
k = SystemDictionary::find(ss.as_symbol(), class_loader, protection_domain, THREAD);
}
if (k != NULL) {
k = k->array_klass_or_null(ndims);
@ -2527,8 +2526,8 @@ static bool is_always_visible_class(oop mirror) {
InstanceKlass::cast(klass)->is_same_class_package(SystemDictionary::MethodHandle_klass())); // java.lang.invoke
}
// Find or construct the Java mirror (java.lang.Class instance) for a
// for the given field type signature, as interpreted relative to the
// Find or construct the Java mirror (java.lang.Class instance) for
// the given field type signature, as interpreted relative to the
// given class loader. Handles primitives, void, references, arrays,
// and all other reflectable types, except method types.
// N.B. Code in reflection should use this entry point.
@ -2538,57 +2537,33 @@ Handle SystemDictionary::find_java_mirror_for_type(Symbol* signature,
Handle protection_domain,
SignatureStream::FailureMode failure_mode,
TRAPS) {
Handle empty;
assert(accessing_klass == NULL || (class_loader.is_null() && protection_domain.is_null()),
"one or the other, or perhaps neither");
SignatureStream ss(signature, false);
// What we have here must be a valid field descriptor,
// and all valid field descriptors are supported.
// Produce the same java.lang.Class that reflection reports.
if (ss.is_primitive() || (ss.type() == T_VOID)) {
// It's a primitive. (Void has a primitive mirror too.)
return Handle(THREAD, java_lang_Class::primitive_mirror(ss.type()));
} else if (ss.is_reference()) {
// It's a reference type.
if (accessing_klass != NULL) {
class_loader = Handle(THREAD, accessing_klass->class_loader());
protection_domain = Handle(THREAD, accessing_klass->protection_domain());
}
Klass* constant_type_klass;
if (failure_mode == SignatureStream::ReturnNull) {
constant_type_klass = resolve_or_null(signature, class_loader, protection_domain,
CHECK_(empty));
} else {
bool throw_error = (failure_mode == SignatureStream::NCDFError);
constant_type_klass = resolve_or_fail(signature, class_loader, protection_domain,
throw_error, CHECK_(empty));
}
if (constant_type_klass == NULL) {
return Handle(); // report failure this way
}
Handle mirror(THREAD, constant_type_klass->java_mirror());
if (accessing_klass != NULL) {
class_loader = Handle(THREAD, accessing_klass->class_loader());
protection_domain = Handle(THREAD, accessing_klass->protection_domain());
}
ResolvingSignatureStream ss(signature, class_loader, protection_domain, false);
oop mirror_oop = ss.as_java_mirror(failure_mode, CHECK_NH);
if (mirror_oop == NULL) {
return Handle(); // report failure this way
}
Handle mirror(THREAD, mirror_oop);
if (accessing_klass != NULL) {
// Check accessibility, emulating ConstantPool::verify_constant_pool_resolve.
if (accessing_klass != NULL) {
Klass* sel_klass = constant_type_klass;
Klass* sel_klass = java_lang_Class::as_Klass(mirror());
if (sel_klass != NULL) {
bool fold_type_to_class = true;
LinkResolver::check_klass_accessability(accessing_klass, sel_klass,
fold_type_to_class, CHECK_(empty));
fold_type_to_class, CHECK_NH);
}
return mirror;
}
// Fall through to an error.
assert(false, "unsupported mirror syntax");
THROW_MSG_(vmSymbols::java_lang_InternalError(), "unsupported mirror syntax", empty);
return mirror;
}

View File

@ -1680,7 +1680,6 @@ void Method::init_intrinsic_id() {
}
}
// These two methods are static since a GC may move the Method
bool Method::load_signature_classes(const methodHandle& m, TRAPS) {
if (!THREAD->can_call_java()) {
// There is nothing useful this routine can do from within the Compile thread.
@ -1689,16 +1688,11 @@ bool Method::load_signature_classes(const methodHandle& m, TRAPS) {
return false;
}
bool sig_is_loaded = true;
Handle class_loader(THREAD, m->method_holder()->class_loader());
Handle protection_domain(THREAD, m->method_holder()->protection_domain());
ResourceMark rm(THREAD);
Symbol* signature = m->signature();
for(SignatureStream ss(signature); !ss.is_done(); ss.next()) {
for (ResolvingSignatureStream ss(m()); !ss.is_done(); ss.next()) {
if (ss.is_reference()) {
Symbol* sym = ss.as_symbol();
Symbol* name = sym;
Klass* klass = SystemDictionary::resolve_or_null(name, class_loader,
protection_domain, THREAD);
// load everything, including arrays "[Lfoo;"
Klass* klass = ss.as_klass(SignatureStream::ReturnNull, THREAD);
// We are loading classes eagerly. If a ClassNotFoundException or
// a LinkageError was generated, be sure to ignore it.
if (HAS_PENDING_EXCEPTION) {
@ -1716,14 +1710,13 @@ bool Method::load_signature_classes(const methodHandle& m, TRAPS) {
}
bool Method::has_unloaded_classes_in_signature(const methodHandle& m, TRAPS) {
Handle class_loader(THREAD, m->method_holder()->class_loader());
Handle protection_domain(THREAD, m->method_holder()->protection_domain());
ResourceMark rm(THREAD);
Symbol* signature = m->signature();
for(SignatureStream ss(signature); !ss.is_done(); ss.next()) {
for(ResolvingSignatureStream ss(m()); !ss.is_done(); ss.next()) {
if (ss.type() == T_OBJECT) {
Symbol* name = ss.as_symbol();
Klass* klass = SystemDictionary::find(name, class_loader, protection_domain, THREAD);
// Do not use ss.is_reference() here, since we don't care about
// unloaded array component types.
Klass* klass = ss.as_klass_if_loaded(THREAD);
assert(!HAS_PENDING_EXCEPTION, "as_klass_if_loaded contract");
if (klass == NULL) return true;
}
}

View File

@ -52,7 +52,11 @@
#include "runtime/thread.inline.hpp"
#include "runtime/vframe.inline.hpp"
static void trace_class_resolution(const Klass* to_class) {
static void trace_class_resolution(oop mirror) {
if (mirror == NULL || java_lang_Class::is_primitive(mirror)) {
return;
}
Klass* to_class = java_lang_Class::as_Klass(mirror);
ResourceMark rm;
int line_number = -1;
const char * source_file = NULL;
@ -750,33 +754,6 @@ void Reflection::check_for_inner_class(const InstanceKlass* outer, const Instanc
);
}
// Utility method converting a single SignatureStream element into java.lang.Class instance
static oop get_mirror_from_signature(const methodHandle& method,
SignatureStream* ss,
TRAPS) {
if (is_reference_type(ss->type())) {
Symbol* name = ss->as_symbol();
oop loader = method->method_holder()->class_loader();
oop protection_domain = method->method_holder()->protection_domain();
const Klass* k = SystemDictionary::resolve_or_fail(name,
Handle(THREAD, loader),
Handle(THREAD, protection_domain),
true,
CHECK_NULL);
if (log_is_enabled(Debug, class, resolve)) {
trace_class_resolution(k);
}
return k->java_mirror();
}
assert(ss->type() != T_VOID || ss->at_return_type(),
"T_VOID should only appear as return type");
return java_lang_Class::primitive_mirror(ss->type());
}
static objArrayHandle get_parameter_types(const methodHandle& method,
int parameter_count,
oop* return_type,
@ -787,19 +764,20 @@ static objArrayHandle get_parameter_types(const methodHandle& method,
int index = 0;
// Collect parameter types
ResourceMark rm(THREAD);
Symbol* signature = method->signature();
SignatureStream ss(signature);
while (!ss.at_return_type()) {
oop mirror = get_mirror_from_signature(method, &ss, CHECK_(objArrayHandle()));
mirrors->obj_at_put(index++, mirror);
ss.next();
for (ResolvingSignatureStream ss(method()); !ss.is_done(); ss.next()) {
oop mirror = ss.as_java_mirror(SignatureStream::NCDFError, CHECK_(objArrayHandle()));
if (log_is_enabled(Debug, class, resolve)) {
trace_class_resolution(mirror);
}
if (!ss.at_return_type()) {
mirrors->obj_at_put(index++, mirror);
} else if (return_type != NULL) {
// Collect return type as well
assert(ss.at_return_type(), "return type should be present");
*return_type = mirror;
}
}
assert(index == parameter_count, "invalid parameter count");
if (return_type != NULL) {
// Collect return type as well
assert(ss.at_return_type(), "return type should be present");
*return_type = get_mirror_from_signature(method, &ss, CHECK_(objArrayHandle()));
}
return mirrors;
}
@ -808,24 +786,11 @@ static objArrayHandle get_exception_types(const methodHandle& method, TRAPS) {
}
static Handle new_type(Symbol* signature, Klass* k, TRAPS) {
SignatureStream ss(signature, false);
// Basic types
BasicType type = ss.is_reference() ? T_OBJECT : ss.type();
if (type != T_OBJECT) {
return Handle(THREAD, Universe::java_mirror(type));
}
Klass* result =
SystemDictionary::resolve_or_fail(signature,
Handle(THREAD, k->class_loader()),
Handle(THREAD, k->protection_domain()),
true, CHECK_(Handle()));
ResolvingSignatureStream ss(signature, k, false);
oop nt = ss.as_java_mirror(SignatureStream::NCDFError, CHECK_NH);
if (log_is_enabled(Debug, class, resolve)) {
trace_class_resolution(result);
trace_class_resolution(nt);
}
oop nt = result->java_mirror();
return Handle(THREAD, nt);
}

View File

@ -373,7 +373,9 @@ Symbol* SignatureStream::find_symbol() {
Klass* SignatureStream::as_klass(Handle class_loader, Handle protection_domain,
FailureMode failure_mode, TRAPS) {
if (!is_reference()) return NULL;
if (!is_reference()) {
return NULL;
}
Symbol* name = as_symbol();
Klass* k = NULL;
if (failure_mode == ReturnNull) {
@ -401,10 +403,13 @@ Klass* SignatureStream::as_klass(Handle class_loader, Handle protection_domain,
oop SignatureStream::as_java_mirror(Handle class_loader, Handle protection_domain,
FailureMode failure_mode, TRAPS) {
if (!is_reference())
if (!is_reference()) {
return Universe::java_mirror(type());
}
Klass* klass = as_klass(class_loader, protection_domain, failure_mode, CHECK_NULL);
if (klass == NULL) return NULL;
if (klass == NULL) {
return NULL;
}
return klass->java_mirror();
}
@ -414,6 +419,52 @@ void SignatureStream::skip_to_return_type() {
}
}
ResolvingSignatureStream::ResolvingSignatureStream(Symbol* signature,
Handle class_loader,
Handle protection_domain,
bool is_method)
: SignatureStream(signature, is_method),
_class_loader(class_loader), _protection_domain(protection_domain)
{
initialize_load_origin(NULL);
}
ResolvingSignatureStream::ResolvingSignatureStream(Symbol* signature, Klass* load_origin, bool is_method)
: SignatureStream(signature, is_method)
{
assert(load_origin != NULL, "");
initialize_load_origin(load_origin);
}
ResolvingSignatureStream::ResolvingSignatureStream(const Method* method)
: SignatureStream(method->signature(), true)
{
initialize_load_origin(method->method_holder());
}
ResolvingSignatureStream::ResolvingSignatureStream(fieldDescriptor& field)
: SignatureStream(field.signature(), false)
{
initialize_load_origin(field.field_holder());
}
void ResolvingSignatureStream::cache_handles(TRAPS) {
assert(_load_origin != NULL, "");
_class_loader = Handle(THREAD, _load_origin->class_loader());
_protection_domain = Handle(THREAD, _load_origin->protection_domain());
}
Klass* ResolvingSignatureStream::as_klass_if_loaded(TRAPS) {
Klass* klass = as_klass(CachedOrNull, THREAD);
// SD::find does not trigger loading, so there should be no throws
// Still, bad things can happen, so we CHECK_NULL and ask callers
// to do likewise.
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
}
return klass;
}
#ifdef ASSERT
extern bool signature_constants_sane(); // called from basic_types_init()

View File

@ -564,6 +564,52 @@ class SignatureStream : public StackObj {
oop as_java_mirror(Handle class_loader, Handle protection_domain, FailureMode failure_mode, TRAPS);
};
// Specialized SignatureStream: used for invoking SystemDictionary to either find
// or resolve the underlying type when iterating over a
// Java descriptor (or parts of it).
class ResolvingSignatureStream : public SignatureStream {
Klass* _load_origin;
bool _handles_cached;
Handle _class_loader; // cached when needed
Handle _protection_domain; // cached when needed
void initialize_load_origin(Klass* load_origin) {
_load_origin = load_origin;
_handles_cached = (load_origin == NULL);
}
void need_handles(TRAPS) {
if (!_handles_cached) {
cache_handles(THREAD);
_handles_cached = true;
}
}
void cache_handles(TRAPS);
public:
ResolvingSignatureStream(Symbol* signature, Klass* load_origin, bool is_method = true);
ResolvingSignatureStream(Symbol* signature, Handle class_loader, Handle protection_domain, bool is_method = true);
ResolvingSignatureStream(const Method* method);
ResolvingSignatureStream(fieldDescriptor& field);
Klass* load_origin() { return _load_origin; }
Handle class_loader(TRAPS) { need_handles(THREAD); return _class_loader; }
Handle protection_domain(TRAPS) { need_handles(THREAD); return _protection_domain; }
Klass* as_klass_if_loaded(TRAPS);
Klass* as_klass(FailureMode failure_mode, TRAPS) {
need_handles(THREAD);
return SignatureStream::as_klass(_class_loader, _protection_domain,
failure_mode, THREAD);
}
oop as_java_mirror(FailureMode failure_mode, TRAPS) {
if (is_reference()) {
need_handles(THREAD);
}
return SignatureStream::as_java_mirror(_class_loader, _protection_domain,
failure_mode, THREAD);
}
};
// Here is how all the SignatureIterator classes invoke the
// SignatureStream engine to do their parsing.
template<typename T> inline