This commit is contained in:
Prasanta Sadhukhan 2020-02-11 13:41:48 +05:30
commit 5f44b6ca1b
115 changed files with 3464 additions and 1103 deletions

View File

@ -618,3 +618,4 @@ a96bc204e3b31ddbf909b20088964112f052927e jdk-14+34
c7d4f2849dbfb755fc5860b362a4044ea0c9e082 jdk-15+8
4a87bb7ebfd7f6a25ec59a5982fe3607242777f8 jdk-14+35
62b5bfef8d618e08e6f3a56cf1fb0e67e89e9cc2 jdk-15+9
bc54620a3848c26cff9766e5e2a6e5ddab98ed18 jdk-14+36

View File

@ -75,6 +75,7 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR)
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.raw \
-Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \
-Duser.language=en -Duser.country=US \
--module-path $(SUPPORT_OUTPUTDIR)/classlist.jar \
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
build.tools.classlist.HelloClasslist \
2> $(LINK_OPT_DIR)/stderr > $(JLI_TRACE_FILE) \

View File

@ -31,6 +31,9 @@
*/
package build.tools.classlist;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.net.InetAddress;
import java.nio.file.FileSystems;
import java.time.LocalDateTime;
@ -55,19 +58,20 @@ public class HelloClasslist {
private static final Logger LOGGER = Logger.getLogger("Hello");
public static void main(String ... args) {
public static void main(String ... args) throws Throwable {
FileSystems.getDefault();
List<String> strings = Arrays.asList("Hello", "World!", "From: ",
InetAddress.getLoopbackAddress().toString());
InetAddress.getLoopbackAddress().toString());
String helloWorld = strings.parallelStream()
.map(s -> s.toLowerCase(Locale.ROOT))
.collect(joining(","));
.map(s -> s.toLowerCase(Locale.ROOT))
.collect(joining(","));
Stream.of(helloWorld.split(","))
.forEach(System.out::println);
Stream.of(helloWorld.split("([,x-z]{1,3})([\\s]*)"))
.map(String::toString)
.forEach(System.out::println);
// Common concatenation patterns
String SS = String.valueOf(args.length) + String.valueOf(args.length);
@ -83,6 +87,10 @@ public class HelloClasslist {
String SCSCS = String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length);
String CI = "string" + args.length;
String IC = args.length + "string";
String SI = String.valueOf(args.length) + args.length;
String IS = args.length + String.valueOf(args.length);
String CIS = "string" + args.length + String.valueOf(args.length);
String CSCI = "string" + String.valueOf(args.length) + "string" + args.length;
String CIC = "string" + args.length + "string";
String CICI = "string" + args.length + "string" + args.length;
String CJ = "string" + System.currentTimeMillis();
@ -99,7 +107,31 @@ public class HelloClasslist {
DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.ROOT)
.format(new Date()));
// A selection of trivial and relatively common MH operations
invoke(MethodHandles.identity(double.class), 1.0);
invoke(MethodHandles.identity(int.class), 1);
invoke(MethodHandles.identity(String.class), "x");
invoke(handle("staticMethod_V", MethodType.methodType(void.class)));
LOGGER.log(Level.FINE, "New Date: " + newDate + " - old: " + oldDate);
}
public static void staticMethod_V() {}
private static MethodHandle handle(String name, MethodType type) throws Throwable {
return MethodHandles.lookup().findStatic(HelloClasslist.class, name, type);
}
private static Object invoke(MethodHandle mh, Object ... args) throws Throwable {
try {
for (Object o : args) {
mh = MethodHandles.insertArguments(mh, 0, o);
}
return mh.invoke();
} catch (Throwable t) {
LOGGER.warning("Failed to find, link and/or invoke " + mh.toString() + ": " + t.getMessage());
throw t;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -672,11 +672,14 @@ void VM_Version::get_processor_features() {
}
}
if (FLAG_IS_DEFAULT(UseAVX)) {
FLAG_SET_DEFAULT(UseAVX, use_avx_limit);
if (is_intel_family_core() && _model == CPU_MODEL_SKYLAKE && _stepping < 5) {
FLAG_SET_DEFAULT(UseAVX, 2); //Set UseAVX=2 for Skylake
// Don't use AVX-512 on older Skylakes unless explicitly requested.
if (use_avx_limit > 2 && is_intel_skylake() && _stepping < 5) {
FLAG_SET_DEFAULT(UseAVX, 2);
} else {
FLAG_SET_DEFAULT(UseAVX, use_avx_limit);
}
} else if (UseAVX > use_avx_limit) {
}
if (UseAVX > use_avx_limit) {
warning("UseAVX=%d is not supported on this CPU, setting it to UseAVX=%d", (int) UseAVX, use_avx_limit);
FLAG_SET_DEFAULT(UseAVX, use_avx_limit);
} else if (UseAVX < 0) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -868,6 +868,9 @@ public:
static bool is_intel_family_core() { return is_intel() &&
extended_cpu_family() == CPU_FAMILY_INTEL_CORE; }
static bool is_intel_skylake() { return is_intel_family_core() &&
extended_cpu_model() == CPU_MODEL_SKYLAKE; }
static bool is_intel_tsc_synched_at_init() {
if (is_intel_family_core()) {
uint32_t ext_model = extended_cpu_model();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -36,11 +36,12 @@ void OSThread::pd_initialize() {
#else
_thread_id = NULL;
#endif
_unique_thread_id = 0;
_pthread_id = NULL;
_siginfo = NULL;
_ucontext = NULL;
_expanding_stack = 0;
_alt_sig_stack = NULL;
_siginfo = NULL;
_ucontext = NULL;
_expanding_stack = 0;
_alt_sig_stack = NULL;
sigemptyset(&_caller_sigmask);
@ -49,6 +50,22 @@ void OSThread::pd_initialize() {
assert(_startThread_lock !=NULL, "check");
}
// Additional thread_id used to correlate threads in SA
void OSThread::set_unique_thread_id() {
#ifdef __APPLE__
thread_identifier_info_data_t m_ident_info;
mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
mach_port_t mach_thread_port = mach_thread_self();
guarantee(mach_thread_port != 0, "just checking");
thread_info(mach_thread_port, THREAD_IDENTIFIER_INFO,
(thread_info_t) &m_ident_info, &count);
mach_port_deallocate(mach_task_self(), mach_thread_port);
_unique_thread_id = m_ident_info.thread_id;
#endif
}
void OSThread::pd_destroy() {
delete _startThread_lock;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -82,9 +82,7 @@
_pthread_id = tid;
}
void set_unique_thread_id(uint64_t id) {
_unique_thread_id = id;
}
void set_unique_thread_id();
// ***************************************************************
// suspension support.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -634,19 +634,6 @@ extern "C" objc_registerThreadWithCollector_t objc_registerThreadWithCollectorFu
objc_registerThreadWithCollector_t objc_registerThreadWithCollectorFunction = NULL;
#endif
#ifdef __APPLE__
static uint64_t locate_unique_thread_id(mach_port_t mach_thread_port) {
// Additional thread_id used to correlate threads in SA
thread_identifier_info_data_t m_ident_info;
mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
thread_info(mach_thread_port, THREAD_IDENTIFIER_INFO,
(thread_info_t) &m_ident_info, &count);
return m_ident_info.thread_id;
}
#endif
// Thread start routine for all newly created threads
static void *thread_native_entry(Thread *thread) {
@ -672,10 +659,10 @@ static void *thread_native_entry(Thread *thread) {
os::current_thread_id(), (uintx) pthread_self());
#ifdef __APPLE__
uint64_t unique_thread_id = locate_unique_thread_id(osthread->thread_id());
guarantee(unique_thread_id != 0, "unique thread id was not found");
osthread->set_unique_thread_id(unique_thread_id);
// Store unique OS X thread id used by SA
osthread->set_unique_thread_id();
#endif
// initialize signal mask for this thread
os::Bsd::hotspot_sigmask(thread);
@ -823,12 +810,12 @@ bool os::create_attached_thread(JavaThread* thread) {
osthread->set_thread_id(os::Bsd::gettid());
// Store pthread info into the OSThread
#ifdef __APPLE__
uint64_t unique_thread_id = locate_unique_thread_id(osthread->thread_id());
guarantee(unique_thread_id != 0, "just checking");
osthread->set_unique_thread_id(unique_thread_id);
// Store unique OS X thread id used by SA
osthread->set_unique_thread_id();
#endif
// Store pthread info into the OSThread
osthread->set_pthread_id(::pthread_self());
// initialize floating point control register
@ -1100,12 +1087,11 @@ void os::die() {
pid_t os::Bsd::gettid() {
int retval = -1;
#ifdef __APPLE__ //XNU kernel
// despite the fact mach port is actually not a thread id use it
// instead of syscall(SYS_thread_selfid) as it certainly fits to u4
retval = ::pthread_mach_thread_np(::pthread_self());
guarantee(retval != 0, "just checking");
return retval;
#ifdef __APPLE__ // XNU kernel
mach_port_t port = mach_thread_self();
guarantee(MACH_PORT_VALID(port), "just checking");
mach_port_deallocate(mach_task_self(), port);
return (pid_t)port;
#else
#ifdef __FreeBSD__
@ -1128,7 +1114,7 @@ pid_t os::Bsd::gettid() {
intx os::current_thread_id() {
#ifdef __APPLE__
return (intx)::pthread_mach_thread_np(::pthread_self());
return (intx)os::Bsd::gettid();
#else
return (intx)::pthread_self();
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -213,14 +213,19 @@ ciInstanceKlass* ciInstanceKlass::get_canonical_holder(int offset) {
}
ciInstanceKlass* self = this;
for (;;) {
assert(self->is_loaded(), "must be loaded to have size");
ciInstanceKlass* super = self->super();
if (super == NULL || super->nof_nonstatic_fields() == 0 ||
!super->contains_field_offset(offset)) {
return self;
} else {
self = super; // return super->get_canonical_holder(offset)
assert(self->is_loaded(), "must be loaded to access field info");
ciField* field = self->get_field_by_offset(offset, false);
if (field != NULL) {
return field->holder();
} else {
for (;;) {
assert(self->is_loaded(), "must be loaded to have size");
ciInstanceKlass* super = self->super();
if (super == NULL || super->nof_nonstatic_fields() == 0) {
return self;
} else {
self = super; // return super->get_canonical_holder(offset)
}
}
}
}
@ -391,6 +396,13 @@ bool ciInstanceKlass::has_finalizable_subclass() {
return Dependencies::find_finalizable_subclass(get_instanceKlass()) != NULL;
}
// ------------------------------------------------------------------
// ciInstanceKlass::contains_field_offset
bool ciInstanceKlass::contains_field_offset(int offset) {
VM_ENTRY_MARK;
return get_instanceKlass()->contains_field_offset(offset);
}
// ------------------------------------------------------------------
// ciInstanceKlass::get_field_by_offset
ciField* ciInstanceKlass::get_field_by_offset(int field_offset, bool is_static) {
@ -457,15 +469,9 @@ int ciInstanceKlass::compute_nonstatic_fields() {
ciInstanceKlass* super = this->super();
GrowableArray<ciField*>* super_fields = NULL;
if (super != NULL && super->has_nonstatic_fields()) {
int super_fsize = super->nonstatic_field_size() * heapOopSize;
int super_flen = super->nof_nonstatic_fields();
super_fields = super->_nonstatic_fields;
assert(super_flen == 0 || super_fields != NULL, "first get nof_fields");
// See if I am no larger than my super; if so, I can use his fields.
if (fsize == super_fsize) {
_nonstatic_fields = super_fields;
return super_fields->length();
}
}
GrowableArray<ciField*>* fields = NULL;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -225,9 +225,7 @@ public:
ciInstanceKlass* unique_concrete_subklass();
bool has_finalizable_subclass();
bool contains_field_offset(int offset) {
return instanceOopDesc::contains_field_offset(offset, nonstatic_field_size());
}
bool contains_field_offset(int offset);
// Get the instance of java.lang.Class corresponding to
// this klass. This instance is used for locking of

View File

@ -30,6 +30,7 @@
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/defaultMethods.hpp"
#include "classfile/dictionary.hpp"
#include "classfile/fieldLayoutBuilder.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/packageEntry.hpp"
@ -60,6 +61,7 @@
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/arguments.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/os.hpp"
@ -1686,8 +1688,12 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs,
field->set_allocation_type(atype);
// After field is initialized with type, we can augment it with aux info
if (parsed_annotations.has_any_annotations())
if (parsed_annotations.has_any_annotations()) {
parsed_annotations.apply_to(field);
if (field->is_contended()) {
_has_contended_fields = true;
}
}
}
int index = length;
@ -3932,39 +3938,6 @@ const InstanceKlass* ClassFileParser::parse_super_class(ConstantPool* const cp,
return super_klass;
}
static unsigned int compute_oop_map_count(const InstanceKlass* super,
unsigned int nonstatic_oop_map_count,
int first_nonstatic_oop_offset) {
unsigned int map_count =
NULL == super ? 0 : super->nonstatic_oop_map_count();
if (nonstatic_oop_map_count > 0) {
// We have oops to add to map
if (map_count == 0) {
map_count = nonstatic_oop_map_count;
}
else {
// Check whether we should add a new map block or whether the last one can
// be extended
const OopMapBlock* const first_map = super->start_of_nonstatic_oop_maps();
const OopMapBlock* const last_map = first_map + map_count - 1;
const int next_offset = last_map->offset() + last_map->count() * heapOopSize;
if (next_offset == first_nonstatic_oop_offset) {
// There is no gap bettwen superklass's last oop field and first
// local oop field, merge maps.
nonstatic_oop_map_count -= 1;
}
else {
// Superklass didn't end with a oop field, add extra maps
assert(next_offset < first_nonstatic_oop_offset, "just checking");
}
map_count += nonstatic_oop_map_count;
}
}
return map_count;
}
#ifndef PRODUCT
static void print_field_layout(const Symbol* name,
Array<u2>* fields,
@ -4002,18 +3975,121 @@ static void print_field_layout(const Symbol* name,
}
#endif
// Values needed for oopmap and InstanceKlass creation
class ClassFileParser::FieldLayoutInfo : public ResourceObj {
public:
int* nonstatic_oop_offsets;
unsigned int* nonstatic_oop_counts;
unsigned int nonstatic_oop_map_count;
unsigned int total_oop_map_count;
int instance_size;
int nonstatic_field_size;
int static_field_size;
bool has_nonstatic_fields;
};
OopMapBlocksBuilder::OopMapBlocksBuilder(unsigned int max_blocks) {
_max_nonstatic_oop_maps = max_blocks;
_nonstatic_oop_map_count = 0;
if (max_blocks == 0) {
_nonstatic_oop_maps = NULL;
} else {
_nonstatic_oop_maps =
NEW_RESOURCE_ARRAY(OopMapBlock, _max_nonstatic_oop_maps);
memset(_nonstatic_oop_maps, 0, sizeof(OopMapBlock) * max_blocks);
}
}
OopMapBlock* OopMapBlocksBuilder::last_oop_map() const {
assert(_nonstatic_oop_map_count > 0, "Has no oop maps");
return _nonstatic_oop_maps + (_nonstatic_oop_map_count - 1);
}
// addition of super oop maps
void OopMapBlocksBuilder::initialize_inherited_blocks(OopMapBlock* blocks, unsigned int nof_blocks) {
assert(nof_blocks && _nonstatic_oop_map_count == 0 &&
nof_blocks <= _max_nonstatic_oop_maps, "invariant");
memcpy(_nonstatic_oop_maps, blocks, sizeof(OopMapBlock) * nof_blocks);
_nonstatic_oop_map_count += nof_blocks;
}
// collection of oops
void OopMapBlocksBuilder::add(int offset, int count) {
if (_nonstatic_oop_map_count == 0) {
_nonstatic_oop_map_count++;
}
OopMapBlock* nonstatic_oop_map = last_oop_map();
if (nonstatic_oop_map->count() == 0) { // Unused map, set it up
nonstatic_oop_map->set_offset(offset);
nonstatic_oop_map->set_count(count);
} else if (nonstatic_oop_map->is_contiguous(offset)) { // contiguous, add
nonstatic_oop_map->increment_count(count);
} else { // Need a new one...
_nonstatic_oop_map_count++;
assert(_nonstatic_oop_map_count <= _max_nonstatic_oop_maps, "range check");
nonstatic_oop_map = last_oop_map();
nonstatic_oop_map->set_offset(offset);
nonstatic_oop_map->set_count(count);
}
}
// general purpose copy, e.g. into allocated instanceKlass
void OopMapBlocksBuilder::copy(OopMapBlock* dst) {
if (_nonstatic_oop_map_count != 0) {
memcpy(dst, _nonstatic_oop_maps, sizeof(OopMapBlock) * _nonstatic_oop_map_count);
}
}
// Sort and compact adjacent blocks
void OopMapBlocksBuilder::compact() {
if (_nonstatic_oop_map_count <= 1) {
return;
}
/*
* Since field layout sneeks in oops before values, we will be able to condense
* blocks. There is potential to compact between super, own refs and values
* containing refs.
*
* Currently compaction is slightly limited due to values being 8 byte aligned.
* This may well change: FixMe if it doesn't, the code below is fairly general purpose
* and maybe it doesn't need to be.
*/
qsort(_nonstatic_oop_maps, _nonstatic_oop_map_count, sizeof(OopMapBlock),
(_sort_Fn)OopMapBlock::compare_offset);
if (_nonstatic_oop_map_count < 2) {
return;
}
// Make a temp copy, and iterate through and copy back into the original
ResourceMark rm;
OopMapBlock* oop_maps_copy =
NEW_RESOURCE_ARRAY(OopMapBlock, _nonstatic_oop_map_count);
OopMapBlock* oop_maps_copy_end = oop_maps_copy + _nonstatic_oop_map_count;
copy(oop_maps_copy);
OopMapBlock* nonstatic_oop_map = _nonstatic_oop_maps;
unsigned int new_count = 1;
oop_maps_copy++;
while(oop_maps_copy < oop_maps_copy_end) {
assert(nonstatic_oop_map->offset() < oop_maps_copy->offset(), "invariant");
if (nonstatic_oop_map->is_contiguous(oop_maps_copy->offset())) {
nonstatic_oop_map->increment_count(oop_maps_copy->count());
} else {
nonstatic_oop_map++;
new_count++;
nonstatic_oop_map->set_offset(oop_maps_copy->offset());
nonstatic_oop_map->set_count(oop_maps_copy->count());
}
oop_maps_copy++;
}
assert(new_count <= _nonstatic_oop_map_count, "end up with more maps after compact() ?");
_nonstatic_oop_map_count = new_count;
}
void OopMapBlocksBuilder::print_on(outputStream* st) const {
st->print_cr(" OopMapBlocks: %3d /%3d", _nonstatic_oop_map_count, _max_nonstatic_oop_maps);
if (_nonstatic_oop_map_count > 0) {
OopMapBlock* map = _nonstatic_oop_maps;
OopMapBlock* last_map = last_oop_map();
assert(map <= last_map, "Last less than first");
while (map <= last_map) {
st->print_cr(" Offset: %3d -%3d Count: %3d", map->offset(),
map->offset() + map->offset_span() - heapOopSize, map->count());
map++;
}
}
}
void OopMapBlocksBuilder::print_value_on(outputStream* st) const {
print_on(st);
}
// Layout fields and fill in FieldLayoutInfo. Could use more refactoring!
void ClassFileParser::layout_fields(ConstantPool* cp,
@ -4100,16 +4176,15 @@ void ClassFileParser::layout_fields(ConstantPool* cp,
// count[i] oops following. Before we know how many regions are required,
// we pessimistically allocate the maps to fit all the oops into the
// distinct regions.
//
// TODO: We add +1 to always allocate non-zero resource arrays; we need
// to figure out if we still need to do this.
unsigned int nonstatic_oop_map_count = 0;
unsigned int max_nonstatic_oop_maps = fac->count[NONSTATIC_OOP] + 1;
int* nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, int, max_nonstatic_oop_maps);
unsigned int* const nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, unsigned int, max_nonstatic_oop_maps);
int super_oop_map_count = (_super_klass == NULL) ? 0 :_super_klass->nonstatic_oop_map_count();
int max_oop_map_count = super_oop_map_count + fac->count[NONSTATIC_OOP];
OopMapBlocksBuilder* nonstatic_oop_maps = new OopMapBlocksBuilder(max_oop_map_count);
if (super_oop_map_count > 0) {
nonstatic_oop_maps->initialize_inherited_blocks(_super_klass->start_of_nonstatic_oop_maps(),
_super_klass->nonstatic_oop_map_count());
}
int first_nonstatic_oop_offset = 0; // will be set for first oop field
@ -4260,26 +4335,7 @@ void ClassFileParser::layout_fields(ConstantPool* cp,
real_offset = next_nonstatic_oop_offset;
next_nonstatic_oop_offset += heapOopSize;
}
// Record this oop in the oop maps
if( nonstatic_oop_map_count > 0 &&
nonstatic_oop_offsets[nonstatic_oop_map_count - 1] ==
real_offset -
int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) *
heapOopSize ) {
// This oop is adjacent to the previous one, add to current oop map
assert(nonstatic_oop_map_count - 1 < max_nonstatic_oop_maps, "range check");
nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1;
} else {
// This oop is not adjacent to the previous one, create new oop map
assert(nonstatic_oop_map_count < max_nonstatic_oop_maps, "range check");
nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset;
nonstatic_oop_counts [nonstatic_oop_map_count] = 1;
nonstatic_oop_map_count += 1;
if( first_nonstatic_oop_offset == 0 ) { // Undefined
first_nonstatic_oop_offset = real_offset;
}
}
nonstatic_oop_maps->add(real_offset, 1);
break;
case NONSTATIC_BYTE:
if( nonstatic_byte_space_count > 0 ) {
@ -4392,26 +4448,7 @@ void ClassFileParser::layout_fields(ConstantPool* cp,
next_nonstatic_padded_offset = align_up(next_nonstatic_padded_offset, heapOopSize);
real_offset = next_nonstatic_padded_offset;
next_nonstatic_padded_offset += heapOopSize;
// Record this oop in the oop maps
if( nonstatic_oop_map_count > 0 &&
nonstatic_oop_offsets[nonstatic_oop_map_count - 1] ==
real_offset -
int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) *
heapOopSize ) {
// This oop is adjacent to the previous one, add to current oop map
assert(nonstatic_oop_map_count - 1 < max_nonstatic_oop_maps, "range check");
nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1;
} else {
// This oop is not adjacent to the previous one, create new oop map
assert(nonstatic_oop_map_count < max_nonstatic_oop_maps, "range check");
nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset;
nonstatic_oop_counts [nonstatic_oop_map_count] = 1;
nonstatic_oop_map_count += 1;
if( first_nonstatic_oop_offset == 0 ) { // Undefined
first_nonstatic_oop_offset = real_offset;
}
}
nonstatic_oop_maps->add(real_offset, 1);
break;
default:
@ -4475,9 +4512,7 @@ void ClassFileParser::layout_fields(ConstantPool* cp,
(nonstatic_fields_count > 0), "double-check nonstatic start/end");
// Number of non-static oop map blocks allocated at end of klass.
const unsigned int total_oop_map_count =
compute_oop_map_count(_super_klass, nonstatic_oop_map_count,
first_nonstatic_oop_offset);
nonstatic_oop_maps->compact();
#ifndef PRODUCT
if (PrintFieldLayout) {
@ -4492,58 +4527,13 @@ void ClassFileParser::layout_fields(ConstantPool* cp,
#endif
// Pass back information needed for InstanceKlass creation
info->nonstatic_oop_offsets = nonstatic_oop_offsets;
info->nonstatic_oop_counts = nonstatic_oop_counts;
info->nonstatic_oop_map_count = nonstatic_oop_map_count;
info->total_oop_map_count = total_oop_map_count;
info->instance_size = instance_size;
info->static_field_size = static_field_size;
info->nonstatic_field_size = nonstatic_field_size;
info->has_nonstatic_fields = has_nonstatic_fields;
info->oop_map_blocks = nonstatic_oop_maps;
info->_instance_size = instance_size;
info->_static_field_size = static_field_size;
info->_nonstatic_field_size = nonstatic_field_size;
info->_has_nonstatic_fields = has_nonstatic_fields;
}
static void fill_oop_maps(const InstanceKlass* k,
unsigned int nonstatic_oop_map_count,
const int* nonstatic_oop_offsets,
const unsigned int* nonstatic_oop_counts) {
assert(k != NULL, "invariant");
OopMapBlock* this_oop_map = k->start_of_nonstatic_oop_maps();
const InstanceKlass* const super = k->superklass();
const unsigned int super_count = super ? super->nonstatic_oop_map_count() : 0;
if (super_count > 0) {
// Copy maps from superklass
OopMapBlock* super_oop_map = super->start_of_nonstatic_oop_maps();
for (unsigned int i = 0; i < super_count; ++i) {
*this_oop_map++ = *super_oop_map++;
}
}
if (nonstatic_oop_map_count > 0) {
if (super_count + nonstatic_oop_map_count > k->nonstatic_oop_map_count()) {
// The counts differ because there is no gap between superklass's last oop
// field and the first local oop field. Extend the last oop map copied
// from the superklass instead of creating new one.
nonstatic_oop_map_count--;
nonstatic_oop_offsets++;
this_oop_map--;
this_oop_map->set_count(this_oop_map->count() + *nonstatic_oop_counts++);
this_oop_map++;
}
// Add new map blocks, fill them
while (nonstatic_oop_map_count-- > 0) {
this_oop_map->set_offset(*nonstatic_oop_offsets++);
this_oop_map->set_count(*nonstatic_oop_counts++);
this_oop_map++;
}
assert(k->start_of_nonstatic_oop_maps() + k->nonstatic_oop_map_count() ==
this_oop_map, "sanity");
}
}
void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) {
assert(ik != NULL, "invariant");
@ -5498,17 +5488,17 @@ int ClassFileParser::verify_legal_method_signature(const Symbol* name,
int ClassFileParser::static_field_size() const {
assert(_field_info != NULL, "invariant");
return _field_info->static_field_size;
return _field_info->_static_field_size;
}
int ClassFileParser::total_oop_map_count() const {
assert(_field_info != NULL, "invariant");
return _field_info->total_oop_map_count;
return _field_info->oop_map_blocks->_nonstatic_oop_map_count;
}
jint ClassFileParser::layout_size() const {
assert(_field_info != NULL, "invariant");
return _field_info->instance_size;
return _field_info->_instance_size;
}
static void check_methods_for_intrinsics(const InstanceKlass* ik,
@ -5652,19 +5642,19 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
set_klass_to_deallocate(ik);
assert(_field_info != NULL, "invariant");
assert(ik->static_field_size() == _field_info->static_field_size, "sanity");
assert(ik->nonstatic_oop_map_count() == _field_info->total_oop_map_count,
"sanity");
assert(ik->static_field_size() == _field_info->_static_field_size, "sanity");
assert(ik->nonstatic_oop_map_count() == _field_info->oop_map_blocks->_nonstatic_oop_map_count,
"sanity");
assert(ik->is_instance_klass(), "sanity");
assert(ik->size_helper() == _field_info->instance_size, "sanity");
assert(ik->size_helper() == _field_info->_instance_size, "sanity");
// Fill in information already parsed
ik->set_should_verify_class(_need_verify);
// Not yet: supers are done below to support the new subtype-checking fields
ik->set_nonstatic_field_size(_field_info->nonstatic_field_size);
ik->set_has_nonstatic_fields(_field_info->has_nonstatic_fields);
ik->set_nonstatic_field_size(_field_info->_nonstatic_field_size);
ik->set_has_nonstatic_fields(_field_info->_has_nonstatic_fields);
assert(_fac != NULL, "invariant");
ik->set_static_oop_field_count(_fac->count[STATIC_OOP]);
@ -5755,10 +5745,15 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
// Compute transitive closure of interfaces this class implements
// Do final class setup
fill_oop_maps(ik,
_field_info->nonstatic_oop_map_count,
_field_info->nonstatic_oop_offsets,
_field_info->nonstatic_oop_counts);
OopMapBlocksBuilder* oop_map_blocks = _field_info->oop_map_blocks;
if (oop_map_blocks->_nonstatic_oop_map_count > 0) {
oop_map_blocks->copy(ik->start_of_nonstatic_oop_maps());
}
if (_has_contended_fields || _parsed_annotations->is_contended() ||
( _super_klass != NULL && _super_klass->has_contended_annotations())) {
ik->set_has_contended_annotations(true);
}
// Fill in has_finalizer, has_vanilla_constructor, and layout_helper
set_precomputed_flags(ik);
@ -6001,6 +5996,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_has_nonstatic_concrete_methods(false),
_declares_nonstatic_concrete_methods(false),
_has_final_method(false),
_has_contended_fields(false),
_has_finalizer(false),
_has_empty_finalizer(false),
_has_vanilla_constructor(false),
@ -6478,7 +6474,13 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st
assert(_parsed_annotations != NULL, "invariant");
_field_info = new FieldLayoutInfo();
layout_fields(cp, _fac, _parsed_annotations, _field_info, CHECK);
if (UseNewFieldLayout) {
FieldLayoutBuilder lb(class_name(), super_klass(), _cp, _fields,
_parsed_annotations->is_contended(), _field_info);
lb.build_layout();
} else {
layout_fields(cp, _fac, _parsed_annotations, _field_info, CHECK);
}
// Compute reference typ
_rt = (NULL ==_super_klass) ? REF_NONE : _super_klass->reference_type();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@
#include "memory/referenceType.hpp"
#include "oops/annotations.hpp"
#include "oops/constantPool.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/typeArrayOop.hpp"
#include "utilities/accessFlags.hpp"
@ -45,17 +46,46 @@ class InstanceKlass;
class RecordComponent;
class Symbol;
class TempNewSymbol;
class FieldLayoutBuilder;
// Utility to collect and compact oop maps during layout
class OopMapBlocksBuilder : public ResourceObj {
public:
OopMapBlock* _nonstatic_oop_maps;
unsigned int _nonstatic_oop_map_count;
unsigned int _max_nonstatic_oop_maps;
OopMapBlocksBuilder(unsigned int max_blocks);
OopMapBlock* last_oop_map() const;
void initialize_inherited_blocks(OopMapBlock* blocks, unsigned int nof_blocks);
void add(int offset, int count);
void copy(OopMapBlock* dst);
void compact();
void print_on(outputStream* st) const;
void print_value_on(outputStream* st) const;
};
// Values needed for oopmap and InstanceKlass creation
class FieldLayoutInfo : public ResourceObj {
public:
OopMapBlocksBuilder* oop_map_blocks;
int _instance_size;
int _nonstatic_field_size;
int _static_field_size;
bool _has_nonstatic_fields;
};
// Parser for for .class files
//
// The bytes describing the class file structure is read from a Stream object
class ClassFileParser {
friend class FieldLayoutBuilder;
friend class FieldLayout;
class ClassAnnotationCollector;
class FieldAllocationCount;
class FieldAnnotationCollector;
class FieldLayoutInfo;
class ClassAnnotationCollector;
class FieldAllocationCount;
class FieldAnnotationCollector;
public:
// The ClassFileParser has an associated "publicity" level
@ -161,6 +191,7 @@ class ClassFileParser {
bool _has_nonstatic_concrete_methods;
bool _declares_nonstatic_concrete_methods;
bool _has_final_method;
bool _has_contended_fields;
// precomputed flags
bool _has_finalizer;

View File

@ -0,0 +1,780 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "jvm.h"
#include "classfile/classFileParser.hpp"
#include "classfile/fieldLayoutBuilder.hpp"
#include "memory/resourceArea.hpp"
#include "oops/array.hpp"
#include "oops/fieldStreams.inline.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "oops/klass.inline.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
LayoutRawBlock::LayoutRawBlock(Kind kind, int size) :
_next_block(NULL),
_prev_block(NULL),
_kind(kind),
_offset(-1),
_alignment(1),
_size(size),
_field_index(-1),
_is_reference(false) {
assert(kind == EMPTY || kind == RESERVED || kind == PADDING || kind == INHERITED,
"Otherwise, should use the constructor with a field index argument");
assert(size > 0, "Sanity check");
}
LayoutRawBlock::LayoutRawBlock(int index, Kind kind, int size, int alignment, bool is_reference) :
_next_block(NULL),
_prev_block(NULL),
_kind(kind),
_offset(-1),
_alignment(alignment),
_size(size),
_field_index(index),
_is_reference(is_reference) {
assert(kind == REGULAR || kind == FLATTENED || kind == INHERITED,
"Other kind do not have a field index");
assert(size > 0, "Sanity check");
assert(alignment > 0, "Sanity check");
}
bool LayoutRawBlock::fit(int size, int alignment) {
int adjustment = 0;
if ((_offset % alignment) != 0) {
adjustment = alignment - (_offset % alignment);
}
return _size >= size + adjustment;
}
FieldGroup::FieldGroup(int contended_group) :
_next(NULL),
_primitive_fields(NULL),
_oop_fields(NULL),
_contended_group(contended_group), // -1 means no contended group, 0 means default contended group
_oop_count(0) {}
void FieldGroup::add_primitive_field(AllFieldStream fs, BasicType type) {
int size = type2aelembytes(type);
LayoutRawBlock* block = new LayoutRawBlock(fs.index(), LayoutRawBlock::REGULAR, size, size /* alignment == size for primitive types */, false);
if (_primitive_fields == NULL) {
_primitive_fields = new(ResourceObj::RESOURCE_AREA, mtInternal) GrowableArray<LayoutRawBlock*>(INITIAL_LIST_SIZE);
}
_primitive_fields->append(block);
}
void FieldGroup::add_oop_field(AllFieldStream fs) {
int size = type2aelembytes(T_OBJECT);
LayoutRawBlock* block = new LayoutRawBlock(fs.index(), LayoutRawBlock::REGULAR, size, size /* alignment == size for oops */, true);
if (_oop_fields == NULL) {
_oop_fields = new(ResourceObj::RESOURCE_AREA, mtInternal) GrowableArray<LayoutRawBlock*>(INITIAL_LIST_SIZE);
}
_oop_fields->append(block);
_oop_count++;
}
void FieldGroup::sort_by_size() {
if (_primitive_fields != NULL) {
_primitive_fields->sort(LayoutRawBlock::compare_size_inverted);
}
}
FieldLayout::FieldLayout(Array<u2>* fields, ConstantPool* cp) :
_fields(fields),
_cp(cp),
_blocks(NULL),
_start(_blocks),
_last(_blocks) {}
void FieldLayout::initialize_static_layout() {
_blocks = new LayoutRawBlock(LayoutRawBlock::EMPTY, INT_MAX);
_blocks->set_offset(0);
_last = _blocks;
_start = _blocks;
// Note: at this stage, InstanceMirrorKlass::offset_of_static_fields() could be zero, because
// during bootstrapping, the size of the java.lang.Class is still not known when layout
// of static field is computed. Field offsets are fixed later when the size is known
// (see java_lang_Class::fixup_mirror())
if (InstanceMirrorKlass::offset_of_static_fields() > 0) {
insert(first_empty_block(), new LayoutRawBlock(LayoutRawBlock::RESERVED, InstanceMirrorKlass::offset_of_static_fields()));
_blocks->set_offset(0);
}
}
void FieldLayout::initialize_instance_layout(const InstanceKlass* super_klass) {
if (super_klass == NULL) {
_blocks = new LayoutRawBlock(LayoutRawBlock::EMPTY, INT_MAX);
_blocks->set_offset(0);
_last = _blocks;
_start = _blocks;
insert(first_empty_block(), new LayoutRawBlock(LayoutRawBlock::RESERVED, instanceOopDesc::base_offset_in_bytes()));
} else {
reconstruct_layout(super_klass);
fill_holes(super_klass);
if (UseEmptySlotsInSupers && !super_klass->has_contended_annotations()) {
_start = _blocks; // Setting _start to _blocks instead of _last would allow subclasses
// to allocate fields in empty slots of their super classes
} else {
_start = _last;
}
}
}
LayoutRawBlock* FieldLayout::first_field_block() {
LayoutRawBlock* block = _start;
while (block->kind() != LayoutRawBlock::INHERITED && block->kind() != LayoutRawBlock::REGULAR
&& block->kind() != LayoutRawBlock::FLATTENED && block->kind() != LayoutRawBlock::PADDING) {
block = block->next_block();
}
return block;
}
// Insert a set of fields into a layout using a best-fit strategy.
// For each field, search for the smallest empty slot able to fit the field
// (satisfying both size and alignment requirements), if none is found,
// add the field at the end of the layout.
// Fields cannot be inserted before the block specified in the "start" argument
void FieldLayout::add(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start) {
if (list == NULL) return;
if (start == NULL) start = this->_start;
bool last_search_success = false;
int last_size = 0;
int last_alignment = 0;
for (int i = 0; i < list->length(); i ++) {
LayoutRawBlock* b = list->at(i);
LayoutRawBlock* cursor = NULL;
LayoutRawBlock* candidate = NULL;
// if start is the last block, just append the field
if (start == last_block()) {
candidate = last_block();
}
// Before iterating over the layout to find an empty slot fitting the field's requirements,
// check if the previous field had the same requirements and if the search for a fitting slot
// was successful. If the requirements were the same but the search failed, a new search will
// fail the same way, so just append the field at the of the layout.
else if (b->size() == last_size && b->alignment() == last_alignment && !last_search_success) {
candidate = last_block();
} else {
// Iterate over the layout to find an empty slot fitting the field's requirements
last_size = b->size();
last_alignment = b->alignment();
cursor = last_block()->prev_block();
assert(cursor != NULL, "Sanity check");
last_search_success = true;
while (cursor != start) {
if (cursor->kind() == LayoutRawBlock::EMPTY && cursor->fit(b->size(), b->alignment())) {
if (candidate == NULL || cursor->size() < candidate->size()) {
candidate = cursor;
}
}
cursor = cursor->prev_block();
}
if (candidate == NULL) {
candidate = last_block();
last_search_success = false;
}
assert(candidate != NULL, "Candidate must not be null");
assert(candidate->kind() == LayoutRawBlock::EMPTY, "Candidate must be an empty block");
assert(candidate->fit(b->size(), b->alignment()), "Candidate must be able to store the block");
}
insert_field_block(candidate, b);
}
}
// Used for classes with hard coded field offsets, insert a field at the specified offset */
void FieldLayout::add_field_at_offset(LayoutRawBlock* block, int offset, LayoutRawBlock* start) {
assert(block != NULL, "Sanity check");
block->set_offset(offset);
if (start == NULL) {
start = this->_start;
}
LayoutRawBlock* slot = start;
while (slot != NULL) {
if ((slot->offset() <= block->offset() && (slot->offset() + slot->size()) > block->offset()) ||
slot == _last){
assert(slot->kind() == LayoutRawBlock::EMPTY, "Matching slot must be an empty slot");
assert(slot->size() >= block->offset() + block->size() ,"Matching slot must be big enough");
if (slot->offset() < block->offset()) {
int adjustment = block->offset() - slot->offset();
LayoutRawBlock* adj = new LayoutRawBlock(LayoutRawBlock::EMPTY, adjustment);
insert(slot, adj);
}
insert(slot, block);
if (slot->size() == 0) {
remove(slot);
}
FieldInfo::from_field_array(_fields, block->field_index())->set_offset(block->offset());
return;
}
slot = slot->next_block();
}
fatal("Should have found a matching slot above, corrupted layout or invalid offset");
}
// The allocation logic uses a best fit strategy: the set of fields is allocated
// in the first empty slot big enough to contain the whole set ((including padding
// to fit alignment constraints).
void FieldLayout::add_contiguously(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start) {
if (list == NULL) return;
if (start == NULL) {
start = _start;
}
// This code assumes that if the first block is well aligned, the following
// blocks would naturally be well aligned (no need for adjustment)
int size = 0;
for (int i = 0; i < list->length(); i++) {
size += list->at(i)->size();
}
LayoutRawBlock* candidate = NULL;
if (start == last_block()) {
candidate = last_block();
} else {
LayoutRawBlock* first = list->at(0);
candidate = last_block()->prev_block();
while (candidate->kind() != LayoutRawBlock::EMPTY || !candidate->fit(size, first->alignment())) {
if (candidate == start) {
candidate = last_block();
break;
}
candidate = candidate->prev_block();
}
assert(candidate != NULL, "Candidate must not be null");
assert(candidate->kind() == LayoutRawBlock::EMPTY, "Candidate must be an empty block");
assert(candidate->fit(size, first->alignment()), "Candidate must be able to store the whole contiguous block");
}
for (int i = 0; i < list->length(); i++) {
LayoutRawBlock* b = list->at(i);
insert_field_block(candidate, b);
assert((candidate->offset() % b->alignment() == 0), "Contiguous blocks must be naturally well aligned");
}
}
LayoutRawBlock* FieldLayout::insert_field_block(LayoutRawBlock* slot, LayoutRawBlock* block) {
assert(slot->kind() == LayoutRawBlock::EMPTY, "Blocks can only be inserted in empty blocks");
if (slot->offset() % block->alignment() != 0) {
int adjustment = block->alignment() - (slot->offset() % block->alignment());
LayoutRawBlock* adj = new LayoutRawBlock(LayoutRawBlock::EMPTY, adjustment);
insert(slot, adj);
}
insert(slot, block);
if (slot->size() == 0) {
remove(slot);
}
FieldInfo::from_field_array(_fields, block->field_index())->set_offset(block->offset());
return block;
}
void FieldLayout::reconstruct_layout(const InstanceKlass* ik) {
GrowableArray<LayoutRawBlock*>* all_fields = new GrowableArray<LayoutRawBlock*>(32);
while (ik != NULL) {
for (AllFieldStream fs(ik->fields(), ik->constants()); !fs.done(); fs.next()) {
BasicType type = Signature::basic_type(fs.signature());
// distinction between static and non-static fields is missing
if (fs.access_flags().is_static()) continue;
int size = type2aelembytes(type);
// INHERITED blocks are marked as non-reference because oop_maps are handled by their holder class
LayoutRawBlock* block = new LayoutRawBlock(fs.index(), LayoutRawBlock::INHERITED, size, size, false);
block->set_offset(fs.offset());
all_fields->append(block);
}
ik = ik->super() == NULL ? NULL : InstanceKlass::cast(ik->super());
}
all_fields->sort(LayoutRawBlock::compare_offset);
_blocks = new LayoutRawBlock(LayoutRawBlock::RESERVED, instanceOopDesc::base_offset_in_bytes());
_blocks->set_offset(0);
_last = _blocks;
for(int i = 0; i < all_fields->length(); i++) {
LayoutRawBlock* b = all_fields->at(i);
_last->set_next_block(b);
b->set_prev_block(_last);
_last = b;
}
_start = _blocks;
}
// Called during the reconstruction of a layout, after fields from super
// classes have been inserted. It fills unused slots between inserted fields
// with EMPTY blocks, so the regular field insertion methods would work.
// This method handles classes with @Contended annotations differently
// by inserting PADDING blocks instead of EMPTY block to prevent subclasses'
// fields to interfere with contended fields/classes.
void FieldLayout::fill_holes(const InstanceKlass* super_klass) {
assert(_blocks != NULL, "Sanity check");
assert(_blocks->offset() == 0, "first block must be at offset zero");
LayoutRawBlock::Kind filling_type = super_klass->has_contended_annotations() ? LayoutRawBlock::PADDING: LayoutRawBlock::EMPTY;
LayoutRawBlock* b = _blocks;
while (b->next_block() != NULL) {
if (b->next_block()->offset() > (b->offset() + b->size())) {
int size = b->next_block()->offset() - (b->offset() + b->size());
LayoutRawBlock* empty = new LayoutRawBlock(filling_type, size);
empty->set_offset(b->offset() + b->size());
empty->set_next_block(b->next_block());
b->next_block()->set_prev_block(empty);
b->set_next_block(empty);
empty->set_prev_block(b);
}
b = b->next_block();
}
assert(b->next_block() == NULL, "Invariant at this point");
assert(b->kind() != LayoutRawBlock::EMPTY, "Sanity check");
// If the super class has @Contended annotation, a padding block is
// inserted at the end to ensure that fields from the subclasses won't share
// the cache line of the last field of the contended class
if (super_klass->has_contended_annotations()) {
LayoutRawBlock* p = new LayoutRawBlock(LayoutRawBlock::PADDING, ContendedPaddingWidth);
p->set_offset(b->offset() + b->size());
b->set_next_block(p);
p->set_prev_block(b);
b = p;
}
if (!UseEmptySlotsInSupers) {
// Add an empty slots to align fields of the subclass on a heapOopSize boundary
// in order to emulate the behavior of the previous algorithm
int align = (b->offset() + b->size()) % heapOopSize;
if (align != 0) {
int sz = heapOopSize - align;
LayoutRawBlock* p = new LayoutRawBlock(LayoutRawBlock::EMPTY, sz);
p->set_offset(b->offset() + b->size());
b->set_next_block(p);
p->set_prev_block(b);
b = p;
}
}
LayoutRawBlock* last = new LayoutRawBlock(LayoutRawBlock::EMPTY, INT_MAX);
last->set_offset(b->offset() + b->size());
assert(last->offset() > 0, "Sanity check");
b->set_next_block(last);
last->set_prev_block(b);
_last = last;
}
LayoutRawBlock* FieldLayout::insert(LayoutRawBlock* slot, LayoutRawBlock* block) {
assert(slot->kind() == LayoutRawBlock::EMPTY, "Blocks can only be inserted in empty blocks");
assert(slot->offset() % block->alignment() == 0, "Incompatible alignment");
block->set_offset(slot->offset());
slot->set_offset(slot->offset() + block->size());
assert((slot->size() - block->size()) < slot->size(), "underflow checking");
assert(slot->size() - block->size() >= 0, "no negative size allowed");
slot->set_size(slot->size() - block->size());
block->set_prev_block(slot->prev_block());
block->set_next_block(slot);
slot->set_prev_block(block);
if (block->prev_block() != NULL) {
block->prev_block()->set_next_block(block);
}
if (_blocks == slot) {
_blocks = block;
}
return block;
}
void FieldLayout::remove(LayoutRawBlock* block) {
assert(block != NULL, "Sanity check");
assert(block != _last, "Sanity check");
if (_blocks == block) {
_blocks = block->next_block();
if (_blocks != NULL) {
_blocks->set_prev_block(NULL);
}
} else {
assert(block->prev_block() != NULL, "_prev should be set for non-head blocks");
block->prev_block()->set_next_block(block->next_block());
block->next_block()->set_prev_block(block->prev_block());
}
if (block == _start) {
_start = block->prev_block();
}
}
void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlass* super) {
ResourceMark rm;
LayoutRawBlock* b = _blocks;
while(b != _last) {
switch(b->kind()) {
case LayoutRawBlock::REGULAR: {
FieldInfo* fi = FieldInfo::from_field_array(_fields, b->field_index());
output->print_cr(" @%d \"%s\" %s %d/%d %s",
b->offset(),
fi->name(_cp)->as_C_string(),
fi->signature(_cp)->as_C_string(),
b->size(),
b->alignment(),
"REGULAR");
break;
}
case LayoutRawBlock::FLATTENED: {
FieldInfo* fi = FieldInfo::from_field_array(_fields, b->field_index());
output->print_cr(" @%d \"%s\" %s %d/%d %s",
b->offset(),
fi->name(_cp)->as_C_string(),
fi->signature(_cp)->as_C_string(),
b->size(),
b->alignment(),
"FLATTENED");
break;
}
case LayoutRawBlock::RESERVED: {
output->print_cr(" @%d %d/- %s",
b->offset(),
b->size(),
"RESERVED");
break;
}
case LayoutRawBlock::INHERITED: {
assert(!is_static, "Static fields are not inherited in layouts");
assert(super != NULL, "super klass must be provided to retrieve inherited fields info");
bool found = false;
const InstanceKlass* ik = super;
while (!found && ik != NULL) {
for (AllFieldStream fs(ik->fields(), ik->constants()); !fs.done(); fs.next()) {
if (fs.offset() == b->offset()) {
output->print_cr(" @%d \"%s\" %s %d/%d %s",
b->offset(),
fs.name()->as_C_string(),
fs.signature()->as_C_string(),
b->size(),
b->size(), // so far, alignment constraint == size, will change with Valhalla
"INHERITED");
found = true;
break;
}
}
ik = ik->java_super();
}
break;
}
case LayoutRawBlock::EMPTY:
output->print_cr(" @%d %d/1 %s",
b->offset(),
b->size(),
"EMPTY");
break;
case LayoutRawBlock::PADDING:
output->print_cr(" @%d %d/1 %s",
b->offset(),
b->size(),
"PADDING");
break;
}
b = b->next_block();
}
}
FieldLayoutBuilder::FieldLayoutBuilder(const Symbol* classname, const InstanceKlass* super_klass, ConstantPool* constant_pool,
Array<u2>* fields, bool is_contended, FieldLayoutInfo* info) :
_classname(classname),
_super_klass(super_klass),
_constant_pool(constant_pool),
_fields(fields),
_info(info),
_root_group(NULL),
_contended_groups(GrowableArray<FieldGroup*>(8)),
_static_fields(NULL),
_layout(NULL),
_static_layout(NULL),
_nonstatic_oopmap_count(0),
_alignment(-1),
_has_nonstatic_fields(false),
_is_contended(is_contended) {}
FieldGroup* FieldLayoutBuilder::get_or_create_contended_group(int g) {
assert(g > 0, "must only be called for named contended groups");
FieldGroup* fg = NULL;
for (int i = 0; i < _contended_groups.length(); i++) {
fg = _contended_groups.at(i);
if (fg->contended_group() == g) return fg;
}
fg = new FieldGroup(g);
_contended_groups.append(fg);
return fg;
}
void FieldLayoutBuilder::prologue() {
_layout = new FieldLayout(_fields, _constant_pool);
const InstanceKlass* super_klass = _super_klass;
_layout->initialize_instance_layout(super_klass);
if (super_klass != NULL) {
_has_nonstatic_fields = super_klass->has_nonstatic_fields();
}
_static_layout = new FieldLayout(_fields, _constant_pool);
_static_layout->initialize_static_layout();
_static_fields = new FieldGroup();
_root_group = new FieldGroup();
}
// Field sorting for regular classes:
// - fields are sorted in static and non-static fields
// - non-static fields are also sorted according to their contention group
// (support of the @Contended annotation)
// - @Contended annotation is ignored for static fields
void FieldLayoutBuilder::regular_field_sorting() {
for (AllFieldStream fs(_fields, _constant_pool); !fs.done(); fs.next()) {
FieldGroup* group = NULL;
if (fs.access_flags().is_static()) {
group = _static_fields;
} else {
_has_nonstatic_fields = true;
if (fs.is_contended()) {
int g = fs.contended_group();
if (g == 0) {
group = new FieldGroup(true);
_contended_groups.append(group);
} else {
group = get_or_create_contended_group(g);
}
} else {
group = _root_group;
}
}
assert(group != NULL, "invariant");
BasicType type = Signature::basic_type(fs.signature());
switch(type) {
case T_BYTE:
case T_CHAR:
case T_DOUBLE:
case T_FLOAT:
case T_INT:
case T_LONG:
case T_SHORT:
case T_BOOLEAN:
group->add_primitive_field(fs, type);
break;
case T_OBJECT:
case T_ARRAY:
if (group != _static_fields) _nonstatic_oopmap_count++;
group->add_oop_field(fs);
break;
default:
fatal("Something wrong?");
}
}
_root_group->sort_by_size();
_static_fields->sort_by_size();
if (!_contended_groups.is_empty()) {
for (int i = 0; i < _contended_groups.length(); i++) {
_contended_groups.at(i)->sort_by_size();
}
}
}
void FieldLayoutBuilder::insert_contended_padding(LayoutRawBlock* slot) {
if (ContendedPaddingWidth > 0) {
LayoutRawBlock* padding = new LayoutRawBlock(LayoutRawBlock::PADDING, ContendedPaddingWidth);
_layout->insert(slot, padding);
}
}
// Computation of regular classes layout is an evolution of the previous default layout
// (FieldAllocationStyle 1):
// - primitive fields are allocated first (from the biggest to the smallest)
// - then oop fields are allocated, either in existing gaps or at the end of
// the layout
void FieldLayoutBuilder::compute_regular_layout() {
bool need_tail_padding = false;
prologue();
regular_field_sorting();
if (_is_contended) {
_layout->set_start(_layout->last_block());
// insertion is currently easy because the current strategy doesn't try to fill holes
// in super classes layouts => the _start block is by consequence the _last_block
insert_contended_padding(_layout->start());
need_tail_padding = true;
}
_layout->add(_root_group->primitive_fields());
_layout->add(_root_group->oop_fields());
if (!_contended_groups.is_empty()) {
for (int i = 0; i < _contended_groups.length(); i++) {
FieldGroup* cg = _contended_groups.at(i);
LayoutRawBlock* start = _layout->last_block();
insert_contended_padding(start);
_layout->add(cg->primitive_fields(), start);
_layout->add(cg->oop_fields(), start);
need_tail_padding = true;
}
}
if (need_tail_padding) {
insert_contended_padding(_layout->last_block());
}
_static_layout->add_contiguously(this->_static_fields->oop_fields());
_static_layout->add(this->_static_fields->primitive_fields());
epilogue();
}
// Compute layout of the java/lang/ref/Reference class according
// to the hard coded offsets of its fields
void FieldLayoutBuilder::compute_java_lang_ref_Reference_layout() {
prologue();
regular_field_sorting();
assert(_contended_groups.is_empty(), "java.lang.Reference has no @Contended annotations");
assert(_root_group->primitive_fields() == NULL, "java.lang.Reference has no nonstatic primitive fields");
int field_count = 0;
int offset = -1;
for (int i = 0; i < _root_group->oop_fields()->length(); i++) {
LayoutRawBlock* b = _root_group->oop_fields()->at(i);
FieldInfo* fi = FieldInfo::from_field_array(_fields, b->field_index());
if (fi->name(_constant_pool)->equals("referent")) {
offset = java_lang_ref_Reference::referent_offset;
} else if (fi->name(_constant_pool)->equals("queue")) {
offset = java_lang_ref_Reference::queue_offset;
} else if (fi->name(_constant_pool)->equals("next")) {
offset = java_lang_ref_Reference::next_offset;
} else if (fi->name(_constant_pool)->equals("discovered")) {
offset = java_lang_ref_Reference::discovered_offset;
}
assert(offset != -1, "Unknown field");
_layout->add_field_at_offset(b, offset);
field_count++;
}
assert(field_count == 4, "Wrong number of fields in java.lang.ref.Reference");
_static_layout->add_contiguously(this->_static_fields->oop_fields());
_static_layout->add(this->_static_fields->primitive_fields());
epilogue();
}
// Compute layout of the boxing class according
// to the hard coded offsets of their fields
void FieldLayoutBuilder::compute_boxing_class_layout() {
prologue();
regular_field_sorting();
assert(_contended_groups.is_empty(), "Boxing classes have no @Contended annotations");
assert(_root_group->oop_fields() == NULL, "Boxing classes have no nonstatic oops fields");
int field_count = 0;
int offset = -1;
for (int i = 0; i < _root_group->primitive_fields()->length(); i++) {
LayoutRawBlock* b = _root_group->primitive_fields()->at(i);
FieldInfo* fi = FieldInfo::from_field_array(_fields, b->field_index());
assert(fi->name(_constant_pool)->equals("value"), "Boxing classes have a single nonstatic field named 'value'");
BasicType type = Signature::basic_type(fi->signature(_constant_pool));
offset = java_lang_boxing_object::value_offset_in_bytes(type);
assert(offset != -1, "Unknown field");
_layout->add_field_at_offset(b, offset);
field_count++;
}
assert(field_count == 1, "Wrong number of fields for a boxing class");
_static_layout->add_contiguously(this->_static_fields->oop_fields());
_static_layout->add(this->_static_fields->primitive_fields());
epilogue();
}
void FieldLayoutBuilder::epilogue() {
// Computing oopmaps
int super_oop_map_count = (_super_klass == NULL) ? 0 :_super_klass->nonstatic_oop_map_count();
int max_oop_map_count = super_oop_map_count + _nonstatic_oopmap_count;
OopMapBlocksBuilder* nonstatic_oop_maps =
new OopMapBlocksBuilder(max_oop_map_count);
if (super_oop_map_count > 0) {
nonstatic_oop_maps->initialize_inherited_blocks(_super_klass->start_of_nonstatic_oop_maps(),
_super_klass->nonstatic_oop_map_count());
}
if (_root_group->oop_fields() != NULL) {
for (int i = 0; i < _root_group->oop_fields()->length(); i++) {
LayoutRawBlock* b = _root_group->oop_fields()->at(i);
nonstatic_oop_maps->add(b->offset(), 1);
}
}
if (!_contended_groups.is_empty()) {
for (int i = 0; i < _contended_groups.length(); i++) {
FieldGroup* cg = _contended_groups.at(i);
if (cg->oop_count() > 0) {
assert(cg->oop_fields() != NULL && cg->oop_fields()->at(0) != NULL, "oop_count > 0 but no oop fields found");
nonstatic_oop_maps->add(cg->oop_fields()->at(0)->offset(), cg->oop_count());
}
}
}
nonstatic_oop_maps->compact();
int instance_end = align_up(_layout->last_block()->offset(), wordSize);
int static_fields_end = align_up(_static_layout->last_block()->offset(), wordSize);
int static_fields_size = (static_fields_end -
InstanceMirrorKlass::offset_of_static_fields()) / wordSize;
int nonstatic_field_end = align_up(_layout->last_block()->offset(), heapOopSize);
// Pass back information needed for InstanceKlass creation
_info->oop_map_blocks = nonstatic_oop_maps;
_info->_instance_size = align_object_size(instance_end / wordSize);
_info->_static_field_size = static_fields_size;
_info->_nonstatic_field_size = (nonstatic_field_end - instanceOopDesc::base_offset_in_bytes()) / heapOopSize;
_info->_has_nonstatic_fields = _has_nonstatic_fields;
if (PrintFieldLayout) {
ResourceMark rm;
tty->print_cr("Layout of class %s", _classname->as_C_string());
tty->print_cr("Instance fields:");
_layout->print(tty, false, _super_klass);
tty->print_cr("Static fields:");
_static_layout->print(tty, true, NULL);
tty->print_cr("Instance size = %d bytes", _info->_instance_size * wordSize);
tty->print_cr("---");
}
}
void FieldLayoutBuilder::build_layout() {
if (_classname == vmSymbols::java_lang_ref_Reference()) {
compute_java_lang_ref_Reference_layout();
} else if (_classname == vmSymbols::java_lang_Boolean() ||
_classname == vmSymbols::java_lang_Character() ||
_classname == vmSymbols::java_lang_Float() ||
_classname == vmSymbols::java_lang_Double() ||
_classname == vmSymbols::java_lang_Byte() ||
_classname == vmSymbols::java_lang_Short() ||
_classname == vmSymbols::java_lang_Integer() ||
_classname == vmSymbols::java_lang_Long()) {
compute_boxing_class_layout();
} else {
compute_regular_layout();
}
}

View File

@ -0,0 +1,267 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_CLASSFILE_FIELDLAYOUTBUILDER_HPP
#define SHARE_CLASSFILE_FIELDLAYOUTBUILDER_HPP
#include "classfile/classFileParser.hpp"
#include "classfile/classLoaderData.hpp"
#include "memory/allocation.hpp"
#include "oops/fieldStreams.hpp"
#include "utilities/growableArray.hpp"
// Classes below are used to compute the field layout of classes.
// A LayoutRawBlock describes an element of a layout.
// Each field is represented by a LayoutRawBlock.
// LayoutRawBlocks can also represent elements injected by the JVM:
// padding, empty blocks, inherited fields, etc.
// All LayoutRawBlocks must have a size and an alignment. The size is the
// exact size of the field expressed in bytes. The alignment is
// the alignment constraint of the field (1 for byte, 2 for short,
// 4 for int, 8 for long, etc.)
//
// LayoutRawBlock are designed to be used in two data structures:
// - a linked list in a layout (using _next_block, _prev_block)
// - a GrowableArray in field group (the growable array contains pointers to LayoutRawBlocks)
//
// next/prev pointers are included in the LayoutRawBlock class to narrow
// the number of allocation required during the computation of a layout.
//
class LayoutRawBlock : public ResourceObj {
public:
// Some code relies on the order of values below.
enum Kind {
EMPTY, // empty slot, space is taken from this to allocate fields
RESERVED, // reserved for JVM usage (for instance object header)
PADDING, // padding (because of alignment constraints or @Contended)
REGULAR, // primitive or oop field (including non-flattened inline fields)
FLATTENED, // flattened field
INHERITED // field(s) inherited from super classes
};
private:
LayoutRawBlock* _next_block;
LayoutRawBlock* _prev_block;
Kind _kind;
int _offset;
int _alignment;
int _size;
int _field_index;
bool _is_reference;
public:
LayoutRawBlock(Kind kind, int size);
LayoutRawBlock(int index, Kind kind, int size, int alignment, bool is_reference = false);
LayoutRawBlock* next_block() const { return _next_block; }
void set_next_block(LayoutRawBlock* next) { _next_block = next; }
LayoutRawBlock* prev_block() const { return _prev_block; }
void set_prev_block(LayoutRawBlock* prev) { _prev_block = prev; }
Kind kind() const { return _kind; }
int offset() const {
assert(_offset >= 0, "Must be initialized");
return _offset;
}
void set_offset(int offset) { _offset = offset; }
int alignment() const { return _alignment; }
int size() const { return _size; }
void set_size(int size) { _size = size; }
int field_index() const {
assert(_field_index != -1, "Must be initialized");
return _field_index;
}
bool is_reference() const { return _is_reference; }
bool fit(int size, int alignment);
static int compare_offset(LayoutRawBlock** x, LayoutRawBlock** y) { return (*x)->offset() - (*y)->offset(); }
// compare_size_inverted() returns the opposite of a regular compare method in order to
// sort fields in decreasing order.
// Note: with line types, the comparison should include alignment constraint if sizes are equals
static int compare_size_inverted(LayoutRawBlock** x, LayoutRawBlock** y) {
#ifdef _WINDOWS
// qsort() on Windows reverse the order of fields with the same size
// the extension of the comparison function below preserves this order
int diff = (*y)->size() - (*x)->size();
if (diff == 0) {
diff = (*x)->field_index() - (*y)->field_index();
}
return diff;
#else
return (*y)->size() - (*x)->size();
#endif // _WINDOWS
}
};
// A Field group represents a set of fields that have to be allocated together,
// this is the way the @Contended annotation is supported.
// Inside a FieldGroup, fields are sorted based on their kind: primitive,
// oop, or flattened.
//
class FieldGroup : public ResourceObj {
private:
FieldGroup* _next;
GrowableArray<LayoutRawBlock*>* _primitive_fields;
GrowableArray<LayoutRawBlock*>* _oop_fields;
int _contended_group;
int _oop_count;
static const int INITIAL_LIST_SIZE = 16;
public:
FieldGroup(int contended_group = -1);
FieldGroup* next() const { return _next; }
void set_next(FieldGroup* next) { _next = next; }
GrowableArray<LayoutRawBlock*>* primitive_fields() const { return _primitive_fields; }
GrowableArray<LayoutRawBlock*>* oop_fields() const { return _oop_fields; }
int contended_group() const { return _contended_group; }
int oop_count() const { return _oop_count; }
void add_primitive_field(AllFieldStream fs, BasicType type);
void add_oop_field(AllFieldStream fs);
void sort_by_size();
};
// The FieldLayout class represents a set of fields organized
// in a layout.
// An instance of FieldLayout can either represent the layout
// of non-static fields (used in an instance object) or the
// layout of static fields (to be included in the class mirror).
//
// _block is a pointer to a list of LayoutRawBlock ordered by increasing
// offsets.
// _start points to the LayoutRawBlock with the first offset that can
// be used to allocate fields of the current class
// _last points to the last LayoutRawBlock of the list. In order to
// simplify the code, the LayoutRawBlock list always ends with an
// EMPTY block (the kind of LayoutRawBlock from which space is taken
// to allocate fields) with a size big enough to satisfy all
// field allocations.
//
class FieldLayout : public ResourceObj {
private:
Array<u2>* _fields;
ConstantPool* _cp;
LayoutRawBlock* _blocks; // the layout being computed
LayoutRawBlock* _start; // points to the first block where a field can be inserted
LayoutRawBlock* _last; // points to the last block of the layout (big empty block)
public:
FieldLayout(Array<u2>* fields, ConstantPool* cp);
void initialize_static_layout();
void initialize_instance_layout(const InstanceKlass* ik);
LayoutRawBlock* first_empty_block() {
LayoutRawBlock* block = _start;
while (block->kind() != LayoutRawBlock::EMPTY) {
block = block->next_block();
}
return block;
}
LayoutRawBlock* start() { return _start; }
void set_start(LayoutRawBlock* start) { _start = start; }
LayoutRawBlock* last_block() { return _last; }
LayoutRawBlock* first_field_block();
void add(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start = NULL);
void add_field_at_offset(LayoutRawBlock* blocks, int offset, LayoutRawBlock* start = NULL);
void add_contiguously(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start = NULL);
LayoutRawBlock* insert_field_block(LayoutRawBlock* slot, LayoutRawBlock* block);
void reconstruct_layout(const InstanceKlass* ik);
void fill_holes(const InstanceKlass* ik);
LayoutRawBlock* insert(LayoutRawBlock* slot, LayoutRawBlock* block);
void remove(LayoutRawBlock* block);
void print(outputStream* output, bool is_static, const InstanceKlass* super);
};
// FieldLayoutBuilder is the main entry point for layout computation.
// This class has three methods to generate layout: one for regular classes
// and two for classes with hard coded offsets (java,lang.ref.Reference
// and the boxing classes). The rationale for having multiple methods
// is that each kind of class has a different set goals regarding
// its layout, so instead of mixing several layout strategies into a
// single method, each kind has its own method (see comments below
// for more details about the allocation strategies).
//
// Computing the layout of a class always goes through 4 steps:
// 1 - Prologue: preparation of data structure and gathering of
// layout information inherited from super classes
// 2 - Field sorting: fields are sorted according to their
// kind (oop, primitive, inline class) and their contention
// annotation (if any)
// 3 - Layout is computed from the set of lists generated during
// step 2
// 4 - Epilogue: oopmaps are generated, layout information is
// prepared so other VM components can use it (instance size,
// static field size, non-static field size, etc.)
//
// Steps 1 and 4 are common to all layout computations. Step 2 and 3
// can vary with the allocation strategy.
//
class FieldLayoutBuilder : public ResourceObj {
private:
const Symbol* _classname;
const InstanceKlass* _super_klass;
ConstantPool* _constant_pool;
Array<u2>* _fields;
FieldLayoutInfo* _info;
FieldGroup* _root_group;
GrowableArray<FieldGroup*> _contended_groups;
FieldGroup* _static_fields;
FieldLayout* _layout;
FieldLayout* _static_layout;
int _nonstatic_oopmap_count;
int _alignment;
bool _has_nonstatic_fields;
bool _is_contended; // is a contended class?
public:
FieldLayoutBuilder(const Symbol* classname, const InstanceKlass* super_klass, ConstantPool* constant_pool,
Array<u2>* fields, bool is_contended, FieldLayoutInfo* info);
int get_alignment() {
assert(_alignment != -1, "Uninitialized");
return _alignment;
}
void build_layout();
void compute_regular_layout();
void compute_java_lang_ref_Reference_layout();
void compute_boxing_class_layout();
void insert_contended_padding(LayoutRawBlock* slot);
private:
void prologue();
void epilogue();
void regular_field_sorting();
FieldGroup* get_or_create_contended_group(int g);
};
#endif // SHARE_CLASSFILE_FIELDLAYOUTBUILDER_HPP

View File

@ -740,6 +740,9 @@ bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const {
}
Node* ShenandoahBarrierSetC2::step_over_gc_barrier(Node* c) const {
if (c == NULL) {
return c;
}
if (c->Opcode() == Op_ShenandoahLoadReferenceBarrier) {
return c->in(ShenandoahLoadReferenceBarrierNode::ValueIn);
}

View File

@ -58,6 +58,11 @@ bool ShenandoahBarrierC2Support::expand(Compile* C, PhaseIterGVN& igvn) {
return false;
}
C->clear_major_progress();
if (C->range_check_cast_count() > 0) {
// No more loop optimizations. Remove all range check dependent CastIINodes.
C->remove_range_check_casts(igvn);
igvn.optimize();
}
}
}
return true;
@ -2009,21 +2014,22 @@ void ShenandoahBarrierC2Support::optimize_after_expansion(VectorSet &visited, No
if (loop != phase->ltree_root() &&
loop->_child == NULL &&
!loop->_irreducible) {
LoopNode* head = loop->_head->as_Loop();
if ((!head->is_CountedLoop() || head->as_CountedLoop()->is_main_loop() || head->as_CountedLoop()->is_normal_loop()) &&
Node* head = loop->_head;
if (head->is_Loop() &&
(!head->is_CountedLoop() || head->as_CountedLoop()->is_main_loop() || head->as_CountedLoop()->is_normal_loop()) &&
!seen.test_set(head->_idx)) {
IfNode* iff = find_unswitching_candidate(loop, phase);
if (iff != NULL) {
Node* bol = iff->in(1);
if (head->is_strip_mined()) {
head->verify_strip_mined(0);
if (head->as_Loop()->is_strip_mined()) {
head->as_Loop()->verify_strip_mined(0);
}
move_heap_stable_test_out_of_loop(iff, phase);
AutoNodeBudget node_budget(phase);
if (loop->policy_unswitching(phase)) {
if (head->is_strip_mined()) {
if (head->as_Loop()->is_strip_mined()) {
OuterStripMinedLoopNode* outer = head->as_CountedLoop()->outer_loop();
hide_strip_mined_loop(outer, head->as_CountedLoop(), phase);
}
@ -2291,7 +2297,12 @@ void MemoryGraphFixer::collect_memory_nodes() {
if (in_opc == Op_Return || in_opc == Op_Rethrow) {
mem = in->in(TypeFunc::Memory);
} else if (in_opc == Op_Halt) {
if (!in->in(0)->is_Region()) {
if (in->in(0)->is_Region()) {
Node* r = in->in(0);
for (uint j = 1; j < r->req(); j++) {
assert(r->in(j)->Opcode() != Op_NeverBranch, "");
}
} else {
Node* proj = in->in(0);
assert(proj->is_Proj(), "");
Node* in = proj->in(0);
@ -2303,25 +2314,37 @@ void MemoryGraphFixer::collect_memory_nodes() {
assert(call->is_Call(), "");
mem = call->in(TypeFunc::Memory);
} else if (in->Opcode() == Op_NeverBranch) {
ResourceMark rm;
Unique_Node_List wq;
wq.push(in);
wq.push(in->as_Multi()->proj_out(0));
for (uint j = 1; j < wq.size(); j++) {
Node* c = wq.at(j);
assert(!c->is_Root(), "shouldn't leave loop");
if (c->is_SafePoint()) {
assert(mem == NULL, "only one safepoint");
Node* head = in->in(0);
assert(head->is_Region() && head->req() == 3, "unexpected infinite loop graph shape");
assert(_phase->is_dominator(head, head->in(1)) || _phase->is_dominator(head, head->in(2)), "no back branch?");
Node* tail = _phase->is_dominator(head, head->in(1)) ? head->in(1) : head->in(2);
Node* c = tail;
while (c != head) {
if (c->is_SafePoint() && !c->is_CallLeaf()) {
mem = c->in(TypeFunc::Memory);
}
for (DUIterator_Fast kmax, k = c->fast_outs(kmax); k < kmax; k++) {
Node* u = c->fast_out(k);
if (u->is_CFG()) {
wq.push(u);
c = _phase->idom(c);
}
assert(mem != NULL, "should have found safepoint");
Node* phi_mem = NULL;
for (DUIterator_Fast jmax, j = head->fast_outs(jmax); j < jmax; j++) {
Node* u = head->fast_out(j);
if (u->is_Phi() && u->bottom_type() == Type::MEMORY) {
if (_phase->C->get_alias_index(u->adr_type()) == _alias) {
assert(phi_mem == NULL || phi_mem->adr_type() == TypePtr::BOTTOM, "");
phi_mem = u;
} else if (u->adr_type() == TypePtr::BOTTOM) {
assert(phi_mem == NULL || _phase->C->get_alias_index(phi_mem->adr_type()) == _alias, "");
if (phi_mem == NULL) {
phi_mem = u;
}
}
}
}
assert(mem != NULL, "should have found safepoint");
if (phi_mem != NULL) {
mem = phi_mem;
}
}
}
} else {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -435,7 +435,7 @@ void JfrThreadSampler::start_thread() {
void JfrThreadSampler::enroll() {
if (_disenrolled) {
log_info(jfr)("Enrolling thread sampler");
log_trace(jfr)("Enrolling thread sampler");
_sample.signal();
_disenrolled = false;
}
@ -445,7 +445,7 @@ void JfrThreadSampler::disenroll() {
if (!_disenrolled) {
_sample.wait();
_disenrolled = true;
log_info(jfr)("Disenrolling thread sampler");
log_trace(jfr)("Disenrolling thread sampler");
}
}
@ -583,12 +583,12 @@ JfrThreadSampling::~JfrThreadSampling() {
}
static void log(size_t interval_java, size_t interval_native) {
log_info(jfr)("Updated thread sampler for java: " SIZE_FORMAT " ms, native " SIZE_FORMAT " ms", interval_java, interval_native);
log_trace(jfr)("Updated thread sampler for java: " SIZE_FORMAT " ms, native " SIZE_FORMAT " ms", interval_java, interval_native);
}
void JfrThreadSampling::start_sampler(size_t interval_java, size_t interval_native) {
assert(_sampler == NULL, "invariant");
log_info(jfr)("Enrolling thread sampler");
log_trace(jfr)("Enrolling thread sampler");
_sampler = new JfrThreadSampler(interval_java, interval_native, JfrOptionSet::stackdepth());
_sampler->start_thread();
_sampler->enroll();
@ -608,7 +608,7 @@ void JfrThreadSampling::set_sampling_interval(bool java_interval, size_t period)
}
if (interval_java > 0 || interval_native > 0) {
if (_sampler == NULL) {
log_info(jfr)("Creating thread sampler for java:%zu ms, native %zu ms", interval_java, interval_native);
log_trace(jfr)("Creating thread sampler for java:%zu ms, native %zu ms", interval_java, interval_native);
start_sampler(interval_java, interval_native);
} else {
_sampler->set_java_interval(interval_java);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -157,7 +157,7 @@
nonstatic_field(InstanceKlass, _constants, ConstantPool*) \
nonstatic_field(InstanceKlass, _source_file_name_index, u2) \
nonstatic_field(InstanceKlass, _init_state, u1) \
nonstatic_field(InstanceKlass, _misc_flags, u2) \
nonstatic_field(InstanceKlass, _misc_flags, u4) \
nonstatic_field(InstanceKlass, _annotations, Annotations*) \
\
volatile_nonstatic_field(JavaFrameAnchor, _last_Java_sp, intptr_t*) \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -47,7 +47,6 @@ class FieldStreamBase : public StackObj {
fieldDescriptor _fd_buf;
FieldInfo* field() const { return FieldInfo::from_field_array(_fields, _index); }
InstanceKlass* field_holder() const { return _constants->pool_holder(); }
int init_generic_signature_start_slot() {
int length = _fields->length();
@ -87,6 +86,7 @@ class FieldStreamBase : public StackObj {
// accessors
int index() const { return _index; }
InstanceKlass* field_holder() const { return _constants->pool_holder(); }
void next() {
if (access_flags().field_has_generic_signature()) {

View File

@ -1399,6 +1399,10 @@ void InstanceKlass::mask_for(const methodHandle& method, int bci,
oop_map_cache->lookup(method, bci, entry_for);
}
bool InstanceKlass::contains_field_offset(int offset) {
fieldDescriptor fd;
return find_field_from_offset(offset, false, &fd);
}
bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const {
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {

View File

@ -103,12 +103,28 @@ class OopMapBlock {
uint count() const { return _count; }
void set_count(uint count) { _count = count; }
void increment_count(int diff) { _count += diff; }
int offset_span() const { return _count * heapOopSize; }
int end_offset() const {
return offset() + offset_span();
}
bool is_contiguous(int another_offset) const {
return another_offset == end_offset();
}
// sizeof(OopMapBlock) in words.
static const int size_in_words() {
return align_up((int)sizeof(OopMapBlock), wordSize) >>
LogBytesPerWord;
}
static int compare_offset(const OopMapBlock* a, const OopMapBlock* b) {
return a->offset() - b->offset();
}
private:
int _offset;
uint _count;
@ -212,7 +228,6 @@ class InstanceKlass: public Klass {
// _is_marked_dependent can be set concurrently, thus cannot be part of the
// _misc_flags.
bool _is_marked_dependent; // used for marking during flushing and deoptimization
bool _is_being_redefined; // used for locking redefinition
// The low two bits of _misc_flags contains the kind field.
// This can be used to quickly discriminate among the four kinds of
@ -243,12 +258,14 @@ class InstanceKlass: public Klass {
_misc_is_shared_boot_class = 1 << 12, // defining class loader is boot class loader
_misc_is_shared_platform_class = 1 << 13, // defining class loader is platform class loader
_misc_is_shared_app_class = 1 << 14, // defining class loader is app class loader
_misc_has_resolved_methods = 1 << 15 // resolved methods table entries added for this class
_misc_has_resolved_methods = 1 << 15, // resolved methods table entries added for this class
_misc_is_being_redefined = 1 << 16, // used for locking redefinition
_misc_has_contended_annotations = 1 << 17 // has @Contended annotation
};
u2 loader_type_bits() {
return _misc_is_shared_boot_class|_misc_is_shared_platform_class|_misc_is_shared_app_class;
}
u2 _misc_flags;
u4 _misc_flags;
u2 _minor_version; // minor version number of class file
u2 _major_version; // major version number of class file
Thread* _init_thread; // Pointer to current thread doing initialization (to handle recursive initialization)
@ -571,9 +588,7 @@ public:
Klass* find_field(Symbol* name, Symbol* sig, bool is_static, fieldDescriptor* fd) const;
// find a non-static or static field given its offset within the class.
bool contains_field_offset(int offset) {
return instanceOopDesc::contains_field_offset(offset, nonstatic_field_size());
}
bool contains_field_offset(int offset);
bool find_local_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const;
bool find_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const;
@ -735,10 +750,29 @@ public:
_nonstatic_oop_map_size = words;
}
bool has_contended_annotations() const {
return ((_misc_flags & _misc_has_contended_annotations) != 0);
}
void set_has_contended_annotations(bool value) {
if (value) {
_misc_flags |= _misc_has_contended_annotations;
} else {
_misc_flags &= ~_misc_has_contended_annotations;
}
}
#if INCLUDE_JVMTI
// Redefinition locking. Class can only be redefined by one thread at a time.
bool is_being_redefined() const { return _is_being_redefined; }
void set_is_being_redefined(bool value) { _is_being_redefined = value; }
bool is_being_redefined() const {
return ((_misc_flags & _misc_is_being_redefined) != 0);
}
void set_is_being_redefined(bool value) {
if (value) {
_misc_flags |= _misc_is_being_redefined;
} else {
_misc_flags &= ~_misc_is_being_redefined;
}
}
// RedefineClasses() support for previous versions:
void add_previous_version(InstanceKlass* ik, int emcp_method_count);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -43,12 +43,6 @@ class instanceOopDesc : public oopDesc {
klass_gap_offset_in_bytes() :
sizeof(instanceOopDesc);
}
static bool contains_field_offset(int offset, int nonstatic_field_size) {
int base_in_bytes = base_offset_in_bytes();
return (offset >= base_in_bytes &&
(offset-base_in_bytes) < nonstatic_field_size * heapOopSize);
}
};
#endif // SHARE_OOPS_INSTANCEOOP_HPP

View File

@ -522,6 +522,8 @@ static SpecialFlag const special_jvm_flags[] = {
{ "AllowRedefinitionToAddDeleteMethods", JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() },
{ "FlightRecorder", JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() },
{ "MonitorBound", JDK_Version::jdk(14), JDK_Version::jdk(15), JDK_Version::jdk(16) },
{ "PrintVMQWaitTime", JDK_Version::jdk(15), JDK_Version::jdk(16), JDK_Version::jdk(17) },
{ "UseNewFieldLayout", JDK_Version::jdk(15), JDK_Version::jdk(16), JDK_Version::jdk(17) },
// --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in:
{ "DefaultMaxRAMFraction", JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() },

View File

@ -1156,18 +1156,18 @@ int compare(ReassignedField* left, ReassignedField* right) {
// Restore fields of an eliminated instance object using the same field order
// returned by HotSpotResolvedObjectTypeImpl.getInstanceFields(true)
static int reassign_fields_by_klass(InstanceKlass* klass, frame* fr, RegisterMap* reg_map, ObjectValue* sv, int svIndex, oop obj, bool skip_internal) {
if (klass->superklass() != NULL) {
svIndex = reassign_fields_by_klass(klass->superklass(), fr, reg_map, sv, svIndex, obj, skip_internal);
}
GrowableArray<ReassignedField>* fields = new GrowableArray<ReassignedField>();
for (AllFieldStream fs(klass); !fs.done(); fs.next()) {
if (!fs.access_flags().is_static() && (!skip_internal || !fs.access_flags().is_internal())) {
ReassignedField field;
field._offset = fs.offset();
field._type = Signature::basic_type(fs.signature());
fields->append(field);
InstanceKlass* ik = klass;
while (ik != NULL) {
for (AllFieldStream fs(ik); !fs.done(); fs.next()) {
if (!fs.access_flags().is_static() && (!skip_internal || !fs.access_flags().is_internal())) {
ReassignedField field;
field._offset = fs.offset();
field._type = Signature::basic_type(fs.signature());
fields->append(field);
}
}
ik = ik->superklass();
}
fields->sort(compare);
for (int i = 0; i < fields->length(); i++) {

View File

@ -267,7 +267,7 @@ const size_t minimumSymbolTableSize = 1024;
"compilation") \
\
product(bool, PrintVMQWaitTime, false, \
"Print out the waiting time in VM operation queue") \
"(Deprecated) Print out the waiting time in VM operation queue") \
\
product(bool, MethodFlushing, true, \
"Reclamation of zombie and not-entrant methods") \
@ -2488,7 +2488,15 @@ const size_t minimumSymbolTableSize = 1024;
"Start flight recording with options")) \
\
experimental(bool, UseFastUnorderedTimeStamps, false, \
"Use platform unstable time where supported for timestamps only")
"Use platform unstable time where supported for timestamps only") \
\
product(bool, UseNewFieldLayout, true, \
"(Deprecated) Use new algorithm to compute field layouts") \
\
product(bool, UseEmptySlotsInSupers, true, \
"Allow allocating fields in empty slots of super-classes") \
\
// Interface macros
#define DECLARE_PRODUCT_FLAG(type, name, value, doc) extern "C" type name;

View File

@ -235,7 +235,7 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
nonstatic_field(InstanceKlass, _static_oop_field_count, u2) \
nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \
nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \
nonstatic_field(InstanceKlass, _misc_flags, u2) \
nonstatic_field(InstanceKlass, _misc_flags, u4) \
nonstatic_field(InstanceKlass, _minor_version, u2) \
nonstatic_field(InstanceKlass, _major_version, u2) \
nonstatic_field(InstanceKlass, _init_state, u1) \

View File

@ -1094,13 +1094,14 @@ public final class Module implements AnnotatedElement {
// map each module to a class loader
ClassLoader pcl = ClassLoaders.platformClassLoader();
boolean isModuleLoaderMapper = ModuleLoaderMap.isBuiltinMapper(clf);
for (int index = 0; index < numModules; index++) {
String name = resolvedModules[index].name();
ClassLoader loader = clf.apply(name);
if (loader == null || loader == pcl) {
if (!(clf instanceof ModuleLoaderMap.Mapper)) {
if (!isModuleLoaderMapper) {
throw new IllegalArgumentException("loader can't be 'null'"
+ " or the platform class loader");
}

View File

@ -109,7 +109,7 @@ public abstract class Record {
* @implSpec
* The implicitly provided implementation returns {@code true} if
* and only if the argument is an instance of the same record type
* as this object, and each component of this record is equal to
* as this record, and each component of this record is equal to
* the corresponding component of the argument; otherwise, {@code
* false} is returned. Equality of a component {@code c} is
* determined as follows:
@ -130,46 +130,70 @@ public abstract class Record {
*
* </ul>
*
* The implicitly provided implementation conforms to the
* semantics described above; the implementation may or may not
* accomplish this by using calls to the particular methods
* listed.
* Apart from the semantics described above, the precise algorithm
* used in the implicitly provided implementation is unspecified
* and is subject to change. The implementation may or may not use
* calls to the particular methods listed, and may or may not
* perform comparisons in the order of component declaration.
*
* @see java.util.Objects#equals(Object,Object)
*
* @param obj the reference object with which to compare.
* @return {@code true} if this object is equal to the
* @return {@code true} if this record is equal to the
* argument; {@code false} otherwise.
*/
@Override
public abstract boolean equals(Object obj);
/**
* Returns a hash code value for the record.
* Obeys the general contract of {@link Object#hashCode Object.hashCode}.
* For records, hashing behavior is constrained by the refined contract
* of {@link Record#equals Record.equals}, so that any two records
* created from the same components must have the same hash code.
*
* @implSpec
* The implicitly provided implementation returns a hash code value derived
* by combining the hash code value for all the components, according to
* {@link Object#hashCode()} for components whose types are reference types,
* or the primitive wrapper hash code for components whose types are primitive
* types.
* by combining appropriate hashes from each component.
* The precise algorithm used in the implicitly provided implementation
* is unspecified and is subject to change within the above limits.
* The resulting integer need not remain consistent from one
* execution of an application to another execution of the same
* application, even if the hashes of the component values were to
* remain consistent in this way. Also, a component of primitive
* type may contribute its bits to the hash code differently than
* the {@code hashCode} of its primitive wrapper class.
*
* @see Object#hashCode()
*
* @return a hash code value for this object.
* @return a hash code value for this record.
*/
@Override
public abstract int hashCode();
/**
* Obeys the general contract of {@link Object#toString Object.toString}.
* Returns a string representation of the record.
* In accordance with the general contract of {@link Object#toString()},
* the {@code toString} method returns a string that
* "textually represents" this record. The result should
* be a concise but informative representation that is easy for a
* person to read.
* <p>
* In addition to this general contract, record classes must further
* participate in the invariant that any two records which are
* {@linkplain Record#equals(Object) equal} must produce equal
* strings. This invariant is necessarily relaxed in the rare
* case where corresponding equal component values might fail
* to produce equal strings for themselves.
*
* @implSpec
* The implicitly provided implementation returns a string that is derived
* from the name of the record class and the names and string representations
* of all the components, according to {@link Object#toString()} for components
* whose types are reference types, and the primitive wrapper {@code toString}
* method for components whose types are primitive types.
* The implicitly provided implementation returns a string which
* contains the name of the record class, the names of components
* of the record, and string representations of component values,
* so as to fulfill the contract of this method.
* The precise format produced by this implicitly provided implementation
* is subject to change, so the present syntax should not be parsed
* by applications to recover record component values.
*
* @see Object#toString()
*

View File

@ -79,7 +79,7 @@ public final class ResolvedModule {
* @return The module descriptor
*/
ModuleDescriptor descriptor() {
return reference().descriptor();
return mref.descriptor();
}
/**
@ -93,7 +93,7 @@ public final class ResolvedModule {
* @return The module name
*/
public String name() {
return reference().descriptor().name();
return mref.descriptor().name();
}
/**

View File

@ -904,6 +904,20 @@ class ImmutableCollections {
@Override public V replace(K key, V value) { throw uoe(); }
@Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
@Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
/**
* @implNote {@code null} values are disallowed in these immutable maps,
* so we can improve upon the default implementation since a
* {@code null} return from {@code get(key)} always means the default
* value should be returned.
*/
@Override
public V getOrDefault(Object key, V defaultValue) {
V v;
return ((v = get(key)) != null)
? v
: defaultValue;
}
}
static final class Map1<K,V> extends AbstractImmutableMap<K,V> {

View File

@ -2064,7 +2064,7 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
Node prev = null;
Node firstTail = null;
Branch branch = null;
Node branchConn = null;
BranchConn branchConn = null;
for (;;) {
Node node = sequence(end);
@ -2212,7 +2212,24 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
break;
}
node = closure(node);
if (node instanceof LineEnding) {
LineEnding le = (LineEnding)node;
node = closureOfLineEnding(le);
if (node != le) {
// LineEnding was replaced with an anonymous group
if (head == null)
head = node;
else
tail.next = node;
// Double return: Tail was returned in root
tail = root;
continue;
}
} else {
node = closure(node);
}
/* save the top dot-greedy nodes (.*, .+) as well
if (node instanceof GreedyCharProperty &&
((GreedyCharProperty)node).cp instanceof Dot) {
@ -3079,18 +3096,31 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
if (saveTCNCount < topClosureNodes.size())
topClosureNodes.subList(saveTCNCount, topClosureNodes.size()).clear();
return groupWithClosure(node, head, tail, capturingGroup);
}
/**
* Transforms a Group with quantifiers into some special constructs
* (such as Branch or Loop/GroupCurly), if necessary.
*
* This method is applied either to actual groups or to the Unicode
* linebreak (aka \\R) represented as an anonymous group.
*/
private Node groupWithClosure(Node node, Node head, Node tail,
boolean capturingGroup)
{
if (node instanceof Ques) {
Ques ques = (Ques) node;
if (ques.type == Qtype.POSSESSIVE) {
root = node;
return node;
}
tail.next = new BranchConn();
tail = tail.next;
BranchConn branchConn = new BranchConn();
tail = tail.next = branchConn;
if (ques.type == Qtype.GREEDY) {
head = new Branch(head, null, tail);
head = new Branch(head, null, branchConn);
} else { // Reluctant quantifier
head = new Branch(null, head, tail);
head = new Branch(null, head, branchConn);
}
root = tail;
return head;
@ -3267,6 +3297,31 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
return new Curly(prev, cmin, MAX_REPS, qtype);
}
/**
* Processing repetition of a Unicode linebreak \\R.
*/
private Node closureOfLineEnding(LineEnding le) {
int ch = peek();
if (ch != '?' && ch != '*' && ch != '+' && ch != '{') {
return le;
}
// Replace the LineEnding with an anonymous group
// (?:\\u000D\\u000A|[\\u000A\\u000B\\u000C\\u000D\\u0085\\u2028\\u2029])
Node grHead = createGroup(true);
Node grTail = root;
BranchConn branchConn = new BranchConn();
branchConn.next = grTail;
Node slice = new Slice(new int[] {0x0D, 0x0A});
slice.next = branchConn;
Node chClass = newCharProperty(x -> x == 0x0A || x == 0x0B ||
x == 0x0C || x == 0x0D || x == 0x85 || x == 0x2028 ||
x == 0x2029);
chClass.next = branchConn;
grHead.next = new Branch(slice, chClass, branchConn);
return groupWithClosure(closure(grHead), grHead, grTail, false);
}
/**
* Processes repetition. If the next character peeked is a quantifier
* then new nodes must be appended to handle the repetition.
@ -4723,8 +4778,8 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
static final class Branch extends Node {
Node[] atoms = new Node[2];
int size = 2;
Node conn;
Branch(Node first, Node second, Node branchConn) {
BranchConn conn;
Branch(Node first, Node second, BranchConn branchConn) {
conn = branchConn;
atoms[0] = first;
atoms[1] = second;
@ -4732,9 +4787,10 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
void add(Node node) {
if (size >= atoms.length) {
Node[] tmp = new Node[atoms.length*2];
System.arraycopy(atoms, 0, tmp, 0, atoms.length);
atoms = tmp;
int len = ArraysSupport.newLength(size,
1, /* minimum growth */
size /* preferred growth */);
atoms = Arrays.copyOf(atoms, len);
}
atoms[size++] = node;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,8 +28,8 @@ package jdk.internal.module;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import jdk.internal.misc.VM;
@ -39,26 +39,26 @@ import jdk.internal.misc.VM;
final class ArchivedModuleGraph {
private static ArchivedModuleGraph archivedModuleGraph;
private final String mainModule;
private final boolean hasSplitPackages;
private final boolean hasIncubatorModules;
private final ModuleFinder finder;
private final Configuration configuration;
private final Function<String, ClassLoader> classLoaderFunction;
private final Map<String, Set<String>> concealedPackagesToOpen;
private final Map<String, Set<String>> exportedPackagesToOpen;
private ArchivedModuleGraph(String mainModule,
boolean hasSplitPackages,
boolean hasIncubatorModules,
ModuleFinder finder,
Configuration configuration,
Map<String, Set<String>> concealedPackagesToOpen,
Map<String, Set<String>> exportedPackagesToOpen) {
this.mainModule = mainModule;
public ArchivedModuleGraph(boolean hasSplitPackages,
boolean hasIncubatorModules,
ModuleFinder finder,
Configuration configuration,
Function<String, ClassLoader> classLoaderFunction,
Map<String, Set<String>> concealedPackagesToOpen,
Map<String, Set<String>> exportedPackagesToOpen) {
this.hasSplitPackages = hasSplitPackages;
this.hasIncubatorModules = hasIncubatorModules;
this.finder = finder;
this.configuration = configuration;
this.classLoaderFunction = classLoaderFunction;
this.concealedPackagesToOpen = concealedPackagesToOpen;
this.exportedPackagesToOpen = exportedPackagesToOpen;
}
@ -71,6 +71,10 @@ final class ArchivedModuleGraph {
return configuration;
}
Function<String, ClassLoader> classLoaderFunction() {
return classLoaderFunction;
}
Map<String, Set<String>> concealedPackagesToOpen() {
return concealedPackagesToOpen;
}
@ -92,7 +96,8 @@ final class ArchivedModuleGraph {
*/
static ArchivedModuleGraph get(String mainModule) {
ArchivedModuleGraph graph = archivedModuleGraph;
if (graph != null && Objects.equals(mainModule, graph.mainModule)) {
// We only allow the unnamed module (default) case for now
if (mainModule == null) {
return graph;
} else {
return null;
@ -102,23 +107,8 @@ final class ArchivedModuleGraph {
/**
* Archive the module graph for the given initial module.
*/
static void archive(String mainModule,
boolean hasSplitPackages,
boolean hasIncubatorModules,
ModuleFinder finder,
Configuration configuration,
Map<String, Set<String>> concealedPackagesToOpen,
Map<String, Set<String>> exportedPackagesToOpen) {
if (mainModule != null) {
throw new UnsupportedOperationException();
}
archivedModuleGraph = new ArchivedModuleGraph(mainModule,
hasSplitPackages,
hasIncubatorModules,
finder,
configuration,
concealedPackagesToOpen,
exportedPackagesToOpen);
static void archive(ArchivedModuleGraph graph) {
archivedModuleGraph = graph;
}
static {

View File

@ -370,7 +370,12 @@ public final class ModuleBootstrap {
// loader.
// mapping of modules to class loaders
Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
Function<String, ClassLoader> clf;
if (archivedModuleGraph != null) {
clf = archivedModuleGraph.classLoaderFunction();
} else {
clf = ModuleLoaderMap.mappingFunction(cf);
}
// check that all modules to be mapped to the boot loader will be
// loaded from the runtime image
@ -440,13 +445,14 @@ public final class ModuleBootstrap {
// Module graph can be archived at CDS dump time. Only allow the
// unnamed module case for now.
if (canArchive && (mainModule == null)) {
ArchivedModuleGraph.archive(mainModule,
hasSplitPackages,
hasIncubatorModules,
systemModuleFinder,
cf,
concealedPackagesToOpen,
exportedPackagesToOpen);
ArchivedModuleGraph.archive(
new ArchivedModuleGraph(hasSplitPackages,
hasIncubatorModules,
systemModuleFinder,
cf,
clf,
concealedPackagesToOpen,
exportedPackagesToOpen));
}
// total time to initialize
@ -737,7 +743,6 @@ public final class ModuleBootstrap {
Modules.addExports(m, pn, other);
}
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,14 +28,12 @@ package jdk.internal.module;
import java.lang.module.Configuration;
import java.lang.module.ResolvedModule;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import jdk.internal.loader.ClassLoaders;
/**
* Supports the mapping of modules to class loaders. The set of modules mapped
* to the boot and platform class loaders is generated at build time from
@ -46,16 +44,55 @@ public final class ModuleLoaderMap {
/**
* Maps the system modules to the built-in class loaders.
*/
public static final class Mapper implements Function<String, ClassLoader> {
private final Map<String, ClassLoader> map;
private static final class Mapper implements Function<String, ClassLoader> {
Mapper(Map<String, ClassLoader> map) {
this.map = map; // defensive copy not needed
private static final ClassLoader PLATFORM_CLASSLOADER =
ClassLoaders.platformClassLoader();
private static final ClassLoader APP_CLASSLOADER =
ClassLoaders.appClassLoader();
private static final Integer PLATFORM_LOADER_INDEX = 1;
private static final Integer APP_LOADER_INDEX = 2;
/**
* Map from module to a class loader index. The index is resolved to the
* actual class loader in {@code apply}.
*/
private final Map<String, Integer> map;
/**
* Creates a Mapper to map module names in the given Configuration to
* built-in classloaders.
*
* As a proxy for the actual classloader, we store an easily archiveable
* index value in the internal map. The index is stored as a boxed value
* so that we can cheaply do identity comparisons during bootstrap.
*/
Mapper(Configuration cf) {
var map = new HashMap<String, Integer>();
for (ResolvedModule resolvedModule : cf.modules()) {
String mn = resolvedModule.name();
if (!Modules.bootModules.contains(mn)) {
if (Modules.platformModules.contains(mn)) {
map.put(mn, PLATFORM_LOADER_INDEX);
} else {
map.put(mn, APP_LOADER_INDEX);
}
}
}
this.map = map;
}
@Override
public ClassLoader apply(String name) {
return map.get(name);
Integer loader = map.get(name);
if (loader == APP_LOADER_INDEX) {
return APP_CLASSLOADER;
} else if (loader == PLATFORM_LOADER_INDEX) {
return PLATFORM_CLASSLOADER;
} else { // BOOT_LOADER_INDEX
return null;
}
}
}
@ -63,50 +100,40 @@ public final class ModuleLoaderMap {
* Returns the names of the modules defined to the boot loader.
*/
public static Set<String> bootModules() {
// The list of boot modules generated at build time.
String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" };
Set<String> bootModules = new HashSet<>(BOOT_MODULES.length);
for (String mn : BOOT_MODULES) {
bootModules.add(mn);
}
return bootModules;
return Modules.bootModules;
}
/**
* Returns the names of the modules defined to the platform loader.
*/
public static Set<String> platformModules() {
// The list of platform modules generated at build time.
String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
Set<String> platformModules = new HashSet<>(PLATFORM_MODULES.length);
for (String mn : PLATFORM_MODULES) {
platformModules.add(mn);
}
return platformModules;
return Modules.platformModules;
}
private static class Modules {
// list of boot modules is generated at build time.
private static final Set<String> bootModules =
Set.of(new String[] { "@@BOOT_MODULE_NAMES@@" });
// list of platform modules is generated at build time.
private static final Set<String> platformModules =
Set.of(new String[] { "@@PLATFORM_MODULE_NAMES@@" });
}
/**
* Returns the function to map modules in the given configuration to the
* Returns a function to map modules in the given configuration to the
* built-in class loaders.
*/
static Function<String, ClassLoader> mappingFunction(Configuration cf) {
Set<String> bootModules = bootModules();
Set<String> platformModules = platformModules();
return new Mapper(cf);
}
ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();
ClassLoader appClassLoader = ClassLoaders.appClassLoader();
Map<String, ClassLoader> map = new HashMap<>();
for (ResolvedModule resolvedModule : cf.modules()) {
String mn = resolvedModule.name();
if (!bootModules.contains(mn)) {
if (platformModules.contains(mn)) {
map.put(mn, platformClassLoader);
} else {
map.put(mn, appClassLoader);
}
}
}
return new Mapper(map);
/**
* When defining modules for a configuration, we only allow defining modules
* to the boot or platform classloader if the ClassLoader mapping function
* originate from here.
*/
public static boolean isBuiltinMapper(Function<String, ClassLoader> clf) {
return clf instanceof Mapper;
}
}

View File

@ -162,7 +162,8 @@ module java.base {
jdk.jlink;
exports jdk.internal.loader to
java.instrument,
java.logging;
java.logging,
java.naming;
exports jdk.internal.jmod to
jdk.compiler,
jdk.jlink;

View File

@ -1,4 +1,4 @@
## Unicode Common Local Data Repository (CLDR) v35.1
## Unicode Common Local Data Repository (CLDR) v36
### CLDR License

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,6 +34,7 @@
#include "childproc.h"
const char * const *parentPathv;
ssize_t
restartableWrite(int fd, const void *buf, size_t count)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -126,7 +126,7 @@ typedef struct _SpawnInfo {
* The cached and split version of the JDK's effective PATH.
* (We don't support putenv("PATH=...") in native code)
*/
const char * const *parentPathv;
extern const char * const *parentPathv;
ssize_t restartableWrite(int fd, const void *buf, size_t count);
int restartableDup2(int fd_from, int fd_to);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,13 +26,15 @@
package javax.naming.spi;
import java.net.MalformedURLException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import javax.naming.*;
import com.sun.naming.internal.VersionHelper;
import com.sun.naming.internal.ResourceManager;
import com.sun.naming.internal.FactoryEnumeration;
import jdk.internal.loader.ClassLoaderValue;
/**
* This class contains methods for creating context objects
@ -79,6 +81,9 @@ public class NamingManager {
*/
private static ObjectFactoryBuilder object_factory_builder = null;
private static final ClassLoaderValue<InitialContextFactory> FACTORIES_CACHE =
new ClassLoaderValue<>();
/**
* The ObjectFactoryBuilder determines the policy used when
* trying to load object factories.
@ -672,6 +677,7 @@ public class NamingManager {
*/
public static Context getInitialContext(Hashtable<?,?> env)
throws NamingException {
ClassLoader loader;
InitialContextFactory factory = null;
InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
@ -689,39 +695,22 @@ public class NamingManager {
throw ne;
}
ServiceLoader<InitialContextFactory> loader =
ServiceLoader.load(InitialContextFactory.class);
Iterator<InitialContextFactory> iterator = loader.iterator();
try {
while (iterator.hasNext()) {
InitialContextFactory f = iterator.next();
if (f.getClass().getName().equals(className)) {
factory = f;
break;
}
}
} catch (ServiceConfigurationError e) {
NoInitialContextException ne =
new NoInitialContextException(
"Cannot load initial context factory "
+ "'" + className + "'");
ne.setRootCause(e);
throw ne;
if (System.getSecurityManager() == null) {
loader = Thread.currentThread().getContextClassLoader();
if (loader == null) loader = ClassLoader.getSystemClassLoader();
} else {
PrivilegedAction<ClassLoader> pa = () -> {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
};
loader = AccessController.doPrivileged(pa);
}
if (factory == null) {
try {
@SuppressWarnings("deprecation")
Object o = helper.loadClass(className).newInstance();
factory = (InitialContextFactory) o;
} catch (Exception e) {
NoInitialContextException ne =
new NoInitialContextException(
"Cannot instantiate class: " + className);
ne.setRootCause(e);
throw ne;
}
var key = FACTORIES_CACHE.sub(className);
try {
factory = key.computeIfAbsent(loader, (ld, ky) -> getFactory(ky.key()));
} catch (FactoryInitializationError e) {
throw e.getCause();
}
} else {
factory = builder.createInitialContextFactory(env);
@ -730,6 +719,43 @@ public class NamingManager {
return factory.getInitialContext(env);
}
private static InitialContextFactory getFactory(String className) {
InitialContextFactory factory;
try {
ServiceLoader<InitialContextFactory> loader =
ServiceLoader.load(InitialContextFactory.class);
factory = loader
.stream()
.filter(p -> p.type().getName().equals(className))
.findFirst()
.map(ServiceLoader.Provider::get)
.orElse(null);
} catch (ServiceConfigurationError e) {
NoInitialContextException ne =
new NoInitialContextException(
"Cannot load initial context factory "
+ "'" + className + "'");
ne.setRootCause(e);
throw new FactoryInitializationError(ne);
}
if (factory == null) {
try {
@SuppressWarnings("deprecation")
Object o = helper.loadClass(className).newInstance();
factory = (InitialContextFactory) o;
} catch (Exception e) {
NoInitialContextException ne =
new NoInitialContextException(
"Cannot instantiate class: " + className);
ne.setRootCause(e);
throw new FactoryInitializationError(ne);
}
}
return factory;
}
/**
* Sets the InitialContextFactory builder to be builder.
@ -921,4 +947,18 @@ public class NamingManager {
return (answer != null) ? answer : obj;
}
private static class FactoryInitializationError extends Error {
@java.io.Serial
static final long serialVersionUID = -5805552256848841560L;
private FactoryInitializationError(NoInitialContextException cause) {
super(cause);
}
@Override
public NoInitialContextException getCause() {
return (NoInitialContextException) super.getCause();
}
}
}

View File

@ -305,9 +305,7 @@ public final class KeyTab {
* Checks if the keytab file exists. Implementation of this method
* should make sure that the result matches the latest status of the
* keytab file.
* <p>
* The caller can use the result to determine if it should fallback to
* another mechanism to read the keys.
*
* @return true if the keytab file exists; false otherwise.
* @throws SecurityException if a security manager exists and the read
* access to the keytab file is not permitted

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,6 +34,8 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import jdk.vm.ci.common.JVMCIError;
@ -61,6 +63,7 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
private static final HotSpotResolvedJavaField[] NO_FIELDS = new HotSpotResolvedJavaField[0];
private static final int METHOD_CACHE_ARRAY_CAPACITY = 8;
private static final SortByOffset fieldSortingMethod = new SortByOffset();
/**
* The Java class this type represents.
@ -708,6 +711,12 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
}
}
static class SortByOffset implements Comparator<ResolvedJavaField> {
public int compare(ResolvedJavaField a, ResolvedJavaField b) {
return a.getOffset() - b.getOffset();
}
}
@Override
public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) {
if (instanceFields == null) {
@ -727,8 +736,17 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
// This class does not have any instance fields of its own.
return NO_FIELDS;
} else if (superClassFieldCount != 0) {
// Fields of the current class can be interleaved with fields of its super-classes
// but the array of fields to be returned must be sorted by increasing offset
// This code populates the array, then applies the sorting function
HotSpotResolvedJavaField[] result = new HotSpotResolvedJavaField[instanceFields.length - superClassFieldCount];
System.arraycopy(instanceFields, superClassFieldCount, result, 0, result.length);
int i = 0;
for (HotSpotResolvedJavaField f : instanceFields) {
if (f.getDeclaringClass() == this) {
result[i++] = f;
}
}
Arrays.sort(result, fieldSortingMethod);
return result;
} else {
// The super classes of this class do not have any instance fields.
@ -781,23 +799,19 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
System.arraycopy(prepend, 0, result, 0, prependLength);
}
// Fields of the current class can be interleaved with fields of its super-classes
// but the array of fields to be returned must be sorted by increasing offset
// This code populates the array, then applies the sorting function
int resultIndex = prependLength;
for (int i = 0; i < index; ++i) {
FieldInfo field = new FieldInfo(i);
if (field.isStatic() == retrieveStaticFields) {
int offset = field.getOffset();
HotSpotResolvedJavaField resolvedJavaField = createField(field.getType(), offset, field.getAccessFlags(), i);
// Make sure the result is sorted by offset.
int j;
for (j = resultIndex - 1; j >= prependLength && result[j].getOffset() > offset; j--) {
result[j + 1] = result[j];
}
result[j + 1] = resolvedJavaField;
resultIndex++;
result[resultIndex++] = resolvedJavaField;
}
}
Arrays.sort(result, fieldSortingMethod);
return result;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -101,7 +101,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess {
final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*");
final int instanceKlassFieldsOffset = getFieldOffset("InstanceKlass::_fields", Integer.class, "Array<u2>*");
final int instanceKlassAnnotationsOffset = getFieldOffset("InstanceKlass::_annotations", Integer.class, "Annotations*");
final int instanceKlassMiscFlagsOffset = getFieldOffset("InstanceKlass::_misc_flags", Integer.class, "u2");
final int instanceKlassMiscFlagsOffset = getFieldOffset("InstanceKlass::_misc_flags", Integer.class, "u4");
final int klassVtableStartOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_start_offset", Integer.class, "int");
final int klassVtableLengthOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_length_offset", Integer.class, "int");

View File

@ -89,7 +89,7 @@ public abstract class AbstractMemberWriter implements MemberSummaryWriter {
this.typeElement = typeElement;
this.utils = configuration.utils;
this.contents = configuration.contents;
this.resources = configuration.resources;
this.resources = configuration.docResources;
this.links = writer.links;
}

View File

@ -202,7 +202,7 @@ public class AnnotationTypeWriterImpl extends SubWriterHolderWriter
Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel);
if (!deprs.isEmpty()) {
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
List<? extends DocTree> commentTags = ch.getDescription(deprs.get(0));
if (!commentTags.isEmpty()) {
addInlineDeprecatedComment(annotationType, deprs.get(0), div);
}

View File

@ -495,7 +495,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
if (!deprs.isEmpty()) {
CommentHelper ch = utils.getCommentHelper(typeElement);
DocTree dt = deprs.get(0);
List<? extends DocTree> commentTags = ch.getBody(configuration, dt);
List<? extends DocTree> commentTags = ch.getBody(dt);
if (!commentTags.isEmpty()) {
addInlineDeprecatedComment(typeElement, deprs.get(0), div);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -182,7 +182,7 @@ public class Contents {
* resources used to look up resource keys, and other details.
*/
Contents(HtmlConfiguration configuration) {
this.resources = configuration.getResources();
this.resources = configuration.getDocResources();
allClassesLabel = getNonBreakContent("doclet.All_Classes");
allImplementedInterfacesLabel = getContent("doclet.All_Implemented_Interfaces");

View File

@ -78,7 +78,7 @@ public class HtmlConfiguration extends BaseConfiguration {
*/
public static final String HTML_DEFAULT_CHARSET = "utf-8";
public final Resources resources;
public final Resources docResources;
/**
* First file to appear in the right-hand frame in the generated
@ -133,17 +133,31 @@ public class HtmlConfiguration extends BaseConfiguration {
*/
public HtmlConfiguration(Doclet doclet, Locale locale, Reporter reporter) {
super(doclet, locale, reporter);
resources = new Resources(locale,
// Use the default locale for console messages.
Resources msgResources = new Resources(Locale.getDefault(),
BaseConfiguration.sharedResourceBundleName,
"jdk.javadoc.internal.doclets.formats.html.resources.standard");
messages = new Messages(this);
// Use the provided locale for generated docs
// Ideally, the doc resources would be in different resource files than the
// message resources, so that we do not have different copies of the same resources.
if (locale.equals(Locale.getDefault())) {
docResources = msgResources;
} else {
docResources = new Resources(locale,
BaseConfiguration.sharedResourceBundleName,
"jdk.javadoc.internal.doclets.formats.html.resources.standard");
}
messages = new Messages(this, msgResources);
contents = new Contents(this);
options = new HtmlOptions(this);
String v;
try {
ResourceBundle rb = ResourceBundle.getBundle(versionBundleName, getLocale());
// the version bundle is not localized
ResourceBundle rb = ResourceBundle.getBundle(versionBundleName, Locale.getDefault());
try {
v = rb.getString("release");
} catch (MissingResourceException e) {
@ -166,10 +180,15 @@ public class HtmlConfiguration extends BaseConfiguration {
}
@Override
public Resources getResources() {
return resources;
public Resources getDocResources() {
return docResources;
}
/**
* Returns a utility object providing commonly used fragments of content.
*
* @return a utility object providing commonly used fragments of content
*/
public Contents getContents() {
return contents;
}
@ -335,12 +354,7 @@ public class HtmlConfiguration extends BaseConfiguration {
Character unicode = (tagLabel.length() == 0)
? '*'
: Character.toUpperCase(tagLabel.charAt(0));
List<SearchIndexItem> list = tagSearchIndexMap.get(unicode);
if (list == null) {
list = new ArrayList<>();
tagSearchIndexMap.put(unicode, list);
}
list.add(sii);
tagSearchIndexMap.computeIfAbsent(unicode, k -> new ArrayList<>()).add(sii);
}
tagSearchIndexKeys = tagSearchIndexMap.keySet();
}
@ -359,7 +373,7 @@ public class HtmlConfiguration extends BaseConfiguration {
if (options.charset() == null) {
options.setCharset(options.docEncoding());
} else if (!options.charset().equals(options.docEncoding())) {
reporter.print(ERROR, resources.getText("doclet.Option_conflict", "-charset", "-docencoding"));
messages.error("doclet.Option_conflict", "-charset", "-docencoding");
return false;
}
}

View File

@ -213,7 +213,7 @@ public class HtmlDocletWriter {
this.options = configuration.getOptions();
this.contents = configuration.contents;
this.messages = configuration.messages;
this.resources = configuration.resources;
this.resources = configuration.docResources;
this.links = new Links(path);
this.utils = configuration.utils;
this.path = path;
@ -1038,14 +1038,14 @@ public class HtmlDocletWriter {
return new RawHtml(seetext);
}
boolean isLinkPlain = kind == LINK_PLAIN;
Content label = plainOrCode(isLinkPlain, new RawHtml(ch.getLabel(configuration, see)));
Content label = plainOrCode(isLinkPlain, new RawHtml(ch.getLabel(see)));
//The text from the @see tag. We will output this text when a label is not specified.
Content text = plainOrCode(kind == LINK_PLAIN, new RawHtml(seetext));
TypeElement refClass = ch.getReferencedClass(configuration, see);
String refClassName = ch.getReferencedClassName(configuration, see);
Element refMem = ch.getReferencedMember(configuration, see);
TypeElement refClass = ch.getReferencedClass(see);
String refClassName = ch.getReferencedClassName(see);
Element refMem = ch.getReferencedMember(see);
String refMemName = ch.getReferencedMemberName(see);
if (refMemName == null && refMem != null) {
@ -1053,7 +1053,7 @@ public class HtmlDocletWriter {
}
if (refClass == null) {
//@see is not referencing an included class
PackageElement refPackage = ch.getReferencedPackage(configuration, see);
PackageElement refPackage = ch.getReferencedPackage(see);
if (refPackage != null && utils.isIncluded(refPackage)) {
//@see is referencing an included package
if (label.isEmpty())
@ -1169,7 +1169,7 @@ public class HtmlDocletWriter {
*/
public void addInlineComment(Element element, DocTree tag, Content htmltree) {
CommentHelper ch = utils.getCommentHelper(element);
List<? extends DocTree> description = ch.getDescription(configuration, tag);
List<? extends DocTree> description = ch.getDescription(tag);
addCommentTags(element, tag, description, false, false, false, htmltree);
}
@ -1194,7 +1194,7 @@ public class HtmlDocletWriter {
*/
public void addInlineDeprecatedComment(Element e, DocTree tag, Content htmltree) {
CommentHelper ch = utils.getCommentHelper(e);
addCommentTags(e, ch.getBody(configuration, tag), true, false, false, htmltree);
addCommentTags(e, ch.getBody(tag), true, false, false, htmltree);
}
/**
@ -1220,8 +1220,8 @@ public class HtmlDocletWriter {
public void addSummaryDeprecatedComment(Element element, DocTree tag, Content htmltree) {
CommentHelper ch = utils.getCommentHelper(element);
List<? extends DocTree> body = ch.getBody(configuration, tag);
addCommentTags(element, ch.getFirstSentenceTrees(configuration, body), true, true, true, htmltree);
List<? extends DocTree> body = ch.getBody(tag);
addCommentTags(element, ch.getFirstSentenceTrees(body), true, true, true, htmltree);
}
/**

View File

@ -33,15 +33,12 @@ import java.util.Set;
import java.util.TreeSet;
import com.sun.tools.doclint.DocLint;
import jdk.javadoc.doclet.Reporter;
import jdk.javadoc.internal.doclets.toolkit.BaseOptions;
import jdk.javadoc.internal.doclets.toolkit.Messages;
import jdk.javadoc.internal.doclets.toolkit.Resources;
import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
import static javax.tools.Diagnostic.Kind.ERROR;
import static javax.tools.Diagnostic.Kind.WARNING;
/**
* Storage for all options supported by the
* {@link jdk.javadoc.doclet.StandardDoclet standard doclet},
@ -199,8 +196,8 @@ public class HtmlOptions extends BaseOptions {
@Override
public Set<? extends Option> getSupportedOptions() {
Resources resources = config.getResources();
Reporter reporter = config.getReporter();
Messages messages = config.getMessages();
Resources resources = messages.getResources();
List<Option> options = List.of(
new Option(resources, "--add-stylesheet", 1) {
@ -255,13 +252,11 @@ public class HtmlOptions extends BaseOptions {
@Override
public boolean process(String opt, List<String> args) {
if (noHelp) {
reporter.print(ERROR, resources.getText("doclet.Option_conflict",
"-helpfile", "-nohelp"));
messages.error("doclet.Option_conflict", "-helpfile", "-nohelp");
return false;
}
if (!helpFile.isEmpty()) {
reporter.print(ERROR, resources.getText("doclet.Option_reuse",
"-helpfile"));
messages.error("doclet.Option_reuse", "-helpfile");
return false;
}
helpFile = args.get(0);
@ -281,8 +276,7 @@ public class HtmlOptions extends BaseOptions {
public boolean process(String opt, List<String> args) {
noHelp = true;
if (!helpFile.isEmpty()) {
reporter.print(ERROR, resources.getText("doclet.Option_conflict",
"-nohelp", "-helpfile"));
messages.error("doclet.Option_conflict", "-nohelp", "-helpfile");
return false;
}
return true;
@ -302,8 +296,7 @@ public class HtmlOptions extends BaseOptions {
public boolean process(String opt, List<String> args) {
createIndex = false;
if (splitIndex) {
reporter.print(ERROR, resources.getText("doclet.Option_conflict",
"-noindex", "-splitindex"));
messages.error("doclet.Option_conflict", "-noindex", "-splitindex");
return false;
}
return true;
@ -323,8 +316,7 @@ public class HtmlOptions extends BaseOptions {
public boolean process(String opt, List<String> args) {
noOverview = true;
if (overviewPath != null) {
reporter.print(ERROR, resources.getText("doclet.Option_conflict",
"-nooverview", "-overview"));
messages.error("doclet.Option_conflict", "-nooverview", "-overview");
return false;
}
return true;
@ -344,8 +336,7 @@ public class HtmlOptions extends BaseOptions {
public boolean process(String opt, List<String> args) {
overviewPath = args.get(0);
if (noOverview) {
reporter.print(ERROR, resources.getText("doclet.Option_conflict",
"-overview", "-nooverview"));
messages.error("doclet.Option_conflict", "-overview", "-nooverview");
return false;
}
return true;
@ -365,8 +356,7 @@ public class HtmlOptions extends BaseOptions {
public boolean process(String opt, List<String> args) {
splitIndex = true;
if (!createIndex) {
reporter.print(ERROR, resources.getText("doclet.Option_conflict",
"-splitindex", "-noindex"));
messages.error("doclet.Option_conflict", "-splitindex", "-noindex");
return false;
}
return true;
@ -418,11 +408,11 @@ public class HtmlOptions extends BaseOptions {
public boolean process(String opt, List<String> args) {
String dopt = opt.replace("-Xdoclint:", DocLint.XMSGS_CUSTOM_PREFIX);
if (dopt.contains("/")) {
reporter.print(ERROR, resources.getText("doclet.Option_doclint_no_qualifiers"));
messages.error("doclet.Option_doclint_no_qualifiers");
return false;
}
if (!DocLint.isValidOption(dopt)) {
reporter.print(ERROR, resources.getText("doclet.Option_doclint_invalid_arg"));
messages.error("doclet.Option_doclint_invalid_arg");
return false;
}
doclintOpts.add(dopt);
@ -435,7 +425,7 @@ public class HtmlOptions extends BaseOptions {
public boolean process(String opt, List<String> args) {
String dopt = opt.replace("-Xdoclint/package:", DocLint.XCHECK_PACKAGE);
if (!DocLint.isValidOption(dopt)) {
reporter.print(ERROR, resources.getText("doclet.Option_doclint_package_invalid_arg"));
messages.error("doclet.Option_doclint_package_invalid_arg");
return false;
}
doclintOpts.add(dopt);
@ -450,7 +440,7 @@ public class HtmlOptions extends BaseOptions {
try {
new URL(docrootParent);
} catch (MalformedURLException e) {
reporter.print(ERROR, resources.getText("doclet.MalformedURL", docrootParent));
messages.error("doclet.MalformedURL", docrootParent);
return false;
}
return true;
@ -460,7 +450,7 @@ public class HtmlOptions extends BaseOptions {
new XOption(resources, "--no-frames") {
@Override
public boolean process(String opt, List<String> args) {
reporter.print(WARNING, resources.getText("doclet.NoFrames_specified"));
messages.warning("doclet.NoFrames_specified");
return true;
}
}
@ -477,14 +467,13 @@ public class HtmlOptions extends BaseOptions {
return false;
}
Resources resources = config.getResources();
Reporter reporter = config.getReporter();
Messages messages = config.getMessages();
// check if helpfile exists
if (!helpFile.isEmpty()) {
DocFile help = DocFile.createFileForInput(config, helpFile);
if (!help.exists()) {
reporter.print(ERROR, resources.getText("doclet.File_not_found", helpFile));
messages.error("doclet.File_not_found", helpFile);
return false;
}
}
@ -492,7 +481,7 @@ public class HtmlOptions extends BaseOptions {
if (!stylesheetFile.isEmpty()) {
DocFile stylesheet = DocFile.createFileForInput(config, stylesheetFile);
if (!stylesheet.exists()) {
reporter.print(ERROR, resources.getText("doclet.File_not_found", stylesheetFile));
messages.error("doclet.File_not_found", stylesheetFile);
return false;
}
}
@ -500,7 +489,7 @@ public class HtmlOptions extends BaseOptions {
for (String ssheet : additionalStylesheets) {
DocFile ssfile = DocFile.createFileForInput(config, ssheet);
if (!ssfile.exists()) {
reporter.print(ERROR, resources.getText("doclet.File_not_found", ssheet));
messages.error("doclet.File_not_found", ssheet);
return false;
}
}

View File

@ -180,7 +180,7 @@ public class HtmlSerialFieldWriter extends FieldWriterImpl
@Override
public void addMemberDescription(VariableElement field, DocTree serialFieldTag, Content contentTree) {
CommentHelper ch = utils.getCommentHelper(field);
List<? extends DocTree> description = ch.getDescription(configuration, serialFieldTag);
List<? extends DocTree> description = ch.getDescription(serialFieldTag);
if (!description.isEmpty()) {
Content serialFieldContent = new RawHtml(ch.getText(description));
Content div = HtmlTree.DIV(HtmlStyle.block, serialFieldContent);

View File

@ -234,7 +234,7 @@ public class LinkFactoryImpl extends LinkFactory {
* @return the tool tip for the appropriate class.
*/
private String getClassToolTip(TypeElement typeElement, boolean isTypeLink) {
Resources resources = m_writer.configuration.getResources();
Resources resources = m_writer.configuration.getDocResources();
if (isTypeLink) {
return resources.getText("doclet.Href_Type_Param_Title",
utils.getSimpleName(typeElement));

View File

@ -375,16 +375,16 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
});
// Generate the map of all services listed using @provides, and the description.
(utils.getBlockTags(mdle, DocTree.Kind.PROVIDES)).forEach((tree) -> {
TypeElement t = ch.getServiceType(configuration, tree);
TypeElement t = ch.getServiceType(tree);
if (t != null) {
providesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(configuration, tree), false, true));
providesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(tree), false, true));
}
});
// Generate the map of all services listed using @uses, and the description.
(utils.getBlockTags(mdle, DocTree.Kind.USES)).forEach((tree) -> {
TypeElement t = ch.getServiceType(configuration, tree);
TypeElement t = ch.getServiceType(tree);
if (t != null) {
usesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(configuration, tree), false, true));
usesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(tree), false, true));
}
});
}
@ -827,7 +827,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle));
deprDiv.add(deprPhrase);
if (!deprs.isEmpty()) {
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
List<? extends DocTree> commentTags = ch.getDescription(deprs.get(0));
if (!commentTags.isEmpty()) {
addInlineDeprecatedComment(mdle, deprs.get(0), deprDiv);
}
@ -892,7 +892,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
deprDiv.add(deprPhrase);
if (!deprs.isEmpty()) {
CommentHelper ch = utils.getCommentHelper(pkg);
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
List<? extends DocTree> commentTags = ch.getDescription(deprs.get(0));
if (!commentTags.isEmpty()) {
addInlineDeprecatedComment(pkg, deprs.get(0), deprDiv);
}

View File

@ -153,7 +153,7 @@ public class PackageWriterImpl extends HtmlDocletWriter
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(packageElement));
deprDiv.add(deprPhrase);
if (!deprs.isEmpty()) {
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
List<? extends DocTree> commentTags = ch.getDescription(deprs.get(0));
if (!commentTags.isEmpty()) {
addInlineDeprecatedComment(packageElement, deprs.get(0), deprDiv);
}

View File

@ -97,7 +97,7 @@ public class SourceToHTMLConverter {
this.configuration = configuration;
this.options = configuration.getOptions();
this.messages = configuration.getMessages();
this.resources = configuration.resources;
this.resources = configuration.docResources;
this.utils = configuration.utils;
this.docEnv = rd;
this.outputdir = outputdir;

View File

@ -88,7 +88,7 @@ public class TagletWriterImpl extends TagletWriter {
configuration = htmlWriter.configuration;
options = configuration.getOptions();
utils = configuration.utils;
resources = configuration.getResources();
resources = configuration.getDocResources();
}
@Override
@ -139,7 +139,7 @@ public class TagletWriterImpl extends TagletWriter {
result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
htmlWriter.getDeprecatedPhrase(element)));
if (!deprs.isEmpty()) {
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
List<? extends DocTree> commentTags = ch.getDescription(deprs.get(0));
if (!commentTags.isEmpty()) {
result.add(commentTagsToOutput(null, element, commentTags, false));
}
@ -150,7 +150,7 @@ public class TagletWriterImpl extends TagletWriter {
result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
htmlWriter.getDeprecatedPhrase(element)));
if (!deprs.isEmpty()) {
List<? extends DocTree> bodyTags = ch.getBody(configuration, deprs.get(0));
List<? extends DocTree> bodyTags = ch.getBody(deprs.get(0));
Content body = commentTagsToOutput(null, element, bodyTags, false);
if (!body.isEmpty())
result.add(HtmlTree.DIV(HtmlStyle.deprecationComment, body));
@ -191,7 +191,7 @@ public class TagletWriterImpl extends TagletWriter {
Content nameTree = new StringContent(paramName);
body.add(HtmlTree.CODE(defineID ? HtmlTree.SPAN_ID("param-" + paramName, nameTree) : nameTree));
body.add(" - ");
List<? extends DocTree> description = ch.getDescription(configuration, paramTag);
List<? extends DocTree> description = ch.getDescription(paramTag);
body.add(htmlWriter.commentTagsToContent(paramTag, element, description, false, inSummary));
return HtmlTree.DD(body);
}
@ -215,7 +215,7 @@ public class TagletWriterImpl extends TagletWriter {
result.add(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.returnLabel,
new StringContent(resources.getText("doclet.Returns")))));
result.add(HtmlTree.DD(htmlWriter.commentTagsToContent(
returnTag, element, ch.getDescription(configuration, returnTag), false, inSummary)));
returnTag, element, ch.getDescription(returnTag), false, inSummary)));
return result;
}
@ -279,7 +279,7 @@ public class TagletWriterImpl extends TagletWriter {
if (many) {
body.add(", ");
}
List<? extends DocTree> bodyTags = ch.getBody(configuration, simpleTag);
List<? extends DocTree> bodyTags = ch.getBody(simpleTag);
body.add(htmlWriter.commentTagsToContent(simpleTag, element, bodyTags, false, inSummary));
many = true;
}
@ -292,7 +292,7 @@ public class TagletWriterImpl extends TagletWriter {
ContentBuilder result = new ContentBuilder();
result.add(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.simpleTagLabel, new RawHtml(header))));
CommentHelper ch = utils.getCommentHelper(element);
List<? extends DocTree> description = ch.getDescription(configuration, simpleTag);
List<? extends DocTree> description = ch.getDescription(simpleTag);
Content body = htmlWriter.commentTagsToContent(simpleTag, element, description, false, inSummary);
result.add(HtmlTree.DD(body));
return result;
@ -317,7 +317,7 @@ public class TagletWriterImpl extends TagletWriter {
public Content throwsTagOutput(Element element, DocTree throwsTag, TypeMirror substituteType) {
ContentBuilder body = new ContentBuilder();
CommentHelper ch = utils.getCommentHelper(element);
Element exception = ch.getException(configuration, throwsTag);
Element exception = ch.getException(throwsTag);
Content excName;
if (substituteType != null) {
excName = htmlWriter.getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.MEMBER,
@ -333,7 +333,7 @@ public class TagletWriterImpl extends TagletWriter {
excName = htmlWriter.getLink(link);
}
body.add(HtmlTree.CODE(excName));
List<? extends DocTree> description = ch.getDescription(configuration, throwsTag);
List<? extends DocTree> description = ch.getDescription(throwsTag);
Content desc = htmlWriter.commentTagsToContent(throwsTag, element, description, false, inSummary);
if (desc != null && !desc.isEmpty()) {
body.add(" - ");

View File

@ -141,7 +141,7 @@ public class Navigation {
this.path = path;
this.pathToRoot = path.parent().invert();
this.links = new Links(path);
this.rowListTitle = configuration.getResources().getText("doclet.Navigation");
this.rowListTitle = configuration.getDocResources().getText("doclet.Navigation");
this.searchLabel = contents.getContent("doclet.search");
}

View File

@ -151,7 +151,7 @@ public abstract class AbstractDoclet implements Doclet {
private void reportInternalError(Throwable t) {
if (getClass().equals(StandardDoclet.class) || getClass().equals(HtmlDoclet.class)) {
System.err.println(configuration.getResources().getText("doclet.internal.report.bug"));
System.err.println(configuration.getDocResources().getText("doclet.internal.report.bug"));
}
dumpStack(true, t);
}

View File

@ -60,8 +60,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.Utils.Pair;
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberCache;
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
import static javax.tools.Diagnostic.Kind.*;
/**
* Configure the output based on the options. Doclets should sub-class
* BaseConfiguration, to configure and add their own options. This class contains
@ -154,7 +152,7 @@ public abstract class BaseConfiguration {
public abstract Messages getMessages();
public abstract Resources getResources();
public abstract Resources getDocResources();
/**
* Returns a string identifying the version of the doclet.
@ -334,9 +332,7 @@ public abstract class BaseConfiguration {
}
// add entries for modules which may not have exported packages
modules.forEach((ModuleElement mdle) -> {
modulePackages.computeIfAbsent(mdle, m -> Collections.emptySet());
});
modules.forEach(mdle -> modulePackages.computeIfAbsent(mdle, m -> Collections.emptySet()));
modules.addAll(modulePackages.keySet());
showModules = !modules.isEmpty();
@ -396,18 +392,18 @@ public abstract class BaseConfiguration {
private void initDestDirectory() throws DocletException {
String destDirName = getOptions().destDirName();
if (!destDirName.isEmpty()) {
Resources resources = getResources();
Messages messages = getMessages();
DocFile destDir = DocFile.createFileForDirectory(this, destDirName);
if (!destDir.exists()) {
//Create the output directory (in case it doesn't exist yet)
reporter.print(NOTE, resources.getText("doclet.dest_dir_create", destDirName));
messages.notice("doclet.dest_dir_create", destDirName);
destDir.mkdirs();
} else if (!destDir.isDirectory()) {
throw new SimpleDocletException(resources.getText(
throw new SimpleDocletException(messages.getResources().getText(
"doclet.destination_directory_not_directory_0",
destDir.getPath()));
} else if (!destDir.canWrite()) {
throw new SimpleDocletException(resources.getText(
throw new SimpleDocletException(messages.getResources().getText(
"doclet.destination_directory_not_writable_0",
destDir.getPath()));
}
@ -689,12 +685,12 @@ public abstract class BaseConfiguration {
*/
public boolean isJavaFXMode() {
TypeElement observable = utils.elementUtils.getTypeElement("javafx.beans.Observable");
if (observable != null) {
ModuleElement javafxModule = utils.elementUtils.getModuleOf(observable);
if (javafxModule == null || javafxModule.isUnnamed() || javafxModule.getQualifiedName().contentEquals("javafx.base")) {
return true;
}
if (observable == null) {
return false;
}
return false;
ModuleElement javafxModule = utils.elementUtils.getModuleOf(observable);
return javafxModule == null
|| javafxModule.isUnnamed()
|| javafxModule.getQualifiedName().contentEquals("javafx.base");
}
}

View File

@ -271,7 +271,7 @@ public abstract class BaseOptions {
}
public Set<? extends Option> getSupportedOptions() {
Resources resources = config.getResources();
Resources resources = config.getDocResources();
Messages messages = config.getMessages();
Reporter reporter = config.getReporter();
@ -572,7 +572,7 @@ public abstract class BaseOptions {
osw = new OutputStreamWriter(ost, docencoding);
} catch (UnsupportedEncodingException exc) {
config.reporter.print(ERROR,
config.getResources().getText("doclet.Encoding_not_supported", docencoding));
config.getDocResources().getText("doclet.Encoding_not_supported", docencoding));
return false;
} finally {
try {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -81,7 +81,7 @@ public class CommentUtils {
protected CommentUtils(BaseConfiguration configuration) {
this.configuration = configuration;
utils = configuration.utils;
resources = configuration.getResources();
resources = configuration.getDocResources();
trees = configuration.docEnv.getDocTrees();
treeFactory = trees.getDocTreeFactory();
elementUtils = configuration.docEnv.getElementUtils();

View File

@ -51,16 +51,26 @@ public class Messages {
* Creates a {@code Messages} object to provide standardized access to
* the doclet's diagnostic reporting mechanisms.
*
* @param configuration the doclet's configuration, used to access
* the doclet's resources, reporter, and additional methods and state
* used to filter out messages, if any, which should be suppressed.
* @param configuration the doclet's configuration, used to access the doclet's
* reporter, and additional methods and state used to
* filter out messages, if any, which should be suppressed.
* @param resources resources for console messages and exceptions
*/
public Messages(BaseConfiguration configuration) {
public Messages(BaseConfiguration configuration, Resources resources) {
this.configuration = configuration;
resources = configuration.getResources();
this.resources = resources;
reporter = configuration.getReporter();
}
/**
* Returns the resources being used when generating messages.
*
* @return the resources
*/
public Resources getResources() {
return resources;
}
// ***** Errors *****
/**

View File

@ -63,7 +63,6 @@ public class Resources {
* specific to a particular format
*/
public Resources(Locale locale, String commonBundleName, String docletBundleName) {
this.commonBundle = ResourceBundle.getBundle(commonBundleName, locale);
this.docletBundle = ResourceBundle.getBundle(docletBundleName, locale);

View File

@ -100,7 +100,7 @@ public abstract class AbstractBuilder {
this.options = configuration.getOptions();
this.builderFactory = configuration.getBuilderFactory();
this.messages = configuration.getMessages();
this.resources = configuration.getResources();
this.resources = configuration.getDocResources();
this.utils = configuration.utils;
this.containingPackagesSeen = c.containingPackagesSeen;
}

View File

@ -482,7 +482,7 @@ public class SerializedFormBuilder extends AbstractBuilder {
if (tag.getName() == null || tag.getType() == null) // ignore malformed @serialField tags
continue;
Content fieldsContentTree = fieldWriter.getFieldsContentHeader(tag.equals(tags.last()));
TypeElement te = ch.getReferencedClass(configuration, tag);
TypeElement te = ch.getReferencedClass(tag);
String fieldType = ch.getReferencedMemberName(tag);
if (te != null && utils.isPrimitive(te.asType())) {
fieldType = utils.getTypeName(te.asType(), false);

View File

@ -49,23 +49,13 @@ public abstract class BasePropertyTaglet extends BaseTaglet {
}
/**
* This method returns the text to be put in the resulting javadoc before
* the property name.
* Returns the text to be included in the documentation before the property name.
*
* @param tagletWriter the taglet writer for output
* @return the string to be put in the resulting javadoc.
* @param tagletWriter the taglet-writer used by the doclet
* @return the text to be included in the documentation before the property name
*/
abstract String getText(TagletWriter tagletWriter);
/**
* Given the <code>Tag</code> representation of this custom
* tag, return its string representation, which is output
* to the generated page.
* @param element
* @param tag the <code>Tag</code> representation of this custom tag.
* @param tagletWriter the taglet writer for output.
* @return the TagletOutput representation of this <code>Tag</code>.
*/
@Override
public Content getTagletOutput(Element element, DocTree tag, TagletWriter tagletWriter) {
return tagletWriter.propertyTagOutput(element, tag, getText(tagletWriter));

View File

@ -188,11 +188,21 @@ public class BaseTaglet implements Taglet {
: tree.getKind() == tagKind;
}
/**
* {@inheritDoc}
*
* @implSpec This implementation throws {@link UnsupportedTagletOperationException}.
*/
@Override
public Content getTagletOutput(Element element, DocTree tag, TagletWriter writer) {
throw new UnsupportedTagletOperationException("Method not supported in taglet " + getName() + ".");
}
/**
* {@inheritDoc}
*
* @implSpec This implementation throws {@link UnsupportedTagletOperationException}
*/
@Override
public Content getTagletOutput(Element holder, TagletWriter writer) {
throw new UnsupportedTagletOperationException("Method not supported in taglet " + getName() + ".");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -126,7 +126,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
if (rankMap.containsKey(paramName) && rankMap.get(paramName).equals((input.tagId))) {
output.holder = input.element;
output.holderTag = tag;
output.inlineTags = ch.getBody(utils.configuration, tag);
output.inlineTags = ch.getBody(tag);
return;
}
}
@ -305,7 +305,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
case RECORD_COMPONENT: key = "doclet.RecordComponents" ; break;
default: throw new IllegalArgumentException(kind.toString());
}
String header = writer.configuration().getResources().getText(key);
String header = writer.configuration().getDocResources().getText(key);
result.add(writer.getParamHeader(header));
}
result.add(writer.paramTagOutput(e, paramTag, name));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,13 +25,6 @@
package jdk.javadoc.internal.doclets.toolkit.taglets;
import java.util.List;
import javax.lang.model.element.Element;
import com.sun.source.doctree.DocTree;
import jdk.javadoc.internal.doclets.toolkit.Content;
/**
* A taglet that adds the initial line of documentation to the JavaFX
* property getters.
@ -52,6 +45,6 @@ public class PropertyGetterTaglet extends BasePropertyTaglet {
@Override
String getText(TagletWriter tagletWriter) {
return tagletWriter.configuration().getResources().getText("doclet.PropertyGetter");
return tagletWriter.configuration().getDocResources().getText("doclet.PropertyGetter");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -45,6 +45,6 @@ public class PropertySetterTaglet extends BasePropertyTaglet {
@Override
String getText(TagletWriter tagletWriter) {
return tagletWriter.configuration().getResources().getText("doclet.PropertySetter");
return tagletWriter.configuration().getDocResources().getText("doclet.PropertySetter");
}
}

View File

@ -64,8 +64,8 @@ public class ReturnTaglet extends BaseTaglet implements InheritableTaglet {
output.holder = input.element;
output.holderTag = tags.get(0);
output.inlineTags = input.isFirstSentence
? ch.getFirstSentenceTrees(input.utils.configuration, output.holderTag)
: ch.getDescription(input.utils.configuration, output.holderTag);
? ch.getFirstSentenceTrees(output.holderTag)
: ch.getDescription(output.holderTag);
}
}

View File

@ -60,7 +60,7 @@ public class SeeTaglet extends BaseTaglet implements InheritableTaglet {
output.holder = input.element;
output.holderTag = tags.get(0);
output.inlineTags = input.isFirstSentence
? ch.getFirstSentenceTrees(input.utils.configuration, output.holderTag)
? ch.getFirstSentenceTrees(output.holderTag)
: ch.getReference(output.holderTag);
}
}

View File

@ -173,8 +173,8 @@ public class SimpleTaglet extends BaseTaglet implements InheritableTaglet {
output.holderTag = tags.get(0);
CommentHelper ch = input.utils.getCommentHelper(output.holder);
output.inlineTags = input.isFirstSentence
? ch.getFirstSentenceTrees(input.utils.configuration, output.holderTag)
: ch.getTags(input.utils.configuration, output.holderTag);
? ch.getFirstSentenceTrees(output.holderTag)
: ch.getTags(output.holderTag);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -135,29 +135,28 @@ public interface Taglet {
String getName();
/**
* Given the <code>Tag</code> representation of this custom
* tag, return its Content representation, which is output
* to the generated page.
* @param holder the element holding the tag
* @param tag the <code>Tag</code> representation of this custom tag.
* @param writer a {@link TagletWriter} Taglet writer.
* @throws UnsupportedOperationException thrown when the method is not supported by the taglet.
* @return the Content representation of this <code>Tag</code>.
* Returns the content to be included in the generated output for an
* instance of a tag handled by this taglet.
*
* @param element the element for the enclosing doc comment
* @param tag the tag
* @param writer the taglet-writer used in this doclet
* @return the output for this tag
* @throws UnsupportedTagletOperationException thrown when the method is not supported by the taglet
*/
Content getTagletOutput(Element holder, DocTree tag, TagletWriter writer) throws
UnsupportedOperationException;
Content getTagletOutput(Element element, DocTree tag, TagletWriter writer) throws
UnsupportedTagletOperationException;
/**
* Given an element object, check if it holds any tags of
* this type. If it does, return the content representing the output.
* If it does not, return null.
* @param holder an element holding the custom tag.
* @param writer a {@link TagletWriter} Taglet writer.
* @throws UnsupportedTagletOperationException thrown when the method is not
* supported by the taglet.
* @return the content representation of this <code>Tag</code>.
* Returns the content to be included in the generated output for all
* instances of tags handled by this taglet.
*
* @param element the element for the enclosing doc comment
* @param writer the taglet-writer used in this doclet
* @return the output for this tag
* @throws UnsupportedTagletOperationException thrown when the method is not supported by the taglet
*/
Content getTagletOutput(Element holder, TagletWriter writer) throws
Content getTagletOutput(Element element, TagletWriter writer) throws
UnsupportedTagletOperationException;
class UnsupportedTagletOperationException extends UnsupportedOperationException {

View File

@ -199,7 +199,7 @@ public class TagletManager {
this.docEnv = configuration.docEnv;
this.doclet = configuration.doclet;
this.messages = configuration.getMessages();
this.resources = configuration.getResources();
this.resources = configuration.getDocResources();
this.showTaglets = options.showTaglets();
this.utils = configuration.utils;
this.tagletPath = options.tagletPath();

View File

@ -72,26 +72,25 @@ public class ThrowsTaglet extends BaseTaglet
Element exception;
CommentHelper ch = utils.getCommentHelper(input.element);
if (input.tagId == null) {
exception = ch.getException(utils.configuration, input.docTreeInfo.docTree);
exception = ch.getException(input.docTreeInfo.docTree);
input.tagId = exception == null
? ch.getExceptionName(input.docTreeInfo.docTree).getSignature()
: utils.getFullyQualifiedName(exception);
} else {
TypeElement element = input.utils.findClass(input.element, input.tagId);
exception = (element == null) ? null : element;
exception = input.utils.findClass(input.element, input.tagId);
}
for (DocTree dt : input.utils.getThrowsTrees(input.element)) {
Element texception = ch.getException(utils.configuration, dt);
if (texception != null && (input.tagId.equals(utils.getSimpleName(texception)) ||
(input.tagId.equals(utils.getFullyQualifiedName(texception))))) {
Element exc = ch.getException(dt);
if (exc != null && (input.tagId.equals(utils.getSimpleName(exc)) ||
(input.tagId.equals(utils.getFullyQualifiedName(exc))))) {
output.holder = input.element;
output.holderTag = dt;
output.inlineTags = ch.getBody(input.utils.configuration, output.holderTag);
output.inlineTags = ch.getBody(output.holderTag);
output.tagList.add(dt);
} else if (exception != null && texception != null &&
utils.isTypeElement(texception) && utils.isTypeElement(exception) &&
utils.isSubclassOf((TypeElement)texception, (TypeElement)exception)) {
} else if (exception != null && exc != null &&
utils.isTypeElement(exc) && utils.isTypeElement(exception) &&
utils.isSubclassOf((TypeElement)exc, (TypeElement)exception)) {
output.tagList.add(dt);
}
}
@ -106,15 +105,15 @@ public class ThrowsTaglet extends BaseTaglet
Content result = writer.getOutputInstance();
//Add links to the exceptions declared but not documented.
for (TypeMirror declaredExceptionType : declaredExceptionTypes) {
TypeElement klass = utils.asTypeElement(declaredExceptionType);
if (klass != null &&
TypeElement te = utils.asTypeElement(declaredExceptionType);
if (te != null &&
!alreadyDocumented.contains(declaredExceptionType.toString()) &&
!alreadyDocumented.contains(utils.getFullyQualifiedName(klass, false))) {
!alreadyDocumented.contains(utils.getFullyQualifiedName(te, false))) {
if (alreadyDocumented.isEmpty()) {
result.add(writer.getThrowsHeader());
}
result.add(writer.throwsTagOutput(declaredExceptionType));
alreadyDocumented.add(utils.getSimpleName(klass));
alreadyDocumented.add(utils.getSimpleName(te));
}
}
return result;
@ -176,18 +175,17 @@ public class ThrowsTaglet extends BaseTaglet
}
/**
* Given an array of <code>Tag</code>s representing this custom
* tag, return its string representation.
* @param throwTags the array of <code>ThrowsTag</code>s to convert.
* @param writer the TagletWriter that will write this tag.
* @param alreadyDocumented the set of exceptions that have already
* been documented.
* @param allowDups True if we allow duplicate throws tags to be documented.
* @return the Content representation of this <code>Tag</code>.
* Returns the generated content for a collection of {@code @throws} tags.
*
* @param throwTags the collection of tags to be converted
* @param writer the taglet-writer used by the doclet
* @param alreadyDocumented the set of exceptions that have already been documented
* @param allowDuplicates {@code true} if we allow duplicate tags to be documented
* @return the generated content for the tags
*/
protected Content throwsTagsOutput(Map<List<? extends DocTree>, ExecutableElement> throwTags,
TagletWriter writer, Set<String> alreadyDocumented,
Map<String,TypeMirror> typeSubstitutions, boolean allowDups) {
Map<String,TypeMirror> typeSubstitutions, boolean allowDuplicates) {
Utils utils = writer.configuration().utils;
Content result = writer.getOutputInstance();
if (!throwTags.isEmpty()) {
@ -195,10 +193,10 @@ public class ThrowsTaglet extends BaseTaglet
CommentHelper ch = utils.getCommentHelper(entry.getValue());
Element e = entry.getValue();
for (DocTree dt : entry.getKey()) {
Element te = ch.getException(utils.configuration, dt);
Element te = ch.getException(dt);
String excName = ch.getExceptionName(dt).toString();
TypeMirror substituteType = typeSubstitutions.get(excName);
if ((!allowDups) &&
if ((!allowDuplicates) &&
(alreadyDocumented.contains(excName) ||
(te != null && alreadyDocumented.contains(utils.getFullyQualifiedName(te, false)))) ||
(substituteType != null && alreadyDocumented.contains(substituteType.toString()))) {

View File

@ -77,7 +77,7 @@ public class ValueTaglet extends BaseTaglet {
Element e = signature == null
? holder
: ch.getReferencedMember(config, tag);
: ch.getReferencedMember(tag);
return (e != null && config.utils.isVariableElement(e))
? (VariableElement) e

View File

@ -28,11 +28,10 @@ package jdk.javadoc.internal.doclets.toolkit.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
@ -84,18 +83,27 @@ import static com.sun.source.doctree.DocTree.Kind.*;
* deletion without notice.</b>
*/
public class CommentHelper {
private final BaseConfiguration configuration;
public final TreePath path;
public final DocCommentTree dctree;
public final DocCommentTree dcTree;
public final Element element;
private Element overriddenElement;
public static final String SPACER = " ";
public CommentHelper(BaseConfiguration configuration, Element element, TreePath path, DocCommentTree dctree) {
//this.configuration = configuration;
/**
* Creates a utility class to encapsulate the contextual information for a doc comment tree.
*
* @param configuration the configuration
* @param element the element for which this is a doc comment
* @param path the path for the element
* @param dcTree the doc comment
*/
public CommentHelper(BaseConfiguration configuration, Element element, TreePath path, DocCommentTree dcTree) {
this.configuration = configuration;
this.element = element;
this.path = path;
this.dctree = dctree;
this.dcTree = dcTree;
}
public void setOverrideElement(Element ove) {
@ -144,17 +152,18 @@ public class CommentHelper {
}
}
Element getElement(BaseConfiguration c, ReferenceTree rtree) {
Element getElement(ReferenceTree rtree) {
Utils utils = configuration.utils;
// likely a synthesized tree
if (path == null) {
// NOTE: this code path only supports module/package/type signatures
// and not member signatures. For more complete support,
// set a suitable path and avoid this branch.
TypeMirror symbol = c.utils.getSymbol(rtree.getSignature());
TypeMirror symbol = utils.getSymbol(rtree.getSignature());
if (symbol == null) {
return null;
}
return c.docEnv.getTypeUtils().asElement(symbol);
return configuration.docEnv.getTypeUtils().asElement(symbol);
}
// case A: the element contains no comments associated and
// the comments need to be copied from ancestor
@ -162,37 +171,37 @@ public class CommentHelper {
// as appropriate has to be copied over.
// Case A.
if (dctree == null && overriddenElement != null) {
CommentHelper ovch = c.utils.getCommentHelper(overriddenElement);
return ovch.getElement(c, rtree);
if (dcTree == null && overriddenElement != null) {
CommentHelper ovch = utils.getCommentHelper(overriddenElement);
return ovch.getElement(rtree);
}
if (dctree == null) {
if (dcTree == null) {
return null;
}
DocTreePath docTreePath = DocTreePath.getPath(path, dctree, rtree);
DocTreePath docTreePath = DocTreePath.getPath(path, dcTree, rtree);
if (docTreePath == null) {
// Case B.
if (overriddenElement != null) {
CommentHelper ovch = c.utils.getCommentHelper(overriddenElement);
return ovch.getElement(c, rtree);
CommentHelper ovch = utils.getCommentHelper(overriddenElement);
return ovch.getElement(rtree);
}
return null;
}
DocTrees doctrees = c.docEnv.getDocTrees();
DocTrees doctrees = configuration.docEnv.getDocTrees();
return doctrees.getElement(docTreePath);
}
public Element getException(BaseConfiguration c, DocTree dtree) {
public Element getException(DocTree dtree) {
if (dtree.getKind() == THROWS || dtree.getKind() == EXCEPTION) {
ThrowsTree tt = (ThrowsTree)dtree;
ReferenceTree exceptionName = tt.getExceptionName();
return getElement(c, exceptionName);
return getElement(exceptionName);
}
return null;
}
public List<? extends DocTree> getDescription(BaseConfiguration c, DocTree dtree) {
return getTags(c, dtree);
public List<? extends DocTree> getDescription(DocTree dtree) {
return getTags(dtree);
}
public String getText(List<? extends DocTree> list) {
@ -224,16 +233,14 @@ public class CommentHelper {
quote = "\"";
break;
case SINGLE:
quote = "\'";
quote = "'";
break;
default:
quote = "";
break;
}
sb.append(quote);
node.getValue().stream().forEach((dt) -> {
dt.accept(this, null);
});
node.getValue().forEach(dt -> dt.accept(this, null));
sb.append(quote);
return null;
}
@ -259,9 +266,7 @@ public class CommentHelper {
}
node.getReference().accept(this, null);
node.getLabel().stream().forEach((dt) -> {
dt.accept(this, null);
});
node.getLabel().forEach(dt -> dt.accept(this, null) );
return null;
}
@ -285,17 +290,13 @@ public class CommentHelper {
@Override
public Void visitSee(SeeTree node, Void p) {
node.getReference().stream().forEach((dt) -> {
dt.accept(this, null);
});
node.getReference().forEach(dt -> dt.accept(this, null));
return null;
}
@Override
public Void visitSerial(SerialTree node, Void p) {
node.getDescription().stream().forEach((dt) -> {
dt.accept(this, null);
});
node.getDescription().forEach(dt -> dt.accept(this, null));
return null;
}
@ -303,9 +304,7 @@ public class CommentHelper {
public Void visitStartElement(StartElementTree node, Void p) {
sb.append("<");
sb.append(node.getName());
node.getAttributes().stream().forEach((dt) -> {
dt.accept(this, null);
});
node.getAttributes().forEach(dt -> dt.accept(this, null));
sb.append((node.isSelfClosing() ? "/>" : ">"));
return null;
}
@ -318,9 +317,7 @@ public class CommentHelper {
@Override
public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
node.getContent().stream().forEach((dt) -> {
dt.accept(this, null);
});
node.getContent().forEach(dt -> dt.accept(this, null));
return null;
}
@ -338,24 +335,22 @@ public class CommentHelper {
return sb;
}
public String getLabel(BaseConfiguration c, DocTree dtree) {
public String getLabel(DocTree dtree) {
return new SimpleDocTreeVisitor<String, Void>() {
@Override
public String visitLink(LinkTree node, Void p) {
StringBuilder sb = new StringBuilder();
node.getLabel().stream().forEach((dt) -> {
sb.append(getText(dt));
});
return sb.toString();
return node.getLabel().stream()
.map(dt -> getText(dt))
.collect(Collectors.joining());
}
@Override
public String visitSee(SeeTree node, Void p) {
StringBuilder sb = new StringBuilder();
node.getReference().stream().filter((dt) -> (c.utils.isText(dt))).forEach((dt) -> {
sb.append(((TextTree)dt).getBody());
});
return sb.toString();
Utils utils = configuration.utils;
return node.getReference().stream()
.filter(utils::isText)
.map(dt -> ((TextTree) dt).getBody())
.collect(Collectors.joining());
}
@Override
@ -365,22 +360,24 @@ public class CommentHelper {
}.visit(dtree, null);
}
public TypeElement getReferencedClass(BaseConfiguration c, DocTree dtree) {
Element e = getReferencedElement(c, dtree);
public TypeElement getReferencedClass(DocTree dtree) {
Utils utils = configuration.utils;
Element e = getReferencedElement(dtree);
if (e == null) {
return null;
} else if (c.utils.isTypeElement(e)) {
} else if (utils.isTypeElement(e)) {
return (TypeElement) e;
} else if (!c.utils.isPackage(e)) {
return c.utils.getEnclosingTypeElement(e);
} else if (!utils.isPackage(e)) {
return utils.getEnclosingTypeElement(e);
}
return null;
}
public String getReferencedClassName(BaseConfiguration c, DocTree dtree) {
Element e = getReferencedClass(c, dtree);
public String getReferencedClassName(DocTree dtree) {
Utils utils = configuration.utils;
Element e = getReferencedClass(dtree);
if (e != null) {
return c.utils.isTypeElement(e) ? c.utils.getSimpleName(e) : null;
return utils.isTypeElement(e) ? utils.getSimpleName(e) : null;
}
String s = getReferencedSignature(dtree);
if (s == null) {
@ -390,12 +387,13 @@ public class CommentHelper {
return (n == -1) ? s : s.substring(0, n);
}
public Element getReferencedMember(BaseConfiguration c, DocTree dtree) {
Element e = getReferencedElement(c, dtree);
public Element getReferencedMember(DocTree dtree) {
Utils utils = configuration.utils;
Element e = getReferencedElement(dtree);
if (e == null) {
return null;
}
return (c.utils.isExecutableElement(e) || c.utils.isVariableElement(e)) ? e : null;
return (utils.isExecutableElement(e) || utils.isVariableElement(e)) ? e : null;
}
public String getReferencedMemberName(DocTree dtree) {
@ -407,33 +405,34 @@ public class CommentHelper {
return (n == -1) ? null : s.substring(n + 1);
}
public String getReferencedMemberName(BaseConfiguration c, Element e) {
public String getReferencedMemberName(Element e) {
if (e == null) {
return null;
}
return c.utils.isExecutableElement(e)
? c.utils.getSimpleName(e) + c.utils.makeSignature((ExecutableElement) e, true, true)
: c.utils.getSimpleName(e);
Utils utils = configuration.utils;
return utils.isExecutableElement(e)
? utils.getSimpleName(e) + utils.makeSignature((ExecutableElement) e, true, true)
: utils.getSimpleName(e);
}
public PackageElement getReferencedPackage(BaseConfiguration c, DocTree dtree) {
Element e = getReferencedElement(c, dtree);
public PackageElement getReferencedPackage(DocTree dtree) {
Element e = getReferencedElement(dtree);
if (e != null) {
return c.utils.containingPackage(e);
Utils utils = configuration.utils;
return utils.containingPackage(e);
}
return null;
}
public List<? extends DocTree> getFirstSentenceTrees(BaseConfiguration c, List<? extends DocTree> body) {
List<DocTree> firstSentence = c.docEnv.getDocTrees().getFirstSentence(body);
return firstSentence;
public List<? extends DocTree> getFirstSentenceTrees(List<? extends DocTree> body) {
return configuration.docEnv.getDocTrees().getFirstSentence(body);
}
public List<? extends DocTree> getFirstSentenceTrees(BaseConfiguration c, DocTree dtree) {
return getFirstSentenceTrees(c, getBody(c, dtree));
public List<? extends DocTree> getFirstSentenceTrees(DocTree dtree) {
return getFirstSentenceTrees(getBody(dtree));
}
private Element getReferencedElement(BaseConfiguration c, DocTree dtree) {
private Element getReferencedElement(DocTree dtree) {
return new SimpleDocTreeVisitor<Element, Void>() {
@Override
public Element visitSee(SeeTree node, Void p) {
@ -460,7 +459,7 @@ public class CommentHelper {
@Override
public Element visitReference(ReferenceTree node, Void p) {
return getElement(c, node);
return getElement(node);
}
@Override
@ -480,10 +479,11 @@ public class CommentHelper {
}.visit(dtree, null);
}
public TypeElement getServiceType(BaseConfiguration c, DocTree dtree) {
Element e = getReferencedElement(c, dtree);
public TypeElement getServiceType(DocTree dtree) {
Element e = getReferencedElement(dtree);
if (e != null) {
return c.utils.isTypeElement(e) ? (TypeElement) e : null;
Utils utils = configuration.utils;
return utils.isTypeElement(e) ? (TypeElement) e : null;
}
return null;
}
@ -546,11 +546,11 @@ public class CommentHelper {
}
}
public List<? extends DocTree> getTags(BaseConfiguration c, DocTree dtree) {
public List<? extends DocTree> getTags(DocTree dtree) {
return new SimpleDocTreeVisitor<List<? extends DocTree>, Void>() {
List<? extends DocTree> asList(String content) {
List<DocTree> out = new ArrayList<>();
out.add(c.cmtUtils.makeTextTree(content));
out.add(configuration.cmtUtils.makeTextTree(content));
return out;
}
@ -651,22 +651,22 @@ public class CommentHelper {
}.visit(dtree, null);
}
public List<? extends DocTree> getBody(BaseConfiguration c, DocTree dtree) {
return getTags(c, dtree);
public List<? extends DocTree> getBody(DocTree dtree) {
return getTags(dtree);
}
public ReferenceTree getType(DocTree dtree) {
if (dtree.getKind() == SERIAL_FIELD) {
return ((SerialFieldTree)dtree).getType();
return ((SerialFieldTree) dtree).getType();
} else {
return null;
}
}
public DocTreePath getDocTreePath(DocTree dtree) {
if (path == null || dctree == null || dtree == null)
if (path == null || dcTree == null || dtree == null)
return null;
return DocTreePath.getPath(path, dctree, dtree);
return DocTreePath.getPath(path, dcTree, dtree);
}
public Element getOverriddenElement() {
@ -680,7 +680,7 @@ public class CommentHelper {
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder("CommentHelper{" + "path=" + path + ", dctree=" + dctree);
StringBuilder sb = new StringBuilder("CommentHelper{" + "path=" + path + ", dcTree=" + dcTree);
sb.append(", element=");
sb.append(element.getEnclosingElement());
sb.append("::");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -134,7 +134,7 @@ public class Extern {
public Extern(BaseConfiguration configuration) {
this.configuration = configuration;
this.resources = configuration.getResources();
this.resources = configuration.getDocResources();
this.utils = configuration.utils;
}

View File

@ -240,8 +240,8 @@ public class Group {
Map<String, SortedSet<ModuleElement>> groupModuleMap = new HashMap<>();
String defaultGroupName =
(elementNameGroupMap.isEmpty() && regExpGroupMap.isEmpty())?
configuration.getResources().getText("doclet.Modules") :
configuration.getResources().getText("doclet.Other_Modules");
configuration.getDocResources().getText("doclet.Modules") :
configuration.getDocResources().getText("doclet.Other_Modules");
// if the user has not used the default group name, add it
if (!groupList.contains(defaultGroupName)) {
groupList.add(defaultGroupName);
@ -282,8 +282,8 @@ public class Group {
Map<String, SortedSet<PackageElement>> groupPackageMap = new HashMap<>();
String defaultGroupName =
(elementNameGroupMap.isEmpty() && regExpGroupMap.isEmpty())?
configuration.getResources().getText("doclet.Packages") :
configuration.getResources().getText("doclet.Other_Packages");
configuration.getDocResources().getText("doclet.Packages") :
configuration.getDocResources().getText("doclet.Other_Packages");
// if the user has not used the default group name, add it
if (!groupList.contains(defaultGroupName)) {
groupList.add(defaultGroupName);

View File

@ -58,7 +58,7 @@ public class MetaKeywords {
*/
public MetaKeywords(BaseConfiguration configuration) {
options = configuration.getOptions();
resources = configuration.getResources();
resources = configuration.getDocResources();
utils = configuration.utils;
}

View File

@ -86,7 +86,7 @@ class StandardDocFileFactory extends DocFileFactory {
fileManager.setLocationFromPaths(DocumentationTool.Location.DOCUMENTATION_OUTPUT, Arrays.asList(dir));
} catch (IOException e) {
// generic IOException from file manager, setting location, e.g. file not a directory
String message = configuration.getResources().getText("doclet.error.initializing.dest.dir", e);
String message = configuration.getDocResources().getText("doclet.error.initializing.dest.dir", e);
throw new SimpleDocletException(message, e);
}
}

View File

@ -32,9 +32,28 @@ import java.text.CollationKey;
import java.text.Collator;
import java.text.ParseException;
import java.text.RuleBasedCollator;
import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -125,7 +144,7 @@ public class Utils {
configuration = c;
options = configuration.getOptions();
messages = configuration.getMessages();
resources = configuration.getResources();
resources = configuration.getDocResources();
elementUtils = c.docEnv.getElementUtils();
typeUtils = c.docEnv.getTypeUtils();
docTrees = c.docEnv.getDocTrees();
@ -937,7 +956,7 @@ public class Utils {
* @return
*/
public TypeMirror getDeclaredType(Collection<TypeMirror> values,
TypeElement enclosing, TypeMirror target) {
TypeElement enclosing, TypeMirror target) {
TypeElement targetElement = asTypeElement(target);
List<? extends TypeParameterElement> targetTypeArgs = targetElement.getTypeParameters();
if (targetTypeArgs.isEmpty()) {
@ -2546,7 +2565,7 @@ public class Utils {
}.visit(e);
}
EnumSet<ElementKind> nestedKinds = EnumSet.of(ANNOTATION_TYPE, CLASS, ENUM, INTERFACE);
Set<ElementKind> nestedKinds = EnumSet.of(ANNOTATION_TYPE, CLASS, ENUM, INTERFACE);
void recursiveGetItems(Collection<Element> list, Element e, boolean filter, ElementKind... select) {
list.addAll(getItems0(e, filter, select));
List<Element> classes = getItems0(e, filter, nestedKinds);
@ -2559,7 +2578,7 @@ public class Utils {
}
private List<Element> getItems0(Element te, boolean filter, ElementKind... select) {
EnumSet<ElementKind> kinds = EnumSet.copyOf(Arrays.asList(select));
Set<ElementKind> kinds = EnumSet.copyOf(Arrays.asList(select));
return getItems0(te, filter, kinds);
}
@ -3002,14 +3021,14 @@ public class Utils {
return doctree.getKind() == match;
}
private final WeakSoftHashMap wksMap = new WeakSoftHashMap(this);
private final CommentHelperCache commentHelperCache = new CommentHelperCache(this);
public CommentHelper getCommentHelper(Element element) {
return wksMap.computeIfAbsent(element);
return commentHelperCache.computeIfAbsent(element);
}
public void removeCommentHelper(Element element) {
wksMap.remove(element);
commentHelperCache.remove(element);
}
public List<? extends DocTree> getBlockTags(Element element) {
@ -3177,13 +3196,13 @@ public class Utils {
}
public DocCommentTree getDocCommentTree(Element element) {
CommentHelper ch = wksMap.get(element);
CommentHelper ch = commentHelperCache.get(element);
if (ch != null) {
return ch.dctree;
return ch.dcTree;
}
DocCommentTree dcTree = getDocCommentTree0(element);
if (dcTree != null) {
wksMap.put(element, new CommentHelper(configuration, element, getTreePath(element), dcTree));
commentHelperCache.put(element, new CommentHelper(configuration, element, getTreePath(element), dcTree));
}
return dcTree;
}
@ -3297,106 +3316,48 @@ public class Utils {
return outer;
}
static class WeakSoftHashMap implements Map<Element, CommentHelper> {
/**
* A memory-sensitive cache for {@link CommentHelper} objects,
* which are expensive to compute.
*/
private static class CommentHelperCache {
private final WeakHashMap<Element, SoftReference<CommentHelper>> wkMap;
private final Map<Element, SoftReference<CommentHelper>> map;
private final Utils utils;
public WeakSoftHashMap(Utils utils) {
wkMap = new WeakHashMap<>();
public CommentHelperCache(Utils utils) {
map = new HashMap<>();
this.utils = utils;
}
@Override
public boolean containsKey(Object key) {
return wkMap.containsKey(key);
}
@Override
public Collection<CommentHelper> values() {
Set<CommentHelper> out = new LinkedHashSet<>();
for (SoftReference<CommentHelper> v : wkMap.values()) {
out.add(v.get());
}
return out;
}
@Override
public boolean containsValue(Object value) {
return wkMap.containsValue(new SoftReference<>((CommentHelper)value));
}
@Override
public CommentHelper remove(Object key) {
SoftReference<CommentHelper> value = wkMap.remove(key);
public CommentHelper remove(Element key) {
SoftReference<CommentHelper> value = map.remove(key);
return value == null ? null : value.get();
}
@Override
public CommentHelper put(Element key, CommentHelper value) {
SoftReference<CommentHelper> nvalue = wkMap.put(key, new SoftReference<>(value));
return nvalue == null ? null : nvalue.get();
SoftReference<CommentHelper> prev = map.put(key, new SoftReference<>(value));
return prev == null ? null : prev.get();
}
@Override
public CommentHelper get(Object key) {
SoftReference<CommentHelper> value = wkMap.get(key);
SoftReference<CommentHelper> value = map.get(key);
return value == null ? null : value.get();
}
@Override
public int size() {
return wkMap.size();
}
@Override
public boolean isEmpty() {
return wkMap.isEmpty();
}
@Override
public void clear() {
wkMap.clear();
}
public CommentHelper computeIfAbsent(Element key) {
if (wkMap.containsKey(key)) {
SoftReference<CommentHelper> value = wkMap.get(key);
SoftReference<CommentHelper> refValue = map.get(key);
if (refValue != null) {
CommentHelper value = refValue.get();
if (value != null) {
CommentHelper cvalue = value.get();
if (cvalue != null) {
return cvalue;
}
return value;
}
}
CommentHelper newValue = new CommentHelper(utils.configuration, key, utils.getTreePath(key),
utils.getDocCommentTree(key));
wkMap.put(key, new SoftReference<>(newValue));
map.put(key, new SoftReference<>(newValue));
return newValue;
}
@Override
public void putAll(Map<? extends Element, ? extends CommentHelper> map) {
for (Map.Entry<? extends Element, ? extends CommentHelper> entry : map.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
@Override
public Set<Element> keySet() {
return wkMap.keySet();
}
@Override
public Set<Entry<Element, CommentHelper>> entrySet() {
Set<Entry<Element, CommentHelper>> out = new LinkedHashSet<>();
for (Element e : wkMap.keySet()) {
SimpleEntry<Element, CommentHelper> n = new SimpleEntry<>(e, get(e));
out.add(n);
}
return out;
}
}
/**

View File

@ -399,14 +399,14 @@ public class Start {
Throwable t = e.getCause();
dumpStack(t == null ? e : t);
return ERROR;
} catch (OptionException toe) {
if (toe.message != null)
messager.printError(toe.message);
} catch (OptionException oe) {
if (oe.message != null)
messager.printError(oe.message);
toe.m.run();
Throwable t = toe.getCause();
dumpStack(t == null ? toe : t);
return toe.result;
oe.m.run();
Throwable t = oe.getCause();
dumpStack(t == null ? oe : t);
return oe.result;
} catch (ToolException exc) {
if (exc.message != null) {
messager.printError(exc.message);
@ -733,7 +733,7 @@ public class Start {
}
if (Doclet.class.isAssignableFrom(docletClass)) {
messager.setLocale(locale);
messager.setLocale(Locale.getDefault()); // use default locale for console messages
try {
Object o = docletClass.getConstructor().newInstance();
doclet = (Doclet) o;
@ -818,10 +818,6 @@ public class Start {
messager.printErrorUsingKey(key, args);
}
void warn(String key, Object... args) {
messager.printWarningUsingKey(key, args);
}
/**
* Get the locale if specified on the command line
* else return null and if locale option is not used
@ -841,21 +837,4 @@ public class Start {
}
}
/**
* Search the locale for specified language, specified country and
* specified variant.
*/
private Locale searchLocale(String language, String country,
String variant) {
for (Locale loc : Locale.getAvailableLocales()) {
if (loc.getLanguage().equals(language) &&
(country == null || loc.getCountry().equals(country)) &&
(variant == null || loc.getVariant().equals(variant))) {
return loc;
}
}
return null;
}
}

View File

@ -47,6 +47,21 @@ import jdk.tools.jlink.plugin.Plugin;
/**
* Plugin to generate java.lang.invoke classes.
*
* The plugin reads in a file generated by running any application with
* {@code -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true}. This is done
* automatically during build, see make/GenerateLinkOptData.gmk. See
* build/tools/classlist/HelloClasslist.java for the training application.
*
* HelloClasslist tries to reflect common use of java.lang.invoke during early
* startup and warmup in various applications. To ensure a good default
* trade-off between static footprint and startup the application should be
* relatively conservative.
*
* When using jlink to build a custom application runtime, generating a trace
* file using {@code -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true} and
* feeding that into jlink using {@code --generate-jli-classes=@trace_file} can
* help improve startup time.
*/
public final class GenerateJLIClassesPlugin implements Plugin {
@ -112,59 +127,6 @@ public final class GenerateJLIClassesPlugin implements Plugin {
return PluginsResourceBundle.getArgument(NAME);
}
/**
* @return the default Species forms to generate.
*
* This list was derived from running a small startup benchmark.
* A better long-term solution is to define and run a set of quick
* generators and extracting this list as a step in the build process.
*/
public static Set<String> defaultSpecies() {
return Set.of("LL", "L3", "L4", "L5", "L6", "L7", "L7I",
"L7II", "L7IIL", "L8", "L9", "L10", "L10I", "L10II", "L10IIL",
"L11", "L12", "L13", "LI", "D", "L3I", "LIL", "LLI", "LLIL",
"LILL", "I", "LLILL");
}
/**
* @return the default invoker forms to generate.
*/
private static Set<String> defaultInvokers() {
return Set.of("LL_L", "LL_I", "LLLL_L", "LLLL_I", "LLIL_L", "LLIL_I",
"L6_L");
}
/**
* @return the default call site forms to generate (linkToTargetMethod).
*/
private static Set<String> defaultCallSiteTypes() {
return Set.of("L5_L", "LIL3_L", "ILL_L");
}
/**
* @return the list of default DirectMethodHandle methods to generate.
*/
private static Map<String, Set<String>> defaultDMHMethods() {
return Map.of(
DMH_INVOKE_INTERFACE, Set.of("LL_L", "L3_I", "L3_V"),
DMH_INVOKE_VIRTUAL, Set.of("LL_L", "LLI_I", "L3_V"),
DMH_INVOKE_SPECIAL, Set.of("LL_I", "LL_L", "LLF_L", "LLD_L",
"L3_I", "L3_L", "L4_L", "L5_L", "L6_L", "L7_L", "L8_L",
"LLI_I", "LLI_L", "LLIL_I", "LLIL_L", "LLII_I", "LLII_L",
"L3I_L", "L3I_I", "L3ILL_L", "LLILI_I", "LLIIL_L", "LLIILL_L",
"LLIILL_I", "LLIIL_I", "LLILIL_I", "LLILILL_I", "LLILII_I",
"LLI3_I", "LLI3L_I", "LLI3LL_I", "LLI3_L", "LLI4_I"),
DMH_INVOKE_STATIC, Set.of("LII_I", "LIL_I", "LILIL_I", "LILII_I",
"L_I", "L_L", "L_V", "LD_L", "LF_L", "LI_I", "LII_L", "LLI_L",
"LL_I", "LLILL_L", "LLIL3_L", "LL_V", "LL_L", "L3_I", "L3_L",
"L3_V", "L4_I", "L4_L", "L5_L", "L6_L", "L7_L", "L8_L", "L9_L",
"L10_L", "L10I_L", "L10II_L", "L10IIL_L", "L11_L", "L12_L",
"L13_L", "L14_L", "L14I_L", "L14II_L"),
DMH_NEW_INVOKE_SPECIAL, Set.of("L_L", "LL_L"),
DMH_INVOKE_SPECIAL_IFC, Set.of("L5_I")
);
}
private static int DMH_INVOKE_VIRTUAL_TYPE = 0;
private static int DMH_INVOKE_INTERFACE_TYPE = 4;
@ -201,19 +163,8 @@ public final class GenerateJLIClassesPlugin implements Plugin {
}
public void initialize(ResourcePool in) {
// Start with the default configuration
defaultSpecies().stream().forEach(this::addSpeciesType);
defaultInvokers().stream().forEach(this::validateMethodType);
defaultCallSiteTypes().stream().forEach(this::addCallSiteType);
defaultDMHMethods().entrySet().stream().forEach(e -> {
e.getValue().stream().forEach(type -> addDMHMethodType(e.getKey(), type));
});
// Extend the default configuration with the contents in the supplied
// input file - if none was supplied we look for the default file
// Load configuration from the contents in the supplied input file
// - if none was supplied we look for the default file
if (mainArgument == null || !mainArgument.startsWith("@")) {
try (InputStream traceFile =
this.getClass().getResourceAsStream(DEFAULT_TRACE_FILE)) {

View File

@ -1,4 +1,4 @@
## Unicode Common Local Data Repository (CLDR) v35.1
## Unicode Common Local Data Repository (CLDR) v36
### CLDR License

View File

@ -177,6 +177,7 @@ ctw_3 = \
applications/ctw/modules/jdk_compiler.java \
applications/ctw/modules/jdk_internal_vm_compiler.java \
applications/ctw/modules/jdk_localedata.java \
applications/ctw/modules/jdk_localedata_2.java \
applications/ctw/modules/jdk_scripting_nashorn.java \
tier1_gc = \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/*
* @test
* @summary run CTW for all classes from jdk.localedata module
* @summary run CTW for some classes from jdk.localedata module
*
* @library /test/lib / /testlibrary/ctw/src
* @modules java.base/jdk.internal.access
@ -35,5 +35,5 @@
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run driver/timeout=7200 sun.hotspot.tools.ctw.CtwRunner modules:jdk.localedata
* @run driver/timeout=7200 sun.hotspot.tools.ctw.CtwRunner modules:jdk.localedata 0% 50%
*/

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary run CTW for some classes from jdk.localedata module
*
* @library /test/lib / /testlibrary/ctw/src
* @modules java.base/jdk.internal.access
* java.base/jdk.internal.jimage
* java.base/jdk.internal.misc
* java.base/jdk.internal.reflect
* @modules jdk.localedata
*
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run driver/timeout=7200 sun.hotspot.tools.ctw.CtwRunner modules:jdk.localedata 50% 100%
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -60,11 +60,6 @@ public class TestJFREvents {
DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
try {
// leave one CPU for system and tools, otherwise this test may be unstable
int maxNrOfAvailableCpus = availableCPUs - 1;
for (int i=1; i < maxNrOfAvailableCpus; i = i * 2) {
testCPUInfo(i, i);
}
long MB = 1024*1024;
testMemory("200m", "" + 200*MB);
@ -79,18 +74,26 @@ public class TestJFREvents {
}
}
// This test case is currently not in use.
// Once new Container events are available, this test case can be used to test
// processor-related configuration such as active processor count (see JDK-8203359).
private static void cpuTestCase() throws Exception {
// leave one CPU for system and tools, otherwise this test may be unstable
int maxNrOfAvailableCpus = availableCPUs - 1;
for (int i=1; i < maxNrOfAvailableCpus; i = i * 2) {
testCPUInfo("jdk.ContainerConfiguration", i, i);
}
}
private static void testCPUInfo(int valueToSet, int expectedValue) throws Exception {
private static void testCPUInfo(String eventName, int valueToSet, int expectedValue) throws Exception {
Common.logNewTestCase("CPUInfo: --cpus = " + valueToSet);
String fieldName = "activeProcessorCount";
DockerTestUtils.dockerRunJava(
commonDockerOpts()
.addDockerOpts("--cpus=" + valueToSet)
.addClassOptions("jdk.CPUInformation"))
.shouldHaveExitValue(0);
// The following assertion is currently disabled due to JFR reporting incorrect values.
// JFR reports values for the host system as opposed to values for the container.
// @ignore 8219999
// .shouldContain("cores = " + expectedValue");
.addClassOptions(eventName))
.shouldHaveExitValue(0)
.shouldContain(fieldName + " = " + expectedValue);
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2020, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8237837
* @summary Shenandoah: assert(mem == __null) failed: only one safepoint
* @key gc
* @requires vm.flavor == "server"
* @requires vm.gc.Shenandoah & !vm.graal.enabled
*
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xcomp -XX:CompileOnly=BarrierInInfiniteLoop::test -XX:CompileCommand=quiet BarrierInInfiniteLoop
*
*/
public class BarrierInInfiniteLoop {
private static Object field1 = new Object();
private static Object field2 = new Object();
public static void main(String[] args) {
test(false);
}
private static void test(boolean flag) {
if (flag) {
for (;;) {
field1 = field2;
}
}
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2020, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test 8238385
* @summary CTW: C2 (Shenandoah) compilation fails with "Range check dependent CastII node was not removed"
* @key gc
* @requires vm.gc.Shenandoah & !vm.graal.enabled
* @modules java.base/jdk.internal.misc:+open
*
* @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC
* FoldIfAfterExpansion
*
*/
import jdk.internal.misc.Unsafe;
public class FoldIfAfterExpansion {
private static int[] field1 = new int[100];
private static int[] field2 = new int[100];
private static int[] field3;
private static volatile int barrier;
static final jdk.internal.misc.Unsafe UNSAFE = Unsafe.getUnsafe();
public static void main(String[] args) {
for (int i = 0; i < 20_000; i++) {
test(true, 10, false, true);
test(false, 10, false, false);
}
}
private static Object test(boolean flag, int i, boolean flag2, boolean flag3) {
int[] array;
if (flag) {
barrier = 1;
array = field1;
final int length = array.length;
if (flag2) {
field3 = array;
}
} else {
barrier = 1;
array = field1;
final int length = array.length;
if (flag2) {
field3 = array;
}
}
array = field1;
if (flag3) {
if (i < 0 || i >= array.length) {
throw new RuntimeException();
}
long l = (long)i;
l = l * UNSAFE.ARRAY_INT_INDEX_SCALE + UNSAFE.ARRAY_INT_BASE_OFFSET;
UNSAFE.putInt(array, l, i);
} else {
if (i < 0 || i >= array.length) {
throw new RuntimeException();
}
long l = (long)i;
l = l * UNSAFE.ARRAY_INT_INDEX_SCALE + UNSAFE.ARRAY_INT_BASE_OFFSET;
UNSAFE.putInt(array, l, i);
}
return array;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -46,6 +46,8 @@ public class VMDeprecatedOptions {
{"InitialRAMFraction", "64"},
{"TLABStats", "false"},
{"AllowRedefinitionToAddDeleteMethods", "true"},
{"PrintVMQWaitTime", "true"},
{"UseNewFieldLayout", "true"},
// deprecated alias flags (see also aliased_jvm_flags):
{"DefaultMaxRAMFraction", "4"},

View File

@ -0,0 +1,157 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8237767
* @summary Verify behaviour of field layout algorithm
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.management
* @run main/othervm FieldDensityTest
*/
/*
* @test
* @requires vm.bits == "64"
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.management
* @run main/othervm -XX:+UseCompressedOops -XX:+UseCompressedClassPointers FieldDensityTest
* @run main/othervm -XX:+UseCompressedOops -XX:-UseCompressedClassPointers FieldDensityTest
*/
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Comparator;
import jdk.internal.misc.Unsafe;
import jdk.test.lib.Asserts;
public class FieldDensityTest {
static int OOP_SIZE_IN_BYTES = 0;
static {
if (System.getProperty("sun.arch.data.model").equals("64")) {
if (System.getProperty("java.vm.compressedOopsMode") == null) {
OOP_SIZE_IN_BYTES = 8;
} else {
OOP_SIZE_IN_BYTES = 4;
}
} else {
OOP_SIZE_IN_BYTES = 4;
}
}
static class FieldInfo {
public Field field;
public long offset;
FieldInfo(Field field, long offset) {
this.field = field;
this.offset = offset;
}
static void checkFieldsContiguity(FieldInfo[] fieldInfo) {
Arrays.sort(fieldInfo, new SortByOffset());
for (int i = 0 ; i < fieldInfo.length - 2; i++) {
int size = sizeInBytesFromType(fieldInfo[i].field.getType());
Asserts.assertEquals((int)(fieldInfo[i].offset + size), (int)fieldInfo[i+1].offset,
"Empty slot between fields, should not happen");
}
}
}
static int sizeInBytesFromType(Class type) {
if (!type.isPrimitive()) {
return OOP_SIZE_IN_BYTES;
}
switch(type.getTypeName()) {
case "boolean":
case "byte": return 1;
case "char":
case "short": return 2;
case "int":
case "float": return 4;
case "long":
case "double": return 8;
default:
throw new RuntimeException("Unrecognized signature");
}
}
static class SortByOffset implements Comparator<FieldInfo> {
public int compare(FieldInfo a, FieldInfo b)
{
return (int)(a.offset - b.offset);
}
}
static class E {
public byte b0;
}
static class F extends E {
public byte b1;
}
static class G extends F {
public byte b2;
}
static class H extends G {
public byte b3;
}
public static class A {
public int i;
public byte b;
public long l;
public Object o;
}
public static class B extends A {
public byte b0, b1, b2;
}
static void testFieldsContiguity(Class c) {
Unsafe unsafe = Unsafe.getUnsafe();
Field[] fields = c.getFields();
FieldInfo[] fieldsInfo = new FieldInfo[fields.length];
int i = 0;
for (Field f : fields) {
long offset = unsafe.objectFieldOffset(f);
fieldsInfo[i] = new FieldInfo(f, offset);
i++;
}
FieldInfo.checkFieldsContiguity(fieldsInfo);
}
public static void main(String[] args) {
H h = new H();
testFieldsContiguity(h.getClass());
B b = new B();
testFieldsContiguity(b.getClass());
}
}

View File

@ -99,9 +99,11 @@ public class CompileTheWorld {
} catch (Throwable t){
t.printStackTrace(ERR);
} finally {
try {
OUT.close();
} catch (Throwable ignore) {
if (OUT != System.out) {
try {
OUT.close();
} catch (Throwable ignore) {
}
}
// <clinit> might have started new threads
System.exit(passed ? 0 : 1);

View File

@ -150,6 +150,9 @@ public class Compiler {
} else {
compileAtLevel(compLevel);
}
// Make the method eligible for sweeping sooner
WHITE_BOX.deoptimizeMethod(method);
}
private void waitCompilation() {

View File

@ -49,7 +49,7 @@ import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class Test {
private static String UNSUPPORTED_OPTION_MESSAGE = "-XX:TieredCompilation not supported in this VM";
private static String UNSUPPORTED_OPTION_MESSAGE = "-XX:+TieredCompilation not supported in this VM";
private static String REGEXP = "^[0-9.]+: \\[compile level=\\d";
public static void main(String[] args) throws Exception {
{
@ -59,7 +59,7 @@ public class Test {
"-XX:+PrintTieredEvents",
"-version");
var output = new OutputAnalyzer(pb.start());
if (output.getStdout().contains(UNSUPPORTED_OPTION_MESSAGE)) {
if (output.getStderr().contains(UNSUPPORTED_OPTION_MESSAGE)) {
throw new SkippedException(UNSUPPORTED_OPTION_MESSAGE);
}
output.shouldHaveExitValue(0)

View File

@ -913,9 +913,6 @@ com/sun/jdi/RepStep.java 8043571 generic-
com/sun/jdi/NashornPopFrameTest.java 8225620 generic-all
com/sun/jdi/JdwpListenTest.java 8234935 windows-all
com/sun/jdi/JdwpAttachTest.java 8234935 windows-all
############################################################################
# jdk_time

View File

@ -25,6 +25,7 @@ import com.sun.jdi.Bootstrap;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.ListeningConnector;
import jdk.test.lib.Platform;
import jdk.test.lib.apps.LingeredApp;
import java.net.Inet4Address;
@ -33,7 +34,6 @@ import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
@ -54,8 +54,6 @@ import java.util.concurrent.Executors;
*/
public class JdwpAttachTest {
private static final boolean IsWindows = System.getProperty("os.name").toLowerCase().contains("windows");
// Set to true to perform testing of attach from wrong address (expected to fail).
// It's off by default as it caused significant test time increase\
// (tests <number_of_addresses> * <number_of_addresses> cases, each case fails by timeout).
@ -115,7 +113,7 @@ public class JdwpAttachTest {
}
log(" Listening port: " + port);
log(" Attaching from " + connectAddress);
log(" Attaching to " + connectAddress);
try {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit((Callable<Exception>)() -> {
@ -155,6 +153,12 @@ public class JdwpAttachTest {
list.add(addr);
}
private static boolean isTeredo(Inet6Address addr) {
// Teredo prefix is 2001::/32 (i.e. first 4 bytes are 2001:0000)
byte[] bytes = addr.getAddress();
return bytes[0] == 0x20 && bytes[1] == 0x01 && bytes[2] == 0x00 && bytes[3] == 0x00;
}
private static List<InetAddress> getAddresses() {
List<InetAddress> result = new LinkedList<>();
try {
@ -173,6 +177,12 @@ public class JdwpAttachTest {
// On other platforms test both symbolic and numeric scopes.
if (addr instanceof Inet6Address) {
Inet6Address addr6 = (Inet6Address)addr;
// Teredo clients cause intermittent errors on listen ("bind failed")
// and attach ("no route to host").
// Teredo is supposed to be a temporary measure, but some test machines have it.
if (isTeredo(addr6)) {
continue;
}
NetworkInterface scopeIface = addr6.getScopedInterface();
if (scopeIface != null && scopeIface.getName() != null) {
// On some test machines VPN creates link local addresses
@ -190,7 +200,7 @@ public class JdwpAttachTest {
throw new RuntimeException("Unexpected", e);
}
if (IsWindows) {
if (Platform.isWindows()) {
// don't add addresses with symbolic scope
continue;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,6 +26,7 @@ import com.sun.jdi.VirtualMachine;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import jdk.test.lib.Platform;
import lib.jdb.Debuggee;
import java.io.IOException;
@ -52,8 +53,6 @@ import java.util.Map;
*/
public class JdwpListenTest {
private static final boolean IsWindows = System.getProperty("os.name").toLowerCase().contains("windows");
// Set to true to allow testing of attach from wrong address (expected to fail).
// It's off by default as it causes test time increase and test interference (see JDK-8231915).
private static boolean allowNegativeTesting = false;
@ -89,7 +88,7 @@ public class JdwpListenTest {
private static void listenTest(String listenAddress, String connectAddress, boolean expectedResult)
throws IOException {
log("\nTest: listen at " + listenAddress + ", attaching from " + connectAddress
log("\nTest: listen at " + listenAddress + ", attaching to " + connectAddress
+ ", expected: " + (expectedResult ? "SUCCESS" : "FAILURE"));
if (!expectedResult && !allowNegativeTesting) {
log("SKIPPED: negative testing is disabled");
@ -99,7 +98,7 @@ public class JdwpListenTest {
log("Starting listening debuggee at " + listenAddress);
try (Debuggee debuggee = Debuggee.launcher("HelloWorld").setAddress(listenAddress + ":0").launch()) {
log("Debuggee is listening on " + listenAddress + ":" + debuggee.getAddress());
log("Connecting from " + connectAddress + ", expected: " + (expectedResult ? "SUCCESS" : "FAILURE"));
log("Connecting to " + connectAddress + ", expected: " + (expectedResult ? "SUCCESS" : "FAILURE"));
try {
VirtualMachine vm = attach(connectAddress, debuggee.getAddress());
vm.dispose();
@ -120,6 +119,12 @@ public class JdwpListenTest {
list.add(addr);
}
private static boolean isTeredo(Inet6Address addr) {
// Teredo prefix is 2001::/32 (i.e. first 4 bytes are 2001:0000)
byte[] bytes = addr.getAddress();
return bytes[0] == 0x20 && bytes[1] == 0x01 && bytes[2] == 0x00 && bytes[3] == 0x00;
}
private static List<InetAddress> getAddresses() {
List<InetAddress> result = new LinkedList<>();
try {
@ -138,6 +143,12 @@ public class JdwpListenTest {
// On other platforms test both symbolic and numeric scopes.
if (addr instanceof Inet6Address) {
Inet6Address addr6 = (Inet6Address)addr;
// Teredo clients cause intermittent errors on listen ("bind failed")
// and attach ("no route to host").
// Teredo is supposed to be a temporary measure, but some test machines have it.
if (isTeredo(addr6)) {
continue;
}
NetworkInterface scopeIface = addr6.getScopedInterface();
if (scopeIface != null && scopeIface.getName() != null) {
// On some test machines VPN creates link local addresses
@ -155,7 +166,7 @@ public class JdwpListenTest {
throw new RuntimeException("Unexpected", e);
}
if (IsWindows) {
if (Platform.isWindows()) {
// don't add addresses with symbolic scope
continue;
}

View File

@ -0,0 +1,231 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* The certificates used by this test.
* They are generated by script gen-certs.sh.
*/
public enum Cert {
/*
* Version: 3 (0x2)
* Serial Number:
* 65:24:13:3c:7a:98:0c:16:a2:91:9c:8e:42:84:cf:be:be:d2:f1:42
* Signature Algorithm: sha256WithRSAEncryption
* Issuer: CN = evil
* Validity
* Not Before: Feb 8 03:59:27 2020 GMT
* Not After : Feb 5 03:59:27 2030 GMT
* Subject: CN = evil
* X509v3 extensions:
* X509v3 Subject Key Identifier:
* 09:D0:E8:51:6C:0F:88:59:47:D1:FD:05:C2:00:10:D6:A4:80:04:07
* X509v3 Authority Key Identifier:
* keyid:09:D0:E8:51:6C:0F:88:59:47:D1:FD:05:C2:00:10:D6:A4:80:04:07
*/
BAD_CERT(
"RSA",
"-----BEGIN CERTIFICATE-----\n" +
"MIIC7jCCAdagAwIBAgIUZSQTPHqYDBaikZyOQoTPvr7S8UIwDQYJKoZIhvcNAQEL\n" +
"BQAwDzENMAsGA1UEAwwEZXZpbDAeFw0yMDAyMDgwMzU5MjdaFw0zMDAyMDUwMzU5\n" +
"MjdaMA8xDTALBgNVBAMMBGV2aWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n" +
"AoIBAQCmirsTOW1G+LoI/Aj59lMk3KLywAbXASeTdnBoWkchuJ0QJWO/5b5kgf6Q\n" +
"VFfe9lXof9psGIKaCGq6KsI0uqj7+7y++//l+E6GB8UshVB8MXc1SLFe8AxPYhWC\n" +
"TXaKWyWGl7PXvugzbByFrf4IwE9+6phYkvl/zHvaMKqdwnkpXuyuBgT3BiYTSNsx\n" +
"k1Ma+s5rqiwsOODSzwhadwmU9T4z11KypYb/DixJgHvUET4gTB+i3ll+PllVdQtX\n" +
"zBLpEuj5HadK0PsqlOIok3eoSU+MpRqsz0gFEQ95y+Les3MlBeQ7fVKBz8GbrFDB\n" +
"Atzca+iknEh8fkLIUUuCjTjUtLvfAgMBAAGjQjBAMB0GA1UdDgQWBBQJ0OhRbA+I\n" +
"WUfR/QXCABDWpIAEBzAfBgNVHSMEGDAWgBQJ0OhRbA+IWUfR/QXCABDWpIAEBzAN\n" +
"BgkqhkiG9w0BAQsFAAOCAQEAQMfPfYfVSSdsiEUOlVg6M5D90HRONzqlg/v0RqQI\n" +
"fb3uufXJs20dg8iamVORXIIeUpGv1OQ2Rx4ndnV3bRLK6ep3gswIkOnD8z/CeNgl\n" +
"odZPvWyklHTMenGqU2TR3ceFep/DvQkrP4aZWyr3e2fjatKR/s4pXgBwHs/hR76O\n" +
"vDYLRDyCG/+MtUClFsc9HLedbU4Wp8JyaafFZ63/VjaIcvdHoDGNILRu5AIN/JVM\n" +
"Sgz4blkWJxS1dlqBYwxvbpJWrHUcktsa3Bzw2zWOkTVGQJi3pMvzRBkgliNaXPi3\n" +
"qcPViqgzVoB4QdOQBnvDtQ9+8Nt/dQY1VJFSBLxZQIefiQ==\n" +
"-----END CERTIFICATE-----",
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmirsTOW1G+LoI\n" +
"/Aj59lMk3KLywAbXASeTdnBoWkchuJ0QJWO/5b5kgf6QVFfe9lXof9psGIKaCGq6\n" +
"KsI0uqj7+7y++//l+E6GB8UshVB8MXc1SLFe8AxPYhWCTXaKWyWGl7PXvugzbByF\n" +
"rf4IwE9+6phYkvl/zHvaMKqdwnkpXuyuBgT3BiYTSNsxk1Ma+s5rqiwsOODSzwha\n" +
"dwmU9T4z11KypYb/DixJgHvUET4gTB+i3ll+PllVdQtXzBLpEuj5HadK0PsqlOIo\n" +
"k3eoSU+MpRqsz0gFEQ95y+Les3MlBeQ7fVKBz8GbrFDBAtzca+iknEh8fkLIUUuC\n" +
"jTjUtLvfAgMBAAECggEATyu2QS5Un5+QOMMvtTx/TA/DOulElyNKYBS23TTFiedM\n" +
"ayeLIuehuf/+NziRSUILlupouGhyda04p2W6SvzNZnTGxnffr8B5+8dn2YFKwK93\n" +
"PxJel4ZAI+C53ubaSm2IClLFwPNVSVTEvlv3XsulPu1hHQJJr5JS8meeRD72AE8G\n" +
"brKbLlq6OGey6u9teao0m4Wo05MzaEoOx4fztPP4BiJJobuPYrdthUwfXJ2mQYeg\n" +
"fJKl+JeLUnAXmq8e+6Zs88NzGK8Gmd2TvGnUahxSDtXHuRkB2lOrGFrEJKkAXDBx\n" +
"2q8r3vvcay6+k95fS2HOvggFDALS37BGckWg4+HYuQKBgQDXkxw0u2G7rCYbF691\n" +
"jil++DLNUzejZonAvA/cceVHShfAMlWCBf58cLNsY33rkRsFazhrdDoDAFqKxejB\n" +
"xWM8U7UHiHZSznuXTL0YbUombfz+0lp/KwXcirnB7O3AdIW4lfMo/ozeMMIuEzsL\n" +
"G/MDvbNSdawEso/qtxFvz87ctQKBgQDFxcCSyWb/SQVr3RkZkO3BW2efuANxNeUh\n" +
"35L4inWTa8ml8UL4SrTrkfUHzu5TnBGbSb2n8CdkPnInA81dKagX6LXuONeLkX/e\n" +
"RXyWIwWRiBkpYSaw2OGApl49DRvk2kCzwoVRWwh8qfhpC0P6AClFRaVAovYcTxm3\n" +
"vhCJL3jmwwKBgGMLvTbhLStMEgn6nOwXECu9H6JE7NhPgVUjUupHDj/t4/GzbqQZ\n" +
"2u4T3ewb3jwAZHjd5YNBWHIOlIsUGTgGV+zczN0ULsEnC5Pddzgk5p+3gzkVLu0k\n" +
"uEG3H1fhYu882j+P7bPVGKXxoxYGUedtxP7gBucJF6rk28jMqd9EjFfNAoGBAKcc\n" +
"ASwGodDzknEh0SOZIkxPP6/lfIMcVw/YKgd4dwCqAykEQuIpvdWO7sw6PYbISNg9\n" +
"5tMQSTiayznMLKqbmD0blR5FSVvVBYZ6kFsMHJhrt1cPj/G+UEy0RsyvVvJ4uFMr\n" +
"+hpUIUe1FwErU7TajgTKZGfJSsuAyupG3xIL2syhAoGALv+ulZAY/gUKH8NigsXo\n" +
"pFPTpiXMyTD/O4RUH/5LcxDELVZ8cnV2q3qEX+ep24y0AtNiBx4oHpZ/vIxtwBCR\n" +
"JKU2xmIGC6NyQMRSzfmNgi0X450rgKbTAxn/LAU8syXmNpBUrFZ8+02pQvWzxqfU\n" +
"zGaMEK3+f1sq8Byzau/qhKU="),
/*
* Version: 3 (0x2)
* Serial Number:
* 70:41:2f:71:43:d1:67:b5:29:c6:3e:ce:62:ba:d5:aa:4a:f1:f7:f0
* Signature Algorithm: sha256WithRSAEncryption
* Issuer: CN = localhost
* Validity
* Not Before: Feb 8 03:59:18 2020 GMT
* Not After : Feb 5 03:59:18 2030 GMT
* Subject: CN = localhost
* X509v3 extensions:
* X509v3 Subject Key Identifier:
* 12:65:C7:4B:D8:77:D8:55:6E:2D:AF:C4:F8:09:FE:08:F4:22:EA:D5
* X509v3 Authority Key Identifier:
* keyid:12:65:C7:4B:D8:77:D8:55:6E:2D:AF:C4:F8:09:FE:08:F4:22:EA:D5
*/
GOOD_CERT(
"RSA",
"-----BEGIN CERTIFICATE-----\n" +
"MIIC+DCCAeCgAwIBAgIUcEEvcUPRZ7Upxj7OYrrVqkrx9/AwDQYJKoZIhvcNAQEL\n" +
"BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMDIwODAzNTkxOFoXDTMwMDIw\n" +
"NTAzNTkxOFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF\n" +
"AAOCAQ8AMIIBCgKCAQEAtSOmfkF0zjPeZ4DDsJZO3OaDq+XHtPLB+xvri1iuL9b+\n" +
"dZDXOqPZ5+koWM9NzDR6Um+IN46oTU+8eJw+hYcZaE9tzS9kH+6qOBk/827yEyVa\n" +
"jh9Wqw164xj16QPyQJuHEeeDJ7elNfaOQXRu2UqZB9suKbolqsHe42hbg0/tbln7\n" +
"C8C6qEJOpnEaapFHi3/3AeoQQ57zywqrzopeiiuUDWmBhXY30ve33RrJl/OIM1sB\n" +
"QSoVCPcaF0mXaDwUTYIksxelon1K9PJa76p9ybGnsxkYfCAGZ8O+fTjJfQONU+Gu\n" +
"zOmcyXL5D5O/nI8lxN8hbZwVIAYXLYRUonECIOJ/iQIDAQABo0IwQDAdBgNVHQ4E\n" +
"FgQUEmXHS9h32FVuLa/E+An+CPQi6tUwHwYDVR0jBBgwFoAUEmXHS9h32FVuLa/E\n" +
"+An+CPQi6tUwDQYJKoZIhvcNAQELBQADggEBAFatzXsT9YZ0TF66G6apSbbs6mH9\n" +
"PMVE9IuE4yv2zyKofSMmDHFdmfNdkMHWkIxcZKuiL00IPFL76LAb9DWNQVy4otq6\n" +
"3+n0CCi808gDNUMYMQLlXVooZsByXuMuokyg29F5mWEH4rswU6ru33lAB7CT7BuN\n" +
"z5/eUhxTcXcJV6pLgcEM68NIc755PULevmqmd8SrVgcFjkxAFOsYd9L86wYLdiPO\n" +
"uXfN/EjLMGHG2gpEqHEzQpEEAA/IsCJ1HQ8vvGkeggUIXPrwlIMbQcz/8WBSDel5\n" +
"hvVRmADJCLf/0IwxKsSOMWZ4OMmcXMjxnae3lWPQomlzWHMZlFraG2rE/Vo=\n" +
"-----END CERTIFICATE-----",
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1I6Z+QXTOM95n\n" +
"gMOwlk7c5oOr5ce08sH7G+uLWK4v1v51kNc6o9nn6ShYz03MNHpSb4g3jqhNT7x4\n" +
"nD6FhxloT23NL2Qf7qo4GT/zbvITJVqOH1arDXrjGPXpA/JAm4cR54Mnt6U19o5B\n" +
"dG7ZSpkH2y4puiWqwd7jaFuDT+1uWfsLwLqoQk6mcRpqkUeLf/cB6hBDnvPLCqvO\n" +
"il6KK5QNaYGFdjfS97fdGsmX84gzWwFBKhUI9xoXSZdoPBRNgiSzF6WifUr08lrv\n" +
"qn3JsaezGRh8IAZnw759OMl9A41T4a7M6ZzJcvkPk7+cjyXE3yFtnBUgBhcthFSi\n" +
"cQIg4n+JAgMBAAECggEAD2O4AYIOKna9ro2CEr6ydJIhHbmn/feiA3Obz3r5UZcy\n" +
"h0qG/rRtDwcAJot2UKMkwVw4dn/oTKk5mgWsSivwPKyC56vfFddxHtMGW+hRKM9D\n" +
"ok+HTYEXr7OvMNzk+Bg+oYbJ3dX8c1k/PNBnmo578e7tPR5TlO5jwW5cWAuyYG2f\n" +
"+YUCqMNe02yZvvlvK1kOSSgqlNH0S14/hVZTYkyxXMCCrkxPFXh5j8w6ZUzVipXg\n" +
"99EYcRdq7dA3XVBSgQQ4m5772FIIzlBn8LdIIfw3VQrtZ9HapowLk6QdcHSHBKMK\n" +
"0rqb1PlG2ynD2n8hKn4MssJ+tkzvbGrQcLjL/+XHAQKBgQDmiOIke90T8puq3FkN\n" +
"NlgdBA9Zem5U2t3TvtQa36cuO/paYrLaVK5U0ucNZ9d4i6avdyp8TyKJrUHDcazi\n" +
"QkDpjxb0KBhisutDZ4o1JFW4ZtB3zwIGIYWBBIE1kRIc0ucYoAurSdOmAsKq6XJQ\n" +
"B0CQYBJPrTHq5niCl0tKPtrISwKBgQDJJfNcKSz46zdnqsNZAmL+q+cMQf4txiCS\n" +
"v0JefOeKKlwNcYWxRgf1yTNENamKKh8wyqOhc/OkxXjglRo9BFMt6BFFARzDddWE\n" +
"Wo18cyLc2WvTTv2FCZ0J/eF1jPTGJsTpCU6Prbt4XPjZpzSTF2cQR7CxLp15FsJm\n" +
"2LMcQ8ma+wKBgQC72So8hFme2X+S+D3wECo4aoh/Zs3kgvtigQqgY0H84I6de/M1\n" +
"CO+M2tW/DLB8336RV87cwDbqbK07rrMrIsV2C0yu4sUMF7Kwl/v8VYEr40tXdOy3\n" +
"RjVc7ejDV1Sk/A2m+TLI/j1h9rndPqARKfeoLUB+gCg+ulHUR6fn9dOchQKBgByx\n" +
"uj6qbQzxWQ0D0iwvZ/nWgfZAr8bN3bWxbQFXphwSoOEWEbFRQS9xzUtssEvSaHKo\n" +
"ZaFRji8yMGUxP/X2WPtSgKwsVXMYqyXfWRGoxw9kQLp7KTVCQtG7Et+XBRADVdG8\n" +
"jyV17ilkcedyr9BP5VbwMyeDc9ljQsYzIZHlpavjAoGAct8Wktj0hegCoTxSukU1\n" +
"SkJ7t4376sSfxVbbUrH86Y1Z55le1O+VkGtqETmk+Q8qf5Ymnal3W9zZ0O9mOE04\n" +
"otFbiB3ifUbpBAipyxS06SIFwMctmSk2EqBcXa3nZ9eUGqx0JhoQahfyDkFzfwJY\n" +
"hiBTWnlMjCiJ40yRYAWDzZg="),
/*
* Version: 3 (0x2)
* Serial Number:
* 3f:62:91:39:7e:02:e9:77:20:61:ce:7e:a2:3c:c0:6c:3f:2e:08:49
* Signature Algorithm: sha256WithRSAEncryption
* Issuer: CN = UNKOWN
* Validity
* Not Before: Feb 8 04:00:04 2020 GMT
* Not After : Feb 5 04:00:04 2030 GMT
* Subject: CN = unknown
* X509v3 extensions:
* X509v3 Subject Key Identifier:
* F7:D7:AE:80:DF:EC:7A:60:5A:E8:62:60:70:03:B6:BD:23:05:19:62
* X509v3 Authority Key Identifier:
* keyid:F7:D7:AE:80:DF:EC:7A:60:5A:E8:62:60:70:03:B6:BD:23:05:19:62
* X509v3 Subject Alternative Name:
* IP Address:127.0.0.1
*/
LOOPBACK_CERT(
"RSA",
"-----BEGIN CERTIFICATE-----\n" +
"MIIDBTCCAe2gAwIBAgIUP2KROX4C6XcgYc5+ojzAbD8uCEkwDQYJKoZIhvcNAQEL\n" +
"BQAwEjEQMA4GA1UEAwwHdW5rbm93bjAeFw0yMDAyMDgwNDAwMDRaFw0zMDAyMDUw\n" +
"NDAwMDRaMBIxEDAOBgNVBAMMB3Vua25vd24wggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" +
"DwAwggEKAoIBAQC8dBwc+nhzuGOcqmeQkcms6JrUPDPcvq6gEEH3dxorzngfxrsl\n" +
"lfM6SPJBV4A7HVEcsGhcMoPzzpFVISi3XyLkGuw2WnEW6nKcB2QgaS0Ub8PoDZ7P\n" +
"erWGOIjHF1slKxX40tZBiEp1oJANDq7CzSGWiyTorCjbX6OiWZCbhQkw+SpXrAdD\n" +
"fzjEAr3y8cgsC7qqTxoz/T9C1+UMmzc88kpAqih7jj2L/i6387dBmV+zrMsNyO0Q\n" +
"UPGACzMiSZV3tiwYA6cvDY3WS3fCwLSYUWdHi1orerHQuGOHLK4eyPVDcvuQdUJ/\n" +
"T0+jbNZa51scqrBUT/aDlCMCxFUY3vquz2xfAgMBAAGjUzBRMB0GA1UdDgQWBBT3\n" +
"166A3+x6YFroYmBwA7a9IwUZYjAfBgNVHSMEGDAWgBT3166A3+x6YFroYmBwA7a9\n" +
"IwUZYjAPBgNVHREECDAGhwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQBcfcv2J73T\n" +
"nHFsCPU3WM6UW2uE8BIM/s/VbjkV1nalFyHi/TU6CN01sDymTABhzIlx5N6PW0HP\n" +
"Z0q1C7l1nsoQHwmJO+avOHu3ZjDrLMpU6wTQLEemTd3R5HTyA3/I/FUVFHeuLwJg\n" +
"L7OLNc8ouT1hkiIZD+xKwfCEdT3o+ldB+9L4WYRJPt2W3bf3W/yM8JmwW8uf6+U3\n" +
"V46xiE5GoOKoIkeAkBAaIbepsZH9rPb7alBSgYgwQYDft9wuGMeNcvPvgVsXjA7I\n" +
"RafJVdxVinVMEaOjckIZ5WlrR5667aIJapZH1r7/tiSQCRaJcILx7pL4x8C+x34z\n" +
"dPHbbyP/Rdq9\n" +
"-----END CERTIFICATE-----",
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC8dBwc+nhzuGOc\n" +
"qmeQkcms6JrUPDPcvq6gEEH3dxorzngfxrsllfM6SPJBV4A7HVEcsGhcMoPzzpFV\n" +
"ISi3XyLkGuw2WnEW6nKcB2QgaS0Ub8PoDZ7PerWGOIjHF1slKxX40tZBiEp1oJAN\n" +
"Dq7CzSGWiyTorCjbX6OiWZCbhQkw+SpXrAdDfzjEAr3y8cgsC7qqTxoz/T9C1+UM\n" +
"mzc88kpAqih7jj2L/i6387dBmV+zrMsNyO0QUPGACzMiSZV3tiwYA6cvDY3WS3fC\n" +
"wLSYUWdHi1orerHQuGOHLK4eyPVDcvuQdUJ/T0+jbNZa51scqrBUT/aDlCMCxFUY\n" +
"3vquz2xfAgMBAAECggEAEcYNpLoGxDs+wdbcf6kQUUt61st6xLYDODtwTUuhX0JQ\n" +
"2AZhPjE/SF764ijDgk/Ih6EnppJpGYSA9ntzIKBLZSIY5yNuiQ/BkW+tBNWGl+fW\n" +
"nTszoDPdjPQmCkjsorvGjbos1O9qvl9PVrvsxZidM1qaN4uNKuuBPl2eItzQOhsM\n" +
"YFbmw1nqSX31gukv9a6yM2VgDUiGMlEGwkOphutbqt+wTO+9hEopGZHB7mNc5NO9\n" +
"foWVVI1rzS2yR2d85lsG4YBqBMDp2s2cBofIAe/SSSpBYPR4RfEBDpSaVceR4+cL\n" +
"Lq52DhLVe/zgVj7LEGdyTZTQxw414sRBIz8KXcRIkQKBgQDon26R0/vToZcxgnpr\n" +
"ososGh+iTov883DCxX30sntl/GbyUhg50q7Tq5mXGyzodoFHGTL+bOcU3g5O4MOV\n" +
"6HlTFe1dUjyC7M0ah6NaCSsl4SPTxtWjeHMBMhNisInDAO+ju4MJAhgoHuYL6p39\n" +
"NDmKSDtpaegFz1Q64C1Ea9fsFwKBgQDPZFvQNjSCm06ObsfXLZKS6IEqgGbihMfM\n" +
"cv/HjIpAKXNp/Y6Y/YmdFBpdHDkOJ9BXwJqTuMuM69BuldvNXkkY7zrhPFPawWyF\n" +
"O/N1aMNCT89AreBwXMYmgG9yLm1EF1FOuz2oAnWWpcUHBups+cZQikYSQxcOSqrL\n" +
"bNTEWffG+QKBgDTk+8lhAGQQ3EY/uwJ6k6oPjp3jamVsHXnMWmWnp/N6vxXeoO+U\n" +
"/nfXDyeS4FVDjQXTrwq3TJwsGejJpu+RWvUPiVes+WFz4vdjXDt+1jbYyMLA9Zck\n" +
"LlJZRpssNUcIEXWTj6oetct5qymOgbovg93zqr6/fCjGCgsRKnniY8ilAoGAcWGH\n" +
"hGQt/v1TTDEqVexXRrOP8iFyngJDjPWN+pVN+9ftfhOeAuwRcOvNofvNAX0ovODS\n" +
"YVJVDfzZ3atWGIekZNpdEUg++8hlQM3OwvB8V2N0hgLJQgSmW+Q5iW3yVJh+3hEl\n" +
"mxWFHdAQ0E+ql9tR3TRLLK67CxgtGbus8o/RE1kCgYAuf9o6Q++l8H0vNZTnzBNu\n" +
"bt0QnLxyh7RuViYuCkzLK+jGftgadVfsRgnOKvxQkMzcXfBgpV5JcVKXtaxDhPxM\n" +
"xHwblgOEGlrD4tAwvtPw3GLhmD4Shy8zcT0Lwto81fquskA5yyDGJxbq9CMzWk3w\n" +
"dSOT2C7lwW+hkycUio/fTQ==");
public final String keyAlgo;
public final String certStr;
public final String keyStr;
private Cert(String keyAlgo, String certStr, String keyStr) {
this.keyAlgo = keyAlgo;
this.certStr = certStr;
this.keyStr = keyStr;
}
}

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