--- a/anonk.patch Sun Sep 07 00:42:43 2008 -0700
+++ b/anonk.patch Wed Nov 12 22:22:46 2008 -0800
@@ -48,22 +48,16 @@ diff --git a/src/share/vm/classfile/clas
}
unsigned int hash;
-@@ -301,7 +313,13 @@
- cp->tag_at(class_index).is_utf8(),
- "Invalid constant pool index %u in class file %s",
- class_index, CHECK_(nullHandle));
-- cp->unresolved_klass_at_put(index, cp->symbol_at(class_index));
-+ symbolOop name = cp->symbol_at(class_index);
-+ klassOop wkk = SystemDictionary::find_well_known_klass(name);
-+ if (wkk != NULL) {
-+ cp->klass_at_put(index, wkk); // eagerly resolve
-+ } else {
-+ cp->unresolved_klass_at_put(index, name);
-+ }
- }
- break;
- case JVM_CONSTANT_UnresolvedString :
-@@ -326,16 +344,46 @@
+@@ -245,7 +257,7 @@
+ int klass_ref_index = cp->klass_ref_index_at(index);
+ int name_and_type_ref_index = cp->name_and_type_ref_index_at(index);
+ check_property(valid_cp_range(klass_ref_index, length) &&
+- cp->tag_at(klass_ref_index).is_klass_reference(),
++ is_klass_reference(cp, klass_ref_index),
+ "Invalid constant pool index %u in class file %s",
+ klass_ref_index,
+ CHECK_(nullHandle));
+@@ -326,16 +338,46 @@
} // end of switch
} // end of for
@@ -110,7 +104,7 @@ diff --git a/src/share/vm/classfile/clas
verify_legal_class_name(class_name, CHECK_(nullHandle));
break;
}
-@@ -378,6 +426,73 @@
+@@ -378,6 +420,73 @@
}
@@ -184,7 +178,7 @@ diff --git a/src/share/vm/classfile/clas
class NameSigHash: public ResourceObj {
public:
symbolOop _name; // name
-@@ -448,25 +563,32 @@
+@@ -448,25 +557,32 @@
int index;
for (index = 0; index < length; index++) {
u2 interface_index = cfs->get_u2(CHECK_(nullHandle));
@@ -192,7 +186,7 @@ diff --git a/src/share/vm/classfile/clas
check_property(
valid_cp_range(interface_index, cp->length()) &&
- cp->tag_at(interface_index).is_unresolved_klass(),
-+ cp->tag_at(interface_index).is_klass_reference(),
++ is_klass_reference(cp, interface_index),
"Interface name has bad constant pool index %u in class file %s",
interface_index, CHECK_(nullHandle));
- symbolHandle unresolved_klass (THREAD, cp->klass_name_at(interface_index));
@@ -232,26 +226,62 @@ diff --git a/src/share/vm/classfile/clas
if (!Klass::cast(interf())->is_interface()) {
THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", nullHandle);
-@@ -877,8 +999,7 @@
+@@ -877,8 +993,7 @@
"Illegal exception table handler in class file %s", CHECK_(nullHandle));
if (catch_type_index != 0) {
guarantee_property(valid_cp_range(catch_type_index, cp->length()) &&
- (cp->tag_at(catch_type_index).is_klass() ||
- cp->tag_at(catch_type_index).is_unresolved_klass()),
-+ cp->tag_at(catch_type_index).is_klass_reference(),
++ is_klass_reference(cp, catch_type_index),
"Catch type in exception table has bad constant type in class file %s", CHECK_(nullHandle));
}
}
-@@ -1117,7 +1238,7 @@
+@@ -1117,7 +1232,7 @@
} else if (tag == ITEM_Object) {
u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK);
guarantee_property(valid_cp_range(class_index, cp->length()) &&
- cp->tag_at(class_index).is_unresolved_klass(),
-+ cp->tag_at(class_index).is_klass_reference(),
++ is_klass_reference(cp, class_index),
"Bad class index %u in StackMap in class file %s",
class_index, CHECK);
} else if (tag == ITEM_Uninitialized) {
-@@ -2349,6 +2470,7 @@
+@@ -1183,7 +1298,7 @@
+ checked_exception = cfs->get_u2_fast();
+ check_property(
+ valid_cp_range(checked_exception, cp->length()) &&
+- cp->tag_at(checked_exception).is_klass_reference(),
++ is_klass_reference(cp, checked_exception),
+ "Exception name has bad type at constant pool %u in class file %s",
+ checked_exception, CHECK_NULL);
+ }
+@@ -1918,7 +2033,7 @@
+ check_property(
+ inner_class_info_index == 0 ||
+ (valid_cp_range(inner_class_info_index, cp_size) &&
+- cp->tag_at(inner_class_info_index).is_klass_reference()),
++ is_klass_reference(cp, inner_class_info_index)),
+ "inner_class_info_index %u has bad constant type in class file %s",
+ inner_class_info_index, CHECK_0);
+ // Outer class index
+@@ -1926,7 +2041,7 @@
+ check_property(
+ outer_class_info_index == 0 ||
+ (valid_cp_range(outer_class_info_index, cp_size) &&
+- cp->tag_at(outer_class_info_index).is_klass_reference()),
++ is_klass_reference(cp, outer_class_info_index)),
+ "outer_class_info_index %u has bad constant type in class file %s",
+ outer_class_info_index, CHECK_0);
+ // Inner class name
+@@ -2088,7 +2203,7 @@
+ }
+ // Validate the constant pool indices and types
+ if (!cp->is_within_bounds(class_index) ||
+- !cp->tag_at(class_index).is_klass_reference()) {
++ !is_klass_reference(cp, class_index)) {
+ classfile_parse_error("Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK);
+ }
+ if (method_index != 0 &&
+@@ -2349,6 +2464,7 @@
instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
Handle class_loader,
Handle protection_domain,
@@ -259,7 +289,7 @@ diff --git a/src/share/vm/classfile/clas
symbolHandle& parsed_name,
TRAPS) {
// So that JVMTI can cache class file in the state before retransformable agents
-@@ -2380,6 +2502,7 @@
+@@ -2380,6 +2496,7 @@
}
}
@@ -267,12 +297,12 @@ diff --git a/src/share/vm/classfile/clas
instanceKlassHandle nullHandle;
-@@ -2510,14 +2633,22 @@
+@@ -2510,14 +2627,22 @@
CHECK_(nullHandle));
} else {
check_property(valid_cp_range(super_class_index, cp_size) &&
- cp->tag_at(super_class_index).is_unresolved_klass(),
-+ cp->tag_at(super_class_index).is_klass_reference(),
++ is_klass_reference(cp, super_class_index),
"Invalid superclass index %u in class file %s",
super_class_index,
CHECK_(nullHandle));
@@ -293,7 +323,7 @@ diff --git a/src/share/vm/classfile/clas
"Bad superclass name in class file %s", CHECK_(nullHandle));
}
}
-@@ -2557,7 +2688,7 @@
+@@ -2557,7 +2682,7 @@
objArrayHandle methods_default_annotations(THREAD, methods_default_annotations_oop);
// We check super class after class file is parsed and format is checked
@@ -302,7 +332,7 @@ diff --git a/src/share/vm/classfile/clas
symbolHandle sk (THREAD, cp->klass_name_at(super_class_index));
if (access_flags.is_interface()) {
// Before attempting to resolve the superclass, check for class format
-@@ -2574,6 +2705,9 @@
+@@ -2574,6 +2699,9 @@
CHECK_(nullHandle));
KlassHandle kh (THREAD, k);
super_klass = instanceKlassHandle(THREAD, kh());
@@ -312,7 +342,7 @@ diff --git a/src/share/vm/classfile/clas
if (super_klass->is_interface()) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
-@@ -3000,6 +3134,7 @@
+@@ -3000,6 +3128,7 @@
this_klass->set_method_ordering(method_ordering());
this_klass->set_initial_method_idnum(methods->length());
this_klass->set_name(cp->klass_name_at(this_class_index));
@@ -331,7 +361,7 @@ diff --git a/src/share/vm/classfile/clas
bool _has_finalizer;
bool _has_empty_finalizer;
-@@ -203,6 +204,25 @@
+@@ -203,6 +204,35 @@
char* skip_over_field_name(char* name, bool slash_ok, unsigned int length);
char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS);
@@ -354,10 +384,20 @@ diff --git a/src/share/vm/classfile/clas
+ }
+ void patch_constant_pool(constantPoolHandle cp, int index, Handle patch, TRAPS);
+
++ // Wrapper for constantTag.is_klass_[or_]reference.
++ // In older versions of the VM, klassOops cannot sneak into early phases of
++ // constant pool construction, but in later versions they can.
++ // %%% Let's phase out the old is_klass_reference.
++ bool is_klass_reference(constantPoolHandle cp, int index) {
++ return ((LinkWellKnownClasses || AnonymousClasses)
++ ? cp->tag_at(index).is_klass_or_reference()
++ : cp->tag_at(index).is_klass_reference());
++ }
++
public:
// Constructor
ClassFileParser(ClassFileStream* st) { set_stream(st); }
-@@ -218,6 +238,14 @@
+@@ -218,6 +248,14 @@
Handle class_loader,
Handle protection_domain,
symbolHandle& parsed_name,
@@ -446,22 +486,6 @@ diff --git a/src/share/vm/classfile/syst
TRAPS);
// Resolve from stream (called by jni_DefineClass and JVM_DefineClass)
-@@ -388,9 +398,13 @@
- // Local definition for direct access to the private array:
- #define WK_KLASS(name) _well_known_klasses[SystemDictionary::WK_KLASS_ENUM_NAME(name)]
-
-+ // Return Integer for T_INT, etc.
-+ // Return NULL if t is not a boxable primitive type, such as T_OBJECT or T_ILLEGAL.
- static klassOop box_klass(BasicType t) {
-- assert((uint)t < T_VOID+1, "range check");
-- return check_klass(_box_klasses[t]);
-+ if ((uint)t <= T_VOID)
-+ return _box_klasses[t];
-+ else
-+ return NULL;
- }
- static BasicType box_klass_type(klassOop k); // inverse of box_klass
-
diff --git a/src/share/vm/classfile/verifier.cpp b/src/share/vm/classfile/verifier.cpp
--- a/src/share/vm/classfile/verifier.cpp
+++ b/src/share/vm/classfile/verifier.cpp
@@ -481,7 +505,7 @@ diff --git a/src/share/vm/includeDB_gc_p
diff --git a/src/share/vm/includeDB_gc_parallel b/src/share/vm/includeDB_gc_parallel
--- a/src/share/vm/includeDB_gc_parallel
+++ b/src/share/vm/includeDB_gc_parallel
-@@ -25,6 +25,12 @@
+@@ -29,6 +29,12 @@
collectorPolicy.cpp cmsGCAdaptivePolicyCounters.hpp
compiledICHolderKlass.cpp oop.pcgc.inline.hpp
@@ -550,16 +574,20 @@ diff --git a/src/share/vm/oops/constantP
// Temp. remove cache so we can do lookups with original indicies.
constantPoolCacheHandle cache (THREAD, cp->cache());
-@@ -302,7 +330,7 @@
+@@ -302,7 +330,11 @@
break;
case JVM_CONSTANT_UnresolvedString :
case JVM_CONSTANT_String :
- anObj = cp->string_at(index, CATCH);
-+ anObj = cp->pseudo_string_at(index);
++ if (cp->is_pseudo_string_at(index)) {
++ anObj = cp->pseudo_string_at(index);
++ } else {
++ anObj = cp->string_at(index, CATCH);
++ }
anObj->print_value_on(st);
st->print(" {0x%lx}", (address)anObj);
break;
-@@ -382,8 +410,12 @@
+@@ -382,8 +414,12 @@
"should be symbol or instance");
}
if (cp->tag_at(i).is_string()) {
@@ -650,7 +678,7 @@ diff --git a/src/share/vm/oops/constantP
+
+ int flags() const { return _flags; }
+ void set_flags(int f) { _flags = f; }
-+ bool flag_at(FlagBit fb) const { return ((_flags >> (int)fb) & 1) != 0; }
++ bool flag_at(FlagBit fb) const { return (_flags & (1 << (int)fb)) != 0; }
+ void set_flag_at(FlagBit fb);
+ // no clear_flag_at function; they only increase
@@ -666,12 +694,16 @@ diff --git a/src/share/vm/oops/constantP
// Klass holding pool
klassOop pool_holder() const { return _pool_holder; }
-@@ -272,6 +286,23 @@
+@@ -272,6 +286,27 @@
return string_at_impl(h_this, which, CHECK_NULL);
}
-+ // A "pseudo string" is an non-string oop that has found is way into
++ // A "pseudo-string" is an non-string oop that has found is way into
+ // a String entry.
++ // Under AnonymousClasses this can happen if the user patches a live
++ // object into a CONSTANT_String entry of an anonymous class.
++ // Method oops internally created for method handles may also
++ // use pseudo-strings to link themselves to related metaobjects.
+
+ bool is_pseudo_string_at(int which);
+
@@ -683,14 +715,14 @@ diff --git a/src/share/vm/oops/constantP
+ void pseudo_string_at_put(int which, oop x) {
+ assert(AnonymousClasses, "");
+ set_pseudo_string(); // mark header
-+ assert(tag_at(which).is_string(), "Corrupted constant pool");
++ assert(tag_at(which).is_string() || tag_at(which).is_unresolved_string(), "Corrupted constant pool");
+ string_at_put(which, x); // this works just fine
+ }
+
// only called when we are sure a string entry is already resolved (via an
// earlier string_at call.
oop resolved_string_at(int which) {
-@@ -293,6 +324,7 @@
+@@ -293,6 +328,7 @@
// UTF8 char* representation was chosen to avoid conversion of
// java_lang_Strings at resolved entries into symbolOops
// or vice versa.
@@ -701,16 +733,18 @@ diff --git a/src/share/vm/oops/instanceK
diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp
--- a/src/share/vm/oops/instanceKlass.hpp
+++ b/src/share/vm/oops/instanceKlass.hpp
-@@ -147,6 +147,8 @@
+@@ -147,6 +147,10 @@
oop _class_loader;
// Protection domain.
oop _protection_domain;
-+ // Host class, which shares access with this class
++ // Host class, which grants its access privileges to this class also.
++ // This is only non-null for an anonymous class (AnonymousClasses enabled).
++ // The host class is either named, or a previously loaded anonymous class.
+ klassOop _host_klass;
// Class signers.
objArrayOop _signers;
// Name of source file containing this klass, NULL if not specified.
-@@ -374,6 +376,11 @@
+@@ -374,6 +378,11 @@
// protection domain
oop protection_domain() { return _protection_domain; }
void set_protection_domain(oop pd) { oop_store((oop*) &_protection_domain, pd); }
@@ -722,7 +756,7 @@ diff --git a/src/share/vm/oops/instanceK
// signers
objArrayOop signers() const { return _signers; }
-@@ -701,6 +708,7 @@
+@@ -709,6 +718,7 @@
oop* adr_constants() const { return (oop*)&this->_constants;}
oop* adr_class_loader() const { return (oop*)&this->_class_loader;}
oop* adr_protection_domain() const { return (oop*)&this->_protection_domain;}
@@ -864,7 +898,7 @@ diff --git a/src/share/vm/prims/jvm.cpp
diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp
--- a/src/share/vm/prims/jvm.cpp
+++ b/src/share/vm/prims/jvm.cpp
-@@ -732,6 +732,7 @@
+@@ -744,6 +744,7 @@
// common code for JVM_DefineClass() and JVM_DefineClassWithSource()
static jclass jvm_define_class_common(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source, TRAPS) {
@@ -872,7 +906,7 @@ diff --git a/src/share/vm/prims/jvm.cpp
// Since exceptions can be thrown, class initialization can take place
// if name is NULL no check for class name in .class stream has to be made.
-@@ -770,7 +771,7 @@
+@@ -782,7 +783,7 @@
JVM_ENTRY(jclass, JVM_DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd))
JVMWrapper2("JVM_DefineClass %s", name);
@@ -902,7 +936,7 @@ diff --git a/src/share/vm/prims/unsafe.c
diff --git a/src/share/vm/prims/unsafe.cpp b/src/share/vm/prims/unsafe.cpp
--- a/src/share/vm/prims/unsafe.cpp
+++ b/src/share/vm/prims/unsafe.cpp
-@@ -837,6 +837,120 @@
+@@ -837,6 +837,163 @@
}
UNSAFE_END
@@ -911,6 +945,49 @@ diff --git a/src/share/vm/prims/unsafe.c
+// - host_class: supplies context for linkage, access control, protection domain, and class loader
+// - data: bytes of a class file, a raw memory address (length gives the number of bytes)
+// - cp_patches: where non-null entries exist, they replace corresponding CP entries in data
++
++// When you load an anonymous class U, it works as if you changed its name just before loading,
++// to a name that you will never use again. Since the name is lost, no other class can directly
++// link to any member of U. Just after U is loaded, the only way to use it is reflectively,
++// through java.lang.Class methods like Class.newInstance.
++
++// Access checks for linkage sites within U continue to follow the same rules as for named classes.
++// The package of an anonymous class is given by the package qualifier on the name under which it was loaded.
++// An anonymous class also has special privileges to access any member of its host class.
++// This is the main reason why this loading operation is unsafe. The purpose of this is to
++// allow language implementations to simulate "open classes"; a host class in effect gets
++// new code when an anonymous class is loaded alongside it. A less convenient but more
++// standard way to do this is with reflection, which can also be set to ignore access
++// restrictions.
++
++// Access into an anonymous class is possible only through reflection. Therefore, there
++// are no special access rules for calling into an anonymous class. The relaxed access
++// rule for the host class is applied in the opposite direction: A host class reflectively
++// access one of its anonymous classes.
++
++// If you load the same bytecodes twice, you get two different classes. You can reload
++// the same bytecodes with or without varying CP patches.
++
++// By using the CP patching array, you can have a new anonymous class U2 refer to an older one U1.
++// The bytecodes for U2 should refer to U1 by a symbolic name (doesn't matter what the name is).
++// The CONSTANT_Class entry for that name can be patched to refer directly to U1.
++
++// This allows, for example, U2 to use U1 as a superclass or super-interface, or as
++// an outer class (so that U2 is an anonymous inner class of anonymous U1).
++// It is not possible for a named class, or an older anonymous class, to refer by
++// name (via its CP) to a newer anonymous class.
++
++// CP patching may also be used to modify (i.e., hack) the names of methods, classes,
++// or type descriptors used in the loaded anonymous class.
++
++// Finally, CP patching may be used to introduce "live" objects into the constant pool,
++// instead of "dead" strings. A compiled statement like println((Object)"hello") can
++// be changed to println(greeting), where greeting is an arbitrary object created before
++// the anonymous class is loaded. This is useful in dynamic languages, in which
++// various kinds of metaobjects must be introduced as constants into bytecode.
++// Note the cast (Object), which tells the verifier to expect an arbitrary object,
++// not just a literal string. For such ldc instructions, the verifier uses the
++// type Object instead of String, if the loaded constant is not in fact a String.
+
+static oop
+Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
@@ -1023,7 +1100,7 @@ diff --git a/src/share/vm/prims/unsafe.c
UNSAFE_ENTRY(void, Unsafe_MonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj))
UnsafeWrapper("Unsafe_MonitorEnter");
-@@ -1291,6 +1405,9 @@
+@@ -1292,6 +1449,9 @@
{CC"copyMemory", CC"("ADR ADR"J)V", FN_PTR(Unsafe_CopyMemory)}
};
@@ -1033,7 +1110,7 @@ diff --git a/src/share/vm/prims/unsafe.c
#undef CC
#undef FN_PTR
-@@ -1353,6 +1470,15 @@
+@@ -1354,6 +1514,15 @@
}
}
}
@@ -1052,7 +1129,7 @@ diff --git a/src/share/vm/runtime/global
diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
--- a/src/share/vm/runtime/globals.hpp
+++ b/src/share/vm/runtime/globals.hpp
-@@ -3187,6 +3187,9 @@
+@@ -3230,6 +3230,9 @@
"Skip assert() and verify() which page-in unwanted shared " \
"objects. ") \
\
@@ -1065,16 +1142,22 @@ diff --git a/src/share/vm/runtime/reflec
diff --git a/src/share/vm/runtime/reflection.cpp b/src/share/vm/runtime/reflection.cpp
--- a/src/share/vm/runtime/reflection.cpp
+++ b/src/share/vm/runtime/reflection.cpp
-@@ -456,10 +456,26 @@
+@@ -456,10 +456,32 @@
return can_relax_access_check_for(current_class, new_class, classloader_only);
}
+static bool under_host_klass(instanceKlass* ik, klassOop host_klass) {
++ DEBUG_ONLY(int inf_loop_check = 1000 * 1000 * 1000);
+ for (;;) {
+ klassOop hc = (klassOop) ik->host_klass();
+ if (hc == NULL) return false;
+ if (hc == host_klass) return true;
+ ik = instanceKlass::cast(hc);
++
++ // There's no way to make a host class loop short of patching memory.
++ // Therefore there cannot be a loop here unles there's another bug.
++ // Still, let's check for it.
++ assert(--inf_loop_check > 0, "no host_klass loop");
+ }
+}
+
@@ -1095,12 +1178,11 @@ diff --git a/src/share/vm/utilities/cons
diff --git a/src/share/vm/utilities/constantTag.hpp b/src/share/vm/utilities/constantTag.hpp
--- a/src/share/vm/utilities/constantTag.hpp
+++ b/src/share/vm/utilities/constantTag.hpp
-@@ -70,7 +70,7 @@
- bool is_unresolved_string() const { return _tag == JVM_CONSTANT_UnresolvedString; }
+@@ -71,6 +71,7 @@
bool is_string_index() const { return _tag == JVM_CONSTANT_StringIndex; }
-- bool is_klass_reference() const { return is_klass_index() || is_unresolved_klass(); }
-+ bool is_klass_reference() const { return is_klass() || is_klass_index() || is_unresolved_klass(); }
+ bool is_klass_reference() const { return is_klass_index() || is_unresolved_klass(); }
++ bool is_klass_or_reference() const{ return is_klass() || is_klass_reference(); }
bool is_field_or_method() const { return is_field() || is_method() || is_interface_method(); }
bool is_symbol() const { return is_utf8(); }