Merge
This commit is contained in:
commit
3b27432323
26
bin/idea.sh
26
bin/idea.sh
@ -136,17 +136,33 @@ add_replacement() {
|
||||
eval TO$NUM_REPLACEMENTS='$2'
|
||||
}
|
||||
|
||||
add_replacement "###BUILD_DIR###" "`dirname $SPEC`"
|
||||
add_replacement "###MODULE_NAMES###" "$MODULE_NAMES"
|
||||
add_replacement "###JTREG_HOME###" "$JT_HOME"
|
||||
add_replacement "###IMAGES_DIR###" "`dirname $SPEC`/images/jdk"
|
||||
add_replacement "###ROOT_DIR###" "$TOPLEVEL_DIR"
|
||||
add_replacement "###IDEA_DIR###" "$IDEA_OUTPUT"
|
||||
SPEC_DIR=`dirname $SPEC`
|
||||
if [ "x$CYGPATH" = "x" ]; then
|
||||
add_replacement "###BUILD_DIR###" "$SPEC_DIR"
|
||||
add_replacement "###JTREG_HOME###" "$JT_HOME"
|
||||
add_replacement "###IMAGES_DIR###" "$SPEC_DIR/images/jdk"
|
||||
add_replacement "###ROOT_DIR###" "$TOPLEVEL_DIR"
|
||||
add_replacement "###IDEA_DIR###" "$IDEA_OUTPUT"
|
||||
else
|
||||
add_replacement "###BUILD_DIR###" "`cygpath -am $SPEC_DIR`"
|
||||
add_replacement "###IMAGES_DIR###" "`cygpath -am $SPEC_DIR`/images/jdk"
|
||||
add_replacement "###ROOT_DIR###" "`cygpath -am $TOPLEVEL_DIR`"
|
||||
add_replacement "###IDEA_DIR###" "`cygpath -am $IDEA_OUTPUT`"
|
||||
if [ "x$JT_HOME" = "x" ]; then
|
||||
add_replacement "###JTREG_HOME###" ""
|
||||
else
|
||||
add_replacement "###JTREG_HOME###" "`cygpath -am $JT_HOME`"
|
||||
fi
|
||||
fi
|
||||
|
||||
SOURCE_PREFIX="<sourceFolder url=\"file://"
|
||||
SOURCE_POSTFIX="\" isTestSource=\"false\" />"
|
||||
|
||||
for root in $MODULE_ROOTS; do
|
||||
if [ "x$CYGPATH" != "x" ]; then
|
||||
root=`cygpath -am $root`
|
||||
fi
|
||||
SOURCES=$SOURCES" $SOURCE_PREFIX""$root""$SOURCE_POSTFIX"
|
||||
done
|
||||
|
||||
|
@ -35,7 +35,7 @@ DEFAULT_VERSION_EXTRA3=0
|
||||
DEFAULT_VERSION_DATE=2019-03-19
|
||||
DEFAULT_VERSION_CLASSFILE_MAJOR=56 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
|
||||
DEFAULT_VERSION_CLASSFILE_MINOR=0
|
||||
DEFAULT_ACCEPTABLE_BOOT_VERSIONS="10 11 12"
|
||||
DEFAULT_ACCEPTABLE_BOOT_VERSIONS="11 12"
|
||||
|
||||
LAUNCHER_NAME=openjdk
|
||||
PRODUCT_NAME=OpenJDK
|
||||
|
@ -361,7 +361,7 @@ var getJibProfilesCommon = function (input, data) {
|
||||
};
|
||||
};
|
||||
|
||||
common.boot_jdk_version = "10";
|
||||
common.boot_jdk_version = "11";
|
||||
common.boot_jdk_home = input.get("boot_jdk", "home_path") + "/jdk-"
|
||||
+ common.boot_jdk_version
|
||||
+ (input.build_os == "macosx" ? ".jdk/Contents/Home" : "");
|
||||
@ -851,9 +851,10 @@ var getJibProfilesDependencies = function (input, common) {
|
||||
server: "jpg",
|
||||
product: "jdk",
|
||||
version: common.boot_jdk_version,
|
||||
build_number: "46",
|
||||
build_number: "28",
|
||||
file: "bundles/" + boot_jdk_platform + "/jdk-" + common.boot_jdk_version + "_"
|
||||
+ boot_jdk_platform + "_bin.tar.gz",
|
||||
+ boot_jdk_platform + "_bin"
|
||||
+ (input.build_os == "windows" ? ".zip" : ".tar.gz"),
|
||||
configure_args: "--with-boot-jdk=" + common.boot_jdk_home,
|
||||
environment_path: common.boot_jdk_home + "/bin"
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2018, 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,7 +43,7 @@ public class Main {
|
||||
/**
|
||||
* ASM version to be used by nasgen tool.
|
||||
*/
|
||||
public static final int ASM_VERSION = Opcodes.ASM5;
|
||||
public static final int ASM_VERSION = Opcodes.ASM7;
|
||||
|
||||
private static final boolean DEBUG = Boolean.getBoolean("nasgen.debug");
|
||||
|
||||
|
@ -1902,8 +1902,8 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
Label L_done;
|
||||
|
||||
__ ldrb(rscratch1, Address(rbcp, 0));
|
||||
__ cmpw(r1, Bytecodes::_invokestatic);
|
||||
__ br(Assembler::EQ, L_done);
|
||||
__ cmpw(rscratch1, Bytecodes::_invokestatic);
|
||||
__ br(Assembler::NE, L_done);
|
||||
|
||||
// The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
|
||||
// Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
|
||||
@ -1938,7 +1938,6 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
// remove the activation (without doing throws on illegalMonitorExceptions)
|
||||
__ remove_activation(vtos, false, true, false);
|
||||
// restore exception
|
||||
// restore exception
|
||||
__ get_vm_result(r0, rthread);
|
||||
|
||||
// In between activations - previous activation type unknown yet
|
||||
@ -1947,9 +1946,8 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
//
|
||||
// r0: exception
|
||||
// lr: return address/pc that threw exception
|
||||
// rsp: expression stack of caller
|
||||
// esp: expression stack of caller
|
||||
// rfp: fp of caller
|
||||
// FIXME: There's no point saving LR here because VM calls don't trash it
|
||||
__ stp(r0, lr, Address(__ pre(sp, -2 * wordSize))); // save exception & return address
|
||||
__ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
|
||||
SharedRuntime::exception_handler_for_return_address),
|
||||
|
@ -498,7 +498,7 @@ class Assembler : public AbstractAssembler {
|
||||
void dmb(DMB_Opt opt, Register reg) {
|
||||
if (VM_Version::arm_arch() >= 7) {
|
||||
emit_int32(0xF57FF050 | opt);
|
||||
} else {
|
||||
} else if (VM_Version::arm_arch() == 6) {
|
||||
bool preserve_tmp = (reg == noreg);
|
||||
if(preserve_tmp) {
|
||||
reg = Rtemp;
|
||||
|
@ -41,10 +41,6 @@ inline int os::file_name_strncmp(const char* s1, const char* s2, size_t num) {
|
||||
return strncmp(s1, s2, num);
|
||||
}
|
||||
|
||||
inline bool os::obsolete_option(const JavaVMOption *option) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool os::uses_stack_guard_pages() {
|
||||
return true;
|
||||
}
|
||||
|
@ -39,10 +39,6 @@ inline int os::file_name_strncmp(const char* s1, const char* s2, size_t num) {
|
||||
return strncmp(s1, s2, num);
|
||||
}
|
||||
|
||||
inline bool os::obsolete_option(const JavaVMOption *option) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool os::uses_stack_guard_pages() {
|
||||
return true;
|
||||
}
|
||||
|
@ -39,10 +39,6 @@ inline int os::file_name_strncmp(const char* s1, const char* s2, size_t num) {
|
||||
return strncmp(s1, s2, num);
|
||||
}
|
||||
|
||||
inline bool os::obsolete_option(const JavaVMOption *option) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool os::uses_stack_guard_pages() {
|
||||
return true;
|
||||
}
|
||||
|
@ -700,19 +700,6 @@ void os::breakpoint() {
|
||||
BREAKPOINT;
|
||||
}
|
||||
|
||||
bool os::obsolete_option(const JavaVMOption *option) {
|
||||
if (!strncmp(option->optionString, "-Xt", 3)) {
|
||||
return true;
|
||||
} else if (!strncmp(option->optionString, "-Xtm", 4)) {
|
||||
return true;
|
||||
} else if (!strncmp(option->optionString, "-Xverifyheap", 12)) {
|
||||
return true;
|
||||
} else if (!strncmp(option->optionString, "-Xmaxjitcodesize", 16)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool os::Solaris::valid_stack_address(Thread* thread, address sp) {
|
||||
address stackStart = (address)thread->stack_base();
|
||||
address stackEnd = (address)(stackStart - (address)thread->stack_size());
|
||||
|
@ -45,10 +45,6 @@ inline void* os::dll_lookup(void *lib, const char *name) {
|
||||
return (void*)::GetProcAddress((HMODULE)lib, name);
|
||||
}
|
||||
|
||||
inline bool os::obsolete_option(const JavaVMOption *option) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool os::uses_stack_guard_pages() {
|
||||
return true;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ inline static void dmb_sy() {
|
||||
__asm__ volatile (
|
||||
".word 0xF57FF050 | 0xf" : : : "memory");
|
||||
#endif
|
||||
} else {
|
||||
} else if (VM_Version::arm_arch() == 6) {
|
||||
intptr_t zero = 0;
|
||||
__asm__ volatile (
|
||||
"mcr p15, 0, %0, c7, c10, 5"
|
||||
@ -80,7 +80,7 @@ inline static void dmb_st() {
|
||||
__asm__ volatile (
|
||||
".word 0xF57FF050 | 0xe" : : : "memory");
|
||||
#endif
|
||||
} else {
|
||||
} else if (VM_Version::arm_arch() == 6) {
|
||||
intptr_t zero = 0;
|
||||
__asm__ volatile (
|
||||
"mcr p15, 0, %0, c7, c10, 5"
|
||||
|
@ -287,7 +287,7 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS
|
||||
if (!is_id_specified()) {
|
||||
error("If source location is specified, id must be also specified");
|
||||
}
|
||||
InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, THREAD);
|
||||
InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL);
|
||||
|
||||
if (strncmp(_class_name, "java/", 5) == 0) {
|
||||
log_info(cds)("Prohibited package for non-bootstrap classes: %s.class from %s",
|
||||
@ -303,8 +303,9 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS
|
||||
_interfaces->length(), k->local_interfaces()->length());
|
||||
}
|
||||
|
||||
if (!SystemDictionaryShared::add_non_builtin_klass(class_name, ClassLoaderData::the_null_class_loader_data(),
|
||||
k, THREAD)) {
|
||||
bool added = SystemDictionaryShared::add_unregistered_class(k, CHECK_NULL);
|
||||
if (!added) {
|
||||
// We allow only a single unregistered class for each unique name.
|
||||
error("Duplicated class %s", _class_name);
|
||||
}
|
||||
|
||||
@ -353,7 +354,7 @@ Klass* ClassListParser::load_current_class(TRAPS) {
|
||||
vmSymbols::loadClass_name(),
|
||||
vmSymbols::string_class_signature(),
|
||||
ext_class_name,
|
||||
THREAD);
|
||||
THREAD); // <-- failure is handled below
|
||||
} else {
|
||||
// array classes are not supported in class list.
|
||||
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
|
||||
|
@ -496,11 +496,11 @@ bool ClassLoaderDataGraph::is_valid(ClassLoaderData* loader_data) {
|
||||
|
||||
// Move class loader data from main list to the unloaded list for unloading
|
||||
// and deallocation later.
|
||||
bool ClassLoaderDataGraph::do_unloading(bool do_cleaning) {
|
||||
bool ClassLoaderDataGraph::do_unloading() {
|
||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||
|
||||
// Indicate whether safepoint cleanup is needed.
|
||||
_safepoint_cleanup_needed |= do_cleaning;
|
||||
_safepoint_cleanup_needed = true;
|
||||
|
||||
ClassLoaderData* data = _head;
|
||||
ClassLoaderData* prev = NULL;
|
||||
|
@ -88,7 +88,7 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||
static void loaded_classes_do(KlassClosure* klass_closure);
|
||||
static void unlocked_loaded_classes_do(KlassClosure* klass_closure);
|
||||
static void classes_unloading_do(void f(Klass* const));
|
||||
static bool do_unloading(bool do_cleaning);
|
||||
static bool do_unloading();
|
||||
|
||||
// Expose state to avoid logging overhead in safepoint cleanup tasks.
|
||||
static inline bool should_clean_metaspaces_and_reset();
|
||||
|
@ -350,7 +350,3 @@ ClassPathEntry* ClassLoaderExt::find_classpath_entry_from_cache(const char* path
|
||||
cached_path_entries->insert_before(0, ccpe);
|
||||
return new_entry;
|
||||
}
|
||||
|
||||
Klass* ClassLoaderExt::load_one_class(ClassListParser* parser, TRAPS) {
|
||||
return parser->load_current_class(THREAD);
|
||||
}
|
||||
|
@ -115,7 +115,6 @@ public:
|
||||
static void record_result(const s2 classpath_index,
|
||||
InstanceKlass* result, TRAPS);
|
||||
static InstanceKlass* load_class(Symbol* h_name, const char* path, TRAPS);
|
||||
static Klass* load_one_class(ClassListParser* parser, TRAPS);
|
||||
static void set_has_app_classes() {
|
||||
_has_app_classes = true;
|
||||
}
|
||||
|
@ -163,6 +163,7 @@ void CompactHashtableWriter::dump(SimpleCompactHashtable *cht, const char* table
|
||||
msg.info("Average bucket size : %9.3f", summary.avg());
|
||||
msg.info("Variance of bucket size : %9.3f", summary.variance());
|
||||
msg.info("Std. dev. of bucket size: %9.3f", summary.sd());
|
||||
msg.info("Maximum bucket size : %9d", (int)summary.maximum());
|
||||
msg.info("Empty buckets : %9d", _num_empty_buckets);
|
||||
msg.info("Value_Only buckets : %9d", _num_value_only_buckets);
|
||||
msg.info("Other buckets : %9d", _num_other_buckets);
|
||||
|
@ -244,8 +244,6 @@ class CompactHashtable : public SimpleCompactHashtable {
|
||||
}
|
||||
|
||||
public:
|
||||
CompactHashtable() : SimpleCompactHashtable() {}
|
||||
|
||||
// Lookup a value V from the compact table using key K
|
||||
inline V lookup(K key, unsigned int hash, int len) const {
|
||||
if (_entry_count > 0) {
|
||||
@ -299,8 +297,53 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_table_statistics(outputStream* st, const char* name) {
|
||||
st->print_cr("%s statistics:", name);
|
||||
int total_entries = 0;
|
||||
int max_bucket = 0;
|
||||
for (u4 i = 0; i < _bucket_count; i++) {
|
||||
u4 bucket_info = _buckets[i];
|
||||
int bucket_type = BUCKET_TYPE(bucket_info);
|
||||
int bucket_size;
|
||||
|
||||
if (bucket_type == VALUE_ONLY_BUCKET_TYPE) {
|
||||
bucket_size = 1;
|
||||
} else {
|
||||
bucket_size = (BUCKET_OFFSET(_buckets[i + 1]) - BUCKET_OFFSET(bucket_info)) / 2;
|
||||
}
|
||||
total_entries += bucket_size;
|
||||
if (max_bucket < bucket_size) {
|
||||
max_bucket = bucket_size;
|
||||
}
|
||||
}
|
||||
st->print_cr("Number of buckets : %9d", _bucket_count);
|
||||
st->print_cr("Number of entries : %9d", total_entries);
|
||||
st->print_cr("Maximum bucket size : %9d", max_bucket);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// OffsetCompactHashtable -- This is used to store many types of objects
|
||||
// in the CDS archive. On 64-bit platforms, we save space by using a 32-bit
|
||||
// offset from the CDS base address.
|
||||
|
||||
template <typename V>
|
||||
V read_value_from_compact_hashtable(address base_address, u4 offset) {
|
||||
return (V)(base_address + offset);
|
||||
}
|
||||
|
||||
template <
|
||||
typename K,
|
||||
typename V,
|
||||
bool (*EQUALS)(V value, K key, int len)
|
||||
>
|
||||
class OffsetCompactHashtable : public CompactHashtable<
|
||||
K, V, read_value_from_compact_hashtable<V>, EQUALS> {
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Read/Write the contents of a hashtable textual dump (created by
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "classfile/dictionary.inline.hpp"
|
||||
#include "classfile/protectionDomainCache.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
@ -44,16 +43,8 @@
|
||||
// needs resizing, which is costly to do at Safepoint.
|
||||
bool Dictionary::_some_dictionary_needs_resizing = false;
|
||||
|
||||
size_t Dictionary::entry_size() {
|
||||
if (DumpSharedSpaces) {
|
||||
return SystemDictionaryShared::dictionary_entry_size();
|
||||
} else {
|
||||
return sizeof(DictionaryEntry);
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary::Dictionary(ClassLoaderData* loader_data, int table_size, bool resizable)
|
||||
: Hashtable<InstanceKlass*, mtClass>(table_size, (int)entry_size()),
|
||||
: Hashtable<InstanceKlass*, mtClass>(table_size, (int)sizeof(DictionaryEntry)),
|
||||
_resizable(resizable), _needs_resizing(false), _loader_data(loader_data) {
|
||||
};
|
||||
|
||||
@ -61,7 +52,7 @@ Dictionary::Dictionary(ClassLoaderData* loader_data, int table_size, bool resiza
|
||||
Dictionary::Dictionary(ClassLoaderData* loader_data,
|
||||
int table_size, HashtableBucket<mtClass>* t,
|
||||
int number_of_entries, bool resizable)
|
||||
: Hashtable<InstanceKlass*, mtClass>(table_size, (int)entry_size(), t, number_of_entries),
|
||||
: Hashtable<InstanceKlass*, mtClass>(table_size, (int)sizeof(DictionaryEntry), t, number_of_entries),
|
||||
_resizable(resizable), _needs_resizing(false), _loader_data(loader_data) {
|
||||
};
|
||||
|
||||
@ -83,9 +74,6 @@ DictionaryEntry* Dictionary::new_entry(unsigned int hash, InstanceKlass* klass)
|
||||
DictionaryEntry* entry = (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::allocate_new_entry(hash, klass);
|
||||
entry->set_pd_set(NULL);
|
||||
assert(klass->is_instance_klass(), "Must be");
|
||||
if (DumpSharedSpaces) {
|
||||
SystemDictionaryShared::init_shared_dictionary_entry(klass, entry);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -280,26 +268,6 @@ void Dictionary::do_unloading() {
|
||||
}
|
||||
}
|
||||
|
||||
void Dictionary::remove_classes_in_error_state() {
|
||||
assert(DumpSharedSpaces, "supported only when dumping");
|
||||
DictionaryEntry* probe = NULL;
|
||||
for (int index = 0; index < table_size(); index++) {
|
||||
for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
|
||||
probe = *p;
|
||||
InstanceKlass* ik = probe->instance_klass();
|
||||
if (ik->is_in_error_state()) { // purge this entry
|
||||
*p = probe->next();
|
||||
free_entry(probe);
|
||||
ResourceMark rm;
|
||||
tty->print_cr("Preload Warning: Removed error class: %s", ik->external_name());
|
||||
continue;
|
||||
}
|
||||
|
||||
p = probe->next_addr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Just the classes from defining class loaders
|
||||
void Dictionary::classes_do(void f(InstanceKlass*)) {
|
||||
for (int index = 0; index < table_size(); index++) {
|
||||
@ -349,7 +317,6 @@ void Dictionary::classes_do(MetaspaceClosure* it) {
|
||||
probe != NULL;
|
||||
probe = probe->next()) {
|
||||
it->push(probe->klass_addr());
|
||||
((SharedDictionaryEntry*)probe)->metaspace_pointers_do(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -390,9 +357,7 @@ DictionaryEntry* Dictionary::get_entry(int index, unsigned int hash,
|
||||
entry != NULL;
|
||||
entry = entry->next()) {
|
||||
if (entry->hash() == hash && entry->equals(class_name)) {
|
||||
if (!DumpSharedSpaces || SystemDictionaryShared::is_builtin(entry)) {
|
||||
return entry;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@ -423,18 +388,6 @@ InstanceKlass* Dictionary::find_class(int index, unsigned int hash,
|
||||
}
|
||||
|
||||
|
||||
// Variant of find_class for shared classes. No locking required, as
|
||||
// that table is static.
|
||||
|
||||
InstanceKlass* Dictionary::find_shared_class(int index, unsigned int hash,
|
||||
Symbol* name) {
|
||||
assert (index == index_for(name), "incorrect index?");
|
||||
|
||||
DictionaryEntry* entry = get_entry(index, hash, name);
|
||||
return (entry != NULL) ? entry->instance_klass() : NULL;
|
||||
}
|
||||
|
||||
|
||||
void Dictionary::add_protection_domain(int index, unsigned int hash,
|
||||
InstanceKlass* klass,
|
||||
Handle protection_domain,
|
||||
@ -465,70 +418,6 @@ bool Dictionary::is_valid_protection_domain(unsigned int hash,
|
||||
return entry->is_valid_protection_domain(protection_domain);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
static bool is_jfr_event_class(Klass *k) {
|
||||
while (k) {
|
||||
if (k->name()->equals("jdk/internal/event/Event")) {
|
||||
return true;
|
||||
}
|
||||
k = k->super();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Dictionary::reorder_dictionary_for_sharing() {
|
||||
|
||||
// Copy all the dictionary entries into a single master list.
|
||||
assert(DumpSharedSpaces, "Should only be used at dump time");
|
||||
|
||||
DictionaryEntry* master_list = NULL;
|
||||
for (int i = 0; i < table_size(); ++i) {
|
||||
DictionaryEntry* p = bucket(i);
|
||||
while (p != NULL) {
|
||||
DictionaryEntry* next = p->next();
|
||||
InstanceKlass*ik = p->instance_klass();
|
||||
if (ik->has_signer_and_not_archived()) {
|
||||
// We cannot include signed classes in the archive because the certificates
|
||||
// used during dump time may be different than those used during
|
||||
// runtime (due to expiration, etc).
|
||||
ResourceMark rm;
|
||||
tty->print_cr("Preload Warning: Skipping %s from signed JAR",
|
||||
ik->name()->as_C_string());
|
||||
free_entry(p);
|
||||
} else if (is_jfr_event_class(ik)) {
|
||||
// We cannot include JFR event classes because they need runtime-specific
|
||||
// instrumentation in order to work with -XX:FlightRecorderOptions=retransform=false.
|
||||
// There are only a small number of these classes, so it's not worthwhile to
|
||||
// support them and make CDS more complicated.
|
||||
ResourceMark rm;
|
||||
tty->print_cr("Skipping JFR event class %s", ik->name()->as_C_string());
|
||||
free_entry(p);
|
||||
} else {
|
||||
p->set_next(master_list);
|
||||
master_list = p;
|
||||
}
|
||||
p = next;
|
||||
}
|
||||
set_entry(i, NULL);
|
||||
}
|
||||
|
||||
// Add the dictionary entries back to the list in the correct buckets.
|
||||
while (master_list != NULL) {
|
||||
DictionaryEntry* p = master_list;
|
||||
master_list = master_list->next();
|
||||
p->set_next(NULL);
|
||||
Symbol* class_name = p->instance_klass()->name();
|
||||
// Since the null class loader data isn't copied to the CDS archive,
|
||||
// compute the hash with NULL for loader data.
|
||||
unsigned int hash = compute_hash(class_name);
|
||||
int index = hash_to_index(hash);
|
||||
p->set_hash(hash);
|
||||
p->set_next(bucket(index));
|
||||
set_entry(index, p);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SymbolPropertyTable::SymbolPropertyTable(int table_size)
|
||||
: Hashtable<Symbol*, mtSymbol>(table_size, sizeof(SymbolPropertyEntry))
|
||||
{
|
||||
@ -605,10 +494,7 @@ void Dictionary::print_on(outputStream* st) const {
|
||||
(loader_data() == e->class_loader_data());
|
||||
st->print("%4d: %s%s", index, is_defining_class ? " " : "^", e->external_name());
|
||||
ClassLoaderData* cld = e->class_loader_data();
|
||||
if (cld == NULL) {
|
||||
// Shared class not restored yet in shared dictionary
|
||||
st->print(", loader data <shared, not restored>");
|
||||
} else if (!loader_data()->is_the_null_class_loader_data()) {
|
||||
if (!loader_data()->is_the_null_class_loader_data()) {
|
||||
// Class loader output for the dictionary for the null class loader data is
|
||||
// redundant and obvious.
|
||||
st->print(", ");
|
||||
@ -634,7 +520,7 @@ void Dictionary::verify() {
|
||||
ClassLoaderData* cld = loader_data();
|
||||
// class loader must be present; a null class loader is the
|
||||
// boostrap loader
|
||||
guarantee(cld != NULL || DumpSharedSpaces ||
|
||||
guarantee(cld != NULL ||
|
||||
cld->class_loader() == NULL ||
|
||||
cld->class_loader()->is_instance(),
|
||||
"checking type of class_loader");
|
||||
|
@ -36,8 +36,7 @@ class DictionaryEntry;
|
||||
class BoolObjectClosure;
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// The data structure for the class loader data dictionaries (and the shared system
|
||||
// dictionary).
|
||||
// The data structure for the class loader data dictionaries.
|
||||
|
||||
class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
|
||||
friend class VMStructs;
|
||||
@ -54,8 +53,6 @@ class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
|
||||
|
||||
void clean_cached_protection_domains(DictionaryEntry* probe);
|
||||
|
||||
protected:
|
||||
static size_t entry_size();
|
||||
public:
|
||||
Dictionary(ClassLoaderData* loader_data, int table_size, bool resizable = false);
|
||||
Dictionary(ClassLoaderData* loader_data, int table_size, HashtableBucket<mtClass>* t, int number_of_entries, bool resizable = false);
|
||||
@ -70,15 +67,12 @@ public:
|
||||
|
||||
InstanceKlass* find_class(int index, unsigned int hash, Symbol* name);
|
||||
|
||||
InstanceKlass* find_shared_class(int index, unsigned int hash, Symbol* name);
|
||||
|
||||
void classes_do(void f(InstanceKlass*));
|
||||
void classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
|
||||
void all_entries_do(KlassClosure* closure);
|
||||
void classes_do(MetaspaceClosure* it);
|
||||
|
||||
void unlink();
|
||||
void remove_classes_in_error_state();
|
||||
|
||||
// Unload classes whose defining loaders are unloaded
|
||||
void do_unloading();
|
||||
@ -92,9 +86,6 @@ public:
|
||||
InstanceKlass* klass,
|
||||
Handle protection_domain, TRAPS);
|
||||
|
||||
// Sharing support
|
||||
void reorder_dictionary_for_sharing() NOT_CDS_RETURN;
|
||||
|
||||
void print_on(outputStream* st) const;
|
||||
void verify();
|
||||
DictionaryEntry* bucket(int i) const {
|
||||
|
@ -1090,8 +1090,7 @@ oop java_lang_Class::archive_mirror(Klass* k, TRAPS) {
|
||||
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass *ik = InstanceKlass::cast(k);
|
||||
assert(ik->signers() == NULL && !k->has_signer_and_not_archived(),
|
||||
"class with signer cannot be supported");
|
||||
assert(ik->signers() == NULL, "class with signer should have been excluded");
|
||||
|
||||
if (!(ik->is_shared_boot_class() || ik->is_shared_platform_class() ||
|
||||
ik->is_shared_app_class())) {
|
||||
|
@ -847,7 +847,7 @@ void StringTable::copy_shared_string_table(CompactHashtableWriter* writer) {
|
||||
assert(HeapShared::is_heap_object_archiving_allowed(), "must be");
|
||||
|
||||
CopyToArchive copy(writer);
|
||||
StringTable::the_table()->_local_table->do_scan(Thread::current(), copy);
|
||||
StringTable::the_table()->_local_table->do_safepoint_scan(copy);
|
||||
}
|
||||
|
||||
void StringTable::write_to_archive() {
|
||||
|
@ -57,9 +57,6 @@
|
||||
#define ON_STACK_BUFFER_LENGTH 128
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
inline Symbol* read_symbol_from_compact_hashtable(address base_address, u4 offset) {
|
||||
return (Symbol*)(base_address + offset);
|
||||
}
|
||||
|
||||
inline bool symbol_equals_compact_hashtable_entry(Symbol* value, const char* key, int len) {
|
||||
if (value->equals(key, len)) {
|
||||
@ -70,9 +67,8 @@ inline bool symbol_equals_compact_hashtable_entry(Symbol* value, const char* key
|
||||
}
|
||||
}
|
||||
|
||||
static CompactHashtable<
|
||||
static OffsetCompactHashtable<
|
||||
const char*, Symbol*,
|
||||
read_symbol_from_compact_hashtable,
|
||||
symbol_equals_compact_hashtable_entry
|
||||
> _shared_table;
|
||||
|
||||
@ -281,7 +277,7 @@ public:
|
||||
void SymbolTable::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
assert(DumpSharedSpaces, "called only during dump time");
|
||||
MetaspacePointersDo mpd(it);
|
||||
SymbolTable::the_table()->_local_table->do_scan(Thread::current(), mpd);
|
||||
SymbolTable::the_table()->_local_table->do_safepoint_scan(mpd);
|
||||
}
|
||||
|
||||
Symbol* SymbolTable::lookup_dynamic(const char* name,
|
||||
@ -637,23 +633,14 @@ struct CopyToArchive : StackObj {
|
||||
unsigned int fixed_hash = hash_shared_symbol((const char*)sym->bytes(), sym->utf8_length());
|
||||
assert(fixed_hash == hash_symbol((const char*)sym->bytes(), sym->utf8_length(), false),
|
||||
"must not rehash during dumping");
|
||||
|
||||
uintx deltax = MetaspaceShared::object_delta(sym);
|
||||
// When the symbols are stored into the archive, we already check that
|
||||
// they won't be more than MAX_SHARED_DELTA from the base address, or
|
||||
// else the dumping would have been aborted.
|
||||
assert(deltax <= MAX_SHARED_DELTA, "must not be");
|
||||
u4 delta = u4(deltax);
|
||||
|
||||
// add to the compact table
|
||||
_writer->add(fixed_hash, delta);
|
||||
_writer->add(fixed_hash, MetaspaceShared::object_delta_u4(sym));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void SymbolTable::copy_shared_symbol_table(CompactHashtableWriter* writer) {
|
||||
CopyToArchive copy(writer);
|
||||
SymbolTable::the_table()->_local_table->do_scan(Thread::current(), copy);
|
||||
SymbolTable::the_table()->_local_table->do_safepoint_scan(copy);
|
||||
}
|
||||
|
||||
void SymbolTable::write_to_archive() {
|
||||
|
@ -96,7 +96,6 @@
|
||||
#endif
|
||||
|
||||
PlaceholderTable* SystemDictionary::_placeholders = NULL;
|
||||
Dictionary* SystemDictionary::_shared_dictionary = NULL;
|
||||
LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL;
|
||||
ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
|
||||
SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
|
||||
@ -355,7 +354,7 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* child_name,
|
||||
assert(!FieldType::is_array(super_name), "invalid super class name");
|
||||
#if INCLUDE_CDS
|
||||
if (DumpSharedSpaces) {
|
||||
// Special processing for CDS dump time.
|
||||
// Special processing for handling UNREGISTERED shared classes.
|
||||
InstanceKlass* k = SystemDictionaryShared::dump_time_resolve_super_or_fail(child_name,
|
||||
super_name, class_loader, protection_domain, is_superclass, CHECK_NULL);
|
||||
if (k) {
|
||||
@ -1163,39 +1162,11 @@ InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void SystemDictionary::set_shared_dictionary(HashtableBucket<mtClass>* t, int length,
|
||||
int number_of_entries) {
|
||||
assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
|
||||
assert(length == _shared_dictionary_size * sizeof(HashtableBucket<mtClass>),
|
||||
"bad shared dictionary size.");
|
||||
_shared_dictionary = new Dictionary(ClassLoaderData::the_null_class_loader_data(),
|
||||
_shared_dictionary_size, t, number_of_entries,
|
||||
false /* explicitly set _resizable to false */);
|
||||
}
|
||||
|
||||
|
||||
// If there is a shared dictionary, then find the entry for the
|
||||
// given shared system class, if any.
|
||||
|
||||
InstanceKlass* SystemDictionary::find_shared_class(Symbol* class_name) {
|
||||
if (shared_dictionary() != NULL) {
|
||||
unsigned int d_hash = shared_dictionary()->compute_hash(class_name);
|
||||
int d_index = shared_dictionary()->hash_to_index(d_hash);
|
||||
|
||||
return shared_dictionary()->find_shared_class(d_index, d_hash, class_name);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Load a class for boot loader from the shared spaces (found through
|
||||
// the shared system dictionary). Force the super class and all interfaces
|
||||
// to be loaded.
|
||||
// Load a class for boot loader from the shared spaces. This also
|
||||
// forces the super class and all interfaces to be loaded.
|
||||
InstanceKlass* SystemDictionary::load_shared_boot_class(Symbol* class_name,
|
||||
TRAPS) {
|
||||
InstanceKlass* ik = find_shared_class(class_name);
|
||||
// Make sure we only return the boot class.
|
||||
InstanceKlass* ik = SystemDictionaryShared::find_builtin_class(class_name);
|
||||
if (ik != NULL && ik->is_shared_boot_class()) {
|
||||
return load_shared_class(ik, Handle(), Handle(), THREAD);
|
||||
}
|
||||
@ -1410,18 +1381,6 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
|
||||
}
|
||||
return ik;
|
||||
}
|
||||
|
||||
void SystemDictionary::clear_invoke_method_table() {
|
||||
SymbolPropertyEntry* spe = NULL;
|
||||
for (int index = 0; index < _invoke_method_table->table_size(); index++) {
|
||||
SymbolPropertyEntry* p = _invoke_method_table->bucket(index);
|
||||
while (p != NULL) {
|
||||
spe = p;
|
||||
p = p->next();
|
||||
_invoke_method_table->free_entry(spe);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
|
||||
@ -1845,15 +1804,14 @@ void SystemDictionary::add_to_hierarchy(InstanceKlass* k, TRAPS) {
|
||||
|
||||
// Assumes classes in the SystemDictionary are only unloaded at a safepoint
|
||||
// Note: anonymous classes are not in the SD.
|
||||
bool SystemDictionary::do_unloading(GCTimer* gc_timer,
|
||||
bool do_cleaning) {
|
||||
bool SystemDictionary::do_unloading(GCTimer* gc_timer) {
|
||||
|
||||
bool unloading_occurred;
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) t("ClassLoaderData", gc_timer);
|
||||
|
||||
// First, mark for unload all ClassLoaderData referencing a dead class loader.
|
||||
unloading_occurred = ClassLoaderDataGraph::do_unloading(do_cleaning);
|
||||
unloading_occurred = ClassLoaderDataGraph::do_unloading();
|
||||
if (unloading_occurred) {
|
||||
JFR_ONLY(Jfr::on_unloading_classes();)
|
||||
ClassLoaderDataGraph::clean_module_and_package_info();
|
||||
@ -1883,7 +1841,7 @@ bool SystemDictionary::do_unloading(GCTimer* gc_timer,
|
||||
_pd_cache_table->trigger_cleanup();
|
||||
}
|
||||
|
||||
if (do_cleaning) {
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) t("ResolvedMethodTable", gc_timer);
|
||||
ResolvedMethodTable::trigger_cleanup();
|
||||
}
|
||||
@ -1901,11 +1859,6 @@ void SystemDictionary::oops_do(OopClosure* f) {
|
||||
invoke_method_table()->oops_do(f);
|
||||
}
|
||||
|
||||
// CDS: scan and relocate all classes in the system dictionary.
|
||||
void SystemDictionary::classes_do(MetaspaceClosure* it) {
|
||||
ClassLoaderData::the_null_class_loader_data()->dictionary()->classes_do(it);
|
||||
}
|
||||
|
||||
// CDS: scan and relocate all classes referenced by _well_known_klasses[].
|
||||
void SystemDictionary::well_known_klasses_do(MetaspaceClosure* it) {
|
||||
for (int id = FIRST_WKID; id < WKID_LIMIT; id++) {
|
||||
@ -1921,22 +1874,6 @@ void SystemDictionary::methods_do(void f(Method*)) {
|
||||
invoke_method_table()->methods_do(f);
|
||||
}
|
||||
|
||||
class RemoveClassesClosure : public CLDClosure {
|
||||
public:
|
||||
void do_cld(ClassLoaderData* cld) {
|
||||
if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
|
||||
cld->dictionary()->remove_classes_in_error_state();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void SystemDictionary::remove_classes_in_error_state() {
|
||||
ClassLoaderData::the_null_class_loader_data()->dictionary()->remove_classes_in_error_state();
|
||||
RemoveClassesClosure rcc;
|
||||
MutexLocker ml(ClassLoaderDataGraph_lock);
|
||||
ClassLoaderDataGraph::cld_do(&rcc);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Initialization
|
||||
|
||||
@ -2039,6 +1976,7 @@ void SystemDictionary::resolve_well_known_classes(TRAPS) {
|
||||
HeapShared::fixup_mapped_heap_regions();
|
||||
|
||||
// Initialize the constant pool for the Object_class
|
||||
assert(Object_klass()->is_shared(), "must be");
|
||||
Object_klass()->constants()->restore_unshareable_info(CHECK);
|
||||
resolve_wk_klasses_through(WK_KLASS_ENUM_NAME(Class_klass), scan, CHECK);
|
||||
} else
|
||||
@ -2922,40 +2860,10 @@ ProtectionDomainCacheEntry* SystemDictionary::cache_get(Handle protection_domain
|
||||
return _pd_cache_table->get(protection_domain);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void SystemDictionary::reorder_dictionary_for_sharing() {
|
||||
ClassLoaderData::the_null_class_loader_data()->dictionary()->reorder_dictionary_for_sharing();
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t SystemDictionary::count_bytes_for_buckets() {
|
||||
return ClassLoaderData::the_null_class_loader_data()->dictionary()->count_bytes_for_buckets();
|
||||
}
|
||||
|
||||
size_t SystemDictionary::count_bytes_for_table() {
|
||||
return ClassLoaderData::the_null_class_loader_data()->dictionary()->count_bytes_for_table();
|
||||
}
|
||||
|
||||
void SystemDictionary::copy_buckets(char* top, char* end) {
|
||||
ClassLoaderData::the_null_class_loader_data()->dictionary()->copy_buckets(top, end);
|
||||
}
|
||||
|
||||
void SystemDictionary::copy_table(char* top, char* end) {
|
||||
ClassLoaderData::the_null_class_loader_data()->dictionary()->copy_table(top, end);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void SystemDictionary::print_shared(outputStream *st) {
|
||||
shared_dictionary()->print_on(st);
|
||||
}
|
||||
|
||||
void SystemDictionary::print_on(outputStream *st) {
|
||||
if (shared_dictionary() != NULL) {
|
||||
st->print_cr("Shared Dictionary");
|
||||
shared_dictionary()->print_on(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
CDS_ONLY(SystemDictionaryShared::print_on(st));
|
||||
GCMutexLocker mu(SystemDictionary_lock);
|
||||
|
||||
ClassLoaderDataGraph::print_dictionary(st);
|
||||
@ -2997,9 +2905,7 @@ void SystemDictionary::dump(outputStream *st, bool verbose) {
|
||||
if (verbose) {
|
||||
print_on(st);
|
||||
} else {
|
||||
if (shared_dictionary() != NULL) {
|
||||
shared_dictionary()->print_table_statistics(st, "Shared Dictionary");
|
||||
}
|
||||
CDS_ONLY(SystemDictionaryShared::print_table_statistics(st));
|
||||
ClassLoaderDataGraph::print_dictionary_statistics(st);
|
||||
placeholders()->print_table_statistics(st, "Placeholder Table");
|
||||
constraints()->print_table_statistics(st, "LoaderConstraints Table");
|
||||
@ -3032,60 +2938,6 @@ int SystemDictionaryDCmd::num_arguments() {
|
||||
}
|
||||
}
|
||||
|
||||
class CombineDictionariesClosure : public CLDClosure {
|
||||
private:
|
||||
Dictionary* _master_dictionary;
|
||||
public:
|
||||
CombineDictionariesClosure(Dictionary* master_dictionary) :
|
||||
_master_dictionary(master_dictionary) {}
|
||||
void do_cld(ClassLoaderData* cld) {
|
||||
ResourceMark rm;
|
||||
if (cld->is_unsafe_anonymous()) {
|
||||
return;
|
||||
}
|
||||
if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
|
||||
for (int i = 0; i < cld->dictionary()->table_size(); ++i) {
|
||||
Dictionary* curr_dictionary = cld->dictionary();
|
||||
DictionaryEntry* p = curr_dictionary->bucket(i);
|
||||
while (p != NULL) {
|
||||
Symbol* name = p->instance_klass()->name();
|
||||
unsigned int d_hash = _master_dictionary->compute_hash(name);
|
||||
int d_index = _master_dictionary->hash_to_index(d_hash);
|
||||
DictionaryEntry* next = p->next();
|
||||
if (p->literal()->class_loader_data() != cld) {
|
||||
// This is an initiating class loader entry; don't use it
|
||||
log_trace(cds)("Skipping initiating cl entry: %s", name->as_C_string());
|
||||
curr_dictionary->free_entry(p);
|
||||
} else {
|
||||
log_trace(cds)("Moved to boot dictionary: %s", name->as_C_string());
|
||||
curr_dictionary->unlink_entry(p);
|
||||
p->set_pd_set(NULL); // pd_set is runtime only information and will be reconstructed.
|
||||
_master_dictionary->add_entry(d_index, p);
|
||||
}
|
||||
p = next;
|
||||
}
|
||||
*curr_dictionary->bucket_addr(i) = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Combining platform and system loader dictionaries into boot loader dictionary.
|
||||
// During run time, we only have one shared dictionary.
|
||||
void SystemDictionary::combine_shared_dictionaries() {
|
||||
assert(DumpSharedSpaces, "dump time only");
|
||||
Dictionary* master_dictionary = ClassLoaderData::the_null_class_loader_data()->dictionary();
|
||||
CombineDictionariesClosure cdc(master_dictionary);
|
||||
ClassLoaderDataGraph::cld_do(&cdc);
|
||||
|
||||
// These tables are no longer valid or necessary. Keeping them around will
|
||||
// cause SystemDictionary::verify() to fail. Let's empty them.
|
||||
_placeholders = new PlaceholderTable(_placeholder_table_size);
|
||||
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
|
||||
|
||||
NOT_PRODUCT(SystemDictionary::verify());
|
||||
}
|
||||
|
||||
void SystemDictionary::initialize_oop_storage() {
|
||||
_vm_weak_oop_storage =
|
||||
new OopStorage("VM Weak Oop Handles",
|
||||
|
@ -347,13 +347,7 @@ public:
|
||||
|
||||
// Unload (that is, break root links to) all unmarked classes and
|
||||
// loaders. Returns "true" iff something was unloaded.
|
||||
static bool do_unloading(GCTimer* gc_timer,
|
||||
bool do_cleaning = true);
|
||||
|
||||
// Used by DumpSharedSpaces only to remove classes that failed verification
|
||||
static void remove_classes_in_error_state();
|
||||
|
||||
static int calculate_systemdictionary_size(int loadedclasses);
|
||||
static bool do_unloading(GCTimer* gc_timer);
|
||||
|
||||
// Applies "f->do_oop" to all root oops in the system dictionary.
|
||||
static void oops_do(OopClosure* f);
|
||||
@ -365,19 +359,9 @@ public:
|
||||
static ProtectionDomainCacheTable* pd_cache_table() { return _pd_cache_table; }
|
||||
|
||||
public:
|
||||
// Sharing support.
|
||||
static void reorder_dictionary_for_sharing() NOT_CDS_RETURN;
|
||||
static void combine_shared_dictionaries();
|
||||
static size_t count_bytes_for_buckets();
|
||||
static size_t count_bytes_for_table();
|
||||
static void copy_buckets(char* top, char* end);
|
||||
static void copy_table(char* top, char* end);
|
||||
static void set_shared_dictionary(HashtableBucket<mtClass>* t, int length,
|
||||
int number_of_entries);
|
||||
// Printing
|
||||
static void print() { return print_on(tty); }
|
||||
static void print_on(outputStream* st);
|
||||
static void print_shared(outputStream* st);
|
||||
static void dump(outputStream* st, bool verbose);
|
||||
|
||||
// Monotonically increasing counter which grows as classes are
|
||||
@ -580,7 +564,6 @@ public:
|
||||
_loader_constraint_size = 107, // number of entries in constraint table
|
||||
_resolution_error_size = 107, // number of entries in resolution error table
|
||||
_invoke_method_size = 139, // number of entries in invoke method table
|
||||
_shared_dictionary_size = 1009, // number of entries in shared dictionary
|
||||
_placeholder_table_size = 1009 // number of entries in hash table for placeholders
|
||||
};
|
||||
|
||||
@ -590,9 +573,6 @@ public:
|
||||
// Hashtable holding placeholders for classes being loaded.
|
||||
static PlaceholderTable* _placeholders;
|
||||
|
||||
// Hashtable holding classes from the shared archive.
|
||||
static Dictionary* _shared_dictionary;
|
||||
|
||||
// Monotonically increasing counter which grows with
|
||||
// loading classes as well as hot-swapping and breakpoint setting
|
||||
// and removal.
|
||||
@ -623,7 +603,6 @@ protected:
|
||||
|
||||
friend class VM_PopulateDumpSharedSpace;
|
||||
friend class TraversePlaceholdersClosure;
|
||||
static Dictionary* shared_dictionary() { return _shared_dictionary; }
|
||||
static PlaceholderTable* placeholders() { return _placeholders; }
|
||||
static LoaderConstraintTable* constraints() { return _loader_constraints; }
|
||||
static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
|
||||
@ -663,7 +642,6 @@ protected:
|
||||
public:
|
||||
static bool is_system_class_loader(oop class_loader);
|
||||
static bool is_platform_class_loader(oop class_loader);
|
||||
static void clear_invoke_method_table();
|
||||
|
||||
// Returns TRUE if the method is a non-public member of class java.lang.Object.
|
||||
static bool is_nonpublic_Object_method(Method* m) {
|
||||
@ -675,8 +653,6 @@ public:
|
||||
static OopStorage* vm_weak_oop_storage();
|
||||
|
||||
protected:
|
||||
static InstanceKlass* find_shared_class(Symbol* class_name);
|
||||
|
||||
// Setup link to hierarchy
|
||||
static void add_to_hierarchy(InstanceKlass* k, TRAPS);
|
||||
|
||||
|
@ -53,12 +53,277 @@
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
#include "utilities/resourceHash.hpp"
|
||||
#include "utilities/stringUtils.hpp"
|
||||
|
||||
|
||||
objArrayOop SystemDictionaryShared::_shared_protection_domains = NULL;
|
||||
objArrayOop SystemDictionaryShared::_shared_jar_urls = NULL;
|
||||
objArrayOop SystemDictionaryShared::_shared_jar_manifests = NULL;
|
||||
DEBUG_ONLY(bool SystemDictionaryShared::_checked_excluded_classes = false;)
|
||||
|
||||
class DumpTimeSharedClassInfo: public CHeapObj<mtClass> {
|
||||
public:
|
||||
struct DTConstraint {
|
||||
Symbol* _name;
|
||||
Symbol* _from_name;
|
||||
DTConstraint() : _name(NULL), _from_name(NULL) {}
|
||||
DTConstraint(Symbol* n, Symbol* fn) : _name(n), _from_name(fn) {}
|
||||
};
|
||||
|
||||
InstanceKlass* _klass;
|
||||
int _id;
|
||||
int _clsfile_size;
|
||||
int _clsfile_crc32;
|
||||
bool _excluded;
|
||||
GrowableArray<DTConstraint>* _verifier_constraints;
|
||||
GrowableArray<char>* _verifier_constraint_flags;
|
||||
|
||||
DumpTimeSharedClassInfo() {
|
||||
_klass = NULL;
|
||||
_id = -1;
|
||||
_clsfile_size = -1;
|
||||
_clsfile_crc32 = -1;
|
||||
_excluded = false;
|
||||
_verifier_constraints = NULL;
|
||||
_verifier_constraint_flags = NULL;
|
||||
}
|
||||
|
||||
void add_verification_constraint(InstanceKlass* k, Symbol* name,
|
||||
Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object);
|
||||
|
||||
bool is_builtin() {
|
||||
return SystemDictionaryShared::is_builtin(_klass);
|
||||
}
|
||||
|
||||
int num_constraints() {
|
||||
if (_verifier_constraint_flags != NULL) {
|
||||
return _verifier_constraint_flags->length();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
it->push(&_klass);
|
||||
if (_verifier_constraints != NULL) {
|
||||
for (int i = 0; i < _verifier_constraints->length(); i++) {
|
||||
DTConstraint* cons = _verifier_constraints->adr_at(i);
|
||||
it->push(&cons->_name);
|
||||
it->push(&cons->_from_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class DumpTimeSharedClassTable: public ResourceHashtable<
|
||||
InstanceKlass*,
|
||||
DumpTimeSharedClassInfo,
|
||||
primitive_hash<InstanceKlass*>,
|
||||
primitive_equals<InstanceKlass*>,
|
||||
15889, // prime number
|
||||
ResourceObj::C_HEAP>
|
||||
{
|
||||
int _builtin_count;
|
||||
int _unregistered_count;
|
||||
public:
|
||||
DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k) {
|
||||
DumpTimeSharedClassInfo* p = get(k);
|
||||
if (p == NULL) {
|
||||
assert(!SystemDictionaryShared::checked_excluded_classes(),
|
||||
"no new classes can be added after check_excluded_classes");
|
||||
put(k, DumpTimeSharedClassInfo());
|
||||
p = get(k);
|
||||
assert(p != NULL, "sanity");
|
||||
p->_klass = k;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
class CountClassByCategory : StackObj {
|
||||
DumpTimeSharedClassTable* _table;
|
||||
public:
|
||||
CountClassByCategory(DumpTimeSharedClassTable* table) : _table(table) {}
|
||||
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
|
||||
if (SystemDictionaryShared::is_builtin(k)) {
|
||||
++ _table->_builtin_count;
|
||||
} else {
|
||||
++ _table->_unregistered_count;
|
||||
}
|
||||
return true; // keep on iterating
|
||||
}
|
||||
};
|
||||
|
||||
void update_counts() {
|
||||
CountClassByCategory counter(this);
|
||||
iterate(&counter);
|
||||
}
|
||||
|
||||
int count_of(bool is_builtin) const {
|
||||
if (is_builtin) {
|
||||
return _builtin_count;
|
||||
} else {
|
||||
return _unregistered_count;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class RunTimeSharedClassInfo {
|
||||
public:
|
||||
struct CrcInfo {
|
||||
int _clsfile_size;
|
||||
int _clsfile_crc32;
|
||||
};
|
||||
|
||||
// This is different than DumpTimeSharedClassInfo::DTConstraint. We use
|
||||
// u4 instead of Symbol* to save space on 64-bit CPU.
|
||||
struct RTConstraint {
|
||||
u4 _name;
|
||||
u4 _from_name;
|
||||
};
|
||||
|
||||
InstanceKlass* _klass;
|
||||
int _num_constraints;
|
||||
|
||||
// optional CrcInfo _crc; (only for UNREGISTERED classes)
|
||||
// optional RTConstraint _verifier_constraints[_num_constraints]
|
||||
// optional char _verifier_constraint_flags[_num_constraints]
|
||||
|
||||
private:
|
||||
static size_t header_size_size() {
|
||||
return sizeof(RunTimeSharedClassInfo);
|
||||
}
|
||||
static size_t crc_size(InstanceKlass* klass) {
|
||||
if (!SystemDictionaryShared::is_builtin(klass)) {
|
||||
return sizeof(CrcInfo);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static size_t verifier_constraints_size(int num_constraints) {
|
||||
return sizeof(RTConstraint) * num_constraints;
|
||||
}
|
||||
static size_t verifier_constraint_flags_size(int num_constraints) {
|
||||
return sizeof(char) * num_constraints;
|
||||
}
|
||||
|
||||
public:
|
||||
static size_t byte_size(InstanceKlass* klass, int num_constraints) {
|
||||
return header_size_size() +
|
||||
crc_size(klass) +
|
||||
verifier_constraints_size(num_constraints) +
|
||||
verifier_constraint_flags_size(num_constraints);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t crc_offset() const {
|
||||
return header_size_size();
|
||||
}
|
||||
size_t verifier_constraints_offset() const {
|
||||
return crc_offset() + crc_size(_klass);
|
||||
}
|
||||
size_t verifier_constraint_flags_offset() const {
|
||||
return verifier_constraints_offset() + verifier_constraints_size(_num_constraints);
|
||||
}
|
||||
|
||||
void check_constraint_offset(int i) const {
|
||||
assert(0 <= i && i < _num_constraints, "sanity");
|
||||
}
|
||||
|
||||
public:
|
||||
CrcInfo* crc() const {
|
||||
assert(crc_size(_klass) > 0, "must be");
|
||||
return (CrcInfo*)(address(this) + crc_offset());
|
||||
}
|
||||
RTConstraint* verifier_constraints() {
|
||||
assert(_num_constraints > 0, "sanity");
|
||||
return (RTConstraint*)(address(this) + verifier_constraints_offset());
|
||||
}
|
||||
RTConstraint* verifier_constraint_at(int i) {
|
||||
check_constraint_offset(i);
|
||||
return verifier_constraints() + i;
|
||||
}
|
||||
|
||||
char* verifier_constraint_flags() {
|
||||
assert(_num_constraints > 0, "sanity");
|
||||
return (char*)(address(this) + verifier_constraint_flags_offset());
|
||||
}
|
||||
|
||||
void init(DumpTimeSharedClassInfo& info) {
|
||||
_klass = info._klass;
|
||||
_num_constraints = info.num_constraints();
|
||||
if (!SystemDictionaryShared::is_builtin(_klass)) {
|
||||
CrcInfo* c = crc();
|
||||
c->_clsfile_size = info._clsfile_size;
|
||||
c->_clsfile_crc32 = info._clsfile_crc32;
|
||||
}
|
||||
if (_num_constraints > 0) {
|
||||
RTConstraint* constraints = verifier_constraints();
|
||||
char* flags = verifier_constraint_flags();
|
||||
int i;
|
||||
for (i = 0; i < _num_constraints; i++) {
|
||||
constraints[i]._name = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._name);
|
||||
constraints[i]._from_name = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._from_name);
|
||||
}
|
||||
for (i = 0; i < _num_constraints; i++) {
|
||||
flags[i] = info._verifier_constraint_flags->at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool matches(int clsfile_size, int clsfile_crc32) const {
|
||||
return crc()->_clsfile_size == clsfile_size &&
|
||||
crc()->_clsfile_crc32 == clsfile_crc32;
|
||||
}
|
||||
|
||||
Symbol* get_constraint_name(int i) {
|
||||
return (Symbol*)(SharedBaseAddress + verifier_constraint_at(i)->_name);
|
||||
}
|
||||
Symbol* get_constraint_from_name(int i) {
|
||||
return (Symbol*)(SharedBaseAddress + verifier_constraint_at(i)->_from_name);
|
||||
}
|
||||
|
||||
char get_constraint_flag(int i) {
|
||||
check_constraint_offset(i);
|
||||
return verifier_constraint_flags()[i];
|
||||
}
|
||||
|
||||
private:
|
||||
// ArchiveCompactor::allocate() has reserved a pointer immediately before
|
||||
// archived InstanceKlasses. We can use this slot to do a quick
|
||||
// lookup of InstanceKlass* -> RunTimeSharedClassInfo* without
|
||||
// building a new hashtable.
|
||||
//
|
||||
// info_pointer_addr(klass) --> 0x0100 RunTimeSharedClassInfo*
|
||||
// InstanceKlass* klass --> 0x0108 <C++ vtbl>
|
||||
// 0x0110 fields from Klass ...
|
||||
static RunTimeSharedClassInfo** info_pointer_addr(InstanceKlass* klass) {
|
||||
return &((RunTimeSharedClassInfo**)klass)[-1];
|
||||
}
|
||||
|
||||
public:
|
||||
static RunTimeSharedClassInfo* get_for(InstanceKlass* klass) {
|
||||
return *info_pointer_addr(klass);
|
||||
}
|
||||
static void set_for(InstanceKlass* klass, RunTimeSharedClassInfo* record) {
|
||||
*info_pointer_addr(klass) = record;
|
||||
}
|
||||
|
||||
// Used by RunTimeSharedDictionary to implement OffsetCompactHashtable::EQUALS
|
||||
static inline bool EQUALS(
|
||||
const RunTimeSharedClassInfo* value, Symbol* key, int len_unused) {
|
||||
return (value->_klass->name() == key);
|
||||
}
|
||||
};
|
||||
|
||||
class RunTimeSharedDictionary : public OffsetCompactHashtable<
|
||||
Symbol*,
|
||||
const RunTimeSharedClassInfo*,
|
||||
RunTimeSharedClassInfo::EQUALS> {};
|
||||
|
||||
static DumpTimeSharedClassTable* _dumptime_table = NULL;
|
||||
static RunTimeSharedDictionary _builtin_dictionary;
|
||||
static RunTimeSharedDictionary _unregistered_dictionary;
|
||||
|
||||
oop SystemDictionaryShared::shared_protection_domain(int index) {
|
||||
return _shared_protection_domains->obj_at(index);
|
||||
@ -478,9 +743,8 @@ InstanceKlass* SystemDictionaryShared::find_or_load_shared_class(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (shared_dictionary() != NULL &&
|
||||
(SystemDictionary::is_system_class_loader(class_loader()) ||
|
||||
SystemDictionary::is_platform_class_loader(class_loader()))) {
|
||||
if (SystemDictionary::is_system_class_loader(class_loader()) ||
|
||||
SystemDictionary::is_platform_class_loader(class_loader())) {
|
||||
// Fix for 4474172; see evaluation for more details
|
||||
class_loader = Handle(
|
||||
THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
|
||||
@ -523,8 +787,7 @@ InstanceKlass* SystemDictionaryShared::find_or_load_shared_class(
|
||||
InstanceKlass* SystemDictionaryShared::load_shared_class_for_builtin_loader(
|
||||
Symbol* class_name, Handle class_loader, TRAPS) {
|
||||
assert(UseSharedSpaces, "must be");
|
||||
assert(shared_dictionary() != NULL, "already checked");
|
||||
InstanceKlass* ik = shared_dictionary()->find_class_for_builtin_loader(class_name);
|
||||
InstanceKlass* ik = find_builtin_class(class_name);
|
||||
|
||||
if (ik != NULL) {
|
||||
if ((ik->is_shared_app_class() &&
|
||||
@ -536,7 +799,6 @@ InstanceKlass* SystemDictionaryShared::load_shared_class_for_builtin_loader(
|
||||
return load_shared_class(ik, class_loader, protection_domain, THREAD);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -574,12 +836,12 @@ void SystemDictionaryShared::allocate_shared_data_arrays(int size, TRAPS) {
|
||||
}
|
||||
|
||||
// This function is called for loading only UNREGISTERED classes
|
||||
InstanceKlass* SystemDictionaryShared::lookup_from_stream(const Symbol* class_name,
|
||||
InstanceKlass* SystemDictionaryShared::lookup_from_stream(Symbol* class_name,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
const ClassFileStream* cfs,
|
||||
TRAPS) {
|
||||
if (shared_dictionary() == NULL) {
|
||||
if (!UseSharedSpaces) {
|
||||
return NULL;
|
||||
}
|
||||
if (class_name == NULL) { // don't do this for anonymous classes
|
||||
@ -592,27 +854,18 @@ InstanceKlass* SystemDictionaryShared::lookup_from_stream(const Symbol* class_na
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader());
|
||||
InstanceKlass* k;
|
||||
|
||||
{ // UNREGISTERED loader
|
||||
if (!shared_dictionary()->class_exists_for_unregistered_loader(class_name)) {
|
||||
// No classes of this name for unregistered loaders.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int clsfile_size = cfs->length();
|
||||
int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
|
||||
|
||||
k = shared_dictionary()->find_class_for_unregistered_loader(class_name,
|
||||
clsfile_size, clsfile_crc32);
|
||||
}
|
||||
|
||||
if (k == NULL) { // not archived
|
||||
const RunTimeSharedClassInfo* record = find_record(&_unregistered_dictionary, class_name);
|
||||
if (record == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return acquire_class_for_current_thread(k, class_loader,
|
||||
int clsfile_size = cfs->length();
|
||||
int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
|
||||
if (!record->matches(clsfile_size, clsfile_crc32)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return acquire_class_for_current_thread(record->_klass, class_loader,
|
||||
protection_domain, THREAD);
|
||||
}
|
||||
|
||||
@ -649,19 +902,27 @@ InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread(
|
||||
return shared_klass;
|
||||
}
|
||||
|
||||
bool SystemDictionaryShared::add_non_builtin_klass(Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
InstanceKlass* k,
|
||||
TRAPS) {
|
||||
assert(DumpSharedSpaces, "only when dumping");
|
||||
assert(boot_loader_dictionary() != NULL, "must be");
|
||||
static ResourceHashtable<
|
||||
Symbol*, bool,
|
||||
primitive_hash<Symbol*>,
|
||||
primitive_equals<Symbol*>,
|
||||
6661, // prime number
|
||||
ResourceObj::C_HEAP> _loaded_unregistered_classes;
|
||||
|
||||
if (boot_loader_dictionary()->add_non_builtin_klass(name, loader_data, k)) {
|
||||
MutexLocker mu_r(Compile_lock, THREAD); // not really necessary, but add_to_hierarchy asserts this.
|
||||
add_to_hierarchy(k, CHECK_0);
|
||||
bool SystemDictionaryShared::add_unregistered_class(InstanceKlass* k, TRAPS) {
|
||||
assert(DumpSharedSpaces, "only when dumping");
|
||||
|
||||
Symbol* name = k->name();
|
||||
if (_loaded_unregistered_classes.get(name) != NULL) {
|
||||
// We don't allow duplicated unregistered classes of the same name.
|
||||
return false;
|
||||
} else {
|
||||
bool isnew = _loaded_unregistered_classes.put(name, true);
|
||||
assert(isnew, "sanity");
|
||||
MutexLocker mu_r(Compile_lock, THREAD); // add_to_hierarchy asserts this.
|
||||
SystemDictionary::add_to_hierarchy(k, CHECK_0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called to resolve the super/interfaces of shared classes for
|
||||
@ -698,81 +959,138 @@ InstanceKlass* SystemDictionaryShared::dump_time_resolve_super_or_fail(
|
||||
}
|
||||
}
|
||||
|
||||
struct SharedMiscInfo {
|
||||
InstanceKlass* _klass;
|
||||
int _clsfile_size;
|
||||
int _clsfile_crc32;
|
||||
};
|
||||
|
||||
static GrowableArray<SharedMiscInfo>* misc_info_array = NULL;
|
||||
DumpTimeSharedClassInfo* SystemDictionaryShared::find_or_allocate_info_for(InstanceKlass* k) {
|
||||
if (_dumptime_table == NULL) {
|
||||
_dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable();
|
||||
}
|
||||
return _dumptime_table->find_or_allocate_info_for(k);
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs) {
|
||||
assert(DumpSharedSpaces, "only when dumping");
|
||||
int clsfile_size = cfs->length();
|
||||
int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
|
||||
|
||||
if (misc_info_array == NULL) {
|
||||
misc_info_array = new (ResourceObj::C_HEAP, mtClass) GrowableArray<SharedMiscInfo>(20, /*c heap*/ true);
|
||||
}
|
||||
|
||||
SharedMiscInfo misc_info;
|
||||
DEBUG_ONLY({
|
||||
for (int i=0; i<misc_info_array->length(); i++) {
|
||||
misc_info = misc_info_array->at(i);
|
||||
assert(misc_info._klass != k, "cannot call set_shared_class_misc_info twice for the same class");
|
||||
}
|
||||
});
|
||||
|
||||
misc_info._klass = k;
|
||||
misc_info._clsfile_size = clsfile_size;
|
||||
misc_info._clsfile_crc32 = clsfile_crc32;
|
||||
|
||||
misc_info_array->append(misc_info);
|
||||
assert(!is_builtin(k), "must be unregistered class");
|
||||
DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
|
||||
info->_clsfile_size = cfs->length();
|
||||
info->_clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::init_shared_dictionary_entry(InstanceKlass* k, DictionaryEntry* ent) {
|
||||
SharedDictionaryEntry* entry = (SharedDictionaryEntry*)ent;
|
||||
entry->_id = -1;
|
||||
entry->_clsfile_size = -1;
|
||||
entry->_clsfile_crc32 = -1;
|
||||
entry->_verifier_constraints = NULL;
|
||||
entry->_verifier_constraint_flags = NULL;
|
||||
void SystemDictionaryShared::init_dumptime_info(InstanceKlass* k) {
|
||||
(void)find_or_allocate_info_for(k);
|
||||
}
|
||||
|
||||
if (misc_info_array != NULL) {
|
||||
for (int i=0; i<misc_info_array->length(); i++) {
|
||||
SharedMiscInfo misc_info = misc_info_array->at(i);
|
||||
if (misc_info._klass == k) {
|
||||
entry->_clsfile_size = misc_info._clsfile_size;
|
||||
entry->_clsfile_crc32 = misc_info._clsfile_crc32;
|
||||
misc_info_array->remove_at(i);
|
||||
return;
|
||||
}
|
||||
void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) {
|
||||
_dumptime_table->remove(k);
|
||||
}
|
||||
|
||||
bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) {
|
||||
while (k) {
|
||||
if (k->name()->equals("jdk/internal/event/Event")) {
|
||||
return true;
|
||||
}
|
||||
k = k->java_super();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) {
|
||||
ResourceMark rm;
|
||||
log_warning(cds)("Skipping %s: %s", k->name()->as_C_string(), reason);
|
||||
}
|
||||
|
||||
bool SystemDictionaryShared::should_be_excluded(InstanceKlass* k) {
|
||||
if (k->class_loader_data()->is_unsafe_anonymous()) {
|
||||
return true; // unsafe anonymous classes are not archived, skip
|
||||
}
|
||||
if (k->is_in_error_state()) {
|
||||
return true;
|
||||
}
|
||||
if (k->shared_classpath_index() < 0 && is_builtin(k)) {
|
||||
// These are classes loaded from unsupported locations (such as those loaded by JVMTI native
|
||||
// agent during dump time).
|
||||
warn_excluded(k, "Unsupported location");
|
||||
return true;
|
||||
}
|
||||
if (k->signers() != NULL) {
|
||||
// We cannot include signed classes in the archive because the certificates
|
||||
// used during dump time may be different than those used during
|
||||
// runtime (due to expiration, etc).
|
||||
warn_excluded(k, "Signed JAR");
|
||||
return true;
|
||||
}
|
||||
if (is_jfr_event_class(k)) {
|
||||
// We cannot include JFR event classes because they need runtime-specific
|
||||
// instrumentation in order to work with -XX:FlightRecorderOptions=retransform=false.
|
||||
// There are only a small number of these classes, so it's not worthwhile to
|
||||
// support them and make CDS more complicated.
|
||||
warn_excluded(k, "JFR event class");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// k is a class before relocating by ArchiveCompactor
|
||||
void SystemDictionaryShared::validate_before_archiving(InstanceKlass* k) {
|
||||
ResourceMark rm;
|
||||
const char* name = k->name()->as_C_string();
|
||||
DumpTimeSharedClassInfo* info = _dumptime_table->get(k);
|
||||
guarantee(info != NULL, "Class %s must be entered into _dumptime_table", name);
|
||||
guarantee(!info->_excluded, "Should not attempt to archive excluded class %s", name);
|
||||
if (is_builtin(k)) {
|
||||
guarantee(k->loader_type() != 0,
|
||||
"Class loader type must be set for BUILTIN class %s", name);
|
||||
} else {
|
||||
guarantee(k->loader_type() == 0,
|
||||
"Class loader type must not be set for UNREGISTERED class %s", name);
|
||||
}
|
||||
}
|
||||
|
||||
class ExcludeDumpTimeSharedClasses : StackObj {
|
||||
public:
|
||||
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
|
||||
if (SystemDictionaryShared::should_be_excluded(k)) {
|
||||
info._excluded = true;
|
||||
}
|
||||
return true; // keep on iterating
|
||||
}
|
||||
};
|
||||
|
||||
void SystemDictionaryShared::check_excluded_classes() {
|
||||
ExcludeDumpTimeSharedClasses excl;
|
||||
_dumptime_table->iterate(&excl);
|
||||
DEBUG_ONLY(_checked_excluded_classes = true;)
|
||||
}
|
||||
|
||||
bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) {
|
||||
assert(_checked_excluded_classes, "sanity");
|
||||
assert(DumpSharedSpaces, "only when dumping");
|
||||
return find_or_allocate_info_for(k)->_excluded;
|
||||
}
|
||||
|
||||
class IterateDumpTimeSharedClassTable : StackObj {
|
||||
MetaspaceClosure *_it;
|
||||
public:
|
||||
IterateDumpTimeSharedClassTable(MetaspaceClosure* it) : _it(it) {}
|
||||
|
||||
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
|
||||
if (!info._excluded) {
|
||||
info.metaspace_pointers_do(_it);
|
||||
}
|
||||
return true; // keep on iterating
|
||||
}
|
||||
};
|
||||
|
||||
void SystemDictionaryShared::dumptime_classes_do(class MetaspaceClosure* it) {
|
||||
IterateDumpTimeSharedClassTable iter(it);
|
||||
_dumptime_table->iterate(&iter);
|
||||
}
|
||||
|
||||
bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbol* name,
|
||||
Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
|
||||
assert(DumpSharedSpaces, "called at dump time only");
|
||||
|
||||
// Skip unsafe anonymous classes, which are not archived as they are not in
|
||||
// dictionary (see assert_no_unsafe_anonymous_classes_in_dictionaries() in
|
||||
// VM_PopulateDumpSharedSpace::doit()).
|
||||
if (k->class_loader_data()->is_unsafe_anonymous()) {
|
||||
return true; // unsafe anonymous classes are not archived, skip
|
||||
}
|
||||
|
||||
SharedDictionaryEntry* entry = ((SharedDictionary*)(k->class_loader_data()->dictionary()))->find_entry_for(k);
|
||||
ResourceMark rm;
|
||||
// Lambda classes are not archived and will be regenerated at runtime.
|
||||
if (entry == NULL) {
|
||||
guarantee(strstr(k->name()->as_C_string(), "Lambda$") != NULL,
|
||||
"class should be in dictionary before being verified");
|
||||
return true;
|
||||
}
|
||||
entry->add_verification_constraint(name, from_name, from_field_is_protected,
|
||||
from_is_array, from_is_object);
|
||||
if (entry->is_builtin()) {
|
||||
DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
|
||||
info->add_verification_constraint(k, name, from_name, from_field_is_protected,
|
||||
from_is_array, from_is_object);
|
||||
if (is_builtin(k)) {
|
||||
// For builtin class loaders, we can try to complete the verification check at dump time,
|
||||
// because we can resolve all the constraint classes.
|
||||
return false;
|
||||
@ -783,135 +1101,54 @@ bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbo
|
||||
}
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::finalize_verification_constraints_for(InstanceKlass* k) {
|
||||
if (!k->is_unsafe_anonymous()) {
|
||||
SharedDictionaryEntry* entry = ((SharedDictionary*)(k->class_loader_data()->dictionary()))->find_entry_for(k);
|
||||
entry->finalize_verification_constraints();
|
||||
}
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::finalize_verification_constraints() {
|
||||
MutexLocker mcld(ClassLoaderDataGraph_lock);
|
||||
ClassLoaderDataGraph::dictionary_classes_do(finalize_verification_constraints_for);
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass,
|
||||
TRAPS) {
|
||||
assert(!DumpSharedSpaces && UseSharedSpaces, "called at run time with CDS enabled only");
|
||||
SharedDictionaryEntry* entry = shared_dictionary()->find_entry_for(klass);
|
||||
assert(entry != NULL, "call this only for shared classes");
|
||||
entry->check_verification_constraints(klass, THREAD);
|
||||
}
|
||||
|
||||
SharedDictionaryEntry* SharedDictionary::find_entry_for(InstanceKlass* klass) {
|
||||
Symbol* class_name = klass->name();
|
||||
unsigned int hash = compute_hash(class_name);
|
||||
int index = hash_to_index(hash);
|
||||
|
||||
for (SharedDictionaryEntry* entry = bucket(index);
|
||||
entry != NULL;
|
||||
entry = entry->next()) {
|
||||
if (entry->hash() == hash && entry->literal() == klass) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SharedDictionaryEntry::add_verification_constraint(Symbol* name,
|
||||
void DumpTimeSharedClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* name,
|
||||
Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
|
||||
if (_verifier_constraints == NULL) {
|
||||
_verifier_constraints = new(ResourceObj::C_HEAP, mtClass) GrowableArray<Symbol*>(8, true, mtClass);
|
||||
_verifier_constraints = new(ResourceObj::C_HEAP, mtClass) GrowableArray<DTConstraint>(4, true, mtClass);
|
||||
}
|
||||
if (_verifier_constraint_flags == NULL) {
|
||||
_verifier_constraint_flags = new(ResourceObj::C_HEAP, mtClass) GrowableArray<char>(4, true, mtClass);
|
||||
}
|
||||
GrowableArray<Symbol*>* vc_array = (GrowableArray<Symbol*>*)_verifier_constraints;
|
||||
for (int i=0; i<vc_array->length(); i+= 2) {
|
||||
if (name == vc_array->at(i) &&
|
||||
from_name == vc_array->at(i+1)) {
|
||||
GrowableArray<DTConstraint>* vc_array = _verifier_constraints;
|
||||
for (int i = 0; i < vc_array->length(); i++) {
|
||||
DTConstraint* p = vc_array->adr_at(i);
|
||||
if (name == p->_name && from_name == p->_from_name) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
vc_array->append(name);
|
||||
vc_array->append(from_name);
|
||||
DTConstraint cons(name, from_name);
|
||||
vc_array->append(cons);
|
||||
|
||||
GrowableArray<char>* vcflags_array = (GrowableArray<char>*)_verifier_constraint_flags;
|
||||
GrowableArray<char>* vcflags_array = _verifier_constraint_flags;
|
||||
char c = 0;
|
||||
c |= from_field_is_protected ? FROM_FIELD_IS_PROTECTED : 0;
|
||||
c |= from_is_array ? FROM_IS_ARRAY : 0;
|
||||
c |= from_is_object ? FROM_IS_OBJECT : 0;
|
||||
c |= from_field_is_protected ? SystemDictionaryShared::FROM_FIELD_IS_PROTECTED : 0;
|
||||
c |= from_is_array ? SystemDictionaryShared::FROM_IS_ARRAY : 0;
|
||||
c |= from_is_object ? SystemDictionaryShared::FROM_IS_OBJECT : 0;
|
||||
vcflags_array->append(c);
|
||||
|
||||
if (log_is_enabled(Trace, cds, verification)) {
|
||||
ResourceMark rm;
|
||||
log_trace(cds, verification)("add_verification_constraint: %s: %s must be subclass of %s",
|
||||
instance_klass()->external_name(), from_name->as_klass_external_name(),
|
||||
k->external_name(), from_name->as_klass_external_name(),
|
||||
name->as_klass_external_name());
|
||||
}
|
||||
}
|
||||
|
||||
int SharedDictionaryEntry::finalize_verification_constraints() {
|
||||
assert(DumpSharedSpaces, "called at dump time only");
|
||||
Thread* THREAD = Thread::current();
|
||||
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
|
||||
GrowableArray<Symbol*>* vc_array = (GrowableArray<Symbol*>*)_verifier_constraints;
|
||||
GrowableArray<char>* vcflags_array = (GrowableArray<char>*)_verifier_constraint_flags;
|
||||
void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass,
|
||||
TRAPS) {
|
||||
assert(!DumpSharedSpaces && UseSharedSpaces, "called at run time with CDS enabled only");
|
||||
RunTimeSharedClassInfo* record = RunTimeSharedClassInfo::get_for(klass);
|
||||
|
||||
if (vc_array != NULL) {
|
||||
if (log_is_enabled(Trace, cds, verification)) {
|
||||
ResourceMark rm;
|
||||
log_trace(cds, verification)("finalize_verification_constraint: %s",
|
||||
literal()->external_name());
|
||||
}
|
||||
int length = record->_num_constraints;
|
||||
if (length > 0) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
Symbol* name = record->get_constraint_name(i);
|
||||
Symbol* from_name = record->get_constraint_from_name(i);
|
||||
char c = record->get_constraint_flag(i);
|
||||
|
||||
// Copy the constraints from C_HEAP-alloced GrowableArrays to Metaspace-alloced
|
||||
// Arrays
|
||||
int size = 0;
|
||||
{
|
||||
// FIXME: change this to be done after relocation, so we can use symbol offset??
|
||||
int length = vc_array->length();
|
||||
Array<Symbol*>* out = MetadataFactory::new_array<Symbol*>(loader_data, length, 0, THREAD);
|
||||
assert(out != NULL, "Dump time allocation failure would have aborted VM");
|
||||
for (int i=0; i<length; i++) {
|
||||
out->at_put(i, vc_array->at(i));
|
||||
}
|
||||
_verifier_constraints = out;
|
||||
size += out->size() * BytesPerWord;
|
||||
delete vc_array;
|
||||
}
|
||||
{
|
||||
int length = vcflags_array->length();
|
||||
Array<char>* out = MetadataFactory::new_array<char>(loader_data, length, 0, THREAD);
|
||||
assert(out != NULL, "Dump time allocation failure would have aborted VM");
|
||||
for (int i=0; i<length; i++) {
|
||||
out->at_put(i, vcflags_array->at(i));
|
||||
}
|
||||
_verifier_constraint_flags = out;
|
||||
size += out->size() * BytesPerWord;
|
||||
delete vcflags_array;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SharedDictionaryEntry::check_verification_constraints(InstanceKlass* klass, TRAPS) {
|
||||
Array<Symbol*>* vc_array = (Array<Symbol*>*)_verifier_constraints;
|
||||
Array<char>* vcflags_array = (Array<char>*)_verifier_constraint_flags;
|
||||
|
||||
if (vc_array != NULL) {
|
||||
int length = vc_array->length();
|
||||
for (int i=0; i<length; i+=2) {
|
||||
Symbol* name = vc_array->at(i);
|
||||
Symbol* from_name = vc_array->at(i+1);
|
||||
char c = vcflags_array->at(i/2);
|
||||
|
||||
bool from_field_is_protected = (c & FROM_FIELD_IS_PROTECTED) ? true : false;
|
||||
bool from_is_array = (c & FROM_IS_ARRAY) ? true : false;
|
||||
bool from_is_object = (c & FROM_IS_OBJECT) ? true : false;
|
||||
bool from_field_is_protected = (c & SystemDictionaryShared::FROM_FIELD_IS_PROTECTED) ? true : false;
|
||||
bool from_is_array = (c & SystemDictionaryShared::FROM_IS_ARRAY) ? true : false;
|
||||
bool from_is_object = (c & SystemDictionaryShared::FROM_IS_OBJECT) ? true : false;
|
||||
|
||||
bool ok = VerificationType::resolve_and_check_assignability(klass, name,
|
||||
from_name, from_field_is_protected, from_is_array, from_is_object, CHECK);
|
||||
@ -930,132 +1167,100 @@ void SharedDictionaryEntry::check_verification_constraints(InstanceKlass* klass,
|
||||
}
|
||||
}
|
||||
|
||||
void SharedDictionaryEntry::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
it->push((Array<Symbol*>**)&_verifier_constraints);
|
||||
it->push((Array<char>**)&_verifier_constraint_flags);
|
||||
class CopySharedClassInfoToArchive : StackObj {
|
||||
CompactHashtableWriter* _writer;
|
||||
bool _is_builtin;
|
||||
public:
|
||||
CopySharedClassInfoToArchive(CompactHashtableWriter* writer, bool is_builtin)
|
||||
: _writer(writer), _is_builtin(is_builtin) {}
|
||||
|
||||
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
|
||||
if (!info._excluded && info.is_builtin() == _is_builtin) {
|
||||
size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_constraints());
|
||||
RunTimeSharedClassInfo* record =
|
||||
(RunTimeSharedClassInfo*)MetaspaceShared::read_only_space_alloc(byte_size);
|
||||
record->init(info);
|
||||
|
||||
unsigned int hash = primitive_hash<Symbol*>(info._klass->name());
|
||||
_writer->add(hash, MetaspaceShared::object_delta_u4(record));
|
||||
|
||||
// Save this for quick runtime lookup of InstanceKlass* -> RunTimeSharedClassInfo*
|
||||
RunTimeSharedClassInfo::set_for(info._klass, record);
|
||||
}
|
||||
return true; // keep on iterating
|
||||
}
|
||||
};
|
||||
|
||||
void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin) {
|
||||
CompactHashtableStats stats;
|
||||
dictionary->reset();
|
||||
int num_buckets = CompactHashtableWriter::default_num_buckets(_dumptime_table->count_of(is_builtin));
|
||||
CompactHashtableWriter writer(num_buckets, &stats);
|
||||
CopySharedClassInfoToArchive copy(&writer, is_builtin);
|
||||
_dumptime_table->iterate(©);
|
||||
writer.dump(dictionary, is_builtin ? "builtin dictionary" : "unregistered dictionary");
|
||||
}
|
||||
|
||||
bool SharedDictionary::add_non_builtin_klass(const Symbol* class_name,
|
||||
ClassLoaderData* loader_data,
|
||||
InstanceKlass* klass) {
|
||||
void SystemDictionaryShared::write_to_archive() {
|
||||
_dumptime_table->update_counts();
|
||||
write_dictionary(&_builtin_dictionary, true);
|
||||
write_dictionary(&_unregistered_dictionary, false);
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::serialize_dictionary_headers(SerializeClosure* soc) {
|
||||
_builtin_dictionary.serialize_header(soc);
|
||||
_unregistered_dictionary.serialize_header(soc);
|
||||
}
|
||||
|
||||
const RunTimeSharedClassInfo*
|
||||
SystemDictionaryShared::find_record(RunTimeSharedDictionary* dict, Symbol* name) {
|
||||
if (UseSharedSpaces) {
|
||||
unsigned int hash = primitive_hash<Symbol*>(name);
|
||||
return dict->lookup(name, hash, 0);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
InstanceKlass* SystemDictionaryShared::find_builtin_class(Symbol* name) {
|
||||
const RunTimeSharedClassInfo* record = find_record(&_builtin_dictionary, name);
|
||||
if (record) {
|
||||
return record->_klass;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) {
|
||||
assert(DumpSharedSpaces, "supported only when dumping");
|
||||
assert(klass != NULL, "adding NULL klass");
|
||||
assert(klass->name() == class_name, "sanity check on name");
|
||||
assert(klass->shared_classpath_index() < 0,
|
||||
"the shared classpath index should not be set for shared class loaded by the custom loaders");
|
||||
DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
|
||||
info->_id = id;
|
||||
}
|
||||
|
||||
// Add an entry for a non-builtin class.
|
||||
// For a shared class for custom class loaders, SystemDictionary::resolve_or_null will
|
||||
// not find this class, because is_builtin() is false.
|
||||
unsigned int hash = compute_hash(class_name);
|
||||
int index = hash_to_index(hash);
|
||||
class SharedDictionaryPrinter : StackObj {
|
||||
outputStream* _st;
|
||||
int _index;
|
||||
public:
|
||||
SharedDictionaryPrinter(outputStream* st) : _st(st), _index(0) {}
|
||||
|
||||
for (SharedDictionaryEntry* entry = bucket(index);
|
||||
entry != NULL;
|
||||
entry = entry->next()) {
|
||||
if (entry->hash() == hash) {
|
||||
InstanceKlass* klass = entry->instance_klass();
|
||||
if (klass->name() == class_name && klass->class_loader_data() == loader_data) {
|
||||
// There is already a class defined with the same name
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void do_value(const RunTimeSharedClassInfo* record) {
|
||||
ResourceMark rm;
|
||||
_st->print_cr("%4d: %s", (_index++), record->_klass->external_name());
|
||||
}
|
||||
};
|
||||
|
||||
assert(Dictionary::entry_size() >= sizeof(SharedDictionaryEntry), "must be big enough");
|
||||
SharedDictionaryEntry* entry = (SharedDictionaryEntry*)new_entry(hash, klass);
|
||||
add_entry(index, entry);
|
||||
|
||||
assert(entry->is_unregistered(), "sanity");
|
||||
assert(!entry->is_builtin(), "sanity");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------
|
||||
// SharedDictionary
|
||||
//-----------------
|
||||
|
||||
|
||||
InstanceKlass* SharedDictionary::find_class_for_builtin_loader(const Symbol* name) const {
|
||||
SharedDictionaryEntry* entry = get_entry_for_builtin_loader(name);
|
||||
return entry != NULL ? entry->instance_klass() : (InstanceKlass*)NULL;
|
||||
}
|
||||
|
||||
InstanceKlass* SharedDictionary::find_class_for_unregistered_loader(const Symbol* name,
|
||||
int clsfile_size,
|
||||
int clsfile_crc32) const {
|
||||
|
||||
const SharedDictionaryEntry* entry = get_entry_for_unregistered_loader(name,
|
||||
clsfile_size,
|
||||
clsfile_crc32);
|
||||
return entry != NULL ? entry->instance_klass() : NULL;
|
||||
}
|
||||
|
||||
void SharedDictionary::update_entry(InstanceKlass* klass, int id) {
|
||||
assert(DumpSharedSpaces, "supported only when dumping");
|
||||
Symbol* class_name = klass->name();
|
||||
unsigned int hash = compute_hash(class_name);
|
||||
int index = hash_to_index(hash);
|
||||
|
||||
for (SharedDictionaryEntry* entry = bucket(index);
|
||||
entry != NULL;
|
||||
entry = entry->next()) {
|
||||
if (entry->hash() == hash && entry->literal() == klass) {
|
||||
entry->_id = id;
|
||||
return;
|
||||
}
|
||||
void SystemDictionaryShared::print_on(outputStream* st) {
|
||||
if (UseSharedSpaces) {
|
||||
st->print_cr("Shared Dictionary");
|
||||
SharedDictionaryPrinter p(st);
|
||||
_builtin_dictionary.iterate(&p);
|
||||
_unregistered_dictionary.iterate(&p);
|
||||
}
|
||||
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
SharedDictionaryEntry* SharedDictionary::get_entry_for_builtin_loader(const Symbol* class_name) const {
|
||||
assert(!DumpSharedSpaces, "supported only when at runtime");
|
||||
unsigned int hash = compute_hash(class_name);
|
||||
const int index = hash_to_index(hash);
|
||||
|
||||
for (SharedDictionaryEntry* entry = bucket(index);
|
||||
entry != NULL;
|
||||
entry = entry->next()) {
|
||||
if (entry->hash() == hash && entry->equals(class_name)) {
|
||||
if (entry->is_builtin()) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
void SystemDictionaryShared::print_table_statistics(outputStream* st) {
|
||||
if (UseSharedSpaces) {
|
||||
_builtin_dictionary.print_table_statistics(st, "Builtin Shared Dictionary");
|
||||
_unregistered_dictionary.print_table_statistics(st, "Unregistered Shared Dictionary");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SharedDictionaryEntry* SharedDictionary::get_entry_for_unregistered_loader(const Symbol* class_name,
|
||||
int clsfile_size,
|
||||
int clsfile_crc32) const {
|
||||
assert(!DumpSharedSpaces, "supported only when at runtime");
|
||||
unsigned int hash = compute_hash(class_name);
|
||||
int index = hash_to_index(hash);
|
||||
|
||||
for (SharedDictionaryEntry* entry = bucket(index);
|
||||
entry != NULL;
|
||||
entry = entry->next()) {
|
||||
if (entry->hash() == hash && entry->equals(class_name)) {
|
||||
if (entry->is_unregistered()) {
|
||||
if (clsfile_size == -1) {
|
||||
// We're called from class_exists_for_unregistered_loader. At run time, we want to
|
||||
// compute the CRC of a ClassFileStream only if there is an UNREGISTERED class
|
||||
// with the matching name.
|
||||
return entry;
|
||||
} else {
|
||||
// We're called from find_class_for_unregistered_loader
|
||||
if (entry->_clsfile_size && clsfile_crc32 == entry->_clsfile_crc32) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
// There can be only 1 class with this name for unregistered loaders.
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -36,13 +36,12 @@
|
||||
Handling of the classes in the AppCDS archive
|
||||
|
||||
To ensure safety and to simplify the implementation, archived classes are
|
||||
"segregated" into several types. The following rules describe how they
|
||||
"segregated" into 2 types. The following rules describe how they
|
||||
are stored and looked up.
|
||||
|
||||
[1] Category of archived classes
|
||||
|
||||
There are 3 disjoint groups of classes stored in the AppCDS archive. They are
|
||||
categorized as by their SharedDictionaryEntry::loader_type()
|
||||
There are 2 disjoint groups of classes stored in the AppCDS archive:
|
||||
|
||||
BUILTIN: These classes may be defined ONLY by the BOOT/PLATFORM/APP
|
||||
loaders.
|
||||
@ -83,112 +82,39 @@
|
||||
Bar id: 3 super: 0 interfaces: 1 source: /foo.jar
|
||||
|
||||
|
||||
[3] Identifying the loader_type of archived classes in the shared dictionary
|
||||
|
||||
Each archived Klass* C is associated with a SharedDictionaryEntry* E
|
||||
[3] Identifying the category of archived classes
|
||||
|
||||
BUILTIN: (C->shared_classpath_index() >= 0)
|
||||
UNREGISTERED: (C->shared_classpath_index() < 0)
|
||||
UNREGISTERED: (C->shared_classpath_index() == UNREGISTERED_INDEX (-9999))
|
||||
|
||||
[4] Lookup of archived classes at run time:
|
||||
|
||||
(a) BUILTIN loaders:
|
||||
|
||||
Search the shared directory for a BUILTIN class with a matching name.
|
||||
search _builtin_dictionary
|
||||
|
||||
(b) UNREGISTERED loaders:
|
||||
|
||||
The search originates with SystemDictionaryShared::lookup_from_stream().
|
||||
|
||||
Search the shared directory for a UNREGISTERED class with a matching
|
||||
(name, clsfile_len, clsfile_crc32) tuple.
|
||||
search _unregistered_dictionary for an entry that matches the
|
||||
(name, clsfile_len, clsfile_crc32).
|
||||
|
||||
===============================================================================*/
|
||||
#define UNREGISTERED_INDEX -9999
|
||||
|
||||
class ClassFileStream;
|
||||
class DumpTimeSharedClassInfo;
|
||||
class DumpTimeSharedClassTable;
|
||||
class RunTimeSharedClassInfo;
|
||||
class RunTimeSharedDictionary;
|
||||
|
||||
// Archived classes need extra information not needed by traditionally loaded classes.
|
||||
// To keep footprint small, we add these in the dictionary entry instead of the InstanceKlass.
|
||||
class SharedDictionaryEntry : public DictionaryEntry {
|
||||
|
||||
class SystemDictionaryShared: public SystemDictionary {
|
||||
public:
|
||||
enum LoaderType {
|
||||
LT_BUILTIN,
|
||||
LT_UNREGISTERED
|
||||
};
|
||||
|
||||
enum {
|
||||
FROM_FIELD_IS_PROTECTED = 1 << 0,
|
||||
FROM_IS_ARRAY = 1 << 1,
|
||||
FROM_IS_OBJECT = 1 << 2
|
||||
};
|
||||
|
||||
int _id;
|
||||
int _clsfile_size;
|
||||
int _clsfile_crc32;
|
||||
void* _verifier_constraints; // FIXME - use a union here to avoid type casting??
|
||||
void* _verifier_constraint_flags;
|
||||
|
||||
// See "Identifying the loader_type of archived classes" comments above.
|
||||
LoaderType loader_type() const {
|
||||
InstanceKlass* k = instance_klass();
|
||||
|
||||
if ((k->shared_classpath_index() != UNREGISTERED_INDEX)) {
|
||||
return LT_BUILTIN;
|
||||
} else {
|
||||
return LT_UNREGISTERED;
|
||||
}
|
||||
}
|
||||
|
||||
SharedDictionaryEntry* next() {
|
||||
return (SharedDictionaryEntry*)(DictionaryEntry::next());
|
||||
}
|
||||
|
||||
bool is_builtin() const {
|
||||
return loader_type() == LT_BUILTIN;
|
||||
}
|
||||
bool is_unregistered() const {
|
||||
return loader_type() == LT_UNREGISTERED;
|
||||
}
|
||||
|
||||
void add_verification_constraint(Symbol* name,
|
||||
Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object);
|
||||
int finalize_verification_constraints();
|
||||
void check_verification_constraints(InstanceKlass* klass, TRAPS);
|
||||
void metaspace_pointers_do(MetaspaceClosure* it) NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
class SharedDictionary : public Dictionary {
|
||||
SharedDictionaryEntry* get_entry_for_builtin_loader(const Symbol* name) const;
|
||||
SharedDictionaryEntry* get_entry_for_unregistered_loader(const Symbol* name,
|
||||
int clsfile_size,
|
||||
int clsfile_crc32) const;
|
||||
|
||||
// Convenience functions
|
||||
SharedDictionaryEntry* bucket(int index) const {
|
||||
return (SharedDictionaryEntry*)(Dictionary::bucket(index));
|
||||
}
|
||||
|
||||
public:
|
||||
SharedDictionaryEntry* find_entry_for(InstanceKlass* klass);
|
||||
|
||||
bool add_non_builtin_klass(const Symbol* class_name,
|
||||
ClassLoaderData* loader_data,
|
||||
InstanceKlass* obj);
|
||||
|
||||
void update_entry(InstanceKlass* klass, int id);
|
||||
|
||||
InstanceKlass* find_class_for_builtin_loader(const Symbol* name) const;
|
||||
InstanceKlass* find_class_for_unregistered_loader(const Symbol* name,
|
||||
int clsfile_size,
|
||||
int clsfile_crc32) const;
|
||||
bool class_exists_for_unregistered_loader(const Symbol* name) {
|
||||
return (get_entry_for_unregistered_loader(name, -1, -1) != NULL);
|
||||
}
|
||||
};
|
||||
|
||||
class SystemDictionaryShared: public SystemDictionary {
|
||||
private:
|
||||
// These _shared_xxxs arrays are used to initialize the java.lang.Package and
|
||||
// java.security.ProtectionDomain objects associated with each shared class.
|
||||
@ -282,8 +208,17 @@ private:
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
TRAPS);
|
||||
static void finalize_verification_constraints_for(InstanceKlass* k);
|
||||
static DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k);
|
||||
static void write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin);
|
||||
static bool is_jfr_event_class(InstanceKlass *k);
|
||||
static void warn_excluded(InstanceKlass* k, const char* reason);
|
||||
|
||||
DEBUG_ONLY(static bool _checked_excluded_classes;)
|
||||
public:
|
||||
static InstanceKlass* find_builtin_class(Symbol* class_name);
|
||||
|
||||
static const RunTimeSharedClassInfo* find_record(RunTimeSharedDictionary* dict, Symbol* name);
|
||||
|
||||
// Called by PLATFORM/APP loader only
|
||||
static InstanceKlass* find_or_load_shared_class(Symbol* class_name,
|
||||
Handle class_loader,
|
||||
@ -311,8 +246,7 @@ public:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool add_non_builtin_klass(Symbol* class_name, ClassLoaderData* loader_data,
|
||||
InstanceKlass* k, TRAPS);
|
||||
static bool add_unregistered_class(InstanceKlass* k, TRAPS);
|
||||
static InstanceKlass* dump_time_resolve_super_or_fail(Symbol* child_name,
|
||||
Symbol* class_name,
|
||||
Handle class_loader,
|
||||
@ -320,36 +254,17 @@ public:
|
||||
bool is_superclass,
|
||||
TRAPS);
|
||||
|
||||
static size_t dictionary_entry_size() {
|
||||
return (DumpSharedSpaces) ? sizeof(SharedDictionaryEntry) : sizeof(DictionaryEntry);
|
||||
}
|
||||
static void init_shared_dictionary_entry(InstanceKlass* k, DictionaryEntry* entry) NOT_CDS_RETURN;
|
||||
static bool is_builtin(DictionaryEntry* ent) {
|
||||
// Can't use virtual function is_builtin because DictionaryEntry doesn't initialize
|
||||
// vtable because it's not constructed properly.
|
||||
SharedDictionaryEntry* entry = (SharedDictionaryEntry*)ent;
|
||||
return entry->is_builtin();
|
||||
}
|
||||
|
||||
// For convenient access to the SharedDictionaryEntry's of the archived classes.
|
||||
static SharedDictionary* shared_dictionary() {
|
||||
assert(!DumpSharedSpaces, "not for dumping");
|
||||
return (SharedDictionary*)SystemDictionary::shared_dictionary();
|
||||
}
|
||||
|
||||
static SharedDictionary* boot_loader_dictionary() {
|
||||
return (SharedDictionary*)ClassLoaderData::the_null_class_loader_data()->dictionary();
|
||||
}
|
||||
|
||||
static void update_shared_entry(InstanceKlass* klass, int id) {
|
||||
assert(DumpSharedSpaces, "sanity");
|
||||
assert((SharedDictionary*)(klass->class_loader_data()->dictionary()) != NULL, "sanity");
|
||||
((SharedDictionary*)(klass->class_loader_data()->dictionary()))->update_entry(klass, id);
|
||||
static void init_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN;
|
||||
static void remove_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN;
|
||||
|
||||
static Dictionary* boot_loader_dictionary() {
|
||||
return ClassLoaderData::the_null_class_loader_data()->dictionary();
|
||||
}
|
||||
|
||||
static void update_shared_entry(InstanceKlass* klass, int id);
|
||||
static void set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs);
|
||||
|
||||
static InstanceKlass* lookup_from_stream(const Symbol* class_name,
|
||||
static InstanceKlass* lookup_from_stream(Symbol* class_name,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
const ClassFileStream* st,
|
||||
@ -366,9 +281,23 @@ public:
|
||||
static bool add_verification_constraint(InstanceKlass* k, Symbol* name,
|
||||
Symbol* from_name, bool from_field_is_protected,
|
||||
bool from_is_array, bool from_is_object) NOT_CDS_RETURN_(false);
|
||||
static void finalize_verification_constraints() NOT_CDS_RETURN;
|
||||
static void check_verification_constraints(InstanceKlass* klass,
|
||||
TRAPS) NOT_CDS_RETURN;
|
||||
TRAPS) NOT_CDS_RETURN;
|
||||
static bool is_builtin(InstanceKlass* k) {
|
||||
return (k->shared_classpath_index() != UNREGISTERED_INDEX);
|
||||
}
|
||||
static bool should_be_excluded(InstanceKlass* k);
|
||||
static void check_excluded_classes();
|
||||
static void validate_before_archiving(InstanceKlass* k);
|
||||
static bool is_excluded_class(InstanceKlass* k);
|
||||
static void dumptime_classes_do(class MetaspaceClosure* it);
|
||||
static void write_to_archive();
|
||||
static void serialize_dictionary_headers(class SerializeClosure* soc);
|
||||
static void print() { return print_on(tty); }
|
||||
static void print_on(outputStream* st) NOT_CDS_RETURN;
|
||||
static void print_table_statistics(outputStream* st) NOT_CDS_RETURN;
|
||||
|
||||
DEBUG_ONLY(static bool checked_excluded_classes() {return _checked_excluded_classes;})
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP
|
||||
|
@ -393,6 +393,10 @@ class BufferBlob: public RuntimeBlob {
|
||||
BufferBlob(const char* name, int size);
|
||||
BufferBlob(const char* name, int size, CodeBuffer* cb);
|
||||
|
||||
// This ordinary operator delete is needed even though not used, so the
|
||||
// below two-argument operator delete will be treated as a placement
|
||||
// delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2.
|
||||
void operator delete(void* p);
|
||||
void* operator new(size_t s, unsigned size) throw();
|
||||
|
||||
public:
|
||||
@ -476,6 +480,10 @@ class RuntimeStub: public RuntimeBlob {
|
||||
bool caller_must_gc_arguments
|
||||
);
|
||||
|
||||
// This ordinary operator delete is needed even though not used, so the
|
||||
// below two-argument operator delete will be treated as a placement
|
||||
// delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2.
|
||||
void operator delete(void* p);
|
||||
void* operator new(size_t s, unsigned size) throw();
|
||||
|
||||
public:
|
||||
@ -511,6 +519,10 @@ class SingletonBlob: public RuntimeBlob {
|
||||
friend class VMStructs;
|
||||
|
||||
protected:
|
||||
// This ordinary operator delete is needed even though not used, so the
|
||||
// below two-argument operator delete will be treated as a placement
|
||||
// delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2.
|
||||
void operator delete(void* p);
|
||||
void* operator new(size_t s, unsigned size) throw();
|
||||
|
||||
public:
|
||||
|
@ -1655,7 +1655,7 @@ void G1ConcurrentMark::weak_refs_work(bool clear_all_soft_refs) {
|
||||
// Unload Klasses, String, Code Cache, etc.
|
||||
if (ClassUnloadingWithConcurrentMark) {
|
||||
GCTraceTime(Debug, gc, phases) debug("Class Unloading", _gc_timer_cm);
|
||||
bool purged_classes = SystemDictionary::do_unloading(_gc_timer_cm, false /* Defer cleaning */);
|
||||
bool purged_classes = SystemDictionary::do_unloading(_gc_timer_cm);
|
||||
_g1h->complete_cleaning(&g1_is_alive, purged_classes);
|
||||
} else {
|
||||
GCTraceTime(Debug, gc, phases) debug("Cleanup", _gc_timer_cm);
|
||||
|
@ -244,6 +244,7 @@ class ClassLoaderData;
|
||||
class MetaspaceClosure;
|
||||
|
||||
class MetaspaceObj {
|
||||
friend class VMStructs;
|
||||
// When CDS is enabled, all shared metaspace objects are mapped
|
||||
// into a single contiguous memory block, so we can use these
|
||||
// two pointers to quickly determine if something is in the
|
||||
|
@ -209,6 +209,7 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
|
||||
_verify_local = BytecodeVerificationLocal;
|
||||
_verify_remote = BytecodeVerificationRemote;
|
||||
_has_platform_or_app_classes = ClassLoaderExt::has_platform_or_app_classes();
|
||||
_shared_base_address = SharedBaseAddress;
|
||||
}
|
||||
|
||||
void SharedClassPathEntry::init(const char* name, bool is_modules_image, TRAPS) {
|
||||
@ -533,6 +534,7 @@ bool FileMapInfo::init_from_file(int fd) {
|
||||
}
|
||||
|
||||
_file_offset += (long)n;
|
||||
SharedBaseAddress = _header->_shared_base_address;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -666,7 +668,8 @@ void FileMapInfo::write_region(int region, char* base, size_t size,
|
||||
// +-- gap
|
||||
size_t FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
|
||||
GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
|
||||
int first_region_id, int max_num_regions) {
|
||||
int first_region_id, int max_num_regions,
|
||||
bool print_log) {
|
||||
assert(max_num_regions <= 2, "Only support maximum 2 memory regions");
|
||||
|
||||
int arr_len = heap_mem == NULL ? 0 : heap_mem->length();
|
||||
@ -687,8 +690,10 @@ size_t FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> *heap_me
|
||||
total_size += size;
|
||||
}
|
||||
|
||||
log_info(cds)("Archive heap region %d " INTPTR_FORMAT " - " INTPTR_FORMAT " = " SIZE_FORMAT_W(8) " bytes",
|
||||
i, p2i(start), p2i(start + size), size);
|
||||
if (print_log) {
|
||||
log_info(cds)("Archive heap region %d " INTPTR_FORMAT " - " INTPTR_FORMAT " = " SIZE_FORMAT_W(8) " bytes",
|
||||
i, p2i(start), p2i(start + size), size);
|
||||
}
|
||||
write_region(i, start, size, false, false);
|
||||
if (size > 0) {
|
||||
space_at(i)->_oopmap = oopmaps->at(arr_idx)._oopmap;
|
||||
|
@ -150,6 +150,7 @@ struct FileMapHeader : public CDSFileMapHeaderBase {
|
||||
bool _verify_local; // BytecodeVerificationLocal setting
|
||||
bool _verify_remote; // BytecodeVerificationRemote setting
|
||||
bool _has_platform_or_app_classes; // Archive contains app classes
|
||||
size_t _shared_base_address; // SharedBaseAddress used at dump time
|
||||
|
||||
void set_has_platform_or_app_classes(bool v) {
|
||||
_has_platform_or_app_classes = v;
|
||||
@ -263,7 +264,8 @@ public:
|
||||
bool read_only, bool allow_exec);
|
||||
size_t write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
|
||||
GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
|
||||
int first_region_id, int max_num_regions);
|
||||
int first_region_id, int max_num_regions,
|
||||
bool print_log);
|
||||
void write_bytes(const void* buffer, size_t count);
|
||||
void write_bytes_aligned(const void* buffer, size_t count);
|
||||
char* map_region(int i, char** top_ret);
|
||||
|
@ -391,9 +391,7 @@ struct CopyKlassSubGraphInfoToArchive : StackObj {
|
||||
record->init(&info);
|
||||
|
||||
unsigned int hash = primitive_hash<Klass*>(klass);
|
||||
uintx deltax = MetaspaceShared::object_delta(record);
|
||||
guarantee(deltax <= MAX_SHARED_DELTA, "must not be");
|
||||
u4 delta = u4(deltax);
|
||||
u4 delta = MetaspaceShared::object_delta_u4(record);
|
||||
_writer->add(hash, delta);
|
||||
}
|
||||
return true; // keep on iterating
|
||||
@ -417,7 +415,7 @@ void HeapShared::write_subgraph_info_table() {
|
||||
int num_buckets = CompactHashtableWriter::default_num_buckets(d_table->_count);
|
||||
CompactHashtableWriter writer(num_buckets, &stats);
|
||||
CopyKlassSubGraphInfoToArchive copy(&writer);
|
||||
_dump_time_subgraph_info_table->iterate(©);
|
||||
d_table->iterate(©);
|
||||
|
||||
writer.dump(&_run_time_subgraph_info_table, "subgraphs");
|
||||
}
|
||||
@ -433,7 +431,7 @@ void HeapShared::initialize_from_archived_subgraph(Klass* k) {
|
||||
assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
|
||||
|
||||
unsigned int hash = primitive_hash<Klass*>(k);
|
||||
ArchivedKlassSubGraphInfoRecord* record = _run_time_subgraph_info_table.lookup(k, hash, 0);
|
||||
const ArchivedKlassSubGraphInfoRecord* record = _run_time_subgraph_info_table.lookup(k, hash, 0);
|
||||
|
||||
// Initialize from archived data. Currently this is done only
|
||||
// during VM initialization time. No lock is needed.
|
||||
|
@ -109,9 +109,9 @@ class ArchivedKlassSubGraphInfoRecord {
|
||||
ArchivedKlassSubGraphInfoRecord() :
|
||||
_k(NULL), _entry_field_records(NULL), _subgraph_object_klasses(NULL) {}
|
||||
void init(KlassSubGraphInfo* info);
|
||||
Klass* klass() { return _k; }
|
||||
Array<juint>* entry_field_records() { return _entry_field_records; }
|
||||
Array<Klass*>* subgraph_object_klasses() { return _subgraph_object_klasses; }
|
||||
Klass* klass() const { return _k; }
|
||||
Array<juint>* entry_field_records() const { return _entry_field_records; }
|
||||
Array<Klass*>* subgraph_object_klasses() const { return _subgraph_object_klasses; }
|
||||
};
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
@ -154,18 +154,16 @@ class HeapShared: AllStatic {
|
||||
int _count;
|
||||
};
|
||||
|
||||
inline static ArchivedKlassSubGraphInfoRecord* read_record_from_compact_hashtable(address base_address, u4 offset) {
|
||||
return (ArchivedKlassSubGraphInfoRecord*)(base_address + offset);
|
||||
}
|
||||
|
||||
inline static bool record_equals_compact_hashtable_entry(ArchivedKlassSubGraphInfoRecord* value, const Klass* key, int len_unused) {
|
||||
public: // solaris compiler wants this for RunTimeKlassSubGraphInfoTable
|
||||
inline static bool record_equals_compact_hashtable_entry(
|
||||
const ArchivedKlassSubGraphInfoRecord* value, const Klass* key, int len_unused) {
|
||||
return (value->klass() == key);
|
||||
}
|
||||
|
||||
typedef CompactHashtable<
|
||||
private:
|
||||
typedef OffsetCompactHashtable<
|
||||
const Klass*,
|
||||
ArchivedKlassSubGraphInfoRecord*,
|
||||
read_record_from_compact_hashtable,
|
||||
const ArchivedKlassSubGraphInfoRecord*,
|
||||
record_equals_compact_hashtable_entry
|
||||
> RunTimeKlassSubGraphInfoTable;
|
||||
|
||||
|
@ -64,7 +64,6 @@
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/bitMap.hpp"
|
||||
#include "utilities/defaultStream.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
#if INCLUDE_G1GC
|
||||
#include "gc/g1/g1CollectedHeap.hpp"
|
||||
#endif
|
||||
@ -124,6 +123,15 @@ private:
|
||||
MetaspaceShared::report_out_of_space(_name, newtop - _top);
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
uintx delta = MetaspaceShared::object_delta_uintx(newtop);
|
||||
if (delta > MAX_SHARED_DELTA) {
|
||||
// This is just a sanity check and should not appear in any real world usage. This
|
||||
// happens only if you allocate more than 2GB of shared objects and would require
|
||||
// millions of shared classes.
|
||||
vm_exit_during_initialization("Out of memory in the CDS archive",
|
||||
"Please reduce the number of shared classes.");
|
||||
}
|
||||
|
||||
MetaspaceShared::commit_shared_space_to(newtop);
|
||||
_top = newtop;
|
||||
return _top;
|
||||
@ -323,6 +331,7 @@ void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() {
|
||||
}
|
||||
|
||||
_mc_region.init(&_shared_rs);
|
||||
SharedBaseAddress = (size_t)_shared_rs.base();
|
||||
tty->print_cr("Allocated shared space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
|
||||
_shared_rs.size(), p2i(_shared_rs.base()));
|
||||
}
|
||||
@ -338,12 +347,6 @@ void MetaspaceShared::post_initialize(TRAPS) {
|
||||
ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index);
|
||||
}
|
||||
}
|
||||
|
||||
if (DumpSharedSpaces) {
|
||||
if (SharedArchiveConfigFile) {
|
||||
read_extra_data(SharedArchiveConfigFile, THREAD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetaspaceShared::read_extra_data(const char* filename, TRAPS) {
|
||||
@ -422,6 +425,7 @@ void MetaspaceShared::serialize(SerializeClosure* soc) {
|
||||
SymbolTable::serialize_shared_table_header(soc);
|
||||
StringTable::serialize_shared_table_header(soc);
|
||||
HeapShared::serialize_subgraph_info_table_header(soc);
|
||||
SystemDictionaryShared::serialize_dictionary_headers(soc);
|
||||
|
||||
JavaClasses::serialize_offsets(soc);
|
||||
InstanceMirrorKlass::serialize_offsets(soc);
|
||||
@ -470,13 +474,11 @@ static void collect_array_classes(Klass* k) {
|
||||
|
||||
class CollectClassesClosure : public KlassClosure {
|
||||
void do_klass(Klass* k) {
|
||||
if (!(k->is_instance_klass() && InstanceKlass::cast(k)->is_in_error_state())) {
|
||||
if (k->is_instance_klass() && InstanceKlass::cast(k)->signers() != NULL) {
|
||||
// Mark any class with signers and don't add to the _global_klass_objects
|
||||
k->set_has_signer_and_not_archived();
|
||||
} else {
|
||||
_global_klass_objects->append_if_missing(k);
|
||||
}
|
||||
if (k->is_instance_klass() &&
|
||||
SystemDictionaryShared::is_excluded_class(InstanceKlass::cast(k))) {
|
||||
// Don't add to the _global_klass_objects
|
||||
} else {
|
||||
_global_klass_objects->append_if_missing(k);
|
||||
}
|
||||
if (k->is_array_klass()) {
|
||||
// Add in the array classes too
|
||||
@ -583,16 +585,6 @@ static void relocate_cached_class_file() {
|
||||
}
|
||||
}
|
||||
|
||||
NOT_PRODUCT(
|
||||
static void assert_not_unsafe_anonymous_class(InstanceKlass* k) {
|
||||
assert(!(k->is_unsafe_anonymous()), "cannot archive unsafe anonymous classes");
|
||||
}
|
||||
|
||||
// Unsafe anonymous classes are not stored inside any dictionaries.
|
||||
static void assert_no_unsafe_anonymous_classes_in_dictionaries() {
|
||||
ClassLoaderDataGraph::dictionary_classes_do(assert_not_unsafe_anonymous_class);
|
||||
})
|
||||
|
||||
// Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables.
|
||||
// (In GCC this is the field <Type>::_vptr, i.e., first word in the object.)
|
||||
//
|
||||
@ -1129,6 +1121,17 @@ public:
|
||||
newtop = _ro_region.top();
|
||||
} else {
|
||||
oldtop = _rw_region.top();
|
||||
if (ref->msotype() == MetaspaceObj::ClassType) {
|
||||
// Save a pointer immediate in front of an InstanceKlass, so
|
||||
// we can do a quick lookup from InstanceKlass* -> RunTimeSharedClassInfo*
|
||||
// without building another hashtable. See RunTimeSharedClassInfo::get_for()
|
||||
// in systemDictionaryShared.cpp.
|
||||
Klass* klass = (Klass*)obj;
|
||||
if (klass->is_instance_klass()) {
|
||||
SystemDictionaryShared::validate_before_archiving(InstanceKlass::cast(klass));
|
||||
_rw_region.allocate(sizeof(address), BytesPerWord);
|
||||
}
|
||||
}
|
||||
p = _rw_region.allocate(bytes, alignment);
|
||||
newtop = _rw_region.top();
|
||||
}
|
||||
@ -1138,16 +1141,6 @@ public:
|
||||
assert(isnew, "must be");
|
||||
|
||||
_alloc_stats->record(ref->msotype(), int(newtop - oldtop), read_only);
|
||||
if (ref->msotype() == MetaspaceObj::SymbolType) {
|
||||
uintx delta = MetaspaceShared::object_delta(p);
|
||||
if (delta > MAX_SHARED_DELTA) {
|
||||
// This is just a sanity check and should not appear in any real world usage. This
|
||||
// happens only if you allocate more than 2GB of Symbols and would require
|
||||
// millions of shared classes.
|
||||
vm_exit_during_initialization("Too many Symbols in the CDS archive",
|
||||
"Please reduce the number of shared classes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static address get_new_loc(MetaspaceClosure::Ref* ref) {
|
||||
@ -1287,7 +1280,7 @@ public:
|
||||
}
|
||||
}
|
||||
FileMapInfo::metaspace_pointers_do(it);
|
||||
SystemDictionary::classes_do(it);
|
||||
SystemDictionaryShared::dumptime_classes_do(it);
|
||||
Universe::metaspace_pointers_do(it);
|
||||
SymbolTable::metaspace_pointers_do(it);
|
||||
vmSymbols::metaspace_pointers_do(it);
|
||||
@ -1321,9 +1314,6 @@ void VM_PopulateDumpSharedSpace::dump_symbols() {
|
||||
|
||||
char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
|
||||
ArchiveCompactor::OtherROAllocMark mark;
|
||||
// Reorder the system dictionary. Moving the symbols affects
|
||||
// how the hash table indices are calculated.
|
||||
SystemDictionary::reorder_dictionary_for_sharing();
|
||||
|
||||
tty->print("Removing java_mirror ... ");
|
||||
if (!HeapShared::is_heap_object_archiving_allowed()) {
|
||||
@ -1331,15 +1321,10 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
|
||||
}
|
||||
remove_java_mirror_in_classes();
|
||||
tty->print_cr("done. ");
|
||||
NOT_PRODUCT(SystemDictionary::verify();)
|
||||
|
||||
size_t buckets_bytes = SystemDictionary::count_bytes_for_buckets();
|
||||
char* buckets_top = _ro_region.allocate(buckets_bytes, sizeof(intptr_t));
|
||||
SystemDictionary::copy_buckets(buckets_top, _ro_region.top());
|
||||
SystemDictionaryShared::write_to_archive();
|
||||
|
||||
size_t table_bytes = SystemDictionary::count_bytes_for_table();
|
||||
char* table_top = _ro_region.allocate(table_bytes, sizeof(intptr_t));
|
||||
SystemDictionary::copy_table(table_top, _ro_region.top());
|
||||
char* start = _ro_region.top();
|
||||
|
||||
// Write the other data to the output array.
|
||||
WriteClosure wc(&_ro_region);
|
||||
@ -1348,7 +1333,7 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
|
||||
// Write the bitmaps for patching the archive heap regions
|
||||
dump_archive_heap_oopmaps();
|
||||
|
||||
return buckets_top;
|
||||
return start;
|
||||
}
|
||||
|
||||
void VM_PopulateDumpSharedSpace::doit() {
|
||||
@ -1373,14 +1358,11 @@ void VM_PopulateDumpSharedSpace::doit() {
|
||||
"loader constraints are not saved");
|
||||
guarantee(SystemDictionary::placeholders()->number_of_entries() == 0,
|
||||
"placeholders are not saved");
|
||||
// Revisit and implement this if we prelink method handle call sites:
|
||||
guarantee(SystemDictionary::invoke_method_table() == NULL ||
|
||||
SystemDictionary::invoke_method_table()->number_of_entries() == 0,
|
||||
"invoke method table is not saved");
|
||||
|
||||
// At this point, many classes have been loaded.
|
||||
// Gather systemDictionary classes in a global array and do everything to
|
||||
// that so we don't have to walk the SystemDictionary again.
|
||||
SystemDictionaryShared::check_excluded_classes();
|
||||
_global_klass_objects = new GrowableArray<Klass*>(1000);
|
||||
CollectClassesClosure collect_classes;
|
||||
ClassLoaderDataGraph::loaded_classes_do(&collect_classes);
|
||||
@ -1409,21 +1391,11 @@ void VM_PopulateDumpSharedSpace::doit() {
|
||||
rewrite_nofast_bytecodes_and_calculate_fingerprints();
|
||||
tty->print_cr("done. ");
|
||||
|
||||
// Move classes from platform/system dictionaries into the boot dictionary
|
||||
SystemDictionary::combine_shared_dictionaries();
|
||||
|
||||
// Make sure all classes have a correct loader type.
|
||||
ClassLoaderData::the_null_class_loader_data()->dictionary()->classes_do(MetaspaceShared::check_shared_class_loader_type);
|
||||
|
||||
// Remove all references outside the metadata
|
||||
tty->print("Removing unshareable information ... ");
|
||||
remove_unshareable_in_classes();
|
||||
tty->print_cr("done. ");
|
||||
|
||||
// We don't support archiving unsafe anonymous classes. Verify that they are not stored in
|
||||
// any dictionaries.
|
||||
NOT_PRODUCT(assert_no_unsafe_anonymous_classes_in_dictionaries());
|
||||
|
||||
ArchiveCompactor::initialize();
|
||||
ArchiveCompactor::copy_and_compact();
|
||||
|
||||
@ -1472,6 +1444,7 @@ void VM_PopulateDumpSharedSpace::doit() {
|
||||
mapinfo->set_core_spaces_size(core_spaces_size);
|
||||
|
||||
for (int pass=1; pass<=2; pass++) {
|
||||
bool print_archive_log = (pass==1);
|
||||
if (pass == 1) {
|
||||
// The first pass doesn't actually write the data to disk. All it
|
||||
// does is to update the fields in the mapinfo->_header.
|
||||
@ -1496,12 +1469,14 @@ void VM_PopulateDumpSharedSpace::doit() {
|
||||
_closed_archive_heap_regions,
|
||||
_closed_archive_heap_oopmaps,
|
||||
MetaspaceShared::first_closed_archive_heap_region,
|
||||
MetaspaceShared::max_closed_archive_heap_region);
|
||||
MetaspaceShared::max_closed_archive_heap_region,
|
||||
print_archive_log);
|
||||
_total_open_archive_region_size = mapinfo->write_archive_heap_regions(
|
||||
_open_archive_heap_regions,
|
||||
_open_archive_heap_oopmaps,
|
||||
MetaspaceShared::first_open_archive_heap_region,
|
||||
MetaspaceShared::max_open_archive_heap_region);
|
||||
MetaspaceShared::max_open_archive_heap_region,
|
||||
print_archive_log);
|
||||
}
|
||||
|
||||
mapinfo->close();
|
||||
@ -1614,17 +1589,6 @@ class CheckSharedClassesClosure : public KlassClosure {
|
||||
}
|
||||
};
|
||||
|
||||
void MetaspaceShared::check_shared_class_loader_type(InstanceKlass* ik) {
|
||||
ResourceMark rm;
|
||||
if (ik->shared_classpath_index() == UNREGISTERED_INDEX) {
|
||||
guarantee(ik->loader_type() == 0,
|
||||
"Class loader type must not be set for this class %s", ik->name()->as_C_string());
|
||||
} else {
|
||||
guarantee(ik->loader_type() != 0,
|
||||
"Class loader type must be set for this class %s", ik->name()->as_C_string());
|
||||
}
|
||||
}
|
||||
|
||||
void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
|
||||
// We need to iterate because verification may cause additional classes
|
||||
// to be loaded.
|
||||
@ -1645,9 +1609,6 @@ void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
|
||||
check_closure.reset();
|
||||
ClassLoaderDataGraph::unlocked_loaded_classes_do(&check_closure);
|
||||
} while (check_closure.made_progress());
|
||||
|
||||
// Unverifiable classes will not be included in the CDS archive.
|
||||
SystemDictionary::remove_classes_in_error_state();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1705,6 +1666,12 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
|
||||
|
||||
log_info(cds)("Shared spaces: preloaded %d classes", class_count);
|
||||
|
||||
if (SharedArchiveConfigFile) {
|
||||
tty->print_cr("Reading extra data from %s ...", SharedArchiveConfigFile);
|
||||
read_extra_data(SharedArchiveConfigFile, THREAD);
|
||||
}
|
||||
tty->print_cr("Reading extra data: done.");
|
||||
|
||||
HeapShared::init_subgraph_entry_fields(THREAD);
|
||||
|
||||
// Rewrite and link classes
|
||||
@ -1717,10 +1684,6 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
|
||||
link_and_cleanup_shared_classes(CATCH);
|
||||
tty->print_cr("Rewriting and linking classes: done");
|
||||
|
||||
SystemDictionary::clear_invoke_method_table();
|
||||
|
||||
SystemDictionaryShared::finalize_verification_constraints();
|
||||
|
||||
VM_PopulateDumpSharedSpace op;
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
@ -1731,36 +1694,36 @@ int MetaspaceShared::preload_classes(const char* class_list_path, TRAPS) {
|
||||
ClassListParser parser(class_list_path);
|
||||
int class_count = 0;
|
||||
|
||||
while (parser.parse_one_line()) {
|
||||
Klass* klass = ClassLoaderExt::load_one_class(&parser, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
if (klass == NULL &&
|
||||
(PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_ClassNotFoundException())) {
|
||||
// print a warning only when the pending exception is class not found
|
||||
tty->print_cr("Preload Warning: Cannot find %s", parser.current_class_name());
|
||||
}
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
}
|
||||
if (klass != NULL) {
|
||||
if (log_is_enabled(Trace, cds)) {
|
||||
ResourceMark rm;
|
||||
log_trace(cds)("Shared spaces preloaded: %s", klass->external_name());
|
||||
}
|
||||
|
||||
if (klass->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(klass);
|
||||
|
||||
// Link the class to cause the bytecodes to be rewritten and the
|
||||
// cpcache to be created. The linking is done as soon as classes
|
||||
// are loaded in order that the related data structures (klass and
|
||||
// cpCache) are located together.
|
||||
try_link_class(ik, THREAD);
|
||||
guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
|
||||
}
|
||||
|
||||
class_count++;
|
||||
while (parser.parse_one_line()) {
|
||||
Klass* klass = parser.load_current_class(THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
if (klass == NULL &&
|
||||
(PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_ClassNotFoundException())) {
|
||||
// print a warning only when the pending exception is class not found
|
||||
tty->print_cr("Preload Warning: Cannot find %s", parser.current_class_name());
|
||||
}
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
}
|
||||
if (klass != NULL) {
|
||||
if (log_is_enabled(Trace, cds)) {
|
||||
ResourceMark rm;
|
||||
log_trace(cds)("Shared spaces preloaded: %s", klass->external_name());
|
||||
}
|
||||
|
||||
if (klass->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(klass);
|
||||
|
||||
// Link the class to cause the bytecodes to be rewritten and the
|
||||
// cpcache to be created. The linking is done as soon as classes
|
||||
// are loaded in order that the related data structures (klass and
|
||||
// cpCache) are located together.
|
||||
try_link_class(ik, THREAD);
|
||||
guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
|
||||
}
|
||||
|
||||
class_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return class_count;
|
||||
}
|
||||
@ -1994,21 +1957,6 @@ void MetaspaceShared::initialize_shared_spaces() {
|
||||
|
||||
// The rest of the data is now stored in the RW region
|
||||
buffer = mapinfo->read_only_tables_start();
|
||||
int sharedDictionaryLen = *(intptr_t*)buffer;
|
||||
buffer += sizeof(intptr_t);
|
||||
int number_of_entries = *(intptr_t*)buffer;
|
||||
buffer += sizeof(intptr_t);
|
||||
SystemDictionary::set_shared_dictionary((HashtableBucket<mtClass>*)buffer,
|
||||
sharedDictionaryLen,
|
||||
number_of_entries);
|
||||
buffer += sharedDictionaryLen;
|
||||
|
||||
// The following data are the linked list elements
|
||||
// (HashtableEntry objects) for the shared dictionary table.
|
||||
|
||||
int len = *(intptr_t*)buffer; // skip over shared dictionary entries
|
||||
buffer += sizeof(intptr_t);
|
||||
buffer += len;
|
||||
|
||||
// Verify various attributes of the archive, plus initialize the
|
||||
// shared string/symbol tables
|
||||
@ -2027,7 +1975,7 @@ void MetaspaceShared::initialize_shared_spaces() {
|
||||
if (PrintSharedArchiveAndExit) {
|
||||
if (PrintSharedDictionary) {
|
||||
tty->print_cr("\nShared classes:\n");
|
||||
SystemDictionary::print_shared(tty);
|
||||
SystemDictionaryShared::print_on(tty);
|
||||
}
|
||||
if (_archive_loading_failed) {
|
||||
tty->print_cr("archive is invalid");
|
||||
|
@ -107,12 +107,19 @@ class MetaspaceShared : AllStatic {
|
||||
static void post_initialize(TRAPS) NOT_CDS_RETURN;
|
||||
|
||||
// Delta of this object from the bottom of the archive.
|
||||
static uintx object_delta(void* obj) {
|
||||
static uintx object_delta_uintx(void* obj) {
|
||||
assert(DumpSharedSpaces, "supported only for dumping");
|
||||
assert(shared_rs()->contains(obj), "must be");
|
||||
address base_address = address(shared_rs()->base());
|
||||
uintx delta = address(obj) - base_address;
|
||||
return delta;
|
||||
uintx deltax = address(obj) - base_address;
|
||||
return deltax;
|
||||
}
|
||||
|
||||
static u4 object_delta_u4(void* obj) {
|
||||
// offset is guaranteed to be less than MAX_SHARED_DELTA in DumpRegion::expand_top_to()
|
||||
uintx deltax = object_delta_uintx(obj);
|
||||
guarantee(deltax <= MAX_SHARED_DELTA, "must be 32-bit offset");
|
||||
return (u4)deltax;
|
||||
}
|
||||
|
||||
static void set_archive_loading_failed() {
|
||||
|
@ -422,17 +422,22 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, Klass
|
||||
_static_field_size(parser.static_field_size()),
|
||||
_nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
|
||||
_itable_len(parser.itable_size()),
|
||||
_reference_type(parser.reference_type()) {
|
||||
set_vtable_length(parser.vtable_size());
|
||||
set_kind(kind);
|
||||
set_access_flags(parser.access_flags());
|
||||
set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
|
||||
set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
|
||||
_reference_type(parser.reference_type())
|
||||
{
|
||||
set_vtable_length(parser.vtable_size());
|
||||
set_kind(kind);
|
||||
set_access_flags(parser.access_flags());
|
||||
set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
|
||||
set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
|
||||
false));
|
||||
|
||||
assert(NULL == _methods, "underlying memory not zeroed?");
|
||||
assert(is_instance_klass(), "is layout incorrect?");
|
||||
assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
|
||||
assert(NULL == _methods, "underlying memory not zeroed?");
|
||||
assert(is_instance_klass(), "is layout incorrect?");
|
||||
assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
|
||||
|
||||
if (DumpSharedSpaces) {
|
||||
SystemDictionaryShared::init_dumptime_info(this);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data,
|
||||
@ -579,6 +584,10 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
|
||||
MetadataFactory::free_metadata(loader_data, annotations());
|
||||
}
|
||||
set_annotations(NULL);
|
||||
|
||||
if (DumpSharedSpaces) {
|
||||
SystemDictionaryShared::remove_dumptime_info(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool InstanceKlass::should_be_initialized() const {
|
||||
|
@ -176,8 +176,7 @@ private:
|
||||
// Flags of the current shared class.
|
||||
u2 _shared_class_flags;
|
||||
enum {
|
||||
_has_raw_archived_mirror = 1,
|
||||
_has_signer_and_not_archived = 1 << 2
|
||||
_has_raw_archived_mirror = 1
|
||||
};
|
||||
#endif
|
||||
// The _archived_mirror is set at CDS dump time pointing to the cached mirror
|
||||
@ -314,15 +313,6 @@ protected:
|
||||
CDS_ONLY(return (_shared_class_flags & _has_raw_archived_mirror) != 0;)
|
||||
NOT_CDS(return false;)
|
||||
}
|
||||
#if INCLUDE_CDS
|
||||
void set_has_signer_and_not_archived() {
|
||||
_shared_class_flags |= _has_signer_and_not_archived;
|
||||
}
|
||||
bool has_signer_and_not_archived() const {
|
||||
assert(DumpSharedSpaces, "dump time only");
|
||||
return (_shared_class_flags & _has_signer_and_not_archived) != 0;
|
||||
}
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
// Obtain the module or package for this class
|
||||
virtual ModuleEntry* module() const = 0;
|
||||
|
@ -942,6 +942,15 @@ private:
|
||||
GrowableArray<float> _freqs; // cache frequencies
|
||||
PhaseIdealLoop* _phase;
|
||||
|
||||
void set_rounding(int mode) {
|
||||
// fesetround is broken on windows
|
||||
NOT_WINDOWS(fesetround(mode);)
|
||||
}
|
||||
|
||||
void check_frequency(float f) {
|
||||
NOT_WINDOWS(assert(f <= 1 && f >= 0, "Incorrect frequency");)
|
||||
}
|
||||
|
||||
public:
|
||||
PathFrequency(Node* dom, PhaseIdealLoop* phase)
|
||||
: _dom(dom), _stack(0), _phase(phase) {
|
||||
@ -949,7 +958,7 @@ public:
|
||||
|
||||
float to(Node* n) {
|
||||
// post order walk on the CFG graph from n to _dom
|
||||
fesetround(FE_TOWARDZERO); // make sure rounding doesn't push frequency above 1
|
||||
set_rounding(FE_TOWARDZERO); // make sure rounding doesn't push frequency above 1
|
||||
IdealLoopTree* loop = _phase->get_loop(_dom);
|
||||
Node* c = n;
|
||||
for (;;) {
|
||||
@ -976,14 +985,14 @@ public:
|
||||
inner_head = inner_loop->_head->as_Loop();
|
||||
inner_head->verify_strip_mined(1);
|
||||
}
|
||||
fesetround(FE_UPWARD); // make sure rounding doesn't push frequency above 1
|
||||
set_rounding(FE_UPWARD); // make sure rounding doesn't push frequency above 1
|
||||
float loop_exit_cnt = 0.0f;
|
||||
for (uint i = 0; i < inner_loop->_body.size(); i++) {
|
||||
Node *n = inner_loop->_body[i];
|
||||
float c = inner_loop->compute_profile_trip_cnt_helper(n);
|
||||
loop_exit_cnt += c;
|
||||
}
|
||||
fesetround(FE_TOWARDZERO);
|
||||
set_rounding(FE_TOWARDZERO);
|
||||
float cnt = -1;
|
||||
if (n->in(0)->is_If()) {
|
||||
IfNode* iff = n->in(0)->as_If();
|
||||
@ -1003,9 +1012,9 @@ public:
|
||||
cnt = p * jmp->_fcnt;
|
||||
}
|
||||
float this_exit_f = cnt > 0 ? cnt / loop_exit_cnt : 0;
|
||||
assert(this_exit_f <= 1 && this_exit_f >= 0, "Incorrect frequency");
|
||||
check_frequency(this_exit_f);
|
||||
f = f * this_exit_f;
|
||||
assert(f <= 1 && f >= 0, "Incorrect frequency");
|
||||
check_frequency(f);
|
||||
} else {
|
||||
float p = -1;
|
||||
if (n->in(0)->is_If()) {
|
||||
@ -1018,7 +1027,7 @@ public:
|
||||
p = n->in(0)->as_Jump()->_probs[n->as_JumpProj()->_con];
|
||||
}
|
||||
f = f * p;
|
||||
assert(f <= 1 && f >= 0, "Incorrect frequency");
|
||||
check_frequency(f);
|
||||
}
|
||||
_freqs.at_put_grow(n->_idx, (float)f, -1);
|
||||
_stack.pop();
|
||||
@ -1026,7 +1035,7 @@ public:
|
||||
float prev_f = _freqs_stack.pop();
|
||||
float new_f = f;
|
||||
f = new_f + prev_f;
|
||||
assert(f <= 1 && f >= 0, "Incorrect frequency");
|
||||
check_frequency(f);
|
||||
uint i = _stack.index();
|
||||
if (i < n->req()) {
|
||||
c = n->in(i);
|
||||
@ -1039,8 +1048,8 @@ public:
|
||||
}
|
||||
}
|
||||
if (_stack.size() == 0) {
|
||||
fesetround(FE_TONEAREST);
|
||||
assert(f >= 0 && f <= 1, "should have been computed");
|
||||
set_rounding(FE_TONEAREST);
|
||||
check_frequency(f);
|
||||
return f;
|
||||
}
|
||||
} else if (c->is_Loop()) {
|
||||
|
@ -1209,7 +1209,9 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) {
|
||||
// Allocate a private array of RegMasks. These RegMasks are not shared.
|
||||
msfpt->_in_rms = NEW_RESOURCE_ARRAY( RegMask, cnt );
|
||||
// Empty them all.
|
||||
memset( msfpt->_in_rms, 0, sizeof(RegMask)*cnt );
|
||||
for (uint i = 0; i < cnt; i++) {
|
||||
msfpt->_in_rms[i] = RegMask();
|
||||
}
|
||||
|
||||
// Do all the pre-defined non-Empty register masks
|
||||
msfpt->_in_rms[TypeFunc::ReturnAdr] = _return_addr_mask;
|
||||
|
@ -2074,17 +2074,10 @@ bool Arguments::is_bad_option(const JavaVMOption* option, jboolean ignore,
|
||||
option_type = ++spacer; // Set both to the empty string.
|
||||
}
|
||||
|
||||
if (os::obsolete_option(option)) {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"Obsolete %s%soption: %s\n", option_type, spacer,
|
||||
option->optionString);
|
||||
return false;
|
||||
} else {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"Unrecognized %s%soption: %s\n", option_type, spacer,
|
||||
option->optionString);
|
||||
return true;
|
||||
}
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"Unrecognized %s%soption: %s\n", option_type, spacer,
|
||||
option->optionString);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char* user_assertion_options[] = {
|
||||
@ -2649,23 +2642,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m
|
||||
// Obsolete in JDK 10
|
||||
JDK_Version::jdk(10).to_string(version, sizeof(version));
|
||||
warning("Ignoring option %s; support was removed in %s", option->optionString, version);
|
||||
// -Xconcurrentio
|
||||
} else if (match_option(option, "-Xconcurrentio")) {
|
||||
if (FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true) != JVMFlag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != JVMFlag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
SafepointSynchronize::set_defer_thr_suspend_loop_count();
|
||||
if (FLAG_SET_CMDLINE(bool, UseTLAB, false) != JVMFlag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
if (FLAG_SET_CMDLINE(size_t, NewSizeThreadIncrease, 16 * K) != JVMFlag::SUCCESS) { // 20Kb per thread added to new generation
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
|
||||
// -Xinternalversion
|
||||
// -Xinternalversion
|
||||
} else if (match_option(option, "-Xinternalversion")) {
|
||||
jio_fprintf(defaultStream::output_stream(), "%s\n",
|
||||
VM_Version::internal_vm_info_string());
|
||||
|
@ -802,9 +802,6 @@ class os: AllStatic {
|
||||
// System loadavg support. Returns -1 if load average cannot be obtained.
|
||||
static int loadavg(double loadavg[], int nelem);
|
||||
|
||||
// Hook for os specific jvm options that we don't want to abort on seeing
|
||||
static bool obsolete_option(const JavaVMOption *option);
|
||||
|
||||
// Amount beyond the callee frame size that we bang the stack.
|
||||
static int extra_bang_size_in_bytes();
|
||||
|
||||
|
@ -178,10 +178,6 @@ public:
|
||||
|
||||
static address safepoint_counter_addr() { return (address)&_safepoint_counter; }
|
||||
|
||||
// This method is only used for -Xconcurrentio support.
|
||||
static void set_defer_thr_suspend_loop_count() {
|
||||
_defer_thr_suspend_loop_count = 1;
|
||||
}
|
||||
};
|
||||
|
||||
// Some helper assert macros for safepoint checks.
|
||||
|
@ -404,6 +404,8 @@ typedef PaddedEnd<ObjectMonitor> PaddedObjectMonitor;
|
||||
/* Memory */ \
|
||||
/**********/ \
|
||||
\
|
||||
static_field(MetaspaceObj, _shared_metaspace_base, void*) \
|
||||
static_field(MetaspaceObj, _shared_metaspace_top, void*) \
|
||||
nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \
|
||||
nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \
|
||||
nonstatic_field(ThreadLocalAllocBuffer, _end, HeapWord*) \
|
||||
@ -460,7 +462,6 @@ typedef PaddedEnd<ObjectMonitor> PaddedObjectMonitor;
|
||||
/* SystemDictionary */ \
|
||||
/********************/ \
|
||||
\
|
||||
static_field(SystemDictionary, _shared_dictionary, Dictionary*) \
|
||||
static_field(SystemDictionary, _system_loader_lock_obj, oop) \
|
||||
static_field(SystemDictionary, WK_KLASS(Object_klass), InstanceKlass*) \
|
||||
static_field(SystemDictionary, WK_KLASS(String_klass), InstanceKlass*) \
|
||||
|
@ -472,6 +472,12 @@ class ConcurrentHashTable : public CHeapObj<F> {
|
||||
template <typename SCAN_FUNC>
|
||||
void do_scan(Thread* thread, SCAN_FUNC& scan_f);
|
||||
|
||||
// Visit all items with SCAN_FUNC without any protection.
|
||||
// It will assume there is no other thread accessing this
|
||||
// table during the safepoint. Must be called with VM thread.
|
||||
template <typename SCAN_FUNC>
|
||||
void do_safepoint_scan(SCAN_FUNC& scan_f);
|
||||
|
||||
// Destroying items matching EVALUATE_FUNC, before destroying items
|
||||
// DELETE_FUNC is called, if resize lock is obtained. Else returns false.
|
||||
template <typename EVALUATE_FUNC, typename DELETE_FUNC>
|
||||
|
@ -1116,6 +1116,8 @@ template <typename SCAN_FUNC>
|
||||
inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
do_scan(Thread* thread, SCAN_FUNC& scan_f)
|
||||
{
|
||||
assert(!SafepointSynchronize::is_at_safepoint(),
|
||||
"must be outside a safepoint");
|
||||
assert(_resize_lock_owner != thread, "Re-size lock held");
|
||||
lock_resize_lock(thread);
|
||||
do_scan_locked(thread, scan_f);
|
||||
@ -1123,6 +1125,49 @@ inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
assert(_resize_lock_owner != thread, "Re-size lock held");
|
||||
}
|
||||
|
||||
template <typename VALUE, typename CONFIG, MEMFLAGS F>
|
||||
template <typename SCAN_FUNC>
|
||||
inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
do_safepoint_scan(SCAN_FUNC& scan_f)
|
||||
{
|
||||
// We only allow this method to be used during a safepoint.
|
||||
assert(SafepointSynchronize::is_at_safepoint(),
|
||||
"must only be called in a safepoint");
|
||||
assert(Thread::current()->is_VM_thread(),
|
||||
"should be in vm thread");
|
||||
|
||||
// Here we skip protection,
|
||||
// thus no other thread may use this table at the same time.
|
||||
InternalTable* table = get_table();
|
||||
for (size_t bucket_it = 0; bucket_it < table->_size; bucket_it++) {
|
||||
Bucket* bucket = table->get_bucket(bucket_it);
|
||||
// If bucket have a redirect the items will be in the new table.
|
||||
// We must visit them there since the new table will contain any
|
||||
// concurrent inserts done after this bucket was resized.
|
||||
// If the bucket don't have redirect flag all items is in this table.
|
||||
if (!bucket->have_redirect()) {
|
||||
if(!visit_nodes(bucket, scan_f)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
assert(bucket->is_locked(), "Bucket must be locked.");
|
||||
}
|
||||
}
|
||||
// If there is a paused resize we also need to visit the already resized items.
|
||||
table = get_new_table();
|
||||
if (table == NULL) {
|
||||
return;
|
||||
}
|
||||
DEBUG_ONLY(if (table == POISON_PTR) { return; })
|
||||
for (size_t bucket_it = 0; bucket_it < table->_size; bucket_it++) {
|
||||
Bucket* bucket = table->get_bucket(bucket_it);
|
||||
assert(!bucket->is_locked(), "Bucket must be unlocked.");
|
||||
if (!visit_nodes(bucket, scan_f)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VALUE, typename CONFIG, MEMFLAGS F>
|
||||
template <typename EVALUATE_FUNC, typename DELETE_FUNC>
|
||||
inline bool ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
@ -1142,6 +1187,8 @@ template <typename EVALUATE_FUNC, typename DELETE_FUNC>
|
||||
inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
bulk_delete(Thread* thread, EVALUATE_FUNC& eval_f, DELETE_FUNC& del_f)
|
||||
{
|
||||
assert(!SafepointSynchronize::is_at_safepoint(),
|
||||
"must be outside a safepoint");
|
||||
lock_resize_lock(thread);
|
||||
do_bulk_delete_locked(thread, eval_f, del_f);
|
||||
unlock_resize_lock(thread);
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include "classfile/stringTable.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/weakHandle.inline.hpp"
|
||||
@ -99,11 +98,7 @@ template <class T, MEMFLAGS F> HashtableEntry<T, F>* Hashtable<T, F>::allocate_n
|
||||
|
||||
template <MEMFLAGS F> void BasicHashtable<F>::free_buckets() {
|
||||
if (NULL != _buckets) {
|
||||
// Don't delete the buckets in the shared space. They aren't
|
||||
// allocated by os::malloc
|
||||
if (!MetaspaceShared::is_in_shared_metaspace(_buckets)) {
|
||||
FREE_C_HEAP_ARRAY(HashtableBucket, _buckets);
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(HashtableBucket, _buckets);
|
||||
_buckets = NULL;
|
||||
}
|
||||
}
|
||||
@ -137,47 +132,6 @@ template <MEMFLAGS F> void BasicHashtable<F>::bulk_free_entries(BucketUnlinkCont
|
||||
}
|
||||
Atomic::add(-context->_num_removed, &_number_of_entries);
|
||||
}
|
||||
// Copy the table to the shared space.
|
||||
template <MEMFLAGS F> size_t BasicHashtable<F>::count_bytes_for_table() {
|
||||
size_t bytes = 0;
|
||||
bytes += sizeof(intptr_t); // len
|
||||
|
||||
for (int i = 0; i < _table_size; ++i) {
|
||||
for (BasicHashtableEntry<F>** p = _buckets[i].entry_addr();
|
||||
*p != NULL;
|
||||
p = (*p)->next_addr()) {
|
||||
bytes += entry_size();
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// Dump the hash table entries (into CDS archive)
|
||||
template <MEMFLAGS F> void BasicHashtable<F>::copy_table(char* top, char* end) {
|
||||
assert(is_aligned(top, sizeof(intptr_t)), "bad alignment");
|
||||
intptr_t *plen = (intptr_t*)(top);
|
||||
top += sizeof(*plen);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < _table_size; ++i) {
|
||||
for (BasicHashtableEntry<F>** p = _buckets[i].entry_addr();
|
||||
*p != NULL;
|
||||
p = (*p)->next_addr()) {
|
||||
*p = (BasicHashtableEntry<F>*)memcpy(top, (void*)*p, entry_size());
|
||||
top += entry_size();
|
||||
}
|
||||
}
|
||||
*plen = (char*)(top) - (char*)plen - sizeof(*plen);
|
||||
assert(top == end, "count_bytes_for_table is wrong");
|
||||
// Set the shared bit.
|
||||
|
||||
for (i = 0; i < _table_size; ++i) {
|
||||
for (BasicHashtableEntry<F>* p = bucket(i); p != NULL; p = p->next()) {
|
||||
p->set_shared();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For oops and Strings the size of the literal is interesting. For other types, nobody cares.
|
||||
static int literal_size(ConstantPool*) { return 0; }
|
||||
@ -297,34 +251,6 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::print_table_statistics(outp
|
||||
st->print_cr("Maximum bucket size : %9d", (int)summary.maximum());
|
||||
}
|
||||
|
||||
|
||||
// Dump the hash table buckets.
|
||||
|
||||
template <MEMFLAGS F> size_t BasicHashtable<F>::count_bytes_for_buckets() {
|
||||
size_t bytes = 0;
|
||||
bytes += sizeof(intptr_t); // len
|
||||
bytes += sizeof(intptr_t); // _number_of_entries
|
||||
bytes += _table_size * sizeof(HashtableBucket<F>); // the buckets
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// Dump the buckets (into CDS archive)
|
||||
template <MEMFLAGS F> void BasicHashtable<F>::copy_buckets(char* top, char* end) {
|
||||
assert(is_aligned(top, sizeof(intptr_t)), "bad alignment");
|
||||
intptr_t len = _table_size * sizeof(HashtableBucket<F>);
|
||||
*(intptr_t*)(top) = len;
|
||||
top += sizeof(intptr_t);
|
||||
|
||||
*(intptr_t*)(top) = _number_of_entries;
|
||||
top += sizeof(intptr_t);
|
||||
|
||||
_buckets = (HashtableBucket<F>*)memcpy(top, (void*)_buckets, len);
|
||||
top += len;
|
||||
|
||||
assert(top == end, "count_bytes_for_buckets is wrong");
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
template <class T> void print_literal(T l) {
|
||||
l->print();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2018, 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
|
||||
@ -147,12 +147,6 @@ public:
|
||||
BasicHashtable(int table_size, int entry_size,
|
||||
HashtableBucket<F>* buckets, int number_of_entries);
|
||||
|
||||
// Sharing support.
|
||||
size_t count_bytes_for_buckets();
|
||||
size_t count_bytes_for_table();
|
||||
void copy_buckets(char* top, char* end);
|
||||
void copy_table(char* top, char* end);
|
||||
|
||||
// Bucket handling
|
||||
int hash_to_index(unsigned int full_hash) const {
|
||||
int h = full_hash % _table_size;
|
||||
|
@ -1433,7 +1433,7 @@ public final class Module implements AnnotatedElement {
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
|
||||
+ ClassWriter.COMPUTE_FRAMES);
|
||||
|
||||
ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) {
|
||||
ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) {
|
||||
@Override
|
||||
public void visit(int version,
|
||||
int access,
|
||||
|
@ -1629,7 +1629,7 @@ public final class StringConcatFactory {
|
||||
@ForceInline
|
||||
private static byte[] newArray(long indexCoder) {
|
||||
byte coder = (byte)(indexCoder >> 32);
|
||||
int index = ((int)indexCoder & 0x7FFFFFFF);
|
||||
int index = (int)indexCoder;
|
||||
return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder);
|
||||
}
|
||||
|
||||
@ -1692,30 +1692,35 @@ public final class StringConcatFactory {
|
||||
// no instantiation
|
||||
}
|
||||
|
||||
private static class StringifierMost extends ClassValue<MethodHandle> {
|
||||
@Override
|
||||
protected MethodHandle computeValue(Class<?> cl) {
|
||||
if (cl == String.class) {
|
||||
return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, Object.class);
|
||||
} else if (cl == float.class) {
|
||||
return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, float.class);
|
||||
} else if (cl == double.class) {
|
||||
return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, double.class);
|
||||
} else if (!cl.isPrimitive()) {
|
||||
MethodHandle mhObject = lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, Object.class);
|
||||
private static class ObjectStringifier {
|
||||
|
||||
// We need the additional conversion here, because String.valueOf(Object) may return null.
|
||||
// String conversion rules in Java state we need to produce "null" String in this case.
|
||||
// It can be easily done with applying valueOf the second time.
|
||||
return MethodHandles.filterReturnValue(mhObject,
|
||||
mhObject.asType(MethodType.methodType(String.class, String.class)));
|
||||
}
|
||||
|
||||
return null;
|
||||
// We need some additional conversion for Objects in general, because String.valueOf(Object)
|
||||
// may return null. String conversion rules in Java state we need to produce "null" String
|
||||
// in this case, so we provide a customized version that deals with this problematic corner case.
|
||||
private static String valueOf(Object value) {
|
||||
String s;
|
||||
return (value == null || (s = value.toString()) == null) ? "null" : s;
|
||||
}
|
||||
|
||||
// Could have used MethodHandles.lookup() instead of Lookup.IMPL_LOOKUP, if not for the fact
|
||||
// java.lang.invoke Lookups are explicitly forbidden to be retrieved using that API.
|
||||
private static final MethodHandle INSTANCE =
|
||||
lookupStatic(Lookup.IMPL_LOOKUP, ObjectStringifier.class, "valueOf", String.class, Object.class);
|
||||
|
||||
}
|
||||
|
||||
private static class FloatStringifiers {
|
||||
private static final MethodHandle FLOAT_INSTANCE =
|
||||
lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, float.class);
|
||||
|
||||
private static final MethodHandle DOUBLE_INSTANCE =
|
||||
lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, double.class);
|
||||
}
|
||||
|
||||
private static class StringifierAny extends ClassValue<MethodHandle> {
|
||||
|
||||
private static final ClassValue<MethodHandle> INSTANCE = new StringifierAny();
|
||||
|
||||
@Override
|
||||
protected MethodHandle computeValue(Class<?> cl) {
|
||||
if (cl == byte.class || cl == short.class || cl == int.class) {
|
||||
@ -1727,7 +1732,7 @@ public final class StringConcatFactory {
|
||||
} else if (cl == long.class) {
|
||||
return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, long.class);
|
||||
} else {
|
||||
MethodHandle mh = STRINGIFIERS_MOST.get(cl);
|
||||
MethodHandle mh = forMost(cl);
|
||||
if (mh != null) {
|
||||
return mh;
|
||||
} else {
|
||||
@ -1737,9 +1742,6 @@ public final class StringConcatFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private static final ClassValue<MethodHandle> STRINGIFIERS_MOST = new StringifierMost();
|
||||
private static final ClassValue<MethodHandle> STRINGIFIERS_ANY = new StringifierAny();
|
||||
|
||||
/**
|
||||
* Returns a stringifier for references and floats/doubles only.
|
||||
* Always returns null for other primitives.
|
||||
@ -1748,7 +1750,14 @@ public final class StringConcatFactory {
|
||||
* @return stringifier; null, if not available
|
||||
*/
|
||||
static MethodHandle forMost(Class<?> t) {
|
||||
return STRINGIFIERS_MOST.get(t);
|
||||
if (!t.isPrimitive()) {
|
||||
return ObjectStringifier.INSTANCE;
|
||||
} else if (t == float.class) {
|
||||
return FloatStringifiers.FLOAT_INSTANCE;
|
||||
} else if (t == double.class) {
|
||||
return FloatStringifiers.DOUBLE_INSTANCE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1758,7 +1767,7 @@ public final class StringConcatFactory {
|
||||
* @return stringifier
|
||||
*/
|
||||
static MethodHandle forAny(Class<?> t) {
|
||||
return STRINGIFIERS_ANY.get(t);
|
||||
return StringifierAny.INSTANCE.get(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
@ -35,7 +35,7 @@ import static sun.invoke.util.Wrapper.*;
|
||||
class TypeConvertingMethodAdapter extends MethodVisitor {
|
||||
|
||||
TypeConvertingMethodAdapter(MethodVisitor mv) {
|
||||
super(Opcodes.ASM5, mv);
|
||||
super(Opcodes.ASM7, mv);
|
||||
}
|
||||
|
||||
private static final int NUM_WRAPPERS = Wrapper.COUNT;
|
||||
|
@ -379,7 +379,7 @@ public abstract class Reference<T> {
|
||||
* Throws {@link CloneNotSupportedException}. A {@code Reference} cannot be
|
||||
* meaningfully cloned. Construct a new {@code Reference} instead.
|
||||
*
|
||||
* @returns never returns normally
|
||||
* @return never returns normally
|
||||
* @throws CloneNotSupportedException always
|
||||
*
|
||||
* @since 11
|
||||
|
@ -62,7 +62,7 @@ import sun.util.logging.PlatformLogger;
|
||||
* <ul>
|
||||
* <li>
|
||||
* CookieHandler is at the core of cookie management. User can call
|
||||
* CookieHandler.setDefault to set a concrete CookieHanlder implementation
|
||||
* CookieHandler.setDefault to set a concrete CookieHandler implementation
|
||||
* to be used.
|
||||
* </li>
|
||||
* <li>
|
||||
@ -354,7 +354,7 @@ public class CookieManager extends CookieHandler
|
||||
private boolean shouldAcceptInternal(URI uri, HttpCookie cookie) {
|
||||
try {
|
||||
return policyCallback.shouldAccept(uri, cookie);
|
||||
} catch (Exception ignored) { // pretect against malicious callback
|
||||
} catch (Exception ignored) { // protect against malicious callback
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ class DatagramSocket implements java.io.Closeable {
|
||||
private void checkOldImpl() {
|
||||
if (impl == null)
|
||||
return;
|
||||
// DatagramSocketImpl.peekdata() is a protected method, therefore we need to use
|
||||
// DatagramSocketImpl.peekData() is a protected method, therefore we need to use
|
||||
// getDeclaredMethod, therefore we need permission to access the member
|
||||
try {
|
||||
AccessController.doPrivileged(
|
||||
@ -660,7 +660,7 @@ class DatagramSocket implements java.io.Closeable {
|
||||
throw new SocketException("Socket is closed");
|
||||
checkAddress (p.getAddress(), "send");
|
||||
if (connectState == ST_NOT_CONNECTED) {
|
||||
// check the address is ok wiht the security manager on every send.
|
||||
// check the address is ok with the security manager on every send.
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
|
||||
// The reason you want to synchronize on datagram packet
|
||||
@ -1070,7 +1070,7 @@ class DatagramSocket implements java.io.Closeable {
|
||||
*
|
||||
* @param on whether to enable or disable the
|
||||
* @exception SocketException if an error occurs enabling or
|
||||
* disabling the {@code SO_RESUEADDR} socket option,
|
||||
* disabling the {@code SO_REUSEADDR} socket option,
|
||||
* or the socket is closed.
|
||||
* @since 1.4
|
||||
* @see #getReuseAddress()
|
||||
|
@ -666,7 +666,7 @@ public final class HttpCookie implements Cloneable {
|
||||
int domainLength = domain.length();
|
||||
int lengthDiff = host.length() - domainLength;
|
||||
if (lengthDiff == 0) {
|
||||
// if the host name and the domain name are just string-compare euqal
|
||||
// if the host name and the domain name are just string-compare equal
|
||||
return host.equalsIgnoreCase(domain);
|
||||
}
|
||||
else if (lengthDiff > 0) {
|
||||
@ -1131,7 +1131,7 @@ public final class HttpCookie implements Cloneable {
|
||||
* Split cookie header string according to rfc 2965:
|
||||
* 1) split where it is a comma;
|
||||
* 2) but not the comma surrounding by double-quotes, which is the comma
|
||||
* inside port list or embeded URIs.
|
||||
* inside port list or embedded URIs.
|
||||
*
|
||||
* @param header
|
||||
* the cookie header string to split
|
||||
|
@ -407,7 +407,7 @@ public final class IDN {
|
||||
// 26-letter Latin alphabet <A-Z a-z>, the digits <0-9>, and the hyphen
|
||||
// <->.
|
||||
// Non LDH refers to characters in the ASCII range, but which are not
|
||||
// letters, digits or the hypen.
|
||||
// letters, digits or the hyphen.
|
||||
//
|
||||
// non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x5B..0x60, 0x7B..0x7F
|
||||
//
|
||||
|
@ -54,7 +54,7 @@ class InMemoryCookieStore implements CookieStore {
|
||||
private Map<String, List<HttpCookie>> domainIndex = null;
|
||||
private Map<URI, List<HttpCookie>> uriIndex = null;
|
||||
|
||||
// use ReentrantLock instead of syncronized for scalability
|
||||
// use ReentrantLock instead of synchronized for scalability
|
||||
private ReentrantLock lock = null;
|
||||
|
||||
|
||||
@ -260,7 +260,7 @@ class InMemoryCookieStore implements CookieStore {
|
||||
int domainLength = domain.length();
|
||||
int lengthDiff = host.length() - domainLength;
|
||||
if (lengthDiff == 0) {
|
||||
// if the host name and the domain name are just string-compare euqal
|
||||
// if the host name and the domain name are just string-compare equal
|
||||
return host.equalsIgnoreCase(domain);
|
||||
} else if (lengthDiff > 0) {
|
||||
// need to check H & D component
|
||||
@ -301,7 +301,7 @@ class InMemoryCookieStore implements CookieStore {
|
||||
toRemove.add(c);
|
||||
}
|
||||
} else {
|
||||
// the cookie has beed removed from main store,
|
||||
// the cookie has been removed from main store,
|
||||
// so also remove it from domain indexed store
|
||||
toRemove.add(c);
|
||||
}
|
||||
@ -345,7 +345,7 @@ class InMemoryCookieStore implements CookieStore {
|
||||
cookieJar.remove(ck);
|
||||
}
|
||||
} else {
|
||||
// the cookie has beed removed from main store,
|
||||
// the cookie has been removed from main store,
|
||||
// so also remove it from domain indexed store
|
||||
it.remove();
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ class Inet4Address extends InetAddress {
|
||||
|
||||
/**
|
||||
* Utility routine to check if the InetAddress is a wildcard address.
|
||||
* @return a {@code boolean} indicating if the Inetaddress is
|
||||
* @return a {@code boolean} indicating if the InetAddress is
|
||||
* a wildcard address.
|
||||
*/
|
||||
public boolean isAnyLocalAddress() {
|
||||
|
@ -415,7 +415,7 @@ class Inet6Address extends InetAddress {
|
||||
* set to the value corresponding to the given interface for the address
|
||||
* type specified in {@code addr}. The call will fail with an
|
||||
* UnknownHostException if the given interface does not have a numeric
|
||||
* scope_id assigned for the given address type (eg. link-local or site-local).
|
||||
* scope_id assigned for the given address type (e.g. link-local or site-local).
|
||||
* See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
|
||||
* scoped addresses.
|
||||
*
|
||||
@ -507,7 +507,7 @@ class Inet6Address extends InetAddress {
|
||||
|
||||
/* check the two Ipv6 addresses and return false if they are both
|
||||
* non global address types, but not the same.
|
||||
* (ie. one is sitelocal and the other linklocal)
|
||||
* (i.e. one is site-local and the other link-local)
|
||||
* return true otherwise.
|
||||
*/
|
||||
|
||||
@ -683,7 +683,7 @@ class Inet6Address extends InetAddress {
|
||||
/**
|
||||
* Utility routine to check if the InetAddress is a wildcard address.
|
||||
*
|
||||
* @return a {@code boolean} indicating if the Inetaddress is
|
||||
* @return a {@code boolean} indicating if the InetAddress is
|
||||
* a wildcard address.
|
||||
*/
|
||||
@Override
|
||||
@ -821,7 +821,7 @@ class Inet6Address extends InetAddress {
|
||||
|
||||
/**
|
||||
* Returns the scoped interface, if this instance was created with
|
||||
* with a scoped interface.
|
||||
* a scoped interface.
|
||||
*
|
||||
* @return the scoped interface, or null if not set.
|
||||
* @since 1.5
|
||||
|
@ -377,7 +377,7 @@ class InetAddress implements java.io.Serializable {
|
||||
|
||||
/**
|
||||
* Utility routine to check if the InetAddress is a wildcard address.
|
||||
* @return a {@code boolean} indicating if the Inetaddress is
|
||||
* @return a {@code boolean} indicating if the InetAddress is
|
||||
* a wildcard address.
|
||||
* @since 1.4
|
||||
*/
|
||||
@ -1022,7 +1022,7 @@ class InetAddress implements java.io.Serializable {
|
||||
* <p>Lookup a host mapping by name. Retrieve the IP addresses
|
||||
* associated with a host.
|
||||
*
|
||||
* <p>Search the configured hosts file for the addresses assocaited with
|
||||
* <p>Search the configured hosts file for the addresses associated
|
||||
* with the specified host name.
|
||||
*
|
||||
* @param host the specified hostname
|
||||
@ -1038,7 +1038,7 @@ class InetAddress implements java.io.Serializable {
|
||||
byte addr[] = new byte[4];
|
||||
ArrayList<InetAddress> inetAddresses = null;
|
||||
|
||||
// lookup the file and create a list InetAddress for the specfied host
|
||||
// lookup the file and create a list InetAddress for the specified host
|
||||
try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), "UTF-8")) {
|
||||
while (hostsFileScanner.hasNextLine()) {
|
||||
hostEntry = hostsFileScanner.nextLine();
|
||||
@ -1341,7 +1341,7 @@ class InetAddress implements java.io.Serializable {
|
||||
throw new UnknownHostException(host + ": invalid IPv6 address");
|
||||
}
|
||||
} else if (ipv6Expected) {
|
||||
// Means an IPv4 litteral between brackets!
|
||||
// Means an IPv4 literal between brackets!
|
||||
throw new UnknownHostException("["+host+"]");
|
||||
}
|
||||
InetAddress[] ret = new InetAddress[1];
|
||||
@ -1358,7 +1358,7 @@ class InetAddress implements java.io.Serializable {
|
||||
return ret;
|
||||
}
|
||||
} else if (ipv6Expected) {
|
||||
// We were expecting an IPv6 Litteral, but got something else
|
||||
// We were expecting an IPv6 Literal, but got something else
|
||||
throw new UnknownHostException("["+host+"]");
|
||||
}
|
||||
return getAllByName0(host, reqAddr, true, true);
|
||||
|
@ -170,7 +170,7 @@ public final class NetworkInterface {
|
||||
* a SecurityException will be returned in the List.
|
||||
*
|
||||
* @return a {@code List} object with all or a subset of the
|
||||
* InterfaceAddresss of this network interface
|
||||
* InterfaceAddress of this network interface
|
||||
* @since 1.6
|
||||
*/
|
||||
public java.util.List<InterfaceAddress> getInterfaceAddresses() {
|
||||
|
@ -136,7 +136,7 @@ public abstract class ProxySelector {
|
||||
* @param uri
|
||||
* The URI that a connection is required to
|
||||
*
|
||||
* @return a List of Proxies. Each element in the
|
||||
* @return a List of Proxies. Each element in
|
||||
* the List is of type
|
||||
* {@link java.net.Proxy Proxy};
|
||||
* when no proxy is available, the list will
|
||||
|
@ -91,7 +91,7 @@ public abstract class ResponseCache {
|
||||
/**
|
||||
* Sets (or unsets) the system-wide cache.
|
||||
*
|
||||
* Note: non-standard procotol handlers may ignore this setting.
|
||||
* Note: non-standard protocol handlers may ignore this setting.
|
||||
*
|
||||
* @param responseCache The response cache, or
|
||||
* {@code null} to unset the cache.
|
||||
|
@ -82,7 +82,7 @@ public abstract class SecureCacheResponse extends CacheResponse {
|
||||
* retrieved the network resource.
|
||||
*
|
||||
* @return the server's principal. Returns an X500Principal of the
|
||||
* end-entity certiticate for X509-based cipher suites, and
|
||||
* end-entity certificate for X509-based cipher suites, and
|
||||
* KerberosPrincipal for Kerberos cipher suites.
|
||||
*
|
||||
* @throws SSLPeerUnverifiedException if the peer was not verified.
|
||||
|
@ -166,7 +166,7 @@ class ServerSocket implements java.io.Closeable {
|
||||
* The {@code backlog} argument is the requested maximum number of
|
||||
* pending connections on the socket. Its exact semantics are implementation
|
||||
* specific. In particular, an implementation may impose a maximum length
|
||||
* or may choose to ignore the parameter altogther. The value provided
|
||||
* or may choose to ignore the parameter altogether. The value provided
|
||||
* should be greater than {@code 0}. If it is less than or equal to
|
||||
* {@code 0}, then an implementation specific default will be used.
|
||||
*
|
||||
@ -214,7 +214,7 @@ class ServerSocket implements java.io.Closeable {
|
||||
* The {@code backlog} argument is the requested maximum number of
|
||||
* pending connections on the socket. Its exact semantics are implementation
|
||||
* specific. In particular, an implementation may impose a maximum length
|
||||
* or may choose to ignore the parameter altogther. The value provided
|
||||
* or may choose to ignore the parameter altogether. The value provided
|
||||
* should be greater than {@code 0}. If it is less than or equal to
|
||||
* {@code 0}, then an implementation specific default will be used.
|
||||
*
|
||||
@ -351,7 +351,7 @@ class ServerSocket implements java.io.Closeable {
|
||||
* The {@code backlog} argument is the requested maximum number of
|
||||
* pending connections on the socket. Its exact semantics are implementation
|
||||
* specific. In particular, an implementation may impose a maximum length
|
||||
* or may choose to ignore the parameter altogther. The value provided
|
||||
* or may choose to ignore the parameter altogether. The value provided
|
||||
* should be greater than {@code 0}. If it is less than or equal to
|
||||
* {@code 0}, then an implementation specific default will be used.
|
||||
* @param endpoint The IP address and port number to bind to.
|
||||
@ -826,7 +826,7 @@ class ServerSocket implements java.io.Closeable {
|
||||
* <p>
|
||||
* The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is used both to
|
||||
* set the size of the internal socket receive buffer, and to set the size
|
||||
* of the TCP receive window that is advertized to the remote peer.
|
||||
* of the TCP receive window that is advertised to the remote peer.
|
||||
* <p>
|
||||
* It is possible to change the value subsequently, by calling
|
||||
* {@link Socket#setReceiveBufferSize(int)}. However, if the application
|
||||
|
@ -1237,7 +1237,7 @@ class Socket implements java.io.Closeable {
|
||||
* should call {@link #getReceiveBufferSize()}.
|
||||
*
|
||||
* <p>The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is also used
|
||||
* to set the TCP receive window that is advertized to the remote peer.
|
||||
* to set the TCP receive window that is advertised to the remote peer.
|
||||
* Generally, the window size can be modified at any time when a socket is
|
||||
* connected. However, if a receive window larger than 64K is required then
|
||||
* this must be requested <B>before</B> the socket is connected to the
|
||||
@ -1578,10 +1578,10 @@ class Socket implements java.io.Closeable {
|
||||
* <p>
|
||||
* Note: Closing a socket doesn't clear its connection state, which means
|
||||
* this method will return {@code true} for a closed socket
|
||||
* (see {@link #isClosed()}) if it was successfuly connected prior
|
||||
* (see {@link #isClosed()}) if it was successfully connected prior
|
||||
* to being closed.
|
||||
*
|
||||
* @return true if the socket was successfuly connected to a server
|
||||
* @return true if the socket was successfully connected to a server
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean isConnected() {
|
||||
@ -1594,10 +1594,10 @@ class Socket implements java.io.Closeable {
|
||||
* <p>
|
||||
* Note: Closing a socket doesn't clear its binding state, which means
|
||||
* this method will return {@code true} for a closed socket
|
||||
* (see {@link #isClosed()}) if it was successfuly bound prior
|
||||
* (see {@link #isClosed()}) if it was successfully bound prior
|
||||
* to being closed.
|
||||
*
|
||||
* @return true if the socket was successfuly bound to an address
|
||||
* @return true if the socket was successfully bound to an address
|
||||
* @since 1.4
|
||||
* @see #bind
|
||||
*/
|
||||
|
@ -51,7 +51,7 @@ class SocketOutputStream extends FileOutputStream {
|
||||
* Creates a new SocketOutputStream. Can only be called
|
||||
* by a Socket. This method needs to hang on to the owner Socket so
|
||||
* that the fd will not be closed.
|
||||
* @param impl the socket output stream inplemented
|
||||
* @param impl the socket output stream implemented
|
||||
*/
|
||||
SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException {
|
||||
super(impl.getFileDescriptor());
|
||||
|
@ -283,7 +283,7 @@ public final class SocketPermission extends Permission
|
||||
* nr = new SocketPermission("204.160.241.0:1024-65535", "connect");
|
||||
* </pre>
|
||||
*
|
||||
* @param host the hostname or IPaddress of the computer, optionally
|
||||
* @param host the hostname or IP address of the computer, optionally
|
||||
* including a colon followed by a port or port range.
|
||||
* @param action the action string.
|
||||
*/
|
||||
@ -317,7 +317,7 @@ public final class SocketPermission extends Permission
|
||||
if ((ind = host.indexOf(':')) != host.lastIndexOf(':')) {
|
||||
/* More than one ":", meaning IPv6 address is not
|
||||
* in RFC 2732 format;
|
||||
* We will rectify user errors for all unambiguious cases
|
||||
* We will rectify user errors for all unambiguous cases
|
||||
*/
|
||||
StringTokenizer st = new StringTokenizer(host, ":");
|
||||
int tokens = st.countTokens();
|
||||
@ -961,7 +961,7 @@ public final class SocketPermission extends Permission
|
||||
return (that.cname.endsWith(this.cname));
|
||||
}
|
||||
|
||||
// comapare IP addresses
|
||||
// compare IP addresses
|
||||
if (this.addresses == null) {
|
||||
this.getIP();
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
||||
private Socket cmdsock = null;
|
||||
private InputStream cmdIn = null;
|
||||
private OutputStream cmdOut = null;
|
||||
/* true if the Proxy has been set programatically */
|
||||
/* true if the Proxy has been set programmatically */
|
||||
private boolean applicationSetProxy; /* false */
|
||||
|
||||
|
||||
@ -145,7 +145,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the authentication machanism required by the proxy.
|
||||
* Provides the authentication mechanism required by the proxy.
|
||||
*/
|
||||
private boolean authenticate(byte method, InputStream in,
|
||||
BufferedOutputStream out) throws IOException {
|
||||
@ -158,7 +158,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
||||
// No Authentication required. We're done then!
|
||||
if (method == NO_AUTH)
|
||||
return true;
|
||||
/**
|
||||
/*
|
||||
* User/Password authentication. Try, in that order :
|
||||
* - The application provided Authenticator, if any
|
||||
* - the user.name & no password (backward compatibility behavior).
|
||||
@ -377,7 +377,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
||||
URI uri;
|
||||
// Use getHostString() to avoid reverse lookups
|
||||
String host = epoint.getHostString();
|
||||
// IPv6 litteral?
|
||||
// IPv6 literal?
|
||||
if (epoint.getAddress() instanceof Inet6Address &&
|
||||
(!host.startsWith("[")) && (host.indexOf(':') >= 0)) {
|
||||
host = "[" + host + "]";
|
||||
@ -692,7 +692,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
||||
URI uri;
|
||||
// Use getHostString() to avoid reverse lookups
|
||||
String host = saddr.getHostString();
|
||||
// IPv6 litteral?
|
||||
// IPv6 literal?
|
||||
if (saddr.getAddress() instanceof Inet6Address &&
|
||||
(!host.startsWith("[")) && (host.indexOf(':') >= 0)) {
|
||||
host = "[" + host + "]";
|
||||
|
@ -861,9 +861,9 @@ public final class URI
|
||||
*
|
||||
* <p> This method is provided for use in situations where it is known that
|
||||
* the given string is a legal URI, for example for URI constants declared
|
||||
* within in a program, and so it would be considered a programming error
|
||||
* within a program, and so it would be considered a programming error
|
||||
* for the string not to parse as such. The constructors, which throw
|
||||
* {@link URISyntaxException} directly, should be used situations where a
|
||||
* {@link URISyntaxException} directly, should be used in situations where a
|
||||
* URI is being constructed from user input or from some other source that
|
||||
* may be prone to errors. </p>
|
||||
*
|
||||
|
@ -1009,7 +1009,7 @@ public final class URL implements java.io.Serializable {
|
||||
* can not be converted to a URI.
|
||||
*
|
||||
* @exception URISyntaxException if this URL is not formatted strictly according to
|
||||
* to RFC2396 and cannot be converted to a URI.
|
||||
* RFC2396 and cannot be converted to a URI.
|
||||
*
|
||||
* @return a URI instance equivalent to this URL.
|
||||
* @since 1.5
|
||||
@ -1054,7 +1054,7 @@ public final class URL implements java.io.Serializable {
|
||||
/**
|
||||
* Same as {@link #openConnection()}, except that the connection will be
|
||||
* made through the specified proxy; Protocol handlers that do not
|
||||
* support proxing will ignore the proxy parameter and make a
|
||||
* support proxying will ignore the proxy parameter and make a
|
||||
* normal connection.
|
||||
*
|
||||
* Invoking this method preempts the system's default
|
||||
|
@ -109,7 +109,7 @@ public class URLEncoder {
|
||||
* list. It is also noteworthy that this is consistent with
|
||||
* O'Reilly's "HTML: The Definitive Guide" (page 164).
|
||||
*
|
||||
* As a last note, Intenet Explorer does not encode the "@"
|
||||
* As a last note, Internet Explorer does not encode the "@"
|
||||
* character which is clearly not unreserved according to the
|
||||
* RFC. We are being consistent with the RFC in this matter,
|
||||
* as is Netscape.
|
||||
|
@ -51,7 +51,7 @@ import java.security.Permission;
|
||||
* portrange = portnumber | -portnumber | portnumber-[portnumber] | *
|
||||
* hostrange = ([*.] dnsname) | IPv4address | IPv6address
|
||||
* </pre>
|
||||
* <i>dnsname</i> is a standard DNS host or domain name, ie. one or more labels
|
||||
* <i>dnsname</i> is a standard DNS host or domain name, i.e. one or more labels
|
||||
* separated by ".". <i>IPv4address</i> is a standard literal IPv4 address and
|
||||
* <i>IPv6address</i> is as defined in <a href="http://www.ietf.org/rfc/rfc2732.txt">
|
||||
* RFC 2732</a>. Literal IPv6 addresses must however, be enclosed in '[]' characters.
|
||||
@ -89,7 +89,7 @@ import java.security.Permission;
|
||||
* </tr>
|
||||
* <tr><th scope="row">http://www.oracle.com/a/b/-</th>
|
||||
* <td>The '-' character refers to all resources recursively below the
|
||||
* preceding path (eg. http://www.oracle.com/a/b/c/d/e.html matches this
|
||||
* preceding path (e.g. http://www.oracle.com/a/b/c/d/e.html matches this
|
||||
* example).
|
||||
* </td>
|
||||
* </tr>
|
||||
|
@ -250,15 +250,15 @@ public abstract class URLStreamHandler {
|
||||
} else if (path != null && path.length() > 0) {
|
||||
isRelPath = true;
|
||||
int ind = path.lastIndexOf('/');
|
||||
String seperator = "";
|
||||
String separator = "";
|
||||
if (ind == -1 && authority != null)
|
||||
seperator = "/";
|
||||
path = path.substring(0, ind + 1) + seperator +
|
||||
separator = "/";
|
||||
path = path.substring(0, ind + 1) + separator +
|
||||
spec.substring(start, limit);
|
||||
|
||||
} else {
|
||||
String seperator = (authority != null) ? "/" : "";
|
||||
path = seperator + spec.substring(start, limit);
|
||||
String separator = (authority != null) ? "/" : "";
|
||||
path = separator + spec.substring(start, limit);
|
||||
}
|
||||
} else if (queryOnly && path != null) {
|
||||
int ind = path.lastIndexOf('/');
|
||||
@ -314,7 +314,7 @@ public abstract class URLStreamHandler {
|
||||
|
||||
/**
|
||||
* Returns the default port for a URL parsed by this handler. This method
|
||||
* is meant to be overidden by handlers with default port numbers.
|
||||
* is meant to be overridden by handlers with default port numbers.
|
||||
* @return the default port for a {@code URL} parsed by this handler.
|
||||
* @since 1.3
|
||||
*/
|
||||
@ -323,14 +323,14 @@ public abstract class URLStreamHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the default equals calculation. May be overidden by handlers
|
||||
* Provides the default equals calculation. May be overridden by handlers
|
||||
* for other protocols that have different requirements for equals().
|
||||
* This method requires that none of its arguments is null. This is
|
||||
* guaranteed by the fact that it is only called by java.net.URL class.
|
||||
* @param u1 a URL object
|
||||
* @param u2 a URL object
|
||||
* @return {@code true} if the two urls are
|
||||
* considered equal, ie. they refer to the same
|
||||
* considered equal, i.e. they refer to the same
|
||||
* fragment in the same file.
|
||||
* @since 1.3
|
||||
*/
|
||||
@ -342,7 +342,7 @@ public abstract class URLStreamHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the default hash calculation. May be overidden by handlers for
|
||||
* Provides the default hash calculation. May be overridden by handlers for
|
||||
* other protocols that have different requirements for hashCode
|
||||
* calculation.
|
||||
* @param u a URL object
|
||||
|
@ -30,7 +30,7 @@ import java.net.URLStreamHandlerFactory;
|
||||
/**
|
||||
* URL stream handler service-provider class.
|
||||
*
|
||||
*<p> A URL stream handler provider is a concrete subclass of this class that
|
||||
* <p> A URL stream handler provider is a concrete subclass of this class that
|
||||
* has a zero-argument constructor. URL stream handler providers may be
|
||||
* installed in an instance of the Java platform by adding them to the
|
||||
* application class path.
|
||||
|
@ -177,7 +177,7 @@ public interface MulticastChannel
|
||||
* @throws SecurityException
|
||||
* If a security manager is set, and its
|
||||
* {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
|
||||
* method denies access to the multiast group
|
||||
* method denies access to the multicast group
|
||||
*/
|
||||
MembershipKey join(InetAddress group, NetworkInterface interf)
|
||||
throws IOException;
|
||||
@ -226,7 +226,7 @@ public interface MulticastChannel
|
||||
* @throws SecurityException
|
||||
* If a security manager is set, and its
|
||||
* {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
|
||||
* method denies access to the multiast group
|
||||
* method denies access to the multicast group
|
||||
*/
|
||||
MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source)
|
||||
throws IOException;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2018, 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
|
||||
@ -153,7 +153,7 @@ public final class ModuleInfoExtender {
|
||||
|
||||
ClassReader cr = new ClassReader(in);
|
||||
|
||||
ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) {
|
||||
ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) {
|
||||
@Override
|
||||
public ModuleVisitor visitModule(String name, int flags, String version) {
|
||||
Version v = ModuleInfoExtender.this.version;
|
||||
@ -170,7 +170,7 @@ public final class ModuleInfoExtender {
|
||||
packages.forEach(pn -> mv.visitPackage(pn.replace('.', '/')));
|
||||
}
|
||||
|
||||
return new ModuleVisitor(Opcodes.ASM6, mv) {
|
||||
return new ModuleVisitor(Opcodes.ASM7, mv) {
|
||||
public void visitMainClass(String existingMainClass) {
|
||||
// skip main class if there is a new value
|
||||
if (mainClass == null) {
|
||||
|
@ -59,9 +59,9 @@
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* A visitor to visit a Java annotation. The methods of this class must be
|
||||
* called in the following order: ( <tt>visit</tt> | <tt>visitEnum</tt> |
|
||||
* <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>.
|
||||
* A visitor to visit a Java annotation. The methods of this class must be called in the following
|
||||
* order: ( {@code visit} | {@code visitEnum} | {@code visitAnnotation} | {@code visitArray} )*
|
||||
* {@code visitEnd}.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
* @author Eugene Kuleshov
|
||||
@ -69,127 +69,105 @@ package jdk.internal.org.objectweb.asm;
|
||||
public abstract class AnnotationVisitor {
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field
|
||||
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
* The ASM API version implemented by this visitor. The value of this field must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/**
|
||||
* The annotation visitor to which this visitor must delegate method calls.
|
||||
* May be null.
|
||||
*/
|
||||
/** The annotation visitor to which this visitor must delegate method calls. May be null. */
|
||||
protected AnnotationVisitor av;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link AnnotationVisitor}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
* Constructs a new {@link AnnotationVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
*/
|
||||
public AnnotationVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link AnnotationVisitor}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
* @param av
|
||||
* the annotation visitor to which this visitor must delegate
|
||||
* method calls. May be null.
|
||||
*/
|
||||
public AnnotationVisitor(final int api, final AnnotationVisitor av) {
|
||||
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
|
||||
* Constructs a new {@link AnnotationVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* @param annotationVisitor the annotation visitor to which this visitor must delegate method
|
||||
* calls. May be null.
|
||||
*/
|
||||
public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
|
||||
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.api = api;
|
||||
this.av = av;
|
||||
this.av = annotationVisitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a primitive value of the annotation.
|
||||
*
|
||||
* @param name
|
||||
* the value name.
|
||||
* @param value
|
||||
* the actual value, whose type must be {@link Byte},
|
||||
* {@link Boolean}, {@link Character}, {@link Short},
|
||||
* {@link Integer} , {@link Long}, {@link Float}, {@link Double},
|
||||
* {@link String} or {@link Type} of OBJECT or ARRAY sort. This
|
||||
* value can also be an array of byte, boolean, short, char, int,
|
||||
* long, float or double values (this is equivalent to using
|
||||
* {@link #visitArray visitArray} and visiting each array element
|
||||
* in turn, but is more convenient).
|
||||
*/
|
||||
public void visit(String name, Object value) {
|
||||
* Visits a primitive value of the annotation.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link
|
||||
* Character}, {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double},
|
||||
* {@link String} or {@link Type} of {@link Type#OBJECT} or {@link Type#ARRAY} sort. This
|
||||
* value can also be an array of byte, boolean, short, char, int, long, float or double values
|
||||
* (this is equivalent to using {@link #visitArray} and visiting each array element in turn,
|
||||
* but is more convenient).
|
||||
*/
|
||||
public void visit(final String name, final Object value) {
|
||||
if (av != null) {
|
||||
av.visit(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an enumeration value of the annotation.
|
||||
*
|
||||
* @param name
|
||||
* the value name.
|
||||
* @param desc
|
||||
* the class descriptor of the enumeration class.
|
||||
* @param value
|
||||
* the actual enumeration value.
|
||||
*/
|
||||
public void visitEnum(String name, String desc, String value) {
|
||||
* Visits an enumeration value of the annotation.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @param descriptor the class descriptor of the enumeration class.
|
||||
* @param value the actual enumeration value.
|
||||
*/
|
||||
public void visitEnum(final String name, final String descriptor, final String value) {
|
||||
if (av != null) {
|
||||
av.visitEnum(name, desc, value);
|
||||
av.visitEnum(name, descriptor, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a nested annotation value of the annotation.
|
||||
*
|
||||
* @param name
|
||||
* the value name.
|
||||
* @param desc
|
||||
* the class descriptor of the nested annotation class.
|
||||
* @return a visitor to visit the actual nested annotation value, or
|
||||
* <tt>null</tt> if this visitor is not interested in visiting this
|
||||
* nested annotation. <i>The nested annotation value must be fully
|
||||
* visited before calling other methods on this annotation
|
||||
* visitor</i>.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
||||
* Visits a nested annotation value of the annotation.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @param descriptor the class descriptor of the nested annotation class.
|
||||
* @return a visitor to visit the actual nested annotation value, or {@literal null} if this
|
||||
* visitor is not interested in visiting this nested annotation. <i>The nested annotation
|
||||
* value must be fully visited before calling other methods on this annotation visitor</i>.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
|
||||
if (av != null) {
|
||||
return av.visitAnnotation(name, desc);
|
||||
return av.visitAnnotation(name, descriptor);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an array value of the annotation. Note that arrays of primitive
|
||||
* types (such as byte, boolean, short, char, int, long, float or double)
|
||||
* can be passed as value to {@link #visit visit}. This is what
|
||||
* {@link ClassReader} does.
|
||||
*
|
||||
* @param name
|
||||
* the value name.
|
||||
* @return a visitor to visit the actual array value elements, or
|
||||
* <tt>null</tt> if this visitor is not interested in visiting these
|
||||
* values. The 'name' parameters passed to the methods of this
|
||||
* visitor are ignored. <i>All the array values must be visited
|
||||
* before calling other methods on this annotation visitor</i>.
|
||||
*/
|
||||
public AnnotationVisitor visitArray(String name) {
|
||||
* Visits an array value of the annotation. Note that arrays of primitive types (such as byte,
|
||||
* boolean, short, char, int, long, float or double) can be passed as value to {@link #visit
|
||||
* visit}. This is what {@link ClassReader} does.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @return a visitor to visit the actual array value elements, or {@literal null} if this visitor
|
||||
* is not interested in visiting these values. The 'name' parameters passed to the methods of
|
||||
* this visitor are ignored. <i>All the array values must be visited before calling other
|
||||
* methods on this annotation visitor</i>.
|
||||
*/
|
||||
public AnnotationVisitor visitArray(final String name) {
|
||||
if (av != null) {
|
||||
return av.visitArray(name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the end of the annotation.
|
||||
*/
|
||||
/** Visits the end of the annotation. */
|
||||
public void visitEnd() {
|
||||
if (av != null) {
|
||||
av.visitEnd();
|
||||
|
@ -59,342 +59,391 @@
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* An {@link AnnotationVisitor} that generates annotations in bytecode form.
|
||||
* An {@link AnnotationVisitor} that generates a corresponding 'annotation' or 'type_annotation'
|
||||
* structure, as defined in the Java Virtual Machine Specification (JVMS). AnnotationWriter
|
||||
* instances can be chained in a doubly linked list, from which Runtime[In]Visible[Type]Annotations
|
||||
* attributes can be generated with the {@link #putAnnotations} method. Similarly, arrays of such
|
||||
* lists can be used to generate Runtime[In]VisibleParameterAnnotations attributes.
|
||||
*
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16">JVMS
|
||||
* 4.7.16</a>
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20">JVMS
|
||||
* 4.7.20</a>
|
||||
* @author Eric Bruneton
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
final class AnnotationWriter extends AnnotationVisitor {
|
||||
|
||||
/**
|
||||
* The class writer to which this annotation must be added.
|
||||
*/
|
||||
private final ClassWriter cw;
|
||||
/** Where the constants used in this AnnotationWriter must be stored. */
|
||||
private final SymbolTable symbolTable;
|
||||
|
||||
/**
|
||||
* The number of values in this annotation.
|
||||
*/
|
||||
private int size;
|
||||
* Whether values are named or not. AnnotationWriter instances used for annotation default and
|
||||
* annotation arrays use unnamed values (i.e. they generate an 'element_value' structure for each
|
||||
* value, instead of an element_name_index followed by an element_value).
|
||||
*/
|
||||
private final boolean useNamedValues;
|
||||
|
||||
/**
|
||||
* <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
|
||||
* writers used for annotation default and annotation arrays use unnamed
|
||||
* values.
|
||||
*/
|
||||
private final boolean named;
|
||||
* The 'annotation' or 'type_annotation' JVMS structure corresponding to the annotation values
|
||||
* visited so far. All the fields of these structures, except the last one - the
|
||||
* element_value_pairs array, must be set before this ByteVector is passed to the constructor
|
||||
* (num_element_value_pairs can be set to 0, it is reset to the correct value in {@link
|
||||
* #visitEnd()}). The element_value_pairs array is filled incrementally in the various visit()
|
||||
* methods.
|
||||
*
|
||||
* <p>Note: as an exception to the above rules, for AnnotationDefault attributes (which contain a
|
||||
* single element_value by definition), this ByteVector is initially empty when passed to the
|
||||
* constructor, and {@link #numElementValuePairsOffset} is set to -1.
|
||||
*/
|
||||
private final ByteVector annotation;
|
||||
|
||||
/**
|
||||
* The annotation values in bytecode form. This byte vector only contains
|
||||
* the values themselves, i.e. the number of values must be stored as a
|
||||
* unsigned short just before these bytes.
|
||||
*/
|
||||
private final ByteVector bv;
|
||||
* The offset in {@link #annotation} where {@link #numElementValuePairs} must be stored (or -1 for
|
||||
* the case of AnnotationDefault attributes).
|
||||
*/
|
||||
private final int numElementValuePairsOffset;
|
||||
|
||||
/** The number of element value pairs visited so far. */
|
||||
private int numElementValuePairs;
|
||||
|
||||
/**
|
||||
* The byte vector to be used to store the number of values of this
|
||||
* annotation. See {@link #bv}.
|
||||
*/
|
||||
private final ByteVector parent;
|
||||
* The previous AnnotationWriter. This field is used to store the list of annotations of a
|
||||
* Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations
|
||||
* (annotation values of annotation type), or for AnnotationDefault attributes.
|
||||
*/
|
||||
private final AnnotationWriter previousAnnotation;
|
||||
|
||||
/**
|
||||
* Where the number of values of this annotation must be stored in
|
||||
* {@link #parent}.
|
||||
*/
|
||||
private final int offset;
|
||||
* The next AnnotationWriter. This field is used to store the list of annotations of a
|
||||
* Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations
|
||||
* (annotation values of annotation type), or for AnnotationDefault attributes.
|
||||
*/
|
||||
private AnnotationWriter nextAnnotation;
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Constructors
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Next annotation writer. This field is used to store annotation lists.
|
||||
*/
|
||||
AnnotationWriter next;
|
||||
|
||||
/**
|
||||
* Previous annotation writer. This field is used to store annotation lists.
|
||||
*/
|
||||
AnnotationWriter prev;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a new {@link AnnotationWriter}.
|
||||
*
|
||||
* @param cw
|
||||
* the class writer to which this annotation must be added.
|
||||
* @param named
|
||||
* <tt>true<tt> if values are named, <tt>false</tt> otherwise.
|
||||
* @param bv
|
||||
* where the annotation values must be stored.
|
||||
* @param parent
|
||||
* where the number of annotation values must be stored.
|
||||
* @param offset
|
||||
* where in <tt>parent</tt> the number of annotation values must
|
||||
* be stored.
|
||||
*/
|
||||
AnnotationWriter(final ClassWriter cw, final boolean named,
|
||||
final ByteVector bv, final ByteVector parent, final int offset) {
|
||||
super(Opcodes.ASM6);
|
||||
this.cw = cw;
|
||||
this.named = named;
|
||||
this.bv = bv;
|
||||
this.parent = parent;
|
||||
this.offset = offset;
|
||||
* Constructs a new {@link AnnotationWriter}.
|
||||
*
|
||||
* @param symbolTable where the constants used in this AnnotationWriter must be stored.
|
||||
* @param useNamedValues whether values are named or not. AnnotationDefault and annotation arrays
|
||||
* use unnamed values.
|
||||
* @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to
|
||||
* the visited content must be stored. This ByteVector must already contain all the fields of
|
||||
* the structure except the last one (the element_value_pairs array).
|
||||
* @param previousAnnotation the previously visited annotation of the
|
||||
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
|
||||
* other cases (e.g. nested or array annotations).
|
||||
*/
|
||||
AnnotationWriter(
|
||||
final SymbolTable symbolTable,
|
||||
final boolean useNamedValues,
|
||||
final ByteVector annotation,
|
||||
final AnnotationWriter previousAnnotation) {
|
||||
super(Opcodes.ASM7);
|
||||
this.symbolTable = symbolTable;
|
||||
this.useNamedValues = useNamedValues;
|
||||
this.annotation = annotation;
|
||||
// By hypothesis, num_element_value_pairs is stored in the last unsigned short of 'annotation'.
|
||||
this.numElementValuePairsOffset = annotation.length == 0 ? -1 : annotation.length - 2;
|
||||
this.previousAnnotation = previousAnnotation;
|
||||
if (previousAnnotation != null) {
|
||||
previousAnnotation.nextAnnotation = this;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/**
|
||||
* Constructs a new {@link AnnotationWriter} using named values.
|
||||
*
|
||||
* @param symbolTable where the constants used in this AnnotationWriter must be stored.
|
||||
* @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to
|
||||
* the visited content must be stored. This ByteVector must already contain all the fields of
|
||||
* the structure except the last one (the element_value_pairs array).
|
||||
* @param previousAnnotation the previously visited annotation of the
|
||||
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
|
||||
* other cases (e.g. nested or array annotations).
|
||||
*/
|
||||
AnnotationWriter(
|
||||
final SymbolTable symbolTable,
|
||||
final ByteVector annotation,
|
||||
final AnnotationWriter previousAnnotation) {
|
||||
this(symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Implementation of the AnnotationVisitor abstract class
|
||||
// ------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void visit(final String name, final Object value) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
// Case of an element_value with a const_value_index, class_info_index or array_index field.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
|
||||
++numElementValuePairs;
|
||||
if (useNamedValues) {
|
||||
annotation.putShort(symbolTable.addConstantUtf8(name));
|
||||
}
|
||||
if (value instanceof String) {
|
||||
bv.put12('s', cw.newUTF8((String) value));
|
||||
annotation.put12('s', symbolTable.addConstantUtf8((String) value));
|
||||
} else if (value instanceof Byte) {
|
||||
bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
|
||||
annotation.put12('B', symbolTable.addConstantInteger(((Byte) value).byteValue()).index);
|
||||
} else if (value instanceof Boolean) {
|
||||
int v = ((Boolean) value).booleanValue() ? 1 : 0;
|
||||
bv.put12('Z', cw.newInteger(v).index);
|
||||
int booleanValue = ((Boolean) value).booleanValue() ? 1 : 0;
|
||||
annotation.put12('Z', symbolTable.addConstantInteger(booleanValue).index);
|
||||
} else if (value instanceof Character) {
|
||||
bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
|
||||
annotation.put12('C', symbolTable.addConstantInteger(((Character) value).charValue()).index);
|
||||
} else if (value instanceof Short) {
|
||||
bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
|
||||
annotation.put12('S', symbolTable.addConstantInteger(((Short) value).shortValue()).index);
|
||||
} else if (value instanceof Type) {
|
||||
bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
|
||||
annotation.put12('c', symbolTable.addConstantUtf8(((Type) value).getDescriptor()));
|
||||
} else if (value instanceof byte[]) {
|
||||
byte[] v = (byte[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('B', cw.newInteger(v[i]).index);
|
||||
byte[] byteArray = (byte[]) value;
|
||||
annotation.put12('[', byteArray.length);
|
||||
for (byte byteValue : byteArray) {
|
||||
annotation.put12('B', symbolTable.addConstantInteger(byteValue).index);
|
||||
}
|
||||
} else if (value instanceof boolean[]) {
|
||||
boolean[] v = (boolean[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
|
||||
boolean[] booleanArray = (boolean[]) value;
|
||||
annotation.put12('[', booleanArray.length);
|
||||
for (boolean booleanValue : booleanArray) {
|
||||
annotation.put12('Z', symbolTable.addConstantInteger(booleanValue ? 1 : 0).index);
|
||||
}
|
||||
} else if (value instanceof short[]) {
|
||||
short[] v = (short[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('S', cw.newInteger(v[i]).index);
|
||||
short[] shortArray = (short[]) value;
|
||||
annotation.put12('[', shortArray.length);
|
||||
for (short shortValue : shortArray) {
|
||||
annotation.put12('S', symbolTable.addConstantInteger(shortValue).index);
|
||||
}
|
||||
} else if (value instanceof char[]) {
|
||||
char[] v = (char[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('C', cw.newInteger(v[i]).index);
|
||||
char[] charArray = (char[]) value;
|
||||
annotation.put12('[', charArray.length);
|
||||
for (char charValue : charArray) {
|
||||
annotation.put12('C', symbolTable.addConstantInteger(charValue).index);
|
||||
}
|
||||
} else if (value instanceof int[]) {
|
||||
int[] v = (int[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('I', cw.newInteger(v[i]).index);
|
||||
int[] intArray = (int[]) value;
|
||||
annotation.put12('[', intArray.length);
|
||||
for (int intValue : intArray) {
|
||||
annotation.put12('I', symbolTable.addConstantInteger(intValue).index);
|
||||
}
|
||||
} else if (value instanceof long[]) {
|
||||
long[] v = (long[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('J', cw.newLong(v[i]).index);
|
||||
long[] longArray = (long[]) value;
|
||||
annotation.put12('[', longArray.length);
|
||||
for (long longValue : longArray) {
|
||||
annotation.put12('J', symbolTable.addConstantLong(longValue).index);
|
||||
}
|
||||
} else if (value instanceof float[]) {
|
||||
float[] v = (float[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('F', cw.newFloat(v[i]).index);
|
||||
float[] floatArray = (float[]) value;
|
||||
annotation.put12('[', floatArray.length);
|
||||
for (float floatValue : floatArray) {
|
||||
annotation.put12('F', symbolTable.addConstantFloat(floatValue).index);
|
||||
}
|
||||
} else if (value instanceof double[]) {
|
||||
double[] v = (double[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('D', cw.newDouble(v[i]).index);
|
||||
double[] doubleArray = (double[]) value;
|
||||
annotation.put12('[', doubleArray.length);
|
||||
for (double doubleValue : doubleArray) {
|
||||
annotation.put12('D', symbolTable.addConstantDouble(doubleValue).index);
|
||||
}
|
||||
} else {
|
||||
Item i = cw.newConstItem(value);
|
||||
bv.put12(".s.IFJDCS".charAt(i.type), i.index);
|
||||
Symbol symbol = symbolTable.addConstant(value);
|
||||
annotation.put12(".s.IFJDCS".charAt(symbol.tag), symbol.index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(final String name, final String desc,
|
||||
final String value) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
public void visitEnum(final String name, final String descriptor, final String value) {
|
||||
// Case of an element_value with an enum_const_value field.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
|
||||
++numElementValuePairs;
|
||||
if (useNamedValues) {
|
||||
annotation.putShort(symbolTable.addConstantUtf8(name));
|
||||
}
|
||||
bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
|
||||
annotation
|
||||
.put12('e', symbolTable.addConstantUtf8(descriptor))
|
||||
.putShort(symbolTable.addConstantUtf8(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String name,
|
||||
final String desc) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
|
||||
// Case of an element_value with an annotation_value field.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
|
||||
++numElementValuePairs;
|
||||
if (useNamedValues) {
|
||||
annotation.putShort(symbolTable.addConstantUtf8(name));
|
||||
}
|
||||
// write tag and type, and reserve space for values count
|
||||
bv.put12('@', cw.newUTF8(desc)).putShort(0);
|
||||
return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
|
||||
// Write tag and type_index, and reserve 2 bytes for num_element_value_pairs.
|
||||
annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
return new AnnotationWriter(symbolTable, annotation, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(final String name) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
// Case of an element_value with an array_value field.
|
||||
// https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1
|
||||
++numElementValuePairs;
|
||||
if (useNamedValues) {
|
||||
annotation.putShort(symbolTable.addConstantUtf8(name));
|
||||
}
|
||||
// write tag, and reserve space for array size
|
||||
bv.put12('[', 0);
|
||||
return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
|
||||
// Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the
|
||||
// end of an element_value of array type is similar to the end of an 'annotation' structure: an
|
||||
// unsigned short num_values followed by num_values element_value, versus an unsigned short
|
||||
// num_element_value_pairs, followed by num_element_value_pairs { element_name_index,
|
||||
// element_value } tuples. This allows us to use an AnnotationWriter with unnamed values to
|
||||
// visit the array elements. Its num_element_value_pairs will correspond to the number of array
|
||||
// elements and will be stored in what is in fact num_values.
|
||||
annotation.put12('[', 0);
|
||||
return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, annotation, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (parent != null) {
|
||||
byte[] data = parent.data;
|
||||
data[offset] = (byte) (size >>> 8);
|
||||
data[offset + 1] = (byte) size;
|
||||
if (numElementValuePairsOffset != -1) {
|
||||
byte[] data = annotation.data;
|
||||
data[numElementValuePairsOffset] = (byte) (numElementValuePairs >>> 8);
|
||||
data[numElementValuePairsOffset + 1] = (byte) numElementValuePairs;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the size of this annotation writer list.
|
||||
*
|
||||
* @return the size of this annotation writer list.
|
||||
*/
|
||||
int getSize() {
|
||||
int size = 0;
|
||||
AnnotationWriter aw = this;
|
||||
while (aw != null) {
|
||||
size += aw.bv.length;
|
||||
aw = aw.next;
|
||||
* Returns the size of a Runtime[In]Visible[Type]Annotations attribute containing this annotation
|
||||
* and all its <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the attribute name
|
||||
* to the constant pool of the class (if not null).
|
||||
*
|
||||
* @param attributeName one of "Runtime[In]Visible[Type]Annotations", or null.
|
||||
* @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this
|
||||
* annotation and all its predecessors. This includes the size of the attribute_name_index and
|
||||
* attribute_length fields.
|
||||
*/
|
||||
int computeAnnotationsSize(final String attributeName) {
|
||||
if (attributeName != null) {
|
||||
symbolTable.addConstantUtf8(attributeName);
|
||||
}
|
||||
return size;
|
||||
// The attribute_name_index, attribute_length and num_annotations fields use 8 bytes.
|
||||
int attributeSize = 8;
|
||||
AnnotationWriter annotationWriter = this;
|
||||
while (annotationWriter != null) {
|
||||
attributeSize += annotationWriter.annotation.length;
|
||||
annotationWriter = annotationWriter.previousAnnotation;
|
||||
}
|
||||
return attributeSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the annotations of this annotation writer list into the given byte
|
||||
* vector.
|
||||
*
|
||||
* @param out
|
||||
* where the annotations must be put.
|
||||
*/
|
||||
void put(final ByteVector out) {
|
||||
int n = 0;
|
||||
int size = 2;
|
||||
AnnotationWriter aw = this;
|
||||
AnnotationWriter last = null;
|
||||
while (aw != null) {
|
||||
++n;
|
||||
size += aw.bv.length;
|
||||
aw.visitEnd(); // in case user forgot to call visitEnd
|
||||
aw.prev = last;
|
||||
last = aw;
|
||||
aw = aw.next;
|
||||
* Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its
|
||||
* <i>predecessors</i> (see {@link #previousAnnotation} in the given ByteVector. Annotations are
|
||||
* put in the same order they have been visited.
|
||||
*
|
||||
* @param attributeNameIndex the constant pool index of the attribute name (one of
|
||||
* "Runtime[In]Visible[Type]Annotations").
|
||||
* @param output where the attribute must be put.
|
||||
*/
|
||||
void putAnnotations(final int attributeNameIndex, final ByteVector output) {
|
||||
int attributeLength = 2; // For num_annotations.
|
||||
int numAnnotations = 0;
|
||||
AnnotationWriter annotationWriter = this;
|
||||
AnnotationWriter firstAnnotation = null;
|
||||
while (annotationWriter != null) {
|
||||
// In case the user forgot to call visitEnd().
|
||||
annotationWriter.visitEnd();
|
||||
attributeLength += annotationWriter.annotation.length;
|
||||
numAnnotations++;
|
||||
firstAnnotation = annotationWriter;
|
||||
annotationWriter = annotationWriter.previousAnnotation;
|
||||
}
|
||||
out.putInt(size);
|
||||
out.putShort(n);
|
||||
aw = last;
|
||||
while (aw != null) {
|
||||
out.putByteArray(aw.bv.data, 0, aw.bv.length);
|
||||
aw = aw.prev;
|
||||
output.putShort(attributeNameIndex);
|
||||
output.putInt(attributeLength);
|
||||
output.putShort(numAnnotations);
|
||||
annotationWriter = firstAnnotation;
|
||||
while (annotationWriter != null) {
|
||||
output.putByteArray(annotationWriter.annotation.data, 0, annotationWriter.annotation.length);
|
||||
annotationWriter = annotationWriter.nextAnnotation;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given annotation lists into the given byte vector.
|
||||
*
|
||||
* @param panns
|
||||
* an array of annotation writer lists.
|
||||
* @param off
|
||||
* index of the first annotation to be written.
|
||||
* @param out
|
||||
* where the annotations must be put.
|
||||
*/
|
||||
static void put(final AnnotationWriter[] panns, final int off,
|
||||
final ByteVector out) {
|
||||
int size = 1 + 2 * (panns.length - off);
|
||||
for (int i = off; i < panns.length; ++i) {
|
||||
size += panns[i] == null ? 0 : panns[i].getSize();
|
||||
* Returns the size of a Runtime[In]VisibleParameterAnnotations attribute containing all the
|
||||
* annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the
|
||||
* constant pool of the class.
|
||||
*
|
||||
* @param attributeName one of "Runtime[In]VisibleParameterAnnotations".
|
||||
* @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
|
||||
* element).
|
||||
* @param annotableParameterCount the number of elements in annotationWriters to take into account
|
||||
* (elements [0..annotableParameterCount[ are taken into account).
|
||||
* @return the size in bytes of a Runtime[In]VisibleParameterAnnotations attribute corresponding
|
||||
* to the given sub-array of AnnotationWriter lists. This includes the size of the
|
||||
* attribute_name_index and attribute_length fields.
|
||||
*/
|
||||
static int computeParameterAnnotationsSize(
|
||||
final String attributeName,
|
||||
final AnnotationWriter[] annotationWriters,
|
||||
final int annotableParameterCount) {
|
||||
// Note: attributeName is added to the constant pool by the call to computeAnnotationsSize
|
||||
// below. This assumes that there is at least one non-null element in the annotationWriters
|
||||
// sub-array (which is ensured by the lazy instantiation of this array in MethodWriter).
|
||||
// The attribute_name_index, attribute_length and num_parameters fields use 7 bytes, and each
|
||||
// element of the parameter_annotations array uses 2 bytes for its num_annotations field.
|
||||
int attributeSize = 7 + 2 * annotableParameterCount;
|
||||
for (int i = 0; i < annotableParameterCount; ++i) {
|
||||
AnnotationWriter annotationWriter = annotationWriters[i];
|
||||
attributeSize +=
|
||||
annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(attributeName) - 8;
|
||||
}
|
||||
out.putInt(size).putByte(panns.length - off);
|
||||
for (int i = off; i < panns.length; ++i) {
|
||||
AnnotationWriter aw = panns[i];
|
||||
AnnotationWriter last = null;
|
||||
int n = 0;
|
||||
while (aw != null) {
|
||||
++n;
|
||||
aw.visitEnd(); // in case user forgot to call visitEnd
|
||||
aw.prev = last;
|
||||
last = aw;
|
||||
aw = aw.next;
|
||||
return attributeSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a Runtime[In]VisibleParameterAnnotations attribute containing all the annotation lists
|
||||
* from the given AnnotationWriter sub-array in the given ByteVector.
|
||||
*
|
||||
* @param attributeNameIndex constant pool index of the attribute name (one of
|
||||
* Runtime[In]VisibleParameterAnnotations).
|
||||
* @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
|
||||
* element).
|
||||
* @param annotableParameterCount the number of elements in annotationWriters to put (elements
|
||||
* [0..annotableParameterCount[ are put).
|
||||
* @param output where the attribute must be put.
|
||||
*/
|
||||
static void putParameterAnnotations(
|
||||
final int attributeNameIndex,
|
||||
final AnnotationWriter[] annotationWriters,
|
||||
final int annotableParameterCount,
|
||||
final ByteVector output) {
|
||||
// The num_parameters field uses 1 byte, and each element of the parameter_annotations array
|
||||
// uses 2 bytes for its num_annotations field.
|
||||
int attributeLength = 1 + 2 * annotableParameterCount;
|
||||
for (int i = 0; i < annotableParameterCount; ++i) {
|
||||
AnnotationWriter annotationWriter = annotationWriters[i];
|
||||
attributeLength +=
|
||||
annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(null) - 8;
|
||||
}
|
||||
output.putShort(attributeNameIndex);
|
||||
output.putInt(attributeLength);
|
||||
output.putByte(annotableParameterCount);
|
||||
for (int i = 0; i < annotableParameterCount; ++i) {
|
||||
AnnotationWriter annotationWriter = annotationWriters[i];
|
||||
AnnotationWriter firstAnnotation = null;
|
||||
int numAnnotations = 0;
|
||||
while (annotationWriter != null) {
|
||||
// In case user the forgot to call visitEnd().
|
||||
annotationWriter.visitEnd();
|
||||
numAnnotations++;
|
||||
firstAnnotation = annotationWriter;
|
||||
annotationWriter = annotationWriter.previousAnnotation;
|
||||
}
|
||||
out.putShort(n);
|
||||
aw = last;
|
||||
while (aw != null) {
|
||||
out.putByteArray(aw.bv.data, 0, aw.bv.length);
|
||||
aw = aw.prev;
|
||||
output.putShort(numAnnotations);
|
||||
annotationWriter = firstAnnotation;
|
||||
while (annotationWriter != null) {
|
||||
output.putByteArray(
|
||||
annotationWriter.annotation.data, 0, annotationWriter.annotation.length);
|
||||
annotationWriter = annotationWriter.nextAnnotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given type reference and type path into the given bytevector.
|
||||
* LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
|
||||
*
|
||||
* @param typeRef
|
||||
* a reference to the annotated type. See {@link TypeReference}.
|
||||
* @param typePath
|
||||
* the path to the annotated type argument, wildcard bound, array
|
||||
* element type, or static inner type within 'typeRef'. May be
|
||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param out
|
||||
* where the type reference and type path must be put.
|
||||
*/
|
||||
static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
|
||||
switch (typeRef >>> 24) {
|
||||
case 0x00: // CLASS_TYPE_PARAMETER
|
||||
case 0x01: // METHOD_TYPE_PARAMETER
|
||||
case 0x16: // METHOD_FORMAL_PARAMETER
|
||||
out.putShort(typeRef >>> 16);
|
||||
break;
|
||||
case 0x13: // FIELD
|
||||
case 0x14: // METHOD_RETURN
|
||||
case 0x15: // METHOD_RECEIVER
|
||||
out.putByte(typeRef >>> 24);
|
||||
break;
|
||||
case 0x47: // CAST
|
||||
case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
out.putInt(typeRef);
|
||||
break;
|
||||
// case 0x10: // CLASS_EXTENDS
|
||||
// case 0x11: // CLASS_TYPE_PARAMETER_BOUND
|
||||
// case 0x12: // METHOD_TYPE_PARAMETER_BOUND
|
||||
// case 0x17: // THROWS
|
||||
// case 0x42: // EXCEPTION_PARAMETER
|
||||
// case 0x43: // INSTANCEOF
|
||||
// case 0x44: // NEW
|
||||
// case 0x45: // CONSTRUCTOR_REFERENCE
|
||||
// case 0x46: // METHOD_REFERENCE
|
||||
default:
|
||||
out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
|
||||
break;
|
||||
}
|
||||
if (typePath == null) {
|
||||
out.putByte(0);
|
||||
} else {
|
||||
int length = typePath.b[typePath.offset] * 2 + 1;
|
||||
out.putByteArray(typePath.b, typePath.offset, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,297 +58,299 @@
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A non standard class, field, method or code attribute.
|
||||
* A non standard class, field, method or code attribute, as defined in the Java Virtual Machine
|
||||
* Specification (JVMS).
|
||||
*
|
||||
* @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7">JVMS
|
||||
* 4.7</a>
|
||||
* @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS
|
||||
* 4.7.3</a>
|
||||
* @author Eric Bruneton
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class Attribute {
|
||||
|
||||
/**
|
||||
* The type of this attribute.
|
||||
*/
|
||||
/** The type of this attribute, also called its name in the JVMS. */
|
||||
public final String type;
|
||||
|
||||
/**
|
||||
* The raw value of this attribute, used only for unknown attributes.
|
||||
*/
|
||||
byte[] value;
|
||||
* The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}).
|
||||
* The 6 header bytes of the attribute (attribute_name_index and attribute_length) are <i>not</i>
|
||||
* included.
|
||||
*/
|
||||
private byte[] content;
|
||||
|
||||
/**
|
||||
* The next attribute in this attribute list. May be <tt>null</tt>.
|
||||
*/
|
||||
Attribute next;
|
||||
* The next attribute in this attribute list (Attribute instances can be linked via this field to
|
||||
* store a list of class, field, method or code attributes). May be {@literal null}.
|
||||
*/
|
||||
Attribute nextAttribute;
|
||||
|
||||
/**
|
||||
* Constructs a new empty attribute.
|
||||
*
|
||||
* @param type
|
||||
* the type of the attribute.
|
||||
*/
|
||||
* Constructs a new empty attribute.
|
||||
*
|
||||
* @param type the type of the attribute.
|
||||
*/
|
||||
protected Attribute(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this type of attribute is unknown. The default
|
||||
* implementation of this method always returns <tt>true</tt>.
|
||||
*
|
||||
* @return <tt>true</tt> if this type of attribute is unknown.
|
||||
*/
|
||||
* Returns {@literal true} if this type of attribute is unknown. This means that the attribute
|
||||
* content can't be parsed to extract constant pool references, labels, etc. Instead, the
|
||||
* attribute content is read as an opaque byte array, and written back as is. This can lead to
|
||||
* invalid attributes, if the content actually contains constant pool references, labels, or other
|
||||
* symbolic references that need to be updated when there are changes to the constant pool, the
|
||||
* method bytecode, etc. The default implementation of this method always returns {@literal true}.
|
||||
*
|
||||
* @return {@literal true} if this type of attribute is unknown.
|
||||
*/
|
||||
public boolean isUnknown() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this type of attribute is a code attribute.
|
||||
*
|
||||
* @return <tt>true</tt> if this type of attribute is a code attribute.
|
||||
*/
|
||||
* Returns {@literal true} if this type of attribute is a code attribute.
|
||||
*
|
||||
* @return {@literal true} if this type of attribute is a code attribute.
|
||||
*/
|
||||
public boolean isCodeAttribute() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the labels corresponding to this attribute.
|
||||
*
|
||||
* @return the labels corresponding to this attribute, or <tt>null</tt> if
|
||||
* this attribute is not a code attribute that contains labels.
|
||||
*/
|
||||
* Returns the labels corresponding to this attribute.
|
||||
*
|
||||
* @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
|
||||
* a code attribute that contains labels.
|
||||
*/
|
||||
protected Label[] getLabels() {
|
||||
return null;
|
||||
return new Label[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a {@link #type type} attribute. This method must return a
|
||||
* <i>new</i> {@link Attribute} object, of type {@link #type type},
|
||||
* corresponding to the <tt>len</tt> bytes starting at the given offset, in
|
||||
* the given class reader.
|
||||
*
|
||||
* @param cr
|
||||
* the class that contains the attribute to be read.
|
||||
* @param off
|
||||
* index of the first byte of the attribute's content in
|
||||
* {@link ClassReader#b cr.b}. The 6 attribute header bytes,
|
||||
* containing the type and the length of the attribute, are not
|
||||
* taken into account here.
|
||||
* @param len
|
||||
* the length of the attribute's content.
|
||||
* @param buf
|
||||
* buffer to be used to call {@link ClassReader#readUTF8
|
||||
* readUTF8}, {@link ClassReader#readClass(int,char[]) readClass}
|
||||
* or {@link ClassReader#readConst readConst}.
|
||||
* @param codeOff
|
||||
* index of the first byte of code's attribute content in
|
||||
* {@link ClassReader#b cr.b}, or -1 if the attribute to be read
|
||||
* is not a code attribute. The 6 attribute header bytes,
|
||||
* containing the type and the length of the attribute, are not
|
||||
* taken into account here.
|
||||
* @param labels
|
||||
* the labels of the method's code, or <tt>null</tt> if the
|
||||
* attribute to be read is not a code attribute.
|
||||
* @return a <i>new</i> {@link Attribute} object corresponding to the given
|
||||
* bytes.
|
||||
*/
|
||||
protected Attribute read(final ClassReader cr, final int off,
|
||||
final int len, final char[] buf, final int codeOff,
|
||||
* Reads a {@link #type} attribute. This method must return a <i>new</i> {@link Attribute} object,
|
||||
* of type {@link #type}, corresponding to the 'length' bytes starting at 'offset', in the given
|
||||
* ClassReader.
|
||||
*
|
||||
* @param classReader the class that contains the attribute to be read.
|
||||
* @param offset index of the first byte of the attribute's content in {@link ClassReader#b}. The
|
||||
* 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into
|
||||
* account here.
|
||||
* @param length the length of the attribute's content (excluding the 6 attribute header bytes).
|
||||
* @param charBuffer the buffer to be used to call the ClassReader methods requiring a
|
||||
* 'charBuffer' parameter.
|
||||
* @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
|
||||
* in {@link ClassReader#b}, or -1 if the attribute to be read is not a code attribute. The 6
|
||||
* attribute header bytes (attribute_name_index and attribute_length) are not taken into
|
||||
* account here.
|
||||
* @param labels the labels of the method's code, or {@literal null} if the attribute to be read
|
||||
* is not a code attribute.
|
||||
* @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
|
||||
*/
|
||||
protected Attribute read(
|
||||
final ClassReader classReader,
|
||||
final int offset,
|
||||
final int length,
|
||||
final char[] charBuffer,
|
||||
final int codeAttributeOffset,
|
||||
final Label[] labels) {
|
||||
Attribute attr = new Attribute(type);
|
||||
attr.value = new byte[len];
|
||||
System.arraycopy(cr.b, off, attr.value, 0, len);
|
||||
return attr;
|
||||
Attribute attribute = new Attribute(type);
|
||||
attribute.content = new byte[length];
|
||||
System.arraycopy(classReader.b, offset, attribute.content, 0, length);
|
||||
return attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte array form of this attribute.
|
||||
*
|
||||
* @param cw
|
||||
* the class to which this attribute must be added. This
|
||||
* parameter can be used to add to the constant pool of this
|
||||
* class the items that corresponds to this attribute.
|
||||
* @param code
|
||||
* the bytecode of the method corresponding to this code
|
||||
* attribute, or <tt>null</tt> if this attribute is not a code
|
||||
* attributes.
|
||||
* @param len
|
||||
* the length of the bytecode of the method corresponding to this
|
||||
* code attribute, or <tt>null</tt> if this attribute is not a
|
||||
* code attribute.
|
||||
* @param maxStack
|
||||
* the maximum stack size of the method corresponding to this
|
||||
* code attribute, or -1 if this attribute is not a code
|
||||
* attribute.
|
||||
* @param maxLocals
|
||||
* the maximum number of local variables of the method
|
||||
* corresponding to this code attribute, or -1 if this attribute
|
||||
* is not a code attribute.
|
||||
* @return the byte array form of this attribute.
|
||||
*/
|
||||
protected ByteVector write(final ClassWriter cw, final byte[] code,
|
||||
final int len, final int maxStack, final int maxLocals) {
|
||||
ByteVector v = new ByteVector();
|
||||
v.data = value;
|
||||
v.length = value.length;
|
||||
return v;
|
||||
* Returns the byte array form of the content of this attribute. The 6 header bytes
|
||||
* (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
|
||||
* ByteVector.
|
||||
*
|
||||
* @param classWriter the class to which this attribute must be added. This parameter can be used
|
||||
* to add the items that corresponds to this attribute to the constant pool of this class.
|
||||
* @param code the bytecode of the method corresponding to this code attribute, or {@literal null}
|
||||
* if this attribute is not a code attribute. Corresponds to the 'code' field of the Code
|
||||
* attribute.
|
||||
* @param codeLength the length of the bytecode of the method corresponding to this code
|
||||
* attribute, or 0 if this attribute is not a code attribute. Corresponds to the 'code_length'
|
||||
* field of the Code attribute.
|
||||
* @param maxStack the maximum stack size of the method corresponding to this code attribute, or
|
||||
* -1 if this attribute is not a code attribute.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to this code
|
||||
* attribute, or -1 if this attribute is not a code attribute.
|
||||
* @return the byte array form of this attribute.
|
||||
*/
|
||||
protected ByteVector write(
|
||||
final ClassWriter classWriter,
|
||||
final byte[] code,
|
||||
final int codeLength,
|
||||
final int maxStack,
|
||||
final int maxLocals) {
|
||||
return new ByteVector(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the attribute list that begins with this attribute.
|
||||
*
|
||||
* @return the length of the attribute list that begins with this attribute.
|
||||
*/
|
||||
final int getCount() {
|
||||
* Returns the number of attributes of the attribute list that begins with this attribute.
|
||||
*
|
||||
* @return the number of attributes of the attribute list that begins with this attribute.
|
||||
*/
|
||||
final int getAttributeCount() {
|
||||
int count = 0;
|
||||
Attribute attr = this;
|
||||
while (attr != null) {
|
||||
Attribute attribute = this;
|
||||
while (attribute != null) {
|
||||
count += 1;
|
||||
attr = attr.next;
|
||||
attribute = attribute.nextAttribute;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of all the attributes in this attribute list.
|
||||
*
|
||||
* @param cw
|
||||
* the class writer to be used to convert the attributes into
|
||||
* byte arrays, with the {@link #write write} method.
|
||||
* @param code
|
||||
* the bytecode of the method corresponding to these code
|
||||
* attributes, or <tt>null</tt> if these attributes are not code
|
||||
* attributes.
|
||||
* @param len
|
||||
* the length of the bytecode of the method corresponding to
|
||||
* these code attributes, or <tt>null</tt> if these attributes
|
||||
* are not code attributes.
|
||||
* @param maxStack
|
||||
* the maximum stack size of the method corresponding to these
|
||||
* code attributes, or -1 if these attributes are not code
|
||||
* attributes.
|
||||
* @param maxLocals
|
||||
* the maximum number of local variables of the method
|
||||
* corresponding to these code attributes, or -1 if these
|
||||
* attributes are not code attributes.
|
||||
* @return the size of all the attributes in this attribute list. This size
|
||||
* includes the size of the attribute headers.
|
||||
*/
|
||||
final int getSize(final ClassWriter cw, final byte[] code, final int len,
|
||||
final int maxStack, final int maxLocals) {
|
||||
Attribute attr = this;
|
||||
* Returns the total size in bytes of all the attributes in the attribute list that begins with
|
||||
* this attribute. This size includes the 6 header bytes (attribute_name_index and
|
||||
* attribute_length) per attribute. Also adds the attribute type names to the constant pool.
|
||||
*
|
||||
* @param symbolTable where the constants used in the attributes must be stored.
|
||||
* @return the size of all the attributes in this attribute list. This size includes the size of
|
||||
* the attribute headers.
|
||||
*/
|
||||
final int computeAttributesSize(final SymbolTable symbolTable) {
|
||||
final byte[] code = null;
|
||||
final int codeLength = 0;
|
||||
final int maxStack = -1;
|
||||
final int maxLocals = -1;
|
||||
return computeAttributesSize(symbolTable, code, codeLength, maxStack, maxLocals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total size in bytes of all the attributes in the attribute list that begins with
|
||||
* this attribute. This size includes the 6 header bytes (attribute_name_index and
|
||||
* attribute_length) per attribute. Also adds the attribute type names to the constant pool.
|
||||
*
|
||||
* @param symbolTable where the constants used in the attributes must be stored.
|
||||
* @param code the bytecode of the method corresponding to these code attributes, or {@literal
|
||||
* null} if they are not code attributes. Corresponds to the 'code' field of the Code
|
||||
* attribute.
|
||||
* @param codeLength the length of the bytecode of the method corresponding to these code
|
||||
* attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
|
||||
* the Code attribute.
|
||||
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or
|
||||
* -1 if they are not code attributes.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to these
|
||||
* code attributes, or -1 if they are not code attribute.
|
||||
* @return the size of all the attributes in this attribute list. This size includes the size of
|
||||
* the attribute headers.
|
||||
*/
|
||||
final int computeAttributesSize(
|
||||
final SymbolTable symbolTable,
|
||||
final byte[] code,
|
||||
final int codeLength,
|
||||
final int maxStack,
|
||||
final int maxLocals) {
|
||||
final ClassWriter classWriter = symbolTable.classWriter;
|
||||
int size = 0;
|
||||
while (attr != null) {
|
||||
cw.newUTF8(attr.type);
|
||||
size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
|
||||
attr = attr.next;
|
||||
Attribute attribute = this;
|
||||
while (attribute != null) {
|
||||
symbolTable.addConstantUtf8(attribute.type);
|
||||
size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length;
|
||||
attribute = attribute.nextAttribute;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes all the attributes of this attribute list in the given byte
|
||||
* vector.
|
||||
*
|
||||
* @param cw
|
||||
* the class writer to be used to convert the attributes into
|
||||
* byte arrays, with the {@link #write write} method.
|
||||
* @param code
|
||||
* the bytecode of the method corresponding to these code
|
||||
* attributes, or <tt>null</tt> if these attributes are not code
|
||||
* attributes.
|
||||
* @param len
|
||||
* the length of the bytecode of the method corresponding to
|
||||
* these code attributes, or <tt>null</tt> if these attributes
|
||||
* are not code attributes.
|
||||
* @param maxStack
|
||||
* the maximum stack size of the method corresponding to these
|
||||
* code attributes, or -1 if these attributes are not code
|
||||
* attributes.
|
||||
* @param maxLocals
|
||||
* the maximum number of local variables of the method
|
||||
* corresponding to these code attributes, or -1 if these
|
||||
* attributes are not code attributes.
|
||||
* @param out
|
||||
* where the attributes must be written.
|
||||
*/
|
||||
final void put(final ClassWriter cw, final byte[] code, final int len,
|
||||
final int maxStack, final int maxLocals, final ByteVector out) {
|
||||
Attribute attr = this;
|
||||
while (attr != null) {
|
||||
ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
|
||||
out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
|
||||
out.putByteArray(b.data, 0, b.length);
|
||||
attr = attr.next;
|
||||
* Puts all the attributes of the attribute list that begins with this attribute, in the given
|
||||
* byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
|
||||
* attribute.
|
||||
*
|
||||
* @param symbolTable where the constants used in the attributes must be stored.
|
||||
* @param output where the attributes must be written.
|
||||
*/
|
||||
final void putAttributes(final SymbolTable symbolTable, final ByteVector output) {
|
||||
final byte[] code = null;
|
||||
final int codeLength = 0;
|
||||
final int maxStack = -1;
|
||||
final int maxLocals = -1;
|
||||
putAttributes(symbolTable, code, codeLength, maxStack, maxLocals, output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts all the attributes of the attribute list that begins with this attribute, in the given
|
||||
* byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
|
||||
* attribute.
|
||||
*
|
||||
* @param symbolTable where the constants used in the attributes must be stored.
|
||||
* @param code the bytecode of the method corresponding to these code attributes, or {@literal
|
||||
* null} if they are not code attributes. Corresponds to the 'code' field of the Code
|
||||
* attribute.
|
||||
* @param codeLength the length of the bytecode of the method corresponding to these code
|
||||
* attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
|
||||
* the Code attribute.
|
||||
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or
|
||||
* -1 if they are not code attributes.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to these
|
||||
* code attributes, or -1 if they are not code attribute.
|
||||
* @param output where the attributes must be written.
|
||||
*/
|
||||
final void putAttributes(
|
||||
final SymbolTable symbolTable,
|
||||
final byte[] code,
|
||||
final int codeLength,
|
||||
final int maxStack,
|
||||
final int maxLocals,
|
||||
final ByteVector output) {
|
||||
final ClassWriter classWriter = symbolTable.classWriter;
|
||||
Attribute attribute = this;
|
||||
while (attribute != null) {
|
||||
ByteVector attributeContent =
|
||||
attribute.write(classWriter, code, codeLength, maxStack, maxLocals);
|
||||
// Put attribute_name_index and attribute_length.
|
||||
output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length);
|
||||
output.putByteArray(attributeContent.data, 0, attributeContent.length);
|
||||
attribute = attribute.nextAttribute;
|
||||
}
|
||||
}
|
||||
|
||||
//The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely removed.
|
||||
//see also changes in ClassReader.accept.
|
||||
/** A set of attribute prototypes (attributes with the same type are considered equal). */
|
||||
static final class Set {
|
||||
|
||||
public static class NestMembers extends Attribute {
|
||||
public NestMembers() {
|
||||
super("NestMembers");
|
||||
}
|
||||
private static final int SIZE_INCREMENT = 6;
|
||||
|
||||
byte[] bytes;
|
||||
String[] classes;
|
||||
private int size;
|
||||
private Attribute[] data = new Attribute[SIZE_INCREMENT];
|
||||
|
||||
@Override
|
||||
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
|
||||
int offset = off;
|
||||
NestMembers a = new NestMembers();
|
||||
int size = cr.readShort(off);
|
||||
a.classes = new String[size];
|
||||
off += 2;
|
||||
for (int i = 0; i < size ; i++) {
|
||||
a.classes[i] = cr.readClass(off, buf);
|
||||
off += 2;
|
||||
void addAttributes(final Attribute attributeList) {
|
||||
Attribute attribute = attributeList;
|
||||
while (attribute != null) {
|
||||
if (!contains(attribute)) {
|
||||
add(attribute);
|
||||
}
|
||||
attribute = attribute.nextAttribute;
|
||||
}
|
||||
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
|
||||
ByteVector v = new ByteVector(bytes.length);
|
||||
v.putShort(classes.length);
|
||||
for (String s : classes) {
|
||||
v.putShort(cw.newClass(s));
|
||||
Attribute[] toArray() {
|
||||
Attribute[] result = new Attribute[size];
|
||||
System.arraycopy(data, 0, result, 0, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean contains(final Attribute attribute) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (data[i].type.equals(attribute.type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void add(final Attribute attribute) {
|
||||
if (size >= data.length) {
|
||||
Attribute[] newData = new Attribute[data.length + SIZE_INCREMENT];
|
||||
System.arraycopy(data, 0, newData, 0, size);
|
||||
data = newData;
|
||||
}
|
||||
data[size++] = attribute;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NestHost extends Attribute {
|
||||
|
||||
byte[] bytes;
|
||||
String clazz;
|
||||
|
||||
public NestHost() {
|
||||
super("NestHost");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
|
||||
int offset = off;
|
||||
NestHost a = new NestHost();
|
||||
a.clazz = cr.readClass(off, buf);
|
||||
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
|
||||
ByteVector v = new ByteVector(bytes.length);
|
||||
v.putShort(cw.newClass(clazz));
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {
|
||||
new NestMembers(),
|
||||
new NestHost()
|
||||
};
|
||||
}
|
||||
|
@ -59,309 +59,333 @@
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* A dynamically extensible vector of bytes. This class is roughly equivalent to
|
||||
* a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
|
||||
* A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream
|
||||
* on top of a ByteArrayOutputStream, but is more efficient.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class ByteVector {
|
||||
|
||||
/**
|
||||
* The content of this vector.
|
||||
*/
|
||||
/** The content of this vector. Only the first {@link #length} bytes contain real data. */
|
||||
byte[] data;
|
||||
|
||||
/**
|
||||
* Actual number of bytes in this vector.
|
||||
*/
|
||||
/** The actual number of bytes in this vector. */
|
||||
int length;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ByteVector ByteVector} with a default initial
|
||||
* size.
|
||||
*/
|
||||
/** Constructs a new {@link ByteVector} with a default initial capacity. */
|
||||
public ByteVector() {
|
||||
data = new byte[64];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ByteVector ByteVector} with the given initial
|
||||
* size.
|
||||
*
|
||||
* @param initialSize
|
||||
* the initial size of the byte vector to be constructed.
|
||||
*/
|
||||
public ByteVector(final int initialSize) {
|
||||
data = new byte[initialSize];
|
||||
* Constructs a new {@link ByteVector} with the given initial capacity.
|
||||
*
|
||||
* @param initialCapacity the initial capacity of the byte vector to be constructed.
|
||||
*/
|
||||
public ByteVector(final int initialCapacity) {
|
||||
data = new byte[initialCapacity];
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a byte into this byte vector. The byte vector is automatically
|
||||
* enlarged if necessary.
|
||||
*
|
||||
* @param b
|
||||
* a byte.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putByte(final int b) {
|
||||
int length = this.length;
|
||||
if (length + 1 > data.length) {
|
||||
* Constructs a new {@link ByteVector} from the given initial data.
|
||||
*
|
||||
* @param data the initial data of the new byte vector.
|
||||
*/
|
||||
ByteVector(final byte[] data) {
|
||||
this.data = data;
|
||||
this.length = data.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param byteValue a byte.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putByte(final int byteValue) {
|
||||
int currentLength = length;
|
||||
if (currentLength + 1 > data.length) {
|
||||
enlarge(1);
|
||||
}
|
||||
data[length++] = (byte) b;
|
||||
this.length = length;
|
||||
data[currentLength++] = (byte) byteValue;
|
||||
length = currentLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts two bytes into this byte vector. The byte vector is automatically
|
||||
* enlarged if necessary.
|
||||
*
|
||||
* @param b1
|
||||
* a byte.
|
||||
* @param b2
|
||||
* another byte.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
ByteVector put11(final int b1, final int b2) {
|
||||
int length = this.length;
|
||||
if (length + 2 > data.length) {
|
||||
* Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param byteValue1 a byte.
|
||||
* @param byteValue2 another byte.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
final ByteVector put11(final int byteValue1, final int byteValue2) {
|
||||
int currentLength = length;
|
||||
if (currentLength + 2 > data.length) {
|
||||
enlarge(2);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) b1;
|
||||
data[length++] = (byte) b2;
|
||||
this.length = length;
|
||||
byte[] currentData = data;
|
||||
currentData[currentLength++] = (byte) byteValue1;
|
||||
currentData[currentLength++] = (byte) byteValue2;
|
||||
length = currentLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a short into this byte vector. The byte vector is automatically
|
||||
* enlarged if necessary.
|
||||
*
|
||||
* @param s
|
||||
* a short.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putShort(final int s) {
|
||||
int length = this.length;
|
||||
if (length + 2 > data.length) {
|
||||
* Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param shortValue a short.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putShort(final int shortValue) {
|
||||
int currentLength = length;
|
||||
if (currentLength + 2 > data.length) {
|
||||
enlarge(2);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) (s >>> 8);
|
||||
data[length++] = (byte) s;
|
||||
this.length = length;
|
||||
byte[] currentData = data;
|
||||
currentData[currentLength++] = (byte) (shortValue >>> 8);
|
||||
currentData[currentLength++] = (byte) shortValue;
|
||||
length = currentLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a byte and a short into this byte vector. The byte vector is
|
||||
* automatically enlarged if necessary.
|
||||
*
|
||||
* @param b
|
||||
* a byte.
|
||||
* @param s
|
||||
* a short.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
ByteVector put12(final int b, final int s) {
|
||||
int length = this.length;
|
||||
if (length + 3 > data.length) {
|
||||
* Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if
|
||||
* necessary.
|
||||
*
|
||||
* @param byteValue a byte.
|
||||
* @param shortValue a short.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
final ByteVector put12(final int byteValue, final int shortValue) {
|
||||
int currentLength = length;
|
||||
if (currentLength + 3 > data.length) {
|
||||
enlarge(3);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) b;
|
||||
data[length++] = (byte) (s >>> 8);
|
||||
data[length++] = (byte) s;
|
||||
this.length = length;
|
||||
byte[] currentData = data;
|
||||
currentData[currentLength++] = (byte) byteValue;
|
||||
currentData[currentLength++] = (byte) (shortValue >>> 8);
|
||||
currentData[currentLength++] = (byte) shortValue;
|
||||
length = currentLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts an int into this byte vector. The byte vector is automatically
|
||||
* enlarged if necessary.
|
||||
*
|
||||
* @param i
|
||||
* an int.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putInt(final int i) {
|
||||
int length = this.length;
|
||||
if (length + 4 > data.length) {
|
||||
* Puts two bytes and a short into this byte vector. The byte vector is automatically enlarged if
|
||||
* necessary.
|
||||
*
|
||||
* @param byteValue1 a byte.
|
||||
* @param byteValue2 another byte.
|
||||
* @param shortValue a short.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
final ByteVector put112(final int byteValue1, final int byteValue2, final int shortValue) {
|
||||
int currentLength = length;
|
||||
if (currentLength + 4 > data.length) {
|
||||
enlarge(4);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) (i >>> 24);
|
||||
data[length++] = (byte) (i >>> 16);
|
||||
data[length++] = (byte) (i >>> 8);
|
||||
data[length++] = (byte) i;
|
||||
this.length = length;
|
||||
byte[] currentData = data;
|
||||
currentData[currentLength++] = (byte) byteValue1;
|
||||
currentData[currentLength++] = (byte) byteValue2;
|
||||
currentData[currentLength++] = (byte) (shortValue >>> 8);
|
||||
currentData[currentLength++] = (byte) shortValue;
|
||||
length = currentLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a long into this byte vector. The byte vector is automatically
|
||||
* enlarged if necessary.
|
||||
*
|
||||
* @param l
|
||||
* a long.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putLong(final long l) {
|
||||
int length = this.length;
|
||||
if (length + 8 > data.length) {
|
||||
* Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param intValue an int.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putInt(final int intValue) {
|
||||
int currentLength = length;
|
||||
if (currentLength + 4 > data.length) {
|
||||
enlarge(4);
|
||||
}
|
||||
byte[] currentData = data;
|
||||
currentData[currentLength++] = (byte) (intValue >>> 24);
|
||||
currentData[currentLength++] = (byte) (intValue >>> 16);
|
||||
currentData[currentLength++] = (byte) (intValue >>> 8);
|
||||
currentData[currentLength++] = (byte) intValue;
|
||||
length = currentLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts one byte and two shorts into this byte vector. The byte vector is automatically enlarged
|
||||
* if necessary.
|
||||
*
|
||||
* @param byteValue a byte.
|
||||
* @param shortValue1 a short.
|
||||
* @param shortValue2 another short.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
final ByteVector put122(final int byteValue, final int shortValue1, final int shortValue2) {
|
||||
int currentLength = length;
|
||||
if (currentLength + 5 > data.length) {
|
||||
enlarge(5);
|
||||
}
|
||||
byte[] currentData = data;
|
||||
currentData[currentLength++] = (byte) byteValue;
|
||||
currentData[currentLength++] = (byte) (shortValue1 >>> 8);
|
||||
currentData[currentLength++] = (byte) shortValue1;
|
||||
currentData[currentLength++] = (byte) (shortValue2 >>> 8);
|
||||
currentData[currentLength++] = (byte) shortValue2;
|
||||
length = currentLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param longValue a long.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putLong(final long longValue) {
|
||||
int currentLength = length;
|
||||
if (currentLength + 8 > data.length) {
|
||||
enlarge(8);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
int i = (int) (l >>> 32);
|
||||
data[length++] = (byte) (i >>> 24);
|
||||
data[length++] = (byte) (i >>> 16);
|
||||
data[length++] = (byte) (i >>> 8);
|
||||
data[length++] = (byte) i;
|
||||
i = (int) l;
|
||||
data[length++] = (byte) (i >>> 24);
|
||||
data[length++] = (byte) (i >>> 16);
|
||||
data[length++] = (byte) (i >>> 8);
|
||||
data[length++] = (byte) i;
|
||||
this.length = length;
|
||||
byte[] currentData = data;
|
||||
int intValue = (int) (longValue >>> 32);
|
||||
currentData[currentLength++] = (byte) (intValue >>> 24);
|
||||
currentData[currentLength++] = (byte) (intValue >>> 16);
|
||||
currentData[currentLength++] = (byte) (intValue >>> 8);
|
||||
currentData[currentLength++] = (byte) intValue;
|
||||
intValue = (int) longValue;
|
||||
currentData[currentLength++] = (byte) (intValue >>> 24);
|
||||
currentData[currentLength++] = (byte) (intValue >>> 16);
|
||||
currentData[currentLength++] = (byte) (intValue >>> 8);
|
||||
currentData[currentLength++] = (byte) intValue;
|
||||
length = currentLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts an UTF8 string into this byte vector. The byte vector is
|
||||
* automatically enlarged if necessary.
|
||||
*
|
||||
* @param s
|
||||
* a String whose UTF8 encoded length must be less than 65536.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putUTF8(final String s) {
|
||||
int charLength = s.length();
|
||||
* Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
|
||||
* necessary.
|
||||
*
|
||||
* @param stringValue a String whose UTF8 encoded length must be less than 65536.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
|
||||
public ByteVector putUTF8(final String stringValue) {
|
||||
int charLength = stringValue.length();
|
||||
if (charLength > 65535) {
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException("UTF8 string too large");
|
||||
}
|
||||
int len = length;
|
||||
if (len + 2 + charLength > data.length) {
|
||||
int currentLength = length;
|
||||
if (currentLength + 2 + charLength > data.length) {
|
||||
enlarge(2 + charLength);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
// optimistic algorithm: instead of computing the byte length and then
|
||||
// serializing the string (which requires two loops), we assume the byte
|
||||
// length is equal to char length (which is the most frequent case), and
|
||||
// we start serializing the string right away. During the serialization,
|
||||
// if we find that this assumption is wrong, we continue with the
|
||||
// general method.
|
||||
data[len++] = (byte) (charLength >>> 8);
|
||||
data[len++] = (byte) charLength;
|
||||
byte[] currentData = data;
|
||||
// Optimistic algorithm: instead of computing the byte length and then serializing the string
|
||||
// (which requires two loops), we assume the byte length is equal to char length (which is the
|
||||
// most frequent case), and we start serializing the string right away. During the
|
||||
// serialization, if we find that this assumption is wrong, we continue with the general method.
|
||||
currentData[currentLength++] = (byte) (charLength >>> 8);
|
||||
currentData[currentLength++] = (byte) charLength;
|
||||
for (int i = 0; i < charLength; ++i) {
|
||||
char c = s.charAt(i);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
data[len++] = (byte) c;
|
||||
char charValue = stringValue.charAt(i);
|
||||
if (charValue >= '\u0001' && charValue <= '\u007F') {
|
||||
currentData[currentLength++] = (byte) charValue;
|
||||
} else {
|
||||
length = len;
|
||||
return encodeUTF8(s, i, 65535);
|
||||
length = currentLength;
|
||||
return encodeUtf8(stringValue, i, 65535);
|
||||
}
|
||||
}
|
||||
length = len;
|
||||
length = currentLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts an UTF8 string into this byte vector. The byte vector is
|
||||
* automatically enlarged if necessary. The string length is encoded in two
|
||||
* bytes before the encoded characters, if there is space for that (i.e. if
|
||||
* this.length - i - 2 >= 0).
|
||||
*
|
||||
* @param s
|
||||
* the String to encode.
|
||||
* @param i
|
||||
* the index of the first character to encode. The previous
|
||||
* characters are supposed to have already been encoded, using
|
||||
* only one byte per character.
|
||||
* @param maxByteLength
|
||||
* the maximum byte length of the encoded string, including the
|
||||
* already encoded characters.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
|
||||
int charLength = s.length();
|
||||
int byteLength = i;
|
||||
char c;
|
||||
for (int j = i; j < charLength; ++j) {
|
||||
c = s.charAt(j);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
* Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
|
||||
* necessary. The string length is encoded in two bytes before the encoded characters, if there is
|
||||
* space for that (i.e. if this.length - offset - 2 >= 0).
|
||||
*
|
||||
* @param stringValue the String to encode.
|
||||
* @param offset the index of the first character to encode. The previous characters are supposed
|
||||
* to have already been encoded, using only one byte per character.
|
||||
* @param maxByteLength the maximum byte length of the encoded string, including the already
|
||||
* encoded characters.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
final ByteVector encodeUtf8(final String stringValue, final int offset, final int maxByteLength) {
|
||||
int charLength = stringValue.length();
|
||||
int byteLength = offset;
|
||||
for (int i = offset; i < charLength; ++i) {
|
||||
char charValue = stringValue.charAt(i);
|
||||
if (charValue >= 0x0001 && charValue <= 0x007F) {
|
||||
byteLength++;
|
||||
} else if (c > '\u07FF') {
|
||||
byteLength += 3;
|
||||
} else {
|
||||
} else if (charValue <= 0x07FF) {
|
||||
byteLength += 2;
|
||||
} else {
|
||||
byteLength += 3;
|
||||
}
|
||||
}
|
||||
if (byteLength > maxByteLength) {
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException("UTF8 string too large");
|
||||
}
|
||||
int start = length - i - 2;
|
||||
if (start >= 0) {
|
||||
data[start] = (byte) (byteLength >>> 8);
|
||||
data[start + 1] = (byte) byteLength;
|
||||
// Compute where 'byteLength' must be stored in 'data', and store it at this location.
|
||||
int byteLengthOffset = length - offset - 2;
|
||||
if (byteLengthOffset >= 0) {
|
||||
data[byteLengthOffset] = (byte) (byteLength >>> 8);
|
||||
data[byteLengthOffset + 1] = (byte) byteLength;
|
||||
}
|
||||
if (length + byteLength - i > data.length) {
|
||||
enlarge(byteLength - i);
|
||||
if (length + byteLength - offset > data.length) {
|
||||
enlarge(byteLength - offset);
|
||||
}
|
||||
int len = length;
|
||||
for (int j = i; j < charLength; ++j) {
|
||||
c = s.charAt(j);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
data[len++] = (byte) c;
|
||||
} else if (c > '\u07FF') {
|
||||
data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
|
||||
data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
|
||||
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||
int currentLength = length;
|
||||
for (int i = offset; i < charLength; ++i) {
|
||||
char charValue = stringValue.charAt(i);
|
||||
if (charValue >= 0x0001 && charValue <= 0x007F) {
|
||||
data[currentLength++] = (byte) charValue;
|
||||
} else if (charValue <= 0x07FF) {
|
||||
data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F);
|
||||
data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
|
||||
} else {
|
||||
data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
|
||||
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||
data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF);
|
||||
data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F);
|
||||
data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
|
||||
}
|
||||
}
|
||||
length = len;
|
||||
length = currentLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts an array of bytes into this byte vector. The byte vector is
|
||||
* automatically enlarged if necessary.
|
||||
*
|
||||
* @param b
|
||||
* an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
|
||||
* null bytes into this byte vector.
|
||||
* @param off
|
||||
* index of the fist byte of b that must be copied.
|
||||
* @param len
|
||||
* number of bytes of b that must be copied.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putByteArray(final byte[] b, final int off, final int len) {
|
||||
if (length + len > data.length) {
|
||||
enlarge(len);
|
||||
* Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if
|
||||
* necessary.
|
||||
*
|
||||
* @param byteArrayValue an array of bytes. May be {@literal null} to put {@code byteLength} null
|
||||
* bytes into this byte vector.
|
||||
* @param byteOffset index of the first byte of byteArrayValue that must be copied.
|
||||
* @param byteLength number of bytes of byteArrayValue that must be copied.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putByteArray(
|
||||
final byte[] byteArrayValue, final int byteOffset, final int byteLength) {
|
||||
if (length + byteLength > data.length) {
|
||||
enlarge(byteLength);
|
||||
}
|
||||
if (b != null) {
|
||||
System.arraycopy(b, off, data, length, len);
|
||||
if (byteArrayValue != null) {
|
||||
System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength);
|
||||
}
|
||||
length += len;
|
||||
length += byteLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enlarge this byte vector so that it can receive n more bytes.
|
||||
*
|
||||
* @param size
|
||||
* number of additional bytes that this byte vector should be
|
||||
* able to receive.
|
||||
*/
|
||||
* Enlarges this byte vector so that it can receive 'size' more bytes.
|
||||
*
|
||||
* @param size number of additional bytes that this byte vector should be able to receive.
|
||||
*/
|
||||
private void enlarge(final int size) {
|
||||
int length1 = 2 * data.length;
|
||||
int length2 = length + size;
|
||||
byte[] newData = new byte[length1 > length2 ? length1 : length2];
|
||||
int doubleCapacity = 2 * data.length;
|
||||
int minimalCapacity = length + size;
|
||||
byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity];
|
||||
System.arraycopy(data, 0, newData, 0, length);
|
||||
data = newData;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* Exception thrown when the constant pool of a class produced by a {@link ClassWriter} is too
|
||||
* large.
|
||||
*
|
||||
* @author Jason Zaugg
|
||||
*/
|
||||
public final class ClassTooLargeException extends IndexOutOfBoundsException {
|
||||
private static final long serialVersionUID = 160715609518896765L;
|
||||
|
||||
private final String className;
|
||||
private final int constantPoolCount;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ClassTooLargeException}.
|
||||
*
|
||||
* @param className the internal name of the class.
|
||||
* @param constantPoolCount the number of constant pool items of the class.
|
||||
*/
|
||||
public ClassTooLargeException(final String className, final int constantPoolCount) {
|
||||
super("Class too large: " + className);
|
||||
this.className = className;
|
||||
this.constantPoolCount = constantPoolCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the internal name of the class.
|
||||
*
|
||||
* @return the internal name of the class.
|
||||
*/
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of constant pool items of the class.
|
||||
*
|
||||
* @return the number of constant pool items of the class.
|
||||
*/
|
||||
public int getConstantPoolCount() {
|
||||
return constantPoolCount;
|
||||
}
|
||||
}
|
@ -59,122 +59,106 @@
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* A visitor to visit a Java class. The methods of this class must be called in
|
||||
* the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
|
||||
* <tt>visitModule</tt> ][ <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
|
||||
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
|
||||
* <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
|
||||
* <tt>visitEnd</tt>.
|
||||
* A visitor to visit a Java class. The methods of this class must be called in the following order:
|
||||
* {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
|
||||
* visitOuterClass} ] ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code
|
||||
* visitAttribute} )* ( {@code visitNestMember} | {@code visitInnerClass} | {@code visitField} |
|
||||
* {@code visitMethod} )* {@code visitEnd}.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public abstract class ClassVisitor {
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field
|
||||
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
* The ASM API version implemented by this visitor. The value of this field must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/**
|
||||
* The class visitor to which this visitor must delegate method calls. May
|
||||
* be null.
|
||||
*/
|
||||
/** The class visitor to which this visitor must delegate method calls. May be null. */
|
||||
protected ClassVisitor cv;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ClassVisitor}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
* Constructs a new {@link ClassVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
*/
|
||||
public ClassVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ClassVisitor}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
* @param cv
|
||||
* the class visitor to which this visitor must delegate method
|
||||
* calls. May be null.
|
||||
*/
|
||||
public ClassVisitor(final int api, final ClassVisitor cv) {
|
||||
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
|
||||
* Constructs a new {@link ClassVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* @param classVisitor the class visitor to which this visitor must delegate method calls. May be
|
||||
* null.
|
||||
*/
|
||||
public ClassVisitor(final int api, final ClassVisitor classVisitor) {
|
||||
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.api = api;
|
||||
this.cv = cv;
|
||||
this.cv = classVisitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the header of the class.
|
||||
*
|
||||
* @param version
|
||||
* the class version.
|
||||
* @param access
|
||||
* the class's access flags (see {@link Opcodes}). This parameter
|
||||
* also indicates if the class is deprecated.
|
||||
* @param name
|
||||
* the internal name of the class (see
|
||||
* {@link Type#getInternalName() getInternalName}).
|
||||
* @param signature
|
||||
* the signature of this class. May be <tt>null</tt> if the class
|
||||
* is not a generic one, and does not extend or implement generic
|
||||
* classes or interfaces.
|
||||
* @param superName
|
||||
* the internal of name of the super class (see
|
||||
* {@link Type#getInternalName() getInternalName}). For
|
||||
* interfaces, the super class is {@link Object}. May be
|
||||
* <tt>null</tt>, but only for the {@link Object} class.
|
||||
* @param interfaces
|
||||
* the internal names of the class's interfaces (see
|
||||
* {@link Type#getInternalName() getInternalName}). May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
public void visit(int version, int access, String name, String signature,
|
||||
String superName, String[] interfaces) {
|
||||
* Visits the header of the class.
|
||||
*
|
||||
* @param version the class version. The minor version is stored in the 16 most significant bits,
|
||||
* and the major version in the 16 least significant bits.
|
||||
* @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if
|
||||
* the class is deprecated.
|
||||
* @param name the internal name of the class (see {@link Type#getInternalName()}).
|
||||
* @param signature the signature of this class. May be {@literal null} if the class is not a
|
||||
* generic one, and does not extend or implement generic classes or interfaces.
|
||||
* @param superName the internal of name of the super class (see {@link Type#getInternalName()}).
|
||||
* For interfaces, the super class is {@link Object}. May be {@literal null}, but only for the
|
||||
* {@link Object} class.
|
||||
* @param interfaces the internal names of the class's interfaces (see {@link
|
||||
* Type#getInternalName()}). May be {@literal null}.
|
||||
*/
|
||||
public void visit(
|
||||
final int version,
|
||||
final int access,
|
||||
final String name,
|
||||
final String signature,
|
||||
final String superName,
|
||||
final String[] interfaces) {
|
||||
if (cv != null) {
|
||||
cv.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the source of the class.
|
||||
*
|
||||
* @param source
|
||||
* the name of the source file from which the class was compiled.
|
||||
* May be <tt>null</tt>.
|
||||
* @param debug
|
||||
* additional debug information to compute the correspondance
|
||||
* between source and compiled elements of the class. May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
public void visitSource(String source, String debug) {
|
||||
* Visits the source of the class.
|
||||
*
|
||||
* @param source the name of the source file from which the class was compiled. May be {@literal
|
||||
* null}.
|
||||
* @param debug additional debug information to compute the correspondence between source and
|
||||
* compiled elements of the class. May be {@literal null}.
|
||||
*/
|
||||
public void visitSource(final String source, final String debug) {
|
||||
if (cv != null) {
|
||||
cv.visitSource(source, debug);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit the module corresponding to the class.
|
||||
* @param name
|
||||
* module name
|
||||
* @param access
|
||||
* module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC}
|
||||
* and {@code ACC_MANDATED}.
|
||||
* @param version
|
||||
* module version or null.
|
||||
* @return a visitor to visit the module values, or <tt>null</tt> if
|
||||
* this visitor is not interested in visiting this module.
|
||||
*/
|
||||
public ModuleVisitor visitModule(String name, int access, String version) {
|
||||
* Visit the module corresponding to the class.
|
||||
*
|
||||
* @param name the fully qualified name (using dots) of the module.
|
||||
* @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
|
||||
* ACC_MANDATED}.
|
||||
* @param version the module version, or {@literal null}.
|
||||
* @return a visitor to visit the module values, or {@literal null} if this visitor is not
|
||||
* interested in visiting this module.
|
||||
*/
|
||||
public ModuleVisitor visitModule(final String name, final int access, final String version) {
|
||||
if (api < Opcodes.ASM6) {
|
||||
throw new RuntimeException();
|
||||
throw new UnsupportedOperationException("This feature requires ASM6");
|
||||
}
|
||||
if (cv != null) {
|
||||
return cv.visitModule(name, access, version);
|
||||
@ -183,186 +167,191 @@ public abstract class ClassVisitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the enclosing class of the class. This method must be called only
|
||||
* if the class has an enclosing class.
|
||||
*
|
||||
* @param owner
|
||||
* internal name of the enclosing class of the class.
|
||||
* @param name
|
||||
* the name of the method that contains the class, or
|
||||
* <tt>null</tt> if the class is not enclosed in a method of its
|
||||
* enclosing class.
|
||||
* @param desc
|
||||
* the descriptor of the method that contains the class, or
|
||||
* <tt>null</tt> if the class is not enclosed in a method of its
|
||||
* enclosing class.
|
||||
*/
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
* Visits the nest host class of the class. A nest is a set of classes of the same package that
|
||||
* share access to their private members. One of these classes, called the host, lists the other
|
||||
* members of the nest, which in turn should link to the host of their nest. This method must be
|
||||
* called only once and only if the visited class is a non-host member of a nest. A class is
|
||||
* implicitly its own nest, so it's invalid to call this method with the visited class name as
|
||||
* argument.
|
||||
*
|
||||
* @param nestHost the internal name of the host class of the nest.
|
||||
*/
|
||||
public void visitNestHost(final String nestHost) {
|
||||
if (api < Opcodes.ASM7) {
|
||||
throw new UnsupportedOperationException("This feature requires ASM7");
|
||||
}
|
||||
if (cv != null) {
|
||||
cv.visitOuterClass(owner, name, desc);
|
||||
cv.visitNestHost(nestHost);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation of the class.
|
||||
*
|
||||
* @param desc
|
||||
* the class descriptor of the annotation class.
|
||||
* @param visible
|
||||
* <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||
* this visitor is not interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
* Visits the enclosing class of the class. This method must be called only if the class has an
|
||||
* enclosing class.
|
||||
*
|
||||
* @param owner internal name of the enclosing class of the class.
|
||||
* @param name the name of the method that contains the class, or {@literal null} if the class is
|
||||
* not enclosed in a method of its enclosing class.
|
||||
* @param descriptor the descriptor of the method that contains the class, or {@literal null} if
|
||||
* the class is not enclosed in a method of its enclosing class.
|
||||
*/
|
||||
public void visitOuterClass(final String owner, final String name, final String descriptor) {
|
||||
if (cv != null) {
|
||||
return cv.visitAnnotation(desc, visible);
|
||||
cv.visitOuterClass(owner, name, descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation of the class.
|
||||
*
|
||||
* @param descriptor the class descriptor of the annotation class.
|
||||
* @param visible {@literal true} if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
if (cv != null) {
|
||||
return cv.visitAnnotation(descriptor, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation on a type in the class signature.
|
||||
*
|
||||
* @param typeRef
|
||||
* a reference to the annotated type. The sort of this type
|
||||
* reference must be {@link TypeReference#CLASS_TYPE_PARAMETER
|
||||
* CLASS_TYPE_PARAMETER},
|
||||
* {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND
|
||||
* CLASS_TYPE_PARAMETER_BOUND} or
|
||||
* {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See
|
||||
* {@link TypeReference}.
|
||||
* @param typePath
|
||||
* the path to the annotated type argument, wildcard bound, array
|
||||
* element type, or static inner type within 'typeRef'. May be
|
||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param desc
|
||||
* the class descriptor of the annotation class.
|
||||
* @param visible
|
||||
* <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||
* this visitor is not interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
* Visits an annotation on a type in the class signature.
|
||||
*
|
||||
* @param typeRef a reference to the annotated type. The sort of this type reference must be
|
||||
* {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link
|
||||
* TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See
|
||||
* {@link TypeReference}.
|
||||
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or
|
||||
* static inner type within 'typeRef'. May be {@literal null} if the annotation targets
|
||||
* 'typeRef' as a whole.
|
||||
* @param descriptor the class descriptor of the annotation class.
|
||||
* @param visible {@literal true} if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
throw new UnsupportedOperationException("This feature requires ASM5");
|
||||
}
|
||||
if (cv != null) {
|
||||
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
return cv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a non standard attribute of the class.
|
||||
*
|
||||
* @param attr
|
||||
* an attribute.
|
||||
*/
|
||||
public void visitAttribute(Attribute attr) {
|
||||
* Visits a non standard attribute of the class.
|
||||
*
|
||||
* @param attribute an attribute.
|
||||
*/
|
||||
public void visitAttribute(final Attribute attribute) {
|
||||
if (cv != null) {
|
||||
cv.visitAttribute(attr);
|
||||
cv.visitAttribute(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits information about an inner class. This inner class is not
|
||||
* necessarily a member of the class being visited.
|
||||
*
|
||||
* @param name
|
||||
* the internal name of an inner class (see
|
||||
* {@link Type#getInternalName() getInternalName}).
|
||||
* @param outerName
|
||||
* the internal name of the class to which the inner class
|
||||
* belongs (see {@link Type#getInternalName() getInternalName}).
|
||||
* May be <tt>null</tt> for not member classes.
|
||||
* @param innerName
|
||||
* the (simple) name of the inner class inside its enclosing
|
||||
* class. May be <tt>null</tt> for anonymous inner classes.
|
||||
* @param access
|
||||
* the access flags of the inner class as originally declared in
|
||||
* the enclosing class.
|
||||
*/
|
||||
public void visitInnerClass(String name, String outerName,
|
||||
String innerName, int access) {
|
||||
* Visits a member of the nest. A nest is a set of classes of the same package that share access
|
||||
* to their private members. One of these classes, called the host, lists the other members of the
|
||||
* nest, which in turn should link to the host of their nest. This method must be called only if
|
||||
* the visited class is the host of a nest. A nest host is implicitly a member of its own nest, so
|
||||
* it's invalid to call this method with the visited class name as argument.
|
||||
*
|
||||
* @param nestMember the internal name of a nest member.
|
||||
*/
|
||||
public void visitNestMember(final String nestMember) {
|
||||
if (api < Opcodes.ASM7) {
|
||||
throw new UnsupportedOperationException("This feature requires ASM7");
|
||||
}
|
||||
if (cv != null) {
|
||||
cv.visitNestMember(nestMember);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits information about an inner class. This inner class is not necessarily a member of the
|
||||
* class being visited.
|
||||
*
|
||||
* @param name the internal name of an inner class (see {@link Type#getInternalName()}).
|
||||
* @param outerName the internal name of the class to which the inner class belongs (see {@link
|
||||
* Type#getInternalName()}). May be {@literal null} for not member classes.
|
||||
* @param innerName the (simple) name of the inner class inside its enclosing class. May be
|
||||
* {@literal null} for anonymous inner classes.
|
||||
* @param access the access flags of the inner class as originally declared in the enclosing
|
||||
* class.
|
||||
*/
|
||||
public void visitInnerClass(
|
||||
final String name, final String outerName, final String innerName, final int access) {
|
||||
if (cv != null) {
|
||||
cv.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a field of the class.
|
||||
*
|
||||
* @param access
|
||||
* the field's access flags (see {@link Opcodes}). This parameter
|
||||
* also indicates if the field is synthetic and/or deprecated.
|
||||
* @param name
|
||||
* the field's name.
|
||||
* @param desc
|
||||
* the field's descriptor (see {@link Type Type}).
|
||||
* @param signature
|
||||
* the field's signature. May be <tt>null</tt> if the field's
|
||||
* type does not use generic types.
|
||||
* @param value
|
||||
* the field's initial value. This parameter, which may be
|
||||
* <tt>null</tt> if the field does not have an initial value,
|
||||
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
|
||||
* {@link Double} or a {@link String} (for <tt>int</tt>,
|
||||
* <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
|
||||
* respectively). <i>This parameter is only used for static
|
||||
* fields</i>. Its value is ignored for non static fields, which
|
||||
* must be initialized through bytecode instructions in
|
||||
* constructors or methods.
|
||||
* @return a visitor to visit field annotations and attributes, or
|
||||
* <tt>null</tt> if this class visitor is not interested in visiting
|
||||
* these annotations and attributes.
|
||||
*/
|
||||
public FieldVisitor visitField(int access, String name, String desc,
|
||||
String signature, Object value) {
|
||||
* Visits a field of the class.
|
||||
*
|
||||
* @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if
|
||||
* the field is synthetic and/or deprecated.
|
||||
* @param name the field's name.
|
||||
* @param descriptor the field's descriptor (see {@link Type}).
|
||||
* @param signature the field's signature. May be {@literal null} if the field's type does not use
|
||||
* generic types.
|
||||
* @param value the field's initial value. This parameter, which may be {@literal null} if the
|
||||
* field does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
|
||||
* Long}, a {@link Double} or a {@link String} (for {@code int}, {@code float}, {@code long}
|
||||
* or {@code String} fields respectively). <i>This parameter is only used for static
|
||||
* fields</i>. Its value is ignored for non static fields, which must be initialized through
|
||||
* bytecode instructions in constructors or methods.
|
||||
* @return a visitor to visit field annotations and attributes, or {@literal null} if this class
|
||||
* visitor is not interested in visiting these annotations and attributes.
|
||||
*/
|
||||
public FieldVisitor visitField(
|
||||
final int access,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final String signature,
|
||||
final Object value) {
|
||||
if (cv != null) {
|
||||
return cv.visitField(access, name, desc, signature, value);
|
||||
return cv.visitField(access, name, descriptor, signature, value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a method of the class. This method <i>must</i> return a new
|
||||
* {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called,
|
||||
* i.e., it should not return a previously returned visitor.
|
||||
*
|
||||
* @param access
|
||||
* the method's access flags (see {@link Opcodes}). This
|
||||
* parameter also indicates if the method is synthetic and/or
|
||||
* deprecated.
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type Type}).
|
||||
* @param signature
|
||||
* the method's signature. May be <tt>null</tt> if the method
|
||||
* parameters, return type and exceptions do not use generic
|
||||
* types.
|
||||
* @param exceptions
|
||||
* the internal names of the method's exception classes (see
|
||||
* {@link Type#getInternalName() getInternalName}). May be
|
||||
* <tt>null</tt>.
|
||||
* @return an object to visit the byte code of the method, or <tt>null</tt>
|
||||
* if this class visitor is not interested in visiting the code of
|
||||
* this method.
|
||||
*/
|
||||
public MethodVisitor visitMethod(int access, String name, String desc,
|
||||
String signature, String[] exceptions) {
|
||||
* Visits a method of the class. This method <i>must</i> return a new {@link MethodVisitor}
|
||||
* instance (or {@literal null}) each time it is called, i.e., it should not return a previously
|
||||
* returned visitor.
|
||||
*
|
||||
* @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
|
||||
* the method is synthetic and/or deprecated.
|
||||
* @param name the method's name.
|
||||
* @param descriptor the method's descriptor (see {@link Type}).
|
||||
* @param signature the method's signature. May be {@literal null} if the method parameters,
|
||||
* return type and exceptions do not use generic types.
|
||||
* @param exceptions the internal names of the method's exception classes (see {@link
|
||||
* Type#getInternalName()}). May be {@literal null}.
|
||||
* @return an object to visit the byte code of the method, or {@literal null} if this class
|
||||
* visitor is not interested in visiting the code of this method.
|
||||
*/
|
||||
public MethodVisitor visitMethod(
|
||||
final int access,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final String signature,
|
||||
final String[] exceptions) {
|
||||
if (cv != null) {
|
||||
return cv.visitMethod(access, name, desc, signature, exceptions);
|
||||
return cv.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the end of the class. This method, which is the last one to be
|
||||
* called, is used to inform the visitor that all the fields and methods of
|
||||
* the class have been visited.
|
||||
*/
|
||||
* Visits the end of the class. This method, which is the last one to be called, is used to inform
|
||||
* the visitor that all the fields and methods of the class have been visited.
|
||||
*/
|
||||
public void visitEnd() {
|
||||
if (cv != null) {
|
||||
cv.visitEnd();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A constant whose value is computed at runtime, with a bootstrap method.
|
||||
*
|
||||
* @author Remi Forax
|
||||
*/
|
||||
public final class ConstantDynamic {
|
||||
|
||||
/** The constant name (can be arbitrary). */
|
||||
private final String name;
|
||||
|
||||
/** The constant type (must be a field descriptor). */
|
||||
private final String descriptor;
|
||||
|
||||
/** The bootstrap method to use to compute the constant value at runtime. */
|
||||
private final Handle bootstrapMethod;
|
||||
|
||||
/**
|
||||
* The arguments to pass to the bootstrap method, in order to compute the constant value at
|
||||
* runtime.
|
||||
*/
|
||||
private final Object[] bootstrapMethodArguments;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ConstantDynamic}.
|
||||
*
|
||||
* @param name the constant name (can be arbitrary).
|
||||
* @param descriptor the constant type (must be a field descriptor).
|
||||
* @param bootstrapMethod the bootstrap method to use to compute the constant value at runtime.
|
||||
* @param bootstrapMethodArguments the arguments to pass to the bootstrap method, in order to
|
||||
* compute the constant value at runtime.
|
||||
*/
|
||||
public ConstantDynamic(
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final Handle bootstrapMethod,
|
||||
final Object... bootstrapMethodArguments) {
|
||||
this.name = name;
|
||||
this.descriptor = descriptor;
|
||||
this.bootstrapMethod = bootstrapMethod;
|
||||
this.bootstrapMethodArguments = bootstrapMethodArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this constant.
|
||||
*
|
||||
* @return the name of this constant.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this constant.
|
||||
*
|
||||
* @return the type of this constant, as a field descriptor.
|
||||
*/
|
||||
public String getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bootstrap method used to compute the value of this constant.
|
||||
*
|
||||
* @return the bootstrap method used to compute the value of this constant.
|
||||
*/
|
||||
public Handle getBootstrapMethod() {
|
||||
return bootstrapMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of arguments passed to the bootstrap method, in order to compute the value
|
||||
* of this constant.
|
||||
*
|
||||
* @return the number of arguments passed to the bootstrap method, in order to compute the value
|
||||
* of this constant.
|
||||
*/
|
||||
public int getBootstrapMethodArgumentCount() {
|
||||
return bootstrapMethodArguments.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an argument passed to the bootstrap method, in order to compute the value of this
|
||||
* constant.
|
||||
*
|
||||
* @param index an argument index, between 0 and {@link #getBootstrapMethodArgumentCount()}
|
||||
* (exclusive).
|
||||
* @return the argument passed to the bootstrap method, with the given index.
|
||||
*/
|
||||
public Object getBootstrapMethodArgument(final int index) {
|
||||
return bootstrapMethodArguments[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the arguments to pass to the bootstrap method, in order to compute the value of this
|
||||
* constant. WARNING: this array must not be modified, and must not be returned to the user.
|
||||
*
|
||||
* @return the arguments to pass to the bootstrap method, in order to compute the value of this
|
||||
* constant.
|
||||
*/
|
||||
Object[] getBootstrapMethodArgumentsUnsafe() {
|
||||
return bootstrapMethodArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of this constant.
|
||||
*
|
||||
* @return the size of this constant, i.e., 2 for {@code long} and {@code double}, 1 otherwise.
|
||||
*/
|
||||
public int getSize() {
|
||||
char firstCharOfDescriptor = descriptor.charAt(0);
|
||||
return (firstCharOfDescriptor == 'J' || firstCharOfDescriptor == 'D') ? 2 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object object) {
|
||||
if (object == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(object instanceof ConstantDynamic)) {
|
||||
return false;
|
||||
}
|
||||
ConstantDynamic constantDynamic = (ConstantDynamic) object;
|
||||
return name.equals(constantDynamic.name)
|
||||
&& descriptor.equals(constantDynamic.descriptor)
|
||||
&& bootstrapMethod.equals(constantDynamic.bootstrapMethod)
|
||||
&& Arrays.equals(bootstrapMethodArguments, constantDynamic.bootstrapMethodArguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode()
|
||||
^ Integer.rotateLeft(descriptor.hashCode(), 8)
|
||||
^ Integer.rotateLeft(bootstrapMethod.hashCode(), 16)
|
||||
^ Integer.rotateLeft(Arrays.hashCode(bootstrapMethodArguments), 24);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name
|
||||
+ " : "
|
||||
+ descriptor
|
||||
+ ' '
|
||||
+ bootstrapMethod
|
||||
+ ' '
|
||||
+ Arrays.toString(bootstrapMethodArguments);
|
||||
}
|
||||
}
|
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* Defines additional JVM opcodes, access flags and constants which are not part of the ASM public
|
||||
* API.
|
||||
*
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
final class Constants implements Opcodes {
|
||||
|
||||
// The ClassFile attribute names, in the order they are defined in
|
||||
// https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7-300.
|
||||
|
||||
static final String CONSTANT_VALUE = "ConstantValue";
|
||||
static final String CODE = "Code";
|
||||
static final String STACK_MAP_TABLE = "StackMapTable";
|
||||
static final String EXCEPTIONS = "Exceptions";
|
||||
static final String INNER_CLASSES = "InnerClasses";
|
||||
static final String ENCLOSING_METHOD = "EnclosingMethod";
|
||||
static final String SYNTHETIC = "Synthetic";
|
||||
static final String SIGNATURE = "Signature";
|
||||
static final String SOURCE_FILE = "SourceFile";
|
||||
static final String SOURCE_DEBUG_EXTENSION = "SourceDebugExtension";
|
||||
static final String LINE_NUMBER_TABLE = "LineNumberTable";
|
||||
static final String LOCAL_VARIABLE_TABLE = "LocalVariableTable";
|
||||
static final String LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable";
|
||||
static final String DEPRECATED = "Deprecated";
|
||||
static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
|
||||
static final String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
|
||||
static final String RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations";
|
||||
static final String RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS =
|
||||
"RuntimeInvisibleParameterAnnotations";
|
||||
static final String RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations";
|
||||
static final String RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations";
|
||||
static final String ANNOTATION_DEFAULT = "AnnotationDefault";
|
||||
static final String BOOTSTRAP_METHODS = "BootstrapMethods";
|
||||
static final String METHOD_PARAMETERS = "MethodParameters";
|
||||
static final String MODULE = "Module";
|
||||
static final String MODULE_PACKAGES = "ModulePackages";
|
||||
static final String MODULE_MAIN_CLASS = "ModuleMainClass";
|
||||
static final String NEST_HOST = "NestHost";
|
||||
static final String NEST_MEMBERS = "NestMembers";
|
||||
|
||||
// ASM specific access flags.
|
||||
// WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
|
||||
// access flags, and also to make sure that these flags are automatically filtered out when
|
||||
// written in class files (because access flags are stored using 16 bits only).
|
||||
|
||||
static final int ACC_CONSTRUCTOR = 0x40000; // method access flag.
|
||||
|
||||
// ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}.
|
||||
|
||||
/**
|
||||
* A frame inserted between already existing frames. This internal stack map frame type (in
|
||||
* addition to the ones declared in {@link Opcodes}) can only be used if the frame content can be
|
||||
* computed from the previous existing frame and from the instructions between this existing frame
|
||||
* and the inserted one, without any knowledge of the type hierarchy. This kind of frame is only
|
||||
* used when an unconditional jump is inserted in a method while expanding an ASM specific
|
||||
* instruction. Keep in sync with Opcodes.java.
|
||||
*/
|
||||
static final int F_INSERT = 256;
|
||||
|
||||
// The JVM opcode values which are not part of the ASM public API.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html.
|
||||
|
||||
static final int LDC_W = 19;
|
||||
static final int LDC2_W = 20;
|
||||
static final int ILOAD_0 = 26;
|
||||
static final int ILOAD_1 = 27;
|
||||
static final int ILOAD_2 = 28;
|
||||
static final int ILOAD_3 = 29;
|
||||
static final int LLOAD_0 = 30;
|
||||
static final int LLOAD_1 = 31;
|
||||
static final int LLOAD_2 = 32;
|
||||
static final int LLOAD_3 = 33;
|
||||
static final int FLOAD_0 = 34;
|
||||
static final int FLOAD_1 = 35;
|
||||
static final int FLOAD_2 = 36;
|
||||
static final int FLOAD_3 = 37;
|
||||
static final int DLOAD_0 = 38;
|
||||
static final int DLOAD_1 = 39;
|
||||
static final int DLOAD_2 = 40;
|
||||
static final int DLOAD_3 = 41;
|
||||
static final int ALOAD_0 = 42;
|
||||
static final int ALOAD_1 = 43;
|
||||
static final int ALOAD_2 = 44;
|
||||
static final int ALOAD_3 = 45;
|
||||
static final int ISTORE_0 = 59;
|
||||
static final int ISTORE_1 = 60;
|
||||
static final int ISTORE_2 = 61;
|
||||
static final int ISTORE_3 = 62;
|
||||
static final int LSTORE_0 = 63;
|
||||
static final int LSTORE_1 = 64;
|
||||
static final int LSTORE_2 = 65;
|
||||
static final int LSTORE_3 = 66;
|
||||
static final int FSTORE_0 = 67;
|
||||
static final int FSTORE_1 = 68;
|
||||
static final int FSTORE_2 = 69;
|
||||
static final int FSTORE_3 = 70;
|
||||
static final int DSTORE_0 = 71;
|
||||
static final int DSTORE_1 = 72;
|
||||
static final int DSTORE_2 = 73;
|
||||
static final int DSTORE_3 = 74;
|
||||
static final int ASTORE_0 = 75;
|
||||
static final int ASTORE_1 = 76;
|
||||
static final int ASTORE_2 = 77;
|
||||
static final int ASTORE_3 = 78;
|
||||
static final int WIDE = 196;
|
||||
static final int GOTO_W = 200;
|
||||
static final int JSR_W = 201;
|
||||
|
||||
// Constants to convert between normal and wide jump instructions.
|
||||
|
||||
// The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP.
|
||||
static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - GOTO;
|
||||
|
||||
// Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa.
|
||||
|
||||
// The delta between the ASM_IFEQ, ..., ASM_IF_ACMPNE, ASM_GOTO and ASM_JSR opcodes
|
||||
// and IFEQ, ..., IF_ACMPNE, GOTO and JSR.
|
||||
static final int ASM_OPCODE_DELTA = 49;
|
||||
|
||||
// The delta between the ASM_IFNULL and ASM_IFNONNULL opcodes and IFNULL and IFNONNULL.
|
||||
static final int ASM_IFNULL_OPCODE_DELTA = 20;
|
||||
|
||||
// ASM specific opcodes, used for long forward jump instructions.
|
||||
|
||||
static final int ASM_IFEQ = IFEQ + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFNE = IFNE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFLT = IFLT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFGE = IFGE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFGT = IFGT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFLE = IFLE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPEQ = IF_ICMPEQ + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPNE = IF_ICMPNE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPLT = IF_ICMPLT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPGE = IF_ICMPGE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPGT = IF_ICMPGT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPLE = IF_ICMPLE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ACMPEQ = IF_ACMPEQ + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ACMPNE = IF_ACMPNE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_GOTO = GOTO + ASM_OPCODE_DELTA;
|
||||
static final int ASM_JSR = JSR + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA;
|
||||
static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
|
||||
static final int ASM_GOTO_W = 220;
|
||||
|
||||
private Constants() {}
|
||||
}
|
@ -56,7 +56,6 @@
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
@ -64,111 +63,105 @@ package jdk.internal.org.objectweb.asm;
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
class Context {
|
||||
final class Context {
|
||||
|
||||
/** The prototypes of the attributes that must be parsed in this class. */
|
||||
Attribute[] attributePrototypes;
|
||||
|
||||
/**
|
||||
* Prototypes of the attributes that must be parsed for this class.
|
||||
*/
|
||||
Attribute[] attrs;
|
||||
* The options used to parse this class. One or more of {@link ClassReader#SKIP_CODE}, {@link
|
||||
* ClassReader#SKIP_DEBUG}, {@link ClassReader#SKIP_FRAMES}, {@link ClassReader#EXPAND_FRAMES} or
|
||||
* {@link ClassReader#EXPAND_ASM_INSNS}.
|
||||
*/
|
||||
int parsingOptions;
|
||||
|
||||
/** The buffer used to read strings in the constant pool. */
|
||||
char[] charBuffer;
|
||||
|
||||
// Information about the current method, i.e. the one read in the current (or latest) call
|
||||
// to {@link ClassReader#readMethod()}.
|
||||
|
||||
/** The access flags of the current method. */
|
||||
int currentMethodAccessFlags;
|
||||
|
||||
/** The name of the current method. */
|
||||
String currentMethodName;
|
||||
|
||||
/** The descriptor of the current method. */
|
||||
String currentMethodDescriptor;
|
||||
|
||||
/**
|
||||
* The {@link ClassReader} option flags for the parsing of this class.
|
||||
*/
|
||||
int flags;
|
||||
* The labels of the current method, indexed by bytecode offset (only bytecode offsets for which a
|
||||
* label is needed have a non null associated Label).
|
||||
*/
|
||||
Label[] currentMethodLabels;
|
||||
|
||||
// Information about the current type annotation target, i.e. the one read in the current
|
||||
// (or latest) call to {@link ClassReader#readAnnotationTarget()}.
|
||||
|
||||
/**
|
||||
* The buffer used to read strings.
|
||||
*/
|
||||
char[] buffer;
|
||||
* The target_type and target_info of the current type annotation target, encoded as described in
|
||||
* {@link TypeReference}.
|
||||
*/
|
||||
int currentTypeAnnotationTarget;
|
||||
|
||||
/** The target_path of the current type annotation target. */
|
||||
TypePath currentTypeAnnotationTargetPath;
|
||||
|
||||
/** The start of each local variable range in the current local variable annotation. */
|
||||
Label[] currentLocalVariableAnnotationRangeStarts;
|
||||
|
||||
/** The end of each local variable range in the current local variable annotation. */
|
||||
Label[] currentLocalVariableAnnotationRangeEnds;
|
||||
|
||||
/**
|
||||
* The start index of each bootstrap method.
|
||||
*/
|
||||
int[] bootstrapMethods;
|
||||
* The local variable index of each local variable range in the current local variable annotation.
|
||||
*/
|
||||
int[] currentLocalVariableAnnotationRangeIndices;
|
||||
|
||||
// Information about the current stack map frame, i.e. the one read in the current (or latest)
|
||||
// call to {@link ClassReader#readFrame()}.
|
||||
|
||||
/** The bytecode offset of the current stack map frame. */
|
||||
int currentFrameOffset;
|
||||
|
||||
/**
|
||||
* The access flags of the method currently being parsed.
|
||||
*/
|
||||
int access;
|
||||
* The type of the current stack map frame. One of {@link Opcodes#F_FULL}, {@link
|
||||
* Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or {@link Opcodes#F_SAME1}.
|
||||
*/
|
||||
int currentFrameType;
|
||||
|
||||
/**
|
||||
* The name of the method currently being parsed.
|
||||
*/
|
||||
String name;
|
||||
* The number of local variable types in the current stack map frame. Each type is represented
|
||||
* with a single array element (even long and double).
|
||||
*/
|
||||
int currentFrameLocalCount;
|
||||
|
||||
/**
|
||||
* The descriptor of the method currently being parsed.
|
||||
*/
|
||||
String desc;
|
||||
* The delta number of local variable types in the current stack map frame (each type is
|
||||
* represented with a single array element - even long and double). This is the number of local
|
||||
* variable types in this frame, minus the number of local variable types in the previous frame.
|
||||
*/
|
||||
int currentFrameLocalCountDelta;
|
||||
|
||||
/**
|
||||
* The label objects, indexed by bytecode offset, of the method currently
|
||||
* being parsed (only bytecode offsets for which a label is needed have a
|
||||
* non null associated Label object).
|
||||
*/
|
||||
Label[] labels;
|
||||
* The types of the local variables in the current stack map frame. Each type is represented with
|
||||
* a single array element (even long and double), using the format described in {@link
|
||||
* MethodVisitor#visitFrame}. Depending on {@link #currentFrameType}, this contains the types of
|
||||
* all the local variables, or only those of the additional ones (compared to the previous frame).
|
||||
*/
|
||||
Object[] currentFrameLocalTypes;
|
||||
|
||||
/**
|
||||
* The target of the type annotation currently being parsed.
|
||||
*/
|
||||
int typeRef;
|
||||
* The number stack element types in the current stack map frame. Each type is represented with a
|
||||
* single array element (even long and double).
|
||||
*/
|
||||
int currentFrameStackCount;
|
||||
|
||||
/**
|
||||
* The path of the type annotation currently being parsed.
|
||||
*/
|
||||
TypePath typePath;
|
||||
|
||||
/**
|
||||
* The offset of the latest stack map frame that has been parsed.
|
||||
*/
|
||||
int offset;
|
||||
|
||||
/**
|
||||
* The labels corresponding to the start of the local variable ranges in the
|
||||
* local variable type annotation currently being parsed.
|
||||
*/
|
||||
Label[] start;
|
||||
|
||||
/**
|
||||
* The labels corresponding to the end of the local variable ranges in the
|
||||
* local variable type annotation currently being parsed.
|
||||
*/
|
||||
Label[] end;
|
||||
|
||||
/**
|
||||
* The local variable indices for each local variable range in the local
|
||||
* variable type annotation currently being parsed.
|
||||
*/
|
||||
int[] index;
|
||||
|
||||
/**
|
||||
* The encoding of the latest stack map frame that has been parsed.
|
||||
*/
|
||||
int mode;
|
||||
|
||||
/**
|
||||
* The number of locals in the latest stack map frame that has been parsed.
|
||||
*/
|
||||
int localCount;
|
||||
|
||||
/**
|
||||
* The number locals in the latest stack map frame that has been parsed,
|
||||
* minus the number of locals in the previous frame.
|
||||
*/
|
||||
int localDiff;
|
||||
|
||||
/**
|
||||
* The local values of the latest stack map frame that has been parsed.
|
||||
*/
|
||||
Object[] local;
|
||||
|
||||
/**
|
||||
* The stack size of the latest stack map frame that has been parsed.
|
||||
*/
|
||||
int stackCount;
|
||||
|
||||
/**
|
||||
* The stack values of the latest stack map frame that has been parsed.
|
||||
*/
|
||||
Object[] stack;
|
||||
* The types of the stack elements in the current stack map frame. Each type is represented with a
|
||||
* single array element (even long and double), using the format described in {@link
|
||||
* MethodVisitor#visitFrame}.
|
||||
*/
|
||||
Object[] currentFrameStackTypes;
|
||||
}
|
||||
|
@ -56,30 +56,31 @@
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* Information about the input stack map frame at the "current" instruction of a
|
||||
* method. This is implemented as a Frame subclass for a "basic block"
|
||||
* containing only one instruction.
|
||||
* Information about the input stack map frame at the "current" instruction of a method. This is
|
||||
* implemented as a Frame subclass for a "basic block" containing only one instruction.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
class CurrentFrame extends Frame {
|
||||
final class CurrentFrame extends Frame {
|
||||
|
||||
CurrentFrame(final Label owner) {
|
||||
super(owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this CurrentFrame to the input stack map frame of the next "current"
|
||||
* instruction, i.e. the instruction just after the given one. It is assumed
|
||||
* that the value of this object when this method is called is the stack map
|
||||
* frame status just before the given instruction is executed.
|
||||
*/
|
||||
* Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the
|
||||
* instruction just after the given one. It is assumed that the value of this object when this
|
||||
* method is called is the stack map frame status just before the given instruction is executed.
|
||||
*/
|
||||
@Override
|
||||
void execute(int opcode, int arg, ClassWriter cw, Item item) {
|
||||
super.execute(opcode, arg, cw, item);
|
||||
Frame successor = new Frame();
|
||||
merge(cw, successor, 0);
|
||||
set(successor);
|
||||
owner.inputStackTop = 0;
|
||||
void execute(
|
||||
final int opcode, final int arg, final Symbol symbolArg, final SymbolTable symbolTable) {
|
||||
super.execute(opcode, arg, symbolArg, symbolTable);
|
||||
Frame successor = new Frame(null);
|
||||
merge(symbolTable, successor, 0);
|
||||
copyFrom(successor);
|
||||
}
|
||||
}
|
||||
|
@ -59,46 +59,64 @@
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* An edge in the control flow graph of a method body. See {@link Label Label}.
|
||||
* An edge in the control flow graph of a method. Each node of this graph is a basic block,
|
||||
* represented with the Label corresponding to its first instruction. Each edge goes from one node
|
||||
* to another, i.e. from one basic block to another (called the predecessor and successor blocks,
|
||||
* respectively). An edge corresponds either to a jump or ret instruction or to an exception
|
||||
* handler.
|
||||
*
|
||||
* @see Label
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
class Edge {
|
||||
final class Edge {
|
||||
|
||||
/**
|
||||
* Denotes a normal control flow graph edge.
|
||||
*/
|
||||
static final int NORMAL = 0;
|
||||
* A control flow graph edge corresponding to a jump or ret instruction. Only used with {@link
|
||||
* ClassWriter#COMPUTE_FRAMES}.
|
||||
*/
|
||||
static final int JUMP = 0;
|
||||
|
||||
/**
|
||||
* Denotes a control flow graph edge corresponding to an exception handler.
|
||||
* More precisely any {@link Edge} whose {@link #info} is strictly positive
|
||||
* corresponds to an exception handler. The actual value of {@link #info} is
|
||||
* the index, in the {@link ClassWriter} type table, of the exception that
|
||||
* is catched.
|
||||
*/
|
||||
* A control flow graph edge corresponding to an exception handler. Only used with {@link
|
||||
* ClassWriter#COMPUTE_MAXS}.
|
||||
*/
|
||||
static final int EXCEPTION = 0x7FFFFFFF;
|
||||
|
||||
/**
|
||||
* Information about this control flow graph edge. If
|
||||
* {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative)
|
||||
* stack size in the basic block from which this edge originates. This size
|
||||
* is equal to the stack size at the "jump" instruction to which this edge
|
||||
* corresponds, relatively to the stack size at the beginning of the
|
||||
* originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used,
|
||||
* this field is the kind of this control flow graph edge (i.e. NORMAL or
|
||||
* EXCEPTION).
|
||||
*/
|
||||
int info;
|
||||
* Information about this control flow graph edge.
|
||||
*
|
||||
* <ul>
|
||||
* <li>If {@link ClassWriter#COMPUTE_MAXS} is used, this field contains either a stack size
|
||||
* delta (for an edge corresponding to a jump instruction), or the value EXCEPTION (for an
|
||||
* edge corresponding to an exception handler). The stack size delta is the stack size just
|
||||
* after the jump instruction, minus the stack size at the beginning of the predecessor
|
||||
* basic block, i.e. the one containing the jump instruction.
|
||||
* <li>If {@link ClassWriter#COMPUTE_FRAMES} is used, this field contains either the value JUMP
|
||||
* (for an edge corresponding to a jump instruction), or the index, in the {@link
|
||||
* ClassWriter} type table, of the exception type that is handled (for an edge corresponding
|
||||
* to an exception handler).
|
||||
* </ul>
|
||||
*/
|
||||
final int info;
|
||||
|
||||
/** The successor block of this control flow graph edge. */
|
||||
final Label successor;
|
||||
|
||||
/**
|
||||
* The successor block of the basic block from which this edge originates.
|
||||
*/
|
||||
Label successor;
|
||||
* The next edge in the list of outgoing edges of a basic block. See {@link Label#outgoingEdges}.
|
||||
*/
|
||||
Edge nextEdge;
|
||||
|
||||
/**
|
||||
* The next edge in the list of successors of the originating basic block.
|
||||
* See {@link Label#successors successors}.
|
||||
*/
|
||||
Edge next;
|
||||
* Constructs a new Edge.
|
||||
*
|
||||
* @param info see {@link #info}.
|
||||
* @param successor see {@link #successor}.
|
||||
* @param nextEdge see {@link #nextEdge}.
|
||||
*/
|
||||
Edge(final int info, final Label successor, final Edge nextEdge) {
|
||||
this.info = info;
|
||||
this.successor = successor;
|
||||
this.nextEdge = nextEdge;
|
||||
}
|
||||
}
|
||||
|
@ -59,118 +59,103 @@
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* A visitor to visit a Java field. The methods of this class must be called in
|
||||
* the following order: ( <tt>visitAnnotation</tt> |
|
||||
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
|
||||
* A visitor to visit a Java field. The methods of this class must be called in the following order:
|
||||
* ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code visitAttribute} )* {@code
|
||||
* visitEnd}.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public abstract class FieldVisitor {
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field
|
||||
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
* The ASM API version implemented by this visitor. The value of this field must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/**
|
||||
* The field visitor to which this visitor must delegate method calls. May
|
||||
* be null.
|
||||
*/
|
||||
/** The field visitor to which this visitor must delegate method calls. May be null. */
|
||||
protected FieldVisitor fv;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link FieldVisitor}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
* Constructs a new {@link FieldVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
*/
|
||||
public FieldVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link FieldVisitor}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
* @param fv
|
||||
* the field visitor to which this visitor must delegate method
|
||||
* calls. May be null.
|
||||
*/
|
||||
public FieldVisitor(final int api, final FieldVisitor fv) {
|
||||
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
|
||||
* Constructs a new {@link FieldVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be
|
||||
* null.
|
||||
*/
|
||||
public FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
|
||||
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.api = api;
|
||||
this.fv = fv;
|
||||
this.fv = fieldVisitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation of the field.
|
||||
*
|
||||
* @param desc
|
||||
* the class descriptor of the annotation class.
|
||||
* @param visible
|
||||
* <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||
* this visitor is not interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
* Visits an annotation of the field.
|
||||
*
|
||||
* @param descriptor the class descriptor of the annotation class.
|
||||
* @param visible {@literal true} if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
if (fv != null) {
|
||||
return fv.visitAnnotation(desc, visible);
|
||||
return fv.visitAnnotation(descriptor, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation on the type of the field.
|
||||
*
|
||||
* @param typeRef
|
||||
* a reference to the annotated type. The sort of this type
|
||||
* reference must be {@link TypeReference#FIELD FIELD}. See
|
||||
* {@link TypeReference}.
|
||||
* @param typePath
|
||||
* the path to the annotated type argument, wildcard bound, array
|
||||
* element type, or static inner type within 'typeRef'. May be
|
||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param desc
|
||||
* the class descriptor of the annotation class.
|
||||
* @param visible
|
||||
* <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||
* this visitor is not interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
* Visits an annotation on the type of the field.
|
||||
*
|
||||
* @param typeRef a reference to the annotated type. The sort of this type reference must be
|
||||
* {@link TypeReference#FIELD}. See {@link TypeReference}.
|
||||
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or
|
||||
* static inner type within 'typeRef'. May be {@literal null} if the annotation targets
|
||||
* 'typeRef' as a whole.
|
||||
* @param descriptor the class descriptor of the annotation class.
|
||||
* @param visible {@literal true} if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
throw new UnsupportedOperationException("This feature requires ASM5");
|
||||
}
|
||||
if (fv != null) {
|
||||
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
return fv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a non standard attribute of the field.
|
||||
*
|
||||
* @param attr
|
||||
* an attribute.
|
||||
*/
|
||||
public void visitAttribute(Attribute attr) {
|
||||
* Visits a non standard attribute of the field.
|
||||
*
|
||||
* @param attribute an attribute.
|
||||
*/
|
||||
public void visitAttribute(final Attribute attribute) {
|
||||
if (fv != null) {
|
||||
fv.visitAttribute(attr);
|
||||
fv.visitAttribute(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the end of the field. This method, which is the last one to be
|
||||
* called, is used to inform the visitor that all the annotations and
|
||||
* attributes of the field have been visited.
|
||||
*/
|
||||
* Visits the end of the field. This method, which is the last one to be called, is used to inform
|
||||
* the visitor that all the annotations and attributes of the field have been visited.
|
||||
*/
|
||||
public void visitEnd() {
|
||||
if (fv != null) {
|
||||
fv.visitEnd();
|
||||
|
@ -59,294 +59,319 @@
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* An {@link FieldVisitor} that generates Java fields in bytecode form.
|
||||
* A {@link FieldVisitor} that generates a corresponding 'field_info' structure, as defined in the
|
||||
* Java Virtual Machine Specification (JVMS).
|
||||
*
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5">JVMS
|
||||
* 4.5</a>
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
final class FieldWriter extends FieldVisitor {
|
||||
|
||||
/**
|
||||
* The class writer to which this field must be added.
|
||||
*/
|
||||
private final ClassWriter cw;
|
||||
/** Where the constants used in this FieldWriter must be stored. */
|
||||
private final SymbolTable symbolTable;
|
||||
|
||||
// Note: fields are ordered as in the field_info structure, and those related to attributes are
|
||||
// ordered as in Section 4.7 of the JVMS.
|
||||
|
||||
/**
|
||||
* Access flags of this field.
|
||||
*/
|
||||
private final int access;
|
||||
* The access_flags field of the field_info JVMS structure. This field can contain ASM specific
|
||||
* access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
|
||||
* ClassFile structure.
|
||||
*/
|
||||
private final int accessFlags;
|
||||
|
||||
/** The name_index field of the field_info JVMS structure. */
|
||||
private final int nameIndex;
|
||||
|
||||
/** The descriptor_index field of the field_info JVMS structure. */
|
||||
private final int descriptorIndex;
|
||||
|
||||
/**
|
||||
* The index of the constant pool item that contains the name of this
|
||||
* method.
|
||||
*/
|
||||
private final int name;
|
||||
* The signature_index field of the Signature attribute of this field_info, or 0 if there is no
|
||||
* Signature attribute.
|
||||
*/
|
||||
private int signatureIndex;
|
||||
|
||||
/**
|
||||
* The index of the constant pool item that contains the descriptor of this
|
||||
* field.
|
||||
*/
|
||||
private final int desc;
|
||||
* The constantvalue_index field of the ConstantValue attribute of this field_info, or 0 if there
|
||||
* is no ConstantValue attribute.
|
||||
*/
|
||||
private int constantValueIndex;
|
||||
|
||||
/**
|
||||
* The index of the constant pool item that contains the signature of this
|
||||
* field.
|
||||
*/
|
||||
private int signature;
|
||||
* The last runtime visible annotation of this field. The previous ones can be accessed with the
|
||||
* {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
|
||||
*/
|
||||
private AnnotationWriter lastRuntimeVisibleAnnotation;
|
||||
|
||||
/**
|
||||
* The index of the constant pool item that contains the constant value of
|
||||
* this field.
|
||||
*/
|
||||
private int value;
|
||||
* The last runtime invisible annotation of this field. The previous ones can be accessed with the
|
||||
* {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
|
||||
*/
|
||||
private AnnotationWriter lastRuntimeInvisibleAnnotation;
|
||||
|
||||
/**
|
||||
* The runtime visible annotations of this field. May be <tt>null</tt>.
|
||||
*/
|
||||
private AnnotationWriter anns;
|
||||
* The last runtime visible type annotation of this field. The previous ones can be accessed with
|
||||
* the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
|
||||
*/
|
||||
private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
|
||||
|
||||
/**
|
||||
* The runtime invisible annotations of this field. May be <tt>null</tt>.
|
||||
*/
|
||||
private AnnotationWriter ianns;
|
||||
* The last runtime invisible type annotation of this field. The previous ones can be accessed
|
||||
* with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
|
||||
*/
|
||||
private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
|
||||
|
||||
/**
|
||||
* The runtime visible type annotations of this field. May be <tt>null</tt>.
|
||||
*/
|
||||
private AnnotationWriter tanns;
|
||||
* The first non standard attribute of this field. The next ones can be accessed with the {@link
|
||||
* Attribute#nextAttribute} field. May be {@literal null}.
|
||||
*
|
||||
* <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
|
||||
* firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
|
||||
* #putFieldInfo} method writes the attributes in the order defined by this list, i.e. in the
|
||||
* reverse order specified by the user.
|
||||
*/
|
||||
private Attribute firstAttribute;
|
||||
|
||||
/**
|
||||
* The runtime invisible type annotations of this field. May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
private AnnotationWriter itanns;
|
||||
|
||||
/**
|
||||
* The non standard attributes of this field. May be <tt>null</tt>.
|
||||
*/
|
||||
private Attribute attrs;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a new {@link FieldWriter}.
|
||||
*
|
||||
* @param cw
|
||||
* the class writer to which this field must be added.
|
||||
* @param access
|
||||
* the field's access flags (see {@link Opcodes}).
|
||||
* @param name
|
||||
* the field's name.
|
||||
* @param desc
|
||||
* the field's descriptor (see {@link Type}).
|
||||
* @param signature
|
||||
* the field's signature. May be <tt>null</tt>.
|
||||
* @param value
|
||||
* the field's constant value. May be <tt>null</tt>.
|
||||
*/
|
||||
FieldWriter(final ClassWriter cw, final int access, final String name,
|
||||
final String desc, final String signature, final Object value) {
|
||||
super(Opcodes.ASM6);
|
||||
if (cw.firstField == null) {
|
||||
cw.firstField = this;
|
||||
} else {
|
||||
cw.lastField.fv = this;
|
||||
}
|
||||
cw.lastField = this;
|
||||
this.cw = cw;
|
||||
this.access = access;
|
||||
this.name = cw.newUTF8(name);
|
||||
this.desc = cw.newUTF8(desc);
|
||||
* Constructs a new {@link FieldWriter}.
|
||||
*
|
||||
* @param symbolTable where the constants used in this FieldWriter must be stored.
|
||||
* @param access the field's access flags (see {@link Opcodes}).
|
||||
* @param name the field's name.
|
||||
* @param descriptor the field's descriptor (see {@link Type}).
|
||||
* @param signature the field's signature. May be {@literal null}.
|
||||
* @param constantValue the field's constant value. May be {@literal null}.
|
||||
*/
|
||||
FieldWriter(
|
||||
final SymbolTable symbolTable,
|
||||
final int access,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final String signature,
|
||||
final Object constantValue) {
|
||||
super(Opcodes.ASM7);
|
||||
this.symbolTable = symbolTable;
|
||||
this.accessFlags = access;
|
||||
this.nameIndex = symbolTable.addConstantUtf8(name);
|
||||
this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
|
||||
if (signature != null) {
|
||||
this.signature = cw.newUTF8(signature);
|
||||
this.signatureIndex = symbolTable.addConstantUtf8(signature);
|
||||
}
|
||||
if (value != null) {
|
||||
this.value = cw.newConstItem(value).index;
|
||||
if (constantValue != null) {
|
||||
this.constantValueIndex = symbolTable.addConstant(constantValue).index;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Implementation of the FieldVisitor abstract class
|
||||
// ------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc,
|
||||
final boolean visible) {
|
||||
ByteVector bv = new ByteVector();
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
// Create a ByteVector to hold an 'annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
|
||||
ByteVector annotation = new ByteVector();
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
if (visible) {
|
||||
aw.next = anns;
|
||||
anns = aw;
|
||||
return lastRuntimeVisibleAnnotation =
|
||||
new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
|
||||
} else {
|
||||
aw.next = ianns;
|
||||
ianns = aw;
|
||||
return lastRuntimeInvisibleAnnotation =
|
||||
new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitTypeAnnotation(final int typeRef,
|
||||
final TypePath typePath, final String desc, final boolean visible) {
|
||||
ByteVector bv = new ByteVector();
|
||||
// write target_type and target_info
|
||||
AnnotationWriter.putTarget(typeRef, typePath, bv);
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
|
||||
bv.length - 2);
|
||||
public AnnotationVisitor visitTypeAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
|
||||
ByteVector typeAnnotation = new ByteVector();
|
||||
// Write target_type, target_info, and target_path.
|
||||
TypeReference.putTarget(typeRef, typeAnnotation);
|
||||
TypePath.put(typePath, typeAnnotation);
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
if (visible) {
|
||||
aw.next = tanns;
|
||||
tanns = aw;
|
||||
return lastRuntimeVisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
|
||||
} else {
|
||||
aw.next = itanns;
|
||||
itanns = aw;
|
||||
return lastRuntimeInvisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attr) {
|
||||
attr.next = attrs;
|
||||
attrs = attr;
|
||||
public void visitAttribute(final Attribute attribute) {
|
||||
// Store the attributes in the <i>reverse</i> order of their visit by this method.
|
||||
attribute.nextAttribute = firstAttribute;
|
||||
firstAttribute = attribute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the size of this field.
|
||||
*
|
||||
* @return the size of this field.
|
||||
*/
|
||||
int getSize() {
|
||||
* Returns the size of the field_info JVMS structure generated by this FieldWriter. Also adds the
|
||||
* names of the attributes of this field in the constant pool.
|
||||
*
|
||||
* @return the size in bytes of the field_info JVMS structure.
|
||||
*/
|
||||
int computeFieldInfoSize() {
|
||||
// The access_flags, name_index, descriptor_index and attributes_count fields use 8 bytes.
|
||||
int size = 8;
|
||||
if (value != 0) {
|
||||
cw.newUTF8("ConstantValue");
|
||||
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
|
||||
if (constantValueIndex != 0) {
|
||||
// ConstantValue attributes always use 8 bytes.
|
||||
symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE);
|
||||
size += 8;
|
||||
}
|
||||
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|
||||
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||
cw.newUTF8("Synthetic");
|
||||
size += 6;
|
||||
}
|
||||
}
|
||||
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
cw.newUTF8("Deprecated");
|
||||
// Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
|
||||
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
|
||||
&& symbolTable.getMajorVersion() < Opcodes.V1_5) {
|
||||
// Synthetic attributes always use 6 bytes.
|
||||
symbolTable.addConstantUtf8(Constants.SYNTHETIC);
|
||||
size += 6;
|
||||
}
|
||||
if (signature != 0) {
|
||||
cw.newUTF8("Signature");
|
||||
if (signatureIndex != 0) {
|
||||
// Signature attributes always use 8 bytes.
|
||||
symbolTable.addConstantUtf8(Constants.SIGNATURE);
|
||||
size += 8;
|
||||
}
|
||||
if (anns != null) {
|
||||
cw.newUTF8("RuntimeVisibleAnnotations");
|
||||
size += 8 + anns.getSize();
|
||||
// ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead.
|
||||
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
// Deprecated attributes always use 6 bytes.
|
||||
symbolTable.addConstantUtf8(Constants.DEPRECATED);
|
||||
size += 6;
|
||||
}
|
||||
if (ianns != null) {
|
||||
cw.newUTF8("RuntimeInvisibleAnnotations");
|
||||
size += 8 + ianns.getSize();
|
||||
if (lastRuntimeVisibleAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeVisibleAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_VISIBLE_ANNOTATIONS);
|
||||
}
|
||||
if (tanns != null) {
|
||||
cw.newUTF8("RuntimeVisibleTypeAnnotations");
|
||||
size += 8 + tanns.getSize();
|
||||
if (lastRuntimeInvisibleAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
|
||||
}
|
||||
if (itanns != null) {
|
||||
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
|
||||
size += 8 + itanns.getSize();
|
||||
if (lastRuntimeVisibleTypeAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
|
||||
}
|
||||
if (attrs != null) {
|
||||
size += attrs.getSize(cw, null, 0, -1, -1);
|
||||
if (lastRuntimeInvisibleTypeAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
|
||||
}
|
||||
if (firstAttribute != null) {
|
||||
size += firstAttribute.computeAttributesSize(symbolTable);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the content of this field into the given byte vector.
|
||||
*
|
||||
* @param out
|
||||
* where the content of this field must be put.
|
||||
*/
|
||||
void put(final ByteVector out) {
|
||||
final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
|
||||
int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
|
||||
| ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
|
||||
out.putShort(access & ~mask).putShort(name).putShort(desc);
|
||||
int attributeCount = 0;
|
||||
if (value != 0) {
|
||||
++attributeCount;
|
||||
* Puts the content of the field_info JVMS structure generated by this FieldWriter into the given
|
||||
* ByteVector.
|
||||
*
|
||||
* @param output where the field_info structure must be put.
|
||||
*/
|
||||
void putFieldInfo(final ByteVector output) {
|
||||
boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
|
||||
// Put the access_flags, name_index and descriptor_index fields.
|
||||
int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0;
|
||||
output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex);
|
||||
// Compute and put the attributes_count field.
|
||||
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
|
||||
int attributesCount = 0;
|
||||
if (constantValueIndex != 0) {
|
||||
++attributesCount;
|
||||
}
|
||||
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|
||||
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||
++attributeCount;
|
||||
}
|
||||
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
|
||||
++attributesCount;
|
||||
}
|
||||
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
++attributeCount;
|
||||
if (signatureIndex != 0) {
|
||||
++attributesCount;
|
||||
}
|
||||
if (signature != 0) {
|
||||
++attributeCount;
|
||||
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
++attributesCount;
|
||||
}
|
||||
if (anns != null) {
|
||||
++attributeCount;
|
||||
if (lastRuntimeVisibleAnnotation != null) {
|
||||
++attributesCount;
|
||||
}
|
||||
if (ianns != null) {
|
||||
++attributeCount;
|
||||
if (lastRuntimeInvisibleAnnotation != null) {
|
||||
++attributesCount;
|
||||
}
|
||||
if (tanns != null) {
|
||||
++attributeCount;
|
||||
if (lastRuntimeVisibleTypeAnnotation != null) {
|
||||
++attributesCount;
|
||||
}
|
||||
if (itanns != null) {
|
||||
++attributeCount;
|
||||
if (lastRuntimeInvisibleTypeAnnotation != null) {
|
||||
++attributesCount;
|
||||
}
|
||||
if (attrs != null) {
|
||||
attributeCount += attrs.getCount();
|
||||
if (firstAttribute != null) {
|
||||
attributesCount += firstAttribute.getAttributeCount();
|
||||
}
|
||||
out.putShort(attributeCount);
|
||||
if (value != 0) {
|
||||
out.putShort(cw.newUTF8("ConstantValue"));
|
||||
out.putInt(2).putShort(value);
|
||||
output.putShort(attributesCount);
|
||||
// Put the field_info attributes.
|
||||
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
|
||||
if (constantValueIndex != 0) {
|
||||
output
|
||||
.putShort(symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE))
|
||||
.putInt(2)
|
||||
.putShort(constantValueIndex);
|
||||
}
|
||||
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|
||||
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||
out.putShort(cw.newUTF8("Synthetic")).putInt(0);
|
||||
}
|
||||
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
|
||||
output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
|
||||
}
|
||||
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
out.putShort(cw.newUTF8("Deprecated")).putInt(0);
|
||||
if (signatureIndex != 0) {
|
||||
output
|
||||
.putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
|
||||
.putInt(2)
|
||||
.putShort(signatureIndex);
|
||||
}
|
||||
if (signature != 0) {
|
||||
out.putShort(cw.newUTF8("Signature"));
|
||||
out.putInt(2).putShort(signature);
|
||||
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
|
||||
}
|
||||
if (anns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
|
||||
anns.put(out);
|
||||
if (lastRuntimeVisibleAnnotation != null) {
|
||||
lastRuntimeVisibleAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
|
||||
}
|
||||
if (ianns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
|
||||
ianns.put(out);
|
||||
if (lastRuntimeInvisibleAnnotation != null) {
|
||||
lastRuntimeInvisibleAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
|
||||
}
|
||||
if (tanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
|
||||
tanns.put(out);
|
||||
if (lastRuntimeVisibleTypeAnnotation != null) {
|
||||
lastRuntimeVisibleTypeAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
|
||||
}
|
||||
if (itanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
|
||||
itanns.put(out);
|
||||
if (lastRuntimeInvisibleTypeAnnotation != null) {
|
||||
lastRuntimeInvisibleTypeAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
|
||||
}
|
||||
if (attrs != null) {
|
||||
attrs.put(cw, null, 0, -1, -1, out);
|
||||
if (firstAttribute != null) {
|
||||
firstAttribute.putAttributes(symbolTable, output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the attributes of this field into the given set of attribute prototypes.
|
||||
*
|
||||
* @param attributePrototypes a set of attribute prototypes.
|
||||
*/
|
||||
final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
|
||||
attributePrototypes.addAttributes(firstAttribute);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -56,7 +56,6 @@
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
@ -68,184 +67,153 @@ package jdk.internal.org.objectweb.asm;
|
||||
public final class Handle {
|
||||
|
||||
/**
|
||||
* The kind of field or method designated by this Handle. Should be
|
||||
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
|
||||
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
|
||||
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
|
||||
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
|
||||
* {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
*/
|
||||
final int tag;
|
||||
* The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD},
|
||||
* {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
|
||||
* Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
|
||||
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
*/
|
||||
private final int tag;
|
||||
|
||||
/** The internal name of the class that owns the field or method designated by this handle. */
|
||||
private final String owner;
|
||||
|
||||
/** The name of the field or method designated by this handle. */
|
||||
private final String name;
|
||||
|
||||
/** The descriptor of the field or method designated by this handle. */
|
||||
private final String descriptor;
|
||||
|
||||
/** Whether the owner is an interface or not. */
|
||||
private final boolean isInterface;
|
||||
|
||||
/**
|
||||
* The internal name of the class that owns the field or method designated
|
||||
* by this handle.
|
||||
*/
|
||||
final String owner;
|
||||
|
||||
/**
|
||||
* The name of the field or method designated by this handle.
|
||||
*/
|
||||
final String name;
|
||||
|
||||
/**
|
||||
* The descriptor of the field or method designated by this handle.
|
||||
*/
|
||||
final String desc;
|
||||
|
||||
|
||||
/**
|
||||
* Indicate if the owner is an interface or not.
|
||||
*/
|
||||
final boolean itf;
|
||||
|
||||
/**
|
||||
* Constructs a new field or method handle.
|
||||
*
|
||||
* @param tag
|
||||
* the kind of field or method designated by this Handle. Must be
|
||||
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
|
||||
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
|
||||
* {@link Opcodes#H_INVOKEVIRTUAL},
|
||||
* {@link Opcodes#H_INVOKESTATIC},
|
||||
* {@link Opcodes#H_INVOKESPECIAL},
|
||||
* {@link Opcodes#H_NEWINVOKESPECIAL} or
|
||||
* {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
* @param owner
|
||||
* the internal name of the class that owns the field or method
|
||||
* designated by this handle.
|
||||
* @param name
|
||||
* the name of the field or method designated by this handle.
|
||||
* @param desc
|
||||
* the descriptor of the field or method designated by this
|
||||
* handle.
|
||||
*
|
||||
* @deprecated this constructor has been superseded
|
||||
* by {@link #Handle(int, String, String, String, boolean)}.
|
||||
*/
|
||||
* Constructs a new field or method handle.
|
||||
*
|
||||
* @param tag the kind of field or method designated by this Handle. Must be {@link
|
||||
* Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link
|
||||
* Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
|
||||
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
|
||||
* Opcodes#H_INVOKEINTERFACE}.
|
||||
* @param owner the internal name of the class that owns the field or method designated by this
|
||||
* handle.
|
||||
* @param name the name of the field or method designated by this handle.
|
||||
* @param descriptor the descriptor of the field or method designated by this handle.
|
||||
* @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String,
|
||||
* boolean)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public Handle(int tag, String owner, String name, String desc) {
|
||||
this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
|
||||
public Handle(final int tag, final String owner, final String name, final String descriptor) {
|
||||
this(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new field or method handle.
|
||||
*
|
||||
* @param tag
|
||||
* the kind of field or method designated by this Handle. Must be
|
||||
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
|
||||
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
|
||||
* {@link Opcodes#H_INVOKEVIRTUAL},
|
||||
* {@link Opcodes#H_INVOKESTATIC},
|
||||
* {@link Opcodes#H_INVOKESPECIAL},
|
||||
* {@link Opcodes#H_NEWINVOKESPECIAL} or
|
||||
* {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
* @param owner
|
||||
* the internal name of the class that owns the field or method
|
||||
* designated by this handle.
|
||||
* @param name
|
||||
* the name of the field or method designated by this handle.
|
||||
* @param desc
|
||||
* the descriptor of the field or method designated by this
|
||||
* handle.
|
||||
* @param itf
|
||||
* true if the owner is an interface.
|
||||
*/
|
||||
public Handle(int tag, String owner, String name, String desc, boolean itf) {
|
||||
* Constructs a new field or method handle.
|
||||
*
|
||||
* @param tag the kind of field or method designated by this Handle. Must be {@link
|
||||
* Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link
|
||||
* Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
|
||||
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
|
||||
* Opcodes#H_INVOKEINTERFACE}.
|
||||
* @param owner the internal name of the class that owns the field or method designated by this
|
||||
* handle.
|
||||
* @param name the name of the field or method designated by this handle.
|
||||
* @param descriptor the descriptor of the field or method designated by this handle.
|
||||
* @param isInterface whether the owner is an interface or not.
|
||||
*/
|
||||
public Handle(
|
||||
final int tag,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
this.tag = tag;
|
||||
this.owner = owner;
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
this.itf = itf;
|
||||
this.descriptor = descriptor;
|
||||
this.isInterface = isInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the kind of field or method designated by this handle.
|
||||
*
|
||||
* @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
|
||||
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
|
||||
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
|
||||
* {@link Opcodes#H_INVOKESPECIAL},
|
||||
* {@link Opcodes#H_NEWINVOKESPECIAL} or
|
||||
* {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
*/
|
||||
* Returns the kind of field or method designated by this handle.
|
||||
*
|
||||
* @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
|
||||
* {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
|
||||
* Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
|
||||
* Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
*/
|
||||
public int getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the internal name of the class that owns the field or method
|
||||
* designated by this handle.
|
||||
*
|
||||
* @return the internal name of the class that owns the field or method
|
||||
* designated by this handle.
|
||||
*/
|
||||
* Returns the internal name of the class that owns the field or method designated by this handle.
|
||||
*
|
||||
* @return the internal name of the class that owns the field or method designated by this handle.
|
||||
*/
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the field or method designated by this handle.
|
||||
*
|
||||
* @return the name of the field or method designated by this handle.
|
||||
*/
|
||||
* Returns the name of the field or method designated by this handle.
|
||||
*
|
||||
* @return the name of the field or method designated by this handle.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the descriptor of the field or method designated by this handle.
|
||||
*
|
||||
* @return the descriptor of the field or method designated by this handle.
|
||||
*/
|
||||
* Returns the descriptor of the field or method designated by this handle.
|
||||
*
|
||||
* @return the descriptor of the field or method designated by this handle.
|
||||
*/
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the owner of the field or method designated
|
||||
* by this handle is an interface.
|
||||
*
|
||||
* @return true if the owner of the field or method designated
|
||||
* by this handle is an interface.
|
||||
*/
|
||||
* Returns true if the owner of the field or method designated by this handle is an interface.
|
||||
*
|
||||
* @return true if the owner of the field or method designated by this handle is an interface.
|
||||
*/
|
||||
public boolean isInterface() {
|
||||
return itf;
|
||||
return isInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
public boolean equals(final Object object) {
|
||||
if (object == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Handle)) {
|
||||
if (!(object instanceof Handle)) {
|
||||
return false;
|
||||
}
|
||||
Handle h = (Handle) obj;
|
||||
return tag == h.tag && itf == h.itf && owner.equals(h.owner)
|
||||
&& name.equals(h.name) && desc.equals(h.desc);
|
||||
Handle handle = (Handle) object;
|
||||
return tag == handle.tag
|
||||
&& isInterface == handle.isInterface
|
||||
&& owner.equals(handle.owner)
|
||||
&& name.equals(handle.name)
|
||||
&& descriptor.equals(handle.descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return tag + (itf? 64: 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
|
||||
return tag
|
||||
+ (isInterface ? 64 : 0)
|
||||
+ owner.hashCode() * name.hashCode() * descriptor.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the textual representation of this handle. The textual
|
||||
* representation is:
|
||||
*
|
||||
* <pre>
|
||||
* for a reference to a class:
|
||||
* owner '.' name desc ' ' '(' tag ')'
|
||||
* for a reference to an interface:
|
||||
* owner '.' name desc ' ' '(' tag ' ' itf ')'
|
||||
* </pre>
|
||||
*
|
||||
* . As this format is unambiguous, it can be parsed if necessary.
|
||||
*/
|
||||
* Returns the textual representation of this handle. The textual representation is:
|
||||
*
|
||||
* <ul>
|
||||
* <li>for a reference to a class: owner "." name descriptor " (" tag ")",
|
||||
* <li>for a reference to an interface: owner "." name descriptor " (" tag " itf)".
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return owner + '.' + name + desc + " (" + tag + (itf? " itf": "") + ')';
|
||||
return owner + '.' + name + descriptor + " (" + tag + (isInterface ? " itf" : "") + ')';
|
||||
}
|
||||
}
|
||||
|
@ -59,92 +59,171 @@
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* Information about an exception handler block.
|
||||
* Information about an exception handler. Corresponds to an element of the exception_table array of
|
||||
* a Code attribute, as defined in the Java Virtual Machine Specification (JVMS). Handler instances
|
||||
* can be chained together, with their {@link #nextHandler} field, to describe a full JVMS
|
||||
* exception_table array.
|
||||
*
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS
|
||||
* 4.7.3</a>
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
class Handler {
|
||||
final class Handler {
|
||||
|
||||
/**
|
||||
* Beginning of the exception handler's scope (inclusive).
|
||||
*/
|
||||
Label start;
|
||||
* The start_pc field of this JVMS exception_table entry. Corresponds to the beginning of the
|
||||
* exception handler's scope (inclusive).
|
||||
*/
|
||||
final Label startPc;
|
||||
|
||||
/**
|
||||
* End of the exception handler's scope (exclusive).
|
||||
*/
|
||||
Label end;
|
||||
* The end_pc field of this JVMS exception_table entry. Corresponds to the end of the exception
|
||||
* handler's scope (exclusive).
|
||||
*/
|
||||
final Label endPc;
|
||||
|
||||
/**
|
||||
* Beginning of the exception handler's code.
|
||||
*/
|
||||
Label handler;
|
||||
* The handler_pc field of this JVMS exception_table entry. Corresponding to the beginning of the
|
||||
* exception handler's code.
|
||||
*/
|
||||
final Label handlerPc;
|
||||
|
||||
/**
|
||||
* Internal name of the type of exceptions handled by this handler, or
|
||||
* <tt>null</tt> to catch any exceptions.
|
||||
*/
|
||||
String desc;
|
||||
* The catch_type field of this JVMS exception_table entry. This is the constant pool index of the
|
||||
* internal name of the type of exceptions handled by this handler, or 0 to catch any exceptions.
|
||||
*/
|
||||
final int catchType;
|
||||
|
||||
/**
|
||||
* Constant pool index of the internal name of the type of exceptions
|
||||
* handled by this handler, or 0 to catch any exceptions.
|
||||
*/
|
||||
int type;
|
||||
* The internal name of the type of exceptions handled by this handler, or {@literal null} to
|
||||
* catch any exceptions.
|
||||
*/
|
||||
final String catchTypeDescriptor;
|
||||
|
||||
/** The next exception handler. */
|
||||
Handler nextHandler;
|
||||
|
||||
/**
|
||||
* Next exception handler block info.
|
||||
*/
|
||||
Handler next;
|
||||
* Constructs a new Handler.
|
||||
*
|
||||
* @param startPc the start_pc field of this JVMS exception_table entry.
|
||||
* @param endPc the end_pc field of this JVMS exception_table entry.
|
||||
* @param handlerPc the handler_pc field of this JVMS exception_table entry.
|
||||
* @param catchType The catch_type field of this JVMS exception_table entry.
|
||||
* @param catchTypeDescriptor The internal name of the type of exceptions handled by this handler,
|
||||
* or {@literal null} to catch any exceptions.
|
||||
*/
|
||||
Handler(
|
||||
final Label startPc,
|
||||
final Label endPc,
|
||||
final Label handlerPc,
|
||||
final int catchType,
|
||||
final String catchTypeDescriptor) {
|
||||
this.startPc = startPc;
|
||||
this.endPc = endPc;
|
||||
this.handlerPc = handlerPc;
|
||||
this.catchType = catchType;
|
||||
this.catchTypeDescriptor = catchTypeDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the range between start and end from the given exception
|
||||
* handlers.
|
||||
*
|
||||
* @param h
|
||||
* an exception handler list.
|
||||
* @param start
|
||||
* the start of the range to be removed.
|
||||
* @param end
|
||||
* the end of the range to be removed. Maybe null.
|
||||
* @return the exception handler list with the start-end range removed.
|
||||
*/
|
||||
static Handler remove(Handler h, Label start, Label end) {
|
||||
if (h == null) {
|
||||
* Constructs a new Handler from the given one, with a different scope.
|
||||
*
|
||||
* @param handler an existing Handler.
|
||||
* @param startPc the start_pc field of this JVMS exception_table entry.
|
||||
* @param endPc the end_pc field of this JVMS exception_table entry.
|
||||
*/
|
||||
Handler(final Handler handler, final Label startPc, final Label endPc) {
|
||||
this(startPc, endPc, handler.handlerPc, handler.catchType, handler.catchTypeDescriptor);
|
||||
this.nextHandler = handler.nextHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the range between start and end from the Handler list that begins with the given
|
||||
* element.
|
||||
*
|
||||
* @param firstHandler the beginning of a Handler list. May be {@literal null}.
|
||||
* @param start the start of the range to be removed.
|
||||
* @param end the end of the range to be removed. Maybe {@literal null}.
|
||||
* @return the exception handler list with the start-end range removed.
|
||||
*/
|
||||
static Handler removeRange(final Handler firstHandler, final Label start, final Label end) {
|
||||
if (firstHandler == null) {
|
||||
return null;
|
||||
} else {
|
||||
h.next = remove(h.next, start, end);
|
||||
firstHandler.nextHandler = removeRange(firstHandler.nextHandler, start, end);
|
||||
}
|
||||
int hstart = h.start.position;
|
||||
int hend = h.end.position;
|
||||
int s = start.position;
|
||||
int e = end == null ? Integer.MAX_VALUE : end.position;
|
||||
// if [hstart,hend[ and [s,e[ intervals intersect...
|
||||
if (s < hend && e > hstart) {
|
||||
if (s <= hstart) {
|
||||
if (e >= hend) {
|
||||
// [hstart,hend[ fully included in [s,e[, h removed
|
||||
h = h.next;
|
||||
} else {
|
||||
// [hstart,hend[ minus [s,e[ = [e,hend[
|
||||
h.start = end;
|
||||
}
|
||||
} else if (e >= hend) {
|
||||
// [hstart,hend[ minus [s,e[ = [hstart,s[
|
||||
h.end = start;
|
||||
int handlerStart = firstHandler.startPc.bytecodeOffset;
|
||||
int handlerEnd = firstHandler.endPc.bytecodeOffset;
|
||||
int rangeStart = start.bytecodeOffset;
|
||||
int rangeEnd = end == null ? Integer.MAX_VALUE : end.bytecodeOffset;
|
||||
// Return early if [handlerStart,handlerEnd[ and [rangeStart,rangeEnd[ don't intersect.
|
||||
if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) {
|
||||
return firstHandler;
|
||||
}
|
||||
if (rangeStart <= handlerStart) {
|
||||
if (rangeEnd >= handlerEnd) {
|
||||
// If [handlerStart,handlerEnd[ is included in [rangeStart,rangeEnd[, remove firstHandler.
|
||||
return firstHandler.nextHandler;
|
||||
} else {
|
||||
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
|
||||
Handler g = new Handler();
|
||||
g.start = end;
|
||||
g.end = h.end;
|
||||
g.handler = h.handler;
|
||||
g.desc = h.desc;
|
||||
g.type = h.type;
|
||||
g.next = h.next;
|
||||
h.end = start;
|
||||
h.next = g;
|
||||
// [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [rangeEnd,handlerEnd[
|
||||
return new Handler(firstHandler, end, firstHandler.endPc);
|
||||
}
|
||||
} else if (rangeEnd >= handlerEnd) {
|
||||
// [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [handlerStart,rangeStart[
|
||||
return new Handler(firstHandler, firstHandler.startPc, start);
|
||||
} else {
|
||||
// [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ =
|
||||
// [handlerStart,rangeStart[ + [rangeEnd,handerEnd[
|
||||
firstHandler.nextHandler = new Handler(firstHandler, end, firstHandler.endPc);
|
||||
return new Handler(firstHandler, firstHandler.startPc, start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements of the Handler list that begins with the given element.
|
||||
*
|
||||
* @param firstHandler the beginning of a Handler list. May be {@literal null}.
|
||||
* @return the number of elements of the Handler list that begins with 'handler'.
|
||||
*/
|
||||
static int getExceptionTableLength(final Handler firstHandler) {
|
||||
int length = 0;
|
||||
Handler handler = firstHandler;
|
||||
while (handler != null) {
|
||||
length++;
|
||||
handler = handler.nextHandler;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size in bytes of the JVMS exception_table corresponding to the Handler list that
|
||||
* begins with the given element. <i>This includes the exception_table_length field.</i>
|
||||
*
|
||||
* @param firstHandler the beginning of a Handler list. May be {@literal null}.
|
||||
* @return the size in bytes of the exception_table_length and exception_table structures.
|
||||
*/
|
||||
static int getExceptionTableSize(final Handler firstHandler) {
|
||||
return 2 + 8 * getExceptionTableLength(firstHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the JVMS exception_table corresponding to the Handler list that begins with the given
|
||||
* element. <i>This includes the exception_table_length field.</i>
|
||||
*
|
||||
* @param firstHandler the beginning of a Handler list. May be {@literal null}.
|
||||
* @param output where the exception_table_length and exception_table structures must be put.
|
||||
*/
|
||||
static void putExceptionTable(final Handler firstHandler, final ByteVector output) {
|
||||
output.putShort(getExceptionTableLength(firstHandler));
|
||||
Handler handler = firstHandler;
|
||||
while (handler != null) {
|
||||
output
|
||||
.putShort(handler.startPc.bytecodeOffset)
|
||||
.putShort(handler.endPc.bytecodeOffset)
|
||||
.putShort(handler.handlerPc.bytecodeOffset)
|
||||
.putShort(handler.catchType);
|
||||
handler = handler.nextHandler;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
@ -1,347 +0,0 @@
|
||||
/*
|
||||
* 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* A constant pool item. Constant pool items can be created with the 'newXXX'
|
||||
* methods in the {@link ClassWriter} class.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
final class Item {
|
||||
|
||||
/**
|
||||
* Index of this item in the constant pool.
|
||||
*/
|
||||
int index;
|
||||
|
||||
/**
|
||||
* Type of this constant pool item. A single class is used to represent all
|
||||
* constant pool item types, in order to minimize the bytecode size of this
|
||||
* package. The value of this field is one of {@link ClassWriter#INT},
|
||||
* {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT},
|
||||
* {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
|
||||
* {@link ClassWriter#STR}, {@link ClassWriter#CLASS},
|
||||
* {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
|
||||
* {@link ClassWriter#METH}, {@link ClassWriter#IMETH},
|
||||
* {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
|
||||
* {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
|
||||
*
|
||||
* MethodHandle constant 9 variations are stored using a range of 9 values
|
||||
* from {@link ClassWriter#HANDLE_BASE} + 1 to
|
||||
* {@link ClassWriter#HANDLE_BASE} + 9.
|
||||
*
|
||||
* Special Item types are used for Items that are stored in the ClassWriter
|
||||
* {@link ClassWriter#typeTable}, instead of the constant pool, in order to
|
||||
* avoid clashes with normal constant pool items in the ClassWriter constant
|
||||
* pool's hash table. These special item types are
|
||||
* {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and
|
||||
* {@link ClassWriter#TYPE_MERGED}.
|
||||
*/
|
||||
int type;
|
||||
|
||||
/**
|
||||
* Value of this item, for an integer item.
|
||||
*/
|
||||
int intVal;
|
||||
|
||||
/**
|
||||
* Value of this item, for a long item.
|
||||
*/
|
||||
long longVal;
|
||||
|
||||
/**
|
||||
* First part of the value of this item, for items that do not hold a
|
||||
* primitive value.
|
||||
*/
|
||||
String strVal1;
|
||||
|
||||
/**
|
||||
* Second part of the value of this item, for items that do not hold a
|
||||
* primitive value.
|
||||
*/
|
||||
String strVal2;
|
||||
|
||||
/**
|
||||
* Third part of the value of this item, for items that do not hold a
|
||||
* primitive value.
|
||||
*/
|
||||
String strVal3;
|
||||
|
||||
/**
|
||||
* The hash code value of this constant pool item.
|
||||
*/
|
||||
int hashCode;
|
||||
|
||||
/**
|
||||
* Link to another constant pool item, used for collision lists in the
|
||||
* constant pool's hash table.
|
||||
*/
|
||||
Item next;
|
||||
|
||||
/**
|
||||
* Constructs an uninitialized {@link Item}.
|
||||
*/
|
||||
Item() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an uninitialized {@link Item} for constant pool element at
|
||||
* given position.
|
||||
*
|
||||
* @param index
|
||||
* index of the item to be constructed.
|
||||
*/
|
||||
Item(final int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a copy of the given item.
|
||||
*
|
||||
* @param index
|
||||
* index of the item to be constructed.
|
||||
* @param i
|
||||
* the item that must be copied into the item to be constructed.
|
||||
*/
|
||||
Item(final int index, final Item i) {
|
||||
this.index = index;
|
||||
type = i.type;
|
||||
intVal = i.intVal;
|
||||
longVal = i.longVal;
|
||||
strVal1 = i.strVal1;
|
||||
strVal2 = i.strVal2;
|
||||
strVal3 = i.strVal3;
|
||||
hashCode = i.hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item to an integer item.
|
||||
*
|
||||
* @param intVal
|
||||
* the value of this item.
|
||||
*/
|
||||
void set(final int intVal) {
|
||||
this.type = ClassWriter.INT;
|
||||
this.intVal = intVal;
|
||||
this.hashCode = 0x7FFFFFFF & (type + intVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item to a long item.
|
||||
*
|
||||
* @param longVal
|
||||
* the value of this item.
|
||||
*/
|
||||
void set(final long longVal) {
|
||||
this.type = ClassWriter.LONG;
|
||||
this.longVal = longVal;
|
||||
this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item to a float item.
|
||||
*
|
||||
* @param floatVal
|
||||
* the value of this item.
|
||||
*/
|
||||
void set(final float floatVal) {
|
||||
this.type = ClassWriter.FLOAT;
|
||||
this.intVal = Float.floatToRawIntBits(floatVal);
|
||||
this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item to a double item.
|
||||
*
|
||||
* @param doubleVal
|
||||
* the value of this item.
|
||||
*/
|
||||
void set(final double doubleVal) {
|
||||
this.type = ClassWriter.DOUBLE;
|
||||
this.longVal = Double.doubleToRawLongBits(doubleVal);
|
||||
this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item to an item that do not hold a primitive value.
|
||||
*
|
||||
* @param type
|
||||
* the type of this item.
|
||||
* @param strVal1
|
||||
* first part of the value of this item.
|
||||
* @param strVal2
|
||||
* second part of the value of this item.
|
||||
* @param strVal3
|
||||
* third part of the value of this item.
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
void set(final int type, final String strVal1, final String strVal2,
|
||||
final String strVal3) {
|
||||
this.type = type;
|
||||
this.strVal1 = strVal1;
|
||||
this.strVal2 = strVal2;
|
||||
this.strVal3 = strVal3;
|
||||
switch (type) {
|
||||
case ClassWriter.CLASS:
|
||||
this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
|
||||
case ClassWriter.UTF8:
|
||||
case ClassWriter.STR:
|
||||
case ClassWriter.MTYPE:
|
||||
case ClassWriter.MODULE:
|
||||
case ClassWriter.PACKAGE:
|
||||
case ClassWriter.TYPE_NORMAL:
|
||||
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
|
||||
return;
|
||||
case ClassWriter.NAME_TYPE: {
|
||||
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
|
||||
* strVal2.hashCode());
|
||||
return;
|
||||
}
|
||||
// ClassWriter.FIELD:
|
||||
// ClassWriter.METH:
|
||||
// ClassWriter.IMETH:
|
||||
// ClassWriter.HANDLE_BASE + 1..9
|
||||
default:
|
||||
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
|
||||
* strVal2.hashCode() * strVal3.hashCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the item to an InvokeDynamic item.
|
||||
*
|
||||
* @param name
|
||||
* invokedynamic's name.
|
||||
* @param desc
|
||||
* invokedynamic's desc.
|
||||
* @param bsmIndex
|
||||
* zero based index into the class attribute BootrapMethods.
|
||||
*/
|
||||
void set(String name, String desc, int bsmIndex) {
|
||||
this.type = ClassWriter.INDY;
|
||||
this.longVal = bsmIndex;
|
||||
this.strVal1 = name;
|
||||
this.strVal2 = desc;
|
||||
this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex
|
||||
* strVal1.hashCode() * strVal2.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the item to a BootstrapMethod item.
|
||||
*
|
||||
* @param position
|
||||
* position in byte in the class attribute BootrapMethods.
|
||||
* @param hashCode
|
||||
* hashcode of the item. This hashcode is processed from the
|
||||
* hashcode of the bootstrap method and the hashcode of all
|
||||
* bootstrap arguments.
|
||||
*/
|
||||
void set(int position, int hashCode) {
|
||||
this.type = ClassWriter.BSM;
|
||||
this.intVal = position;
|
||||
this.hashCode = hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the given item is equal to this one. <i>This method assumes
|
||||
* that the two items have the same {@link #type}</i>.
|
||||
*
|
||||
* @param i
|
||||
* the item to be compared to this one. Both items must have the
|
||||
* same {@link #type}.
|
||||
* @return <tt>true</tt> if the given item if equal to this one,
|
||||
* <tt>false</tt> otherwise.
|
||||
*/
|
||||
boolean isEqualTo(final Item i) {
|
||||
switch (type) {
|
||||
case ClassWriter.UTF8:
|
||||
case ClassWriter.STR:
|
||||
case ClassWriter.CLASS:
|
||||
case ClassWriter.MODULE:
|
||||
case ClassWriter.PACKAGE:
|
||||
case ClassWriter.MTYPE:
|
||||
case ClassWriter.TYPE_NORMAL:
|
||||
return i.strVal1.equals(strVal1);
|
||||
case ClassWriter.TYPE_MERGED:
|
||||
case ClassWriter.LONG:
|
||||
case ClassWriter.DOUBLE:
|
||||
return i.longVal == longVal;
|
||||
case ClassWriter.INT:
|
||||
case ClassWriter.FLOAT:
|
||||
return i.intVal == intVal;
|
||||
case ClassWriter.TYPE_UNINIT:
|
||||
return i.intVal == intVal && i.strVal1.equals(strVal1);
|
||||
case ClassWriter.NAME_TYPE:
|
||||
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
|
||||
case ClassWriter.INDY: {
|
||||
return i.longVal == longVal && i.strVal1.equals(strVal1)
|
||||
&& i.strVal2.equals(strVal2);
|
||||
}
|
||||
// case ClassWriter.FIELD:
|
||||
// case ClassWriter.METH:
|
||||
// case ClassWriter.IMETH:
|
||||
// case ClassWriter.HANDLE_BASE + 1..9
|
||||
default:
|
||||
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2)
|
||||
&& i.strVal3.equals(strVal3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* Exception thrown when the Code attribute of a method produced by a {@link ClassWriter} is too
|
||||
* large.
|
||||
*
|
||||
* @author Jason Zaugg
|
||||
*/
|
||||
public final class MethodTooLargeException extends IndexOutOfBoundsException {
|
||||
private static final long serialVersionUID = 6807380416709738314L;
|
||||
|
||||
private final String className;
|
||||
private final String methodName;
|
||||
private final String descriptor;
|
||||
private final int codeSize;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link MethodTooLargeException}.
|
||||
*
|
||||
* @param className the internal name of the owner class.
|
||||
* @param methodName the name of the method.
|
||||
* @param descriptor the descriptor of the method.
|
||||
* @param codeSize the size of the method's Code attribute, in bytes.
|
||||
*/
|
||||
public MethodTooLargeException(
|
||||
final String className,
|
||||
final String methodName,
|
||||
final String descriptor,
|
||||
final int codeSize) {
|
||||
super("Method too large: " + className + "." + methodName + " " + descriptor);
|
||||
this.className = className;
|
||||
this.methodName = methodName;
|
||||
this.descriptor = descriptor;
|
||||
this.codeSize = codeSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the internal name of the owner class.
|
||||
*
|
||||
* @return the internal name of the owner class.
|
||||
*/
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the method.
|
||||
*
|
||||
* @return the name of the method.
|
||||
*/
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the descriptor of the method.
|
||||
*
|
||||
* @return the descriptor of the method.
|
||||
*/
|
||||
public String getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the method's Code attribute, in bytes.
|
||||
*
|
||||
* @return the size of the method's Code attribute, in bytes.
|
||||
*/
|
||||
public int getCodeSize() {
|
||||
return codeSize;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user