[openjdk-7-jre-dcevm] 03/04: DCEVM patch for Java 7u60
Emmanuel Bourg
ebourg-guest at moszumanska.debian.org
Mon Sep 1 21:20:17 UTC 2014
This is an automated email from the git hooks/post-receive script.
ebourg-guest pushed a commit to branch master
in repository openjdk-7-jre-dcevm.
commit 7da47b300d5a2863119a1e5982719d085a31db39
Author: Emmanuel Bourg <ebourg at apache.org>
Date: Mon Sep 1 19:54:52 2014 +0200
DCEVM patch for Java 7u60
---
...ll-jdk7u55-b13.patch => full-jdk7u60-b09.patch} | 2957 ++++++++++----------
debian/patches/series | 2 +-
2 files changed, 1547 insertions(+), 1412 deletions(-)
diff --git a/debian/patches/full-jdk7u55-b13.patch b/debian/patches/full-jdk7u60-b09.patch
similarity index 96%
rename from debian/patches/full-jdk7u55-b13.patch
rename to debian/patches/full-jdk7u60-b09.patch
index 20c086d..4c7dedd 100644
--- a/debian/patches/full-jdk7u55-b13.patch
+++ b/debian/patches/full-jdk7u60-b09.patch
@@ -1,6 +1,6 @@
--- a/make/bsd/makefiles/gcc.make
+++ b/make/bsd/makefiles/gcc.make
-@@ -116,7 +116,10 @@
+@@ -117,7 +117,10 @@
CFLAGS += -fno-rtti
CFLAGS += -fno-exceptions
CFLAGS += -pthread
@@ -331,25 +331,6 @@
// Get receiver klass into rdx - also a null check
__ restore_locals(); // restore r14
__ null_check(rcx, oopDesc::klass_offset_in_bytes());
---- a/src/os/bsd/vm/attachListener_bsd.cpp
-+++ b/src/os/bsd/vm/attachListener_bsd.cpp
-@@ -460,14 +460,14 @@
-
- void AttachListener::vm_start() {
- char fn[UNIX_PATH_MAX];
-- struct stat64 st;
-+ struct stat st;
- int ret;
-
- int n = snprintf(fn, UNIX_PATH_MAX, "%s/.java_pid%d",
- os::get_temp_directory(), os::current_process_id());
- assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow");
-
-- RESTARTABLE(::stat64(fn, &st), ret);
-+ RESTARTABLE(::stat(fn, &st), ret);
- if (ret == 0) {
- ret = ::unlink(fn);
- if (ret == -1) {
--- a/src/share/vm/c1/c1_Compilation.hpp
+++ b/src/share/vm/c1/c1_Compilation.hpp
@@ -242,8 +242,8 @@
@@ -567,7 +548,7 @@
// Copy byte codes
m->set_code(code_start);
-@@ -2797,6 +2838,15 @@
+@@ -2792,6 +2833,15 @@
"Invalid Deprecated classfile attribute length %u in class file %s",
attribute_length, CHECK);
}
@@ -583,7 +564,7 @@
} else if (_major_version >= JAVA_1_5_VERSION) {
if (tag == vmSymbols::tag_signature()) {
if (attribute_length != 2) {
-@@ -2900,6 +2950,17 @@
+@@ -2895,6 +2945,17 @@
}
k->set_inner_classes(_inner_classes());
k->set_class_annotations(_annotations());
@@ -601,7 +582,7 @@
}
typeArrayHandle ClassFileParser::assemble_annotations(u1* runtime_visible_annotations,
-@@ -2923,9 +2984,126 @@
+@@ -2918,9 +2979,126 @@
}
@@ -728,7 +709,7 @@
KlassHandle host_klass,
GrowableArray<Handle>* cp_patches,
TempNewSymbol& parsed_name,
-@@ -2976,10 +3154,13 @@
+@@ -2971,10 +3149,13 @@
unsigned char* ptr = cfs->buffer();
unsigned char* end_ptr = cfs->buffer() + cfs->length();
@@ -742,7 +723,7 @@
if (ptr != cfs->buffer()) {
// JVMTI agent has modified class file data.
-@@ -3135,7 +3316,11 @@
+@@ -3130,7 +3311,11 @@
// However, make sure it is not an array type.
bool is_array = false;
if (cp->tag_at(super_class_index).is_klass()) {
@@ -755,7 +736,7 @@
if (_need_verify)
is_array = super_klass->oop_is_array();
} else if (_need_verify) {
-@@ -3153,7 +3338,7 @@
+@@ -3148,7 +3333,7 @@
if (itfs_len == 0) {
local_interfaces = objArrayHandle(THREAD, Universe::the_empty_system_obj_array());
} else {
@@ -764,7 +745,7 @@
}
u2 java_fields_count = 0;
-@@ -3207,7 +3392,9 @@
+@@ -3202,7 +3387,9 @@
protection_domain,
true,
CHECK_(nullHandle));
@@ -775,7 +756,7 @@
KlassHandle kh (THREAD, k);
super_klass = instanceKlassHandle(THREAD, kh());
}
-@@ -3596,6 +3783,19 @@
+@@ -3591,6 +3778,19 @@
rt = REF_NONE;
} else {
rt = super_klass->reference_type();
@@ -795,7 +776,7 @@
}
// We can now create the basic klassOop for this klass
-@@ -3696,7 +3896,7 @@
+@@ -3691,7 +3891,7 @@
fill_oop_maps(this_klass, nonstatic_oop_map_count, nonstatic_oop_offsets, nonstatic_oop_counts);
// Fill in has_finalizer, has_vanilla_constructor, and layout_helper
@@ -804,7 +785,7 @@
// reinitialize modifiers, using the InnerClasses attribute
int computed_modifiers = this_klass->compute_modifier_flags(CHECK_(nullHandle));
-@@ -3719,6 +3919,10 @@
+@@ -3714,6 +3914,10 @@
// Allocate mirror and initialize static fields
java_lang_Class::create_mirror(this_klass, CHECK_(nullHandle));
@@ -815,7 +796,7 @@
ClassLoadingService::notify_class_loaded(instanceKlass::cast(this_klass()),
false /* not shared class */);
-@@ -3861,7 +4065,7 @@
+@@ -3856,7 +4060,7 @@
}
@@ -824,7 +805,7 @@
klassOop super = k->super();
// Check if this klass has an empty finalize method (i.e. one with return bytecode only),
-@@ -3869,7 +4073,9 @@
+@@ -3864,7 +4068,9 @@
if (!_has_empty_finalizer) {
if (_has_finalizer ||
(super != NULL && super->klass_part()->has_finalizer())) {
@@ -835,7 +816,7 @@
}
}
-@@ -3885,7 +4091,7 @@
+@@ -3880,7 +4086,7 @@
// Check if this klass supports the java.lang.Cloneable interface
if (SystemDictionary::Cloneable_klass_loaded()) {
@@ -1251,7 +1232,7 @@
Handle linkage_exception = Handle(); // null handle
-@@ -1612,6 +1647,14 @@
+@@ -1613,6 +1648,14 @@
Universe::flush_dependents_on(k);
}
@@ -1266,7 +1247,7 @@
// ----------------------------------------------------------------------------
// GC support
-@@ -1701,6 +1744,24 @@
+@@ -1702,6 +1745,24 @@
}
@@ -1291,7 +1272,7 @@
void SystemDictionary::preloaded_oops_do(OopClosure* f) {
for (int k = (int)FIRST_WKID; k < (int)WKID_LIMIT; k++) {
f->do_oop((oop*) &_well_known_klasses[k]);
-@@ -1733,6 +1794,11 @@
+@@ -1734,6 +1795,11 @@
dictionary()->classes_do(f);
}
@@ -1303,7 +1284,7 @@
// Added for initialize_itable_for_klass
// Just the classes from defining class loaders
// Don't iterate over placeholders
-@@ -1869,7 +1935,9 @@
+@@ -1870,7 +1936,9 @@
// Preload ref klasses and set reference types
instanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER);
@@ -1314,7 +1295,7 @@
initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(PhantomReference_klass), scan, CHECK);
instanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT);
-@@ -1955,7 +2023,11 @@
+@@ -1956,7 +2024,11 @@
// also holds array classes
assert(check->klass_part()->oop_is_instance(), "noninstance in systemdictionary");
@@ -1329,7 +1310,7 @@
} else {
--- a/src/share/vm/classfile/systemDictionary.hpp
+++ b/src/share/vm/classfile/systemDictionary.hpp
-@@ -268,7 +268,7 @@
+@@ -269,7 +269,7 @@
// Resolve from stream (called by jni_DefineClass and JVM_DefineClass)
static klassOop resolve_from_stream(Symbol* class_name, Handle class_loader,
Handle protection_domain,
@@ -1338,7 +1319,7 @@
// Lookup an already loaded class. If not found NULL is returned.
static klassOop find(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS);
-@@ -309,6 +309,8 @@
+@@ -310,6 +310,8 @@
// Iterate over all klasses in dictionary
// Just the classes from defining class loaders
static void classes_do(void f(klassOop));
@@ -1347,7 +1328,7 @@
// Added for initialize_itable_for_klass to handle exceptions
static void classes_do(void f(klassOop, TRAPS), TRAPS);
// All classes, and their class loaders
-@@ -415,6 +417,8 @@
+@@ -416,6 +418,8 @@
initialize_wk_klasses_until((WKID) limit, start_id, THREAD);
}
@@ -1356,7 +1337,7 @@
public:
#define WK_KLASS_DECLARE(name, symbol, option) \
static klassOop name() { return check_klass_##option(_well_known_klasses[WK_KLASS_ENUM_NAME(name)]); }
-@@ -596,7 +600,7 @@
+@@ -597,11 +601,11 @@
// after waiting, but before reentering SystemDictionary_lock
// to preserve lock order semantics.
static void double_lock_wait(Handle lockObject, TRAPS);
@@ -1365,18 +1346,22 @@
static instanceKlassHandle find_or_define_instance_class(Symbol* class_name,
Handle class_loader,
instanceKlassHandle k, TRAPS);
-@@ -615,12 +619,17 @@
+- static instanceKlassHandle load_shared_class(Symbol* class_name,
++ static instanceKlassHandle load_shared_class(Symbol* class_name, // after waiting, but before reentering SystemDictionary_lock,
+ Handle class_loader, TRAPS);
+ static instanceKlassHandle load_shared_class(instanceKlassHandle ik,
+ Handle class_loader, TRAPS);
+@@ -616,12 +620,16 @@
// Setup link to hierarchy
static void add_to_hierarchy(instanceKlassHandle k, TRAPS);
+public:
-+
+ // Remove link to hierarchy
+ static void remove_from_hierarchy(instanceKlassHandle k);
+
+private:
// event based tracing
- static void post_class_load_event(TracingTime start_time, instanceKlassHandle k,
+ static void post_class_load_event(const Ticks& start_time, instanceKlassHandle k,
Handle initiating_loader);
static void post_class_unload_events(BoolObjectClosure* is_alive);
@@ -1513,7 +1498,7 @@
\
/* exception klasses: at least all exceptions thrown by the VM have entries here */ \
template(java_lang_ArithmeticException, "java/lang/ArithmeticException") \
-@@ -377,6 +381,10 @@
+@@ -379,6 +383,10 @@
template(oop_size_name, "oop_size") \
template(static_oop_field_count_name, "static_oop_field_count") \
\
@@ -1847,7 +1832,7 @@
// means then there could be a bug here.
--- a/src/share/vm/interpreter/interpreterRuntime.hpp
+++ b/src/share/vm/interpreter/interpreterRuntime.hpp
-@@ -140,6 +140,9 @@
+@@ -141,6 +141,9 @@
static void post_method_entry(JavaThread *thread);
static void post_method_exit (JavaThread *thread);
static int interpreter_contains(address pc);
@@ -2951,9 +2936,9 @@
// Debugging
static bool verify_in_progress() { return _verify_in_progress; }
+ static void set_verify_in_progress(bool b) { _verify_in_progress = b; }
- static void verify(bool silent, VerifyOption option);
- static void verify(bool silent) {
- verify(silent, VerifyOption_Default /* option */);
+ static void verify(VerifyOption option, const char* prefix, bool silent = VerifySilently);
+ static void verify(const char* prefix, bool silent = VerifySilently) {
+ verify(VerifyOption_Default, prefix, silent);
--- a/src/share/vm/oops/arrayKlass.cpp
+++ b/src/share/vm/oops/arrayKlass.cpp
@@ -129,9 +129,9 @@
@@ -3761,7 +3746,7 @@
#ifdef ASSERT
tty->print_cr("### %s can't find dependent nmethod:", this->external_name());
nm->print();
-@@ -2382,6 +2677,9 @@
+@@ -2417,6 +2712,9 @@
klassOop mirrored_klass = java_lang_Class::as_klassOop(obj);
st->print(BULLET"fake entry for mirror: ");
mirrored_klass->print_value_on(st);
@@ -3773,7 +3758,7 @@
methodOop ctor = java_lang_Class::resolved_constructor(obj);
--- a/src/share/vm/oops/instanceKlass.hpp
+++ b/src/share/vm/oops/instanceKlass.hpp
-@@ -101,6 +101,22 @@
+@@ -102,6 +102,22 @@
virtual void do_field(fieldDescriptor* fd) = 0;
};
@@ -3796,7 +3781,7 @@
#ifndef PRODUCT
// Print fields.
// If "obj" argument to constructor is NULL, prints static fields, otherwise prints non-static fields.
-@@ -285,6 +301,11 @@
+@@ -287,6 +303,11 @@
// _idnum_allocated_count.
u1 _init_state; // state of class
@@ -3808,7 +3793,7 @@
u1 _reference_type; // reference type
// embedded Java vtable follows here
-@@ -452,6 +473,7 @@
+@@ -454,6 +475,7 @@
// initialization (virtuals from Klass)
bool should_be_initialized() const; // means that initialize should be called
void initialize(TRAPS);
@@ -3816,7 +3801,7 @@
void link_class(TRAPS);
bool link_class_or_fail(TRAPS); // returns false on failure
void unlink_class();
-@@ -629,6 +651,7 @@
+@@ -631,6 +653,7 @@
static void get_jmethod_id_length_value(jmethodID* cache, size_t idnum,
size_t *length_p, jmethodID* id_p);
jmethodID jmethod_id_or_null(methodOop method);
@@ -3824,7 +3809,7 @@
// cached itable index support
void set_cached_itable_index(size_t idnum, int index);
-@@ -711,6 +734,7 @@
+@@ -713,6 +736,7 @@
// subclass/subinterface checks
bool implements_interface(klassOop k) const;
@@ -3832,7 +3817,7 @@
// Access to the implementor of an interface.
klassOop implementor() const
-@@ -760,6 +784,12 @@
+@@ -762,6 +786,12 @@
void do_local_static_fields(FieldClosure* cl);
void do_nonstatic_fields(FieldClosure* cl); // including inherited fields
void do_local_static_fields(void f(fieldDescriptor*, TRAPS), TRAPS);
@@ -4736,12 +4721,12 @@
+++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp
@@ -1,5 +1,5 @@
/*
-- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2011, 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
-@@ -30,498 +30,637 @@
+@@ -30,581 +30,637 @@
#include "interpreter/rewriter.hpp"
#include "memory/gcLocker.hpp"
#include "memory/universe.inline.hpp"
@@ -4753,6 +4738,7 @@
#include "prims/jvmtiRedefineClasses.hpp"
+#include "prims/jvmtiClassFileReconstituter.hpp"
#include "prims/methodComparator.hpp"
+-#include "prims/methodHandles.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/relocator.hpp"
#include "utilities/bitMap.inline.hpp"
@@ -5115,27 +5101,10 @@
+ if (_class_defs[i].class_byte_count == 0) RC_ABORT(JVMTI_ERROR_INVALID_CLASS_FORMAT);
+ if (_class_defs[i].class_bytes == NULL) RC_ABORT(JVMTI_ERROR_NULL_POINTER);
+ }
-
-- if (scratch_i != *merge_cp_length_p) {
-- // The new entry in *merge_cp_p is at a different index than
-- // the new entry in scratch_cp so we need to map the index values.
-- map_index(scratch_cp, scratch_i, *merge_cp_length_p);
-- }
-- (*merge_cp_length_p)++;
-- } break;
++
+ return true;
+}
-
-- // this is an indirect CP entry so it needs special handling
-- case JVM_CONSTANT_NameAndType:
-- {
-- int name_ref_i = scratch_cp->name_ref_index_at(scratch_i);
-- int new_name_ref_i = 0;
-- bool match = (name_ref_i < *merge_cp_length_p) &&
-- scratch_cp->compare_entry_to(name_ref_i, *merge_cp_p, name_ref_i,
-- THREAD);
-- if (!match) {
-- // forward reference in *merge_cp_p or not a direct match
++
+jvmtiError VM_RedefineClasses::check_exception() const {
+ Thread* THREAD = Thread::current();
+ if (HAS_PENDING_EXCEPTION) {
@@ -5165,25 +5134,7 @@
+ return JVMTI_ERROR_FAILS_VERIFICATION;
+ }
+ }
-
-- int found_i = scratch_cp->find_matching_entry(name_ref_i, *merge_cp_p,
-- THREAD);
-- if (found_i != 0) {
-- guarantee(found_i != name_ref_i,
-- "compare_entry_to() and find_matching_entry() do not agree");
--
-- // Found a matching entry somewhere else in *merge_cp_p so
-- // just need a mapping entry.
-- new_name_ref_i = found_i;
-- map_index(scratch_cp, name_ref_i, found_i);
-- } else {
-- // no match found so we have to append this entry to *merge_cp_p
-- append_entry(scratch_cp, name_ref_i, merge_cp_p, merge_cp_length_p,
-- THREAD);
-- // The above call to append_entry() can only append one entry
-- // so the post call query of *merge_cp_length_p is only for
-- // the sake of consistency.
-- new_name_ref_i = *merge_cp_length_p - 1;
++
+ return JVMTI_ERROR_NONE;
+}
+
@@ -5204,7 +5155,11 @@
+ (int)err));
+ return err;
+ }
-+
+
+- if (scratch_i != *merge_cp_length_p) {
+- // The new entry in *merge_cp_p is at a different index than
+- // the new entry in scratch_cp so we need to map the index values.
+- map_index(scratch_cp, scratch_i, *merge_cp_length_p);
+
+ JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current());
+
@@ -5302,40 +5257,82 @@
+ while (subklass != NULL) {
+ assert(subklass->new_version() == NULL, "Most recent version of class!");
+ subklass = subklass->next_sibling();
- }
++ }
+ } else {
+ // This can happen for reflection generated classes.. ?
+ CLEAR_PENDING_EXCEPTION;
}
+- (*merge_cp_length_p)++;
+- } break;
+ }
+- // this is an indirect CP entry so it needs special handling
+- case JVM_CONSTANT_NameAndType:
+- {
+- int name_ref_i = scratch_cp->name_ref_index_at(scratch_i);
+- int new_name_ref_i = find_or_append_indirect_entry(scratch_cp, name_ref_i, merge_cp_p,
+- merge_cp_length_p, THREAD);
+-
- int signature_ref_i = scratch_cp->signature_ref_index_at(scratch_i);
-- int new_signature_ref_i = 0;
-- match = (signature_ref_i < *merge_cp_length_p) &&
-- scratch_cp->compare_entry_to(signature_ref_i, *merge_cp_p,
-- signature_ref_i, THREAD);
-- if (!match) {
-- // forward reference in *merge_cp_p or not a direct match
--
-- int found_i = scratch_cp->find_matching_entry(signature_ref_i,
-- *merge_cp_p, THREAD);
-- if (found_i != 0) {
-- guarantee(found_i != signature_ref_i,
-- "compare_entry_to() and find_matching_entry() do not agree");
--
-- // Found a matching entry somewhere else in *merge_cp_p so
-- // just need a mapping entry.
-- new_signature_ref_i = found_i;
-- map_index(scratch_cp, signature_ref_i, found_i);
-- } else {
-- // no match found so we have to append this entry to *merge_cp_p
-- append_entry(scratch_cp, signature_ref_i, merge_cp_p,
-- merge_cp_length_p, THREAD);
-- // The above call to append_entry() can only append one entry
-- // so the post call query of *merge_cp_length_p is only for
-- // the sake of consistency.
-- new_signature_ref_i = *merge_cp_length_p - 1;
-- }
+- int new_signature_ref_i = find_or_append_indirect_entry(scratch_cp, signature_ref_i,
+- merge_cp_p, merge_cp_length_p,
+- THREAD);
+-
+- // If the referenced entries already exist in *merge_cp_p, then
+- // both new_name_ref_i and new_signature_ref_i will both be 0.
+- // In that case, all we are appending is the current entry.
+- if (new_name_ref_i != name_ref_i) {
+- RC_TRACE(0x00080000,
+- ("NameAndType entry@%d name_ref_index change: %d to %d",
+- *merge_cp_length_p, name_ref_i, new_name_ref_i));
+- }
+- if (new_signature_ref_i != signature_ref_i) {
+- RC_TRACE(0x00080000,
+- ("NameAndType entry@%d signature_ref_index change: %d to %d",
+- *merge_cp_length_p, signature_ref_i, new_signature_ref_i));
+- }
+-
+- (*merge_cp_p)->name_and_type_at_put(*merge_cp_length_p,
+- new_name_ref_i, new_signature_ref_i);
+- if (scratch_i != *merge_cp_length_p) {
+- // The new entry in *merge_cp_p is at a different index than
+- // the new entry in scratch_cp so we need to map the index values.
+- map_index(scratch_cp, scratch_i, *merge_cp_length_p);
+- }
+- (*merge_cp_length_p)++;
+- } break;
+-
+- // this is a double-indirect CP entry so it needs special handling
+- case JVM_CONSTANT_Fieldref: // fall through
+- case JVM_CONSTANT_InterfaceMethodref: // fall through
+- case JVM_CONSTANT_Methodref:
+- {
+- int klass_ref_i = scratch_cp->uncached_klass_ref_index_at(scratch_i);
+- int new_klass_ref_i = find_or_append_indirect_entry(scratch_cp, klass_ref_i,
+- merge_cp_p, merge_cp_length_p, THREAD);
+- int name_and_type_ref_i = scratch_cp->uncached_name_and_type_ref_index_at(scratch_i);
+- int new_name_and_type_ref_i = find_or_append_indirect_entry(scratch_cp, name_and_type_ref_i,
+- merge_cp_p, merge_cp_length_p, THREAD);
+-
+- const char *entry_name;
+- switch (scratch_cp->tag_at(scratch_i).value()) {
+- case JVM_CONSTANT_Fieldref:
+- entry_name = "Fieldref";
+- (*merge_cp_p)->field_at_put(*merge_cp_length_p, new_klass_ref_i,
+- new_name_and_type_ref_i);
+- break;
+- case JVM_CONSTANT_InterfaceMethodref:
+- entry_name = "IFMethodref";
+- (*merge_cp_p)->interface_method_at_put(*merge_cp_length_p,
+- new_klass_ref_i, new_name_and_type_ref_i);
+- break;
+- case JVM_CONSTANT_Methodref:
+- entry_name = "Methodref";
+- (*merge_cp_p)->method_at_put(*merge_cp_length_p, new_klass_ref_i,
+- new_name_and_type_ref_i);
+- break;
+- default:
+- guarantee(false, "bad switch");
+#endif
+
+ if (RC_TRACE_ENABLED(0x00000001)) {
@@ -5344,18 +5341,9 @@
+ new_class->name()->as_C_string(),
+ new_class->layout_helper(),
+ the_class->layout_helper()));
- }
++ }
+ }
-
-- // If the referenced entries already exist in *merge_cp_p, then
-- // both new_name_ref_i and new_signature_ref_i will both be 0.
-- // In that case, all we are appending is the current entry.
-- if (new_name_ref_i == 0) {
-- new_name_ref_i = name_ref_i;
-- } else {
-- RC_TRACE(0x00080000,
-- ("NameAndType entry@%d name_ref_index change: %d to %d",
-- *merge_cp_length_p, name_ref_i, new_name_ref_i));
++
+ // Set the new version of the class
+ new_class->set_revision_number(_revision_number);
+ new_class->set_redefinition_index(i);
@@ -5375,66 +5363,30 @@
+ if (allowed != JVMTI_ERROR_NONE) {
+ RC_TRACE(0x00000001, ("Error redefinition not allowed!"));
+ result = allowed;
-+ break;
+ break;
}
-- if (new_signature_ref_i == 0) {
-- new_signature_ref_i = signature_ref_i;
-- } else {
++ redefinition_flags = Klass::ModifyClass;
++ }
++
++ if (new_class->super() != NULL) {
++ redefinition_flags = redefinition_flags | new_class->super()->klass_part()->redefinition_flags();
++ }
+
+- if (klass_ref_i != new_klass_ref_i) {
+- RC_TRACE(0x00080000, ("%s entry@%d class_index changed: %d to %d",
+- entry_name, *merge_cp_length_p, klass_ref_i, new_klass_ref_i));
+- }
+- if (name_and_type_ref_i != new_name_and_type_ref_i) {
- RC_TRACE(0x00080000,
-- ("NameAndType entry@%d signature_ref_index change: %d to %d",
-- *merge_cp_length_p, signature_ref_i, new_signature_ref_i));
+- ("%s entry@%d name_and_type_index changed: %d to %d",
+- entry_name, *merge_cp_length_p, name_and_type_ref_i,
+- new_name_and_type_ref_i));
- }
-
-- (*merge_cp_p)->name_and_type_at_put(*merge_cp_length_p,
-- new_name_ref_i, new_signature_ref_i);
- if (scratch_i != *merge_cp_length_p) {
- // The new entry in *merge_cp_p is at a different index than
- // the new entry in scratch_cp so we need to map the index values.
- map_index(scratch_cp, scratch_i, *merge_cp_length_p);
-- }
-- (*merge_cp_length_p)++;
-- } break;
--
-- // this is a double-indirect CP entry so it needs special handling
-- case JVM_CONSTANT_Fieldref: // fall through
-- case JVM_CONSTANT_InterfaceMethodref: // fall through
-- case JVM_CONSTANT_Methodref:
-- {
-- int klass_ref_i = scratch_cp->uncached_klass_ref_index_at(scratch_i);
-- int new_klass_ref_i = 0;
-- bool match = (klass_ref_i < *merge_cp_length_p) &&
-- scratch_cp->compare_entry_to(klass_ref_i, *merge_cp_p, klass_ref_i,
-- THREAD);
-- if (!match) {
-- // forward reference in *merge_cp_p or not a direct match
-+ redefinition_flags = Klass::ModifyClass;
-+ }
-
-- int found_i = scratch_cp->find_matching_entry(klass_ref_i, *merge_cp_p,
-- THREAD);
-- if (found_i != 0) {
-- guarantee(found_i != klass_ref_i,
-- "compare_entry_to() and find_matching_entry() do not agree");
--
-- // Found a matching entry somewhere else in *merge_cp_p so
-- // just need a mapping entry.
-- new_klass_ref_i = found_i;
-- map_index(scratch_cp, klass_ref_i, found_i);
-- } else {
-- // no match found so we have to append this entry to *merge_cp_p
-- append_entry(scratch_cp, klass_ref_i, merge_cp_p, merge_cp_length_p,
-- THREAD);
-- // The above call to append_entry() can only append one entry
-- // so the post call query of *merge_cp_length_p is only for
-- // the sake of consistency. Without the optimization where we
-- // use JVM_CONSTANT_UnresolvedClass, then up to two entries
-- // could be appended.
-- new_klass_ref_i = *merge_cp_length_p - 1;
-- }
-+ if (new_class->super() != NULL) {
-+ redefinition_flags = redefinition_flags | new_class->super()->klass_part()->redefinition_flags();
-+ }
-+
+ for (int j=0; j<new_class->local_interfaces()->length(); j++) {
+ redefinition_flags = redefinition_flags | ((klassOop)new_class->local_interfaces()->obj_at(j))->klass_part()->redefinition_flags();
+ }
@@ -5456,44 +5408,53 @@
+ fd_new.initialize(new_class(), fs.index());
+ fd_old.initialize(new_class->old_version(), fs.index());
+ transfer_special_access_flags(&fd_old, &fd_new);
-+ }
+ }
+- (*merge_cp_length_p)++;
+- } break;
+ }
-+
+
+- // this is an indirect CP entry so it needs special handling
+- case JVM_CONSTANT_MethodType:
+- {
+- int ref_i = scratch_cp->method_type_index_at(scratch_i);
+- int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p,
+- merge_cp_length_p, THREAD);
+- if (new_ref_i != ref_i) {
+- RC_TRACE(0x00080000,
+- ("MethodType entry@%d ref_index change: %d to %d",
+- *merge_cp_length_p, ref_i, new_ref_i));
+- }
+- (*merge_cp_p)->method_type_index_at_put(*merge_cp_length_p, new_ref_i);
+- if (scratch_i != *merge_cp_length_p) {
+- // The new entry in *merge_cp_p is at a different index than
+- // the new entry in scratch_cp so we need to map the index values.
+- map_index(scratch_cp, scratch_i, *merge_cp_length_p);
+ if (RC_TRACE_ENABLED(0x00000008)) {
+ if (new_class->super() != NULL) {
+ RC_TRACE(0x00000008, ("Super class is %s",
+ new_class->super()->klass_part()->name()->as_C_string()));
}
+- (*merge_cp_length_p)++;
+- } break;
+ }
-- int name_and_type_ref_i =
-- scratch_cp->uncached_name_and_type_ref_index_at(scratch_i);
-- int new_name_and_type_ref_i = 0;
-- match = (name_and_type_ref_i < *merge_cp_length_p) &&
-- scratch_cp->compare_entry_to(name_and_type_ref_i, *merge_cp_p,
-- name_and_type_ref_i, THREAD);
-- if (!match) {
-- // forward reference in *merge_cp_p or not a direct match
--
-- int found_i = scratch_cp->find_matching_entry(name_and_type_ref_i,
-- *merge_cp_p, THREAD);
-- if (found_i != 0) {
-- guarantee(found_i != name_and_type_ref_i,
-- "compare_entry_to() and find_matching_entry() do not agree");
--
-- // Found a matching entry somewhere else in *merge_cp_p so
-- // just need a mapping entry.
-- new_name_and_type_ref_i = found_i;
-- map_index(scratch_cp, name_and_type_ref_i, found_i);
-- } else {
-- // no match found so we have to append this entry to *merge_cp_p
-- append_entry(scratch_cp, name_and_type_ref_i, merge_cp_p,
-- merge_cp_length_p, THREAD);
-- // The above call to append_entry() can append more than
-- // one entry so the post call query of *merge_cp_length_p
-- // is required in order to get the right index for the
-- // JVM_CONSTANT_NameAndType entry.
-- new_name_and_type_ref_i = *merge_cp_length_p - 1;
+- // this is an indirect CP entry so it needs special handling
+- case JVM_CONSTANT_MethodHandle:
+- {
+- int ref_kind = scratch_cp->method_handle_ref_kind_at(scratch_i);
+- int ref_i = scratch_cp->method_handle_index_at(scratch_i);
+- int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p,
+- merge_cp_length_p, THREAD);
+- if (new_ref_i != ref_i) {
+- RC_TRACE(0x00080000,
+- ("MethodHandle entry@%d ref_index change: %d to %d",
+- *merge_cp_length_p, ref_i, new_ref_i));
+- }
+- (*merge_cp_p)->method_handle_index_at_put(*merge_cp_length_p, ref_kind, new_ref_i);
+- if (scratch_i != *merge_cp_length_p) {
+- // The new entry in *merge_cp_p is at a different index than
+- // the new entry in scratch_cp so we need to map the index values.
+- map_index(scratch_cp, scratch_i, *merge_cp_length_p);
+#ifdef ASSERT
+ assert(new_class->super() == NULL || new_class->super()->klass_part()->new_version() == NULL, "Super klass must be newest version!");
+
@@ -5535,60 +5496,34 @@
+ }
+
+ cur_klass = cur_klass->next_sibling();
- }
- }
-
-- // If the referenced entries already exist in *merge_cp_p, then
-- // both new_klass_ref_i and new_name_and_type_ref_i will both be
-- // 0. In that case, all we are appending is the current entry.
-- if (new_klass_ref_i == 0) {
-- new_klass_ref_i = klass_ref_i;
-- }
-- if (new_name_and_type_ref_i == 0) {
-- new_name_and_type_ref_i = name_and_type_ref_i;
-- }
--
-- const char *entry_name;
-- switch (scratch_cp->tag_at(scratch_i).value()) {
-- case JVM_CONSTANT_Fieldref:
-- entry_name = "Fieldref";
-- (*merge_cp_p)->field_at_put(*merge_cp_length_p, new_klass_ref_i,
-- new_name_and_type_ref_i);
-- break;
-- case JVM_CONSTANT_InterfaceMethodref:
-- entry_name = "IFMethodref";
-- (*merge_cp_p)->interface_method_at_put(*merge_cp_length_p,
-- new_klass_ref_i, new_name_and_type_ref_i);
-- break;
-- case JVM_CONSTANT_Methodref:
-- entry_name = "Methodref";
-- (*merge_cp_p)->method_at_put(*merge_cp_length_p, new_klass_ref_i,
-- new_name_and_type_ref_i);
-- break;
-- default:
-- guarantee(false, "bad switch");
-- break;
-+ int new_count = all_affected_klasses.length() - 1 - i;
-+ if (new_count != 0) {
-+
-+ unlock_threads();
-+ RC_TRACE(0x00000001, ("Found new number of affected classes: %d",
-+ new_count));
++ }
}
-+ }
-+ }
+- (*merge_cp_length_p)++;
+- } break;
-- if (klass_ref_i != new_klass_ref_i) {
-- RC_TRACE(0x00080000, ("%s entry@%d class_index changed: %d to %d",
-- entry_name, *merge_cp_length_p, klass_ref_i, new_klass_ref_i));
+- // this is an indirect CP entry so it needs special handling
+- case JVM_CONSTANT_InvokeDynamic:
+- {
+- // Index of the bootstrap specifier in the operands array
+- int old_bs_i = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i);
+- int new_bs_i = find_or_append_operand(scratch_cp, old_bs_i, merge_cp_p,
+- merge_cp_length_p, THREAD);
+- // The bootstrap method NameAndType_info index
+- int old_ref_i = scratch_cp->invoke_dynamic_name_and_type_ref_index_at(scratch_i);
+- int new_ref_i = find_or_append_indirect_entry(scratch_cp, old_ref_i, merge_cp_p,
+- merge_cp_length_p, THREAD);
+- if (new_bs_i != old_bs_i) {
+- RC_TRACE(0x00080000,
+- ("InvokeDynamic entry@%d bootstrap_method_attr_index change: %d to %d",
+- *merge_cp_length_p, old_bs_i, new_bs_i));
- }
-- if (name_and_type_ref_i != new_name_and_type_ref_i) {
+- if (new_ref_i != old_ref_i) {
- RC_TRACE(0x00080000,
-- ("%s entry@%d name_and_type_index changed: %d to %d",
-- entry_name, *merge_cp_length_p, name_and_type_ref_i,
-- new_name_and_type_ref_i));
+- ("InvokeDynamic entry@%d name_and_type_index change: %d to %d",
+- *merge_cp_length_p, old_ref_i, new_ref_i));
- }
-
+- (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, new_bs_i, new_ref_i);
- if (scratch_i != *merge_cp_length_p) {
- // The new entry in *merge_cp_p is at a different index than
- // the new entry in scratch_cp so we need to map the index values.
@@ -5597,7 +5532,7 @@
- (*merge_cp_length_p)++;
- } break;
-
-- // At this stage, Class or UnresolvedClass could be here, but not
+- // At this stage, Class or UnresolvedClass could be here, but not
- // ClassIndex
- case JVM_CONSTANT_ClassIndex: // fall through
-
@@ -5613,10 +5548,8 @@
- // At this stage JVM_CONSTANT_UnresolvedClassInError should not be
- // here
- case JVM_CONSTANT_UnresolvedClassInError: // fall through
-+ if (result != JVMTI_ERROR_NONE) {
-+ rollback();
-+ return result;
-+ }
++ int new_count = all_affected_klasses.length() - 1 - i;
++ if (new_count != 0) {
- default:
- {
@@ -5626,13 +5559,128 @@
- } break;
- } // end switch tag value
-} // end append_entry()
+-
+-
+-int VM_RedefineClasses::find_or_append_indirect_entry(constantPoolHandle scratch_cp,
+- int ref_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) {
+-
+- int new_ref_i = ref_i;
+- bool match = (ref_i < *merge_cp_length_p) &&
+- scratch_cp->compare_entry_to(ref_i, *merge_cp_p, ref_i, THREAD);
+-
+- if (!match) {
+- // forward reference in *merge_cp_p or not a direct match
+- int found_i = scratch_cp->find_matching_entry(ref_i, *merge_cp_p, THREAD);
+- if (found_i != 0) {
+- guarantee(found_i != ref_i, "compare_entry_to() and find_matching_entry() do not agree");
+- // Found a matching entry somewhere else in *merge_cp_p so just need a mapping entry.
+- new_ref_i = found_i;
+- map_index(scratch_cp, ref_i, found_i);
+- } else {
+- // no match found so we have to append this entry to *merge_cp_p
+- append_entry(scratch_cp, ref_i, merge_cp_p, merge_cp_length_p, THREAD);
+- // The above call to append_entry() can only append one entry
+- // so the post call query of *merge_cp_length_p is only for
+- // the sake of consistency.
+- new_ref_i = *merge_cp_length_p - 1;
+- }
+- }
+-
+- return new_ref_i;
+-} // end find_or_append_indirect_entry()
+-
+-
+-// Append a bootstrap specifier into the merge_cp operands that is semantically equal
+-// to the scratch_cp operands bootstrap specifier passed by the old_bs_i index.
+-// Recursively append new merge_cp entries referenced by the new bootstrap specifier.
+-void VM_RedefineClasses::append_operand(constantPoolHandle scratch_cp, int old_bs_i,
+- constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) {
+-
+- int old_ref_i = scratch_cp->operand_bootstrap_method_ref_index_at(old_bs_i);
+- int new_ref_i = find_or_append_indirect_entry(scratch_cp, old_ref_i, merge_cp_p,
+- merge_cp_length_p, THREAD);
+- if (new_ref_i != old_ref_i) {
+- RC_TRACE(0x00080000,
+- ("operands entry@%d bootstrap method ref_index change: %d to %d",
+- _operands_cur_length, old_ref_i, new_ref_i));
+- }
+-
+- typeArrayOop merge_ops = (*merge_cp_p)->operands();
+- int new_bs_i = _operands_cur_length;
+- // We have _operands_cur_length == 0 when the merge_cp operands is empty yet.
+- // However, the operand_offset_at(0) was set in the extend_operands() call.
+- int new_base = (new_bs_i == 0) ? (*merge_cp_p)->operand_offset_at(0)
+- : (*merge_cp_p)->operand_next_offset_at(new_bs_i - 1);
+- int argc = scratch_cp->operand_argument_count_at(old_bs_i);
+-
+- constantPoolOopDesc::operand_offset_at_put(merge_ops, _operands_cur_length, new_base);
+- merge_ops->short_at_put(new_base++, new_ref_i);
+- merge_ops->short_at_put(new_base++, argc);
+-
+- for (int i = 0; i < argc; i++) {
+- int old_arg_ref_i = scratch_cp->operand_argument_index_at(old_bs_i, i);
+- int new_arg_ref_i = find_or_append_indirect_entry(scratch_cp, old_arg_ref_i, merge_cp_p,
+- merge_cp_length_p, THREAD);
+- merge_ops->short_at_put(new_base++, new_arg_ref_i);
+- if (new_arg_ref_i != old_arg_ref_i) {
+- RC_TRACE(0x00080000,
+- ("operands entry@%d bootstrap method argument ref_index change: %d to %d",
+- _operands_cur_length, old_arg_ref_i, new_arg_ref_i));
+- }
+- }
+- if (old_bs_i != _operands_cur_length) {
+- // The bootstrap specifier in *merge_cp_p is at a different index than
+- // that in scratch_cp so we need to map the index values.
+- map_operand_index(old_bs_i, new_bs_i);
+- }
+- _operands_cur_length++;
+-} // end append_operand()
+-
+-
+-int VM_RedefineClasses::find_or_append_operand(constantPoolHandle scratch_cp,
+- int old_bs_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) {
+-
+- int new_bs_i = old_bs_i; // bootstrap specifier index
+- bool match = (old_bs_i < _operands_cur_length) &&
+- scratch_cp->compare_operand_to(old_bs_i, *merge_cp_p, old_bs_i, THREAD);
+-
+- if (!match) {
+- // forward reference in *merge_cp_p or not a direct match
+- int found_i = scratch_cp->find_matching_operand(old_bs_i, *merge_cp_p,
+- _operands_cur_length, THREAD);
+- if (found_i != -1) {
+- guarantee(found_i != old_bs_i, "compare_operand_to() and find_matching_operand() disagree");
+- // found a matching operand somewhere else in *merge_cp_p so just need a mapping
+- new_bs_i = found_i;
+- map_operand_index(old_bs_i, found_i);
+- } else {
+- // no match found so we have to append this bootstrap specifier to *merge_cp_p
+- append_operand(scratch_cp, old_bs_i, merge_cp_p, merge_cp_length_p, THREAD);
+- new_bs_i = _operands_cur_length - 1;
++ unlock_threads();
++ RC_TRACE(0x00000001, ("Found new number of affected classes: %d",
++ new_count));
++ }
+ }
+ }
+- return new_bs_i;
+-} // end find_or_append_operand()
+
++ if (result != JVMTI_ERROR_NONE) {
++ rollback();
++ return result;
++ }
++
+ RC_TIMER_STOP(_timer_prologue);
+ RC_TIMER_START(_timer_class_linking);
+ // Link and verify new classes _after_ all classes have been updated in the system dictionary!
+ for (int i=0; i<all_affected_klasses.length(); i++) {
+ instanceKlassHandle the_class = all_affected_klasses.at(i);
+ instanceKlassHandle new_class(the_class->new_version());
-+
+
+-void VM_RedefineClasses::finalize_operands_merge(constantPoolHandle merge_cp, TRAPS) {
+- if (merge_cp->operands() == NULL) {
+- return;
+ RC_TRACE(0x00000002, ("Linking class %d/%d %s",
+ i,
+ all_affected_klasses.length(),
@@ -5641,11 +5689,23 @@
+
+ result = check_exception();
+ if (result != JVMTI_ERROR_NONE) break;
-+ }
+ }
+- // Shrink the merge_cp operands
+- merge_cp->shrink_operands(_operands_cur_length, CHECK);
+ RC_TIMER_STOP(_timer_class_linking);
+ RC_TIMER_START(_timer_prologue);
-+
-+ if (result != JVMTI_ERROR_NONE) {
+
+- if (RC_TRACE_ENABLED(0x00040000)) {
+- // don't want to loop unless we are tracing
+- int count = 0;
+- for (int i = 1; i < _operands_index_map_p->length(); i++) {
+- int value = _operands_index_map_p->at(i);
+- if (value != -1) {
+- RC_TRACE_WITH_THREAD(0x00040000, THREAD,
+- ("operands_index_map[%d]: old=%d new=%d", count, i, value));
+- count++;
+- }
++ if (result != JVMTI_ERROR_NONE) {
+ rollback();
+ return result;
+ }
@@ -5658,7 +5718,7 @@
+ assert(the_class->new_version() != NULL, "Must have been redefined");
+ instanceKlassHandle new_version = instanceKlassHandle(THREAD, the_class->new_version());
+ assert(new_version->new_version() == NULL, "Must be newest version");
-
++
+ if (!(new_version->super() == NULL || new_version->super()->klass_part()->new_version() == NULL)) {
+ new_version()->print();
+ new_version->super()->print();
@@ -5706,20 +5766,25 @@
+ while (javaThread != NULL) {
+ if (javaThread != Thread::current()) {
+ javaThread->redefine_classes_mutex()->lock();
-+ }
+ }
+ javaThread = javaThread->next();
-+ }
-+
-+
+ }
+- // Clean-up
+- _operands_index_map_p = NULL;
+- _operands_cur_length = 0;
+- _operands_index_map_count = 0;
+-} // end finalize_operands_merge()
+
+
+-void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class) {
+- typeArrayOop save;
+ RC_TRACE(0x00000002, ("Locked %d threads", cnt));
+
+ RC_TIMER_STOP(_timer_wait_for_locks);
+}
+
+void VM_RedefineClasses::unlock_threads() {
-
--void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class) {
-- typeArrayOop save;
++
+ int cnt = 0;
+ JavaThread *javaThread = Threads::first();
+ Thread *thread = Thread::current();
@@ -5789,7 +5854,7 @@
}
// Check if the number, names and order of directly implemented interfaces are the same.
-@@ -539,8 +678,8 @@
+@@ -622,8 +678,8 @@
}
for (i = 0; i < n_intfs; i++) {
if (Klass::cast((klassOop) k_interfaces->obj_at(i))->name() !=
@@ -5800,7 +5865,7 @@
}
}
-@@ -689,12 +828,8 @@
+@@ -772,12 +828,8 @@
idnum_owner->set_method_idnum(new_num);
}
k_new_method->set_method_idnum(old_num);
@@ -5813,7 +5878,7 @@
// advance to next pair of methods
++oi;
++ni;
-@@ -703,11 +838,11 @@
+@@ -786,11 +838,11 @@
// method added, see if it is OK
new_flags = (jushort) k_new_method->access_flags().get_flags();
if ((new_flags & JVM_ACC_PRIVATE) == 0
@@ -5830,7 +5895,7 @@
}
{
u2 num = the_class->next_method_idnum();
-@@ -722,24 +857,19 @@
+@@ -805,24 +857,19 @@
idnum_owner->set_method_idnum(new_num);
}
k_new_method->set_method_idnum(num);
@@ -5860,7 +5925,7 @@
++oi; // advance to next old method
break;
default:
-@@ -750,2200 +880,1783 @@
+@@ -833,2254 +880,1783 @@
return JVMTI_ERROR_NONE;
}
@@ -5881,59 +5946,62 @@
- // happen if a corrupt annotation is processed.
- return 0;
- }
--
++ int result = Klass::NoRedefinition;
+
- int value = _index_map_p->at(old_index);
- if (value == -1) {
- // the old_index is not mapped
- return 0;
- }
-+ int result = Klass::NoRedefinition;
- return value;
-} // end find_new_index()
-
--// Returns true if the current mismatch is due to a resolved/unresolved
--// class pair. Otherwise, returns false.
--bool VM_RedefineClasses::is_unresolved_class_mismatch(constantPoolHandle cp1,
-- int index1, constantPoolHandle cp2, int index2) {
+ RC_TRACE(0x00000002, ("Comparing different class versions of class %s",
+ new_class->name()->as_C_string()));
-- jbyte t1 = cp1->tag_at(index1).value();
-- if (t1 != JVM_CONSTANT_Class && t1 != JVM_CONSTANT_UnresolvedClass) {
-- return false; // wrong entry type; not our special case
+-// Find new bootstrap specifier index value for old bootstrap specifier index
+-// value by seaching the index map. Returns zero (-1) if there is no mapped
+-// value for the old bootstrap specifier index.
+-int VM_RedefineClasses::find_new_operand_index(int old_index) {
+- if (_operands_index_map_count == 0) {
+- // map is empty so nothing can be found
+- return -1;
- }
+ assert(new_class->old_version() != NULL, "must have old version");
+ instanceKlassHandle the_class(new_class->old_version());
-- jbyte t2 = cp2->tag_at(index2).value();
-- if (t2 != JVM_CONSTANT_Class && t2 != JVM_CONSTANT_UnresolvedClass) {
-- return false; // wrong entry type; not our special case
+- if (old_index == -1 || old_index >= _operands_index_map_p->length()) {
+- // The old_index is out of range so it is not mapped.
+- // This should not happen in regular constant pool merging use.
+- return -1;
+ // Check whether class is in the error init state.
+ if (the_class->is_in_error_state()) {
+ // TBD #5057930: special error code is needed in 1.6
+ //result = Klass::union_redefinition_level(result, Klass::Invalid);
}
-- if (t1 == t2) {
-- return false; // not a mismatch; not our special case
-- }
+- int value = _operands_index_map_p->at(old_index);
+-
+- return value;
+-} // end find_new_operand_index()
+-
+ int i;
-- char *s1 = cp1->klass_name_at(index1)->as_C_string();
-- char *s2 = cp2->klass_name_at(index2)->as_C_string();
-- if (strcmp(s1, s2) != 0) {
-- return false; // strings don't match; not our special case
-- }
+-// Returns true if the current mismatch is due to a resolved/unresolved
+-// class pair. Otherwise, returns false.
+-bool VM_RedefineClasses::is_unresolved_class_mismatch(constantPoolHandle cp1,
+- int index1, constantPoolHandle cp2, int index2) {
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Check superclasses
+ assert(new_class->super() == NULL || new_class->super()->klass_part()->is_newest_version(), "");
+ if (the_class->super() != new_class->super()) {
+ // Super class changed
-- return true; // made it through the gauntlet; this is our special case
--} // end is_unresolved_class_mismatch()
+- jbyte t1 = cp1->tag_at(index1).value();
+- if (t1 != JVM_CONSTANT_Class && t1 != JVM_CONSTANT_UnresolvedClass) {
+- return false; // wrong entry type; not our special case
+- }
+ klassOop cur_klass = the_class->super();
+ while (cur_klass != NULL) {
+ if (!new_class->is_subclass_of(cur_klass->klass_part()->newest_version())) {
@@ -5941,6 +6009,10 @@
+ cur_klass->klass_part()->name()->as_C_string()));
+ result = result | Klass::RemoveSuperType | Klass::ModifyInstances | Klass::ModifyClass;
+- jbyte t2 = cp2->tag_at(index2).value();
+- if (t2 != JVM_CONSTANT_Class && t2 != JVM_CONSTANT_UnresolvedClass) {
+- return false; // wrong entry type; not our special case
+- }
+ if (!cur_klass->klass_part()->has_subtype_changed()) {
+ RC_TRACE(0x00000002, ("Subtype changed of class %s",
+ cur_klass->klass_part()->name()->as_C_string()));
@@ -5948,16 +6020,16 @@
+ }
+ }
--// Returns true if the current mismatch is due to a resolved/unresolved
--// string pair. Otherwise, returns false.
--bool VM_RedefineClasses::is_unresolved_string_mismatch(constantPoolHandle cp1,
-- int index1, constantPoolHandle cp2, int index2) {
+- if (t1 == t2) {
+- return false; // not a mismatch; not our special case
+- }
+ cur_klass = cur_klass->klass_part()->super();
+ }
-- jbyte t1 = cp1->tag_at(index1).value();
-- if (t1 != JVM_CONSTANT_String && t1 != JVM_CONSTANT_UnresolvedString) {
-- return false; // wrong entry type; not our special case
+- char *s1 = cp1->klass_name_at(index1)->as_C_string();
+- char *s2 = cp2->klass_name_at(index2)->as_C_string();
+- if (strcmp(s1, s2) != 0) {
+- return false; // strings don't match; not our special case
+ cur_klass = new_class->super();
+ while (cur_klass != NULL) {
+ if (!the_class->is_subclass_of(cur_klass->klass_part()->old_version())) {
@@ -5969,15 +6041,20 @@
+ }
}
-- jbyte t2 = cp2->tag_at(index2).value();
-- if (t2 != JVM_CONSTANT_String && t2 != JVM_CONSTANT_UnresolvedString) {
-- return false; // wrong entry type; not our special case
-- }
+- return true; // made it through the gauntlet; this is our special case
+-} // end is_unresolved_class_mismatch()
+-
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Check interfaces
-- if (t1 == t2) {
-- return false; // not a mismatch; not our special case
+-// Returns true if the current mismatch is due to a resolved/unresolved
+-// string pair. Otherwise, returns false.
+-bool VM_RedefineClasses::is_unresolved_string_mismatch(constantPoolHandle cp1,
+- int index1, constantPoolHandle cp2, int index2) {
+-
+- jbyte t1 = cp1->tag_at(index1).value();
+- if (t1 != JVM_CONSTANT_String && t1 != JVM_CONSTANT_UnresolvedString) {
+- return false; // wrong entry type; not our special case
+ // Interfaces removed?
+ objArrayOop old_interfaces = the_class->transitive_interfaces();
+ for (i = 0; i<old_interfaces->length(); i++) {
@@ -5995,10 +6072,9 @@
+ }
}
-- char *s1 = cp1->string_at_noresolve(index1);
-- char *s2 = cp2->string_at_noresolve(index2);
-- if (strcmp(s1, s2) != 0) {
-- return false; // strings don't match; not our special case
+- jbyte t2 = cp2->tag_at(index2).value();
+- if (t2 != JVM_CONSTANT_String && t2 != JVM_CONSTANT_UnresolvedString) {
+- return false; // wrong entry type; not our special case
+ // Interfaces added?
+ objArrayOop new_interfaces = new_class->transitive_interfaces();
+ for (i = 0; i<new_interfaces->length(); i++) {
@@ -6009,22 +6085,32 @@
+ }
}
-- return true; // made it through the gauntlet; this is our special case
--} // end is_unresolved_string_mismatch()
+- if (t1 == t2) {
+- return false; // not a mismatch; not our special case
+- }
+- char *s1 = cp1->string_at_noresolve(index1);
+- char *s2 = cp2->string_at_noresolve(index2);
+- if (strcmp(s1, s2) != 0) {
+- return false; // strings don't match; not our special case
+ // Check whether class modifiers are the same.
+ jushort old_flags = (jushort) the_class->access_flags().get_flags();
+ jushort new_flags = (jushort) new_class->access_flags().get_flags();
+ if (old_flags != new_flags) {
+ // TODO (tw): Can this have any effects?
-+ }
+ }
+- return true; // made it through the gauntlet; this is our special case
+-} // end is_unresolved_string_mismatch()
+-
+-
-jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) {
- // For consistency allocate memory using os::malloc wrapper.
- _scratch_classes = (instanceKlassHandle *)
- os::malloc(sizeof(instanceKlassHandle) * _class_count, mtInternal);
- if (_scratch_classes == NULL) {
- return JVMTI_ERROR_OUT_OF_MEMORY;
+- }
+ // Check if the number, names, types and order of fields declared in these classes
+ // are the same.
+ JavaFieldStream old_fs(the_class);
@@ -6048,7 +6134,7 @@
+ if (name_sym1 != name_sym2 || sig_sym1 != sig_sym2) {
+ result = result | Klass::ModifyInstances;
+ }
- }
++ }
- ResourceMark rm(THREAD);
+ if (!old_fs.done() || !new_fs.done()) {
@@ -6576,93 +6662,23 @@
- // old_index is already mapped
- return;
- }
--
++ public:
+
- if (old_index == new_index) {
- // no mapping is needed
- return;
- }
--
-- _index_map_p->at_put(old_index, new_index);
-- _index_map_count++;
--
-- RC_TRACE(0x00040000, ("mapped tag %d at index %d to %d",
-- scratch_cp->tag_at(old_index).value(), old_index, new_index));
--} // end map_index()
--
--
--// Merge old_cp and scratch_cp and return the results of the merge via
--// merge_cp_p. The number of entries in *merge_cp_p is returned via
--// merge_cp_length_p. The entries in old_cp occupy the same locations
--// in *merge_cp_p. Also creates a map of indices from entries in
--// scratch_cp to the corresponding entry in *merge_cp_p. Index map
--// entries are only created for entries in scratch_cp that occupy a
--// different location in *merged_cp_p.
--bool VM_RedefineClasses::merge_constant_pools(constantPoolHandle old_cp,
-- constantPoolHandle scratch_cp, constantPoolHandle *merge_cp_p,
-- int *merge_cp_length_p, TRAPS) {
--
-- if (merge_cp_p == NULL) {
-- assert(false, "caller must provide scatch constantPool");
-- return false; // robustness
-- }
-- if (merge_cp_length_p == NULL) {
-- assert(false, "caller must provide scatch CP length");
-- return false; // robustness
-- }
-- // Worst case we need old_cp->length() + scratch_cp()->length(),
-- // but the caller might be smart so make sure we have at least
-- // the minimum.
-- if ((*merge_cp_p)->length() < old_cp->length()) {
-- assert(false, "merge area too small");
-- return false; // robustness
-- }
--
-- RC_TRACE_WITH_THREAD(0x00010000, THREAD,
-- ("old_cp_len=%d, scratch_cp_len=%d", old_cp->length(),
-- scratch_cp->length()));
-+ public:
-
-- {
-- // Pass 0:
-- // The old_cp is copied to *merge_cp_p; this means that any code
-- // using old_cp does not have to change. This work looks like a
-- // perfect fit for constantPoolOop::copy_cp_to(), but we need to
-- // handle one special case:
-- // - revert JVM_CONSTANT_Class to JVM_CONSTANT_UnresolvedClass
-- // This will make verification happy.
--
-- int old_i; // index into old_cp
--
-- // index zero (0) is not used in constantPools
-- for (old_i = 1; old_i < old_cp->length(); old_i++) {
-- // leave debugging crumb
-- jbyte old_tag = old_cp->tag_at(old_i).value();
-- switch (old_tag) {
-- case JVM_CONSTANT_Class:
-- case JVM_CONSTANT_UnresolvedClass:
-- // revert the copy to JVM_CONSTANT_UnresolvedClass
-- // May be resolving while calling this so do the same for
-- // JVM_CONSTANT_UnresolvedClass (klass_name_at() deals with transition)
-- (*merge_cp_p)->unresolved_klass_at_put(old_i,
-- old_cp->klass_name_at(old_i));
-- break;
+ GrowableArray< Pair<int, klassOop> > *_arr;
-- case JVM_CONSTANT_Double:
-- case JVM_CONSTANT_Long:
-- // just copy the entry to *merge_cp_p, but double and long take
-- // two constant pool entries
-- constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0);
-- old_i++;
-- break;
+- _index_map_p->at_put(old_index, new_index);
+- _index_map_count++;
+ MyFieldClosure(GrowableArray< Pair<int, klassOop> > *arr) {
+ _arr = arr;
+ }
-- default:
-- // just copy the entry to *merge_cp_p
-- constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0);
-- break;
+- RC_TRACE(0x00040000, ("mapped tag %d at index %d to %d",
+- scratch_cp->tag_at(old_index).value(), old_index, new_index));
+-} // end map_index()
+ virtual void do_field(fieldDescriptor* fd) {
+ if (fd->field_type() == T_OBJECT) {
+ Symbol* signature = fd->signature();
@@ -6677,12 +6693,17 @@
+ _arr->append(Pair<int, klassOop>(fd->offset(), field_klass->klass_part()->newest_version()));
+ }
+ }
-+
+
+ // Array fields can never be a problem!
- }
-- } // end for each old_cp entry
++ }
+ }
-+
+
+-// Map old_index to new_index as needed.
+-void VM_RedefineClasses::map_operand_index(int old_index, int new_index) {
+- if (find_new_operand_index(old_index) != -1) {
+- // old_index is already mapped
+- return;
+- }
+ bool is_field_dangerous(Symbol* klass_name, fieldDescriptor *fd, klassOop &field_klass) {
+ field_klass = SystemDictionary::find(klass_name, fd->field_holder()->klass_part()->class_loader(),
+ fd->field_holder()->klass_part()->protection_domain(), Thread::current());
@@ -6698,9 +6719,9 @@
+ }
+ };
-- // We don't need to sanity check that *merge_cp_length_p is within
-- // *merge_cp_p bounds since we have the minimum on-entry check above.
-- (*merge_cp_length_p) = old_i;
+- if (old_index == new_index) {
+- // no mapping is needed
+- return;
+ MyFieldClosure fieldClosure(&type_check_information);
+ cur_instance_klass->do_nonstatic_fields(&fieldClosure);
+
@@ -6710,242 +6731,54 @@
}
+}
-- // merge_cp_len should be the same as old_cp->length() at this point
-- // so this trace message is really a "warm-and-breathing" message.
-- RC_TRACE_WITH_THREAD(0x00020000, THREAD,
-- ("after pass 0: merge_cp_len=%d", *merge_cp_length_p));
+- _operands_index_map_p->at_put(old_index, new_index);
+- _operands_index_map_count++;
+bool VM_RedefineClasses::check_field_value_types() {
-- int scratch_i; // index into scratch_cp
-- {
-- // Pass 1a:
-- // Compare scratch_cp entries to the old_cp entries that we have
-- // already copied to *merge_cp_p. In this pass, we are eliminating
-- // exact duplicates (matching entry at same index) so we only
-- // compare entries in the common indice range.
-- int increment = 1;
-- int pass1a_length = MIN2(old_cp->length(), scratch_cp->length());
-- for (scratch_i = 1; scratch_i < pass1a_length; scratch_i += increment) {
-- switch (scratch_cp->tag_at(scratch_i).value()) {
-- case JVM_CONSTANT_Double:
-- case JVM_CONSTANT_Long:
-- // double and long take two constant pool entries
-- increment = 2;
-- break;
+- RC_TRACE(0x00040000, ("mapped bootstrap specifier at index %d to %d", old_index, new_index));
+-} // end map_index()
+ Thread *THREAD = Thread::current();
+ class CheckFieldTypesClosure : public ObjectClosure {
-- default:
-- increment = 1;
-- break;
-- }
+ private:
-- bool match = scratch_cp->compare_entry_to(scratch_i, *merge_cp_p,
-- scratch_i, CHECK_0);
-- if (match) {
-- // found a match at the same index so nothing more to do
-- continue;
-- } else if (is_unresolved_class_mismatch(scratch_cp, scratch_i,
-- *merge_cp_p, scratch_i)) {
-- // The mismatch in compare_entry_to() above is because of a
-- // resolved versus unresolved class entry at the same index
-- // with the same string value. Since Pass 0 reverted any
-- // class entries to unresolved class entries in *merge_cp_p,
-- // we go with the unresolved class entry.
-- continue;
-- } else if (is_unresolved_string_mismatch(scratch_cp, scratch_i,
-- *merge_cp_p, scratch_i)) {
-- // The mismatch in compare_entry_to() above is because of a
-- // resolved versus unresolved string entry at the same index
-- // with the same string value. We can live with whichever
-- // happens to be at scratch_i in *merge_cp_p.
-- continue;
-- }
--
-- int found_i = scratch_cp->find_matching_entry(scratch_i, *merge_cp_p,
-- CHECK_0);
-- if (found_i != 0) {
-- guarantee(found_i != scratch_i,
-- "compare_entry_to() and find_matching_entry() do not agree");
--
-- // Found a matching entry somewhere else in *merge_cp_p so
-- // just need a mapping entry.
-- map_index(scratch_cp, scratch_i, found_i);
-- continue;
-- }
--
-- // The find_matching_entry() call above could fail to find a match
-- // due to a resolved versus unresolved class or string entry situation
-- // like we solved above with the is_unresolved_*_mismatch() calls.
-- // However, we would have to call is_unresolved_*_mismatch() over
-- // all of *merge_cp_p (potentially) and that doesn't seem to be
-- // worth the time.
--
-- // No match found so we have to append this entry and any unique
-- // referenced entries to *merge_cp_p.
-- append_entry(scratch_cp, scratch_i, merge_cp_p, merge_cp_length_p,
-- CHECK_0);
-- }
-- }
--
-- RC_TRACE_WITH_THREAD(0x00020000, THREAD,
-- ("after pass 1a: merge_cp_len=%d, scratch_i=%d, index_map_len=%d",
-- *merge_cp_length_p, scratch_i, _index_map_count));
--
-- if (scratch_i < scratch_cp->length()) {
-- // Pass 1b:
-- // old_cp is smaller than scratch_cp so there are entries in
-- // scratch_cp that we have not yet processed. We take care of
-- // those now.
-- int increment = 1;
-- for (; scratch_i < scratch_cp->length(); scratch_i += increment) {
-- switch (scratch_cp->tag_at(scratch_i).value()) {
-- case JVM_CONSTANT_Double:
-- case JVM_CONSTANT_Long:
-- // double and long take two constant pool entries
-- increment = 2;
-- break;
+-// Merge old_cp and scratch_cp and return the results of the merge via
+-// merge_cp_p. The number of entries in *merge_cp_p is returned via
+-// merge_cp_length_p. The entries in old_cp occupy the same locations
+-// in *merge_cp_p. Also creates a map of indices from entries in
+-// scratch_cp to the corresponding entry in *merge_cp_p. Index map
+-// entries are only created for entries in scratch_cp that occupy a
+-// different location in *merged_cp_p.
+-bool VM_RedefineClasses::merge_constant_pools(constantPoolHandle old_cp,
+- constantPoolHandle scratch_cp, constantPoolHandle *merge_cp_p,
+- int *merge_cp_length_p, TRAPS) {
+ bool _result;
-- default:
-- increment = 1;
-- break;
-- }
-+ public:
-
-- int found_i =
-- scratch_cp->find_matching_entry(scratch_i, *merge_cp_p, CHECK_0);
-- if (found_i != 0) {
-- // Found a matching entry somewhere else in *merge_cp_p so
-- // just need a mapping entry.
-- map_index(scratch_cp, scratch_i, found_i);
-- continue;
-- }
--
-- // No match found so we have to append this entry and any unique
-- // referenced entries to *merge_cp_p.
-- append_entry(scratch_cp, scratch_i, merge_cp_p, merge_cp_length_p,
-- CHECK_0);
-- }
--
-- RC_TRACE_WITH_THREAD(0x00020000, THREAD,
-- ("after pass 1b: merge_cp_len=%d, scratch_i=%d, index_map_len=%d",
-- *merge_cp_length_p, scratch_i, _index_map_count));
+- if (merge_cp_p == NULL) {
+- assert(false, "caller must provide scatch constantPool");
+- return false; // robustness
- }
+- if (merge_cp_length_p == NULL) {
+- assert(false, "caller must provide scatch CP length");
+- return false; // robustness
++ public:
++
+ CheckFieldTypesClosure() {
+ _result = true;
+ }
-
-- return true;
--} // end merge_constant_pools()
++
+ bool result() { return _result; }
-
++
+ virtual void do_object(oop obj) {
-
--// Merge constant pools between the_class and scratch_class and
--// potentially rewrite bytecodes in scratch_class to use the merged
--// constant pool.
--jvmtiError VM_RedefineClasses::merge_cp_and_rewrite(
-- instanceKlassHandle the_class, instanceKlassHandle scratch_class,
-- TRAPS) {
-- // worst case merged constant pool length is old and new combined
-- int merge_cp_length = the_class->constants()->length()
-- + scratch_class->constants()->length();
--
-- constantPoolHandle old_cp(THREAD, the_class->constants());
-- constantPoolHandle scratch_cp(THREAD, scratch_class->constants());
--
-- // Constant pools are not easily reused so we allocate a new one
-- // each time.
-- // merge_cp is created unsafe for concurrent GC processing. It
-- // should be marked safe before discarding it. Even though
-- // garbage, if it crosses a card boundary, it may be scanned
-- // in order to find the start of the first complete object on the card.
-- constantPoolHandle merge_cp(THREAD,
-- oopFactory::new_constantPool(merge_cp_length,
-- oopDesc::IsUnsafeConc,
-- THREAD));
-- int orig_length = old_cp->orig_length();
-- if (orig_length == 0) {
-- // This old_cp is an actual original constant pool. We save
-- // the original length in the merged constant pool so that
-- // merge_constant_pools() can be more efficient. If a constant
-- // pool has a non-zero orig_length() value, then that constant
-- // pool was created by a merge operation in RedefineClasses.
-- merge_cp->set_orig_length(old_cp->length());
-- } else {
-- // This old_cp is a merged constant pool from a previous
-- // RedefineClasses() calls so just copy the orig_length()
-- // value.
-- merge_cp->set_orig_length(old_cp->orig_length());
-- }
++
+ if (!_result) {
+ return;
+ }
-
-- ResourceMark rm(THREAD);
-- _index_map_count = 0;
-- _index_map_p = new intArray(scratch_cp->length(), -1);
++
+ if (obj->is_objArray()) {
-
-- bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp,
-- &merge_cp_length, THREAD);
-- if (!result) {
-- // The merge can fail due to memory allocation failure or due
-- // to robustness checks.
-- return JVMTI_ERROR_INTERNAL;
-- }
--
-- RC_TRACE_WITH_THREAD(0x00010000, THREAD,
-- ("merge_cp_len=%d, index_map_len=%d", merge_cp_length, _index_map_count));
--
-- if (_index_map_count == 0) {
-- // there is nothing to map between the new and merged constant pools
--
-- if (old_cp->length() == scratch_cp->length()) {
-- // The old and new constant pools are the same length and the
-- // index map is empty. This means that the three constant pools
-- // are equivalent (but not the same). Unfortunately, the new
-- // constant pool has not gone through link resolution nor have
-- // the new class bytecodes gone through constant pool cache
-- // rewriting so we can't use the old constant pool with the new
-- // class.
--
-- merge_cp()->set_is_conc_safe(true);
-- merge_cp = constantPoolHandle(); // toss the merged constant pool
-- } else if (old_cp->length() < scratch_cp->length()) {
-- // The old constant pool has fewer entries than the new constant
-- // pool and the index map is empty. This means the new constant
-- // pool is a superset of the old constant pool. However, the old
-- // class bytecodes have already gone through constant pool cache
-- // rewriting so we can't use the new constant pool with the old
-- // class.
++
+ objArrayOop array = objArrayOop(obj);
-
-- merge_cp()->set_is_conc_safe(true);
-- merge_cp = constantPoolHandle(); // toss the merged constant pool
-- } else {
-- // The old constant pool has more entries than the new constant
-- // pool and the index map is empty. This means that both the old
-- // and merged constant pools are supersets of the new constant
-- // pool.
--
-- // Replace the new constant pool with a shrunken copy of the
-- // merged constant pool; the previous new constant pool will
-- // get GCed.
-- set_new_constant_pool(scratch_class, merge_cp, merge_cp_length, true,
-- THREAD);
-- // drop local ref to the merged constant pool
-- merge_cp()->set_is_conc_safe(true);
-- merge_cp = constantPoolHandle();
-- }
-- } else {
-- if (RC_TRACE_ENABLED(0x00040000)) {
-- // don't want to loop unless we are tracing
-- int count = 0;
-- for (int i = 1; i < _index_map_p->length(); i++) {
-- int value = _index_map_p->at(i);
++
+ klassOop element_klass = objArrayKlass::cast(array->klass())->element_klass();
+
+ if (element_klass->klass_part()->has_subtype_changed()) {
@@ -6965,11 +6798,7 @@
+ }
+ }
+ }
-
-- if (value != -1) {
-- RC_TRACE_WITH_THREAD(0x00040000, THREAD,
-- ("index_map[%d]: old=%d new=%d", count, i, value));
-- count++;
++
+ } else {
+ Pair<int, klassOop> *cur = obj->klass()->klass_part()->type_check_information();
+ if (cur != NULL) {
@@ -6978,14 +6807,10 @@
+ check_field(obj, (*cur).left(), (*cur).right());
+ cur++;
+ }
- }
- }
- }
-
-- // We have entries mapped between the new and merged constant pools
-- // so we have to rewrite some constant pool references.
-- if (!rewrite_cp_refs(scratch_class, THREAD)) {
-- return JVMTI_ERROR_INTERNAL;
++ }
++ }
++ }
++
+ void check_field(oop obj, int offset, klassOop static_type) {
+ oop field_value = obj->obj_field(offset);
+ if (field_value != NULL) {
@@ -7007,40 +6832,20 @@
+ _result = false;
+ }
+ }
- }
++ }
+ };
-
-- // Replace the new constant pool with a shrunken copy of the
-- // merged constant pool so now the rewritten bytecodes have
-- // valid references; the previous new constant pool will get
-- // GCed.
-- set_new_constant_pool(scratch_class, merge_cp, merge_cp_length, true,
-- THREAD);
-- merge_cp()->set_is_conc_safe(true);
-- }
-- assert(old_cp()->is_conc_safe(), "Just checking");
-- assert(scratch_cp()->is_conc_safe(), "Just checking");
--
-- return JVMTI_ERROR_NONE;
--} // end merge_cp_and_rewrite()
++
+ CheckFieldTypesClosure myObjectClosure;
-
++
+ // make sure that heap is parsable (fills TLABs with filler objects)
+ Universe::heap()->ensure_parsability(false); // no need to retire TLABs
-
--// Rewrite constant pool references in klass scratch_class.
--bool VM_RedefineClasses::rewrite_cp_refs(instanceKlassHandle scratch_class,
-- TRAPS) {
++
+ // do the iteration
+ // If this operation encounters a bad object when using CMS,
+ // consider using safe_object_iterate() which avoids perm gen
+ // objects that may contain bad references.
+ Universe::heap()->object_iterate(&myObjectClosure);
-
-- // rewrite constant pool references in the methods:
-- if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) {
-- // propagate failure back to caller
-- return false;
++
+ // when sharing is enabled we must iterate over the shared spaces
+ if (UseSharedSpaces) {
+ GenCollectedHeap* gch = GenCollectedHeap::heap();
@@ -7048,41 +6853,62 @@
+ gen->ro_space()->object_iterate(&myObjectClosure);
+ gen->rw_space()->object_iterate(&myObjectClosure);
}
-
-- // rewrite constant pool references in the class_annotations:
-- if (!rewrite_cp_refs_in_class_annotations(scratch_class, THREAD)) {
-- // propagate failure back to caller
-- return false;
-- }
-+ return myObjectClosure.result();
-+}
-
-- // rewrite constant pool references in the fields_annotations:
-- if (!rewrite_cp_refs_in_fields_annotations(scratch_class, THREAD)) {
-- // propagate failure back to caller
-- return false;
+- // Worst case we need old_cp->length() + scratch_cp()->length(),
+- // but the caller might be smart so make sure we have at least
+- // the minimum.
+- if ((*merge_cp_p)->length() < old_cp->length()) {
+- assert(false, "merge area too small");
+- return false; // robustness
++
++ return myObjectClosure.result();
++}
++
+void VM_RedefineClasses::clear_type_check_information(klassOop k) {
+ if (k->klass_part()->is_redefining()) {
+ k = k->klass_part()->old_version();
}
-- // rewrite constant pool references in the methods_annotations:
-- if (!rewrite_cp_refs_in_methods_annotations(scratch_class, THREAD)) {
-- // propagate failure back to caller
-- return false;
-- }
+- RC_TRACE_WITH_THREAD(0x00010000, THREAD,
+- ("old_cp_len=%d, scratch_cp_len=%d", old_cp->length(),
+- scratch_cp->length()));
+ // We found an instance klass!
+ instanceKlass *cur_instance_klass = instanceKlass::cast(k);
+ cur_instance_klass->clear_type_check_information();
+}
-- // rewrite constant pool references in the methods_parameter_annotations:
-- if (!rewrite_cp_refs_in_methods_parameter_annotations(scratch_class,
-- THREAD)) {
-- // propagate failure back to caller
-- return false;
+- {
+- // Pass 0:
+- // The old_cp is copied to *merge_cp_p; this means that any code
+- // using old_cp does not have to change. This work looks like a
+- // perfect fit for constantPoolOop::copy_cp_to(), but we need to
+- // handle one special case:
+- // - revert JVM_CONSTANT_Class to JVM_CONSTANT_UnresolvedClass
+- // This will make verification happy.
+-
+- int old_i; // index into old_cp
+-
+- // index zero (0) is not used in constantPools
+- for (old_i = 1; old_i < old_cp->length(); old_i++) {
+- // leave debugging crumb
+- jbyte old_tag = old_cp->tag_at(old_i).value();
+- switch (old_tag) {
+- case JVM_CONSTANT_Class:
+- case JVM_CONSTANT_UnresolvedClass:
+- // revert the copy to JVM_CONSTANT_UnresolvedClass
+- // May be resolving while calling this so do the same for
+- // JVM_CONSTANT_UnresolvedClass (klass_name_at() deals with transition)
+- (*merge_cp_p)->unresolved_klass_at_put(old_i,
+- old_cp->klass_name_at(old_i));
+- break;
+void VM_RedefineClasses::update_active_methods() {
-+
+
+- case JVM_CONSTANT_Double:
+- case JVM_CONSTANT_Long:
+- // just copy the entry to *merge_cp_p, but double and long take
+- // two constant pool entries
+- constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0);
+- old_i++;
+- break;
+ RC_TRACE(0x00000002, ("Updating active methods"));
+ JavaThread *java_thread = Threads::first();
+ while (java_thread != NULL) {
@@ -7147,7 +6973,11 @@
+ cp_new->entry_at(i)->print(tty, i);
+ }
+ }
-+
+
+- default:
+- // just copy the entry to *merge_cp_p
+- constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0);
+- break;
+ iframe->set_method(jvf->method()->new_version(), bci);
+ RC_TRACE(0x00000002, ("Updated method to newer version"));
+ assert(jvf->method()->new_version() == NULL, "must be latest version");
@@ -7156,21 +6986,22 @@
+ }
+ }
+ vf = vf->sender();
-+ }
+ }
+- } // end for each old_cp entry
+ }
+
+ // Advance to next thread
+ java_thread = java_thread->next();
- }
++ }
+}
-- // rewrite constant pool references in the methods_default_annotations:
-- if (!rewrite_cp_refs_in_methods_default_annotations(scratch_class,
-- THREAD)) {
-- // propagate failure back to caller
-- return false;
+- constantPoolOopDesc::copy_operands(old_cp, *merge_cp_p, CHECK_0);
+- (*merge_cp_p)->extend_operands(scratch_cp, CHECK_0);
+void VM_RedefineClasses::method_forwarding() {
-+
+
+- // We don't need to sanity check that *merge_cp_length_p is within
+- // *merge_cp_p bounds since we have the minimum on-entry check above.
+- (*merge_cp_length_p) = old_i;
+ int forwarding_count = 0;
+ JavaThread *java_thread = Threads::first();
+ while (java_thread != NULL) {
@@ -7256,28 +7087,110 @@
+ java_thread = java_thread->next();
}
-- return true;
--} // end rewrite_cp_refs()
+- // merge_cp_len should be the same as old_cp->length() at this point
+- // so this trace message is really a "warm-and-breathing" message.
+- RC_TRACE_WITH_THREAD(0x00020000, THREAD,
+- ("after pass 0: merge_cp_len=%d", *merge_cp_length_p));
+ RC_TRACE(0x00000001, ("Method forwarding applied to %d methods",
+ forwarding_count));
+}
+- int scratch_i; // index into scratch_cp
+- {
+- // Pass 1a:
+- // Compare scratch_cp entries to the old_cp entries that we have
+- // already copied to *merge_cp_p. In this pass, we are eliminating
+- // exact duplicates (matching entry at same index) so we only
+- // compare entries in the common indice range.
+- int increment = 1;
+- int pass1a_length = MIN2(old_cp->length(), scratch_cp->length());
+- for (scratch_i = 1; scratch_i < pass1a_length; scratch_i += increment) {
+- switch (scratch_cp->tag_at(scratch_i).value()) {
+- case JVM_CONSTANT_Double:
+- case JVM_CONSTANT_Long:
+- // double and long take two constant pool entries
+- increment = 2;
+- break;
+bool VM_RedefineClasses::check_method_stacks() {
--// Rewrite constant pool references in the methods.
--bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
-- instanceKlassHandle scratch_class, TRAPS) {
+- default:
+- increment = 1;
+- break;
+- }
+ JavaThread *java_thread = Threads::first();
+ while (java_thread != NULL) {
-- objArrayHandle methods(THREAD, scratch_class->methods());
+- bool match = scratch_cp->compare_entry_to(scratch_i, *merge_cp_p,
+- scratch_i, CHECK_0);
+- if (match) {
+- // found a match at the same index so nothing more to do
+- continue;
+- } else if (is_unresolved_class_mismatch(scratch_cp, scratch_i,
+- *merge_cp_p, scratch_i)) {
+- // The mismatch in compare_entry_to() above is because of a
+- // resolved versus unresolved class entry at the same index
+- // with the same string value. Since Pass 0 reverted any
+- // class entries to unresolved class entries in *merge_cp_p,
+- // we go with the unresolved class entry.
+- continue;
+- } else if (is_unresolved_string_mismatch(scratch_cp, scratch_i,
+- *merge_cp_p, scratch_i)) {
+- // The mismatch in compare_entry_to() above is because of a
+- // resolved versus unresolved string entry at the same index
+- // with the same string value. We can live with whichever
+- // happens to be at scratch_i in *merge_cp_p.
+- continue;
+- }
+-
+- int found_i = scratch_cp->find_matching_entry(scratch_i, *merge_cp_p,
+- CHECK_0);
+- if (found_i != 0) {
+- guarantee(found_i != scratch_i,
+- "compare_entry_to() and find_matching_entry() do not agree");
+-
+- // Found a matching entry somewhere else in *merge_cp_p so
+- // just need a mapping entry.
+- map_index(scratch_cp, scratch_i, found_i);
+- continue;
+- }
+-
+- // The find_matching_entry() call above could fail to find a match
+- // due to a resolved versus unresolved class or string entry situation
+- // like we solved above with the is_unresolved_*_mismatch() calls.
+- // However, we would have to call is_unresolved_*_mismatch() over
+- // all of *merge_cp_p (potentially) and that doesn't seem to be
+- // worth the time.
+-
+- // No match found so we have to append this entry and any unique
+- // referenced entries to *merge_cp_p.
+- append_entry(scratch_cp, scratch_i, merge_cp_p, merge_cp_length_p,
+- CHECK_0);
+- }
+- }
+-
+- RC_TRACE_WITH_THREAD(0x00020000, THREAD,
+- ("after pass 1a: merge_cp_len=%d, scratch_i=%d, index_map_len=%d",
+- *merge_cp_length_p, scratch_i, _index_map_count));
+-
+- if (scratch_i < scratch_cp->length()) {
+- // Pass 1b:
+- // old_cp is smaller than scratch_cp so there are entries in
+- // scratch_cp that we have not yet processed. We take care of
+- // those now.
+- int increment = 1;
+- for (; scratch_i < scratch_cp->length(); scratch_i += increment) {
+- switch (scratch_cp->tag_at(scratch_i).value()) {
+- case JVM_CONSTANT_Double:
+- case JVM_CONSTANT_Long:
+- // double and long take two constant pool entries
+- increment = 2;
+- break;
+ int stack_depth = 0;
+ if (java_thread->has_last_Java_frame()) {
-- if (methods.is_null() || methods->length() == 0) {
-- // no methods so nothing to do
-- return true;
-- }
+- default:
+- increment = 1;
+- break;
+ RC_TRACE(0x00000400, ("checking stack of Java thread %s", java_thread->name()));
+
+ // vframes are resource allocated
@@ -7382,32 +7295,527 @@
+ Thread::current()->clear_pending_exception();
+ return false;
+ }
-
-- // rewrite constant pool references in the methods:
-- for (int i = methods->length() - 1; i >= 0; i--) {
-- methodHandle method(THREAD, (methodOop)methods->obj_at(i));
-- methodHandle new_method;
-- rewrite_cp_refs_in_method(method, &new_method, CHECK_false);
-- if (!new_method.is_null()) {
-- // the method has been replaced so save the new method version
-- methods->obj_at_put(i, new_method());
++
+ }
+ }
+ }
+ }
+ }
-+ vf = vf->sender();
++ vf = vf->sender();
+ }
++ }
+
+- int found_i =
+- scratch_cp->find_matching_entry(scratch_i, *merge_cp_p, CHECK_0);
+- if (found_i != 0) {
+- // Found a matching entry somewhere else in *merge_cp_p so
+- // just need a mapping entry.
+- map_index(scratch_cp, scratch_i, found_i);
+- continue;
+- }
+-
+- // No match found so we have to append this entry and any unique
+- // referenced entries to *merge_cp_p.
+- append_entry(scratch_cp, scratch_i, merge_cp_p, merge_cp_length_p,
+- CHECK_0);
+- }
+-
+- RC_TRACE_WITH_THREAD(0x00020000, THREAD,
+- ("after pass 1b: merge_cp_len=%d, scratch_i=%d, index_map_len=%d",
+- *merge_cp_length_p, scratch_i, _index_map_count));
++ // Advance to next thread
++ java_thread = java_thread->next();
+ }
+- finalize_operands_merge(*merge_cp_p, THREAD);
+
+ return true;
+-} // end merge_constant_pools()
++}
+
++bool VM_RedefineClasses::check_method(methodOop method) {
+
+-// Merge constant pools between the_class and scratch_class and
+-// potentially rewrite bytecodes in scratch_class to use the merged
+-// constant pool.
+-jvmtiError VM_RedefineClasses::merge_cp_and_rewrite(
+- instanceKlassHandle the_class, instanceKlassHandle scratch_class,
+- TRAPS) {
+- // worst case merged constant pool length is old and new combined
+- int merge_cp_length = the_class->constants()->length()
+- + scratch_class->constants()->length();
+-
+- constantPoolHandle old_cp(THREAD, the_class->constants());
+- constantPoolHandle scratch_cp(THREAD, scratch_class->constants());
+-
+- // Constant pools are not easily reused so we allocate a new one
+- // each time.
+- // merge_cp is created unsafe for concurrent GC processing. It
+- // should be marked safe before discarding it. Even though
+- // garbage, if it crosses a card boundary, it may be scanned
+- // in order to find the start of the first complete object on the card.
+- constantPoolHandle merge_cp(THREAD,
+- oopFactory::new_constantPool(merge_cp_length,
+- oopDesc::IsUnsafeConc,
+- THREAD));
+- int orig_length = old_cp->orig_length();
+- if (orig_length == 0) {
+- // This old_cp is an actual original constant pool. We save
+- // the original length in the merged constant pool so that
+- // merge_constant_pools() can be more efficient. If a constant
+- // pool has a non-zero orig_length() value, then that constant
+- // pool was created by a merge operation in RedefineClasses.
+- merge_cp->set_orig_length(old_cp->length());
+- } else {
+- // This old_cp is a merged constant pool from a previous
+- // RedefineClasses() calls so just copy the orig_length()
+- // value.
+- merge_cp->set_orig_length(old_cp->orig_length());
+- }
+
+- ResourceMark rm(THREAD);
+- _index_map_count = 0;
+- _index_map_p = new intArray(scratch_cp->length(), -1);
++ return true;
++}
+
+- _operands_cur_length = constantPoolOopDesc::operand_array_length(old_cp->operands());
+- _operands_index_map_count = 0;
+- _operands_index_map_p = new intArray(
+- constantPoolOopDesc::operand_array_length(scratch_cp->operands()), -1);
+-
+- // reference to the cp holder is needed for copy_operands()
+- merge_cp->set_pool_holder(scratch_class());
+- bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp,
+- &merge_cp_length, THREAD);
+- merge_cp->set_pool_holder(NULL);
++// Warning: destroys redefinition level values of klasses.
++bool VM_RedefineClasses::check_loaded_methods() {
+
+- if (!result) {
+- // The merge can fail due to memory allocation failure or due
+- // to robustness checks.
+- return JVMTI_ERROR_INTERNAL;
+- }
+-
+- RC_TRACE_WITH_THREAD(0x00010000, THREAD,
+- ("merge_cp_len=%d, index_map_len=%d", merge_cp_length, _index_map_count));
+-
+- if (_index_map_count == 0) {
+- // there is nothing to map between the new and merged constant pools
+-
+- if (old_cp->length() == scratch_cp->length()) {
+- // The old and new constant pools are the same length and the
+- // index map is empty. This means that the three constant pools
+- // are equivalent (but not the same). Unfortunately, the new
+- // constant pool has not gone through link resolution nor have
+- // the new class bytecodes gone through constant pool cache
+- // rewriting so we can't use the old constant pool with the new
+- // class.
+-
+- merge_cp()->set_is_conc_safe(true);
+- merge_cp = constantPoolHandle(); // toss the merged constant pool
+- } else if (old_cp->length() < scratch_cp->length()) {
+- // The old constant pool has fewer entries than the new constant
+- // pool and the index map is empty. This means the new constant
+- // pool is a superset of the old constant pool. However, the old
+- // class bytecodes have already gone through constant pool cache
+- // rewriting so we can't use the new constant pool with the old
+- // class.
++ class CheckLoadedMethodsClosure : public ObjectClosure {
+
+- merge_cp()->set_is_conc_safe(true);
+- merge_cp = constantPoolHandle(); // toss the merged constant pool
+- } else {
+- // The old constant pool has more entries than the new constant
+- // pool and the index map is empty. This means that both the old
+- // and merged constant pools are supersets of the new constant
+- // pool.
+-
+- // Replace the new constant pool with a shrunken copy of the
+- // merged constant pool; the previous new constant pool will
+- // get GCed.
+- set_new_constant_pool(scratch_class, merge_cp, merge_cp_length,
+- THREAD);
+- // drop local ref to the merged constant pool
+- merge_cp()->set_is_conc_safe(true);
+- merge_cp = constantPoolHandle();
++ private:
++
++ bool _result;
++ GrowableArray<klassOop> *_dangerous_klasses;
++
++ public:
++ CheckLoadedMethodsClosure(GrowableArray<klassOop> *dangerous_klasses) {
++ _result = true;
++ _dangerous_klasses = dangerous_klasses;
++ }
++
++ bool result() {
++ return _result;
++ }
++
++ bool is_class_dangerous(klassOop k) {
++ return k->klass_part()->newest_version()->klass_part()->check_redefinition_flag(Klass::RemoveSuperType);
++ }
++
++ bool can_be_affected(instanceKlass *klass) {
++
++ constantPoolOop cp = klass->constants();
++
++ Thread *THREAD = Thread::current();
++ klassOop k;
++ Symbol* symbol;
++
++ for (int i=1; i<cp->length(); i++) {
++ jbyte tag = cp->tag_at(i).value();
++ switch(tag) {
++ case JVM_CONSTANT_Long:
++ case JVM_CONSTANT_Double:
++ i++;
++ break;
++
++ case JVM_CONSTANT_Utf8:
++ case JVM_CONSTANT_Unicode:
++ case JVM_CONSTANT_Integer:
++ case JVM_CONSTANT_Float:
++ case JVM_CONSTANT_String:
++ case JVM_CONSTANT_Fieldref:
++ case JVM_CONSTANT_Methodref:
++ case JVM_CONSTANT_InterfaceMethodref:
++ case JVM_CONSTANT_ClassIndex:
++ case JVM_CONSTANT_UnresolvedString:
++ case JVM_CONSTANT_StringIndex:
++ case JVM_CONSTANT_UnresolvedClassInError:
++ case JVM_CONSTANT_Object:
++ // do nothing
++ break;
++
++ case JVM_CONSTANT_Class:
++ k = cp->klass_at(i, CHECK_(true));
++ if (is_class_dangerous(k)) {
++ RC_TRACE(0x00000002, ("Class %s is potentially affected, because at cp[%d] references class %s",
++ klass->name()->as_C_string(),
++ i,
++ k->klass_part()->name()->as_C_string()));
++ return true;
++ }
++ break;
++
++ case JVM_CONSTANT_NameAndType:
++ symbol = cp->symbol_at(cp->signature_ref_index_at(i));
++ if (symbol->byte_at(0) == '(') {
++ // This must be a method
++ SignatureStream signatureStream(symbol);
++ while (true) {
++
++ if (signatureStream.is_array()) {
++ Symbol* cur_signature = signatureStream.as_symbol(Thread::current());
++ if (is_type_signature_dangerous(cur_signature)) {
++ return true;
++ }
++ } else if (signatureStream.is_object()) {
++ if (is_symbol_dangerous(signatureStream.as_symbol(Thread::current()))) {
++ return true;
++ }
++ }
++
++ if (signatureStream.at_return_type()) {
++ break;
++ }
++
++ signatureStream.next();
++ }
++
++ } else if (is_type_signature_dangerous(symbol)) {
++ return true;
++ }
++ break;
++
++ case JVM_CONSTANT_UnresolvedClass:
++ symbol = cp->unresolved_klass_at(i);
++ if (is_symbol_dangerous(symbol)) {
++ return true;
++ }
++ break;
++
++ default:
++ ShouldNotReachHere();
++ }
++ }
++
++ return false;
+ }
+- } else {
+- if (RC_TRACE_ENABLED(0x00040000)) {
+- // don't want to loop unless we are tracing
+- int count = 0;
+- for (int i = 1; i < _index_map_p->length(); i++) {
+- int value = _index_map_p->at(i);
+
+- if (value != -1) {
+- RC_TRACE_WITH_THREAD(0x00040000, THREAD,
+- ("index_map[%d]: old=%d new=%d", count, i, value));
+- count++;
++ bool is_type_signature_dangerous(Symbol* signature) {
++ // This must be a field type
++ if (FieldType::is_obj(signature)) {
++ Symbol* name = signature_to_class_name(signature);
++ if (is_symbol_dangerous(name)) {
++ return true;
++ }
++ } else if (FieldType::is_array(signature)) {
++ //jint dimension;
++ //Symbol* object_key;
++ FieldArrayInfo fd;
++ FieldType::get_array_info(signature, fd, Thread::current());
++ if (is_symbol_dangerous(fd.object_key())) {
++ return true;
+ }
+ }
++ return false;
+ }
+
+- // We have entries mapped between the new and merged constant pools
+- // so we have to rewrite some constant pool references.
+- if (!rewrite_cp_refs(scratch_class, THREAD)) {
+- return JVMTI_ERROR_INTERNAL;
++ bool is_symbol_dangerous(Symbol* symbol) {
++ for (int i=0; i<_dangerous_klasses->length(); i++) {
++ if(_dangerous_klasses->at(i)->klass_part()->name() == symbol) {
++ RC_TRACE(0x00000002, ("Found constant pool index %d references class %s",
++ i,
++ symbol->as_C_string()));
++ return true;
++ }
++ }
++ return false;
+ }
+
+- // Replace the new constant pool with a shrunken copy of the
+- // merged constant pool so now the rewritten bytecodes have
+- // valid references; the previous new constant pool will get
+- // GCed.
+- set_new_constant_pool(scratch_class, merge_cp, merge_cp_length,
+- THREAD);
+- merge_cp()->set_is_conc_safe(true);
+- }
+- assert(old_cp()->is_conc_safe(), "Just checking");
+- assert(scratch_cp()->is_conc_safe(), "Just checking");
++ virtual void do_object(oop obj) {
+
+- return JVMTI_ERROR_NONE;
+-} // end merge_cp_and_rewrite()
++ if (!_result) return;
+
++ klassOop klassObj = (klassOop)obj;
++ Thread *THREAD = Thread::current();
+
+-// Rewrite constant pool references in klass scratch_class.
+-bool VM_RedefineClasses::rewrite_cp_refs(instanceKlassHandle scratch_class,
+- TRAPS) {
++ // We found an instance klass!
++ instanceKlass *klass = instanceKlass::cast(klassObj);
++ instanceKlassHandle handle(klassObj);
+
+- // rewrite constant pool references in the methods:
+- if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) {
+- // propagate failure back to caller
+- return false;
+- }
++ RC_TRACE(0x00000400, ("Check if verification is necessary for class %s major_version=%d", handle->name()->as_C_string(), handle->major_version()));
+
+- // rewrite constant pool references in the class_annotations:
+- if (!rewrite_cp_refs_in_class_annotations(scratch_class, THREAD)) {
+- // propagate failure back to caller
+- return false;
+- }
++ if (!can_be_affected(klass)) {
++ RC_TRACE(0x00000400, ("Skipping verification of class %s major_version=%d", handle->name()->as_C_string(), handle->major_version()));
++ return;
++ }
+
+- // rewrite constant pool references in the fields_annotations:
+- if (!rewrite_cp_refs_in_fields_annotations(scratch_class, THREAD)) {
+- // propagate failure back to caller
+- return false;
++ if (handle->major_version() < Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION) {
++ RC_TRACE(0x00000001, ("Failing because cannot verify class %s major_version=%d", handle->name()->as_C_string(), handle->major_version()));
++ _result = false;
++ return;
++ }
++
++ RC_TRACE(0x00000001, ("Verifying class %s", handle->name()->as_C_string()));
++
++ if (!Verifier::verify(handle, Verifier::NoException, true, false, Thread::current())) {
++
++ RC_TRACE(0x00000001, ("Verification of class %s failed", handle->name()->as_C_string()));
++ //Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
++ //RC_TRACE(0x00000002, ("exception when verifying class: '%s'", ex_name->as_C_string());
++ //PENDING_EXCEPTION->print();
++ CLEAR_PENDING_EXCEPTION;
++ _result = false;
++ }
++
++ /*int method_count = klass->methods()->length();
++ for (int i=0; i<method_count; i++) {
++ methodOop cur_method = (methodOop)klass->methods()->obj_at(i);
++ if (!check_method(cur_method)) {
++ RC_TRACE(0x00000001, ("Failed to verify consistency of method %s of klass %s", cur_method->name()->as_C_string(), klass->name()->as_C_string());
++ }
++ }*/
++ }
++ };
++
++ // TODO: Check bytecodes in case of interface => class or class => interface etc..
++
++ GrowableArray<klassOop> dangerous_klasses;
++ for (int i=0; i<_new_classes->length(); i++) {
++ instanceKlassHandle handle = _new_classes->at(i);
++ if (handle->check_redefinition_flag(Klass::RemoveSuperType)) {
++ dangerous_klasses.append(handle());
++ }
+ }
+
+- // rewrite constant pool references in the methods_annotations:
+- if (!rewrite_cp_refs_in_methods_annotations(scratch_class, THREAD)) {
+- // propagate failure back to caller
++ CheckLoadedMethodsClosure checkLoadedMethodsClosure(&dangerous_klasses);
++ Thread::current()->set_pretend_new_universe(true);
++ SystemDictionary::classes_do(&checkLoadedMethodsClosure);
++ Thread::current()->set_pretend_new_universe(false);
++
++
++ return checkLoadedMethodsClosure.result();
++}
++
++bool VM_RedefineClasses::check_type_consistency() {
++
++ Universe::set_verify_in_progress(true);
++
++ SystemDictionary::classes_do(calculate_type_check_information);
++ bool result = check_field_value_types();
++ SystemDictionary::classes_do(clear_type_check_information);
++ if (!result) {
++ RC_TRACE(0x00000001, ("Aborting redefinition because of wrong field or array element value!"));
++ Universe::set_verify_in_progress(false);
+ return false;
+ }
+
+- // rewrite constant pool references in the methods_parameter_annotations:
+- if (!rewrite_cp_refs_in_methods_parameter_annotations(scratch_class,
+- THREAD)) {
+- // propagate failure back to caller
++ result = check_method_stacks();
++ if (!result) {
++ RC_TRACE(0x00000001, ("Aborting redefinition because of wrong value on the stack"));
++ Universe::set_verify_in_progress(false);
+ return false;
+ }
+
+- // rewrite constant pool references in the methods_default_annotations:
+- if (!rewrite_cp_refs_in_methods_default_annotations(scratch_class,
+- THREAD)) {
+- // propagate failure back to caller
++ result = check_loaded_methods();
++ if (!result) {
++ RC_TRACE(0x00000001, ("Aborting redefinition because of wrong loaded method"));
++ Universe::set_verify_in_progress(false);
+ return false;
+ }
+
++ RC_TRACE(0x00000001, ("Verification passed => hierarchy change is valid!"));
++ Universe::set_verify_in_progress(false);
+ return true;
+-} // end rewrite_cp_refs()
+-
+-
+-// Rewrite constant pool references in the methods.
+-bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
+- instanceKlassHandle scratch_class, TRAPS) {
++}
+
+- objArrayHandle methods(THREAD, scratch_class->methods());
++void VM_RedefineClasses::rollback() {
++ RC_TRACE(0x00000001, ("Rolling back redefinition!"));
++ SystemDictionary::rollback_redefinition();
++
++ RC_TRACE(0x00000001, ("After rolling back system dictionary!"));
++ for (int i=0; i<_new_classes->length(); i++) {
++ SystemDictionary::remove_from_hierarchy(_new_classes->at(i));
++ }
+
+- if (methods.is_null() || methods->length() == 0) {
+- // no methods so nothing to do
+- return true;
++ for (int i=0; i<_new_classes->length(); i++) {
++ instanceKlassHandle new_class = _new_classes->at(i);
++ new_class->set_redefining(false);
++ new_class->old_version()->klass_part()->set_new_version(NULL);
++ new_class->set_old_version(NULL);
+ }
+
+- // rewrite constant pool references in the methods:
+- for (int i = methods->length() - 1; i >= 0; i--) {
+- methodHandle method(THREAD, (methodOop)methods->obj_at(i));
+- methodHandle new_method;
+- rewrite_cp_refs_in_method(method, &new_method, CHECK_false);
+- if (!new_method.is_null()) {
+- // the method has been replaced so save the new method version
+- methods->obj_at_put(i, new_method());
++}
++
++template <class T> void VM_RedefineClasses::do_oop_work(T* p) {
++ T heap_oop = oopDesc::load_heap_oop(p);
++ if (!oopDesc::is_null(heap_oop)) {
++ oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
++ if (obj->is_instanceKlass()) {
++ klassOop klass = (klassOop)obj;
++ // DCEVM: note: can overwrite owner of old_klass constants pool with new_klass, so we need to fix it back later
++ if (klass->new_version() != NULL && klass->new_version()->klass_part()->is_redefining()) {
++ obj = klass->klass_part()->new_version();
++ oopDesc::encode_store_heap_oop_not_null(p, obj);
++ }
++ } else if (obj->blueprint()->newest_version() == SystemDictionary::Class_klass()->klass_part()->newest_version()) {
++ // update references to java.lang.Class to point to newest version. Only update references to non-primitive
++ // java.lang.Class instances.
++ klassOop klass_oop = java_lang_Class::as_klassOop(obj);
++ if (klass_oop != NULL) {
++ if (klass_oop->new_version() != NULL && klass_oop->new_version()->klass_part()->is_redefining()) {
++ obj = klass_oop->new_version()->java_mirror();
++ } else if (klass_oop->klass_part()->is_redefining()) {
++ obj = klass_oop->java_mirror();
++ }
++ oopDesc::encode_store_heap_oop_not_null(p, obj);
++
++
++ // FIXME: DCEVM: better implementation?
++ // Starting from JDK 7 java_mirror can be kept in the regular heap. Therefore, it is possible
++ // that new java_mirror is in the young generation whereas p is in tenured generation. In that
++ // case we need to run write barrier to make sure card table is properly updated. This will
++ // allow JVM to detect reference in tenured generation properly during young generation GC.
++ if (Universe::heap()->is_in_reserved(p)) {
++ if (GenCollectedHeap::heap()->is_in_young(obj)) {
++ GenRemSet* rs = GenCollectedHeap::heap()->rem_set();
++ assert(rs->rs_kind() == GenRemSet::CardTable, "Wrong rem set kind.");
++ CardTableRS* _rs = (CardTableRS*)rs;
++ _rs->inline_write_ref_field_gc(p, obj);
++ }
++ }
+ }
}
-+
-+ // Advance to next thread
-+ java_thread = java_thread->next();
}
++}
- return true;
+- return true;
++void VM_RedefineClasses::swap_marks(oop first, oop second) {
++ markOop first_mark = first->mark();
++ markOop second_mark = second->mark();
++ first->set_mark(second_mark);
++ second->set_mark(first_mark);
}
-+bool VM_RedefineClasses::check_method(methodOop method) {
++void VM_RedefineClasses::doit() {
++ Thread *thread = Thread::current();
-// Rewrite constant pool references in the specific method. This code
-// was adapted from Rewriter::rewrite_method().
@@ -7437,39 +7845,17 @@
- // More complicated bytecodes report a length of zero so
- // we have to try again a slightly different way.
- bc_length = Bytecodes::length_at(method(), bcp);
-+
-+ return true;
-+}
-+
-+// Warning: destroys redefinition level values of klasses.
-+bool VM_RedefineClasses::check_loaded_methods() {
-+
-+ class CheckLoadedMethodsClosure : public ObjectClosure {
-+
-+ private:
-+
-+ bool _result;
-+ GrowableArray<klassOop> *_dangerous_klasses;
-+
-+ public:
-+ CheckLoadedMethodsClosure(GrowableArray<klassOop> *dangerous_klasses) {
-+ _result = true;
-+ _dangerous_klasses = dangerous_klasses;
- }
+- }
++ RC_TRACE(0x00000001, ("Entering doit!"));
- assert(bc_length != 0, "impossible bytecode length");
-+ bool result() {
-+ return _result;
-+ }
- switch (c) {
- case Bytecodes::_ldc:
- {
- int cp_index = *(bcp + 1);
- int new_index = find_new_index(cp_index);
-+ bool is_class_dangerous(klassOop k) {
-+ return k->klass_part()->newest_version()->klass_part()->check_redefinition_flag(Klass::RemoveSuperType);
-+ }
++ if ((_max_redefinition_flags & Klass::RemoveSuperType) != 0) {
- if (StressLdcRewrite && new_index == 0) {
- // If we are stressing ldc -> ldc_w rewriting, then we
@@ -7509,78 +7895,9 @@
- m = rc.insert_space_at(bci, 3, inst_buffer, THREAD);
- if (m.is_null() || HAS_PENDING_EXCEPTION) {
- guarantee(false, "insert_space_at() failed");
-+ bool can_be_affected(instanceKlass *klass) {
-+
-+ constantPoolOop cp = klass->constants();
-+
-+ Thread *THREAD = Thread::current();
-+ klassOop k;
-+ Symbol* symbol;
-+
-+ for (int i=1; i<cp->length(); i++) {
-+ jbyte tag = cp->tag_at(i).value();
-+ switch(tag) {
-+ case JVM_CONSTANT_Long:
-+ case JVM_CONSTANT_Double:
-+ i++;
-+ break;
-+
-+ case JVM_CONSTANT_Utf8:
-+ case JVM_CONSTANT_Unicode:
-+ case JVM_CONSTANT_Integer:
-+ case JVM_CONSTANT_Float:
-+ case JVM_CONSTANT_String:
-+ case JVM_CONSTANT_Fieldref:
-+ case JVM_CONSTANT_Methodref:
-+ case JVM_CONSTANT_InterfaceMethodref:
-+ case JVM_CONSTANT_ClassIndex:
-+ case JVM_CONSTANT_UnresolvedString:
-+ case JVM_CONSTANT_StringIndex:
-+ case JVM_CONSTANT_UnresolvedClassInError:
-+ case JVM_CONSTANT_Object:
-+ // do nothing
-+ break;
-+
-+ case JVM_CONSTANT_Class:
-+ k = cp->klass_at(i, CHECK_(true));
-+ if (is_class_dangerous(k)) {
-+ RC_TRACE(0x00000002, ("Class %s is potentially affected, because at cp[%d] references class %s",
-+ klass->name()->as_C_string(),
-+ i,
-+ k->klass_part()->name()->as_C_string()));
-+ return true;
-+ }
-+ break;
-+
-+ case JVM_CONSTANT_NameAndType:
-+ symbol = cp->symbol_at(cp->signature_ref_index_at(i));
-+ if (symbol->byte_at(0) == '(') {
-+ // This must be a method
-+ SignatureStream signatureStream(symbol);
-+ while (true) {
-+
-+ if (signatureStream.is_array()) {
-+ Symbol* cur_signature = signatureStream.as_symbol(Thread::current());
-+ if (is_type_signature_dangerous(cur_signature)) {
-+ return true;
-+ }
-+ } else if (signatureStream.is_object()) {
-+ if (is_symbol_dangerous(signatureStream.as_symbol(Thread::current()))) {
-+ return true;
-+ }
-+ }
-+
-+ if (signatureStream.at_return_type()) {
-+ break;
-+ }
-+
-+ signatureStream.next();
- }
-+
-+ } else if (is_type_signature_dangerous(symbol)) {
-+ return true;
- }
-+ break;
+- }
+- }
++ RC_TIMER_START(_timer_check_type);
- // return the new method so that the caller can update
- // the containing class
@@ -7603,6 +7920,7 @@
- case Bytecodes::_getfield : // fall through
- case Bytecodes::_getstatic : // fall through
- case Bytecodes::_instanceof : // fall through
+- case Bytecodes::_invokedynamic : // fall through
- case Bytecodes::_invokeinterface: // fall through
- case Bytecodes::_invokespecial : // fall through
- case Bytecodes::_invokestatic : // fall through
@@ -7618,153 +7936,52 @@
- int cp_index = Bytes::get_Java_u2(p);
- int new_index = find_new_index(cp_index);
- if (new_index != 0) {
-- // the original index is mapped so update w/ new value
-- RC_TRACE_WITH_THREAD(0x00080000, THREAD,
-- ("%s@" INTPTR_FORMAT " old=%d, new=%d", Bytecodes::name(c),
-- bcp, cp_index, new_index));
-- // Rewriter::rewrite_method() uses put_native_u2() in this
-- // situation because it is reusing the constant pool index
-- // location for a native index into the constantPoolCache.
-- // Since we are updating the constant pool index prior to
-- // verification and constantPoolCache initialization, we
-- // need to keep the new index in Java byte order.
-- Bytes::put_Java_u2(p, new_index);
-- }
-- } break;
-- }
-- } // end for each bytecode
--} // end rewrite_cp_refs_in_method()
--
--
--// Rewrite constant pool references in the class_annotations field.
--bool VM_RedefineClasses::rewrite_cp_refs_in_class_annotations(
-- instanceKlassHandle scratch_class, TRAPS) {
--
-- typeArrayHandle class_annotations(THREAD,
-- scratch_class->class_annotations());
-- if (class_annotations.is_null() || class_annotations->length() == 0) {
-- // no class_annotations so nothing to do
-- return true;
-- }
--
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
-- ("class_annotations length=%d", class_annotations->length()));
--
-- int byte_i = 0; // byte index into class_annotations
-- return rewrite_cp_refs_in_annotations_typeArray(class_annotations, byte_i,
-- THREAD);
-+ case JVM_CONSTANT_UnresolvedClass:
-+ symbol = cp->unresolved_klass_at(i);
-+ if (is_symbol_dangerous(symbol)) {
-+ return true;
-+ }
-+ break;
-+
-+ default:
-+ ShouldNotReachHere();
-+ }
-+ }
-+
-+ return false;
-+ }
-+
-+ bool is_type_signature_dangerous(Symbol* signature) {
-+ // This must be a field type
-+ if (FieldType::is_obj(signature)) {
-+ Symbol* name = signature_to_class_name(signature);
-+ if (is_symbol_dangerous(name)) {
-+ return true;
-+ }
-+ } else if (FieldType::is_array(signature)) {
-+ //jint dimension;
-+ //Symbol* object_key;
-+ FieldArrayInfo fd;
-+ FieldType::get_array_info(signature, fd, Thread::current());
-+ if (is_symbol_dangerous(fd.object_key())) {
-+ return true;
-+ }
-+ }
-+ return false;
-+ }
-+
-+ bool is_symbol_dangerous(Symbol* symbol) {
-+ for (int i=0; i<_dangerous_klasses->length(); i++) {
-+ if(_dangerous_klasses->at(i)->klass_part()->name() == symbol) {
-+ RC_TRACE(0x00000002, ("Found constant pool index %d references class %s",
-+ i,
-+ symbol->as_C_string()));
-+ return true;
-+ }
-+ }
-+ return false;
-+ }
-+
-+ virtual void do_object(oop obj) {
-+
-+ if (!_result) return;
-+
-+ klassOop klassObj = (klassOop)obj;
-+ Thread *THREAD = Thread::current();
-+
-+ // We found an instance klass!
-+ instanceKlass *klass = instanceKlass::cast(klassObj);
-+ instanceKlassHandle handle(klassObj);
-+
-+ RC_TRACE(0x00000400, ("Check if verification is necessary for class %s major_version=%d", handle->name()->as_C_string(), handle->major_version()));
-+
-+ if (!can_be_affected(klass)) {
-+ RC_TRACE(0x00000400, ("Skipping verification of class %s major_version=%d", handle->name()->as_C_string(), handle->major_version()));
-+ return;
-+ }
-+
-+ if (handle->major_version() < Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION) {
-+ RC_TRACE(0x00000001, ("Failing because cannot verify class %s major_version=%d", handle->name()->as_C_string(), handle->major_version()));
-+ _result = false;
-+ return;
-+ }
-+
-+ RC_TRACE(0x00000001, ("Verifying class %s", handle->name()->as_C_string()));
-+
-+ if (!Verifier::verify(handle, Verifier::NoException, true, false, Thread::current())) {
-+
-+ RC_TRACE(0x00000001, ("Verification of class %s failed", handle->name()->as_C_string()));
-+ //Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
-+ //RC_TRACE(0x00000002, ("exception when verifying class: '%s'", ex_name->as_C_string());
-+ //PENDING_EXCEPTION->print();
-+ CLEAR_PENDING_EXCEPTION;
-+ _result = false;
-+ }
-+
-+ /*int method_count = klass->methods()->length();
-+ for (int i=0; i<method_count; i++) {
-+ methodOop cur_method = (methodOop)klass->methods()->obj_at(i);
-+ if (!check_method(cur_method)) {
-+ RC_TRACE(0x00000001, ("Failed to verify consistency of method %s of klass %s", cur_method->name()->as_C_string(), klass->name()->as_C_string());
-+ }
-+ }*/
-+ }
-+ };
-+
-+ // TODO: Check bytecodes in case of interface => class or class => interface etc..
-+
-+ GrowableArray<klassOop> dangerous_klasses;
-+ for (int i=0; i<_new_classes->length(); i++) {
-+ instanceKlassHandle handle = _new_classes->at(i);
-+ if (handle->check_redefinition_flag(Klass::RemoveSuperType)) {
-+ dangerous_klasses.append(handle());
+- // the original index is mapped so update w/ new value
+- RC_TRACE_WITH_THREAD(0x00080000, THREAD,
+- ("%s@" INTPTR_FORMAT " old=%d, new=%d", Bytecodes::name(c),
+- bcp, cp_index, new_index));
+- // Rewriter::rewrite_method() uses put_native_u2() in this
+- // situation because it is reusing the constant pool index
+- // location for a native index into the constantPoolCache.
+- // Since we are updating the constant pool index prior to
+- // verification and constantPoolCache initialization, we
+- // need to keep the new index in Java byte order.
+- Bytes::put_Java_u2(p, new_index);
+- }
+- } break;
+- }
+- } // end for each bytecode
+-} // end rewrite_cp_refs_in_method()
+-
+-
+-// Rewrite constant pool references in the class_annotations field.
+-bool VM_RedefineClasses::rewrite_cp_refs_in_class_annotations(
+- instanceKlassHandle scratch_class, TRAPS) {
+-
+- typeArrayHandle class_annotations(THREAD,
+- scratch_class->class_annotations());
+- if (class_annotations.is_null() || class_annotations->length() == 0) {
+- // no class_annotations so nothing to do
+- return true;
+- }
+-
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
+- ("class_annotations length=%d", class_annotations->length()));
+-
+- int byte_i = 0; // byte index into class_annotations
+- return rewrite_cp_refs_in_annotations_typeArray(class_annotations, byte_i,
+- THREAD);
+-}
++ if (!check_type_consistency()) {
++ // (tw) TODO: Rollback the class redefinition
++ rollback();
++ RC_TRACE(0x00000001, ("Detected type inconsistency!"));
++ _result = JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED;
++ RC_TIMER_STOP(_timer_check_type);
++ return;
+ }
-+ }
-+
-+ CheckLoadedMethodsClosure checkLoadedMethodsClosure(&dangerous_klasses);
-+ Thread::current()->set_pretend_new_universe(true);
-+ SystemDictionary::classes_do(&checkLoadedMethodsClosure);
-+ Thread::current()->set_pretend_new_universe(false);
-+
-+
-+ return checkLoadedMethodsClosure.result();
- }
-+bool VM_RedefineClasses::check_type_consistency() {
++ RC_TIMER_STOP(_timer_check_type);
-// Rewrite constant pool references in an annotations typeArray. This
-// "structure" is adapted from the RuntimeVisibleAnnotations_attribute
@@ -7777,19 +7994,18 @@
-//
-bool VM_RedefineClasses::rewrite_cp_refs_in_annotations_typeArray(
- typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) {
-+ Universe::set_verify_in_progress(true);
++ } else {
++ RC_TRACE(0x00000001, ("No type narrowing => skipping check for type inconsistency"));
++ }
- if ((byte_i_ref + 2) > annotations_typeArray->length()) {
- // not enough room for num_annotations field
- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
- ("length() is too small for num_annotations field"));
-+ SystemDictionary::classes_do(calculate_type_check_information);
-+ bool result = check_field_value_types();
-+ SystemDictionary::classes_do(clear_type_check_information);
-+ if (!result) {
-+ RC_TRACE(0x00000001, ("Aborting redefinition because of wrong field or array element value!"));
-+ Universe::set_verify_in_progress(false);
- return false;
+- return false;
++ if (UseMethodForwardPoints) {
++ RC_TRACE(0x00000001, ("Check stack for forwarding methods to new version"));
++ method_forwarding();
}
- u2 num_annotations = Bytes::get_Java_u2((address)
@@ -7807,37 +8023,23 @@
- ("bad annotation_struct at %d", calc_num_annotations));
- // propagate failure back to caller
- return false;
-- }
-+ result = check_method_stacks();
-+ if (!result) {
-+ RC_TRACE(0x00000001, ("Aborting redefinition because of wrong value on the stack"));
-+ Universe::set_verify_in_progress(false);
-+ return false;
-+ }
-+
-+ result = check_loaded_methods();
-+ if (!result) {
-+ RC_TRACE(0x00000001, ("Aborting redefinition because of wrong loaded method"));
-+ Universe::set_verify_in_progress(false);
-+ return false;
++ if (UseSharedSpaces) {
++ // Sharing is enabled so we remap the shared readonly space to
++ // shared readwrite, private just in case we need to redefine
++ // a shared class. We do the remap during the doit() phase of
++ // the safepoint to be safer.
++ if (!CompactingPermGenGen::remap_shared_readonly_as_readwrite()) {
++ RC_TRACE(0x00000001, ("failed to remap shared readonly space to readwrite, private"));
++ _result = JVMTI_ERROR_INTERNAL;
++ return;
+ }
}
- assert(num_annotations == calc_num_annotations, "sanity check");
-+ RC_TRACE(0x00000001, ("Verification passed => hierarchy change is valid!"));
-+ Universe::set_verify_in_progress(false);
- return true;
+- return true;
-} // end rewrite_cp_refs_in_annotations_typeArray()
-+}
-
-+void VM_RedefineClasses::rollback() {
-+ RC_TRACE(0x00000001, ("Rolling back redefinition!"));
-+ SystemDictionary::rollback_redefinition();
-+
-+ RC_TRACE(0x00000001, ("After rolling back system dictionary!"));
-+ for (int i=0; i<_new_classes->length(); i++) {
-+ SystemDictionary::remove_from_hierarchy(_new_classes->at(i));
-+ }
-
+-
+-
-// Rewrite constant pool references in the annotation struct portion of
-// an annotations_typeArray. This "structure" is from section 4.8.15 of
-// the 2nd-edition of the VM spec:
@@ -7858,17 +8060,14 @@
- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
- ("length() is too small for annotation_struct"));
- return false;
-+ for (int i=0; i<_new_classes->length(); i++) {
-+ instanceKlassHandle new_class = _new_classes->at(i);
-+ new_class->set_redefining(false);
-+ new_class->old_version()->klass_part()->set_new_version(NULL);
-+ new_class->set_old_version(NULL);
++ RC_TIMER_START(_timer_prepare_redefinition);
++ for (int i = 0; i < _new_classes->length(); i++) {
++ redefine_single_class(_new_classes->at(i), thread);
}
- u2 type_index = rewrite_cp_ref_in_annotation_data(annotations_typeArray,
- byte_i_ref, "mapped old type_index=%d", THREAD);
-+}
-
+-
- u2 num_element_value_pairs = Bytes::get_Java_u2((address)
- annotations_typeArray->byte_at_addr(
- byte_i_ref));
@@ -7887,47 +8086,9 @@
- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
- ("length() is too small for element_name_index"));
- return false;
-+template <class T> void VM_RedefineClasses::do_oop_work(T* p) {
-+ T heap_oop = oopDesc::load_heap_oop(p);
-+ if (!oopDesc::is_null(heap_oop)) {
-+ oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
-+ if (obj->is_instanceKlass()) {
-+ klassOop klass = (klassOop)obj;
-+ // DCEVM: note: can overwrite owner of old_klass constants pool with new_klass, so we need to fix it back later
-+ if (klass->new_version() != NULL && klass->new_version()->klass_part()->is_redefining()) {
-+ obj = klass->klass_part()->new_version();
-+ oopDesc::encode_store_heap_oop_not_null(p, obj);
-+ }
-+ } else if (obj->blueprint()->newest_version() == SystemDictionary::Class_klass()->klass_part()->newest_version()) {
-+ // update references to java.lang.Class to point to newest version. Only update references to non-primitive
-+ // java.lang.Class instances.
-+ klassOop klass_oop = java_lang_Class::as_klassOop(obj);
-+ if (klass_oop != NULL) {
-+ if (klass_oop->new_version() != NULL && klass_oop->new_version()->klass_part()->is_redefining()) {
-+ obj = klass_oop->new_version()->java_mirror();
-+ } else if (klass_oop->klass_part()->is_redefining()) {
-+ obj = klass_oop->java_mirror();
-+ }
-+ oopDesc::encode_store_heap_oop_not_null(p, obj);
-+
-+
-+ // FIXME: DCEVM: better implementation?
-+ // Starting from JDK 7 java_mirror can be kept in the regular heap. Therefore, it is possible
-+ // that new java_mirror is in the young generation whereas p is in tenured generation. In that
-+ // case we need to run write barrier to make sure card table is properly updated. This will
-+ // allow JVM to detect reference in tenured generation properly during young generation GC.
-+ if (Universe::heap()->is_in_reserved(p)) {
-+ if (GenCollectedHeap::heap()->is_in_young(obj)) {
-+ GenRemSet* rs = GenCollectedHeap::heap()->rem_set();
-+ assert(rs->rs_kind() == GenRemSet::CardTable, "Wrong rem set kind.");
-+ CardTableRS* _rs = (CardTableRS*)rs;
-+ _rs->inline_write_ref_field_gc(p, obj);
-+ }
-+ }
-+ }
- }
-+ }
-+}
+- }
++ // Deoptimize all compiled code that depends on this class
++ flush_dependent_code(instanceKlassHandle(Thread::current(), (klassOop)NULL), Thread::current());
- u2 element_name_index = rewrite_cp_ref_in_annotation_data(
- annotations_typeArray, byte_i_ref,
@@ -7946,19 +8107,19 @@
- } // end for each component
- assert(num_element_value_pairs == calc_num_element_value_pairs,
- "sanity check");
-+void VM_RedefineClasses::swap_marks(oop first, oop second) {
-+ markOop first_mark = first->mark();
-+ markOop second_mark = second->mark();
-+ first->set_mark(second_mark);
-+ second->set_mark(first_mark);
-+}
++ // Adjust constantpool caches and vtables for all classes
++ // that reference methods of the evolved class.
++ SystemDictionary::classes_do(adjust_cpool_cache, Thread::current());
- return true;
-} // end rewrite_cp_refs_in_annotation_struct()
-+void VM_RedefineClasses::doit() {
-+ Thread *thread = Thread::current();
++ RC_TIMER_STOP(_timer_prepare_redefinition);
++ RC_TIMER_START(_timer_redefinition);
-+ RC_TRACE(0x00000001, ("Entering doit!"));
++ class ChangePointersOopClosure : public OopClosure {
++ virtual void do_oop(oop* o) {
++ do_oop_work(o);
++ }
-// Rewrite a constant pool reference at the current position in
-// annotations_typeArray if needed. Returns the original constant
@@ -7980,8 +8141,12 @@
- byte_i_ref += 2;
- return old_cp_index;
-}
++ virtual void do_oop(narrowOop* o) {
++ do_oop_work(o);
++ }
++ };
-+ if ((_max_redefinition_flags & Klass::RemoveSuperType) != 0) {
++ class ChangePointersObjectClosure : public ObjectClosure {
-// Rewrite constant pool references in the element_value portion of an
-// annotations_typeArray. This "structure" is from section 4.8.15.1 of
@@ -8006,27 +8171,17 @@
-//
-bool VM_RedefineClasses::rewrite_cp_refs_in_element_value(
- typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) {
-+ RC_TIMER_START(_timer_check_type);
++ private:
- if ((byte_i_ref + 1) > annotations_typeArray->length()) {
- // not enough room for a tag let alone the rest of an element_value
- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
- ("length() is too small for a tag"));
- return false;
-+ if (!check_type_consistency()) {
-+ // (tw) TODO: Rollback the class redefinition
-+ rollback();
-+ RC_TRACE(0x00000001, ("Detected type inconsistency!"));
-+ _result = JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED;
-+ RC_TIMER_STOP(_timer_check_type);
-+ return;
-+ }
-+
-+ RC_TIMER_STOP(_timer_check_type);
-+
-+ } else {
-+ RC_TRACE(0x00000001, ("No type narrowing => skipping check for type inconsistency"));
- }
+- }
++ OopClosure *_closure;
++ bool _needs_instance_update;
++ GrowableArray<oop> *_updated_oops;
- u1 tag = annotations_typeArray->byte_at(byte_i_ref);
- byte_i_ref++;
@@ -8049,88 +8204,68 @@
- {
- // For the above tag values (including the BaseType values),
- // value.const_value_index is right union field.
-+ if (UseMethodForwardPoints) {
-+ RC_TRACE(0x00000001, ("Check stack for forwarding methods to new version"));
-+ method_forwarding();
-+ }
++ public:
++ ChangePointersObjectClosure(OopClosure *closure) : _closure(closure), _needs_instance_update(false), _updated_oops(NULL) {}
- if ((byte_i_ref + 2) > annotations_typeArray->length()) {
- // not enough room for a const_value_index
- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
- ("length() is too small for a const_value_index"));
- return false;
-- }
-+ if (UseSharedSpaces) {
-+ // Sharing is enabled so we remap the shared readonly space to
-+ // shared readwrite, private just in case we need to redefine
-+ // a shared class. We do the remap during the doit() phase of
-+ // the safepoint to be safer.
-+ if (!CompactingPermGenGen::remap_shared_readonly_as_readwrite()) {
-+ RC_TRACE(0x00000001, ("failed to remap shared readonly space to readwrite, private"));
-+ _result = JVMTI_ERROR_INTERNAL;
-+ return;
-+ }
-+ }
++ bool needs_instance_update() {
++ return _needs_instance_update;
+ }
- u2 const_value_index = rewrite_cp_ref_in_annotation_data(
- annotations_typeArray, byte_i_ref,
- "mapped old const_value_index=%d", THREAD);
-+ RC_TIMER_START(_timer_prepare_redefinition);
-+ for (int i = 0; i < _new_classes->length(); i++) {
-+ redefine_single_class(_new_classes->at(i), thread);
-+ }
-
+-
- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
- ("const_value_index=%d", const_value_index));
- } break;
-+ // Deoptimize all compiled code that depends on this class
-+ flush_dependent_code(instanceKlassHandle(Thread::current(), (klassOop)NULL), Thread::current());
++ GrowableArray<oop> *updated_oops() { return _updated_oops; }
- case 'e':
- {
- // for the above tag value, value.enum_const_value is right union field
-+ // Adjust constantpool caches and vtables for all classes
-+ // that reference methods of the evolved class.
-+ SystemDictionary::classes_do(adjust_cpool_cache, Thread::current());
-+
-+ RC_TIMER_STOP(_timer_prepare_redefinition);
-+ RC_TIMER_START(_timer_redefinition);
-
+-
- if ((byte_i_ref + 4) > annotations_typeArray->length()) {
-- // not enough room for a enum_const_value
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
-- ("length() is too small for a enum_const_value"));
-- return false;
-+ class ChangePointersOopClosure : public OopClosure {
-+ virtual void do_oop(oop* o) {
-+ do_oop_work(o);
- }
-
+- // not enough room for a enum_const_value
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
+- ("length() is too small for a enum_const_value"));
+- return false;
+- }
+-
- u2 type_name_index = rewrite_cp_ref_in_annotation_data(
- annotations_typeArray, byte_i_ref,
- "mapped old type_name_index=%d", THREAD);
-+ virtual void do_oop(narrowOop* o) {
-+ do_oop_work(o);
-+ }
-+ };
++ virtual void do_object(oop obj) {
++ if (!obj->is_instanceKlass()) {
++ obj->oop_iterate(_closure);
++
++ if (obj->blueprint()->is_redefining()) {
- u2 const_name_index = rewrite_cp_ref_in_annotation_data(
- annotations_typeArray, byte_i_ref,
- "mapped old const_name_index=%d", THREAD);
-+ class ChangePointersObjectClosure : public ObjectClosure {
++ if (obj->blueprint()->check_redefinition_flag(Klass::HasInstanceTransformer)) {
++ if (_updated_oops == NULL) {
++ _updated_oops = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<oop>(100, true);
++ }
++ _updated_oops->append(obj);
++ }
- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
- ("type_name_index=%d const_name_index=%d", type_name_index,
- const_name_index));
- } break;
-+ private:
++ if(obj->blueprint()->update_information() != NULL || obj->is_perm()) {
- case 'c':
- {
- // for the above tag value, value.class_info_index is right union field
-+ OopClosure *_closure;
-+ bool _needs_instance_update;
-+ GrowableArray<oop> *_updated_oops;
++ assert(obj->blueprint()->old_version() != NULL, "must have old version");
++ obj->set_klass_no_check(obj->blueprint()->old_version());
- if ((byte_i_ref + 2) > annotations_typeArray->length()) {
- // not enough room for a class_info_index
@@ -8156,8 +8291,16 @@
- return false;
- }
- break;
-+ public:
-+ ChangePointersObjectClosure(OopClosure *closure) : _closure(closure), _needs_instance_update(false), _updated_oops(NULL) {}
++ if (obj->size() != obj->size_given_klass(obj->blueprint()->new_version()->klass_part()) || obj->is_perm()) {
++ // We need an instance update => set back to old klass
++ _needs_instance_update = true;
++
++ } else {
++ MarkSweep::update_fields(obj, obj);
++ assert(obj->blueprint()->is_redefining(), "update fields resets the klass");
++ }
++ }
++ }
- case '[':
- {
@@ -8183,59 +8326,6 @@
- ("bad nested element_value at %d", calc_num_values));
- // propagate failure back to caller
- return false;
-- }
-+ bool needs_instance_update() {
-+ return _needs_instance_update;
- }
-- assert(num_values == calc_num_values, "sanity check");
-- } break;
-
-- default:
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("bad tag=0x%x", tag));
-- return false;
-- } // end decode tag field
-+ GrowableArray<oop> *updated_oops() { return _updated_oops; }
-
-- return true;
--} // end rewrite_cp_refs_in_element_value()
-+ virtual void do_object(oop obj) {
-+ if (!obj->is_instanceKlass()) {
-+ obj->oop_iterate(_closure);
-+
-+ if (obj->blueprint()->is_redefining()) {
-+
-+ if (obj->blueprint()->check_redefinition_flag(Klass::HasInstanceTransformer)) {
-+ if (_updated_oops == NULL) {
-+ _updated_oops = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<oop>(100, true);
-+ }
-+ _updated_oops->append(obj);
-+ }
-
-+ if(obj->blueprint()->update_information() != NULL || obj->is_perm()) {
-
--// Rewrite constant pool references in a fields_annotations field.
--bool VM_RedefineClasses::rewrite_cp_refs_in_fields_annotations(
-- instanceKlassHandle scratch_class, TRAPS) {
-+ assert(obj->blueprint()->old_version() != NULL, "must have old version");
-+ obj->set_klass_no_check(obj->blueprint()->old_version());
-
-- objArrayHandle fields_annotations(THREAD,
-- scratch_class->fields_annotations());
-+ if (obj->size() != obj->size_given_klass(obj->blueprint()->new_version()->klass_part()) || obj->is_perm()) {
-+ // We need an instance update => set back to old klass
-+ _needs_instance_update = true;
-+
-+ } else {
-+ MarkSweep::update_fields(obj, obj);
-+ assert(obj->blueprint()->is_redefining(), "update fields resets the klass");
-+ }
-+ }
-+ }
-
-- if (fields_annotations.is_null() || fields_annotations->length() == 0) {
-- // no fields_annotations so nothing to do
-- return true;
-- }
+ } else {
+ instanceKlass *klass = instanceKlass::cast((klassOop)obj);
+ if (klass->is_redefining()) {
@@ -8252,51 +8342,46 @@
+ // idubrov: need to check if there is a test to verify that fields referencing class being updated
+ // idubrov: will get new version of that class
+ //klass->iterate_static_fields(_closure);
-+ }
-+ }
+ }
+ }
+- assert(num_values == calc_num_values, "sanity check");
+- } break;
+ };
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
-- ("fields_annotations length=%d", fields_annotations->length()));
+- default:
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("bad tag=0x%x", tag));
+- return false;
+- } // end decode tag field
+ ChangePointersOopClosure oopClosure;
+ ChangePointersObjectClosure objectClosure(&oopClosure);
-- for (int i = 0; i < fields_annotations->length(); i++) {
-- typeArrayHandle field_annotations(THREAD,
-- (typeArrayOop)fields_annotations->obj_at(i));
-- if (field_annotations.is_null() || field_annotations->length() == 0) {
-- // this field does not have any annotations so skip it
-- continue;
+- return true;
+-} // end rewrite_cp_refs_in_element_value()
+ {
+ SharedHeap::heap()->gc_prologue(true);
+ Universe::root_oops_do(&oopClosure);
+ Universe::heap()->object_iterate(&objectClosure);
+ SharedHeap::heap()->gc_epilogue(false);
- }
++ }
-- int byte_i = 0; // byte index into field_annotations
-- if (!rewrite_cp_refs_in_annotations_typeArray(field_annotations, byte_i,
-- THREAD)) {
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
-- ("bad field_annotations at %d", i));
-- // propagate failure back to caller
-- return false;
+ // Swap marks to have same hashcodes
+ for (int i=0; i<_new_classes->length(); i++) {
+ swap_marks(_new_classes->at(i)(), _new_classes->at(i)->old_version());
+ swap_marks(_new_classes->at(i)->java_mirror(), _new_classes->at(i)->old_version()->java_mirror());
- }
-- }
++ }
-- return true;
--} // end rewrite_cp_refs_in_fields_annotations()
+-// Rewrite constant pool references in a fields_annotations field.
+-bool VM_RedefineClasses::rewrite_cp_refs_in_fields_annotations(
+- instanceKlassHandle scratch_class, TRAPS) {
+ _updated_oops = objectClosure.updated_oops();
+- objArrayHandle fields_annotations(THREAD,
+- scratch_class->fields_annotations());
+ if (objectClosure.needs_instance_update()){
--// Rewrite constant pool references in a methods_annotations field.
--bool VM_RedefineClasses::rewrite_cp_refs_in_methods_annotations(
-- instanceKlassHandle scratch_class, TRAPS) {
+- if (fields_annotations.is_null() || fields_annotations->length() == 0) {
+- // no fields_annotations so nothing to do
+- return true;
+ // Do a full garbage collection to update the instance sizes accordingly
+ RC_TRACE(0x00000001, ("Before performing full GC!"));
+ Universe::set_redefining_gc_run(true);
@@ -8306,24 +8391,36 @@
+ notify_gc_end();
+ Universe::set_redefining_gc_run(false);
+ RC_TRACE(0x00000001, ("GC done!"));
-+ }
+ }
-- objArrayHandle methods_annotations(THREAD,
-- scratch_class->methods_annotations());
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
+- ("fields_annotations length=%d", fields_annotations->length()));
+-
+- for (int i = 0; i < fields_annotations->length(); i++) {
+- typeArrayHandle field_annotations(THREAD,
+- (typeArrayOop)fields_annotations->obj_at(i));
+- if (field_annotations.is_null() || field_annotations->length() == 0) {
+- // this field does not have any annotations so skip it
+- continue;
+- }
-- if (methods_annotations.is_null() || methods_annotations->length() == 0) {
-- // no methods_annotations so nothing to do
-- return true;
+- int byte_i = 0; // byte index into field_annotations
+- if (!rewrite_cp_refs_in_annotations_typeArray(field_annotations, byte_i,
+- THREAD)) {
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
+- ("bad field_annotations at %d", i));
+- // propagate failure back to caller
+- return false;
+ if (RC_TRACE_ENABLED(0x00000001)) {
+ if (_updated_oops != NULL) {
+ RC_TRACE(0x00000001, ("%d object(s) updated!", _updated_oops->length()));
+ } else {
+ RC_TRACE(0x00000001, ("No objects updated!"));
-+ }
+ }
}
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
-- ("methods_annotations length=%d", methods_annotations->length()));
+- return true;
+-} // end rewrite_cp_refs_in_fields_annotations()
+ // Unmark klassOops as "redefining"
+ for (int i=0; i<_new_classes->length(); i++) {
+ klassOop cur = _new_classes->at(i)();
@@ -8331,6 +8428,35 @@
+ _new_classes->at(i)->clear_update_information();
+ _new_classes->at(i)->update_supers_to_newest_version();
++ if (((instanceKlass *)cur->klass_part()->old_version()->klass_part())->array_klasses() != NULL) {
++ update_array_classes_to_newest_version(((instanceKlass *)cur->klass_part()->old_version()->klass_part())->array_klasses());
+
+-// Rewrite constant pool references in a methods_annotations field.
+-bool VM_RedefineClasses::rewrite_cp_refs_in_methods_annotations(
+- instanceKlassHandle scratch_class, TRAPS) {
++ // Transfer the array classes, otherwise we might get cast exceptions when casting array types.
++ ((instanceKlass*)cur->klass_part())->set_array_klasses(((instanceKlass*)cur->klass_part()->old_version()->klass_part())->array_klasses());
+
+- objArrayHandle methods_annotations(THREAD,
+- scratch_class->methods_annotations());
++ oop new_mirror = _new_classes->at(i)->java_mirror();
++ oop old_mirror = _new_classes->at(i)->old_version()->java_mirror();
++ java_lang_Class::set_array_klass(new_mirror, java_lang_Class::array_klass(old_mirror));
++ }
++ }
+
+- if (methods_annotations.is_null() || methods_annotations->length() == 0) {
+- // no methods_annotations so nothing to do
+- return true;
++ for (int i=T_BOOLEAN; i<=T_LONG; i++) {
++ update_array_classes_to_newest_version(Universe::typeArrayKlassObj((BasicType)i));
+ }
+
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
+- ("methods_annotations length=%d", methods_annotations->length()));
++ // Disable any dependent concurrent compilations
++ SystemDictionary::notice_modification();
+
- for (int i = 0; i < methods_annotations->length(); i++) {
- typeArrayHandle method_annotations(THREAD,
- (typeArrayOop)methods_annotations->obj_at(i));
@@ -8338,8 +8464,9 @@
- // this method does not have any annotations so skip it
- continue;
- }
-+ if (((instanceKlass *)cur->klass_part()->old_version()->klass_part())->array_klasses() != NULL) {
-+ update_array_classes_to_newest_version(((instanceKlass *)cur->klass_part()->old_version()->klass_part())->array_klasses());
++ // Set flag indicating that some invariants are no longer true.
++ // See jvmtiExport.hpp for detailed explanation.
++ JvmtiExport::set_has_redefined_a_class();
- int byte_i = 0; // byte index into method_annotations
- if (!rewrite_cp_refs_in_annotations_typeArray(method_annotations, byte_i,
@@ -8348,23 +8475,17 @@
- ("bad method_annotations at %d", i));
- // propagate failure back to caller
- return false;
-+ // Transfer the array classes, otherwise we might get cast exceptions when casting array types.
-+ ((instanceKlass*)cur->klass_part())->set_array_klasses(((instanceKlass*)cur->klass_part()->old_version()->klass_part())->array_klasses());
-+
-+ oop new_mirror = _new_classes->at(i)->java_mirror();
-+ oop old_mirror = _new_classes->at(i)->old_version()->java_mirror();
-+ java_lang_Class::set_array_klass(new_mirror, java_lang_Class::array_klass(old_mirror));
- }
- }
+- }
+- }
++ // Clean up caches in the compiler interface and compiler threads
++ CompileBroker::cleanup_after_redefinition();
- return true;
-} // end rewrite_cp_refs_in_methods_annotations()
-+ for (int i=T_BOOLEAN; i<=T_LONG; i++) {
-+ update_array_classes_to_newest_version(Universe::typeArrayKlassObj((BasicType)i));
-+ }
++#ifdef ASSERT
-+ // Disable any dependent concurrent compilations
-+ SystemDictionary::notice_modification();
++ // Universe::verify();
++ // JNIHandles::verify();
-// Rewrite constant pool references in a methods_parameter_annotations
-// field. This "structure" is adapted from the
@@ -8381,14 +8502,13 @@
-//
-bool VM_RedefineClasses::rewrite_cp_refs_in_methods_parameter_annotations(
- instanceKlassHandle scratch_class, TRAPS) {
-+ // Set flag indicating that some invariants are no longer true.
-+ // See jvmtiExport.hpp for detailed explanation.
-+ JvmtiExport::set_has_redefined_a_class();
++ SystemDictionary::classes_do(check_class, thread);
++#endif
- objArrayHandle methods_parameter_annotations(THREAD,
- scratch_class->methods_parameter_annotations());
-+ // Clean up caches in the compiler interface and compiler threads
-+ CompileBroker::cleanup_after_redefinition();
++ update_active_methods();
++ RC_TIMER_STOP(_timer_redefinition);
- if (methods_parameter_annotations.is_null()
- || methods_parameter_annotations->length() == 0) {
@@ -8415,21 +8535,18 @@
- ("length() is too small for a num_parameters field at %d", i));
- return false;
- }
-+#ifdef ASSERT
++}
- int byte_i = 0; // byte index into method_parameter_annotations
-+ // Universe::verify();
-+ // JNIHandles::verify();
++void VM_RedefineClasses::update_array_classes_to_newest_version(klassOop smallest_dimension) {
- u1 num_parameters = method_parameter_annotations->byte_at(byte_i);
- byte_i++;
-+ SystemDictionary::classes_do(check_class, thread);
-+#endif
++ arrayKlass *curArrayKlass = arrayKlass::cast(smallest_dimension);
++ assert(curArrayKlass->lower_dimension() == NULL, "argument must be smallest dimension");
- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
- ("num_parameters=%d", num_parameters));
-+ update_active_methods();
-+ RC_TIMER_STOP(_timer_redefinition);
- int calc_num_parameters = 0;
- for (; calc_num_parameters < num_parameters; calc_num_parameters++) {
@@ -8440,17 +8557,23 @@
- // propagate failure back to caller
- return false;
- }
-- }
-- assert(num_parameters == calc_num_parameters, "sanity check");
-- }
-+}
++ while (curArrayKlass != NULL) {
++ klassOop higher_dimension = curArrayKlass->higher_dimension();
++ klassOop lower_dimension = curArrayKlass->lower_dimension();
++ curArrayKlass->update_supers_to_newest_version();
++
++ curArrayKlass = NULL;
++ if (higher_dimension != NULL) {
++ curArrayKlass = arrayKlass::cast(higher_dimension);
+ }
+- assert(num_parameters == calc_num_parameters, "sanity check");
+ }
- return true;
-} // end rewrite_cp_refs_in_methods_parameter_annotations()
-+void VM_RedefineClasses::update_array_classes_to_newest_version(klassOop smallest_dimension) {
++}
-+ arrayKlass *curArrayKlass = arrayKlass::cast(smallest_dimension);
-+ assert(curArrayKlass->lower_dimension() == NULL, "argument must be smallest dimension");
++void VM_RedefineClasses::doit_epilogue() {
-// Rewrite constant pool references in a methods_default_annotations
-// field. This "structure" is adapted from the AnnotationDefault_attribute
@@ -8462,13 +8585,11 @@
-//
-bool VM_RedefineClasses::rewrite_cp_refs_in_methods_default_annotations(
- instanceKlassHandle scratch_class, TRAPS) {
++ RC_TIMER_START(_timer_vm_op_epilogue);
- objArrayHandle methods_default_annotations(THREAD,
- scratch_class->methods_default_annotations());
-+ while (curArrayKlass != NULL) {
-+ klassOop higher_dimension = curArrayKlass->higher_dimension();
-+ klassOop lower_dimension = curArrayKlass->lower_dimension();
-+ curArrayKlass->update_supers_to_newest_version();
++ unlock_threads();
- if (methods_default_annotations.is_null()
- || methods_default_annotations->length() == 0) {
@@ -8497,16 +8618,16 @@
- ("bad default element_value at %d", i));
- // propagate failure back to caller
- return false;
-+ curArrayKlass = NULL;
-+ if (higher_dimension != NULL) {
-+ curArrayKlass = arrayKlass::cast(higher_dimension);
- }
- }
+- }
+- }
++ ResourceMark mark;
- return true;
-} // end rewrite_cp_refs_in_methods_default_annotations()
--
-+}
++ VM_GC_Operation::doit_epilogue();
++ RC_TRACE(0x00000001, ("GC Operation epilogue finished! "));
+
++ GrowableArray<methodHandle> instanceTransformerMethods;
-// Rewrite constant pool references in the method's stackmap table.
-// These "structures" are adapted from the StackMapTable_attribute that
@@ -8521,12 +8642,23 @@
-//
-void VM_RedefineClasses::rewrite_cp_refs_in_stack_map_table(
- methodHandle method, TRAPS) {
-+void VM_RedefineClasses::doit_epilogue() {
++ // Call static transformers
++ for (int i=0; i<_new_classes->length(); i++) {
++
++ instanceKlassHandle klass = _new_classes->at(i);
- if (!method->has_stackmap_table()) {
- return;
- }
-+ RC_TIMER_START(_timer_vm_op_epilogue);
++ // Transfer init state
++ if (klass->old_version() != NULL) {
++ instanceKlass::ClassState state = instanceKlass::cast(klass->old_version())->init_state();
++ if (state > instanceKlass::linked) {
++ klass->initialize(Thread::current());
++ }
++ }
++
++ // Find instance transformer method
- typeArrayOop stackmap_data = method->stackmap_data();
- address stackmap_p = (address)stackmap_data->byte_at_addr(0);
@@ -8731,7 +8863,7 @@
- case ITEM_UninitializedThis:
- // nothing more to do for the above tag types
- break;
-+ unlock_threads();
++ if (klass->check_redefinition_flag(Klass::HasInstanceTransformer)) {
- // Object_variable_info {
- // u1 tag = ITEM_Object; /* 7 */
@@ -8763,7 +8895,23 @@
- assert(stackmap_p_ref + 2 <= stackmap_end, "no room for offset");
- stackmap_p_ref += 2;
- break;
-+ ResourceMark mark;
++ RC_TRACE(0x00008000, ("Call instance transformer of %s instance", klass->name()->as_C_string()));
++ klassOop cur_klass = klass();
++ while (cur_klass != NULL) {
++ methodOop method = ((instanceKlass*)cur_klass->klass_part())->find_method(vmSymbols::transformer_name(), vmSymbols::void_method_signature());
++ if (method != NULL) {
++ methodHandle instanceTransformerMethod(method);
++ instanceTransformerMethods.append(instanceTransformerMethod);
++ break;
++ } else {
++ cur_klass = cur_klass->klass_part()->super();
++ }
++ }
++ assert(cur_klass != NULL, "must have instance transformer method");
++ } else {
++ instanceTransformerMethods.append(methodHandle(Thread::current(), NULL));
++ }
++ }
- default:
- RC_TRACE_WITH_THREAD(0x04000000, THREAD,
@@ -8772,10 +8920,9 @@
- break;
- } // end switch (tag)
-} // end rewrite_cp_refs_in_verification_type_info()
-+ VM_GC_Operation::doit_epilogue();
-+ RC_TRACE(0x00000001, ("GC Operation epilogue finished! "));
-+ GrowableArray<methodHandle> instanceTransformerMethods;
++ // Call instance transformers
++ if (_updated_oops != NULL) {
-// Change the constant pool associated with klass scratch_class to
-// scratch_cp. If shrink is true, then scratch_cp_length elements
@@ -8783,30 +8930,30 @@
-// smaller constant pool is associated with scratch_class.
-void VM_RedefineClasses::set_new_constant_pool(
- instanceKlassHandle scratch_class, constantPoolHandle scratch_cp,
-- int scratch_cp_length, bool shrink, TRAPS) {
-- assert(!shrink || scratch_cp->length() >= scratch_cp_length, "sanity check");
--
-- if (shrink) {
-- // scratch_cp is a merged constant pool and has enough space for a
-- // worst case merge situation. We want to associate the minimum
-- // sized constant pool with the klass to save space.
-- constantPoolHandle smaller_cp(THREAD,
-- oopFactory::new_constantPool(scratch_cp_length,
-- oopDesc::IsUnsafeConc,
-- THREAD));
-- // preserve orig_length() value in the smaller copy
-- int orig_length = scratch_cp->orig_length();
-- assert(orig_length != 0, "sanity check");
-- smaller_cp->set_orig_length(orig_length);
-- scratch_cp->copy_cp_to(1, scratch_cp_length - 1, smaller_cp, 1, THREAD);
-- scratch_cp = smaller_cp;
-- smaller_cp()->set_is_conc_safe(true);
-- }
--
-- // attach new constant pool to klass
-- scratch_cp->set_pool_holder(scratch_class());
+- int scratch_cp_length, TRAPS) {
+- assert(scratch_cp->length() >= scratch_cp_length, "sanity check");
+-
+- // scratch_cp is a merged constant pool and has enough space for a
+- // worst case merge situation. We want to associate the minimum
+- // sized constant pool with the klass to save space.
+- constantPoolHandle smaller_cp(THREAD,
+- oopFactory::new_constantPool(scratch_cp_length,
+- oopDesc::IsUnsafeConc,
+- THREAD));
+- // preserve orig_length() value in the smaller copy
+- int orig_length = scratch_cp->orig_length();
+- assert(orig_length != 0, "sanity check");
+- smaller_cp->set_orig_length(orig_length);
-
- // attach klass to new constant pool
+- // reference to the cp holder is needed for copy_operands()
+- smaller_cp->set_pool_holder(scratch_class());
+-
+- scratch_cp->copy_cp_to(1, scratch_cp_length - 1, smaller_cp, 1, THREAD);
+- scratch_cp = smaller_cp;
+- smaller_cp()->set_is_conc_safe(true);
+-
+- // attach new constant pool to klass
- scratch_class->set_constants(scratch_cp());
-
- int i; // for portability
@@ -8977,20 +9124,12 @@
- } // end for each method
- assert(scratch_cp()->is_conc_safe(), "Just checking");
-} // end set_new_constant_pool()
-+ // Call static transformers
-+ for (int i=0; i<_new_classes->length(); i++) {
-+
-+ instanceKlassHandle klass = _new_classes->at(i);
++ for (int i=0; i<_updated_oops->length(); i++) {
++ assert(_updated_oops->at(i) != NULL, "must not be null!");
++ Handle cur(_updated_oops->at(i));
++ instanceKlassHandle klass(cur->klass());
-+ // Transfer init state
-+ if (klass->old_version() != NULL) {
-+ instanceKlass::ClassState state = instanceKlass::cast(klass->old_version())->init_state();
-+ if (state > instanceKlass::linked) {
-+ klass->initialize(Thread::current());
-+ }
-+ }
-+
-+ // Find instance transformer method
++ if (klass->check_redefinition_flag(Klass::HasInstanceTransformer)) {
-// Unevolving classes may point to methods of the_class directly
-// from their constant pool caches, itables, and/or vtables. We
@@ -9005,7 +9144,7 @@
- if (k->oop_is_instance()) {
- HandleMark hm(THREAD);
- instanceKlass *ik = (instanceKlass *) k;
-+ if (klass->check_redefinition_flag(Klass::HasInstanceTransformer)) {
++ methodHandle method = instanceTransformerMethods.at(klass->redefinition_index());
- // HotSpot specific optimization! HotSpot does not currently
- // support delegation from the bootstrap class loader to a
@@ -9023,23 +9162,16 @@
- instanceKlass::cast(_the_class_oop)->class_loader() != NULL;
- if (is_user_defined && ik->class_loader() == NULL) {
- return;
-+ RC_TRACE(0x00008000, ("Call instance transformer of %s instance", klass->name()->as_C_string()));
-+ klassOop cur_klass = klass();
-+ while (cur_klass != NULL) {
-+ methodOop method = ((instanceKlass*)cur_klass->klass_part())->find_method(vmSymbols::transformer_name(), vmSymbols::void_method_signature());
-+ if (method != NULL) {
-+ methodHandle instanceTransformerMethod(method);
-+ instanceTransformerMethods.append(instanceTransformerMethod);
-+ break;
-+ } else {
-+ cur_klass = cur_klass->klass_part()->super();
-+ }
-+ }
-+ assert(cur_klass != NULL, "must have instance transformer method");
-+ } else {
-+ instanceTransformerMethods.append(methodHandle(Thread::current(), NULL));
- }
-+ }
+- }
++ RC_TRACE(0x00008000, ("executing transformer method"));
++
++ Thread *__the_thread__ = Thread::current();
++ JavaValue result(T_VOID);
++ JavaCallArguments args(cur);
++ JavaCalls::call(&result,
++ method,
++ &args,
++ THREAD);
- // This is a very busy routine. We don't want too much tracing
- // printed out.
@@ -9064,7 +9196,15 @@
- _matching_new_methods,
- _matching_methods_length,
- &trace_name_printed);
-- }
++ // TODO: What to do with an exception here?
++ if (HAS_PENDING_EXCEPTION) {
++ Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
++ RC_TRACE(0x00000002, ("exception when executing transformer: '%s'",
++ ex_name->as_C_string()));
++ CLEAR_PENDING_EXCEPTION;
++ }
++ }
+ }
- // If the current class has an itable and we are either redefining an
- // interface or if the current class is a subclass of the_class, then
@@ -9097,8 +9237,9 @@
- // that case.
- constantPoolHandle other_cp;
- constantPoolCacheOop cp_cache;
-+ // Call instance transformers
-+ if (_updated_oops != NULL) {
++ delete _updated_oops;
++ _updated_oops = NULL;
++ }
- if (k_oop != _the_class_oop) {
- // this klass' constant pool cache may need adjustment
@@ -9109,34 +9250,8 @@
- _matching_new_methods,
- _matching_methods_length,
- &trace_name_printed);
-+ for (int i=0; i<_updated_oops->length(); i++) {
-+ assert(_updated_oops->at(i) != NULL, "must not be null!");
-+ Handle cur(_updated_oops->at(i));
-+ instanceKlassHandle klass(cur->klass());
-+
-+ if (klass->check_redefinition_flag(Klass::HasInstanceTransformer)) {
-+
-+ methodHandle method = instanceTransformerMethods.at(klass->redefinition_index());
-+
-+ RC_TRACE(0x00008000, ("executing transformer method"));
-+
-+ Thread *__the_thread__ = Thread::current();
-+ JavaValue result(T_VOID);
-+ JavaCallArguments args(cur);
-+ JavaCalls::call(&result,
-+ method,
-+ &args,
-+ THREAD);
-+
-+ // TODO: What to do with an exception here?
-+ if (HAS_PENDING_EXCEPTION) {
-+ Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
-+ RC_TRACE(0x00000002, ("exception when executing transformer: '%s'",
-+ ex_name->as_C_string()));
-+ CLEAR_PENDING_EXCEPTION;
-+ }
- }
- }
+- }
+- }
- {
- ResourceMark rm(THREAD);
- // PreviousVersionInfo objects returned via PreviousVersionWalker
@@ -9159,17 +9274,25 @@
- }
- } // pvw is cleaned up
- } // rm is cleaned up
-+
-+ delete _updated_oops;
-+ _updated_oops = NULL;
- }
-+
+ // Free the array of scratch classes
+ delete _new_classes;
+ _new_classes = NULL;
+ RC_TRACE(0x00000001, ("Redefinition finished!"));
+
+ RC_TIMER_STOP(_timer_vm_op_epilogue);
++}
++
++bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) {
++ // classes for primitives cannot be redefined
++ if (java_lang_Class::is_primitive(klass_mirror)) {
++ return false;
++ }
++ klassOop the_class_oop = java_lang_Class::as_klassOop(klass_mirror);
++ // classes for arrays cannot be redefined
++ if (the_class_oop == NULL || !Klass::cast(the_class_oop)->oop_is_instance()) {
++ return false;
+ }
++ return true;
}
-void VM_RedefineClasses::update_jmethod_ids() {
@@ -9183,17 +9306,16 @@
- assert(JNIHandles::resolve_jmethod_id(jmid) == _matching_new_methods[j],
- "should be replaced");
- }
-+bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) {
-+ // classes for primitives cannot be redefined
-+ if (java_lang_Class::is_primitive(klass_mirror)) {
-+ return false;
++#ifdef ASSERT
++
++void VM_RedefineClasses::verify_classes(klassOop k_oop_latest, oop initiating_loader, TRAPS) {
++ klassOop k_oop = k_oop_latest;
++ while (k_oop != NULL) {
++
++ instanceKlassHandle k_handle(THREAD, k_oop);
++ Verifier::verify(k_handle, Verifier::ThrowException, true, true, THREAD);
++ k_oop = k_oop->klass_part()->old_version();
}
-+ klassOop the_class_oop = java_lang_Class::as_klassOop(klass_mirror);
-+ // classes for arrays cannot be redefined
-+ if (the_class_oop == NULL || !Klass::cast(the_class_oop)->oop_is_instance()) {
-+ return false;
-+ }
-+ return true;
}
-void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
@@ -9289,7 +9411,7 @@
- // mark obsolete methods as such
- old_method->set_is_obsolete();
- obsolete_count++;
-+#ifdef ASSERT
++#endif
- // obsolete methods need a unique idnum
- u2 num = instanceKlass::cast(_the_class_oop)->next_method_idnum();
@@ -9297,31 +9419,6 @@
-// u2 old_num = old_method->method_idnum();
- old_method->set_method_idnum(num);
-// TO DO: attach obsolete annotations to obsolete method's new idnum
-- }
-- // With tracing we try not to "yack" too much. The position of
-- // this trace assumes there are fewer obsolete methods than
-- // EMCP methods.
-- RC_TRACE(0x00000100, ("mark %s(%s) as obsolete",
-- old_method->name()->as_C_string(),
-- old_method->signature()->as_C_string()));
-- }
-- old_method->set_is_old();
-+void VM_RedefineClasses::verify_classes(klassOop k_oop_latest, oop initiating_loader, TRAPS) {
-+ klassOop k_oop = k_oop_latest;
-+ while (k_oop != NULL) {
-+
-+ instanceKlassHandle k_handle(THREAD, k_oop);
-+ Verifier::verify(k_handle, Verifier::ThrowException, true, true, THREAD);
-+ k_oop = k_oop->klass_part()->old_version();
- }
-- for (int i = 0; i < _deleted_methods_length; ++i) {
-- methodOop old_method = _deleted_methods[i];
-+}
-
-- assert(old_method->vtable_index() < 0,
-- "cannot delete methods with vtable entries");;
-+#endif
-+
+// Rewrite faster byte-codes back to their slower equivalent. Undoes rewriting happening in templateTable_xxx.cpp
+// The reason is that once we zero cpool caches, we need to re-resolve all entries again. Faster bytecodes do not
+// do that, they assume that cache entry is resolved already.
@@ -9351,8 +9448,21 @@
+ java_code == Bytecodes::_putfield ||
+ java_code == Bytecodes::_aload_0)) {
+ *bcp = java_code;
-+ }
-+ }
+ }
+- // With tracing we try not to "yack" too much. The position of
+- // this trace assumes there are fewer obsolete methods than
+- // EMCP methods.
+- RC_TRACE(0x00000100, ("mark %s(%s) as obsolete",
+- old_method->name()->as_C_string(),
+- old_method->signature()->as_C_string()));
+ }
+- old_method->set_is_old();
+- }
+- for (int i = 0; i < _deleted_methods_length; ++i) {
+- methodOop old_method = _deleted_methods[i];
+-
+- assert(old_method->vtable_index() < 0,
+- "cannot delete methods with vtable entries");;
- // Mark all deleted methods as old and obsolete
- old_method->set_is_old();
@@ -9598,7 +9708,7 @@
// Deoptimize all compiled code that depends on this class.
//
// If the can_redefine_classes capability is obtained in the onload
-@@ -2964,7 +2677,10 @@
+@@ -3101,7 +2677,10 @@
// All dependencies have been recorded from startup or this is a second or
// subsequent use of RedefineClasses
@@ -9610,7 +9720,7 @@
Universe::flush_evol_dependents_on(k_h);
} else {
CodeCache::mark_all_nmethods_for_deoptimization();
-@@ -2987,10 +2703,10 @@
+@@ -3124,10 +2703,10 @@
methodOop old_method;
methodOop new_method;
@@ -9625,7 +9735,7 @@
_matching_methods_length = 0;
_deleted_methods_length = 0;
-@@ -3005,36 +2721,36 @@
+@@ -3142,36 +2721,36 @@
}
// New method at the end
new_method = (methodOop) _new_methods->obj_at(nj);
@@ -9669,7 +9779,7 @@
++oj;
}
}
-@@ -3042,6 +2758,8 @@
+@@ -3179,6 +2758,8 @@
}
assert(_matching_methods_length + _deleted_methods_length == _old_methods->length(), "sanity");
assert(_matching_methods_length + _added_methods_length == _new_methods->length(), "sanity");
@@ -9678,7 +9788,7 @@
}
-@@ -3049,287 +2767,184 @@
+@@ -3186,297 +2767,184 @@
// Install the redefinition of a class:
// - house keeping (flushing breakpoints and caches, deoptimizing
// dependent compiled code)
@@ -9979,6 +10089,16 @@
+ assert(the_new_class->old_version() != NULL, "Must not be null");
+ assert(the_new_class->old_version()->klass_part()->new_version() == the_new_class(), "Must equal");
+- // JSR-292 support
+- MemberNameTable* mnt = the_class->member_names();
+- if (mnt != NULL) {
+- bool trace_name_printed = false;
+- mnt->adjust_method_entries(_matching_old_methods,
+- _matching_new_methods,
+- _matching_methods_length,
+- &trace_name_printed);
+- }
+-
- if (the_class->oop_map_cache() != NULL) {
- // Flush references to any obsolete methods from the oop map cache
- // so that obsolete methods are not pinned.
@@ -10111,7 +10231,7 @@
// Increment the classRedefinedCount field in the specific instanceKlass
// and in all direct and indirect subclasses.
-@@ -3338,134 +2953,324 @@
+@@ -3485,134 +2953,324 @@
klassOop class_oop = java_lang_Class::as_klassOop(class_mirror);
int new_count = java_lang_Class::classRedefinedCount(class_mirror) + 1;
java_lang_Class::set_classRedefinedCount(class_mirror, new_count);
@@ -10948,10 +11068,17 @@
// The instance fields are used to pass information from
// doit_prologue() to doit() and doit_epilogue().
jint _class_count;
-@@ -370,36 +70,29 @@
+@@ -370,43 +70,29 @@
// _index_map_p contains any entries.
int _index_map_count;
intArray * _index_map_p;
+-
+- // _operands_index_map_count is just an optimization for knowing if
+- // _operands_index_map_p contains any entries.
+- int _operands_cur_length;
+- int _operands_index_map_count;
+- intArray * _operands_index_map_p;
+-
- // ptr to _class_count scratch_classes
- instanceKlassHandle * _scratch_classes;
- jvmtiError _res;
@@ -11002,7 +11129,7 @@
// Figure out which new methods match old methods in name and signature,
// which methods have been added, and which are no longer present
void compute_added_deleted_matching_methods();
-@@ -407,95 +100,100 @@
+@@ -414,103 +100,100 @@
// Change jmethodIDs to point to the new methods
void update_jmethod_ids();
@@ -11044,16 +11171,24 @@
// and in all direct and indirect subclasses.
void increment_class_counter(instanceKlass *ik, TRAPS);
-- // Support for constant pool merging (these routines are in alpha
-- // order):
+- // Support for constant pool merging (these routines are in alpha order):
- void append_entry(constantPoolHandle scratch_cp, int scratch_i,
- constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
+- void append_operand(constantPoolHandle scratch_cp, int scratch_bootstrap_spec_index,
+- constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
+- void finalize_operands_merge(constantPoolHandle merge_cp, TRAPS);
+- int find_or_append_indirect_entry(constantPoolHandle scratch_cp, int scratch_i,
+- constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
+- int find_or_append_operand(constantPoolHandle scratch_cp, int scratch_bootstrap_spec_index,
+- constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
- int find_new_index(int old_index);
+- int find_new_operand_index(int old_bootstrap_spec_index);
- bool is_unresolved_class_mismatch(constantPoolHandle cp1, int index1,
- constantPoolHandle cp2, int index2);
- bool is_unresolved_string_mismatch(constantPoolHandle cp1, int index1,
- constantPoolHandle cp2, int index2);
- void map_index(constantPoolHandle scratch_cp, int old_index, int new_index);
+- void map_operand_index(int old_bootstrap_spec_index, int new_bootstrap_spec_index);
- bool merge_constant_pools(constantPoolHandle old_cp,
- constantPoolHandle scratch_cp, constantPoolHandle *merge_cp_p,
- int *merge_cp_length_p, TRAPS);
@@ -11087,7 +11222,7 @@
- address& stackmap_addr_ref, address stackmap_end, u2 frame_i,
- u1 frame_size, TRAPS);
- void set_new_constant_pool(instanceKlassHandle scratch_class,
-- constantPoolHandle scratch_cp, int scratch_cp_length, bool shrink, TRAPS);
+- constantPoolHandle scratch_cp, int scratch_cp_length, TRAPS);
void flush_dependent_code(instanceKlassHandle k_h, TRAPS);
@@ -11252,7 +11387,7 @@
KlassHandle klass (THREAD, SystemDictionary::ClassLoader_klass());
--- a/src/share/vm/runtime/arguments.cpp
+++ b/src/share/vm/runtime/arguments.cpp
-@@ -1792,6 +1792,15 @@
+@@ -1831,6 +1831,15 @@
status = false;
}
@@ -11311,7 +11446,7 @@
ResourceMark res_mark;
--- a/src/share/vm/runtime/frame.cpp
+++ b/src/share/vm/runtime/frame.cpp
-@@ -407,6 +407,12 @@
+@@ -408,6 +408,12 @@
*interpreter_frame_method_addr() = method;
}
@@ -11324,7 +11459,7 @@
void frame::interpreter_frame_set_bcx(intptr_t bcx) {
assert(is_interpreted_frame(), "Not an interpreted frame");
if (ProfileInterpreter) {
-@@ -422,19 +428,27 @@
+@@ -423,19 +429,27 @@
// The bcx was just converted from bci to bcp.
// Convert the mdx in parallel.
methodDataOop mdo = interpreter_frame_method()->method_data();
@@ -11480,7 +11615,7 @@
Monitor* SystemDictionary_lock = NULL;
Mutex* PackageTable_lock = NULL;
Mutex* CompiledIC_lock = NULL;
-@@ -90,6 +91,7 @@
+@@ -91,6 +92,7 @@
Mutex* DirtyCardQ_FL_lock = NULL;
Monitor* DirtyCardQ_CBL_mon = NULL;
Mutex* Shared_DirtyCardQ_lock = NULL;
@@ -11488,7 +11623,7 @@
Mutex* ParGCRareEvent_lock = NULL;
Mutex* EvacFailureStack_lock = NULL;
Mutex* DerivedPointerTableGC_lock = NULL;
-@@ -207,6 +209,7 @@
+@@ -208,6 +210,7 @@
def(HotCardCache_lock , Mutex , special , true );
def(EvacFailureStack_lock , Mutex , nonleaf , true );
}
@@ -11496,7 +11631,7 @@
def(ParGCRareEvent_lock , Mutex , leaf , true );
def(DerivedPointerTableGC_lock , Mutex, leaf, true );
def(CodeCache_lock , Mutex , special, true );
-@@ -281,6 +284,7 @@
+@@ -283,6 +286,7 @@
def(Debug3_lock , Mutex , nonleaf+4, true );
def(CompileThread_lock , Monitor, nonleaf+5, false);
def(PeriodicTask_lock , Monitor, nonleaf+5, true);
diff --git a/debian/patches/series b/debian/patches/series
index 2aa4e5c..bdb102e 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,2 @@
distro-name.patch
-full-jdk7u55-b13.patch
+full-jdk7u60-b09.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/openjdk-7-jre-dcevm.git
More information about the pkg-java-commits
mailing list