class ClassFileParser VALUE_OBJ_CLASS_SPEC {
private:
bool _need_verify;
bool _relax_verify;
u2 _major_version;
u2 _minor_version;
u2 _this_class_index;
Symbol* _class_name;
ClassLoaderData* _loader_data;
KlassHandle _host_klass;
GrowableArray<Handle>* _cp_patches; // overrides for CP entries
bool _has_finalizer;
bool _has_empty_finalizer;
bool _has_vanilla_constructor;
int _max_bootstrap_specifier_index; // detects BSS values
bool _synthetic_flag;
int _sde_length;
char* _sde_buffer;
u2 _sourcefile_index;
u2 _generic_signature_index;
instanceKlassHandle _super_klass;
ConstantPool* _cp;
Array<u2>* _fields;
Array<Method*>* _methods;
Array<u2>* _inner_classes;
Array<Klass*>* _local_interfaces;
Array<Klass*>* _transitive_interfaces;
Annotations* _combined_annotations;
AnnotationArray* _annotations;
AnnotationArray* _type_annotations;
Array<AnnotationArray*>* _fields_annotations;
Array<AnnotationArray*>* _fields_type_annotations;
InstanceKlass* _klass; // InstanceKlass once created.
void set_class_synthetic_flag(bool x) { _synthetic_flag = x; }
void set_class_sourcefile_index(u2 x) { _sourcefile_index = x; }
void set_class_generic_signature_index(u2 x) { _generic_signature_index = x; }
void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; }
void create_combined_annotations(TRAPS);
void init_parsed_class_attributes(ClassLoaderData* loader_data) {
_loader_data = loader_data;
_synthetic_flag = false;
_sourcefile_index = 0;
_generic_signature_index = 0;
_sde_buffer = NULL;
_sde_length = 0;
_has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false;
_max_bootstrap_specifier_index = -1;
clear_class_metadata();
_klass = NULL;
}
void apply_parsed_class_attributes(instanceKlassHandle k); // update k
void apply_parsed_class_metadata(instanceKlassHandle k, int fields_count, TRAPS);
void clear_class_metadata() {
_cp = NULL;
_fields = NULL;
_methods = NULL;
_inner_classes = NULL;
_local_interfaces = NULL;
_transitive_interfaces = NULL;
_combined_annotations = NULL;
_annotations = _type_annotations = NULL;
_fields_annotations = _fields_type_annotations = NULL;
}
class AnnotationCollector {
public:
enum Location { _in_field, _in_method, _in_class };
enum ID {
_unknown = 0,
_method_CallerSensitive,
_method_ForceInline,
_method_DontInline,
_method_InjectedProfile,
_method_LambdaForm_Compiled,
_method_LambdaForm_Hidden,
_sun_misc_Contended,
_field_Stable,
_annotation_LIMIT
};
const Location _location;
int _annotations_present;
u2 _contended_group;
AnnotationCollector(Location location)
: _location(location), _annotations_present(0), _contended_group(0)
{
assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, "");
}
ID annotation_index(ClassLoaderData* loader_data, Symbol* name);
void set_annotation(ID id) {
assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
_annotations_present |= nth_bit((int)id);
}
void remove_annotation(ID id) {
assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
_annotations_present &= ~nth_bit((int)id);
}
bool has_any_annotations() const { return _annotations_present != 0; }
bool has_annotation(ID id) const { return (nth_bit((int)id) & _annotations_present) != 0; }
void set_contended_group(u2 group) { _contended_group = group; }
u2 contended_group() const { return _contended_group; }
bool is_contended() const { return has_annotation(_sun_misc_Contended); }
void set_stable(bool stable) { set_annotation(_field_Stable); }
bool is_stable() const { return has_annotation(_field_Stable); }
};
class FieldAnnotationCollector: public AnnotationCollector {
ClassLoaderData* _loader_data;
AnnotationArray* _field_annotations;
AnnotationArray* _field_type_annotations;
public:
FieldAnnotationCollector(ClassLoaderData* loader_data) :
AnnotationCollector(_in_field),
_loader_data(loader_data),
_field_annotations(NULL),
_field_type_annotations(NULL) {}
void apply_to(FieldInfo* f);
~FieldAnnotationCollector();
AnnotationArray* field_annotations() { return _field_annotations; }
AnnotationArray* field_type_annotations() { return _field_type_annotations; }
void set_field_annotations(AnnotationArray* a) { _field_annotations = a; }
void set_field_type_annotations(AnnotationArray* a) { _field_type_annotations = a; }
};
class MethodAnnotationCollector: public AnnotationCollector {
public:
MethodAnnotationCollector() : AnnotationCollector(_in_method) { }
void apply_to(methodHandle m);
};
class ClassAnnotationCollector: public AnnotationCollector {
public:
ClassAnnotationCollector() : AnnotationCollector(_in_class) { }
void apply_to(instanceKlassHandle k);
};
enum { fixed_buffer_size = 128 };
u_char linenumbertable_buffer[fixed_buffer_size];
ClassFileStream* _stream; // Actual input stream
enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names
ClassFileStream* stream() { return _stream; }
void set_stream(ClassFileStream* st) { _stream = st; }
void parse_constant_pool_entries(int length, TRAPS);
constantPoolHandle parse_constant_pool(TRAPS);
Array<Klass*>* parse_interfaces(int length,
Handle protection_domain,
Symbol* class_name,
bool* has_default_methods,
TRAPS);
void record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS);
instanceKlassHandle parse_super_class(int super_class_index, TRAPS);
void parse_field_attributes(u2 attributes_count,
bool is_static, u2 signature_index,
u2* constantvalue_index_addr,
bool* is_synthetic_addr,
u2* generic_signature_index_addr,
FieldAnnotationCollector* parsed_annotations,
TRAPS);
Array<u2>* parse_fields(Symbol* class_name,
bool is_interface,
FieldAllocationCount *fac,
u2* java_fields_count_ptr, TRAPS);
void print_field_layout(Symbol* name,
Array<u2>* fields,
constantPoolHandle cp,
int instance_size,
int instance_fields_start,
int instance_fields_end,
int static_fields_end);
methodHandle parse_method(bool is_interface,
AccessFlags* promoted_flags,
TRAPS);
Array<Method*>* parse_methods(bool is_interface,
AccessFlags* promoted_flags,
bool* has_final_method,
bool* declares_default_methods,
TRAPS);
intArray* sort_methods(Array<Method*>* methods);
u2* parse_exception_table(u4 code_length, u4 exception_table_length,
TRAPS);
void parse_linenumber_table(
u4 code_attribute_length, u4 code_length,
CompressedLineNumberWriteStream** write_stream, TRAPS);
u2* parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length,
u2* localvariable_table_length,
bool isLVTT, TRAPS);
u2* parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length,
TRAPS);
void parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index,
u1* u1_array, u2* u2_array, TRAPS);
u1* parse_stackmap_table(u4 code_attribute_length, TRAPS);
u2 parse_generic_signature_attribute(TRAPS);
void parse_classfile_sourcefile_attribute(TRAPS);
void parse_classfile_source_debug_extension_attribute(int length, TRAPS);
bool check_inner_classes_circularity(const ConstantPool* cp, int length, TRAPS);
u2 parse_classfile_inner_classes_attribute(const ConstantPool* cp,
u1* inner_classes_attribute_start,
bool parsed_enclosingmethod_attribute,
u2 enclosing_method_class_index,
u2 enclosing_method_method_index,
TRAPS);
void parse_classfile_attributes(ClassAnnotationCollector* parsed_annotations,
TRAPS);
void parse_classfile_synthetic_attribute(TRAPS);
void parse_classfile_signature_attribute(TRAPS);
void parse_classfile_bootstrap_methods_attribute(u4 attribute_length, TRAPS);
AnnotationArray* assemble_annotations(u1* runtime_visible_annotations,
int runtime_visible_annotations_length,
u1* runtime_invisible_annotations,
int runtime_invisible_annotations_length, TRAPS);
int skip_annotation(u1* buffer, int limit, int index);
int skip_annotation_value(u1* buffer, int limit, int index);
void parse_annotations(u1* buffer, int limit,
AnnotationCollector* result,
TRAPS);
unsigned int compute_oop_map_count(instanceKlassHandle super,
unsigned int nonstatic_oop_count,
int first_nonstatic_oop_offset);
void fill_oop_maps(instanceKlassHandle k,
unsigned int nonstatic_oop_map_count,
int* nonstatic_oop_offsets,
unsigned int* nonstatic_oop_counts);
void set_precomputed_flags(instanceKlassHandle k);
Array<Klass*>* compute_transitive_interfaces(instanceKlassHandle super,
Array<Klass*>* local_ifs, TRAPS);
void classfile_parse_error(const char* msg, TRAPS);
void classfile_parse_error(const char* msg, int index, TRAPS);
void classfile_parse_error(const char* msg, const char *name, TRAPS);
void classfile_parse_error(const char* msg, int index, const char *name, TRAPS);
void classfile_parse_error(const char* msg, const char* name, const char* signature, TRAPS);
inline void guarantee_property(bool b, const char* msg, TRAPS) {
if (!b) { classfile_parse_error(msg, CHECK); }
}
PRAGMA_DIAG_PUSH
PRAGMA_FORMAT_NONLITERAL_IGNORED
inline void assert_property(bool b, const char* msg, TRAPS) {
#ifdef ASSERT
if (!b) {
ResourceMark rm(THREAD);
fatal(err_msg(msg, _class_name->as_C_string()));
}
#endif
}
inline void assert_property(bool b, const char* msg, int index, TRAPS) {
#ifdef ASSERT
if (!b) {
ResourceMark rm(THREAD);
fatal(err_msg(msg, index, _class_name->as_C_string()));
}
#endif
}
PRAGMA_DIAG_POP
inline void check_property(bool property, const char* msg, int index, TRAPS) {
if (_need_verify) {
guarantee_property(property, msg, index, CHECK);
} else {
assert_property(property, msg, index, CHECK);
}
}
inline void check_property(bool property, const char* msg, TRAPS) {
if (_need_verify) {
guarantee_property(property, msg, CHECK);
} else {
assert_property(property, msg, CHECK);
}
}
inline void guarantee_property(bool b, const char* msg, int index, TRAPS) {
if (!b) { classfile_parse_error(msg, index, CHECK); }
}
inline void guarantee_property(bool b, const char* msg, const char *name, TRAPS) {
if (!b) { classfile_parse_error(msg, name, CHECK); }
}
inline void guarantee_property(bool b, const char* msg, int index, const char *name, TRAPS) {
if (!b) { classfile_parse_error(msg, index, name, CHECK); }
}
void throwIllegalSignature(
const char* type, Symbol* name, Symbol* sig, TRAPS);
bool is_supported_version(u2 major, u2 minor);
bool has_illegal_visibility(jint flags);
void verify_constantvalue(int constantvalue_index, int signature_index, TRAPS);
void verify_legal_utf8(const unsigned char* buffer, int length, TRAPS);
void verify_legal_class_name(Symbol* name, TRAPS);
void verify_legal_field_name(Symbol* name, TRAPS);
void verify_legal_method_name(Symbol* name, TRAPS);
void verify_legal_field_signature(Symbol* fieldname, Symbol* signature, TRAPS);
int verify_legal_method_signature(Symbol* methodname, Symbol* signature, TRAPS);
void verify_legal_class_modifiers(jint flags, TRAPS);
void verify_legal_field_modifiers(jint flags, bool is_interface, TRAPS);
void verify_legal_method_modifiers(jint flags, bool is_interface, Symbol* name, TRAPS);
bool verify_unqualified_name(char* name, unsigned int length, int type);
char* skip_over_field_name(char* name, bool slash_ok, unsigned int length);
char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS);
bool is_anonymous() {
assert(EnableInvokeDynamic || _host_klass.is_null(), "");
return _host_klass.not_null();
}
bool has_cp_patch_at(int index) {
assert(EnableInvokeDynamic, "");
assert(index >= 0, "oob");
return (_cp_patches != NULL
&& index < _cp_patches->length()
&& _cp_patches->adr_at(index)->not_null());
}
Handle cp_patch_at(int index) {
assert(has_cp_patch_at(index), "oob");
return _cp_patches->at(index);
}
Handle clear_cp_patch_at(int index) {
Handle patch = cp_patch_at(index);
_cp_patches->at_put(index, Handle());
assert(!has_cp_patch_at(index), "");
return patch;
}
void patch_constant_pool(constantPoolHandle cp, int index, Handle patch, TRAPS);
bool valid_klass_reference_at(int index) {
return _cp->is_within_bounds(index) &&
(EnableInvokeDynamic
? _cp->tag_at(index).is_klass_or_reference()
: _cp->tag_at(index).is_klass_reference());
}
bool valid_symbol_at(int cpool_index) {
return (_cp->is_within_bounds(cpool_index) &&
_cp->tag_at(cpool_index).is_utf8());
}
void copy_localvariable_table(ConstMethod* cm, int lvt_cnt,
u2* localvariable_table_length,
u2** localvariable_table_start,
int lvtt_cnt,
u2* localvariable_type_table_length,
u2** localvariable_type_table_start,
TRAPS);
void copy_method_annotations(ConstMethod* cm,
u1* runtime_visible_annotations,
int runtime_visible_annotations_length,
u1* runtime_invisible_annotations,
int runtime_invisible_annotations_length,
u1* runtime_visible_parameter_annotations,
int runtime_visible_parameter_annotations_length,
u1* runtime_invisible_parameter_annotations,
int runtime_invisible_parameter_annotations_length,
u1* runtime_visible_type_annotations,
int runtime_visible_type_annotations_length,
u1* runtime_invisible_type_annotations,
int runtime_invisible_type_annotations_length,
u1* annotation_default,
int annotation_default_length,
TRAPS);
void layout_fields(Handle class_loader, FieldAllocationCount* fac,
ClassAnnotationCollector* parsed_annotations,
FieldLayoutInfo* info, TRAPS);
public:
ClassFileParser(ClassFileStream* st) { set_stream(st); }
~ClassFileParser();
instanceKlassHandle parseClassFile(Symbol* name,
ClassLoaderData* loader_data,
Handle protection_domain,
TempNewSymbol& parsed_name,
bool verify,
TRAPS) {
KlassHandle no_host_klass;
return parseClassFile(name, loader_data, protection_domain, no_host_klass, NULL, parsed_name, verify, THREAD);
}
instanceKlassHandle parseClassFile(Symbol* name,
ClassLoaderData* loader_data,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray<Handle>* cp_patches,
TempNewSymbol& parsed_name,
bool verify,
TRAPS);
static void check_super_class_access(instanceKlassHandle this_klass, TRAPS);
static void check_super_interface_access(instanceKlassHandle this_klass, TRAPS);
static void check_final_method_override(instanceKlassHandle this_klass, TRAPS);
static void check_illegal_static_method(instanceKlassHandle this_klass, TRAPS);
u2 this_class_index() const { return _this_class_index; }
#if INCLUDE_JFR
ClassFileStream* clone_stream() const;
void set_klass_to_deallocate(InstanceKlass* klass);
#endif // INCLUDE_JFR
};
#endif // SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP
C:\hotspot-69087d08d473\src\share\vm/classfile/classFileStream.cpp
#include "precompiled.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/vmSymbols.hpp"
void ClassFileStream::truncated_file_error(TRAPS) {
THROW_MSG(vmSymbols::java_lang_ClassFormatError(), "Truncated class file");
}
ClassFileStream::ClassFileStream(u1* buffer, int length, const char* source, bool need_verify) {
_buffer_start = buffer;
_buffer_end = buffer + length;
_current = buffer;
_source = source;
_need_verify = need_verify;
}
u1 ClassFileStream::get_u1(TRAPS) {
if (_need_verify) {
guarantee_more(1, CHECK_0);
} else {
assert(1 <= _buffer_end - _current, "buffer overflow");
}
return *_current++;
}
u2 ClassFileStream::get_u2(TRAPS) {
if (_need_verify) {
guarantee_more(2, CHECK_0);
} else {
assert(2 <= _buffer_end - _current, "buffer overflow");
}
u1* tmp = _current;
_current += 2;
return Bytes::get_Java_u2(tmp);
}
u4 ClassFileStream::get_u4(TRAPS) {
if (_need_verify) {
guarantee_more(4, CHECK_0);
} else {
assert(4 <= _buffer_end - _current, "buffer overflow");
}
u1* tmp = _current;
_current += 4;
return Bytes::get_Java_u4(tmp);
}
u8 ClassFileStream::get_u8(TRAPS) {
if (_need_verify) {
guarantee_more(8, CHECK_0);
} else {
assert(8 <= _buffer_end - _current, "buffer overflow");
}
u1* tmp = _current;
_current += 8;
return Bytes::get_Java_u8(tmp);
}
void ClassFileStream::skip_u1(int length, TRAPS) {
if (_need_verify) {
guarantee_more(length, CHECK);
}
_current += length;
}
void ClassFileStream::skip_u2(int length, TRAPS) {
if (_need_verify) {
guarantee_more(length * 2, CHECK);
}
_current += length * 2;
}
void ClassFileStream::skip_u4(int length, TRAPS) {
if (_need_verify) {
guarantee_more(length * 4, CHECK);
}
_current += length * 4;
}
#if INCLUDE_JFR
u1* ClassFileStream::clone_buffer() const {
u1* const new_buffer_start = NEW_RESOURCE_ARRAY(u1, length());
memcpy(new_buffer_start, _buffer_start, length());
return new_buffer_start;
}
const char* const ClassFileStream::clone_source() const {
const char* const src = source();
char* source_copy = NULL;
if (src != NULL) {
size_t source_len = strlen(src);
source_copy = NEW_RESOURCE_ARRAY(char, source_len + 1);
strncpy(source_copy, src, source_len + 1);
}
return source_copy;
}
ClassFileStream* ClassFileStream::clone() const {
u1* const new_buffer_start = clone_buffer();
return new ClassFileStream(new_buffer_start,
length(),
clone_source(),
need_verify());
}
#endif // INCLUDE_JFR
C:\hotspot-69087d08d473\src\share\vm/classfile/classFileStream.hpp
#ifndef SHARE_VM_CLASSFILE_CLASSFILESTREAM_HPP
#define SHARE_VM_CLASSFILE_CLASSFILESTREAM_HPP
#include "utilities/top.hpp"
#ifdef TARGET_ARCH_x86
# include "bytes_x86.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "bytes_aarch64.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "bytes_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "bytes_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "bytes_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "bytes_ppc.hpp"
#endif
class ClassFileStream: public ResourceObj {
private:
u1* _buffer_start; // Buffer bottom
u1* _buffer_end; // Buffer top (one past last element)
u1* _current; // Current buffer position
const char* _source; // Source of stream (directory name, ZIP/JAR archive name)
bool _need_verify; // True if verification is on for the class file
void truncated_file_error(TRAPS);
#if INCLUDE_JFR
u1* clone_buffer() const;
const char* const clone_source() const;
#endif
public:
ClassFileStream(u1* buffer, int length, const char* source, bool need_verify = false);
u1* buffer() const { return _buffer_start; }
int length() const { return _buffer_end - _buffer_start; }
u1* current() const { return _current; }
void set_current(u1* pos) { _current = pos; }
juint current_offset() const {
return (juint)(_current - _buffer_start);
}
const char* source() const { return _source; }
void set_verify(bool flag) { _need_verify = flag; }
void check_truncated_file(bool b, TRAPS) {
if (b) {
truncated_file_error(THREAD);
}
}
void guarantee_more(int size, TRAPS) {
size_t remaining = (size_t)(_buffer_end - _current);
unsigned int usize = (unsigned int)size;
check_truncated_file(usize > remaining, CHECK);
}
u1 get_u1(TRAPS);
u1 get_u1_fast() {
return *_current++;
}
u2 get_u2(TRAPS);
u2 get_u2_fast() {
u2 res = Bytes::get_Java_u2(_current);
_current += 2;
return res;
}
u4 get_u4(TRAPS);
u4 get_u4_fast() {
u4 res = Bytes::get_Java_u4(_current);
_current += 4;
return res;
}
u8 get_u8(TRAPS);
u8 get_u8_fast() {
u8 res = Bytes::get_Java_u8(_current);
_current += 8;
return res;
}
u1* get_u1_buffer() {
return _current;
}
u2* get_u2_buffer() {
return (u2*) _current;
}
void skip_u1(int length, TRAPS);
void skip_u1_fast(int length) {
_current += length;
}
void skip_u2(int length, TRAPS);
void skip_u2_fast(int length) {
_current += 2 * length;
}
void skip_u4(int length, TRAPS);
void skip_u4_fast(int length) {
_current += 4 * length;
}
bool at_eos() const { return _current == _buffer_end; }
#if INCLUDE_JFR
ClassFileStream* clone() const;
bool need_verify() const { return _need_verify; }
#endif
};
#endif // SHARE_VM_CLASSFILE_CLASSFILESTREAM_HPP
C:\hotspot-69087d08d473\src\share\vm/classfile/classLoader.cpp
#include "precompiled.hpp"
#include "classfile/classFileParser.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderExt.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.hpp"
#if INCLUDE_CDS
#include "classfile/sharedPathsMiscInfo.hpp"
#include "classfile/sharedClassUtil.hpp"
#endif
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "compiler/compileBroker.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/oopMapCache.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/filemap.hpp"
#include "memory/generation.hpp"
#include "memory/oopFactory.hpp"
#include "memory/universe.inline.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/instanceRefKlass.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "prims/jvm_misc.hpp"
#include "runtime/arguments.hpp"
#include "runtime/compilationPolicy.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/handles.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/threadCritical.hpp"
#include "runtime/timer.hpp"
#include "services/management.hpp"
#include "services/threadService.hpp"
#include "utilities/events.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/hashtable.inline.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "os_linux.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "os_solaris.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "os_windows.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_aix
# include "os_aix.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "os_bsd.inline.hpp"
#endif
typedef void * * (JNICALL *ZipOpen_t)(const char *name, char **pmsg);
typedef void (JNICALL *ZipClose_t)(jzfile *zip);
typedef jzentry* (JNICALL *FindEntry_t)(jzfile *zip, const char *name, jint *sizeP, jint *nameLen);
typedef jboolean (JNICALL *ReadEntry_t)(jzfile *zip, jzentry *entry, unsigned char *buf, char *namebuf);
typedef jboolean (JNICALL *ReadMappedEntry_t)(jzfile *zip, jzentry *entry, unsigned char **buf, char *namebuf);
typedef jzentry* (JNICALL *GetNextEntry_t)(jzfile *zip, jint n);
typedef jint (JNICALL *Crc32_t)(jint crc, const jbyte *buf, jint len);
static ZipOpen_t ZipOpen = NULL;
static ZipClose_t ZipClose = NULL;
static FindEntry_t FindEntry = NULL;
static ReadEntry_t ReadEntry = NULL;
static ReadMappedEntry_t ReadMappedEntry = NULL;
static GetNextEntry_t GetNextEntry = NULL;
static canonicalize_fn_t CanonicalizeEntry = NULL;
static Crc32_t Crc32 = NULL;
PerfCounter* ClassLoader::_perf_accumulated_time = NULL;
PerfCounter* ClassLoader::_perf_classes_inited = NULL;
PerfCounter* ClassLoader::_perf_class_init_time = NULL;
PerfCounter* ClassLoader::_perf_class_init_selftime = NULL;
PerfCounter* ClassLoader::_perf_classes_verified = NULL;
PerfCounter* ClassLoader::_perf_class_verify_time = NULL;
PerfCounter* ClassLoader::_perf_class_verify_selftime = NULL;
PerfCounter* ClassLoader::_perf_classes_linked = NULL;
PerfCounter* ClassLoader::_perf_class_link_time = NULL;
PerfCounter* ClassLoader::_perf_class_link_selftime = NULL;
PerfCounter* ClassLoader::_perf_class_parse_time = NULL;
PerfCounter* ClassLoader::_perf_class_parse_selftime = NULL;
PerfCounter* ClassLoader::_perf_sys_class_lookup_time = NULL;
PerfCounter* ClassLoader::_perf_shared_classload_time = NULL;
PerfCounter* ClassLoader::_perf_sys_classload_time = NULL;
PerfCounter* ClassLoader::_perf_app_classload_time = NULL;
PerfCounter* ClassLoader::_perf_app_classload_selftime = NULL;
PerfCounter* ClassLoader::_perf_app_classload_count = NULL;
PerfCounter* ClassLoader::_perf_define_appclasses = NULL;
PerfCounter* ClassLoader::_perf_define_appclass_time = NULL;
PerfCounter* ClassLoader::_perf_define_appclass_selftime = NULL;
PerfCounter* ClassLoader::_perf_app_classfile_bytes_read = NULL;
PerfCounter* ClassLoader::_perf_sys_classfile_bytes_read = NULL;
PerfCounter* ClassLoader::_sync_systemLoaderLockContentionRate = NULL;
PerfCounter* ClassLoader::_sync_nonSystemLoaderLockContentionRate = NULL;
PerfCounter* ClassLoader::_sync_JVMFindLoadedClassLockFreeCounter = NULL;
PerfCounter* ClassLoader::_sync_JVMDefineClassLockFreeCounter = NULL;
PerfCounter* ClassLoader::_sync_JNIDefineClassLockFreeCounter = NULL;
PerfCounter* ClassLoader::_unsafe_defineClassCallCounter = NULL;
PerfCounter* ClassLoader::_isUnsyncloadClass = NULL;
PerfCounter* ClassLoader::_load_instance_class_failCounter = NULL;
ClassPathEntry* ClassLoader::_first_entry = NULL;
ClassPathEntry* ClassLoader::_last_entry = NULL;
int ClassLoader::_num_entries = 0;
PackageHashtable* ClassLoader::_package_hash_table = NULL;
#if INCLUDE_CDS
SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL;
#endif
bool string_starts_with(const char* str, const char* str_to_find) {
size_t str_len = strlen(str);
size_t str_to_find_len = strlen(str_to_find);
if (str_to_find_len > str_len) {
return false;
}
return (strncmp(str, str_to_find, str_to_find_len) == 0);
}
bool string_ends_with(const char* str, const char* str_to_find) {
size_t str_len = strlen(str);
size_t str_to_find_len = strlen(str_to_find);
if (str_to_find_len > str_len) {
return false;
}
return (strncmp(str + (str_len - str_to_find_len), str_to_find, str_to_find_len) == 0);
}
const char* ClassLoader::package_from_name(const char* const class_name, bool* bad_class_name) {
if (class_name == NULL) {
if (bad_class_name != NULL) {
}
return NULL;
}
if (bad_class_name != NULL) {
}
const char* const last_slash = strrchr(class_name, '/');
if (last_slash == NULL) {
return NULL;
}
char* class_name_ptr = (char*) class_name;
if (*class_name_ptr == '[') {
do {
class_name_ptr++;
} while (*class_name_ptr == '[');
if (*class_name_ptr == 'L') {
if (bad_class_name != NULL) {
}
return NULL;
}
}
int length = last_slash - class_name_ptr;
if (length <= 0) {
if (bad_class_name != NULL) {
}
return NULL;
}
char* pkg_name = NEW_RESOURCE_ARRAY(char, length + 1);
strncpy(pkg_name, class_name_ptr, length);
return (const char *)pkg_name;
}
MetaIndex::MetaIndex(char** meta_package_names, int num_meta_package_names) {
if (num_meta_package_names == 0) {
_meta_package_names = NULL;
_num_meta_package_names = 0;
} else {
_meta_package_names = NEW_C_HEAP_ARRAY(char*, num_meta_package_names, mtClass);
_num_meta_package_names = num_meta_package_names;
memcpy(_meta_package_names, meta_package_names, num_meta_package_names * sizeof(char*));
}
}
MetaIndex::~MetaIndex() {
FREE_C_HEAP_ARRAY(char*, _meta_package_names, mtClass);
}
bool MetaIndex::may_contain(const char* class_name) {
if ( _num_meta_package_names == 0) {
return false;
}
size_t class_name_len = strlen(class_name);
for (int i = 0; i < _num_meta_package_names; i++) {
char* pkg = _meta_package_names[i];
size_t pkg_len = strlen(pkg);
size_t min_len = MIN2(class_name_len, pkg_len);
if (!strncmp(class_name, pkg, min_len)) {
return true;
}
}
return false;
}
ClassPathEntry::ClassPathEntry() {
set_next(NULL);
}
bool ClassPathEntry::is_lazy() {
return false;
}
ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() {
char* copy = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass);
strcpy(copy, dir);
_dir = copy;
}
ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
char path[JVM_MAXPATHLEN];
if (jio_snprintf(path, sizeof(path), "%s%s%s", _dir, os::file_separator(), name) == -1) {
return NULL;
}
struct stat st;
if (os::stat(path, &st) == 0) {
#if INCLUDE_CDS
if (DumpSharedSpaces) {
ShouldNotReachHere();
}
#endif
int file_handle = os::open(path, 0, 0);
if (file_handle != -1) {
u1* buffer = NEW_RESOURCE_ARRAY(u1, st.st_size);
size_t num_read = os::read(file_handle, (char*) buffer, st.st_size);
os::close(file_handle);
if (num_read == (size_t)st.st_size) {
if (UsePerfData) {
ClassLoader::perf_sys_classfile_bytes_read()->inc(num_read);
}
return new ClassFileStream(buffer, st.st_size, _dir); // Resource allocated
}
}
}
return NULL;
}
ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name) : ClassPathEntry() {
_zip = zip;
char *copy = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass);
strcpy(copy, zip_name);
_zip_name = copy;
}
ClassPathZipEntry::~ClassPathZipEntry() {
if (ZipClose != NULL) {
(*ZipClose)(_zip);
}
FREE_C_HEAP_ARRAY(char, _zip_name, mtClass);
}
u1* ClassPathZipEntry::open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS) {
JavaThread* thread = JavaThread::current();
ThreadToNativeFromVM ttn(thread);
jint name_len;
jzentry* entry = (*FindEntry)(_zip, name, filesize, &name_len);
if (entry == NULL) return NULL;
u1* buffer;
char name_buf[128];
char* filename;
if (name_len < 128) {
filename = name_buf;
} else {
filename = NEW_RESOURCE_ARRAY(char, name_len + 1);
}
if (ReadMappedEntry == NULL ||
!(*ReadMappedEntry)(_zip, entry, &buffer, filename)) {
int size = (*filesize) + ((nul_terminate) ? 1 : 0);
buffer = NEW_RESOURCE_ARRAY(u1, size);
if (!(*ReadEntry)(_zip, entry, buffer, filename)) return NULL;
}
if (nul_terminate) {
buffer[*filesize] = 0;
}
return buffer;
}
ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) {
jint filesize;
u1* buffer = open_entry(name, &filesize, false, CHECK_NULL);
if (buffer == NULL) {
return NULL;
}
if (UsePerfData) {
ClassLoader::perf_sys_classfile_bytes_read()->inc(filesize);
}
return new ClassFileStream(buffer, filesize, _zip_name); // Resource allocated
}
void ClassPathZipEntry::contents_do(void f(const char* name, void* context), void* context) {
JavaThread* thread = JavaThread::current();
HandleMark handle_mark(thread);
ThreadToNativeFromVM ttn(thread);
for (int n = 0; ; n++) {
jzentry * ze = ((*GetNextEntry)(_zip, n));
if (ze == NULL) break;
(*f)(ze->name, context);
}
}
LazyClassPathEntry::LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception) : ClassPathEntry() {
_path = strdup(path);
_st = *st;
_meta_index = NULL;
_resolved_entry = NULL;
_has_error = false;
_throw_exception = throw_exception;
}
bool LazyClassPathEntry::is_jar_file() {
return ((_st.st_mode & S_IFREG) == S_IFREG);
}
ClassPathEntry* LazyClassPathEntry::resolve_entry(TRAPS) {
if (_resolved_entry != NULL) {
return (ClassPathEntry*) _resolved_entry;
}
ClassPathEntry* new_entry = NULL;
new_entry = ClassLoader::create_class_path_entry(_path, &_st, false, _throw_exception, CHECK_NULL);
if (!_throw_exception && new_entry == NULL) {
assert(!HAS_PENDING_EXCEPTION, "must be");
return NULL;
}
{
ThreadCritical tc;
if (_resolved_entry == NULL) {
_resolved_entry = new_entry;
return new_entry;
}
}
assert(_resolved_entry != NULL, "bug in MT-safe resolution logic");
delete new_entry;
return (ClassPathEntry*) _resolved_entry;
}
ClassFileStream* LazyClassPathEntry::open_stream(const char* name, TRAPS) {
if (_meta_index != NULL &&
!_meta_index->may_contain(name)) {
return NULL;
}
if (_has_error) {
return NULL;
}
ClassPathEntry* cpe = resolve_entry(THREAD);
if (cpe == NULL) {
_has_error = true;
return NULL;
} else {
return cpe->open_stream(name, THREAD);
}
}
bool LazyClassPathEntry::is_lazy() {
return true;
}
u1* LazyClassPathEntry::open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS) {
if (_has_error) {
return NULL;
}
ClassPathEntry* cpe = resolve_entry(THREAD);
if (cpe == NULL) {
_has_error = true;
return NULL;
} else if (cpe->is_jar_file()) {
return ((ClassPathZipEntry*)cpe)->open_entry(name, filesize, nul_terminate,THREAD);
} else {
ShouldNotReachHere();
return NULL;
}
}
static void print_meta_index(LazyClassPathEntry* entry,
GrowableArray<char*>& meta_packages) {
tty->print("[Meta index for %s=", entry->name());
for (int i = 0; i < meta_packages.length(); i++) {
if (i > 0) tty->print(" ");
tty->print("%s", meta_packages.at(i));
}
tty->print_cr("]");
}
#if INCLUDE_CDS
void ClassLoader::exit_with_path_failure(const char* error, const char* message) {
assert(DumpSharedSpaces, "only called at dump time");
tty->print_cr("Hint: enable -XX:+TraceClassPaths to diagnose the failure");
vm_exit_during_initialization(error, message);
}
#endif
void ClassLoader::trace_class_path(outputStream* out, const char* msg, const char* name) {
if (!TraceClassPaths) {
return;
}
if (msg) {
out->print("%s", msg);
}
if (name) {
if (strlen(name) < 256) {
out->print("%s", name);
} else {
while (name[0] != '\0') {
out->print("%c", name[0]);
name++;
}
}
}
if (msg && msg[0] == '[') {
out->print_cr("]");
} else {
out->cr();
}
}
void ClassLoader::setup_bootstrap_meta_index() {
const char* meta_index_path = Arguments::get_meta_index_path();
const char* meta_index_dir = Arguments::get_meta_index_dir();
setup_meta_index(meta_index_path, meta_index_dir, 0);
}
void ClassLoader::setup_meta_index(const char* meta_index_path, const char* meta_index_dir, int start_index) {
const char* known_version = "% VERSION 2";
FILE* file = fopen(meta_index_path, "r");
int line_no = 0;
#if INCLUDE_CDS
if (DumpSharedSpaces) {
if (file != NULL) {
_shared_paths_misc_info->add_required_file(meta_index_path);
} else {
_shared_paths_misc_info->add_nonexist_path(meta_index_path);
}
}
#endif
if (file != NULL) {
ResourceMark rm;
LazyClassPathEntry* cur_entry = NULL;
GrowableArray<char*> boot_class_path_packages(10);
char package_name[256];
bool skipCurrentJar = false;
while (fgets(package_name, sizeof(package_name), file) != NULL) {
++line_no;
package_name[strlen(package_name) - 1] = '\0';
switch(package_name[0]) {
case '%':
{
if ((line_no == 1) && (strcmp(package_name, known_version) != 0)) {
if (TraceClassLoading && Verbose) {
tty->print("[Unsupported meta index version]");
}
fclose(file);
return;
}
}
case '#':
case '!':
case '@':
{
if ((cur_entry != NULL) &&
(boot_class_path_packages.length() > 0)) {
if ((TraceClassLoading || TraceClassPaths) && Verbose) {
print_meta_index(cur_entry, boot_class_path_packages);
}
MetaIndex* index = new MetaIndex(boot_class_path_packages.adr_at(0),
boot_class_path_packages.length());
cur_entry->set_meta_index(index);
}
cur_entry = NULL;
boot_class_path_packages.clear();
int count = 0;
for (ClassPathEntry* entry = _first_entry; entry != NULL; entry = entry->next(), count++) {
if (count >= start_index &&
entry->is_lazy() &&
string_starts_with(entry->name(), meta_index_dir) &&
string_ends_with(entry->name(), &package_name[2])) {
cur_entry = (LazyClassPathEntry*) entry;
break;
}
}
if (package_name[0] == '@') {
if (cur_entry != NULL) {
cur_entry->set_meta_index(new MetaIndex(NULL, 0));
}
cur_entry = NULL;
skipCurrentJar = true;
} else {
skipCurrentJar = false;
}
break;
}
default:
{
if (!skipCurrentJar && cur_entry != NULL) {
char* new_name = strdup(package_name);
boot_class_path_packages.append(new_name);
}
}
}
}
if ((cur_entry != NULL) &&
(boot_class_path_packages.length() > 0)) {
if ((TraceClassLoading || TraceClassPaths) && Verbose) {
print_meta_index(cur_entry, boot_class_path_packages);
}
MetaIndex* index = new MetaIndex(boot_class_path_packages.adr_at(0),
boot_class_path_packages.length());
cur_entry->set_meta_index(index);
}
fclose(file);
}
}
#if INCLUDE_CDS
void ClassLoader::check_shared_classpath(const char *path) {
if (strcmp(path, "") == 0) {
exit_with_path_failure("Cannot have empty path in archived classpaths", NULL);
}
struct stat st;
if (os::stat(path, &st) == 0) {
if ((st.st_mode & S_IFREG) != S_IFREG) { // is directory
if (!os::dir_is_empty(path)) {
tty->print_cr("Error: non-empty directory '%s'", path);
exit_with_path_failure("CDS allows only empty directories in archived classpaths", NULL);
}
}
}
}
#endif
void ClassLoader::setup_bootstrap_search_path() {
assert(_first_entry == NULL, "should not setup bootstrap class search path twice");
const char* sys_class_path = Arguments::get_sysclasspath();
if (PrintSharedArchiveAndExit) {
} else {
trace_class_path(tty, "[Bootstrap loader class path=", sys_class_path);
}
#if INCLUDE_CDS
if (DumpSharedSpaces) {
_shared_paths_misc_info->add_boot_classpath(sys_class_path);
}
#endif
setup_search_path(sys_class_path);
}
#if INCLUDE_CDS
int ClassLoader::get_shared_paths_misc_info_size() {
return _shared_paths_misc_info->get_used_bytes();
}
void* ClassLoader::get_shared_paths_misc_info() {
return _shared_paths_misc_info->buffer();
}
bool ClassLoader::check_shared_paths_misc_info(void *buf, int size) {
SharedPathsMiscInfo* checker = SharedClassUtil::allocate_shared_paths_misc_info((char*)buf, size);
bool result = checker->check();
delete checker;
return result;
}
#endif
void ClassLoader::setup_search_path(const char *class_path, bool canonicalize) {
int offset = 0;
int len = (int)strlen(class_path);
int end = 0;
for (int start = 0; start < len; start = end) {
while (class_path[end] && class_path[end] != os::path_separator()[0]) {
end++;
}
EXCEPTION_MARK;
ResourceMark rm(THREAD);
char* path = NEW_RESOURCE_ARRAY(char, end - start + 1);
strncpy(path, &class_path[start], end - start);
path[end - start] = '\0';
if (canonicalize) {
char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN + 1);
if (get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) {
path = canonical_path;
}
}
update_class_path_entry_list(path, /*check_for_duplicates=*/canonicalize);
#if INCLUDE_CDS
if (DumpSharedSpaces) {
check_shared_classpath(path);
}
#endif
while (class_path[end] == os::path_separator()[0]) {
end++;
}
}
}
ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const struct stat* st,
bool lazy, bool throw_exception, TRAPS) {
JavaThread* thread = JavaThread::current();
if (lazy) {
return new LazyClassPathEntry(path, st, throw_exception);
}
ClassPathEntry* new_entry = NULL;
if ((st->st_mode & S_IFREG) == S_IFREG) {
char canonical_path[JVM_MAXPATHLEN];
if (!get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) {
if (throw_exception) {
THROW_MSG_(vmSymbols::java_io_IOException(), "Bad pathname", NULL);
} else {
return NULL;
}
}
char* error_msg = NULL;
jzfile* zip;
{
ThreadToNativeFromVM ttn(thread);
HandleMark hm(thread);
zip = (*ZipOpen)(canonical_path, &error_msg);
}
if (zip != NULL && error_msg == NULL) {
new_entry = new ClassPathZipEntry(zip, path);
if (TraceClassLoading || TraceClassPaths) {
tty->print_cr("[Opened %s]", path);
}
} else {
ResourceMark rm(thread);
char *msg;
if (error_msg == NULL) {
msg = NEW_RESOURCE_ARRAY(char, strlen(path) + 128); ;
jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path);
} else {
int len = (int)(strlen(path) + strlen(error_msg) + 128);
msg = NEW_RESOURCE_ARRAY(char, len); ;
jio_snprintf(msg, len - 1, "error in opening JAR file <%s> %s", error_msg, path);
}
if (throw_exception) {
THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL);
} else {
return NULL;
}
}
} else {
new_entry = new ClassPathDirEntry(path);
if (TraceClassLoading || TraceClassPaths) {
tty->print_cr("[Path %s]", path);
}
}
return new_entry;
}
ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path) {
struct stat st;
if (os::stat(path, &st) == 0) {
if ((st.st_mode & S_IFREG) == S_IFREG) {
char canonical_path[JVM_MAXPATHLEN];
if (get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) {
char* error_msg = NULL;
jzfile* zip;
{
JavaThread* thread = JavaThread::current();
ThreadToNativeFromVM ttn(thread);
HandleMark hm(thread);
zip = (*ZipOpen)(canonical_path, &error_msg);
}
if (zip != NULL && error_msg == NULL) {
return new ClassPathZipEntry(zip, canonical_path);
}
}
}
}
return NULL;
}
bool ClassLoader::contains_entry(ClassPathEntry *entry) {
ClassPathEntry* e = _first_entry;
while (e != NULL) {
if (strcmp(entry->name(), e->name()) == 0) {
return true;
}
e = e->next();
}
return false;
}
void ClassLoader::add_to_list(ClassPathEntry *new_entry) {
if (new_entry != NULL) {
if (_last_entry == NULL) {
_first_entry = _last_entry = new_entry;
} else {
_last_entry->set_next(new_entry);
_last_entry = new_entry;
}
}
_num_entries ++;
}
bool ClassLoader::update_class_path_entry_list(const char *path,
bool check_for_duplicates,
bool throw_exception) {
struct stat st;
if (os::stat(path, &st) == 0) {
ClassPathEntry* new_entry = NULL;
Thread* THREAD = Thread::current();
new_entry = create_class_path_entry(path, &st, LazyBootClassLoader, throw_exception, CHECK_(false));
if (new_entry == NULL) {
return false;
}
if (!check_for_duplicates || !contains_entry(new_entry)) {
ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry);
}
return true;
} else {
#if INCLUDE_CDS
if (DumpSharedSpaces) {
_shared_paths_misc_info->add_nonexist_path(path);
}
#endif
return false;
}
}
void ClassLoader::print_bootclasspath() {
ClassPathEntry* e = _first_entry;
tty->print("[bootclasspath= ");
while (e != NULL) {
tty->print("%s ;", e->name());
e = e->next();
}
tty->print_cr("]");
}
void ClassLoader::load_zip_library() {
assert(ZipOpen == NULL, "should not load zip library twice");
os::native_java_library();
char path[JVM_MAXPATHLEN];
char ebuf[1024];
void* handle = NULL;
if (os::dll_build_name(path, sizeof(path), Arguments::get_dll_dir(), "zip")) {
handle = os::dll_load(path, ebuf, sizeof ebuf);
}
if (handle == NULL) {
vm_exit_during_initialization("Unable to load ZIP library", path);
}
ZipOpen = CAST_TO_FN_PTR(ZipOpen_t, os::dll_lookup(handle, "ZIP_Open"));
ZipClose = CAST_TO_FN_PTR(ZipClose_t, os::dll_lookup(handle, "ZIP_Close"));
FindEntry = CAST_TO_FN_PTR(FindEntry_t, os::dll_lookup(handle, "ZIP_FindEntry"));
ReadEntry = CAST_TO_FN_PTR(ReadEntry_t, os::dll_lookup(handle, "ZIP_ReadEntry"));
ReadMappedEntry = CAST_TO_FN_PTR(ReadMappedEntry_t, os::dll_lookup(handle, "ZIP_ReadMappedEntry"));
GetNextEntry = CAST_TO_FN_PTR(GetNextEntry_t, os::dll_lookup(handle, "ZIP_GetNextEntry"));
Crc32 = CAST_TO_FN_PTR(Crc32_t, os::dll_lookup(handle, "ZIP_CRC32"));
if (ZipOpen == NULL || FindEntry == NULL || ReadEntry == NULL ||
GetNextEntry == NULL || Crc32 == NULL) {
vm_exit_during_initialization("Corrupted ZIP library", path);
}
void *javalib_handle = os::native_java_library();
CanonicalizeEntry = CAST_TO_FN_PTR(canonicalize_fn_t, os::dll_lookup(javalib_handle, "Canonicalize"));
}
int ClassLoader::crc32(int crc, const char* buf, int len) {
assert(Crc32 != NULL, "ZIP_CRC32 is not found");
return (*Crc32)(crc, (const jbyte*)buf, len);
}
class PackageInfo: public BasicHashtableEntry<mtClass> {
public:
const char* _pkgname; // Package name
int _classpath_index; // Index of directory or JAR file loaded from
PackageInfo* next() {
return (PackageInfo*)BasicHashtableEntry<mtClass>::next();
}
const char* pkgname() { return _pkgname; }
void set_pkgname(char* pkgname) { _pkgname = pkgname; }
const char* filename() {
return ClassLoader::classpath_entry(_classpath_index)->name();
}
void set_index(int index) {
_classpath_index = index;
}
};
class PackageHashtable : public BasicHashtable<mtClass> {
private:
inline unsigned int compute_hash(const char *s, int n) {
unsigned int val = 0;
while (--n >= 0) {
val = *s++ + 31 * val;
}
return val;
}
PackageInfo* bucket(int index) {
return (PackageInfo*)BasicHashtable<mtClass>::bucket(index);
}
PackageInfo* get_entry(int index, unsigned int hash,
const char* pkgname, size_t n) {
for (PackageInfo* pp = bucket(index); pp != NULL; pp = pp->next()) {
if (pp->hash() == hash &&
strncmp(pkgname, pp->pkgname(), n) == 0 &&
pp->pkgname()[n] == '\0') {
return pp;
}
}
return NULL;
}
public:
PackageHashtable(int table_size)
: BasicHashtable<mtClass>(table_size, sizeof(PackageInfo)) {}
PackageHashtable(int table_size, HashtableBucket<mtClass>* t, int number_of_entries)
: BasicHashtable<mtClass>(table_size, sizeof(PackageInfo), t, number_of_entries) {}
PackageInfo* get_entry(const char* pkgname, int n) {
unsigned int hash = compute_hash(pkgname, n);
return get_entry(hash_to_index(hash), hash, pkgname, n);
}
PackageInfo* new_entry(char* pkgname, int n) {
unsigned int hash = compute_hash(pkgname, n);
PackageInfo* pp;
pp = (PackageInfo*)BasicHashtable<mtClass>::new_entry(hash);
pp->set_pkgname(pkgname);
return pp;
}
void add_entry(PackageInfo* pp) {
int index = hash_to_index(pp->hash());
BasicHashtable<mtClass>::add_entry(index, pp);
}
void copy_pkgnames(const char** packages) {
int n = 0;
for (int i = 0; i < table_size(); ++i) {
for (PackageInfo* pp = bucket(i); pp != NULL; pp = pp->next()) {
packages[n++] = pp->pkgname();
}
}
assert(n == number_of_entries(), "just checking");
}
CDS_ONLY(void copy_table(char** top, char* end, PackageHashtable* table);)
};
#if INCLUDE_CDS
void PackageHashtable::copy_table(char** top, char* end,
PackageHashtable* table) {
BasicHashtable<mtClass>::copy_table(top, end);
int i;
intptr_t* tableSize = (intptr_t*)(*top);
char* tableStart = *top;
for (i = 0; i < table_size(); ++i) {
for (PackageInfo* pp = table->bucket(i);
pp != NULL;
pp = pp->next()) {
int n1 = (int)(strlen(pp->pkgname()) + 1);
if (*top + n1 >= end) {
report_out_of_shared_space(SharedMiscData);
}
pp->set_pkgname((char*)memcpy(*top, pp->pkgname(), n1));
}
}
if (*top >= end) {
report_out_of_shared_space(SharedMiscData);
}
intptr_t len = *top - (char*)tableStart;
}
void ClassLoader::copy_package_info_buckets(char** top, char* end) {
_package_hash_table->copy_buckets(top, end);
}
void ClassLoader::copy_package_info_table(char** top, char* end) {
_package_hash_table->copy_table(top, end, _package_hash_table);
}
#endif
PackageInfo* ClassLoader::lookup_package(const char *pkgname) {
const char *cp = strrchr(pkgname, '/');
if (cp != NULL) {
int n = cp - pkgname + 1;
return _package_hash_table->get_entry(pkgname, n);
}
return NULL;
}
bool ClassLoader::add_package(const char *pkgname, int classpath_index, TRAPS) {
assert(pkgname != NULL, "just checking");
{
MutexLocker ml(PackageTable_lock, THREAD);
PackageInfo* pp = lookup_package(pkgname);
if (pp != NULL) {
pp->set_index(classpath_index);
return true;
}
const char *cp = strrchr(pkgname, '/');
if (cp != NULL) {
int n = cp - pkgname + 1;
char* new_pkgname = NEW_C_HEAP_ARRAY(char, n + 1, mtClass);
if (new_pkgname == NULL) {
return false;
}
memcpy(new_pkgname, pkgname, n);
new_pkgname[n] = '\0';
pp = _package_hash_table->new_entry(new_pkgname, n);
pp->set_index(classpath_index);
_package_hash_table->add_entry(pp);
}
return true;
}
}
oop ClassLoader::get_system_package(const char* name, TRAPS) {
PackageInfo* pp;
{
MutexLocker ml(PackageTable_lock, THREAD);
pp = lookup_package(name);
}
if (pp == NULL) {
return NULL;
} else {
Handle p = java_lang_String::create_from_str(pp->filename(), THREAD);
return p();
}
}
objArrayOop ClassLoader::get_system_packages(TRAPS) {
ResourceMark rm(THREAD);
int nof_entries;
const char** packages;
{
MutexLocker ml(PackageTable_lock, THREAD);
nof_entries = _package_hash_table->number_of_entries();
if ((packages = NEW_RESOURCE_ARRAY(const char*, nof_entries)) == NULL) {
return NULL;
}
_package_hash_table->copy_pkgnames(packages);
}
objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(),
nof_entries, CHECK_0);
objArrayHandle result(THREAD, r);
for (int i = 0; i < nof_entries; i++) {
Handle str = java_lang_String::create_from_str(packages[i], CHECK_0);
result->obj_at_put(i, str());
}
return result();
}
instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {
ResourceMark rm(THREAD);
const char* class_name = h_name->as_C_string();
EventMark m("loading class %s", class_name);
ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);
stringStream st;
st.print_raw(h_name->as_utf8());
st.print_raw(".class");
const char* file_name = st.as_string();
ClassLoaderExt::Context context(class_name, file_name, THREAD);
ClassFileStream* stream = NULL;
int classpath_index = 0;
ClassPathEntry* e = NULL;
instanceKlassHandle h;
{
PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(),
((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(),
PerfClassTraceTime::CLASS_LOAD);
e = _first_entry;
while (e != NULL) {
stream = e->open_stream(file_name, CHECK_NULL);
if (!context.check(stream, classpath_index)) {
return h; // NULL
}
if (stream != NULL) {
break;
}
e = e->next();
++classpath_index;
}
}
if (stream != NULL) {
ClassFileParser parser(stream);
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
Handle protection_domain;
TempNewSymbol parsed_name = NULL;
instanceKlassHandle result = parser.parseClassFile(h_name,
loader_data,
protection_domain,
parsed_name,
context.should_verify(classpath_index),
THREAD);
if (HAS_PENDING_EXCEPTION) {
ResourceMark rm;
if (DumpSharedSpaces) {
tty->print_cr("Preload Error: Failed to load %s", class_name);
}
return h;
}
#if INCLUDE_JFR
{
InstanceKlass* ik = result();
ON_KLASS_CREATION(ik, parser, THREAD);
result = instanceKlassHandle(ik);
}
#endif
h = context.record_result(classpath_index, e, result, THREAD);
} else {
if (DumpSharedSpaces) {
tty->print_cr("Preload Warning: Cannot find %s", class_name);
}
}
return h;
}
void ClassLoader::create_package_info_table(HashtableBucket<mtClass> *t, int length,
int number_of_entries) {
assert(_package_hash_table == NULL, "One package info table allowed.");
assert(length == package_hash_table_size * sizeof(HashtableBucket<mtClass>),
"bad shared package info size.");
_package_hash_table = new PackageHashtable(package_hash_table_size, t,
number_of_entries);
}
void ClassLoader::create_package_info_table() {
assert(_package_hash_table == NULL, "shouldn't have one yet");
_package_hash_table = new PackageHashtable(package_hash_table_size);
}
void ClassLoader::initialize() {
assert(_package_hash_table == NULL, "should have been initialized by now.");
EXCEPTION_MARK;
if (UsePerfData) {
NEWPERFTICKCOUNTER(_perf_accumulated_time, SUN_CLS, "time");
NEWPERFTICKCOUNTER(_perf_class_init_time, SUN_CLS, "classInitTime");
NEWPERFTICKCOUNTER(_perf_class_init_selftime, SUN_CLS, "classInitTime.self");
NEWPERFTICKCOUNTER(_perf_class_verify_time, SUN_CLS, "classVerifyTime");
NEWPERFTICKCOUNTER(_perf_class_verify_selftime, SUN_CLS, "classVerifyTime.self");
NEWPERFTICKCOUNTER(_perf_class_link_time, SUN_CLS, "classLinkedTime");
NEWPERFTICKCOUNTER(_perf_class_link_selftime, SUN_CLS, "classLinkedTime.self");
NEWPERFEVENTCOUNTER(_perf_classes_inited, SUN_CLS, "initializedClasses");
NEWPERFEVENTCOUNTER(_perf_classes_linked, SUN_CLS, "linkedClasses");
NEWPERFEVENTCOUNTER(_perf_classes_verified, SUN_CLS, "verifiedClasses");
NEWPERFTICKCOUNTER(_perf_class_parse_time, SUN_CLS, "parseClassTime");
NEWPERFTICKCOUNTER(_perf_class_parse_selftime, SUN_CLS, "parseClassTime.self");
NEWPERFTICKCOUNTER(_perf_sys_class_lookup_time, SUN_CLS, "lookupSysClassTime");
NEWPERFTICKCOUNTER(_perf_shared_classload_time, SUN_CLS, "sharedClassLoadTime");
NEWPERFTICKCOUNTER(_perf_sys_classload_time, SUN_CLS, "sysClassLoadTime");
NEWPERFTICKCOUNTER(_perf_app_classload_time, SUN_CLS, "appClassLoadTime");
NEWPERFTICKCOUNTER(_perf_app_classload_selftime, SUN_CLS, "appClassLoadTime.self");
NEWPERFEVENTCOUNTER(_perf_app_classload_count, SUN_CLS, "appClassLoadCount");
NEWPERFTICKCOUNTER(_perf_define_appclasses, SUN_CLS, "defineAppClasses");
NEWPERFTICKCOUNTER(_perf_define_appclass_time, SUN_CLS, "defineAppClassTime");
NEWPERFTICKCOUNTER(_perf_define_appclass_selftime, SUN_CLS, "defineAppClassTime.self");
NEWPERFBYTECOUNTER(_perf_app_classfile_bytes_read, SUN_CLS, "appClassBytes");
NEWPERFBYTECOUNTER(_perf_sys_classfile_bytes_read, SUN_CLS, "sysClassBytes");
NEWPERFEVENTCOUNTER(_sync_systemLoaderLockContentionRate, SUN_CLS,
"systemLoaderLockContentionRate");
NEWPERFEVENTCOUNTER(_sync_nonSystemLoaderLockContentionRate, SUN_CLS,
"nonSystemLoaderLockContentionRate");
NEWPERFEVENTCOUNTER(_sync_JVMFindLoadedClassLockFreeCounter, SUN_CLS,
"jvmFindLoadedClassNoLockCalls");
NEWPERFEVENTCOUNTER(_sync_JVMDefineClassLockFreeCounter, SUN_CLS,
"jvmDefineClassNoLockCalls");
NEWPERFEVENTCOUNTER(_sync_JNIDefineClassLockFreeCounter, SUN_CLS,
"jniDefineClassNoLockCalls");
NEWPERFEVENTCOUNTER(_unsafe_defineClassCallCounter, SUN_CLS,
"unsafeDefineClassCalls");
NEWPERFEVENTCOUNTER(_isUnsyncloadClass, SUN_CLS, "isUnsyncloadClassSet");
NEWPERFEVENTCOUNTER(_load_instance_class_failCounter, SUN_CLS,
"loadInstanceClassFailRate");
if (UnsyncloadClass) {
_isUnsyncloadClass->inc();
}
}
load_zip_library();
#if INCLUDE_CDS
if (DumpSharedSpaces) {
_shared_paths_misc_info = SharedClassUtil::allocate_shared_paths_misc_info();
}
#endif
setup_bootstrap_search_path();
if (LazyBootClassLoader) {
setup_bootstrap_meta_index();
}
}
#if INCLUDE_CDS
void ClassLoader::initialize_shared_path() {
if (DumpSharedSpaces) {
ClassLoaderExt::setup_search_paths();
_shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
}
}
#endif
jlong ClassLoader::classloader_time_ms() {
return UsePerfData ?
Management::ticks_to_ms(_perf_accumulated_time->get_value()) : -1;
}
jlong ClassLoader::class_init_count() {
return UsePerfData ? _perf_classes_inited->get_value() : -1;
}
jlong ClassLoader::class_init_time_ms() {
return UsePerfData ?
Management::ticks_to_ms(_perf_class_init_time->get_value()) : -1;
}
jlong ClassLoader::class_verify_time_ms() {
return UsePerfData ?
Management::ticks_to_ms(_perf_class_verify_time->get_value()) : -1;
}
jlong ClassLoader::class_link_count() {
return UsePerfData ? _perf_classes_linked->get_value() : -1;
}
jlong ClassLoader::class_link_time_ms() {
return UsePerfData ?
Management::ticks_to_ms(_perf_class_link_time->get_value()) : -1;
}
int ClassLoader::compute_Object_vtable() {
int JDK_1_2_Object_vtable_size = 5;
return JDK_1_2_Object_vtable_size * vtableEntry::size();
}
void classLoader_init() {
ClassLoader::initialize();
}
bool ClassLoader::get_canonical_path(const char* orig, char* out, int len) {
assert(orig != NULL && out != NULL && len > 0, "bad arguments");
if (CanonicalizeEntry != NULL) {
JavaThread* THREAD = JavaThread::current();
JNIEnv* env = THREAD->jni_environment();
ResourceMark rm(THREAD);
char* orig_copy = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(orig)+1);
strcpy(orig_copy, orig);
if ((CanonicalizeEntry)(env, os::native_path(orig_copy), out, len) < 0) {
return false;
}
} else {
strncpy(out, orig, len);
out[len - 1] = '\0';
}
return true;
}
#ifndef PRODUCT
void ClassLoader::verify() {
_package_hash_table->verify();
}
typedef struct real_jzentry13 { /* Zip file entry */
char *name; /* entry name */
jint time; /* modification time */
jint size; /* size of uncompressed data */
jint csize; /* size of compressed data (zero if uncompressed) */
jint crc; /* crc of uncompressed data */
char *comment; /* optional zip file comment */
jbyte *extra; /* optional extra data */
jint pos; /* position of LOC header (if negative) or data */
} real_jzentry13;
typedef struct real_jzfile13 { /* Zip file */
char *name; /* zip file name */
jint refs; /* number of active references */
jint fd; /* open file descriptor */
void *lock; /* read lock */
char *comment; /* zip file comment */
char *msg; /* zip error message */
void *entries; /* array of hash cells */
jint total; /* total number of entries */
unsigned short *table; /* Hash chain heads: indexes into entries */
jint tablelen; /* number of hash eads */
real_jzfile13 *next; /* next zip file in search list */
jzentry *cache; /* we cache the most recently freed jzentry */
char **metanames; /* array of meta names (may have null names) */
jint metacount; /* number of slots in metanames array */
char **comments;
} real_jzfile13;
typedef struct real_jzentry12 { /* Zip file entry */
char *name; /* entry name */
jint time; /* modification time */
jint size; /* size of uncompressed data */
jint csize; /* size of compressed data (zero if uncompressed) */
jint crc; /* crc of uncompressed data */
char *comment; /* optional zip file comment */
jbyte *extra; /* optional extra data */
jint pos; /* position of LOC header (if negative) or data */
struct real_jzentry12 *next; /* next entry in hash table */
} real_jzentry12;
typedef struct real_jzfile12 { /* Zip file */
char *name; /* zip file name */
jint refs; /* number of active references */
jint fd; /* open file descriptor */
void *lock; /* read lock */
char *comment; /* zip file comment */
char *msg; /* zip error message */
real_jzentry12 *entries; /* array of zip entries */
jint total; /* total number of entries */
real_jzentry12 **table; /* hash table of entries */
jint tablelen; /* number of buckets */
jzfile *next; /* next zip file in search list */
} real_jzfile12;
void ClassPathDirEntry::compile_the_world(Handle loader, TRAPS) {
tty->print_cr("CompileTheWorld : Skipped classes in %s", _dir);
tty->cr();
}
bool ClassPathDirEntry::is_rt_jar() {
return false;
}
void ClassPathZipEntry::compile_the_world(Handle loader, TRAPS) {
if (JDK_Version::is_jdk12x_version()) {
compile_the_world12(loader, THREAD);
} else {
compile_the_world13(loader, THREAD);
}
if (HAS_PENDING_EXCEPTION) {
if (PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())) {
CLEAR_PENDING_EXCEPTION;
tty->print_cr("\nCompileTheWorld : Ran out of memory\n");
tty->print_cr("Increase class metadata storage if a limit was set");
} else {
tty->print_cr("\nCompileTheWorld : Unexpected exception occurred\n");
}
}
}
void ClassPathZipEntry::compile_the_world13(Handle loader, TRAPS) {
real_jzfile13* zip = (real_jzfile13*) _zip;
tty->print_cr("CompileTheWorld : Compiling all classes in %s", zip->name);
tty->cr();
for (int n = 0; ; n++) {
real_jzentry13 * ze = (real_jzentry13 *)((*GetNextEntry)(_zip, n));
if (ze == NULL) break;
ClassLoader::compile_the_world_in(ze->name, loader, CHECK);
}
}
void ClassPathZipEntry::compile_the_world12(Handle loader, TRAPS) {
real_jzfile12* zip = (real_jzfile12*) _zip;
tty->print_cr("CompileTheWorld : Compiling all classes in %s", zip->name);
tty->cr();
for (int n = 0; ; n++) {
real_jzentry12 * ze = (real_jzentry12 *)((*GetNextEntry)(_zip, n));
if (ze == NULL) break;
ClassLoader::compile_the_world_in(ze->name, loader, CHECK);
}
}
bool ClassPathZipEntry::is_rt_jar() {
if (JDK_Version::is_jdk12x_version()) {
return is_rt_jar12();
} else {
return is_rt_jar13();
}
}
bool ClassPathZipEntry::is_rt_jar13() {
real_jzfile13* zip = (real_jzfile13*) _zip;
int len = (int)strlen(zip->name);
return (len >= 6) && (strcasecmp(zip->name + len - 6, "rt.jar") == 0);
}
bool ClassPathZipEntry::is_rt_jar12() {
real_jzfile12* zip = (real_jzfile12*) _zip;
int len = (int)strlen(zip->name);
return (len >= 6) && (strcasecmp(zip->name + len - 6, "rt.jar") == 0);
}
void LazyClassPathEntry::compile_the_world(Handle loader, TRAPS) {
ClassPathEntry* cpe = resolve_entry(THREAD);
if (cpe != NULL) {
cpe->compile_the_world(loader, CHECK);
}
}
bool LazyClassPathEntry::is_rt_jar() {
Thread* THREAD = Thread::current();
ClassPathEntry* cpe = resolve_entry(THREAD);
return (cpe != NULL) ? cpe->is_jar_file() : false;
}
void ClassLoader::compile_the_world() {
EXCEPTION_MARK;
HandleMark hm(THREAD);
ResourceMark rm(THREAD);
BackgroundCompilation = false;
Handle system_class_loader (THREAD, SystemDictionary::java_system_loader());
ClassPathEntry* e = _first_entry;
jlong start = os::javaTimeMillis();
while (e != NULL) {
if (e->is_rt_jar() && e != _first_entry) break;
e->compile_the_world(system_class_loader, CATCH);
e = e->next();
}
jlong end = os::javaTimeMillis();
tty->print_cr("CompileTheWorld : Done (%d classes, %d methods, " JLONG_FORMAT " ms)",
_compile_the_world_class_counter, _compile_the_world_method_counter, (end - start));
{
extern void print_statistics();
print_statistics();
}
vm_exit(0);
}
int ClassLoader::_compile_the_world_class_counter = 0;
int ClassLoader::_compile_the_world_method_counter = 0;
static int _codecache_sweep_counter = 0;
static void clear_pending_exception_if_not_oom(TRAPS) {
if (HAS_PENDING_EXCEPTION &&
!PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())) {
CLEAR_PENDING_EXCEPTION;
}
}
static bool can_be_compiled(methodHandle m, int comp_level) {
assert(CompileTheWorld, "must be");
vmIntrinsics::ID iid = m->intrinsic_id();
if (MethodHandles::is_signature_polymorphic(iid) && MethodHandles::has_member_arg(iid)) {
return false;
}
return CompilationPolicy::can_be_compiled(m, comp_level);
}
void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
size_t len = strlen(name);
if (len > 6 && strcmp(".class", name + len - 6) == 0) {
char buffer[2048];
if (len-6 >= sizeof(buffer)) return;
strncpy(buffer, name, sizeof(buffer));
buffer[len-6] = 0; // Truncate ".class" suffix.
if (strchr(buffer, '.') == NULL) {
_compile_the_world_class_counter++;
if (_compile_the_world_class_counter > CompileTheWorldStopAt) return;
TempNewSymbol sym = SymbolTable::new_symbol(buffer, CHECK);
Klass* ik = SystemDictionary::resolve_or_null(sym, loader, Handle(), THREAD);
instanceKlassHandle k (THREAD, ik);
if (k.not_null() && !HAS_PENDING_EXCEPTION) {
k->initialize(THREAD);
}
bool exception_occurred = HAS_PENDING_EXCEPTION;
clear_pending_exception_if_not_oom(CHECK);
if (CompileTheWorldPreloadClasses && k.not_null()) {
ConstantPool::preload_and_initialize_all_classes(k->constants(), THREAD);
if (HAS_PENDING_EXCEPTION) {
clear_pending_exception_if_not_oom(CHECK);
tty->print_cr("Preloading failed for (%d) %s", _compile_the_world_class_counter, buffer);
}
}
if (_compile_the_world_class_counter >= CompileTheWorldStartAt) {
if (k.is_null() || exception_occurred) {
tty->print_cr("CompileTheWorld (%d) : Skipping %s", _compile_the_world_class_counter, buffer);
} else {
tty->print_cr("CompileTheWorld (%d) : %s", _compile_the_world_class_counter, buffer);
int comp_level = CompilationPolicy::policy()->initial_compile_level();
for (int n = 0; n < k->methods()->length(); n++) {
methodHandle m (THREAD, k->methods()->at(n));
if (can_be_compiled(m, comp_level)) {
if (++_codecache_sweep_counter == CompileTheWorldSafepointInterval) {
VM_ForceSafepoint op;
VMThread::execute(&op);
_codecache_sweep_counter = 0;
}
CompileBroker::compile_method(m, InvocationEntryBci, comp_level,
methodHandle(), 0, "CTW", THREAD);
if (HAS_PENDING_EXCEPTION) {
clear_pending_exception_if_not_oom(CHECK);
tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name_and_sig_as_C_string());
} else {
_compile_the_world_method_counter++;
}
if (TieredCompilation && TieredStopAtLevel >= CompLevel_full_optimization) {
nmethod* nm = m->code();
if (nm != NULL && !m->is_method_handle_intrinsic()) {
nm->make_not_entrant();
}
CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_full_optimization,
methodHandle(), 0, "CTW", THREAD);
if (HAS_PENDING_EXCEPTION) {
clear_pending_exception_if_not_oom(CHECK);
tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name_and_sig_as_C_string());
} else {
_compile_the_world_method_counter++;
}
}
} else {
tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name_and_sig_as_C_string());
}
nmethod* nm = m->code();
if (nm != NULL && !m->is_method_handle_intrinsic()) {
nm->make_not_entrant();
}
}
}
}
}
}
}
#endif //PRODUCT
void PerfClassTraceTime::initialize() {
if (!UsePerfData) return;
if (_eventp != NULL) {
_eventp->inc();
}
_prev_active_event = -1;
for (int i=0; i < EVENT_TYPE_COUNT; i++) {
if (_timers[i].is_active()) {
assert(_prev_active_event == -1, "should have only one active timer");
_prev_active_event = i;
_timers[i].stop();
}
}
if (_recursion_counters == NULL || (_recursion_counters[_event_type])++ == 0) {
_t.start();
}
if (!_timers[_event_type].is_active()) {
_timers[_event_type].start();
}
}
PerfClassTraceTime::~PerfClassTraceTime() {
if (!UsePerfData) return;
_timers[_event_type].stop();
jlong selftime = _timers[_event_type].ticks();
if (_prev_active_event >= 0) {
_timers[_prev_active_event].start();
}
if (_recursion_counters != NULL && --(_recursion_counters[_event_type]) > 0) return;
_t.stop();
_timep->inc(_t.ticks());
if (_selftimep != NULL) {
_selftimep->inc(selftime);
}
ClassLoader::perf_accumulated_time()->inc(selftime);
_timers[_event_type].reset();
}
C:\hotspot-69087d08d473\src\share\vm/classfile/classLoader.hpp
#ifndef SHARE_VM_CLASSFILE_CLASSLOADER_HPP
#define SHARE_VM_CLASSFILE_CLASSLOADER_HPP
#include "classfile/classFileParser.hpp"
#include "runtime/perfData.hpp"
#include <sys/stat.h>
class MetaIndex: public CHeapObj<mtClass> {
private:
char** _meta_package_names;
int _num_meta_package_names;
public:
MetaIndex(char** meta_package_names, int num_meta_package_names);
virtual ~MetaIndex();
bool may_contain(const char* class_name);
};
class ClassPathEntry: public CHeapObj<mtClass> {
private:
ClassPathEntry* _next;
public:
ClassPathEntry* next() { return _next; }
void set_next(ClassPathEntry* next) {
OrderAccess::release_store_ptr(&_next, next);
}
virtual bool is_jar_file() = 0;
virtual const char* name() = 0;
virtual bool is_lazy();
ClassPathEntry();
virtual ~ClassPathEntry() {}
virtual ClassFileStream* open_stream(const char* name, TRAPS) = 0;
NOT_PRODUCT(virtual void compile_the_world(Handle loader, TRAPS) = 0;)
NOT_PRODUCT(virtual bool is_rt_jar() = 0;)
};
class ClassPathDirEntry: public ClassPathEntry {
private:
const char* _dir; // Name of directory
public:
bool is_jar_file() { return false; }
const char* name() { return _dir; }
ClassPathDirEntry(const char* dir);
virtual ~ClassPathDirEntry() {}
ClassFileStream* open_stream(const char* name, TRAPS);
NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);)
NOT_PRODUCT(bool is_rt_jar();)
};
typedef void* jzfile;
typedef struct {
char *name; /* entry name */
jlong time; /* modification time */
jlong size; /* size of uncompressed data */
jlong csize; /* size of compressed data (zero if uncompressed) */
jint crc; /* crc of uncompressed data */
char *comment; /* optional zip file comment */
jbyte *extra; /* optional extra data */
jlong pos; /* position of LOC header (if negative) or data */
} jzentry;
class ClassPathZipEntry: public ClassPathEntry {
private:
jzfile* _zip; // The zip archive
const char* _zip_name; // Name of zip archive
public:
bool is_jar_file() { return true; }
const char* name() { return _zip_name; }
ClassPathZipEntry(jzfile* zip, const char* zip_name);
virtual ~ClassPathZipEntry();
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
ClassFileStream* open_stream(const char* name, TRAPS);
void contents_do(void f(const char* name, void* context), void* context);
NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);)
NOT_PRODUCT(void compile_the_world12(Handle loader, TRAPS);) // JDK 1.2 version
NOT_PRODUCT(void compile_the_world13(Handle loader, TRAPS);) // JDK 1.3 version
NOT_PRODUCT(bool is_rt_jar();)
NOT_PRODUCT(bool is_rt_jar12();)
NOT_PRODUCT(bool is_rt_jar13();)
};
class LazyClassPathEntry: public ClassPathEntry {
private:
const char* _path; // dir or file
struct stat _st;
MetaIndex* _meta_index;
bool _has_error;
bool _throw_exception;
volatile ClassPathEntry* _resolved_entry;
public:
ClassPathEntry* resolve_entry(TRAPS);
bool is_jar_file();
const char* name() { return _path; }
LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception);
virtual ~LazyClassPathEntry() {}
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
ClassFileStream* open_stream(const char* name, TRAPS);
void set_meta_index(MetaIndex* meta_index) { _meta_index = meta_index; }
virtual bool is_lazy();
NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);)
NOT_PRODUCT(bool is_rt_jar();)
};
class PackageHashtable;
class PackageInfo;
class SharedPathsMiscInfo;
template <MEMFLAGS F> class HashtableBucket;
class ClassLoader: AllStatic {
public:
enum SomeConstants {
package_hash_table_size = 31 // Number of buckets
};
protected:
friend class LazyClassPathEntry;
static PerfCounter* _perf_accumulated_time;
static PerfCounter* _perf_classes_inited;
static PerfCounter* _perf_class_init_time;
static PerfCounter* _perf_class_init_selftime;
static PerfCounter* _perf_classes_verified;
static PerfCounter* _perf_class_verify_time;
static PerfCounter* _perf_class_verify_selftime;
static PerfCounter* _perf_classes_linked;
static PerfCounter* _perf_class_link_time;
static PerfCounter* _perf_class_link_selftime;
static PerfCounter* _perf_class_parse_time;
static PerfCounter* _perf_class_parse_selftime;
static PerfCounter* _perf_sys_class_lookup_time;
static PerfCounter* _perf_shared_classload_time;
static PerfCounter* _perf_sys_classload_time;
static PerfCounter* _perf_app_classload_time;
static PerfCounter* _perf_app_classload_selftime;
static PerfCounter* _perf_app_classload_count;
static PerfCounter* _perf_define_appclasses;
static PerfCounter* _perf_define_appclass_time;
static PerfCounter* _perf_define_appclass_selftime;
static PerfCounter* _perf_app_classfile_bytes_read;
static PerfCounter* _perf_sys_classfile_bytes_read;
static PerfCounter* _sync_systemLoaderLockContentionRate;
static PerfCounter* _sync_nonSystemLoaderLockContentionRate;
static PerfCounter* _sync_JVMFindLoadedClassLockFreeCounter;
static PerfCounter* _sync_JVMDefineClassLockFreeCounter;
static PerfCounter* _sync_JNIDefineClassLockFreeCounter;
static PerfCounter* _unsafe_defineClassCallCounter;
static PerfCounter* _isUnsyncloadClass;
static PerfCounter* _load_instance_class_failCounter;
static ClassPathEntry* _first_entry;
static ClassPathEntry* _last_entry;
static int _num_entries;
static PackageHashtable* _package_hash_table;
static const char* _shared_archive;
CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;)
static unsigned int hash(const char *s, int n);
static PackageInfo* lookup_package(const char *pkgname);
static bool add_package(const char *pkgname, int classpath_index, TRAPS);
static void setup_bootstrap_meta_index();
static void setup_meta_index(const char* meta_index_path, const char* meta_index_dir,
int start_index);
static void setup_bootstrap_search_path();
static void setup_search_path(const char *class_path, bool canonicalize=false);
static void load_zip_library();
static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st,
bool lazy, bool throw_exception, TRAPS);
static bool get_canonical_path(const char* orig, char* out, int len);
public:
static int crc32(int crc, const char* buf, int len);
static bool update_class_path_entry_list(const char *path,
bool check_for_duplicates,
bool throw_exception=true);
static void print_bootclasspath();
static PerfCounter* perf_accumulated_time() { return _perf_accumulated_time; }
static PerfCounter* perf_classes_inited() { return _perf_classes_inited; }
static PerfCounter* perf_class_init_time() { return _perf_class_init_time; }
static PerfCounter* perf_class_init_selftime() { return _perf_class_init_selftime; }
static PerfCounter* perf_classes_verified() { return _perf_classes_verified; }
static PerfCounter* perf_class_verify_time() { return _perf_class_verify_time; }
static PerfCounter* perf_class_verify_selftime() { return _perf_class_verify_selftime; }
static PerfCounter* perf_classes_linked() { return _perf_classes_linked; }
static PerfCounter* perf_class_link_time() { return _perf_class_link_time; }
static PerfCounter* perf_class_link_selftime() { return _perf_class_link_selftime; }
static PerfCounter* perf_class_parse_time() { return _perf_class_parse_time; }
static PerfCounter* perf_class_parse_selftime() { return _perf_class_parse_selftime; }
static PerfCounter* perf_sys_class_lookup_time() { return _perf_sys_class_lookup_time; }
static PerfCounter* perf_shared_classload_time() { return _perf_shared_classload_time; }
static PerfCounter* perf_sys_classload_time() { return _perf_sys_classload_time; }
static PerfCounter* perf_app_classload_time() { return _perf_app_classload_time; }
static PerfCounter* perf_app_classload_selftime() { return _perf_app_classload_selftime; }
static PerfCounter* perf_app_classload_count() { return _perf_app_classload_count; }
static PerfCounter* perf_define_appclasses() { return _perf_define_appclasses; }
static PerfCounter* perf_define_appclass_time() { return _perf_define_appclass_time; }
static PerfCounter* perf_define_appclass_selftime() { return _perf_define_appclass_selftime; }
static PerfCounter* perf_app_classfile_bytes_read() { return _perf_app_classfile_bytes_read; }
static PerfCounter* perf_sys_classfile_bytes_read() { return _perf_sys_classfile_bytes_read; }
static PerfCounter* sync_systemLoaderLockContentionRate() {
return _sync_systemLoaderLockContentionRate;
}
static PerfCounter* sync_nonSystemLoaderLockContentionRate() {
return _sync_nonSystemLoaderLockContentionRate;
}
static PerfCounter* sync_JVMFindLoadedClassLockFreeCounter() {
return _sync_JVMFindLoadedClassLockFreeCounter;
}
static PerfCounter* sync_JVMDefineClassLockFreeCounter() {
return _sync_JVMDefineClassLockFreeCounter;
}
static PerfCounter* sync_JNIDefineClassLockFreeCounter() {
return _sync_JNIDefineClassLockFreeCounter;
}
static PerfCounter* unsafe_defineClassCallCounter() {
return _unsafe_defineClassCallCounter;
}
static PerfCounter* load_instance_class_failCounter() {
return _load_instance_class_failCounter;
}
static instanceKlassHandle load_classfile(Symbol* h_name, TRAPS);
static oop get_system_package(const char* name, TRAPS);
static objArrayOop get_system_packages(TRAPS);
static void initialize();
CDS_ONLY(static void initialize_shared_path();)
static void create_package_info_table();
static void create_package_info_table(HashtableBucket<mtClass> *t, int length,
int number_of_entries);
static int compute_Object_vtable();
static ClassPathEntry* classpath_entry(int n) {
ClassPathEntry* e = ClassLoader::_first_entry;
while (--n >= 0) {
assert(e != NULL, "Not that many classpath entries.");
e = e->next();
}
return e;
}
static int num_classpath_entries() {
return _num_entries;
}
#if INCLUDE_CDS
static void copy_package_info_buckets(char** top, char* end);
static void copy_package_info_table(char** top, char* end);
static void check_shared_classpath(const char *path);
static void finalize_shared_paths_misc_info();
static int get_shared_paths_misc_info_size();
static void* get_shared_paths_misc_info();
static bool check_shared_paths_misc_info(void* info, int size);
static void exit_with_path_failure(const char* error, const char* message);
#endif
static void trace_class_path(outputStream* out, const char* msg, const char* name = NULL);
static jlong classloader_time_ms();
static jlong class_method_total_size();
static jlong class_init_count();
static jlong class_init_time_ms();
static jlong class_verify_time_ms();
static jlong class_link_count();
static jlong class_link_time_ms();
static bool contains_entry(ClassPathEntry* entry);
static void add_to_list(ClassPathEntry* new_entry);
static ClassPathZipEntry* create_class_path_zip_entry(const char *apath);
static const char* package_from_name(const char* const class_name, bool* bad_class_name = NULL);
static void verify() PRODUCT_RETURN;
#ifndef PRODUCT
protected:
static int _compile_the_world_class_counter;
static int _compile_the_world_method_counter;
public:
static void compile_the_world();
static void compile_the_world_in(char* name, Handle loader, TRAPS);
static int compile_the_world_counter() { return _compile_the_world_class_counter; }
#endif //PRODUCT
};
class PerfClassTraceTime {
public:
enum {
CLASS_LOAD = 0,
PARSE_CLASS = 1,
CLASS_LINK = 2,
CLASS_VERIFY = 3,
CLASS_CLINIT = 4,
DEFINE_CLASS = 5,
EVENT_TYPE_COUNT = 6
};
protected:
elapsedTimer _t;
PerfLongCounter* _timep;
PerfLongCounter* _selftimep;
PerfLongCounter* _eventp;
int* _recursion_counters;
elapsedTimer* _timers;
int _event_type;
int _prev_active_event;
public:
inline PerfClassTraceTime(PerfLongCounter* timep, /* counter incremented with inclusive time */
PerfLongCounter* selftimep, /* counter incremented with exclusive time */
PerfLongCounter* eventp, /* event counter */
int* recursion_counters, /* thread-local recursion counter array */
elapsedTimer* timers, /* thread-local timer array */
int type /* event type */ ) :
_timep(timep), _selftimep(selftimep), _eventp(eventp), _recursion_counters(recursion_counters), _timers(timers), _event_type(type) {
initialize();
}
inline PerfClassTraceTime(PerfLongCounter* timep, /* counter incremented with inclusive time */
elapsedTimer* timers, /* thread-local timer array */
int type /* event type */ ) :
_timep(timep), _selftimep(NULL), _eventp(NULL), _recursion_counters(NULL), _timers(timers), _event_type(type) {
initialize();
}
inline void suspend() { _t.stop(); _timers[_event_type].stop(); }
inline void resume() { _t.start(); _timers[_event_type].start(); }
~PerfClassTraceTime();
void initialize();
};
#endif // SHARE_VM_CLASSFILE_CLASSLOADER_HPP
C:\hotspot-69087d08d473\src\share\vm/classfile/classLoaderData.cpp
#include "precompiled.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "memory/gcLocker.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/mutex.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/synchronizer.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) :
_class_loader(h_class_loader()),
_is_anonymous(is_anonymous),
_keep_alive(is_anonymous || h_class_loader.is_null()),
_metaspace(NULL), _unloading(false), _klasses(NULL),
_claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
_next(NULL), _dependencies(dependencies),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {
JFR_ONLY(INIT_ID(this);)
}
void ClassLoaderData::init_dependencies(TRAPS) {
assert(!Universe::is_fully_initialized(), "should only be called when initializing");
assert(is_the_null_class_loader_data(), "should only call this for the null class loader");
_dependencies.init(CHECK);
}
void ClassLoaderData::Dependencies::init(TRAPS) {
_list_head = oopFactory::new_objectArray(2, CHECK);
}
ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() {
Chunk* c = _head;
while (c != NULL) {
Chunk* next = c->_next;
delete c;
c = next;
}
}
oop* ClassLoaderData::ChunkedHandleList::add(oop o) {
if (_head == NULL || _head->_size == Chunk::CAPACITY) {
Chunk* next = new Chunk(_head);
OrderAccess::release_store_ptr(&_head, next);
}
oop* handle = &_head->_data[_head->_size];
OrderAccess::release_store(&_head->_size, _head->_size + 1);
return handle;
}
inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chunk* c, const juint size) {
for (juint i = 0; i < size; i++) {
if (c->_data[i] != NULL) {
f->do_oop(&c->_data[i]);
}
}
}
void ClassLoaderData::ChunkedHandleList::oops_do(OopClosure* f) {
Chunk* head = (Chunk*) OrderAccess::load_ptr_acquire(&_head);
if (head != NULL) {
oops_do_chunk(f, head, OrderAccess::load_acquire(&head->_size));
for (Chunk* c = head->_next; c != NULL; c = c->_next) {
oops_do_chunk(f, c, c->_size);
}
}
}
bool ClassLoaderData::claim() {
if (_claimed == 1) {
return false;
}
return (int) Atomic::cmpxchg(1, &_claimed, 0) == 0;
}
void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
if (must_claim && !claim()) {
return;
}
f->do_oop(&_class_loader);
_dependencies.oops_do(f);
_handles.oops_do(f);
if (klass_closure != NULL) {
classes_do(klass_closure);
}
}
void ClassLoaderData::Dependencies::oops_do(OopClosure* f) {
f->do_oop((oop*)&_list_head);
}
void ClassLoaderData::classes_do(KlassClosure* klass_closure) {
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
klass_closure->do_klass(k);
assert(k != k->next_link(), "no loops!");
}
}
void ClassLoaderData::classes_do(void f(Klass * const)) {
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
f(k);
}
}
void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
if (k->oop_is_array() || (k->oop_is_instance() && InstanceKlass::cast(k)->is_loaded())) {
klass_closure->do_klass(k);
}
}
}
void ClassLoaderData::classes_do(void f(InstanceKlass*)) {
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
if (k->oop_is_instance()) {
f(InstanceKlass::cast(k));
}
assert(k != k->next_link(), "no loops!");
}
}
void ClassLoaderData::record_dependency(Klass* k, TRAPS) {
ClassLoaderData * const from_cld = this;
ClassLoaderData * const to_cld = k->class_loader_data();
if (to_cld->is_the_null_class_loader_data()) {
return;
}
oop to;
if (to_cld->is_anonymous()) {
to = k->java_mirror();
} else {
to = to_cld->class_loader();
if (!from_cld->is_anonymous()) {
oop from = from_cld->class_loader();
oop curr = from;
while (curr != NULL) {
if (curr == to) {
return; // this class loader is in the parent list, no need to add it.
}
curr = java_lang_ClassLoader::parent(curr);
}
}
}
Handle dependency(THREAD, to);
from_cld->_dependencies.add(dependency, CHECK);
}
void ClassLoaderData::Dependencies::add(Handle dependency, TRAPS) {
objArrayOop ok = _list_head;
objArrayOop last = NULL;
while (ok != NULL) {
last = ok;
if (ok->obj_at(0) == dependency()) {
return;
}
ok = (objArrayOop)ok->obj_at(1);
}
assert (last != NULL, "dependencies should be initialized");
objArrayHandle last_handle(THREAD, last);
objArrayOop deps = oopFactory::new_objectArray(2, CHECK);
deps->obj_at_put(0, dependency());
objArrayHandle new_dependency(THREAD, deps);
locked_add(last_handle, new_dependency, THREAD);
}
void ClassLoaderData::Dependencies::locked_add(objArrayHandle last_handle,
objArrayHandle new_dependency,
Thread* THREAD) {
ObjectLocker ol(Handle(THREAD, _list_head), THREAD);
oop loader_or_mirror = new_dependency->obj_at(0);
objArrayOop end = last_handle();
objArrayOop last = NULL;
while (end != NULL) {
last = end;
if (end->obj_at(0) == loader_or_mirror) {
return;
}
end = (objArrayOop)end->obj_at(1);
}
assert (last != NULL, "dependencies should be initialized");
if (last->obj_at(0) == NULL) {
last->obj_at_put(0, new_dependency->obj_at(0));
} else {
last->obj_at_put(1, new_dependency());
}
}
void ClassLoaderDataGraph::clear_claimed_marks() {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
cld->clear_claimed();
}
}
void ClassLoaderData::add_class(Klass* k) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
Klass* old_value = _klasses;
k->set_next_link(old_value);
_klasses = k;
if (TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
ResourceMark rm;
tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: "
PTR_FORMAT " loader: " PTR_FORMAT " %s",
p2i(k),
k->external_name(),
p2i(k->class_loader_data()),
p2i((void *)k->class_loader()),
loader_name());
}
}
void ClassLoaderData::remove_class(Klass* scratch_class) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
Klass* prev = NULL;
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
if (k == scratch_class) {
if (prev == NULL) {
_klasses = k->next_link();
} else {
Klass* next = k->next_link();
prev->set_next_link(next);
}
return;
}
prev = k;
assert(k != k->next_link(), "no loops!");
}
ShouldNotReachHere(); // should have found this class!!
}
void ClassLoaderData::unload() {
_unloading = true;
classes_do(InstanceKlass::notify_unload_class);
if (TraceClassLoaderData) {
ResourceMark rm;
tty->print("[ClassLoaderData: unload loader data " INTPTR_FORMAT, p2i(this));
tty->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)class_loader()),
loader_name());
if (is_anonymous()) {
tty->print(" for anonymous class " INTPTR_FORMAT " ", p2i(_klasses));
}
tty->print_cr("]");
}
}
oop ClassLoaderData::keep_alive_object() const {
assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive");
return is_anonymous() ? _klasses->java_mirror() : class_loader();
}
bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const {
bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
|| is_alive_closure->do_object_b(keep_alive_object());
return alive;
}
ClassLoaderData::~ClassLoaderData() {
classes_do(InstanceKlass::release_C_heap_structures);
Metaspace *m = _metaspace;
if (m != NULL) {
_metaspace = NULL;
delete m;
}
if (_jmethod_ids != NULL) {
Method::clear_jmethod_ids(this);
}
delete _metaspace_lock;
if (_deallocate_list != NULL) {
delete _deallocate_list;
}
}
bool ClassLoaderData::is_ext_class_loader_data() const {
return SystemDictionary::is_ext_class_loader(class_loader());
}
Metaspace* ClassLoaderData::metaspace_non_null() {
assert(!DumpSharedSpaces, "wrong metaspace!");
if (_metaspace == NULL) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
if (_metaspace != NULL) {
return _metaspace;
}
if (this == the_null_class_loader_data()) {
assert (class_loader() == NULL, "Must be");
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType));
} else if (is_anonymous()) {
if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
tty->print_cr("is_anonymous: %s", class_loader()->klass()->internal_name());
}
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType));
} else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
tty->print_cr("is_reflection: %s", class_loader()->klass()->internal_name());
}
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType));
} else {
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::StandardMetaspaceType));
}
}
return _metaspace;
}
jobject ClassLoaderData::add_handle(Handle h) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
return (jobject) _handles.add(h());
}
void ClassLoaderData::add_to_deallocate_list(Metadata* m) {
if (!m->is_shared()) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
if (_deallocate_list == NULL) {
_deallocate_list = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(100, true);
}
_deallocate_list->append_if_missing(m);
}
}
void ClassLoaderData::free_deallocate_list() {
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
if (_deallocate_list == NULL) {
return;
}
for (int i = _deallocate_list->length() - 1; i >= 0; i--) {
Metadata* m = _deallocate_list->at(i);
if (!m->on_stack()) {
_deallocate_list->remove_at(i);
if (m->is_method()) {
MetadataFactory::free_metadata(this, (Method*)m);
} else if (m->is_constantPool()) {
MetadataFactory::free_metadata(this, (ConstantPool*)m);
} else if (m->is_klass()) {
MetadataFactory::free_metadata(this, (InstanceKlass*)m);
} else {
ShouldNotReachHere();
}
}
}
}
ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(oop loader, TRAPS) {
return ClassLoaderDataGraph::add(loader, true, THREAD);
}
const char* ClassLoaderData::loader_name() {
return SystemDictionary::loader_name(class_loader());
}
#ifndef PRODUCT
#undef CLD_DUMP_KLASSES
void ClassLoaderData::dump(outputStream * const out) {
ResourceMark rm;
out->print("ClassLoaderData CLD: " PTR_FORMAT ", loader: " PTR_FORMAT ", loader_klass: " PTR_FORMAT " %s {",
p2i(this), p2i((void *)class_loader()),
p2i(class_loader() != NULL ? class_loader()->klass() : NULL), loader_name());
if (claimed()) out->print(" claimed ");
if (is_unloading()) out->print(" unloading ");
out->cr();
if (metaspace_or_null() != NULL) {
out->print_cr("metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null()));
metaspace_or_null()->dump(out);
} else {
out->print_cr("metaspace: NULL");
}
#ifdef CLD_DUMP_KLASSES
if (Verbose) {
ResourceMark rm;
Klass* k = _klasses;
while (k != NULL) {
out->print_cr("klass " PTR_FORMAT ", %s, CT: %d, MUT: %d", k, k->name()->as_C_string(),
k->has_modified_oops(), k->has_accumulated_modified_oops());
assert(k != k->next_link(), "no loops!");
k = k->next_link();
}
}
#endif // CLD_DUMP_KLASSES
#undef CLD_DUMP_KLASSES
if (_jmethod_ids != NULL) {
Method::print_jmethod_ids(this, out);
}
out->print_cr("}");
}
#endif // PRODUCT
void ClassLoaderData::verify() {
oop cl = class_loader();
guarantee(this == class_loader_data(cl) || is_anonymous(), "Must be the same");
guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data() || is_anonymous(), "must be");
if (metaspace_or_null() != NULL) {
metaspace_or_null()->verify();
}
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
guarantee(k->class_loader_data() == this, "Must be the same");
k->verify();
assert(k != k->next_link(), "no loops!");
}
}
bool ClassLoaderData::contains_klass(Klass* klass) {
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
if (k == klass) return true;
}
return false;
}
ClassLoaderData* ClassLoaderDataGraph::_head = NULL;
ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL;
ClassLoaderData* ClassLoaderDataGraph::_saved_unloading = NULL;
ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL;
bool ClassLoaderDataGraph::_should_purge = false;
ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous, TRAPS) {
ClassLoaderData::Dependencies dependencies(CHECK_NULL);
No_Safepoint_Verifier no_safepoints; // we mustn't GC until we've installed the
ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous, dependencies);
if (!is_anonymous) {
ClassLoaderData** cld_addr = java_lang_ClassLoader::loader_data_addr(loader());
ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
if (old != NULL) {
delete cld;
return old;
}
}
ClassLoaderData** list_head = &_head;
ClassLoaderData* next = _head;
do {
cld->set_next(next);
ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
if (exchanged == next) {
if (TraceClassLoaderData) {
ResourceMark rm;
tty->print("[ClassLoaderData: ");
tty->print("create class loader data " INTPTR_FORMAT, p2i(cld));
tty->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)cld->class_loader()),
cld->loader_name());
tty->print_cr("]");
}
return cld;
}
next = exchanged;
} while (true);
}
void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
cld->oops_do(f, klass_closure, must_claim);
}
}
void ClassLoaderDataGraph::keep_alive_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
if (cld->keep_alive()) {
cld->oops_do(f, klass_closure, must_claim);
}
}
}
void ClassLoaderDataGraph::always_strong_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
if (ClassUnloading) {
keep_alive_oops_do(f, klass_closure, must_claim);
} else {
oops_do(f, klass_closure, must_claim);
}
}
void ClassLoaderDataGraph::cld_do(CLDClosure* cl) {
for (ClassLoaderData* cld = _head; cl != NULL && cld != NULL; cld = cld->next()) {
cl->do_cld(cld);
}
}
void ClassLoaderDataGraph::cld_unloading_do(CLDClosure* cl) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
assert(cld->is_unloading(), "invariant");
cl->do_cld(cld);
}
}
void ClassLoaderDataGraph::roots_cld_do(CLDClosure* strong, CLDClosure* weak) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) {
CLDClosure* closure = cld->keep_alive() ? strong : weak;
if (closure != NULL) {
closure->do_cld(cld);
}
}
}
void ClassLoaderDataGraph::keep_alive_cld_do(CLDClosure* cl) {
roots_cld_do(cl, NULL);
}
void ClassLoaderDataGraph::always_strong_cld_do(CLDClosure* cl) {
if (ClassUnloading) {
keep_alive_cld_do(cl);
} else {
cld_do(cl);
}
}
void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
cld->classes_do(klass_closure);
}
}
void ClassLoaderDataGraph::classes_do(void f(Klass* const)) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
cld->classes_do(f);
}
}
void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
cld->loaded_classes_do(klass_closure);
}
}
void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
cld->classes_do(f);
}
}
GrowableArray<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() {
assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?");
GrowableArray<ClassLoaderData*>* array = new GrowableArray<ClassLoaderData*>();
ClassLoaderData* curr = _head;
while (curr != _saved_head) {
if (!curr->claimed()) {
array->push(curr);
if (TraceClassLoaderData) {
tty->print("[ClassLoaderData] found new CLD: ");
curr->print_value_on(tty);
tty->cr();
}
}
curr = curr->_next;
}
return array;
}
bool ClassLoaderDataGraph::unload_list_contains(const void* x) {
assert(SafepointSynchronize::is_at_safepoint(), "only safe to call at safepoint");
for (ClassLoaderData* cld = _unloading; cld != NULL; cld = cld->next()) {
if (cld->metaspace_or_null() != NULL && cld->metaspace_or_null()->contains(x)) {
return true;
}
}
return false;
}
#ifndef PRODUCT
bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) {
for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
if (loader_data == data) {
return true;
}
}
return false;
}
#endif // PRODUCT
bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, bool clean_alive) {
ClassLoaderData* data = _head;
ClassLoaderData* prev = NULL;
bool seen_dead_loader = false;
_saved_unloading = _unloading;
while (data != NULL) {
if (data->is_alive(is_alive_closure)) {
prev = data;
data = data->next();
continue;
}
seen_dead_loader = true;
ClassLoaderData* dead = data;
dead->unload();
data = data->next();
if (prev != NULL) {
prev->set_next(data);
} else {
assert(dead == _head, "sanity check");
_head = data;
}
dead->set_next(_unloading);
_unloading = dead;
}
if (clean_alive) {
ClassLoaderDataGraph::clean_metaspaces();
}
return seen_dead_loader;
}
void ClassLoaderDataGraph::clean_metaspaces() {
bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
MetadataOnStackMark md_on_stack(has_redefined_a_class);
if (has_redefined_a_class) {
for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
data->classes_do(InstanceKlass::purge_previous_versions);
}
}
free_deallocate_lists();
}
void ClassLoaderDataGraph::purge() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
ClassLoaderData* list = _unloading;
_unloading = NULL;
ClassLoaderData* next = list;
while (next != NULL) {
ClassLoaderData* purge_me = next;
next = purge_me->next();
delete purge_me;
}
Metaspace::purge();
}
void ClassLoaderDataGraph::free_deallocate_lists() {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
cld->free_deallocate_list();
}
for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
cld->free_deallocate_list();
}
}
Metaspace* ClassLoaderData::_ro_metaspace = NULL;
Metaspace* ClassLoaderData::_rw_metaspace = NULL;
static bool _shared_metaspaces_initialized = false;
void ClassLoaderData::initialize_shared_metaspaces() {
assert(DumpSharedSpaces, "only use this for dumping shared spaces");
assert(this == ClassLoaderData::the_null_class_loader_data(),
"only supported for null loader data for now");
assert (!_shared_metaspaces_initialized, "only initialize once");
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
_ro_metaspace = new Metaspace(_metaspace_lock, Metaspace::ROMetaspaceType);
_rw_metaspace = new Metaspace(_metaspace_lock, Metaspace::ReadWriteMetaspaceType);
_shared_metaspaces_initialized = true;
}
Metaspace* ClassLoaderData::ro_metaspace() {
assert(_ro_metaspace != NULL, "should already be initialized");
return _ro_metaspace;
}
Metaspace* ClassLoaderData::rw_metaspace() {
assert(_rw_metaspace != NULL, "should already be initialized");
return _rw_metaspace;
}
ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic()
: _next_klass(NULL) {
ClassLoaderData* cld = ClassLoaderDataGraph::_head;
Klass* klass = NULL;
while (cld != NULL) {
klass = cld->_klasses;
if (klass != NULL) {
_next_klass = klass;
return;
}
cld = cld->next();
}
}
Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass_in_cldg(Klass* klass) {
Klass* next = klass->next_link();
if (next != NULL) {
return next;
}
ClassLoaderData* cld = klass->class_loader_data();
while (next == NULL) {
cld = cld->next();
if (cld == NULL) {
break;
}
next = cld->_klasses;
}
return next;
}
Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() {
Klass* head = _next_klass;
while (head != NULL) {
Klass* next = next_klass_in_cldg(head);
Klass* old_head = (Klass*)Atomic::cmpxchg_ptr(next, &_next_klass, head);
if (old_head == head) {
return head; // Won the CAS.
}
head = old_head;
}
assert(head == NULL, err_msg("head is " PTR_FORMAT ", expected not null:", p2i(head)));
return NULL;
}
ClassLoaderDataGraphMetaspaceIterator::ClassLoaderDataGraphMetaspaceIterator() {
_data = ClassLoaderDataGraph::_head;
}
ClassLoaderDataGraphMetaspaceIterator::~ClassLoaderDataGraphMetaspaceIterator() {}
#ifndef PRODUCT
extern "C" int print_loader_data_graph() {
ClassLoaderDataGraph::dump_on(tty);
return 0;
}
void ClassLoaderDataGraph::verify() {
for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
data->verify();
}
}
void ClassLoaderDataGraph::dump_on(outputStream * const out) {
for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
data->dump(out);
}
MetaspaceAux::dump(out);
}
#endif // PRODUCT
void ClassLoaderData::print_value_on(outputStream* out) const {
if (class_loader() == NULL) {
out->print("NULL class_loader");
} else {
out->print("class loader " INTPTR_FORMAT, p2i(this));
class_loader()->print_value_on(out);
}
}
C:\hotspot-69087d08d473\src\share\vm/classfile/classLoaderData.hpp
#ifndef SHARE_VM_CLASSFILE_CLASSLOADERDATA_HPP
#define SHARE_VM_CLASSFILE_CLASSLOADERDATA_HPP
#include "memory/allocation.hpp"
#include "memory/memRegion.hpp"
#include "memory/metaspace.hpp"
#include "memory/metaspaceCounters.hpp"
#include "runtime/mutex.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_JFR
#include "jfr/support/jfrTraceIdExtension.hpp"
#endif
class ClassLoaderData;
class JNIMethodBlock;
class Metadebug;
class ClassLoaderDataGraph : public AllStatic {
friend class ClassLoaderData;
friend class ClassLoaderDataGraphMetaspaceIterator;
friend class ClassLoaderDataGraphKlassIteratorAtomic;
friend class VMStructs;
private:
static ClassLoaderData* _head;
static ClassLoaderData* _unloading;
static ClassLoaderData* _saved_head;
static ClassLoaderData* _saved_unloading;
static bool _should_purge;
static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS);
static void clean_metaspaces();
public:
static ClassLoaderData* find_or_create(Handle class_loader, TRAPS);
static void purge();
static void clear_claimed_marks();
static void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim);
static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
static void always_strong_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
static void cld_do(CLDClosure* cl);
static void cld_unloading_do(CLDClosure* cl);
static void roots_cld_do(CLDClosure* strong, CLDClosure* weak);
static void keep_alive_cld_do(CLDClosure* cl);
static void always_strong_cld_do(CLDClosure* cl);
static void classes_do(KlassClosure* klass_closure);
static void classes_do(void f(Klass* const));
static void loaded_classes_do(KlassClosure* klass_closure);
static void classes_unloading_do(void f(Klass* const));
static bool do_unloading(BoolObjectClosure* is_alive, bool clean_alive);
static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); }
static GrowableArray<ClassLoaderData*>* new_clds();
static void set_should_purge(bool b) { _should_purge = b; }
static void purge_if_needed() {
if (_should_purge) {
purge();
set_should_purge(false);
}
}
static void free_deallocate_lists();
static void dump_on(outputStream * const out) PRODUCT_RETURN;
static void dump() { dump_on(tty); }
static void verify();
static bool unload_list_contains(const void* x);
#ifndef PRODUCT
static bool contains_loader_data(ClassLoaderData* loader_data);
#endif
};
class ClassLoaderData : public CHeapObj<mtClass> {
friend class VMStructs;
private:
class Dependencies VALUE_OBJ_CLASS_SPEC {
objArrayOop _list_head;
void locked_add(objArrayHandle last,
objArrayHandle new_dependency,
Thread* THREAD);
public:
Dependencies() : _list_head(NULL) {}
Dependencies(TRAPS) : _list_head(NULL) {
init(CHECK);
}
void add(Handle dependency, TRAPS);
void init(TRAPS);
void oops_do(OopClosure* f);
};
class ChunkedHandleList VALUE_OBJ_CLASS_SPEC {
struct Chunk : public CHeapObj<mtClass> {
static const size_t CAPACITY = 32;
oop _data[CAPACITY];
volatile juint _size;
Chunk* _next;
Chunk(Chunk* c) : _next(c), _size(0) { }
};
Chunk* _head;
void oops_do_chunk(OopClosure* f, Chunk* c, const juint size);
public:
ChunkedHandleList() : _head(NULL) {}
~ChunkedHandleList();
oop* add(oop o);
void oops_do(OopClosure* f);
};
friend class ClassLoaderDataGraph;
friend class ClassLoaderDataGraphKlassIteratorAtomic;
friend class ClassLoaderDataGraphMetaspaceIterator;
friend class MetaDataFactory;
friend class Method;
static ClassLoaderData * _the_null_class_loader_data;
oop _class_loader; // oop used to uniquely identify a class loader
Dependencies _dependencies; // holds dependencies from this class loader
Metaspace * _metaspace; // Meta-space where meta-data defined by the
Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup.
bool _unloading; // true if this class loader goes away
bool _keep_alive; // if this CLD is kept alive without a keep_alive_object().
bool _is_anonymous; // if this CLD is for an anonymous class
volatile int _claimed; // true if claimed, for example during GC traces.
Klass* _klasses; // The classes defined by the class loader.
ChunkedHandleList _handles; // Handles to constant pool arrays, etc, which
JNIMethodBlock* _jmethod_ids;
GrowableArray<Metadata*>* _deallocate_list;
ClassLoaderData* _next; /// Next loader_datas created
static Metaspace* _ro_metaspace;
static Metaspace* _rw_metaspace;
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
void set_next(ClassLoaderData* next) { _next = next; }
ClassLoaderData* next() const { return _next; }
ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies);
~ClassLoaderData();
void set_metaspace(Metaspace* m) { _metaspace = m; }
Mutex* metaspace_lock() const { return _metaspace_lock; }
void unload();
bool keep_alive() const { return _keep_alive; }
void classes_do(void f(Klass*));
void loaded_classes_do(KlassClosure* klass_closure);
void classes_do(void f(InstanceKlass*));
void free_deallocate_list();
MetaWord* allocate(size_t size);
public:
void clear_claimed() { _claimed = 0; }
bool claimed() const { return _claimed == 1; }
bool claim();
bool is_alive(BoolObjectClosure* is_alive_closure) const;
Metaspace* metaspace_or_null() const { return _metaspace; }
static ClassLoaderData* the_null_class_loader_data() {
return _the_null_class_loader_data;
}
bool is_anonymous() const { return _is_anonymous; }
static void init_null_class_loader_data() {
assert(_the_null_class_loader_data == NULL, "cannot initialize twice");
assert(ClassLoaderDataGraph::_head == NULL, "cannot initialize twice");
_the_null_class_loader_data = new ClassLoaderData((oop)NULL, false, Dependencies());
ClassLoaderDataGraph::_head = _the_null_class_loader_data;
assert(_the_null_class_loader_data->is_the_null_class_loader_data(), "Must be");
if (DumpSharedSpaces) {
_the_null_class_loader_data->initialize_shared_metaspaces();
}
}
bool is_the_null_class_loader_data() const {
return this == _the_null_class_loader_data;
}
bool is_ext_class_loader_data() const;
Metaspace* metaspace_non_null();
oop class_loader() const { return _class_loader; }
oop keep_alive_object() const;
bool is_unloading() const {
assert(!(is_the_null_class_loader_data() && _unloading), "The null class loader can never be unloaded");
return _unloading;
}
void set_keep_alive(bool value) { _keep_alive = value; }
unsigned int identity_hash() {
return _class_loader == NULL ? 0 : _class_loader->identity_hash();
}
void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim);
void classes_do(KlassClosure* klass_closure);
JNIMethodBlock* jmethod_ids() const { return _jmethod_ids; }
void set_jmethod_ids(JNIMethodBlock* new_block) { _jmethod_ids = new_block; }
void print_value() { print_value_on(tty); }
void print_value_on(outputStream* out) const;
void dump(outputStream * const out) PRODUCT_RETURN;
void verify();
const char* loader_name();
jobject add_handle(Handle h);
void add_class(Klass* k);
void remove_class(Klass* k);
bool contains_klass(Klass* k);
void record_dependency(Klass* to, TRAPS);
void init_dependencies(TRAPS);
void add_to_deallocate_list(Metadata* m);
static ClassLoaderData* class_loader_data(oop loader);
static ClassLoaderData* class_loader_data_or_null(oop loader);
static ClassLoaderData* anonymous_class_loader_data(oop loader, TRAPS);
static void print_loader(ClassLoaderData *loader_data, outputStream *out);
Metaspace* ro_metaspace();
Metaspace* rw_metaspace();
void initialize_shared_metaspaces();
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
};
class ClassLoaderDataGraphKlassIteratorAtomic : public StackObj {
Klass* volatile _next_klass;
public:
ClassLoaderDataGraphKlassIteratorAtomic();
Klass* next_klass();
private:
static Klass* next_klass_in_cldg(Klass* klass);
};
class ClassLoaderDataGraphMetaspaceIterator : public StackObj {
ClassLoaderData* _data;
public:
ClassLoaderDataGraphMetaspaceIterator();
~ClassLoaderDataGraphMetaspaceIterator();
bool repeat() { return _data != NULL; }
Metaspace* get_next() {
assert(_data != NULL, "Should not be NULL in call to the iterator");
Metaspace* result = _data->metaspace_or_null();
_data = _data->next();
return result;
}
};
#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATA_HPP
C:\hotspot-69087d08d473\src\share\vm/classfile/classLoaderData.inline.hpp
#include "classfile/classLoaderData.hpp"
#include "classfile/javaClasses.hpp"
inline ClassLoaderData* ClassLoaderData::class_loader_data_or_null(oop loader) {
if (loader == NULL) {
return ClassLoaderData::the_null_class_loader_data();
}
return java_lang_ClassLoader::loader_data(loader);
}
inline ClassLoaderData* ClassLoaderData::class_loader_data(oop loader) {
ClassLoaderData* loader_data = class_loader_data_or_null(loader);
assert(loader_data != NULL, "Must be");
return loader_data;
}
inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader, TRAPS) {
guarantee(loader() != NULL && loader()->is_oop(), "Loader must be oop");
ClassLoaderData* loader_data= java_lang_ClassLoader::loader_data(loader());
if (loader_data) {
return loader_data;
}
return ClassLoaderDataGraph::add(loader, false, THREAD);
}
C:\hotspot-69087d08d473\src\share\vm/classfile/classLoaderExt.hpp
#ifndef SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
#define SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
#include "classfile/classLoader.hpp"
class ClassLoaderExt: public ClassLoader { // AllStatic
public:
class Context {
const char* _file_name;
public:
Context(const char* class_name, const char* file_name, TRAPS) {
_file_name = file_name;
}
bool check(ClassFileStream* stream, const int classpath_index) {
return true;
}
bool should_verify(int classpath_index) {
return false;
}
instanceKlassHandle record_result(const int classpath_index,
ClassPathEntry* e, instanceKlassHandle result, TRAPS) {
if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) {
if (DumpSharedSpaces) {
result->set_shared_classpath_index(classpath_index);
}
return result;
} else {
return instanceKlassHandle(); // NULL
}
}
};
static void add_class_path_entry(const char* path, bool check_for_duplicates,
ClassPathEntry* new_entry) {
ClassLoader::add_to_list(new_entry);
}
static void append_boot_classpath(ClassPathEntry* new_entry) {
ClassLoader::add_to_list(new_entry);
}
static void setup_search_paths() {}
static void init_lookup_cache(TRAPS) {}
static void copy_lookup_cache_to_archive(char** top, char* end) {}
static char* restore_lookup_cache_from_archive(char* buffer) {return buffer;}
static inline bool is_lookup_cache_enabled() {return false;}
static bool known_to_not_exist(JNIEnv *env, jobject loader, const char *classname, TRAPS) {return false;}
static jobjectArray get_lookup_cache_urls(JNIEnv *env, jobject loader, TRAPS) {return NULL;}
static jintArray get_lookup_cache(JNIEnv *env, jobject loader, const char *pkgname, TRAPS) {return NULL;}
};
#endif // SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
C:\hotspot-69087d08d473\src\share\vm/classfile/classLoaderStats.cpp
#include "precompiled.hpp"
#include "classfile/classLoaderStats.hpp"
#include "utilities/globalDefinitions.hpp"
class ClassStatsClosure : public KlassClosure {
public:
int _num_classes;
ClassStatsClosure() :
_num_classes(0) {
}
virtual void do_klass(Klass* k) {
_num_classes++;
}
};
void ClassLoaderStatsClosure::do_cld(ClassLoaderData* cld) {
oop cl = cld->class_loader();
ClassLoaderStats* cls;
ClassLoaderStats** cls_ptr = _stats->get(cl);
if (cls_ptr == NULL) {
cls = new ClassLoaderStats();
_stats->put(cl, cls);
_total_loaders++;
} else {
cls = *cls_ptr;
}
if (!cld->is_anonymous()) {
cls->_cld = cld;
}
cls->_class_loader = cl;
if (cl != NULL) {
cls->_parent = java_lang_ClassLoader::parent(cl);
addEmptyParents(cls->_parent);
}
ClassStatsClosure csc;
cld->classes_do(&csc);
if(cld->is_anonymous()) {
cls->_anon_classes_count += csc._num_classes;
} else {
cls->_classes_count = csc._num_classes;
}
_total_classes += csc._num_classes;
Metaspace* ms = cld->metaspace_or_null();
if (ms != NULL) {
if(cld->is_anonymous()) {
cls->_anon_chunk_sz += ms->allocated_chunks_bytes();
cls->_anon_block_sz += ms->allocated_blocks_bytes();
} else {
cls->_chunk_sz = ms->allocated_chunks_bytes();
cls->_block_sz = ms->allocated_blocks_bytes();
}
_total_chunk_sz += ms->allocated_chunks_bytes();
_total_block_sz += ms->allocated_blocks_bytes();
}
}
#ifdef _LP64
#define SPACE "%8s"
#else
#define SPACE "%s"
#endif
bool ClassLoaderStatsClosure::do_entry(oop const& key, ClassLoaderStats* const& cls) {
Klass* class_loader_klass = (cls->_class_loader == NULL ? NULL : cls->_class_loader->klass());
Klass* parent_klass = (cls->_parent == NULL ? NULL : cls->_parent->klass());
_out->print(INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " UINTX_FORMAT_W(6) " " SIZE_FORMAT_W(8) " " SIZE_FORMAT_W(8) " ",
p2i(class_loader_klass), p2i(parent_klass), p2i(cls->_cld),
cls->_classes_count,
cls->_chunk_sz, cls->_block_sz);
if (class_loader_klass != NULL) {
_out->print("%s", class_loader_klass->external_name());
} else {
_out->print("<boot class loader>");
}
_out->cr();
if (cls->_anon_classes_count > 0) {
_out->print_cr(SPACE SPACE SPACE " " UINTX_FORMAT_W(6) " " SIZE_FORMAT_W(8) " " SIZE_FORMAT_W(8) " + unsafe anonymous classes",
"", "", "",
cls->_anon_classes_count,
cls->_anon_chunk_sz, cls->_anon_block_sz);
}
return true;
}
void ClassLoaderStatsClosure::print() {
_out->print_cr("ClassLoader" SPACE " Parent" SPACE " CLD*" SPACE " Classes ChunkSz BlockSz Type", "", "", "");
_stats->iterate(this);
_out->print("Total = " UINTX_FORMAT_W(-6), _total_loaders);
_out->print(SPACE SPACE SPACE " ", "", "", "");
_out->print_cr(UINTX_FORMAT_W(6) " " SIZE_FORMAT_W(8) " " SIZE_FORMAT_W(8) " ",
_total_classes,
_total_chunk_sz,
_total_block_sz);
_out->print_cr("ChunkSz: Total size of all allocated metaspace chunks");
_out->print_cr("BlockSz: Total size of all allocated metaspace blocks (each chunk has several blocks)");
}
void ClassLoaderStatsClosure::addEmptyParents(oop cl) {
while (cl != NULL && java_lang_ClassLoader::loader_data(cl) == NULL) {
ClassLoaderStats** cls_ptr = _stats->get(cl);
if (cls_ptr == NULL) {
ClassLoaderStats* cls = new ClassLoaderStats();
cls->_class_loader = cl;
cls->_parent = java_lang_ClassLoader::parent(cl);
_stats->put(cl, cls);
_total_loaders++;
}
cl = java_lang_ClassLoader::parent(cl);
}
}
void ClassLoaderStatsVMOperation::doit() {
ClassLoaderStatsClosure clsc (_out);
ClassLoaderDataGraph::cld_do(&clsc);
clsc.print();
}
void ClassLoaderStatsDCmd::execute(DCmdSource source, TRAPS) {
ClassLoaderStatsVMOperation op(output());
VMThread::execute(&op);
}
C:\hotspot-69087d08d473\src\share\vm/classfile/classLoaderStats.hpp
#ifndef SHARE_VM_CLASSFILE_CLASSLOADERSTATS_HPP
#define SHARE_VM_CLASSFILE_CLASSLOADERSTATS_HPP
#include "classfile/classLoaderData.hpp"
#include "oops/klass.hpp"
#include "oops/oopsHierarchy.hpp"
#include "runtime/vm_operations.hpp"
#include "services/diagnosticCommand.hpp"
#include "utilities/resourceHash.hpp"
class ClassLoaderStatsDCmd : public DCmd {
public:
ClassLoaderStatsDCmd(outputStream* output, bool heap) :
DCmd(output, heap) {
}
static const char* name() {
return "VM.classloader_stats";
}
static const char* description() {
return "Print statistics about all ClassLoaders.";
}
static const char* impact() {
return "Low";
}
virtual void execute(DCmdSource source, TRAPS);
static int num_arguments() {
return 0;
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
};
class ClassLoaderStats : public ResourceObj {
public:
ClassLoaderData* _cld;
oop _class_loader;
oop _parent;
size_t _chunk_sz;
size_t _block_sz;
uintx _classes_count;
size_t _anon_chunk_sz;
size_t _anon_block_sz;
uintx _anon_classes_count;
ClassLoaderStats() :
_cld(0),
_class_loader(0),
_parent(0),
_chunk_sz(0),
_block_sz(0),
_classes_count(0),
_anon_block_sz(0),
_anon_chunk_sz(0),
_anon_classes_count(0) {
}
};
class ClassLoaderStatsClosure : public CLDClosure {
protected:
static bool oop_equals(oop const& s1, oop const& s2) {
return s1 == s2;
}
static unsigned oop_hash(oop const& s1) {
uintptr_t tmp = cast_from_oop<uintptr_t>(s1);
unsigned hash = (unsigned)tmp;
hash = ~hash + (hash << 15);
hash = hash ^ (hash >> 12);
hash = hash + (hash << 2);
hash = hash ^ (hash >> 4);
hash = hash * 2057;
hash = hash ^ (hash >> 16);
return hash;
}
typedef ResourceHashtable<oop, ClassLoaderStats*,
ClassLoaderStatsClosure::oop_hash, ClassLoaderStatsClosure::oop_equals> StatsTable;
outputStream* _out;
StatsTable* _stats;
uintx _total_loaders;
uintx _total_classes;
size_t _total_chunk_sz;
size_t _total_block_sz;
public:
ClassLoaderStatsClosure(outputStream* out) :
_out(out),
_total_loaders(0),
_total_block_sz(0),
_total_chunk_sz(0),
_total_classes(0),
_stats(new StatsTable()) {
}
virtual void do_cld(ClassLoaderData* cld);
virtual bool do_entry(oop const& key, ClassLoaderStats* const& cls);
void print();
private:
void addEmptyParents(oop cl);
};
class ClassLoaderStatsVMOperation : public VM_Operation {
outputStream* _out;
public:
ClassLoaderStatsVMOperation(outputStream* out) :
_out(out) {
}
VMOp_Type type() const {
return VMOp_ClassLoaderStatsOperation;
}
void doit();
};
#endif // SHARE_VM_CLASSFILE_CLASSLOADERSTATS_HPP
C:\hotspot-69087d08d473\src\share\vm/classfile/defaultMethods.cpp
#include "precompiled.hpp"
#include "classfile/bytecodeAssembler.hpp"
#include "classfile/defaultMethods.hpp"
#include "classfile/symbolTable.hpp"
#include "memory/allocation.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/signature.hpp"
#include "runtime/thread.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klass.hpp"
#include "oops/method.hpp"
#include "utilities/accessFlags.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/ostream.hpp"
#include "utilities/pair.hpp"
#include "utilities/resourceHash.hpp"
typedef enum { QUALIFIED, DISQUALIFIED } QualifiedState;
class PseudoScopeMark : public ResourceObj {
public:
virtual void destroy() = 0;
};
class PseudoScope : public ResourceObj {
private:
GrowableArray<PseudoScopeMark*> _marks;
public:
static PseudoScope* cast(void* data) {
return static_cast<PseudoScope*>(data);
}
void add_mark(PseudoScopeMark* psm) {
_marks.append(psm);
}
void destroy() {
for (int i = 0; i < _marks.length(); ++i) {
_marks.at(i)->destroy();
}
}
};
#ifndef PRODUCT
static void print_slot(outputStream* str, Symbol* name, Symbol* signature) {
ResourceMark rm;
str->print("%s%s", name->as_C_string(), signature->as_C_string());
}
static void print_method(outputStream* str, Method* mo, bool with_class=true) {
ResourceMark rm;
if (with_class) {
str->print("%s.", mo->klass_name()->as_C_string());
}
print_slot(str, mo->name(), mo->signature());
}
#endif // ndef PRODUCT
template <class ALGO>
class HierarchyVisitor : StackObj {
private:
class Node : public ResourceObj {
public:
InstanceKlass* _class;
bool _super_was_visited;
int _interface_index;
void* _algorithm_data;
Node(InstanceKlass* cls, void* data, bool visit_super)
: _class(cls), _super_was_visited(!visit_super),
_interface_index(0), _algorithm_data(data) {}
int number_of_interfaces() { return _class->local_interfaces()->length(); }
int interface_index() { return _interface_index; }
void set_super_visited() { _super_was_visited = true; }
void increment_visited_interface() { ++_interface_index; }
void set_all_interfaces_visited() {
_interface_index = number_of_interfaces();
}
bool has_visited_super() { return _super_was_visited; }
bool has_visited_all_interfaces() {
return interface_index() >= number_of_interfaces();
}
InstanceKlass* interface_at(int index) {
return InstanceKlass::cast(_class->local_interfaces()->at(index));
}
InstanceKlass* next_super() { return _class->java_super(); }
InstanceKlass* next_interface() {
return interface_at(interface_index());
}
};
bool _cancelled;
GrowableArray<Node*> _path;
Node* current_top() const { return _path.top(); }
bool has_more_nodes() const { return !_path.is_empty(); }
void push(InstanceKlass* cls, void* data) {
assert(cls != NULL, "Requires a valid instance class");
Node* node = new Node(cls, data, has_super(cls));
_path.push(node);
}
void pop() { _path.pop(); }
void reset_iteration() {
_cancelled = false;
_path.clear();
}
bool is_cancelled() const { return _cancelled; }
static bool has_super(InstanceKlass* cls) {
return cls->super() != NULL;
}
Node* node_at_depth(int i) const {
return (i >= _path.length()) ? NULL : _path.at(_path.length() - i - 1);
}
protected:
int current_depth() const { return _path.length() - 1; }
InstanceKlass* class_at_depth(int i) {
Node* n = node_at_depth(i);
return n == NULL ? NULL : n->_class;
}
InstanceKlass* current_class() { return class_at_depth(0); }
void* data_at_depth(int i) {
Node* n = node_at_depth(i);
return n == NULL ? NULL : n->_algorithm_data;
}
void* current_data() { return data_at_depth(0); }
void cancel_iteration() { _cancelled = true; }
public:
void run(InstanceKlass* root) {
ALGO* algo = static_cast<ALGO*>(this);
reset_iteration();
void* algo_data = algo->new_node_data(root);
push(root, algo_data);
bool top_needs_visit = true;
do {
Node* top = current_top();
if (top_needs_visit) {
if (algo->visit() == false) {
top->set_super_visited();
top->set_all_interfaces_visited();
}
top_needs_visit = false;
}
if (top->has_visited_super() && top->has_visited_all_interfaces()) {
algo->free_node_data(top->_algorithm_data);
pop();
} else {
InstanceKlass* next = NULL;
if (top->has_visited_super() == false) {
next = top->next_super();
top->set_super_visited();
} else {
next = top->next_interface();
top->increment_visited_interface();
}
assert(next != NULL, "Otherwise we shouldn't be here");
algo_data = algo->new_node_data(next);
push(next, algo_data);
top_needs_visit = true;
}
} while (!is_cancelled() && has_more_nodes());
}
};
#ifndef PRODUCT
class PrintHierarchy : public HierarchyVisitor<PrintHierarchy> {
public:
bool visit() {
InstanceKlass* cls = current_class();
streamIndentor si(tty, current_depth() * 2);
tty->indent().print_cr("%s", cls->name()->as_C_string());
return true;
}
void* new_node_data(InstanceKlass* cls) { return NULL; }
void free_node_data(void* data) { return; }
};
#endif // ndef PRODUCT
class KeepAliveRegistrar : public StackObj {
private:
Thread* _thread;
GrowableArray<ConstantPool*> _keep_alive;
public:
KeepAliveRegistrar(Thread* thread) : _thread(thread), _keep_alive(20) {
assert(thread == Thread::current(), "Must be current thread");
}
~KeepAliveRegistrar() {
for (int i = _keep_alive.length() - 1; i >= 0; --i) {
ConstantPool* cp = _keep_alive.at(i);
int idx = _thread->metadata_handles()->find_from_end(cp);
assert(idx > 0, "Must be in the list");
_thread->metadata_handles()->remove_at(idx);
}
}
void register_class(InstanceKlass* ik) {
ConstantPool* cp = ik->constants();
_keep_alive.push(cp);
_thread->metadata_handles()->push(cp);
}
};
class KeepAliveVisitor : public HierarchyVisitor<KeepAliveVisitor> {
private:
KeepAliveRegistrar* _registrar;
public:
KeepAliveVisitor(KeepAliveRegistrar* registrar) : _registrar(registrar) {}
void* new_node_data(InstanceKlass* cls) { return NULL; }
void free_node_data(void* data) { return; }
bool visit() {
_registrar->register_class(current_class());
return true;
}
};
class MethodFamily : public ResourceObj {
private:
GrowableArray<Pair<Method*,QualifiedState> > _members;
ResourceHashtable<Method*, int> _member_index;
Method* _selected_target; // Filled in later, if a unique target exists
Symbol* _exception_message; // If no unique target is found
Symbol* _exception_name; // If no unique target is found
bool contains_method(Method* method) {
int* lookup = _member_index.get(method);
return lookup != NULL;
}
void add_method(Method* method, QualifiedState state) {
Pair<Method*,QualifiedState> entry(method, state);
_member_index.put(method, _members.length());
_members.append(entry);
}
void disqualify_method(Method* method) {
int* index = _member_index.get(method);
guarantee(index != NULL && *index >= 0 && *index < _members.length(), "bad index");
_members.at(*index).second = DISQUALIFIED;
}
Symbol* generate_no_defaults_message(TRAPS) const;
Symbol* generate_method_message(Symbol *klass_name, Method* method, TRAPS) const;
Symbol* generate_conflicts_message(GrowableArray<Method*>* methods, TRAPS) const;
public:
MethodFamily()
: _selected_target(NULL), _exception_message(NULL), _exception_name(NULL) {}
void set_target_if_empty(Method* m) {
if (_selected_target == NULL && !m->is_overpass()) {
_selected_target = m;
}
}
void record_qualified_method(Method* m) {
if (!contains_method(m)) {
add_method(m, QUALIFIED);
}
}
void record_disqualified_method(Method* m) {
if (!contains_method(m)) {
add_method(m, DISQUALIFIED);
} else {
disqualify_method(m);
}
}
bool has_target() const { return _selected_target != NULL; }
bool throws_exception() { return _exception_message != NULL; }
Method* get_selected_target() { return _selected_target; }
Symbol* get_exception_message() { return _exception_message; }
Symbol* get_exception_name() { return _exception_name; }
void determine_target(InstanceKlass* root, TRAPS) {
if (has_target() || throws_exception()) {
return;
}
GrowableArray<Method*> qualified_methods;
int num_defaults = 0;
int default_index = -1;
int qualified_index = -1;
for (int i = 0; i < _members.length(); ++i) {
Pair<Method*,QualifiedState> entry = _members.at(i);
if (entry.second == QUALIFIED) {
qualified_methods.append(entry.first);
qualified_index++;
if (entry.first->is_default_method()) {
num_defaults++;
default_index = qualified_index;
}
}
}
if (num_defaults == 0) {
if (qualified_methods.length() == 0) {
_exception_message = generate_no_defaults_message(CHECK);
} else {
assert(root != NULL, "Null root class");
_exception_message = generate_method_message(root->name(), qualified_methods.at(0), CHECK);
}
_exception_name = vmSymbols::java_lang_AbstractMethodError();
} else if (num_defaults == 1) {
_selected_target = qualified_methods.at(default_index);
} else if (num_defaults > 1) {
_exception_message = generate_conflicts_message(&qualified_methods,CHECK);
_exception_name = vmSymbols::java_lang_IncompatibleClassChangeError();
if (TraceDefaultMethods) {
_exception_message->print_value_on(tty);
tty->cr();
}
}
}
bool contains_signature(Symbol* query) {
for (int i = 0; i < _members.length(); ++i) {
if (query == _members.at(i).first->signature()) {
return true;
}
}
return false;
}
#ifndef PRODUCT
void print_sig_on(outputStream* str, Symbol* signature, int indent) const {
streamIndentor si(str, indent * 2);
str->indent().print_cr("Logical Method %s:", signature->as_C_string());
streamIndentor si2(str);
for (int i = 0; i < _members.length(); ++i) {
str->indent();
print_method(str, _members.at(i).first);
if (_members.at(i).second == DISQUALIFIED) {
str->print(" (disqualified)");
}
str->cr();
}
if (_selected_target != NULL) {
print_selected(str, 1);
}
}
void print_selected(outputStream* str, int indent) const {
assert(has_target(), "Should be called otherwise");
streamIndentor si(str, indent * 2);
str->indent().print("Selected method: ");
print_method(str, _selected_target);
Klass* method_holder = _selected_target->method_holder();
if (!method_holder->is_interface()) {
tty->print(" : in superclass");
}
str->cr();
}
void print_exception(outputStream* str, int indent) {
assert(throws_exception(), "Should be called otherwise");
assert(_exception_name != NULL, "exception_name should be set");
streamIndentor si(str, indent * 2);
str->indent().print_cr("%s: %s", _exception_name->as_C_string(), _exception_message->as_C_string());
}
#endif // ndef PRODUCT
};
Symbol* MethodFamily::generate_no_defaults_message(TRAPS) const {
return SymbolTable::new_symbol("No qualifying defaults found", THREAD);
}
Symbol* MethodFamily::generate_method_message(Symbol *klass_name, Method* method, TRAPS) const {
stringStream ss;
ss.print("Method ");
Symbol* name = method->name();
Symbol* signature = method->signature();
ss.write((const char*)klass_name->bytes(), klass_name->utf8_length());
ss.print(".");
ss.write((const char*)name->bytes(), name->utf8_length());
ss.write((const char*)signature->bytes(), signature->utf8_length());
ss.print(" is abstract");
return SymbolTable::new_symbol(ss.base(), (int)ss.size(), THREAD);
}
Symbol* MethodFamily::generate_conflicts_message(GrowableArray<Method*>* methods, TRAPS) const {
stringStream ss;
ss.print("Conflicting default methods:");
for (int i = 0; i < methods->length(); ++i) {
Method* method = methods->at(i);
Symbol* klass = method->klass_name();
Symbol* name = method->name();
ss.print(" ");
ss.write((const char*)klass->bytes(), klass->utf8_length());
ss.print(".");
ss.write((const char*)name->bytes(), name->utf8_length());
}
return SymbolTable::new_symbol(ss.base(), (int)ss.size(), THREAD);
}
class StateRestorer;
class StatefulMethodFamily : public ResourceObj {
friend class StateRestorer;
private:
QualifiedState _qualification_state;
void set_qualification_state(QualifiedState state) {
_qualification_state = state;
}
protected:
MethodFamily* _method_family;
public:
StatefulMethodFamily() {
_method_family = new MethodFamily();
_qualification_state = QUALIFIED;
}
StatefulMethodFamily(MethodFamily* mf) {
_method_family = mf;
_qualification_state = QUALIFIED;
}
void set_target_if_empty(Method* m) { _method_family->set_target_if_empty(m); }
MethodFamily* get_method_family() { return _method_family; }
StateRestorer* record_method_and_dq_further(Method* mo);
};
class StateRestorer : public PseudoScopeMark {
private:
StatefulMethodFamily* _method;
QualifiedState _state_to_restore;
public:
StateRestorer(StatefulMethodFamily* dm, QualifiedState state)
: _method(dm), _state_to_restore(state) {}
~StateRestorer() { destroy(); }
void restore_state() { _method->set_qualification_state(_state_to_restore); }
virtual void destroy() { restore_state(); }
};
StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) {
StateRestorer* mark = new StateRestorer(this, _qualification_state);
if (_qualification_state == QUALIFIED) {
_method_family->record_qualified_method(mo);
} else {
_method_family->record_disqualified_method(mo);
}
set_qualification_state(DISQUALIFIED);
return mark;
}
class EmptyVtableSlot : public ResourceObj {
private:
Symbol* _name;
Symbol* _signature;
int _size_of_parameters;
MethodFamily* _binding;
public:
EmptyVtableSlot(Method* method)
: _name(method->name()), _signature(method->signature()),
_size_of_parameters(method->size_of_parameters()), _binding(NULL) {}
Symbol* name() const { return _name; }
Symbol* signature() const { return _signature; }
int size_of_parameters() const { return _size_of_parameters; }
void bind_family(MethodFamily* lm) { _binding = lm; }
bool is_bound() { return _binding != NULL; }
MethodFamily* get_binding() { return _binding; }
#ifndef PRODUCT
void print_on(outputStream* str) const {
print_slot(str, name(), signature());
}
#endif // ndef PRODUCT
};
static bool already_in_vtable_slots(GrowableArray<EmptyVtableSlot*>* slots, Method* m) {
bool found = false;
for (int j = 0; j < slots->length(); ++j) {
if (slots->at(j)->name() == m->name() &&
slots->at(j)->signature() == m->signature() ) {
found = true;
break;
}
}
return found;
}
static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots(
InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS) {
assert(klass != NULL, "Must be valid class");
GrowableArray<EmptyVtableSlot*>* slots = new GrowableArray<EmptyVtableSlot*>();
for (int i = 0; i < mirandas->length(); ++i) {
Method* m = mirandas->at(i);
if (!already_in_vtable_slots(slots, m)) {
slots->append(new EmptyVtableSlot(m));
}
}
InstanceKlass* super = klass->java_super();
while (super != NULL) {
for (int i = 0; i < super->methods()->length(); ++i) {
Method* m = super->methods()->at(i);
if (m->is_overpass() || m->is_static()) {
Method* impl = klass->lookup_method(m->name(), m->signature());
if (impl == NULL || impl->is_overpass() || impl->is_static()) {
if (!already_in_vtable_slots(slots, m)) {
slots->append(new EmptyVtableSlot(m));
}
}
}
}
if (super->default_methods() != NULL) {
for (int i = 0; i < super->default_methods()->length(); ++i) {
Method* m = super->default_methods()->at(i);
Method* impl = klass->lookup_method(m->name(), m->signature());
if (impl == NULL || impl->is_overpass() || impl->is_static()) {
if (!already_in_vtable_slots(slots, m)) {
slots->append(new EmptyVtableSlot(m));
}
}
}
}
super = super->java_super();
}
#ifndef PRODUCT
if (TraceDefaultMethods) {
tty->print_cr("Slots that need filling:");
streamIndentor si(tty);
for (int i = 0; i < slots->length(); ++i) {
tty->indent();
slots->at(i)->print_on(tty);
tty->cr();
}
}
#endif // ndef PRODUCT
return slots;
}
class FindMethodsByErasedSig : public HierarchyVisitor<FindMethodsByErasedSig> {
private:
Symbol* _method_name;
Symbol* _method_signature;
StatefulMethodFamily* _family;
public:
FindMethodsByErasedSig(Symbol* name, Symbol* signature) :
_method_name(name), _method_signature(signature),
_family(NULL) {}
void get_discovered_family(MethodFamily** family) {
if (_family != NULL) {
} else {
}
}
void* new_node_data(InstanceKlass* cls) { return new PseudoScope(); }
void free_node_data(void* node_data) {
PseudoScope::cast(node_data)->destroy();
}
bool visit() {
PseudoScope* scope = PseudoScope::cast(current_data());
InstanceKlass* iklass = current_class();
Method* m = iklass->find_method(_method_name, _method_signature);
if (m != NULL && !m->is_static() && !m->is_overpass() && !m->is_private()) {
if (_family == NULL) {
_family = new StatefulMethodFamily();
}
if (iklass->is_interface()) {
StateRestorer* restorer = _family->record_method_and_dq_further(m);
scope->add_mark(restorer);
} else {
_family->set_target_if_empty(m);
}
}
return true;
}
};
static void create_defaults_and_exceptions(
GrowableArray<EmptyVtableSlot*>* slots, InstanceKlass* klass, TRAPS);
static void generate_erased_defaults(
InstanceKlass* klass, GrowableArray<EmptyVtableSlot*>* empty_slots,
EmptyVtableSlot* slot, TRAPS) {
FindMethodsByErasedSig visitor(slot->name(), slot->signature());
visitor.run(klass);
MethodFamily* family;
visitor.get_discovered_family(&family);
if (family != NULL) {
family->determine_target(klass, CHECK);
slot->bind_family(family);
}
}
static void merge_in_new_methods(InstanceKlass* klass,
GrowableArray<Method*>* new_methods, TRAPS);
static void create_default_methods( InstanceKlass* klass,
GrowableArray<Method*>* new_methods, TRAPS);
void DefaultMethods::generate_default_methods(
InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS) {
ResourceMark rm(THREAD);
KeepAliveRegistrar keepAlive(THREAD);
KeepAliveVisitor loadKeepAlive(&keepAlive);
loadKeepAlive.run(klass);
#ifndef PRODUCT
if (TraceDefaultMethods) {
ResourceMark rm; // be careful with these!
tty->print_cr("%s %s requires default method processing",
klass->is_interface() ? "Interface" : "Class",
klass->name()->as_klass_external_name());
PrintHierarchy printer;
printer.run(klass);
}
#endif // ndef PRODUCT
GrowableArray<EmptyVtableSlot*>* empty_slots =
find_empty_vtable_slots(klass, mirandas, CHECK);
for (int i = 0; i < empty_slots->length(); ++i) {
EmptyVtableSlot* slot = empty_slots->at(i);
#ifndef PRODUCT
if (TraceDefaultMethods) {
streamIndentor si(tty, 2);
tty->indent().print("Looking for default methods for slot ");
slot->print_on(tty);
tty->cr();
}
#endif // ndef PRODUCT
generate_erased_defaults(klass, empty_slots, slot, CHECK);
}
#ifndef PRODUCT
if (TraceDefaultMethods) {
tty->print_cr("Creating defaults and overpasses...");
}
#endif // ndef PRODUCT
create_defaults_and_exceptions(empty_slots, klass, CHECK);
#ifndef PRODUCT
if (TraceDefaultMethods) {
tty->print_cr("Default method processing complete");
}
#endif // ndef PRODUCT
}
static int assemble_method_error(
BytecodeConstantPool* cp, BytecodeBuffer* buffer, Symbol* errorName, Symbol* message, TRAPS) {
Symbol* init = vmSymbols::object_initializer_name();
Symbol* sig = vmSymbols::string_void_signature();
BytecodeAssembler assem(buffer, cp);
assem._new(errorName);
assem.dup();
assem.load_string(message);
assem.invokespecial(errorName, init, sig);
assem.athrow();
return 3; // max stack size: [ exception, exception, string ]
}
static Method* new_method(
BytecodeConstantPool* cp, BytecodeBuffer* bytecodes, Symbol* name,
Symbol* sig, AccessFlags flags, int max_stack, int params,
ConstMethod::MethodType mt, TRAPS) {
address code_start = 0;
int code_length = 0;
InlineTableSizes sizes;
if (bytecodes != NULL && bytecodes->length() > 0) {
code_start = static_cast<address>(bytecodes->adr_at(0));
code_length = bytecodes->length();
}
Method* m = Method::allocate(cp->pool_holder()->class_loader_data(),
code_length, flags, &sizes,
mt, CHECK_NULL);
m->set_constants(NULL); // This will get filled in later
m->set_name_index(cp->utf8(name));
m->set_signature_index(cp->utf8(sig));
ResultTypeFinder rtf(sig);
m->constMethod()->set_result_type(rtf.type());
m->set_size_of_parameters(params);
m->set_max_stack(max_stack);
m->set_max_locals(params);
m->constMethod()->set_stackmap_data(NULL);
m->set_code(code_start);
return m;
}
static void switchover_constant_pool(BytecodeConstantPool* bpool,
InstanceKlass* klass, GrowableArray<Method*>* new_methods, TRAPS) {
if (new_methods->length() > 0) {
ConstantPool* cp = bpool->create_constant_pool(CHECK);
if (cp != klass->constants()) {
klass->class_loader_data()->add_to_deallocate_list(klass->constants());
klass->set_constants(cp);
cp->set_pool_holder(klass);
for (int i = 0; i < new_methods->length(); ++i) {
new_methods->at(i)->set_constants(cp);
}
for (int i = 0; i < klass->methods()->length(); ++i) {
Method* mo = klass->methods()->at(i);
mo->set_constants(cp);
}
}
}
}
static void create_defaults_and_exceptions(
GrowableArray<EmptyVtableSlot*>* slots,
InstanceKlass* klass, TRAPS) {
GrowableArray<Method*> overpasses;
GrowableArray<Method*> defaults;
BytecodeConstantPool bpool(klass->constants());
for (int i = 0; i < slots->length(); ++i) {
EmptyVtableSlot* slot = slots->at(i);
if (slot->is_bound()) {
MethodFamily* method = slot->get_binding();
BytecodeBuffer buffer;
#ifndef PRODUCT
if (TraceDefaultMethods) {
tty->print("for slot: ");
slot->print_on(tty);
tty->cr();
if (method->has_target()) {
method->print_selected(tty, 1);
} else if (method->throws_exception()) {
method->print_exception(tty, 1);
}
}
#endif // ndef PRODUCT
if (method->has_target()) {
Method* selected = method->get_selected_target();
if (selected->method_holder()->is_interface()) {
defaults.push(selected);
}
} else if (method->throws_exception()) {
int max_stack = assemble_method_error(&bpool, &buffer,
method->get_exception_name(), method->get_exception_message(), CHECK);
AccessFlags flags = accessFlags_from(
JVM_ACC_PUBLIC | JVM_ACC_SYNTHETIC | JVM_ACC_BRIDGE);
Method* m = new_method(&bpool, &buffer, slot->name(), slot->signature(),
flags, max_stack, slot->size_of_parameters(),
ConstMethod::OVERPASS, CHECK);
if (m != NULL) {
overpasses.push(m);
}
}
}
}
#ifndef PRODUCT
if (TraceDefaultMethods) {
tty->print_cr("Created %d overpass methods", overpasses.length());
tty->print_cr("Created %d default methods", defaults.length());
}
#endif // ndef PRODUCT
if (overpasses.length() > 0) {
switchover_constant_pool(&bpool, klass, &overpasses, CHECK);
merge_in_new_methods(klass, &overpasses, CHECK);
}
if (defaults.length() > 0) {
create_default_methods(klass, &defaults, CHECK);
}
}
static void create_default_methods( InstanceKlass* klass,
GrowableArray<Method*>* new_methods, TRAPS) {
int new_size = new_methods->length();
Array<Method*>* total_default_methods = MetadataFactory::new_array<Method*>(
klass->class_loader_data(), new_size, NULL, CHECK);
for (int index = 0; index < new_size; index++ ) {
total_default_methods->at_put(index, new_methods->at(index));
}
Method::sort_methods(total_default_methods, false, false);
klass->set_default_methods(total_default_methods);
}
static void sort_methods(GrowableArray<Method*>* methods) {
bool sorted = true;
for (int i = methods->length() - 1; i > 0; --i) {
for (int j = 0; j < i; ++j) {
Method* m1 = methods->at(j);
Method* m2 = methods->at(j + 1);
if ((uintptr_t)m1->name() > (uintptr_t)m2->name()) {
methods->at_put(j, m2);
methods->at_put(j + 1, m1);
sorted = false;
}
}
if (sorted) break;
sorted = true;
}
#ifdef ASSERT
uintptr_t prev = 0;
for (int i = 0; i < methods->length(); ++i) {
Method* mh = methods->at(i);
uintptr_t nv = (uintptr_t)mh->name();
assert(nv >= prev, "Incorrect overpass method ordering");
prev = nv;
}
#endif
}
static void merge_in_new_methods(InstanceKlass* klass,
GrowableArray<Method*>* new_methods, TRAPS) {
enum { ANNOTATIONS, PARAMETERS, DEFAULTS, NUM_ARRAYS };
Array<Method*>* original_methods = klass->methods();
Array<int>* original_ordering = klass->method_ordering();
Array<int>* merged_ordering = Universe::the_empty_int_array();
int new_size = klass->methods()->length() + new_methods->length();
Array<Method*>* merged_methods = MetadataFactory::new_array<Method*>(
klass->class_loader_data(), new_size, NULL, CHECK);
if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) {
merged_ordering = MetadataFactory::new_array<int>(
klass->class_loader_data(), new_size, CHECK);
}
int method_order_index = klass->methods()->length();
sort_methods(new_methods);
int orig_idx = 0;
int new_idx = 0;
for (int i = 0; i < new_size; ++i) {
Method* orig_method = NULL;
Method* new_method = NULL;
if (orig_idx < original_methods->length()) {
orig_method = original_methods->at(orig_idx);
}
if (new_idx < new_methods->length()) {
new_method = new_methods->at(new_idx);
}
if (orig_method != NULL &&
(new_method == NULL || orig_method->name() < new_method->name())) {
merged_methods->at_put(i, orig_method);
original_methods->at_put(orig_idx, NULL);
if (merged_ordering->length() > 0) {
assert(original_ordering != NULL && original_ordering->length() > 0,
"should have original order information for this method");
merged_ordering->at_put(i, original_ordering->at(orig_idx));
}
++orig_idx;
} else {
merged_methods->at_put(i, new_method);
if (merged_ordering->length() > 0) {
merged_ordering->at_put(i, method_order_index++);
}
++new_idx;
}
merged_methods->at(i)->set_method_idnum(i);
merged_methods->at(i)->set_orig_method_idnum(i);
}
#ifdef ASSERT
uintptr_t prev = 0;
for (int i = 0; i < merged_methods->length(); ++i) {
Method* mo = merged_methods->at(i);
uintptr_t nv = (uintptr_t)mo->name();
assert(nv >= prev, "Incorrect method ordering");
prev = nv;
}
#endif
klass->set_methods(merged_methods);
klass->set_initial_method_idnum(new_size);
klass->set_method_ordering(merged_ordering);
ClassLoaderData* cld = klass->class_loader_data();
if (original_methods->length() > 0) {
MetadataFactory::free_array(cld, original_methods);
}
if (original_ordering != NULL && original_ordering->length() > 0) {
MetadataFactory::free_array(cld, original_ordering);
}
}
C:\hotspot-69087d08d473\src\share\vm/classfile/defaultMethods.hpp
#ifndef SHARE_VM_CLASSFILE_DEFAULTMETHODS_HPP
#define SHARE_VM_CLASSFILE_DEFAULTMETHODS_HPP
#include "runtime/handles.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/exceptions.hpp"
class InstanceKlass;
class Symbol;
class Method;
class DefaultMethods : AllStatic {
public:
static void generate_default_methods(
InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS);
};
#endif // SHARE_VM_CLASSFILE_DEFAULTMETHODS_HPP
C:\hotspot-69087d08d473\src\share\vm/classfile/dictionary.cpp
#include "precompiled.hpp"
#include "classfile/dictionary.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "memory/iterator.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiRedefineClassesTrace.hpp"
#include "runtime/orderAccess.inline.hpp"
#include "utilities/hashtable.inline.hpp"
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
DictionaryEntry* Dictionary::_current_class_entry = NULL;
int Dictionary::_current_class_index = 0;
size_t Dictionary::entry_size() {
if (DumpSharedSpaces) {
return SystemDictionaryShared::dictionary_entry_size();
} else {
return sizeof(DictionaryEntry);
}
}
Dictionary::Dictionary(int table_size)
: TwoOopHashtable<Klass*, mtClass>(table_size, (int)entry_size()) {
_current_class_index = 0;
_current_class_entry = NULL;
_pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize);
};
Dictionary::Dictionary(int table_size, HashtableBucket<mtClass>* t,
int number_of_entries)
: TwoOopHashtable<Klass*, mtClass>(table_size, (int)entry_size(), t, number_of_entries) {
_current_class_index = 0;
_current_class_entry = NULL;
_pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize);
};
ProtectionDomainCacheEntry* Dictionary::cache_get(oop protection_domain) {
return _pd_cache_table->get(protection_domain);
}
DictionaryEntry* Dictionary::new_entry(unsigned int hash, Klass* klass,
ClassLoaderData* loader_data) {
DictionaryEntry* entry = (DictionaryEntry*)Hashtable<Klass*, mtClass>::new_entry(hash, klass);
entry->set_loader_data(loader_data);
entry->set_pd_set(NULL);
assert(klass->oop_is_instance(), "Must be");
if (DumpSharedSpaces) {
SystemDictionaryShared::init_shared_dictionary_entry(klass, entry);
}
return entry;
}
void Dictionary::free_entry(DictionaryEntry* entry) {
while (entry->pd_set() != NULL) {
ProtectionDomainEntry* to_delete = entry->pd_set();
entry->set_pd_set(to_delete->next());
delete to_delete;
}
Hashtable<Klass*, mtClass>::free_entry(entry);
}
bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
#ifdef ASSERT
if (protection_domain == InstanceKlass::cast(klass())->protection_domain()) {
bool in_pd_set = false;
for (ProtectionDomainEntry* current = _pd_set;
current != NULL;
current = current->next()) {
if (current->protection_domain() == protection_domain) {
in_pd_set = true;
break;
}
}
if (in_pd_set) {
assert(false, "A klass's protection domain should not show up "
"in its sys. dict. PD set");
}
}
#endif /* ASSERT */
if (protection_domain == InstanceKlass::cast(klass())->protection_domain()) {
return true;
}
for (ProtectionDomainEntry* current = _pd_set;
current != NULL;
current = current->next()) {
if (current->protection_domain() == protection_domain) return true;
}
return false;
}
void DictionaryEntry::add_protection_domain(Dictionary* dict, oop protection_domain) {
assert_locked_or_safepoint(SystemDictionary_lock);
if (!contains_protection_domain(protection_domain)) {
ProtectionDomainCacheEntry* entry = dict->cache_get(protection_domain);
ProtectionDomainEntry* new_head =
new ProtectionDomainEntry(entry, _pd_set);
OrderAccess::release_store_ptr(&_pd_set, new_head);
}
if (TraceProtectionDomainVerification && WizardMode) {
print();
}
}
void Dictionary::do_unloading() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
DictionaryEntry* probe = NULL;
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
probe = *p;
Klass* e = probe->klass();
ClassLoaderData* loader_data = probe->loader_data();
InstanceKlass* ik = InstanceKlass::cast(e);
if (!is_strongly_reachable(loader_data, e)) {
assert(!loader_data->is_the_null_class_loader_data(), "unloading entry with null class loader");
if (loader_data->is_unloading()) {
if (probe == _current_class_entry) {
_current_class_entry = NULL;
}
free_entry(probe);
continue;
}
}
p = probe->next_addr();
}
}
}
void Dictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) {
if (strong == weak) {
oops_do(strong);
return;
}
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry *probe = bucket(index);
probe != NULL;
probe = probe->next()) {
Klass* e = probe->klass();
ClassLoaderData* loader_data = probe->loader_data();
if (is_strongly_reachable(loader_data, e)) {
probe->set_strongly_reachable();
}
}
}
_pd_cache_table->roots_oops_do(strong, weak);
}
void Dictionary::remove_classes_in_error_state() {
assert(DumpSharedSpaces, "supported only when dumping");
DictionaryEntry* probe = NULL;
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
probe = *p;
InstanceKlass* ik = InstanceKlass::cast(probe->klass());
if (ik->is_in_error_state()) { // purge this entry
if (probe == _current_class_entry) {
_current_class_entry = NULL;
}
free_entry(probe);
ResourceMark rm;
tty->print_cr("Preload Warning: Removed error class: %s", ik->external_name());
continue;
}
p = probe->next_addr();
}
}
}
void Dictionary::always_strong_oops_do(OopClosure* blk) {
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry *probe = bucket(index);
probe != NULL;
probe = probe->next()) {
Klass* e = probe->klass();
ClassLoaderData* loader_data = probe->loader_data();
if (is_strongly_reachable(loader_data, e)) {
probe->set_strongly_reachable();
}
}
}
_pd_cache_table->always_strong_oops_do(blk);
}
void Dictionary::always_strong_classes_do(KlassClosure* closure) {
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
Klass* e = probe->klass();
ClassLoaderData* loader_data = probe->loader_data();
if (is_strongly_reachable(loader_data, e)) {
closure->do_klass(e);
}
}
}
}
void Dictionary::classes_do(void f(Klass*)) {
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
Klass* k = probe->klass();
if (probe->loader_data() == InstanceKlass::cast(k)->class_loader_data()) {
f(k);
}
}
}
}
void Dictionary::classes_do(void f(Klass*, TRAPS), TRAPS) {
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
Klass* k = probe->klass();
if (probe->loader_data() == InstanceKlass::cast(k)->class_loader_data()) {
f(k, CHECK);
}
}
}
}
void Dictionary::classes_do(void f(Klass*, ClassLoaderData*)) {
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
Klass* k = probe->klass();
f(k, probe->loader_data());
}
}
}
void Dictionary::oops_do(OopClosure* f) {
_pd_cache_table->oops_do(f);
}
void Dictionary::methods_do(void f(Method*)) {
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
Klass* k = probe->klass();
if (probe->loader_data() == InstanceKlass::cast(k)->class_loader_data()) {
InstanceKlass::cast(k)->methods_do(f);
}
}
}
}
void Dictionary::unlink(BoolObjectClosure* is_alive) {
_pd_cache_table->unlink(is_alive);
}
Klass* Dictionary::try_get_next_class() {
while (true) {
if (_current_class_entry != NULL) {
Klass* k = _current_class_entry->klass();
_current_class_entry = _current_class_entry->next();
return k;
}
_current_class_index = (_current_class_index + 1) % table_size();
_current_class_entry = bucket(_current_class_index);
}
}
void Dictionary::add_klass(Symbol* class_name, ClassLoaderData* loader_data,
KlassHandle obj) {
assert_locked_or_safepoint(SystemDictionary_lock);
assert(obj() != NULL, "adding NULL obj");
assert(obj()->name() == class_name, "sanity check on name");
assert(loader_data != NULL, "Must be non-NULL");
unsigned int hash = compute_hash(class_name, loader_data);
int index = hash_to_index(hash);
DictionaryEntry* entry = new_entry(hash, obj(), loader_data);
add_entry(index, entry);
}
DictionaryEntry* Dictionary::get_entry(int index, unsigned int hash,
Symbol* class_name,
ClassLoaderData* loader_data) {
debug_only(_lookup_count++);
for (DictionaryEntry* entry = bucket(index);
entry != NULL;
entry = entry->next()) {
if (entry->hash() == hash && entry->equals(class_name, loader_data)) {
return entry;
}
debug_only(_lookup_length++);
}
return NULL;
}
Klass* Dictionary::find(int index, unsigned int hash, Symbol* name,
ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
DictionaryEntry* entry = get_entry(index, hash, name, loader_data);
if (entry != NULL && entry->is_valid_protection_domain(protection_domain)) {
return entry->klass();
} else {
return NULL;
}
}
Klass* Dictionary::find_class(int index, unsigned int hash,
Symbol* name, ClassLoaderData* loader_data) {
assert_locked_or_safepoint(SystemDictionary_lock);
assert (index == index_for(name, loader_data), "incorrect index?");
DictionaryEntry* entry = get_entry(index, hash, name, loader_data);
return (entry != NULL) ? entry->klass() : (Klass*)NULL;
}
Klass* Dictionary::find_shared_class(int index, unsigned int hash,
Symbol* name) {
assert (index == index_for(name, NULL), "incorrect index?");
DictionaryEntry* entry = get_entry(index, hash, name, NULL);
return (entry != NULL) ? entry->klass() : (Klass*)NULL;
}
void Dictionary::add_protection_domain(int index, unsigned int hash,
instanceKlassHandle klass,
ClassLoaderData* loader_data, Handle protection_domain,
TRAPS) {
Symbol* klass_name = klass->name();
DictionaryEntry* entry = get_entry(index, hash, klass_name, loader_data);
assert(entry != NULL,"entry must be present, we just created it");
assert(protection_domain() != NULL,
"real protection domain should be present");
entry->add_protection_domain(this, protection_domain());
assert(entry->contains_protection_domain(protection_domain()),
"now protection domain should be present");
}
bool Dictionary::is_valid_protection_domain(int index, unsigned int hash,
Symbol* name,
ClassLoaderData* loader_data,
Handle protection_domain) {
DictionaryEntry* entry = get_entry(index, hash, name, loader_data);
return entry->is_valid_protection_domain(protection_domain);
}
void Dictionary::reorder_dictionary() {
DictionaryEntry* master_list = NULL;
for (int i = 0; i < table_size(); ++i) {
DictionaryEntry* p = bucket(i);
while (p != NULL) {
DictionaryEntry* tmp;
tmp = p->next();
p->set_next(master_list);
master_list = p;
p = tmp;
}
set_entry(i, NULL);
}
while (master_list != NULL) {
DictionaryEntry* p = master_list;
master_list = master_list->next();
p->set_next(NULL);
Symbol* class_name = InstanceKlass::cast((Klass*)(p->klass()))->name();
unsigned int hash = compute_hash(class_name, NULL);
int index = hash_to_index(hash);
p->set_hash(hash);
p->set_loader_data(NULL); // loader_data isn't copied to CDS
p->set_next(bucket(index));
set_entry(index, p);
}
}
ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size)
: Hashtable<oop, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry))
{
}
void ProtectionDomainCacheTable::unlink(BoolObjectClosure* is_alive) {
assert(SafepointSynchronize::is_at_safepoint(), "must be");
for (int i = 0; i < table_size(); ++i) {
ProtectionDomainCacheEntry** p = bucket_addr(i);
ProtectionDomainCacheEntry* entry = bucket(i);
while (entry != NULL) {
if (is_alive->do_object_b(entry->literal())) {
p = entry->next_addr();
} else {
free_entry(entry);
}
entry = *p;
}
}
}
void ProtectionDomainCacheTable::oops_do(OopClosure* f) {
for (int index = 0; index < table_size(); index++) {
for (ProtectionDomainCacheEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
probe->oops_do(f);
}
}
}
void ProtectionDomainCacheTable::roots_oops_do(OopClosure* strong, OopClosure* weak) {
for (int index = 0; index < table_size(); index++) {
for (ProtectionDomainCacheEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
if (probe->is_strongly_reachable()) {
probe->reset_strongly_reachable();
probe->oops_do(strong);
} else {
if (weak != NULL) {
probe->oops_do(weak);
}
}
}
}
}
uint ProtectionDomainCacheTable::bucket_size() {
return sizeof(ProtectionDomainCacheEntry);
}
#ifndef PRODUCT
void ProtectionDomainCacheTable::print() {
tty->print_cr("Protection domain cache table (table_size=%d, classes=%d)",
table_size(), number_of_entries());
for (int index = 0; index < table_size(); index++) {
for (ProtectionDomainCacheEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
probe->print();
}
}
}
void ProtectionDomainCacheEntry::print() {
tty->print_cr("entry " PTR_FORMAT " value " PTR_FORMAT " strongly_reachable %d next " PTR_FORMAT,
this, (void*)literal(), _strongly_reachable, next());
}
#endif
void ProtectionDomainCacheTable::verify() {
int element_count = 0;
for (int index = 0; index < table_size(); index++) {
for (ProtectionDomainCacheEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
probe->verify();
element_count++;
}
}
guarantee(number_of_entries() == element_count,
"Verify of protection domain cache table failed");
debug_only(verify_lookup_length((double)number_of_entries() / table_size()));
}
void ProtectionDomainCacheEntry::verify() {
guarantee(literal()->is_oop(), "must be an oop");
}
void ProtectionDomainCacheTable::always_strong_oops_do(OopClosure* f) {
for (int index = 0; index < table_size(); index++) {
for (ProtectionDomainCacheEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
if (probe->is_strongly_reachable()) {
probe->reset_strongly_reachable();
probe->oops_do(f);
}
}
}
}
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(oop protection_domain) {
unsigned int hash = compute_hash(protection_domain);
int index = hash_to_index(hash);
ProtectionDomainCacheEntry* entry = find_entry(index, protection_domain);
if (entry == NULL) {
entry = add_entry(index, hash, protection_domain);
}
return entry;
}
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::find_entry(int index, oop protection_domain) {
for (ProtectionDomainCacheEntry* e = bucket(index); e != NULL; e = e->next()) {
if (e->protection_domain() == protection_domain) {
return e;
}
}
return NULL;
}
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, unsigned int hash, oop protection_domain) {
assert_locked_or_safepoint(SystemDictionary_lock);
assert(index == index_for(protection_domain), "incorrect index?");
assert(find_entry(index, protection_domain) == NULL, "no double entry");
ProtectionDomainCacheEntry* p = new_entry(hash, protection_domain);
Hashtable<oop, mtClass>::add_entry(index, p);
return p;
}
void ProtectionDomainCacheTable::free(ProtectionDomainCacheEntry* to_delete) {
unsigned int hash = compute_hash(to_delete->protection_domain());
int index = hash_to_index(hash);
ProtectionDomainCacheEntry** p = bucket_addr(index);
ProtectionDomainCacheEntry* entry = bucket(index);
while (true) {
assert(entry != NULL, "sanity");
if (entry == to_delete) {
Hashtable<oop, mtClass>::free_entry(entry);
break;
} else {
p = entry->next_addr();
entry = *p;
}
}
}
SymbolPropertyTable::SymbolPropertyTable(int table_size)
: Hashtable<Symbol*, mtSymbol>(table_size, sizeof(SymbolPropertyEntry))
{
}
SymbolPropertyTable::SymbolPropertyTable(int table_size, HashtableBucket<mtSymbol>* t,
int number_of_entries)
: Hashtable<Symbol*, mtSymbol>(table_size, sizeof(SymbolPropertyEntry), t, number_of_entries)
{
}
SymbolPropertyEntry* SymbolPropertyTable::find_entry(int index, unsigned int hash,
Symbol* sym,
intptr_t sym_mode) {
assert(index == index_for(sym, sym_mode), "incorrect index?");
for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
if (p->hash() == hash && p->symbol() == sym && p->symbol_mode() == sym_mode) {
return p;
}
}
return NULL;
}
SymbolPropertyEntry* SymbolPropertyTable::add_entry(int index, unsigned int hash,
Symbol* sym, intptr_t sym_mode) {
assert_locked_or_safepoint(SystemDictionary_lock);
assert(index == index_for(sym, sym_mode), "incorrect index?");
assert(find_entry(index, hash, sym, sym_mode) == NULL, "no double entry");
SymbolPropertyEntry* p = new_entry(hash, sym, sym_mode);
Hashtable<Symbol*, mtSymbol>::add_entry(index, p);
return p;
}
void SymbolPropertyTable::oops_do(OopClosure* f) {
for (int index = 0; index < table_size(); index++) {
for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
if (p->method_type() != NULL) {
f->do_oop(p->method_type_addr());
}
}
}
}
void SymbolPropertyTable::methods_do(void f(Method*)) {
for (int index = 0; index < table_size(); index++) {
for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
Method* prop = p->method();
if (prop != NULL) {
f((Method*)prop);
}
}
}
}
void Dictionary::print(bool details) {
ResourceMark rm;
HandleMark hm;
if (details) {
tty->print_cr("Java system dictionary (table_size=%d, classes=%d)",
table_size(), number_of_entries());
tty->print_cr("^ indicates that initiating loader is different from "
"defining loader");
}
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
if (Verbose) tty->print("%4d: ", index);
Klass* e = probe->klass();
ClassLoaderData* loader_data = probe->loader_data();
bool is_defining_class =
(loader_data == InstanceKlass::cast(e)->class_loader_data());
tty->print("%s%s", ((!details) || is_defining_class) ? " " : "^",
e->external_name());
if (details) {
tty->print(", loader ");
if (loader_data != NULL) {
loader_data->print_value();
} else {
tty->print("NULL");
}
}
tty->cr();
}
}
if (details) {
tty->cr();
_pd_cache_table->print();
}
tty->cr();
}
void Dictionary::verify() {
guarantee(number_of_entries() >= 0, "Verify of system dictionary failed");
int element_count = 0;
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
Klass* e = probe->klass();
ClassLoaderData* loader_data = probe->loader_data();
guarantee(e->oop_is_instance(),
"Verify of system dictionary failed");
guarantee(loader_data != NULL || DumpSharedSpaces ||
loader_data->class_loader() == NULL ||
loader_data->class_loader()->is_instance(),
"checking type of class_loader");
e->verify();
probe->verify_protection_domain_set();
element_count++;
}
}
guarantee(number_of_entries() == element_count,
"Verify of system dictionary failed");
debug_only(verify_lookup_length((double)number_of_entries() / table_size()));
_pd_cache_table->verify();
}
C:\hotspot-69087d08d473\src\share\vm/classfile/dictionary.hpp
#ifndef SHARE_VM_CLASSFILE_DICTIONARY_HPP
#define SHARE_VM_CLASSFILE_DICTIONARY_HPP
#include "classfile/systemDictionary.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/oop.inline.hpp"
#include "utilities/hashtable.hpp"
class DictionaryEntry;
class PSPromotionManager;
class ProtectionDomainCacheTable;
class ProtectionDomainCacheEntry;
class BoolObjectClosure;
class Dictionary : public TwoOopHashtable<Klass*, mtClass> {
friend class VMStructs;
private:
static int _current_class_index;
static DictionaryEntry* _current_class_entry;
ProtectionDomainCacheTable* _pd_cache_table;
DictionaryEntry* get_entry(int index, unsigned int hash,
Symbol* name, ClassLoaderData* loader_data);
protected:
DictionaryEntry* bucket(int i) {
return (DictionaryEntry*)Hashtable<Klass*, mtClass>::bucket(i);
}
DictionaryEntry** bucket_addr(int i) {
return (DictionaryEntry**)Hashtable<Klass*, mtClass>::bucket_addr(i);
}
void add_entry(int index, DictionaryEntry* new_entry) {
Hashtable<Klass*, mtClass>::add_entry(index, (HashtableEntry<Klass*, mtClass>*)new_entry);
}
static size_t entry_size();
public:
Dictionary(int table_size);
Dictionary(int table_size, HashtableBucket<mtClass>* t, int number_of_entries);
DictionaryEntry* new_entry(unsigned int hash, Klass* klass, ClassLoaderData* loader_data);
DictionaryEntry* new_entry();
void free_entry(DictionaryEntry* entry);
void add_klass(Symbol* class_name, ClassLoaderData* loader_data,KlassHandle obj);
Klass* find_class(int index, unsigned int hash,
Symbol* name, ClassLoaderData* loader_data);
Klass* find_shared_class(int index, unsigned int hash, Symbol* name);
Klass* try_get_next_class();
void oops_do(OopClosure* f);
void always_strong_oops_do(OopClosure* blk);
void roots_oops_do(OopClosure* strong, OopClosure* weak);
void always_strong_classes_do(KlassClosure* closure);
void classes_do(void f(Klass*));
void classes_do(void f(Klass*, TRAPS), TRAPS);
void classes_do(void f(Klass*, ClassLoaderData*));
void methods_do(void f(Method*));
void unlink(BoolObjectClosure* is_alive);
void remove_classes_in_error_state();
static bool is_strongly_reachable(ClassLoaderData* loader_data, Klass* klass) {
assert (klass != NULL, "should have non-null klass");
return (loader_data->is_the_null_class_loader_data() || !ClassUnloading);
}
void do_unloading();
Klass* find(int index, unsigned int hash, Symbol* name,
ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
bool is_valid_protection_domain(int index, unsigned int hash,
Symbol* name, ClassLoaderData* loader_data,
Handle protection_domain);
void add_protection_domain(int index, unsigned int hash,
instanceKlassHandle klass, ClassLoaderData* loader_data,
Handle protection_domain, TRAPS);
void reorder_dictionary();
ProtectionDomainCacheEntry* cache_get(oop protection_domain);
void print(bool details = true);
void verify();
};
class ProtectionDomainCacheEntry : public HashtableEntry<oop, mtClass> {
friend class VMStructs;
private:
bool _strongly_reachable;
public:
oop protection_domain() { return literal(); }
void init() {
_strongly_reachable = false;
}
ProtectionDomainCacheEntry* next() {
return (ProtectionDomainCacheEntry*)HashtableEntry<oop, mtClass>::next();
}
ProtectionDomainCacheEntry** next_addr() {
return (ProtectionDomainCacheEntry**)HashtableEntry<oop, mtClass>::next_addr();
}
void oops_do(OopClosure* f) {
f->do_oop(literal_addr());
}
void set_strongly_reachable() { _strongly_reachable = true; }
bool is_strongly_reachable() { return _strongly_reachable; }
void reset_strongly_reachable() { _strongly_reachable = false; }
void print() PRODUCT_RETURN;
void verify();
};
class ProtectionDomainCacheTable : public Hashtable<oop, mtClass> {
friend class VMStructs;
private:
ProtectionDomainCacheEntry* bucket(int i) {
return (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::bucket(i);
}
ProtectionDomainCacheEntry** bucket_addr(int i) {
return (ProtectionDomainCacheEntry**) Hashtable<oop, mtClass>::bucket_addr(i);
}
ProtectionDomainCacheEntry* new_entry(unsigned int hash, oop protection_domain) {
ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::new_entry(hash, protection_domain);
entry->init();
return entry;
}
static unsigned int compute_hash(oop protection_domain) {
return (unsigned int)(protection_domain->identity_hash());
}
int index_for(oop protection_domain) {
return hash_to_index(compute_hash(protection_domain));
}
ProtectionDomainCacheEntry* add_entry(int index, unsigned int hash, oop protection_domain);
ProtectionDomainCacheEntry* find_entry(int index, oop protection_domain);
public:
ProtectionDomainCacheTable(int table_size);
ProtectionDomainCacheEntry* get(oop protection_domain);
void free(ProtectionDomainCacheEntry* entry);
void unlink(BoolObjectClosure* cl);
void oops_do(OopClosure* f);
void always_strong_oops_do(OopClosure* f);
void roots_oops_do(OopClosure* strong, OopClosure* weak);
static uint bucket_size();
void print() PRODUCT_RETURN;
void verify();
};
class ProtectionDomainEntry :public CHeapObj<mtClass> {
friend class VMStructs;
public:
ProtectionDomainEntry* _next;
ProtectionDomainCacheEntry* _pd_cache;
ProtectionDomainEntry(ProtectionDomainCacheEntry* pd_cache, ProtectionDomainEntry* next) {
_pd_cache = pd_cache;
_next = next;
}
ProtectionDomainEntry* next() { return _next; }
oop protection_domain() { return _pd_cache->protection_domain(); }
};
class DictionaryEntry : public HashtableEntry<Klass*, mtClass> {
friend class VMStructs;
private:
ProtectionDomainEntry* _pd_set;
ClassLoaderData* _loader_data;
public:
bool contains_protection_domain(oop protection_domain) const;
void add_protection_domain(Dictionary* dict, oop protection_domain);
Klass* klass() const { return (Klass*)literal(); }
Klass** klass_addr() { return (Klass**)literal_addr(); }
DictionaryEntry* next() const {
return (DictionaryEntry*)HashtableEntry<Klass*, mtClass>::next();
}
DictionaryEntry** next_addr() {
return (DictionaryEntry**)HashtableEntry<Klass*, mtClass>::next_addr();
}
ClassLoaderData* loader_data() const { return _loader_data; }
void set_loader_data(ClassLoaderData* loader_data) { _loader_data = loader_data; }
ProtectionDomainEntry* pd_set() const { return _pd_set; }
void set_pd_set(ProtectionDomainEntry* pd_set) { _pd_set = pd_set; }
bool has_protection_domain() { return _pd_set != NULL; }
bool is_valid_protection_domain(Handle protection_domain) {
if (!ProtectionDomainVerification) return true;
if (!SystemDictionary::has_checkPackageAccess()) return true;
return protection_domain() == NULL
? true
: contains_protection_domain(protection_domain());
}
void set_strongly_reachable() {
for (ProtectionDomainEntry* current = _pd_set;
current != NULL;
current = current->_next) {
current->_pd_cache->set_strongly_reachable();
}
}
void verify_protection_domain_set() {
for (ProtectionDomainEntry* current = _pd_set;
current != NULL;
current = current->_next) {
current->_pd_cache->protection_domain()->verify();
}
}
bool equals(Symbol* class_name, ClassLoaderData* loader_data) const {
Klass* klass = (Klass*)literal();
return (InstanceKlass::cast(klass)->name() == class_name &&
_loader_data == loader_data);
}
void print() {
int count = 0;
for (ProtectionDomainEntry* current = _pd_set;
current != NULL;
current = current->_next) {
count++;
}
tty->print_cr("pd set = #%d", count);
}
};
class SymbolPropertyEntry : public HashtableEntry<Symbol*, mtSymbol> {
friend class VMStructs;
private:
intptr_t _symbol_mode; // secondary key
Method* _method;
oop _method_type;
public:
Symbol* symbol() const { return literal(); }
intptr_t symbol_mode() const { return _symbol_mode; }
void set_symbol_mode(intptr_t m) { _symbol_mode = m; }
Method* method() const { return _method; }
void set_method(Method* p) { _method = p; }
oop method_type() const { return _method_type; }
oop* method_type_addr() { return &_method_type; }
void set_method_type(oop p) { _method_type = p; }
SymbolPropertyEntry* next() const {
return (SymbolPropertyEntry*)HashtableEntry<Symbol*, mtSymbol>::next();
}
SymbolPropertyEntry** next_addr() {
return (SymbolPropertyEntry**)HashtableEntry<Symbol*, mtSymbol>::next_addr();
}
void print_on(outputStream* st) const {
symbol()->print_value_on(st);
st->print("/mode=" INTX_FORMAT, symbol_mode());
st->print(" -> ");
bool printed = false;
if (method() != NULL) {
method()->print_value_on(st);
printed = true;
}
if (method_type() != NULL) {
if (printed) st->print(" and ");
st->print(INTPTR_FORMAT, p2i((void *)method_type()));
printed = true;
}
st->print_cr(printed ? "" : "(empty)");
}
};
class SymbolPropertyTable : public Hashtable<Symbol*, mtSymbol> {
friend class VMStructs;
private:
SymbolPropertyEntry* bucket(int i) {
return (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::bucket(i);
}
SymbolPropertyEntry** bucket_addr(int i) {
return (SymbolPropertyEntry**) Hashtable<Symbol*, mtSymbol>::bucket_addr(i);
}
void add_entry(int index, SymbolPropertyEntry* new_entry) {
ShouldNotReachHere();
}
void set_entry(int index, SymbolPropertyEntry* new_entry) {
ShouldNotReachHere();
}
SymbolPropertyEntry* new_entry(unsigned int hash, Symbol* symbol, intptr_t symbol_mode) {
SymbolPropertyEntry* entry = (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::new_entry(hash, symbol);
symbol->increment_refcount();
entry->set_symbol_mode(symbol_mode);
entry->set_method(NULL);
entry->set_method_type(NULL);
return entry;
}
public:
SymbolPropertyTable(int table_size);
SymbolPropertyTable(int table_size, HashtableBucket<mtSymbol>* t, int number_of_entries);
void free_entry(SymbolPropertyEntry* entry) {
entry->literal()->decrement_refcount();
Hashtable<Symbol*, mtSymbol>::free_entry(entry);
}
unsigned int compute_hash(Symbol* sym, intptr_t symbol_mode) {
return Hashtable<Symbol*, mtSymbol>::compute_hash(sym) ^ symbol_mode;
}
int index_for(Symbol* name, intptr_t symbol_mode) {
return hash_to_index(compute_hash(name, symbol_mode));
}
SymbolPropertyEntry* find_entry(int index, unsigned int hash, Symbol* name, intptr_t name_mode);
SymbolPropertyEntry* add_entry(int index, unsigned int hash, Symbol* name, intptr_t name_mode);
void oops_do(OopClosure* f);
void methods_do(void f(Method*));
void reorder_dictionary();
#ifndef PRODUCT
void print();
#endif
void verify();
};
#endif // SHARE_VM_CLASSFILE_DICTIONARY_HPP
C:\hotspot-69087d08d473\src\share\vm/classfile/javaAssertions.cpp
#include "precompiled.hpp"
#include "classfile/javaAssertions.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/handles.inline.hpp"
bool JavaAssertions::_userDefault = false;
bool JavaAssertions::_sysDefault = false;
JavaAssertions::OptionList* JavaAssertions::_classes = 0;
JavaAssertions::OptionList* JavaAssertions::_packages = 0;
JavaAssertions::OptionList::OptionList(const char* name, bool enabled,
OptionList* next) {
assert(name != 0, "need a name");
_name = name;
_enabled = enabled;
_next = next;
}
int JavaAssertions::OptionList::count(OptionList* p) {
int rc;
for (rc = 0; p != 0; p = p->next(), ++rc) /* empty */;
return rc;
}
void JavaAssertions::addOption(const char* name, bool enable) {
assert(name != 0, "must have a name");
int len = (int)strlen(name);
char *name_copy = NEW_C_HEAP_ARRAY(char, len + 1, mtClass);
strcpy(name_copy, name);
OptionList** head = &_classes;
if (len >= 3 && strcmp(name_copy + len - 3, "...") == 0) {
len -= 3;
name_copy[len] = '\0';
head = &_packages;
}
for (int i = 0; i < len; ++i) {
if (name_copy[i] == '.') name_copy[i] = '/';
}
if (TraceJavaAssertions) {
tty->print_cr("JavaAssertions: adding %s %s=%d",
head == &_classes ? "class" : "package",
name_copy[0] != '\0' ? name_copy : "'default'",
enable);
}
}
oop JavaAssertions::createAssertionStatusDirectives(TRAPS) {
Symbol* asd_sym = vmSymbols::java_lang_AssertionStatusDirectives();
Klass* k = SystemDictionary::resolve_or_fail(asd_sym, true, CHECK_NULL);
instanceKlassHandle asd_klass (THREAD, k);
asd_klass->initialize(CHECK_NULL);
Handle h = asd_klass->allocate_instance_handle(CHECK_NULL);
int len;
typeArrayOop t;
len = OptionList::count(_packages);
objArrayOop pn = oopFactory::new_objArray(SystemDictionary::String_klass(), len, CHECK_NULL);
objArrayHandle pkgNames (THREAD, pn);
t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL);
typeArrayHandle pkgEnabled(THREAD, t);
fillJavaArrays(_packages, len, pkgNames, pkgEnabled, CHECK_NULL);
len = OptionList::count(_classes);
objArrayOop cn = oopFactory::new_objArray(SystemDictionary::String_klass(), len, CHECK_NULL);
objArrayHandle classNames (THREAD, cn);
t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL);
typeArrayHandle classEnabled(THREAD, t);
fillJavaArrays(_classes, len, classNames, classEnabled, CHECK_NULL);
java_lang_AssertionStatusDirectives::set_packages(h(), pkgNames());
java_lang_AssertionStatusDirectives::set_packageEnabled(h(), pkgEnabled());
java_lang_AssertionStatusDirectives::set_classes(h(), classNames());
java_lang_AssertionStatusDirectives::set_classEnabled(h(), classEnabled());
java_lang_AssertionStatusDirectives::set_deflt(h(), userClassDefault());
return h();
}
void JavaAssertions::fillJavaArrays(const OptionList* p, int len,
objArrayHandle names, typeArrayHandle enabled, TRAPS) {
int index;
for (index = len - 1; p != 0; p = p->next(), --index) {
assert(index >= 0, "length does not match list");
Handle s = java_lang_String::create_from_str(p->name(), CHECK);
s = java_lang_String::char_converter(s, '/', '.', CHECK);
names->obj_at_put(index, s());
enabled->bool_at_put(index, p->enabled());
}
assert(index == -1, "length does not match list");
}
inline JavaAssertions::OptionList*
JavaAssertions::match_class(const char* classname) {
for (OptionList* p = _classes; p != 0; p = p->next()) {
if (strcmp(p->name(), classname) == 0) {
return p;
}
}
return 0;
}
JavaAssertions::OptionList*
JavaAssertions::match_package(const char* classname) {
if (_packages == 0) return 0;
size_t len = strlen(classname);
for (/* empty */; len > 0 && classname[len] != '/'; --len) /* empty */;
do {
assert(len == 0 || classname[len] == '/', "not a package name");
for (OptionList* p = _packages; p != 0; p = p->next()) {
if (strncmp(p->name(), classname, len) == 0 && p->name()[len] == '\0') {
return p;
}
}
while (len > 0 && classname[--len] != '/') /* empty */;
} while (len > 0);
return 0;
}
inline void JavaAssertions::trace(const char* name,
const char* typefound, const char* namefound, bool enabled) {
if (TraceJavaAssertions) {
tty->print_cr("JavaAssertions: search for %s found %s %s=%d",
name, typefound, namefound[0] != '\0' ? namefound : "'default'", enabled);
}
}
bool JavaAssertions::enabled(const char* classname, bool systemClass) {
assert(classname != 0, "must have a classname");
OptionList* p;
if (p = match_class(classname)) {
trace(classname, "class", p->name(), p->enabled());
return p->enabled();
}
if (p = match_package(classname)) {
trace(classname, "package", p->name(), p->enabled());
return p->enabled();
}
bool result = systemClass ? systemClassDefault() : userClassDefault();
trace(classname, systemClass ? "system" : "user", "default", result);
return result;
}
C:\hotspot-69087d08d473\src\share\vm/classfile/javaAssertions.hpp
#ifndef SHARE_VM_CLASSFILE_JAVAASSERTIONS_HPP
#define SHARE_VM_CLASSFILE_JAVAASSERTIONS_HPP
#include "oops/objArrayOop.hpp"
#include "oops/typeArrayOop.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/ostream.hpp"
class JavaAssertions: AllStatic {
public:
static inline bool userClassDefault();
static inline void setUserClassDefault(bool enabled);
static inline bool systemClassDefault();
static inline void setSystemClassDefault(bool enabled);
static void addOption(const char* name, bool enable);
static bool enabled(const char* classname, bool systemClass);
static oop createAssertionStatusDirectives(TRAPS);
private:
class OptionList;
static void fillJavaArrays(const OptionList* p, int len, objArrayHandle names,
typeArrayHandle status, TRAPS);
static inline void trace(const char* name, const char* typefound,
const char* namefound, bool enabled);
static inline OptionList* match_class(const char* classname);
static OptionList* match_package(const char* classname);
static bool _userDefault; // User class default (-ea/-da).
static bool _sysDefault; // System class default (-esa/-dsa).
static OptionList* _classes; // Options for classes.
static OptionList* _packages; // Options for package trees.
};
class JavaAssertions::OptionList: public CHeapObj<mtClass> {
public:
inline OptionList(const char* name, bool enable, OptionList* next);
inline const char* name() const { return _name; }
inline bool enabled() const { return _enabled; }
inline OptionList* next() const { return _next; }
static int count(OptionList* p);
private:
const char* _name;
OptionList* _next;
bool _enabled;
};
inline bool JavaAssertions::userClassDefault() {
return _userDefault;
}
inline void JavaAssertions::setUserClassDefault(bool enabled) {
if (TraceJavaAssertions)
tty->print_cr("JavaAssertions::setUserClassDefault(%d)", enabled);
_userDefault = enabled;
}
inline bool JavaAssertions::systemClassDefault() {
return _sysDefault;
}
inline void JavaAssertions::setSystemClassDefault(bool enabled) {
if (TraceJavaAssertions)
tty->print_cr("JavaAssertions::setSystemClassDefault(%d)", enabled);
_sysDefault = enabled;
}
#endif // SHARE_VM_CLASSFILE_JAVAASSERTIONS_HPP
C:\hotspot-69087d08d473\src\share\vm/classfile/javaClasses.cpp
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/debugInfo.hpp"
#include "code/pcDesc.hpp"
#include "compiler/compilerOracle.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.inline.hpp"
#include "oops/fieldStreams.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "oops/klass.hpp"
#include "oops/method.hpp"
#include "oops/symbol.hpp"
#include "oops/typeArrayOop.hpp"
#include "prims/jvmtiRedefineClassesTrace.hpp"
#include "runtime/fieldDescriptor.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/vframe.hpp"
#include "utilities/preserveException.hpp"
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
#define INJECTED_FIELD_COMPUTE_OFFSET(klass, name, signature, may_be_java) \
klass::_##name##_offset = JavaClasses::compute_injected_offset(JavaClasses::klass##_##name##_enum);
#define DECLARE_INJECTED_FIELD(klass, name, signature, may_be_java) \
{ SystemDictionary::WK_KLASS_ENUM_NAME(klass), vmSymbols::VM_SYMBOL_ENUM_NAME(name##_name), vmSymbols::VM_SYMBOL_ENUM_NAME(signature), may_be_java },
InjectedField JavaClasses::_injected_fields[] = {
ALL_INJECTED_FIELDS(DECLARE_INJECTED_FIELD)
};
int JavaClasses::compute_injected_offset(InjectedFieldID id) {
return _injected_fields[id].compute_offset();
}
InjectedField* JavaClasses::get_injected(Symbol* class_name, int* field_count) {
vmSymbols::SID sid = vmSymbols::find_sid(class_name);
if (sid == vmSymbols::NO_SID) {
return NULL;
}
int count = 0;
int start = -1;
#define LOOKUP_INJECTED_FIELD(klass, name, signature, may_be_java) \
if (sid == vmSymbols::VM_SYMBOL_ENUM_NAME(klass)) { \
count++; \
if (start == -1) start = klass##_##name##_enum; \
}
ALL_INJECTED_FIELDS(LOOKUP_INJECTED_FIELD);
#undef LOOKUP_INJECTED_FIELD
if (start != -1) {
return _injected_fields + start;
}
return NULL;
}
static bool find_field(InstanceKlass* ik,
Symbol* name_symbol, Symbol* signature_symbol,
fieldDescriptor* fd,
bool allow_super = false) {
if (allow_super)
return ik->find_field(name_symbol, signature_symbol, fd) != NULL;
else
return ik->find_local_field(name_symbol, signature_symbol, fd);
}
static void
compute_offset(int &dest_offset,
Klass* klass_oop, Symbol* name_symbol, Symbol* signature_symbol,
bool allow_super = false) {
fieldDescriptor fd;
InstanceKlass* ik = InstanceKlass::cast(klass_oop);
if (!find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) {
ResourceMark rm;
tty->print_cr("Invalid layout of %s at %s", ik->external_name(), name_symbol->as_C_string());
#ifndef PRODUCT
klass_oop->print();
tty->print_cr("all fields:");
for (AllFieldStream fs(InstanceKlass::cast(klass_oop)); !fs.done(); fs.next()) {
tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int());
}
#endif //PRODUCT
vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class");
}
dest_offset = fd.offset();
}
static void
compute_optional_offset(int& dest_offset,
Klass* klass_oop, Symbol* name_symbol, Symbol* signature_symbol,
bool allow_super = false) {
fieldDescriptor fd;
InstanceKlass* ik = InstanceKlass::cast(klass_oop);
if (find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) {
dest_offset = fd.offset();
}
}
int java_lang_String::value_offset = 0;
int java_lang_String::offset_offset = 0;
int java_lang_String::count_offset = 0;
int java_lang_String::hash_offset = 0;
bool java_lang_String::initialized = false;
void java_lang_String::compute_offsets() {
assert(!initialized, "offsets should be initialized only once");
Klass* k = SystemDictionary::String_klass();
compute_offset(value_offset, k, vmSymbols::value_name(), vmSymbols::char_array_signature());
compute_optional_offset(offset_offset, k, vmSymbols::offset_name(), vmSymbols::int_signature());
compute_optional_offset(count_offset, k, vmSymbols::count_name(), vmSymbols::int_signature());
compute_optional_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature());
initialized = true;
}
Handle java_lang_String::basic_create(int length, TRAPS) {
assert(initialized, "Must be initialized");
oop obj;
obj = InstanceKlass::cast(SystemDictionary::String_klass())->allocate_instance(CHECK_NH);
Handle h_obj(THREAD, obj);
typeArrayOop buffer;
buffer = oopFactory::new_charArray(length, CHECK_NH);
obj = h_obj();
set_value(obj, buffer);
assert(offset(obj) == 0, "initial String offset should be zero");
set_count(obj, length);
return h_obj;
}
Handle java_lang_String::create_from_unicode(jchar* unicode, int length, TRAPS) {
Handle h_obj = basic_create(length, CHECK_NH);
typeArrayOop buffer = value(h_obj());
for (int index = 0; index < length; index++) {
buffer->char_at_put(index, unicode[index]);
}
return h_obj;
}
oop java_lang_String::create_oop_from_unicode(jchar* unicode, int length, TRAPS) {
Handle h_obj = create_from_unicode(unicode, length, CHECK_0);
return h_obj();
}
Handle java_lang_String::create_from_str(const char* utf8_str, TRAPS) {
if (utf8_str == NULL) {
return Handle();
}
int length = UTF8::unicode_length(utf8_str);
Handle h_obj = basic_create(length, CHECK_NH);
if (length > 0) {
UTF8::convert_to_unicode(utf8_str, value(h_obj())->char_at_addr(0), length);
}
return h_obj;
}
oop java_lang_String::create_oop_from_str(const char* utf8_str, TRAPS) {
Handle h_obj = create_from_str(utf8_str, CHECK_0);
return h_obj();
}
Handle java_lang_String::create_from_symbol(Symbol* symbol, TRAPS) {
int length = UTF8::unicode_length((char*)symbol->bytes(), symbol->utf8_length());
Handle h_obj = basic_create(length, CHECK_NH);
if (length > 0) {
UTF8::convert_to_unicode((char*)symbol->bytes(), value(h_obj())->char_at_addr(0), length);
}
return h_obj;
}
Handle java_lang_String::create_from_platform_dependent_str(const char* str, TRAPS) {
assert(str != NULL, "bad arguments");
typedef jstring (*to_java_string_fn_t)(JNIEnv*, const char *);
static to_java_string_fn_t _to_java_string_fn = NULL;
if (_to_java_string_fn == NULL) {
void *lib_handle = os::native_java_library();
_to_java_string_fn = CAST_TO_FN_PTR(to_java_string_fn_t, os::dll_lookup(lib_handle, "NewStringPlatform"));
if (_to_java_string_fn == NULL) {
fatal("NewStringPlatform missing");
}
}
jstring js = NULL;
{ JavaThread* thread = (JavaThread*)THREAD;
assert(thread->is_Java_thread(), "must be java thread");
HandleMark hm(thread);
ThreadToNativeFromVM ttn(thread);
js = (_to_java_string_fn)(thread->jni_environment(), str);
}
return Handle(THREAD, JNIHandles::resolve(js));
}
char* java_lang_String::as_platform_dependent_str(Handle java_string, TRAPS) {
typedef char* (*to_platform_string_fn_t)(JNIEnv*, jstring, bool*);
static to_platform_string_fn_t _to_platform_string_fn = NULL;
if (_to_platform_string_fn == NULL) {
void *lib_handle = os::native_java_library();
_to_platform_string_fn = CAST_TO_FN_PTR(to_platform_string_fn_t, os::dll_lookup(lib_handle, "GetStringPlatformChars"));
if (_to_platform_string_fn == NULL) {
fatal("GetStringPlatformChars missing");
}
}
char *native_platform_string;
{ JavaThread* thread = (JavaThread*)THREAD;
assert(thread->is_Java_thread(), "must be java thread");
JNIEnv *env = thread->jni_environment();
jstring js = (jstring) JNIHandles::make_local(env, java_string());
bool is_copy;
HandleMark hm(thread);
ThreadToNativeFromVM ttn(thread);
native_platform_string = (_to_platform_string_fn)(env, js, &is_copy);
assert(is_copy == JNI_TRUE, "is_copy value changed");
JNIHandles::destroy_local(js);
}
return native_platform_string;
}
Handle java_lang_String::char_converter(Handle java_string, jchar from_char, jchar to_char, TRAPS) {
oop obj = java_string();
typeArrayOop value = java_lang_String::value(obj);
int offset = java_lang_String::offset(obj);
int length = java_lang_String::length(obj);
int index; // Declared outside, used later
for (index = 0; index < length; index++) {
if (value->char_at(index + offset) == from_char) {
break;
}
}
if (index == length) {
return java_string;
}
typeArrayHandle h_value(THREAD, value);
Handle string = basic_create(length, CHECK_NH);
typeArrayOop from_buffer = h_value();
typeArrayOop to_buffer = java_lang_String::value(string());
for (index = 0; index < length; index++) {
jchar c = from_buffer->char_at(index + offset);
if (c == from_char) {
c = to_char;
}
to_buffer->char_at_put(index, c);
}
return string;
}
jchar* java_lang_String::as_unicode_string(oop java_string, int& length, TRAPS) {
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
length = java_lang_String::length(java_string);
jchar* result = NEW_RESOURCE_ARRAY_RETURN_NULL(jchar, length);
if (result != NULL) {
for (int index = 0; index < length; index++) {
result[index] = value->char_at(index + offset);
}
} else {
THROW_MSG_0(vmSymbols::java_lang_OutOfMemoryError(), "could not allocate Unicode string");
}
return result;
}
unsigned int java_lang_String::hash_code(oop java_string) {
int length = java_lang_String::length(java_string);
if (length == 0) return 0;
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
return java_lang_String::hash_code(value->char_at_addr(offset), length);
}
char* java_lang_String::as_quoted_ascii(oop java_string) {
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
int length = java_lang_String::length(java_string);
jchar* base = (length == 0) ? NULL : value->char_at_addr(offset);
if (base == NULL) return NULL;
int result_length = UNICODE::quoted_ascii_length(base, length) + 1;
char* result = NEW_RESOURCE_ARRAY(char, result_length);
UNICODE::as_quoted_ascii(base, length, result, result_length);
assert(result_length >= length + 1, "must not be shorter");
assert(result_length == (int)strlen(result) + 1, "must match");
return result;
}
unsigned int java_lang_String::hash_string(oop java_string) {
int length = java_lang_String::length(java_string);
if (length == 0) {
return StringTable::hash_string(NULL, 0);
}
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
return StringTable::hash_string(value->char_at_addr(offset), length);
}
Symbol* java_lang_String::as_symbol(Handle java_string, TRAPS) {
oop obj = java_string();
typeArrayOop value = java_lang_String::value(obj);
int offset = java_lang_String::offset(obj);
int length = java_lang_String::length(obj);
jchar* base = (length == 0) ? NULL : value->char_at_addr(offset);
Symbol* sym = SymbolTable::lookup_unicode(base, length, THREAD);
return sym;
}
Symbol* java_lang_String::as_symbol_or_null(oop java_string) {
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
int length = java_lang_String::length(java_string);
jchar* base = (length == 0) ? NULL : value->char_at_addr(offset);
return SymbolTable::probe_unicode(base, length);
}
int java_lang_String::utf8_length(oop java_string) {
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
int length = java_lang_String::length(java_string);
jchar* position = (length == 0) ? NULL : value->char_at_addr(offset);
return UNICODE::utf8_length(position, length);
}
char* java_lang_String::as_utf8_string(oop java_string) {
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
int length = java_lang_String::length(java_string);
jchar* position = (length == 0) ? NULL : value->char_at_addr(offset);
return UNICODE::as_utf8(position, length);
}
char* java_lang_String::as_utf8_string(oop java_string, char* buf, int buflen) {
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
int length = java_lang_String::length(java_string);
jchar* position = (length == 0) ? NULL : value->char_at_addr(offset);
return UNICODE::as_utf8(position, length, buf, buflen);
}
char* java_lang_String::as_utf8_string(oop java_string, int start, int len) {
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
int length = java_lang_String::length(java_string);
assert(start + len <= length, "just checking");
jchar* position = value->char_at_addr(offset + start);
return UNICODE::as_utf8(position, len);
}
bool java_lang_String::equals(oop java_string, jchar* chars, int len) {
assert(java_string->klass() == SystemDictionary::String_klass(),
"must be java_string");
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
int length = java_lang_String::length(java_string);
if (length != len) {
return false;
}
for (int i = 0; i < len; i++) {
if (value->char_at(i + offset) != chars[i]) {
return false;
}
}
return true;
}
bool java_lang_String::equals(oop str1, oop str2) {
assert(str1->klass() == SystemDictionary::String_klass(),
"must be java String");
assert(str2->klass() == SystemDictionary::String_klass(),
"must be java String");
typeArrayOop value1 = java_lang_String::value(str1);
int offset1 = java_lang_String::offset(str1);
int length1 = java_lang_String::length(str1);
typeArrayOop value2 = java_lang_String::value(str2);
int offset2 = java_lang_String::offset(str2);
int length2 = java_lang_String::length(str2);
if (length1 != length2) {
return false;
}
for (int i = 0; i < length1; i++) {
if (value1->char_at(i + offset1) != value2->char_at(i + offset2)) {
return false;
}
}
return true;
}
void java_lang_String::print(oop java_string, outputStream* st) {
assert(java_string->klass() == SystemDictionary::String_klass(), "must be java_string");
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
int length = java_lang_String::length(java_string);
int end = MIN2(length, 100);
if (value == NULL) {
st->print_cr("NULL");
} else {
st->print("\"");
for (int index = 0; index < length; index++) {
st->print("%c", value->char_at(index + offset));
}
st->print("\"");
}
}
static void initialize_static_field(fieldDescriptor* fd, Handle mirror, TRAPS) {
assert(mirror.not_null() && fd->is_static(), "just checking");
if (fd->has_initial_value()) {
BasicType t = fd->field_type();
switch (t) {
case T_BYTE:
mirror()->byte_field_put(fd->offset(), fd->int_initial_value());
break;
case T_BOOLEAN:
mirror()->bool_field_put(fd->offset(), fd->int_initial_value());
break;
case T_CHAR:
mirror()->char_field_put(fd->offset(), fd->int_initial_value());
break;
case T_SHORT:
mirror()->short_field_put(fd->offset(), fd->int_initial_value());
break;
case T_INT:
mirror()->int_field_put(fd->offset(), fd->int_initial_value());
break;
case T_FLOAT:
mirror()->float_field_put(fd->offset(), fd->float_initial_value());
break;
case T_DOUBLE:
mirror()->double_field_put(fd->offset(), fd->double_initial_value());
break;
case T_LONG:
mirror()->long_field_put(fd->offset(), fd->long_initial_value());
break;
case T_OBJECT:
{
#ifdef ASSERT
TempNewSymbol sym = SymbolTable::new_symbol("Ljava/lang/String;", CHECK);
assert(fd->signature() == sym, "just checking");
#endif
oop string = fd->string_initial_value(CHECK);
mirror()->obj_field_put(fd->offset(), string);
}
break;
default:
THROW_MSG(vmSymbols::java_lang_ClassFormatError(),
"Illegal ConstantValue attribute in class file");
}
}
}
void java_lang_Class::fixup_mirror(KlassHandle k, TRAPS) {
assert(InstanceMirrorKlass::offset_of_static_fields() != 0, "must have been computed already");
if (!k->is_shared()) {
if (k->oop_is_instance()) {
for (JavaFieldStream fs(InstanceKlass::cast(k())); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) {
int real_offset = fs.offset() + InstanceMirrorKlass::offset_of_static_fields();
fs.set_offset(real_offset);
}
}
}
}
create_mirror(k, Handle(NULL), Handle(NULL), CHECK);
}
void java_lang_Class::initialize_mirror_fields(KlassHandle k,
Handle mirror,
Handle protection_domain,
TRAPS) {
typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK);
set_init_lock(mirror(), r);
set_protection_domain(mirror(), protection_domain());
InstanceKlass::cast(k())->do_local_static_fields(&initialize_static_field, mirror, CHECK);
}
void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader,
Handle protection_domain, TRAPS) {
assert(k->java_mirror() == NULL, "should only assign mirror once");
int computed_modifiers = k->compute_modifier_flags(CHECK);
k->set_modifier_flags(computed_modifiers);
if (SystemDictionary::Class_klass_loaded()) {
Handle mirror = InstanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance(k, CHECK);
if (!k.is_null()) {
java_lang_Class::set_klass(mirror(), k());
}
InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass());
assert(oop_size(mirror()) == mk->instance_size(k), "should have been set");
java_lang_Class::set_static_oop_field_count(mirror(), mk->compute_static_oop_field_count(mirror()));
if (k->oop_is_array()) {
Handle comp_mirror;
if (k->oop_is_typeArray()) {
BasicType type = TypeArrayKlass::cast(k())->element_type();
comp_mirror = Universe::java_mirror(type);
} else {
assert(k->oop_is_objArray(), "Must be");
Klass* element_klass = ObjArrayKlass::cast(k())->element_klass();
assert(element_klass != NULL, "Must have an element klass");
comp_mirror = element_klass->java_mirror();
}
assert(comp_mirror.not_null(), "must have a mirror");
ArrayKlass::cast(k())->set_component_mirror(comp_mirror());
set_array_klass(comp_mirror(), k());
} else {
assert(k->oop_is_instance(), "Must be");
initialize_mirror_fields(k, mirror, protection_domain, THREAD);
if (HAS_PENDING_EXCEPTION) {
java_lang_Class::set_klass(mirror(), NULL);
return;
}
}
assert(class_loader() == k->class_loader(), "should be same");
set_class_loader(mirror(), class_loader());
if (!k.is_null()) {
k->set_java_mirror(mirror());
}
} else {
if (fixup_mirror_list() == NULL) {
GrowableArray<Klass*>* list =
new (ResourceObj::C_HEAP, mtClass) GrowableArray<Klass*>(40, true);
set_fixup_mirror_list(list);
}
fixup_mirror_list()->push(k());
}
}
int java_lang_Class::oop_size(oop java_class) {
assert(_oop_size_offset != 0, "must be set");
return java_class->int_field(_oop_size_offset);
}
void java_lang_Class::set_oop_size(oop java_class, int size) {
assert(_oop_size_offset != 0, "must be set");
java_class->int_field_put(_oop_size_offset, size);
}
int java_lang_Class::static_oop_field_count(oop java_class) {
assert(_static_oop_field_count_offset != 0, "must be set");
return java_class->int_field(_static_oop_field_count_offset);
}
void java_lang_Class::set_static_oop_field_count(oop java_class, int size) {
assert(_static_oop_field_count_offset != 0, "must be set");
java_class->int_field_put(_static_oop_field_count_offset, size);
}
oop java_lang_Class::protection_domain(oop java_class) {
assert(_protection_domain_offset != 0, "must be set");
return java_class->obj_field(_protection_domain_offset);
}
void java_lang_Class::set_protection_domain(oop java_class, oop pd) {
assert(_protection_domain_offset != 0, "must be set");
java_class->obj_field_put(_protection_domain_offset, pd);
}
oop java_lang_Class::init_lock(oop java_class) {
assert(_init_lock_offset != 0, "must be set");
return java_class->obj_field(_init_lock_offset);
}
void java_lang_Class::set_init_lock(oop java_class, oop init_lock) {
assert(_init_lock_offset != 0, "must be set");
java_class->obj_field_put(_init_lock_offset, init_lock);
}
objArrayOop java_lang_Class::signers(oop java_class) {
assert(_signers_offset != 0, "must be set");
return (objArrayOop)java_class->obj_field(_signers_offset);
}
void java_lang_Class::set_signers(oop java_class, objArrayOop signers) {
assert(_signers_offset != 0, "must be set");
java_class->obj_field_put(_signers_offset, (oop)signers);
}
void java_lang_Class::set_class_loader(oop java_class, oop loader) {
if (_class_loader_offset != 0) {
java_class->obj_field_put(_class_loader_offset, loader);
}
}
oop java_lang_Class::class_loader(oop java_class) {
assert(_class_loader_offset != 0, "must be set");
return java_class->obj_field(_class_loader_offset);
}
oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) {
oop java_class = InstanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance(NULL, CHECK_0);
if (type != T_VOID) {
Klass* aklass = Universe::typeArrayKlassObj(type);
assert(aklass != NULL, "correct bootstrap");
set_array_klass(java_class, aklass);
}
#ifdef ASSERT
InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(SystemDictionary::Class_klass());
assert(java_lang_Class::static_oop_field_count(java_class) == 0, "should have been zeroed by allocation");
#endif
return java_class;
}
Klass* java_lang_Class::as_Klass(oop java_class) {
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
Klass* k = ((Klass*)java_class->metadata_field(_klass_offset));
assert(k == NULL || k->is_klass(), "type check");
return k;
}
void java_lang_Class::set_klass(oop java_class, Klass* klass) {
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
java_class->metadata_field_put(_klass_offset, klass);
}
void java_lang_Class::print_signature(oop java_class, outputStream* st) {
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
Symbol* name = NULL;
bool is_instance = false;
if (is_primitive(java_class)) {
name = vmSymbols::type_signature(primitive_type(java_class));
} else {
Klass* k = as_Klass(java_class);
is_instance = k->oop_is_instance();
name = k->name();
}
if (name == NULL) {
st->print("<null>");
return;
}
if (is_instance) st->print("L");
st->write((char*) name->base(), (int) name->utf8_length());
if (is_instance) st->print(";");
}
Symbol* java_lang_Class::as_signature(oop java_class, bool intern_if_not_found, TRAPS) {
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
Symbol* name;
if (is_primitive(java_class)) {
name = vmSymbols::type_signature(primitive_type(java_class));
name->increment_refcount();
} else {
Klass* k = as_Klass(java_class);
if (!k->oop_is_instance()) {
name = k->name();
name->increment_refcount();
} else {
ResourceMark rm;
const char* sigstr = k->signature_name();
int siglen = (int) strlen(sigstr);
if (!intern_if_not_found) {
name = SymbolTable::probe(sigstr, siglen);
} else {
name = SymbolTable::new_symbol(sigstr, siglen, THREAD);
}
}
}
return name;
}
const char* java_lang_Class::as_external_name(oop java_class) {
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
const char* name = NULL;
if (is_primitive(java_class)) {
name = type2name(primitive_type(java_class));
} else {
name = as_Klass(java_class)->external_name();
}
if (name == NULL) {
name = "<null>";
}
return name;
}
Klass* java_lang_Class::array_klass(oop java_class) {
Klass* k = ((Klass*)java_class->metadata_field(_array_klass_offset));
assert(k == NULL || k->is_klass() && k->oop_is_array(), "should be array klass");
return k;
}
void java_lang_Class::set_array_klass(oop java_class, Klass* klass) {
assert(klass->is_klass() && klass->oop_is_array(), "should be array klass");
java_class->metadata_field_put(_array_klass_offset, klass);
}
bool java_lang_Class::is_primitive(oop java_class) {
bool is_primitive = (java_class->metadata_field(_klass_offset) == NULL);
#ifdef ASSERT
if (is_primitive) {
Klass* k = ((Klass*)java_class->metadata_field(_array_klass_offset));
assert(k == NULL || is_java_primitive(ArrayKlass::cast(k)->element_type()),
"Should be either the T_VOID primitive or a java primitive");
}
#endif
return is_primitive;
}
BasicType java_lang_Class::primitive_type(oop java_class) {
assert(java_lang_Class::is_primitive(java_class), "just checking");
Klass* ak = ((Klass*)java_class->metadata_field(_array_klass_offset));
BasicType type = T_VOID;
if (ak != NULL) {
type = ArrayKlass::cast(ak)->element_type();
} else {
assert(java_class == Universe::void_mirror(), "only valid non-array primitive");
}
assert(Universe::java_mirror(type) == java_class, "must be consistent");
return type;
}
BasicType java_lang_Class::as_BasicType(oop java_class, Klass** reference_klass) {
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
if (is_primitive(java_class)) {
if (reference_klass != NULL)
(*reference_klass) = NULL;
return primitive_type(java_class);
} else {
if (reference_klass != NULL)
(*reference_klass) = as_Klass(java_class);
return T_OBJECT;
}
}
oop java_lang_Class::primitive_mirror(BasicType t) {
oop mirror = Universe::java_mirror(t);
assert(mirror != NULL && mirror->is_a(SystemDictionary::Class_klass()), "must be a Class");
assert(java_lang_Class::is_primitive(mirror), "must be primitive");
return mirror;
}
bool java_lang_Class::offsets_computed = false;
int java_lang_Class::classRedefinedCount_offset = -1;
void java_lang_Class::compute_offsets() {
assert(!offsets_computed, "offsets should be initialized only once");
offsets_computed = true;
Klass* klass_oop = SystemDictionary::Class_klass();
compute_optional_offset(classRedefinedCount_offset,
klass_oop, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature());
compute_optional_offset(_class_loader_offset,
klass_oop, vmSymbols::classLoader_name(),
vmSymbols::classloader_signature());
CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}
int java_lang_Class::classRedefinedCount(oop the_class_mirror) {
if (!JDK_Version::is_gte_jdk15x_version()
|| classRedefinedCount_offset == -1) {
return -1;
}
return the_class_mirror->int_field(classRedefinedCount_offset);
}
void java_lang_Class::set_classRedefinedCount(oop the_class_mirror, int value) {
if (!JDK_Version::is_gte_jdk15x_version()
|| classRedefinedCount_offset == -1) {
return;
}
the_class_mirror->int_field_put(classRedefinedCount_offset, value);
}
int java_lang_Thread::_name_offset = 0;
int java_lang_Thread::_group_offset = 0;
int java_lang_Thread::_contextClassLoader_offset = 0;
int java_lang_Thread::_inheritedAccessControlContext_offset = 0;
int java_lang_Thread::_priority_offset = 0;
int java_lang_Thread::_eetop_offset = 0;
int java_lang_Thread::_daemon_offset = 0;
int java_lang_Thread::_stillborn_offset = 0;
int java_lang_Thread::_stackSize_offset = 0;
int java_lang_Thread::_tid_offset = 0;
int java_lang_Thread::_thread_status_offset = 0;
int java_lang_Thread::_park_blocker_offset = 0;
int java_lang_Thread::_park_event_offset = 0 ;
void java_lang_Thread::compute_offsets() {
assert(_group_offset == 0, "offsets should be initialized only once");
Klass* k = SystemDictionary::Thread_klass();
compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
compute_offset(_group_offset, k, vmSymbols::group_name(), vmSymbols::threadgroup_signature());
compute_offset(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(), vmSymbols::classloader_signature());
compute_offset(_inheritedAccessControlContext_offset, k, vmSymbols::inheritedAccessControlContext_name(), vmSymbols::accesscontrolcontext_signature());
compute_offset(_priority_offset, k, vmSymbols::priority_name(), vmSymbols::int_signature());
compute_offset(_daemon_offset, k, vmSymbols::daemon_name(), vmSymbols::bool_signature());
compute_offset(_eetop_offset, k, vmSymbols::eetop_name(), vmSymbols::long_signature());
compute_offset(_stillborn_offset, k, vmSymbols::stillborn_name(), vmSymbols::bool_signature());
compute_optional_offset(_stackSize_offset, k, vmSymbols::stackSize_name(), vmSymbols::long_signature());
compute_optional_offset(_tid_offset, k, vmSymbols::thread_id_name(), vmSymbols::long_signature());
compute_optional_offset(_thread_status_offset, k, vmSymbols::thread_status_name(), vmSymbols::int_signature());
compute_optional_offset(_park_blocker_offset, k, vmSymbols::park_blocker_name(), vmSymbols::object_signature());
compute_optional_offset(_park_event_offset, k, vmSymbols::park_event_name(),
vmSymbols::long_signature());
}
JavaThread* java_lang_Thread::thread(oop java_thread) {
return (JavaThread*)java_thread->address_field(_eetop_offset);
}
void java_lang_Thread::set_thread(oop java_thread, JavaThread* thread) {
java_thread->address_field_put(_eetop_offset, (address)thread);
}
oop java_lang_Thread::name(oop java_thread) {
return java_thread->obj_field(_name_offset);
}
void java_lang_Thread::set_name(oop java_thread, oop name) {
java_thread->obj_field_put(_name_offset, name);
}
ThreadPriority java_lang_Thread::priority(oop java_thread) {
return (ThreadPriority)java_thread->int_field(_priority_offset);
}
void java_lang_Thread::set_priority(oop java_thread, ThreadPriority priority) {
java_thread->int_field_put(_priority_offset, priority);
}
oop java_lang_Thread::threadGroup(oop java_thread) {
return java_thread->obj_field(_group_offset);
}
bool java_lang_Thread::is_stillborn(oop java_thread) {
return java_thread->bool_field(_stillborn_offset) != 0;
}
void java_lang_Thread::set_stillborn(oop java_thread) {
java_thread->bool_field_put(_stillborn_offset, true);
}
bool java_lang_Thread::is_alive(oop java_thread) {
JavaThread* thr = java_lang_Thread::thread(java_thread);
return (thr != NULL);
}
bool java_lang_Thread::is_daemon(oop java_thread) {
return java_thread->bool_field(_daemon_offset) != 0;
}
void java_lang_Thread::set_daemon(oop java_thread) {
java_thread->bool_field_put(_daemon_offset, true);
}
oop java_lang_Thread::context_class_loader(oop java_thread) {
return java_thread->obj_field(_contextClassLoader_offset);
}
oop java_lang_Thread::inherited_access_control_context(oop java_thread) {
return java_thread->obj_field(_inheritedAccessControlContext_offset);
}
jlong java_lang_Thread::stackSize(oop java_thread) {
if (_stackSize_offset > 0) {
assert(JDK_Version::is_gte_jdk14x_version(), "sanity check");
return java_thread->long_field(_stackSize_offset);
} else {
return 0;
}
}
void java_lang_Thread::set_thread_status(oop java_thread,
java_lang_Thread::ThreadStatus status) {
if (_thread_status_offset > 0) {
java_thread->int_field_put(_thread_status_offset, status);
}
}
java_lang_Thread::ThreadStatus java_lang_Thread::get_thread_status(oop java_thread) {
assert(Threads_lock->owned_by_self() || Thread::current()->is_Watcher_thread() ||
Thread::current()->is_VM_thread() ||
JavaThread::current()->thread_state() == _thread_in_vm,
"Java Thread is not running in vm");
if (_thread_status_offset > 0) {
return (java_lang_Thread::ThreadStatus)java_thread->int_field(_thread_status_offset);
} else {
JavaThread* thr = java_lang_Thread::thread(java_thread);
if (thr == NULL) {
return NEW;
}
return (java_lang_Thread::ThreadStatus)JVMTI_THREAD_STATE_ALIVE;
}
}
jlong java_lang_Thread::thread_id(oop java_thread) {
if (_tid_offset > 0) {
return java_thread->long_field(_tid_offset);
} else {
return 0;
}
}
oop java_lang_Thread::park_blocker(oop java_thread) {
assert(JDK_Version::current().supports_thread_park_blocker() &&
_park_blocker_offset != 0, "Must support parkBlocker field");
if (_park_blocker_offset > 0) {
return java_thread->obj_field(_park_blocker_offset);
}
return NULL;
}
jlong java_lang_Thread::park_event(oop java_thread) {
if (_park_event_offset > 0) {
return java_thread->long_field(_park_event_offset);
}
return 0;
}
bool java_lang_Thread::set_park_event(oop java_thread, jlong ptr) {
if (_park_event_offset > 0) {
java_thread->long_field_put(_park_event_offset, ptr);
return true;
}
return false;
}
const char* java_lang_Thread::thread_status_name(oop java_thread) {
assert(JDK_Version::is_gte_jdk15x_version() && _thread_status_offset != 0, "Must have thread status");
ThreadStatus status = (java_lang_Thread::ThreadStatus)java_thread->int_field(_thread_status_offset);
switch (status) {
case NEW : return "NEW";
case RUNNABLE : return "RUNNABLE";
case SLEEPING : return "TIMED_WAITING (sleeping)";
case IN_OBJECT_WAIT : return "WAITING (on object monitor)";
case IN_OBJECT_WAIT_TIMED : return "TIMED_WAITING (on object monitor)";
case PARKED : return "WAITING (parking)";
case PARKED_TIMED : return "TIMED_WAITING (parking)";
case BLOCKED_ON_MONITOR_ENTER : return "BLOCKED (on object monitor)";
case TERMINATED : return "TERMINATED";
default : return "UNKNOWN";
};
}
int java_lang_ThreadGroup::_parent_offset = 0;
int java_lang_ThreadGroup::_name_offset = 0;
int java_lang_ThreadGroup::_threads_offset = 0;
int java_lang_ThreadGroup::_groups_offset = 0;
int java_lang_ThreadGroup::_maxPriority_offset = 0;
int java_lang_ThreadGroup::_destroyed_offset = 0;
int java_lang_ThreadGroup::_daemon_offset = 0;
int java_lang_ThreadGroup::_vmAllowSuspension_offset = 0;
int java_lang_ThreadGroup::_nthreads_offset = 0;
int java_lang_ThreadGroup::_ngroups_offset = 0;
oop java_lang_ThreadGroup::parent(oop java_thread_group) {
assert(java_thread_group->is_oop(), "thread group must be oop");
return java_thread_group->obj_field(_parent_offset);
}
typeArrayOop java_lang_ThreadGroup::name(oop java_thread_group) {
oop name = java_thread_group->obj_field(_name_offset);
return name == NULL ? (typeArrayOop)NULL : java_lang_String::value(name);
}
int java_lang_ThreadGroup::nthreads(oop java_thread_group) {
assert(java_thread_group->is_oop(), "thread group must be oop");
return java_thread_group->int_field(_nthreads_offset);
}
objArrayOop java_lang_ThreadGroup::threads(oop java_thread_group) {
oop threads = java_thread_group->obj_field(_threads_offset);
assert(threads != NULL, "threadgroups should have threads");
assert(threads->is_objArray(), "just checking"); // Todo: Add better type checking code
return objArrayOop(threads);
}
int java_lang_ThreadGroup::ngroups(oop java_thread_group) {
assert(java_thread_group->is_oop(), "thread group must be oop");
return java_thread_group->int_field(_ngroups_offset);
}
objArrayOop java_lang_ThreadGroup::groups(oop java_thread_group) {
oop groups = java_thread_group->obj_field(_groups_offset);
assert(groups == NULL || groups->is_objArray(), "just checking"); // Todo: Add better type checking code
return objArrayOop(groups);
}
ThreadPriority java_lang_ThreadGroup::maxPriority(oop java_thread_group) {
assert(java_thread_group->is_oop(), "thread group must be oop");
return (ThreadPriority) java_thread_group->int_field(_maxPriority_offset);
}
bool java_lang_ThreadGroup::is_destroyed(oop java_thread_group) {
assert(java_thread_group->is_oop(), "thread group must be oop");
return java_thread_group->bool_field(_destroyed_offset) != 0;
}
bool java_lang_ThreadGroup::is_daemon(oop java_thread_group) {
assert(java_thread_group->is_oop(), "thread group must be oop");
return java_thread_group->bool_field(_daemon_offset) != 0;
}
bool java_lang_ThreadGroup::is_vmAllowSuspension(oop java_thread_group) {
assert(java_thread_group->is_oop(), "thread group must be oop");
return java_thread_group->bool_field(_vmAllowSuspension_offset) != 0;
}
void java_lang_ThreadGroup::compute_offsets() {
assert(_parent_offset == 0, "offsets should be initialized only once");
Klass* k = SystemDictionary::ThreadGroup_klass();
compute_offset(_parent_offset, k, vmSymbols::parent_name(), vmSymbols::threadgroup_signature());
compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
compute_offset(_threads_offset, k, vmSymbols::threads_name(), vmSymbols::thread_array_signature());
compute_offset(_groups_offset, k, vmSymbols::groups_name(), vmSymbols::threadgroup_array_signature());
compute_offset(_maxPriority_offset, k, vmSymbols::maxPriority_name(), vmSymbols::int_signature());
compute_offset(_destroyed_offset, k, vmSymbols::destroyed_name(), vmSymbols::bool_signature());
compute_offset(_daemon_offset, k, vmSymbols::daemon_name(), vmSymbols::bool_signature());
compute_offset(_vmAllowSuspension_offset, k, vmSymbols::vmAllowSuspension_name(), vmSymbols::bool_signature());
compute_offset(_nthreads_offset, k, vmSymbols::nthreads_name(), vmSymbols::int_signature());
compute_offset(_ngroups_offset, k, vmSymbols::ngroups_name(), vmSymbols::int_signature());
}
oop java_lang_Throwable::unassigned_stacktrace() {
InstanceKlass* ik = InstanceKlass::cast(SystemDictionary::Throwable_klass());
address addr = ik->static_field_addr(static_unassigned_stacktrace_offset);
if (UseCompressedOops) {
return oopDesc::load_decode_heap_oop((narrowOop *)addr);
} else {
return oopDesc::load_decode_heap_oop((oop*)addr);
}
}
oop java_lang_Throwable::backtrace(oop throwable) {
return throwable->obj_field_acquire(backtrace_offset);
}
void java_lang_Throwable::set_backtrace(oop throwable, oop value) {
throwable->release_obj_field_put(backtrace_offset, value);
}
oop java_lang_Throwable::message(oop throwable) {
return throwable->obj_field(detailMessage_offset);
}
oop java_lang_Throwable::message(Handle throwable) {
return throwable->obj_field(detailMessage_offset);
}
Symbol* java_lang_Throwable::detail_message(oop throwable) {
PRESERVE_EXCEPTION_MARK; // Keep original exception
oop detailed_message = java_lang_Throwable::message(throwable);
if (detailed_message != NULL) {
return java_lang_String::as_symbol(detailed_message, THREAD);
}
return NULL;
}
void java_lang_Throwable::set_message(oop throwable, oop value) {
throwable->obj_field_put(detailMessage_offset, value);
}
void java_lang_Throwable::set_stacktrace(oop throwable, oop st_element_array) {
throwable->obj_field_put(stackTrace_offset, st_element_array);
}
void java_lang_Throwable::clear_stacktrace(oop throwable) {
assert(JDK_Version::is_gte_jdk14x_version(), "should only be called in >= 1.4");
set_stacktrace(throwable, NULL);
}
void java_lang_Throwable::print(oop throwable, outputStream* st) {
ResourceMark rm;
Klass* k = throwable->klass();
assert(k != NULL, "just checking");
st->print("%s", InstanceKlass::cast(k)->external_name());
oop msg = message(throwable);
if (msg != NULL) {
st->print(": %s", java_lang_String::as_utf8_string(msg));
}
}
void java_lang_Throwable::print(Handle throwable, outputStream* st) {
ResourceMark rm;
Klass* k = throwable->klass();
assert(k != NULL, "just checking");
st->print("%s", InstanceKlass::cast(k)->external_name());
oop msg = message(throwable);
if (msg != NULL) {
st->print(": %s", java_lang_String::as_utf8_string(msg));
}
}
const int MAX_VERSION = USHRT_MAX;
static inline int merge_bci_and_version(int bci, int version) {
if (version > USHRT_MAX || version < 0) version = MAX_VERSION;
assert((jushort)bci == bci, "bci should be short");
return build_int_from_shorts(version, bci);
}
static inline int bci_at(unsigned int merged) {
return extract_high_short_from_int(merged);
}
static inline int version_at(unsigned int merged) {
return extract_low_short_from_int(merged);
}
static inline bool version_matches(Method* method, int version) {
assert(version < MAX_VERSION, "version is too big");
return method != NULL && (method->constants()->version() == version);
}
static inline int get_line_number(Method* method, int bci) {
int line_number = 0;
if (method->is_native()) {
line_number = -2;
} else {
line_number = method->line_number_from_bci(bci);
if (line_number == -1 && ShowHiddenFrames) {
line_number = bci + 1000000;
}
}
return line_number;
}
class BacktraceBuilder: public StackObj {
private:
Handle _backtrace;
objArrayOop _head;
typeArrayOop _methods;
typeArrayOop _bcis;
objArrayOop _mirrors;
typeArrayOop _cprefs; // needed to insulate method name against redefinition
int _index;
No_Safepoint_Verifier _nsv;
public:
enum {
trace_methods_offset = java_lang_Throwable::trace_methods_offset,
trace_bcis_offset = java_lang_Throwable::trace_bcis_offset,
trace_mirrors_offset = java_lang_Throwable::trace_mirrors_offset,
trace_cprefs_offset = java_lang_Throwable::trace_cprefs_offset,
trace_next_offset = java_lang_Throwable::trace_next_offset,
trace_size = java_lang_Throwable::trace_size,
trace_chunk_size = java_lang_Throwable::trace_chunk_size
};
static typeArrayOop get_methods(objArrayHandle chunk) {
typeArrayOop methods = typeArrayOop(chunk->obj_at(trace_methods_offset));
assert(methods != NULL, "method array should be initialized in backtrace");
return methods;
}
static typeArrayOop get_bcis(objArrayHandle chunk) {
typeArrayOop bcis = typeArrayOop(chunk->obj_at(trace_bcis_offset));
assert(bcis != NULL, "bci array should be initialized in backtrace");
return bcis;
}
static objArrayOop get_mirrors(objArrayHandle chunk) {
objArrayOop mirrors = objArrayOop(chunk->obj_at(trace_mirrors_offset));
assert(mirrors != NULL, "mirror array should be initialized in backtrace");
return mirrors;
}
static typeArrayOop get_cprefs(objArrayHandle chunk) {
typeArrayOop cprefs = typeArrayOop(chunk->obj_at(trace_cprefs_offset));
assert(cprefs != NULL, "cprefs array should be initialized in backtrace");
return cprefs;
}
BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL), _cprefs(NULL) {
expand(CHECK);
_backtrace = _head;
_index = 0;
}
BacktraceBuilder(objArrayHandle backtrace) {
_methods = get_methods(backtrace);
_bcis = get_bcis(backtrace);
_mirrors = get_mirrors(backtrace);
_cprefs = get_cprefs(backtrace);
assert(_methods->length() == _bcis->length() &&
_methods->length() == _mirrors->length(),
"method and source information arrays should match");
_backtrace = _head = backtrace();
_index = 0;
}
void expand(TRAPS) {
objArrayHandle old_head(THREAD, _head);
Pause_No_Safepoint_Verifier pnsv(&_nsv);
objArrayOop head = oopFactory::new_objectArray(trace_size, CHECK);
objArrayHandle new_head(THREAD, head);
typeArrayOop methods = oopFactory::new_shortArray(trace_chunk_size, CHECK);
typeArrayHandle new_methods(THREAD, methods);
typeArrayOop bcis = oopFactory::new_intArray(trace_chunk_size, CHECK);
typeArrayHandle new_bcis(THREAD, bcis);
objArrayOop mirrors = oopFactory::new_objectArray(trace_chunk_size, CHECK);
objArrayHandle new_mirrors(THREAD, mirrors);
typeArrayOop cprefs = oopFactory::new_shortArray(trace_chunk_size, CHECK);
typeArrayHandle new_cprefs(THREAD, cprefs);
if (!old_head.is_null()) {
old_head->obj_at_put(trace_next_offset, new_head());
}
new_head->obj_at_put(trace_methods_offset, new_methods());
new_head->obj_at_put(trace_bcis_offset, new_bcis());
new_head->obj_at_put(trace_mirrors_offset, new_mirrors());
new_head->obj_at_put(trace_cprefs_offset, new_cprefs());
_head = new_head();
_methods = new_methods();
_bcis = new_bcis();
_mirrors = new_mirrors();
_cprefs = new_cprefs();
_index = 0;
}
oop backtrace() {
return _backtrace();
}
inline void push(Method* method, int bci, TRAPS) {
if (bci == SynchronizationEntryBCI) bci = 0;
if (_index >= trace_chunk_size) {
methodHandle mhandle(THREAD, method);
expand(CHECK);
method = mhandle();
}
_methods->ushort_at_put(_index, method->orig_method_idnum());
_bcis->int_at_put(_index, merge_bci_and_version(bci, method->constants()->version()));
_cprefs->ushort_at_put(_index, method->name_index());
assert(method->method_holder()->java_mirror() != NULL, "never push null for mirror");
_mirrors->obj_at_put(_index, method->method_holder()->java_mirror());
_index++;
}
};
char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror,
int method_id, int version, int bci, int cpref) {
InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror()));
const char* klass_name = holder->external_name();
int buf_len = (int)strlen(klass_name);
Method* method = holder->method_with_orig_idnum(method_id, version);
Symbol* sym = (method != NULL) ? method->name() : holder->constants()->symbol_at(cpref);
char* method_name = sym->as_C_string();
buf_len += (int)strlen(method_name);
holder = holder->get_klass_version(version);
char* source_file_name = NULL;
if (holder != NULL) {
Symbol* source = holder->source_file_name();
if (source != NULL) {
source_file_name = source->as_C_string();
buf_len += (int)strlen(source_file_name);
}
}
char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64);
sprintf(buf, "\tat %s.%s", klass_name, method_name);
if (!version_matches(method, version)) {
strcat(buf, "(Redefined)");
} else {
int line_number = get_line_number(method, bci);
if (line_number == -2) {
strcat(buf, "(Native Method)");
} else {
if (source_file_name != NULL && (line_number != -1)) {
sprintf(buf + (int)strlen(buf), "(%s:%d)", source_file_name, line_number);
} else if (source_file_name != NULL) {
sprintf(buf + (int)strlen(buf), "(%s)", source_file_name);
} else {
sprintf(buf + (int)strlen(buf), "(Unknown Source)");
}
nmethod* nm = method->code();
if (WizardMode && nm != NULL) {
sprintf(buf + (int)strlen(buf), "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm);
}
}
}
return buf;
}
void java_lang_Throwable::print_stack_element(outputStream *st, Handle mirror,
int method_id, int version, int bci, int cpref) {
ResourceMark rm;
char* buf = print_stack_element_to_buffer(mirror, method_id, version, bci, cpref);
st->print_cr("%s", buf);
}
void java_lang_Throwable::print_stack_element(outputStream *st, methodHandle method, int bci) {
Handle mirror = method->method_holder()->java_mirror();
int method_id = method->orig_method_idnum();
int version = method->constants()->version();
int cpref = method->name_index();
print_stack_element(st, mirror, method_id, version, bci, cpref);
}
const char* java_lang_Throwable::no_stack_trace_message() {
return "\t<<no stack trace available>>";
}
void java_lang_Throwable::print_stack_trace(oop throwable, outputStream* st) {
Thread *THREAD = Thread::current();
Handle h_throwable(THREAD, throwable);
while (h_throwable.not_null()) {
objArrayHandle result (THREAD, objArrayOop(backtrace(h_throwable())));
if (result.is_null()) {
st->print_cr("%s", no_stack_trace_message());
return;
}
while (result.not_null()) {
typeArrayHandle methods (THREAD, BacktraceBuilder::get_methods(result));
typeArrayHandle bcis (THREAD, BacktraceBuilder::get_bcis(result));
objArrayHandle mirrors (THREAD, BacktraceBuilder::get_mirrors(result));
typeArrayHandle cprefs (THREAD, BacktraceBuilder::get_cprefs(result));
int length = methods()->length();
for (int index = 0; index < length; index++) {
Handle mirror(THREAD, mirrors->obj_at(index));
if (mirror.is_null()) goto handle_cause;
int method = methods->ushort_at(index);
int version = version_at(bcis->int_at(index));
int bci = bci_at(bcis->int_at(index));
int cpref = cprefs->ushort_at(index);
print_stack_element(st, mirror, method, version, bci, cpref);
}
result = objArrayHandle(THREAD, objArrayOop(result->obj_at(trace_next_offset)));
}
handle_cause:
{
EXCEPTION_MARK;
JavaValue cause(T_OBJECT);
JavaCalls::call_virtual(&cause,
h_throwable,
KlassHandle(THREAD, h_throwable->klass()),
vmSymbols::getCause_name(),
vmSymbols::void_throwable_signature(),
THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
h_throwable = Handle();
} else {
h_throwable = Handle(THREAD, (oop) cause.get_jobject());
if (h_throwable.not_null()) {
st->print("Caused by: ");
print(h_throwable, st);
st->cr();
}
}
}
}
}
ssssssss13
最新推荐文章于 2024-08-01 15:05:06 发布