This commit is contained in:
Prasanta Sadhukhan 2018-11-14 17:26:24 +05:30
commit 3b27432323
357 changed files with 33098 additions and 28906 deletions

View File

@ -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

View File

@ -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

View File

@ -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"
},

View File

@ -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");

View File

@ -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),

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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());

View File

@ -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;
}

View File

@ -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"

View File

@ -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());

View File

@ -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;

View File

@ -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();

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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");

View File

@ -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 {

View File

@ -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())) {

View File

@ -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() {

View File

@ -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() {

View File

@ -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",

View File

@ -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);

View File

@ -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(&copy);
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;
}

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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(&copy);
d_table->iterate(&copy);
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.

View File

@ -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;

View File

@ -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");

View File

@ -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() {

View File

@ -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 {

View File

@ -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;

View File

@ -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()) {

View File

@ -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;

View File

@ -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());

View File

@ -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();

View File

@ -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.

View File

@ -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*) \

View File

@ -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>

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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

View File

@ -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;
}
}

View File

@ -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()

View File

@ -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

View File

@ -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
//

View File

@ -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();
}

View File

@ -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() {

View File

@ -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

View File

@ -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);

View File

@ -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() {

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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
*/

View File

@ -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());

View File

@ -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();
}

View File

@ -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 + "]";

View File

@ -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>
*

View File

@ -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

View File

@ -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.

View File

@ -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>

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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) {

View File

@ -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();

View File

@ -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);
}
}
}

View File

@ -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()
};
}

View File

@ -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 &gt;= 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;
}

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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() {}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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" : "") + ')';
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

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