--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nonperm.patch Thu Jul 02 19:04:11 2009 -0700
@@ -0,0 +1,901 @@
+Sketch of changes necessary to allow non-perm oops into the code cache.
+This is useful as a way to directly address java.dyn.CallSite and java.dyn.MethodHandle objects for invokedynamic.
+It is not complete. Here is a test case:
+
+diff --git a/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java b/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java
+--- a/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java
++++ b/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java
+@@ -33,6 +33,7 @@
+
+ public class CodeCache {
+ private static AddressField heapField;
++ private static AddressField nonPermOopNMethodsField;
+ private static VirtualConstructor virtualConstructor;
+
+ private CodeHeap heap;
+@@ -49,6 +50,7 @@
+ Type type = db.lookupType("CodeCache");
+
+ heapField = type.getAddressField("_heap");
++ nonPermOopNMethodsField = type.getAddressField("_non_perm_oop_nmethods");
+
+ virtualConstructor = new VirtualConstructor(db);
+ // Add mappings for all possible CodeBlob subclasses
+@@ -67,6 +69,10 @@
+ heap = (CodeHeap) VMObjectFactory.newObject(CodeHeap.class, heapField.getValue());
+ }
+
++ public NMethod nonPermOopNMethods() {
++ return (NMethod) VMObjectFactory.newObject(NMethod.class, nonPermOopNMethodsField.getValue());
++ }
++
+ public boolean contains(Address p) {
+ return getHeap().contains(p);
+ }
+diff --git a/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java b/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java
+--- a/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java
++++ b/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java
+@@ -40,7 +40,10 @@
+ /** != InvocationEntryBci if this nmethod is an on-stack replacement method */
+ private static CIntegerField entryBCIField;
+ /** To support simple linked-list chaining of nmethods */
+- private static AddressField linkField;
++ private static AddressField osrLinkField;
++ private static AddressField nonPermLinkField;
++ private static CIntegerField nonPermOopStateField;
++
+ /** Offsets for different nmethod parts */
+ private static CIntegerField exceptionOffsetField;
+ private static CIntegerField deoptOffsetField;
+@@ -87,7 +90,10 @@
+ zombieInstructionSizeField = type.getCIntegerField("_zombie_instruction_size");
+ methodField = type.getOopField("_method");
+ entryBCIField = type.getCIntegerField("_entry_bci");
+- linkField = type.getAddressField("_link");
++ osrLinkField = type.getAddressField("_osr_link");
++ nonPermLinkField = type.getAddressField("_non_perm_link");
++ nonPermOopStateField = type.getCIntegerField("_non_perm_oop_state");
++
+ exceptionOffsetField = type.getCIntegerField("_exception_offset");
+ deoptOffsetField = type.getCIntegerField("_deoptimize_offset");
+ origPCOffsetField = type.getCIntegerField("_orig_pc_offset");
+@@ -219,10 +225,19 @@
+ return getEntryBCI();
+ }
+
+- public NMethod getLink() {
+- return (NMethod) VMObjectFactory.newObject(NMethod.class, linkField.getValue(addr));
++ public NMethod getOSRLink() {
++ return (NMethod) VMObjectFactory.newObject(NMethod.class, osrLinkField.getValue(addr));
+ }
+
++ public NMethod getNonPermLink() {
++ return (NMethod) VMObjectFactory.newObject(NMethod.class, nonPermLinkField.getValue(addr));
++ }
++
++ public int getNonPermOopState() {
++ return (int) nonPermOopStateField.getValue(addr);
++ }
++
++
+ /** Tells whether frames described by this nmethod can be
+ deoptimized. Note: native wrappers cannot be deoptimized. */
+ public boolean canBeDeoptimized() { return isJavaMethod(); }
+diff --git a/src/cpu/x86/vm/x86_32.ad b/src/cpu/x86/vm/x86_32.ad
+--- a/src/cpu/x86/vm/x86_32.ad
++++ b/src/cpu/x86/vm/x86_32.ad
+@@ -400,7 +400,9 @@
+ int format) {
+ #ifdef ASSERT
+ if (rspec.reloc()->type() == relocInfo::oop_type && d32 != 0 && d32 != (int)Universe::non_oop_word()) {
+- assert(oop(d32)->is_oop() && oop(d32)->is_perm(), "cannot embed non-perm oops in code");
++ assert(oop(d32)->is_oop(), "non-oop in code?");
++ if (!NonPermCodeRefs)
++ assert(oop(d32)->is_perm(), "cannot embed non-perm oops in code");
+ }
+ #endif
+ cbuf.relocate(cbuf.inst_mark(), rspec, format);
+diff --git a/src/cpu/x86/vm/x86_64.ad b/src/cpu/x86/vm/x86_64.ad
+--- a/src/cpu/x86/vm/x86_64.ad
++++ b/src/cpu/x86/vm/x86_64.ad
+@@ -683,7 +683,9 @@
+ #ifdef ASSERT
+ if (rspec.reloc()->type() == relocInfo::oop_type &&
+ d32 != 0 && d32 != (intptr_t) Universe::non_oop_word()) {
+- assert(oop((intptr_t)d32)->is_oop() && oop((intptr_t)d32)->is_perm(), "cannot embed non-perm oops in code");
++ assert(oop((intptr_t)d32)->is_oop(), "cannot embed non-perm oops in code");
++ if (!NonPermCodeRefs)
++ assert(oop((intptr_t)d32)->is_perm(), "cannot embed non-perm oops in code");
+ }
+ #endif
+ cbuf.relocate(cbuf.inst_mark(), rspec, format);
+@@ -721,7 +723,7 @@
+ #ifdef ASSERT
+ if (rspec.reloc()->type() == relocInfo::oop_type &&
+ d64 != 0 && d64 != (int64_t) Universe::non_oop_word()) {
+- assert(oop(d64)->is_oop() && oop(d64)->is_perm(),
++ assert(oop(d64)->is_oop() && (NonPermCodeRefs || oop(d64)->is_perm()),
+ "cannot embed non-perm oops in code");
+ }
+ #endif
+diff --git a/src/share/vm/ci/ciObject.cpp b/src/share/vm/ci/ciObject.cpp
+--- a/src/share/vm/ci/ciObject.cpp
++++ b/src/share/vm/ci/ciObject.cpp
+@@ -181,6 +181,7 @@
+ // ------------------------------------------------------------------
+ // ciObject::has_encoding
+ bool ciObject::has_encoding() {
++ if (NonPermCodeRefs) return true; // everybody codes now
+ return handle() == NULL || is_perm();
+ }
+
+diff --git a/src/share/vm/ci/ciObject.hpp b/src/share/vm/ci/ciObject.hpp
+--- a/src/share/vm/ci/ciObject.hpp
++++ b/src/share/vm/ci/ciObject.hpp
+@@ -92,6 +92,7 @@
+ int hash();
+
+ // Tells if this oop has an encoding. (I.e., is it null or perm?)
++ // If NonPermCodeRefs is true, all oops have encodings.
+ // If it does not have an encoding, the compiler is responsible for
+ // making other arrangements for dealing with the oop.
+ // See ciEnv::make_perm_array
+diff --git a/src/share/vm/code/codeBlob.hpp b/src/share/vm/code/codeBlob.hpp
+--- a/src/share/vm/code/codeBlob.hpp
++++ b/src/share/vm/code/codeBlob.hpp
+@@ -175,6 +175,7 @@
+ OopClosure* keep_alive,
+ bool unloading_occurred);
+ virtual void oops_do(OopClosure* f) = 0;
++ virtual bool non_perm_oops_do(OopClosure* f) = 0; // return false if no non-perms
+
+ // OopMap for frame
+ OopMapSet* oop_maps() const { return _oop_maps; }
+@@ -241,6 +242,7 @@
+ bool unloading_occurred) { /* do nothing */ }
+
+ void oops_do(OopClosure* f) { /* do nothing*/ }
++ bool non_perm_oops_do(OopClosure* f) { /* do-nothing */ return false; }
+
+ void verify();
+ void print() const PRODUCT_RETURN;
+@@ -295,6 +297,7 @@
+ OopClosure* keep_alive,
+ bool unloading_occurred) { /* do nothing */ }
+ void oops_do(OopClosure* f) { /* do-nothing*/ }
++ bool non_perm_oops_do(OopClosure* f) { /* do-nothing */ return false; }
+
+ void verify();
+ void print() const PRODUCT_RETURN;
+@@ -382,6 +385,7 @@
+
+ // Iteration
+ void oops_do(OopClosure* f) {}
++ bool non_perm_oops_do(OopClosure* f) { return false; }
+
+ // Printing
+ void print_value_on(outputStream* st) const PRODUCT_RETURN;
+@@ -437,6 +441,7 @@
+
+ // Iteration
+ void oops_do(OopClosure* f) {}
++ bool non_perm_oops_do(OopClosure* f) { return false; }
+ };
+
+
+@@ -472,6 +477,7 @@
+
+ // Iteration
+ void oops_do(OopClosure* f) {}
++ bool non_perm_oops_do(OopClosure* f) { return false; }
+ };
+ #endif // COMPILER2
+
+@@ -508,4 +514,5 @@
+
+ // Iteration
+ void oops_do(OopClosure* f) {}
++ bool non_perm_oops_do(OopClosure* f) { return false; }
+ };
+diff --git a/src/share/vm/code/codeCache.cpp b/src/share/vm/code/codeCache.cpp
+--- a/src/share/vm/code/codeCache.cpp
++++ b/src/share/vm/code/codeCache.cpp
+@@ -95,6 +95,7 @@
+ int CodeCache::_number_of_blobs = 0;
+ int CodeCache::_number_of_nmethods_with_dependencies = 0;
+ bool CodeCache::_needs_cache_clean = false;
++nmethod* CodeCache::_non_perm_oop_nmethods = NULL;
+
+
+ CodeBlob* CodeCache::first() {
+@@ -264,9 +265,86 @@
+ assert_locked_or_safepoint(CodeCache_lock);
+ FOR_ALL_ALIVE_BLOBS(cb) {
+ cb->oops_do(f);
++
++#ifdef ASSERT
++ if (cb->is_nmethod())
++ ((nmethod*)cb)->verify_non_perm_oops();
++#endif
+ }
+ }
+
++void CodeCache::non_perm_oops_do(OopClosure* f) {
++ assert_locked_or_safepoint(CodeCache_lock);
++ debug_only(mark_non_perm_oop_nmethods());
++
++ // Walk the list of methods containing non-perm oops, pruning as we go.
++ nmethod* last = NULL;
++ nmethod* cur = non_perm_oop_nmethods();
++ while (cur != NULL) {
++ bool saw_non_perm = cur->non_perm_oops_do(f);
++ assert(cur->has_non_perm_oops(), "else shouldn't be on this list");
++
++ if (saw_non_perm) {
++ // Leave it on the list.
++ debug_only(cur->_non_perm_oop_state = NPO_PLAIN_BIT);
++ last = cur;
++ cur = last->non_perm_link();
++ } else {
++
++ // Prune it from the list, so we don't have to look at it any more.
++ nmethod* next = cur->non_perm_link();
++ cur->set_non_perm_link(NULL);
++ cur->clear_has_non_perm_oops();
++ if (last != NULL)
++ last->set_non_perm_link(next);
++ else set_non_perm_oop_nmethods(next);
++ cur = next;
++ }
++ }
++
++ debug_only(unmark_non_perm_oop_nmethods());
++}
++
++#ifndef PRODUCT
++void CodeCache::asserted_perm_oops_do(OopClosure* f) {
++ // While we are here, verify the integrity of the list.
++ mark_non_perm_oop_nmethods();
++ for (nmethod* cur = non_perm_oop_nmethods(); cur != NULL; cur = cur->non_perm_link()) {
++ assert(cur->has_non_perm_oops(), "else shouldn't be on this list");
++ cur->_non_perm_oop_state = NPO_PLAIN_BIT;
++ }
++ unmark_non_perm_oop_nmethods(f);
++}
++
++// Mark nmethods that are on the list, temporarily.
++void CodeCache::mark_non_perm_oop_nmethods() {
++ FOR_ALL_ALIVE_BLOBS(cb) {
++ if (cb->is_nmethod()) {
++ nmethod *nm = (nmethod*)cb;
++ assert((nm->_non_perm_oop_state & ~NPO_PLAIN_BIT) == 0, "clean state");
++ if (nm->has_non_perm_oops()) {
++ nm->_non_perm_oop_state = (NPO_NEED_VISIT | NPO_PLAIN_BIT);
++ }
++ }
++ }
++}
++
++// Make sure that the effects of mark_non_perm_oop_nmethods is gone.
++void CodeCache::unmark_non_perm_oop_nmethods(OopClosure* f) {
++ FOR_ALL_ALIVE_BLOBS(cb) {
++ bool call_f = (f != NULL);
++ if (cb->is_nmethod()) {
++ nmethod *nm = (nmethod*)cb;
++ assert((nm->_non_perm_oop_state & NPO_NEED_VISIT) == 0, "must be already processed");
++ if (nm->has_non_perm_oops())
++ call_f = false; // don't show this one to the client
++ nm->verify_non_perm_oops();
++ }
++ if (call_f) cb->oops_do(f);
++ }
++}
++#endif //PRODUCT
++
+ void CodeCache::gc_prologue() {
+ }
+
+diff --git a/src/share/vm/code/codeCache.hpp b/src/share/vm/code/codeCache.hpp
+--- a/src/share/vm/code/codeCache.hpp
++++ b/src/share/vm/code/codeCache.hpp
+@@ -45,8 +45,15 @@
+ static int _number_of_blobs;
+ static int _number_of_nmethods_with_dependencies;
+ static bool _needs_cache_clean;
++ static nmethod* _non_perm_oop_nmethods; // linked via nm->non_perm_link()
+
+ static void verify_if_often() PRODUCT_RETURN;
++
++ // Bit patterns in nmethod::_non_perm_oop_state:
++ enum { NPO_PLAIN_BIT = 0x01, NPO_NEED_VISIT = 0x10 };
++ static void mark_non_perm_oop_nmethods() PRODUCT_RETURN;
++ static void unmark_non_perm_oop_nmethods(OopClosure* f = NULL) PRODUCT_RETURN;
++
+ public:
+
+ // Initialization
+@@ -96,6 +103,8 @@
+ static CodeBlob* alive(CodeBlob *cb);
+ static nmethod* alive_nmethod(CodeBlob *cb);
+ static int nof_blobs() { return _number_of_blobs; }
++ static nmethod* non_perm_oop_nmethods() { return _non_perm_oop_nmethods; }
++ static void set_non_perm_oop_nmethods(nmethod* nm) { _non_perm_oop_nmethods = nm; }
+
+ // GC support
+ static void gc_epilogue();
+@@ -107,6 +116,8 @@
+ OopClosure* keep_alive,
+ bool unloading_occurred);
+ static void oops_do(OopClosure* f);
++ static void non_perm_oops_do(OopClosure* f); // scan a small subset of nmethods
++ static void asserted_perm_oops_do(OopClosure* f = NULL) PRODUCT_RETURN;
+
+ // Printing/debugging
+ static void print() PRODUCT_RETURN; // prints summary
+diff --git a/src/share/vm/code/nmethod.cpp b/src/share/vm/code/nmethod.cpp
+--- a/src/share/vm/code/nmethod.cpp
++++ b/src/share/vm/code/nmethod.cpp
+@@ -584,7 +584,9 @@
+ NOT_PRODUCT(_has_debug_info = false; )
+ _method = method;
+ _entry_bci = InvocationEntryBci;
+- _link = NULL;
++ _osr_link = NULL;
++ _non_perm_link = NULL;
++ _non_perm_oop_state = 0;
+ _compiler = NULL;
+ // We have no exception handler or deopt handler make the
+ // values something that will never match a pc like the nmethod vtable entry
+@@ -618,7 +620,7 @@
+ _stack_traversal_mark = 0;
+
+ code_buffer->copy_oops_to(this);
+- debug_only(check_store();)
++ debug_only(verify_non_perm_oops());
+ CodeCache::commit(this);
+ VTune::create_nmethod(this);
+ }
+@@ -671,7 +673,9 @@
+ NOT_PRODUCT(_has_debug_info = false; )
+ _method = method;
+ _entry_bci = InvocationEntryBci;
+- _link = NULL;
++ _osr_link = NULL;
++ _non_perm_link = NULL;
++ _non_perm_oop_state = 0;
+ _compiler = NULL;
+ // We have no exception handler or deopt handler make the
+ // values something that will never match a pc like the nmethod vtable entry
+@@ -703,7 +707,7 @@
+ _stack_traversal_mark = 0;
+
+ code_buffer->copy_oops_to(this);
+- debug_only(check_store();)
++ debug_only(verify_non_perm_oops());
+ CodeCache::commit(this);
+ VTune::create_nmethod(this);
+ }
+@@ -775,7 +779,9 @@
+ _compile_id = compile_id;
+ _comp_level = comp_level;
+ _entry_bci = entry_bci;
+- _link = NULL;
++ _osr_link = NULL;
++ _non_perm_link = NULL;
++ _non_perm_oop_state = 0;
+ _compiler = compiler;
+ _orig_pc_offset = orig_pc_offset;
+ #ifdef HAVE_DTRACE_H
+@@ -813,7 +819,8 @@
+ code_buffer->copy_oops_to(this);
+ debug_info->copy_to(this);
+ dependencies->copy_to(this);
+- debug_only(check_store();)
++ check_for_non_perm_oops();
++ debug_only(verify_non_perm_oops());
+
+ CodeCache::commit(this);
+
+@@ -1105,7 +1112,8 @@
+ // The methodOop is gone at this point
+ assert(_method == NULL, "Tautology");
+
+- set_link(NULL);
++ set_osr_link(NULL);
++ set_non_perm_link(NULL);
+ NMethodSweeper::notify(this);
+ }
+
+@@ -1520,7 +1528,9 @@
+ #endif // !PRODUCT
+ }
+
+-void nmethod::oops_do(OopClosure* f) {
++bool nmethod::oops_do_internal(OopClosure* f, bool do_perm) {
++ bool saw_non_perm = false;
++
+ // make sure the oops ready to receive visitors
+ assert(!is_zombie() && !is_unloaded(),
+ "should not call follow on zombie or unloaded nmethod");
+@@ -1537,11 +1547,13 @@
+ }
+
+ // Compiled code
+- f->do_oop((oop*) &_method);
+- ExceptionCache* ec = exception_cache();
+- while(ec != NULL) {
+- f->do_oop((oop*)ec->exception_type_addr());
+- ec = ec->next();
++ if (do_perm) {
++ f->do_oop((oop*) &_method);
++ ExceptionCache* ec = exception_cache();
++ while(ec != NULL) {
++ f->do_oop((oop*)ec->exception_type_addr());
++ ec = ec->next();
++ }
+ }
+
+ RelocIterator iter(this, low_boundary);
+@@ -1551,17 +1563,55 @@
+ // In this loop, we must only follow those oops directly embedded in
+ // the code. Other oops (oop_index>0) are seen as part of scopes_oops.
+ assert(1 == (r->oop_is_immediate()) + (r->oop_addr() >= oops_begin() && r->oop_addr() < oops_end()), "oop must be found in exactly one place");
+- if (r->oop_is_immediate() && r->oop_value() != NULL) {
++ if (r->oop_is_immediate()) {
++ oop x = r->oop_value();
++ if (x == NULL) {
++ continue;
++ } else if (!x->is_perm()) {
++ saw_non_perm = true;
++ } else {
++ if (!do_perm) continue;
++ }
+ f->do_oop(r->oop_addr());
+ }
+ }
+ }
+
+- // Scopes
++ // Scopes & oop constants
+ for (oop* p = oops_begin(); p < oops_end(); p++) {
+- if (*p == Universe::non_oop_word()) continue; // skip non-oops
++ oop x = *p;
++ if (x == Universe::non_oop_word()) {
++ continue; // skip non-oops
++ } else if (x == NULL) {
++ // fall through (needed to scan empty spaces?)
++ } else if (!x->is_perm()) {
++ saw_non_perm = true;
++ } else {
++ if (!do_perm) continue;
++ }
+ f->do_oop(p);
+ }
++
++ return saw_non_perm;
++}
++
++class IgnoreOops: public OopClosure {
++public:
++ IgnoreOops() { }
++ virtual void do_oop(oop* p) { }
++ virtual void do_oop(narrowOop* p) { }
++};
++static IgnoreOops ignore_oops_closure;
++
++void nmethod::check_for_non_perm_oops() {
++ assert_locked_or_safepoint(CodeCache_lock);
++ if (NonPermCodeRefs &&
++ !has_non_perm_oops() &&
++ oops_do_internal(&ignore_oops_closure, false)) {
++ set_has_non_perm_oops();
++ set_non_perm_link(CodeCache::non_perm_oop_nmethods());
++ CodeCache::set_non_perm_oop_nmethods(this);
++ }
+ }
+
+ // Method that knows how to preserve outgoing arguments at call. This method must be
+@@ -1974,19 +2024,34 @@
+ // Non-product code
+ #ifndef PRODUCT
+
+-void nmethod::check_store() {
+- // Make sure all oops in the compiled code are tenured
++class CheckForNonPerm: public OopClosure {
++ nmethod* _nm;
++ bool _ok;
++public:
++ CheckForNonPerm(nmethod* nm) : _nm(nm), _ok(true) { }
++ bool ok() { return _ok; }
++ virtual void do_oop(oop* p) {
++ if ((*p) == NULL || (*p)->is_perm()) return;
++ if (_ok) {
++ _nm->print_nmethod(true);
++ _ok = false;
++ }
++ tty->print_cr("*** non-perm oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)",
++ (intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm));
++ (*p)->print();
++ }
++ virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
++};
+
+- RelocIterator iter(this);
+- while (iter.next()) {
+- if (iter.type() == relocInfo::oop_type) {
+- oop_Relocation* reloc = iter.oop_reloc();
+- oop obj = reloc->oop_value();
+- if (obj != NULL && !obj->is_perm()) {
+- fatal("must be permanent oop in compiled code");
+- }
+- }
++void nmethod::verify_non_perm_oops() {
++ if (!has_non_perm_oops()) {
++ // Actually look inside, to verify the claim that it's clean.
++ CheckForNonPerm check_for_non_perm(this);
++ oops_do(&check_for_non_perm);
++ if (!check_for_non_perm.ok())
++ fatal("found an unadvertised bad non-perm oop in the code cache");
+ }
++ assert((_non_perm_oop_state & ~1) == 0, "an unmarked state is a simple boolean");
+ }
+
+ #endif // PRODUCT
+@@ -2019,6 +2084,7 @@
+ if (is_not_entrant()) tty->print("not_entrant ");
+ if (is_zombie()) tty->print("zombie ");
+ if (is_unloaded()) tty->print("unloaded ");
++ if (has_non_perm_oops()) tty->print("non_perm_oops ");
+ tty->print_cr("}:");
+ }
+ if (size () > 0) tty->print_cr(" total in heap [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+diff --git a/src/share/vm/code/nmethod.hpp b/src/share/vm/code/nmethod.hpp
+--- a/src/share/vm/code/nmethod.hpp
++++ b/src/share/vm/code/nmethod.hpp
+@@ -125,6 +125,7 @@
+ class nmethod : public CodeBlob {
+ friend class VMStructs;
+ friend class NMethodSweeper;
++ friend class CodeCache; // non-perm oops
+ private:
+ // Shared fields for all nmethod's
+ static int _zombie_instruction_size;
+@@ -132,7 +133,9 @@
+ methodOop _method;
+ int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method
+
+- nmethod* _link; // To support simple linked-list chaining of nmethods
++ // To support simple linked-list chaining of nmethods:
++ nmethod* _osr_link;
++ nmethod* _non_perm_link;
+
+ AbstractCompiler* _compiler; // The compiler which compiled this nmethod
+
+@@ -174,6 +177,8 @@
+ // used by jvmti to track if an unload event has been posted for this nmethod.
+ bool _unload_reported;
+
++ jbyte _non_perm_oop_state;
++
+ NOT_PRODUCT(bool _has_debug_info; )
+
+ // Nmethod Flushing lock (if non-zero, then the nmethod is not removed)
+@@ -242,7 +247,6 @@
+
+ // helper methods
+ void* operator new(size_t size, int nmethod_size);
+- void check_store();
+
+ const char* reloc_string_for(u_char* begin, u_char* end);
+ void make_not_entrant_or_zombie(int state);
+@@ -407,6 +411,16 @@
+ int version() const { return flags.version; }
+ void set_version(int v);
+
++ // Non-perm oop support
++ bool has_non_perm_oops() const { return (_non_perm_oop_state & 1) != 0; }
++ protected:
++ // There is assertion-checking logic that uses the other bits of _non_perm_oop_state.
++ void set_has_non_perm_oops() { _non_perm_oop_state = 1; }
++ void clear_has_non_perm_oops() { _non_perm_oop_state = 0; }
++ nmethod* non_perm_link() const { return _non_perm_link; }
++ void set_non_perm_link(nmethod *n) { _non_perm_link = n; }
++ public:
++
+ // Sweeper support
+ long stack_traversal_mark() { return _stack_traversal_mark; }
+ void set_stack_traversal_mark(long l) { _stack_traversal_mark = l; }
+@@ -425,8 +439,8 @@
+ int osr_entry_bci() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _entry_bci; }
+ address osr_entry() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _osr_entry_point; }
+ void invalidate_osr_method();
+- nmethod* link() const { return _link; }
+- void set_link(nmethod *n) { _link = n; }
++ nmethod* osr_link() const { return _osr_link; }
++ void set_osr_link(nmethod *n) { _osr_link = n; }
+
+ // tells whether frames described by this nmethod can be deoptimized
+ // note: native wrappers cannot be deoptimized.
+@@ -446,6 +460,9 @@
+ protected:
+ void flush();
+
++ bool oops_do_internal(OopClosure* f, bool do_perm);
++ // this function returns true if non-perm seen
++
+ public:
+ // If returning true, it is unsafe to remove this nmethod even though it is a zombie
+ // nmethod, since the VM might have a reference to it. Should only be called from a safepoint.
+@@ -466,7 +483,10 @@
+
+ void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map,
+ OopClosure* f);
+- void oops_do(OopClosure* f);
++ void oops_do(OopClosure* f) { oops_do_internal(f, true); }
++ bool non_perm_oops_do(OopClosure* f) { return oops_do_internal(f, false); }
++ void verify_non_perm_oops() PRODUCT_RETURN;
++ void check_for_non_perm_oops();
+
+ // ScopeDesc for an instruction
+ ScopeDesc* scope_desc_at(address pc);
+diff --git a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp
+--- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp
++++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp
+@@ -107,6 +107,10 @@
+ vmSymbols::oops_do(&mark_and_push_closure);
+ break;
+
++ case code_cache:
++ CodeCache::non_perm_oops_do(&mark_and_push_closure);
++ break;
++
+ default:
+ fatal("Unknown root type");
+ }
+diff --git a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp
+--- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp
++++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp
+@@ -92,7 +92,8 @@
+ jvmti = 7,
+ system_dictionary = 8,
+ vm_symbols = 9,
+- reference_processing = 10
++ reference_processing = 10,
++ code_cache = 11
+ };
+ private:
+ RootType _root_type;
+diff --git a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp
+--- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp
++++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp
+@@ -517,6 +517,7 @@
+ JvmtiExport::oops_do(mark_and_push_closure());
+ SystemDictionary::always_strong_oops_do(mark_and_push_closure());
+ vmSymbols::oops_do(mark_and_push_closure());
++ CodeCache::non_perm_oops_do(mark_and_push_closure());
+
+ // Flush marking stack.
+ follow_stack();
+@@ -617,6 +618,7 @@
+ // SO_AllClasses
+ SystemDictionary::oops_do(adjust_root_pointer_closure());
+ vmSymbols::oops_do(adjust_root_pointer_closure());
++ CodeCache::non_perm_oops_do(adjust_root_pointer_closure());
+
+ // Now adjust pointers in remaining weak roots. (All of which should
+ // have been cleared if they pointed to non-surviving objects.)
+diff --git a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
+--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
++++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
+@@ -2335,6 +2335,7 @@
+ q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::system_dictionary));
+ q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::jvmti));
+ q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::vm_symbols));
++ q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::code_cache));
+
+ if (parallel_gc_threads > 1) {
+ for (uint j = 0; j < parallel_gc_threads; j++) {
+@@ -2413,6 +2414,7 @@
+ // SO_AllClasses
+ SystemDictionary::oops_do(adjust_root_pointer_closure());
+ vmSymbols::oops_do(adjust_root_pointer_closure());
++ CodeCache::non_perm_oops_do(adjust_root_pointer_closure());
+
+ // Now adjust pointers in remaining weak roots. (All of which should
+ // have been cleared if they pointed to non-surviving objects.)
+diff --git a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp
+--- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp
++++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp
+@@ -376,6 +376,7 @@
+ q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::management));
+ q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::system_dictionary));
+ q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::jvmti));
++ q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::code_cache));
+
+ ParallelTaskTerminator terminator(
+ gc_task_manager()->workers(),
+diff --git a/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp b/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp
+--- a/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp
++++ b/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp
+@@ -90,6 +90,11 @@
+ JvmtiExport::oops_do(&roots_closure);
+ break;
+
++
++ case code_cache:
++ CodeCache::non_perm_oops_do(&roots_closure);
++ break;
++
+ default:
+ fatal("Unknown root type");
+ }
+diff --git a/src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp b/src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp
+--- a/src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp
++++ b/src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp
+@@ -54,7 +54,8 @@
+ flat_profiler = 5,
+ system_dictionary = 6,
+ management = 7,
+- jvmti = 8
++ jvmti = 8,
++ code_cache = 9
+ };
+ private:
+ RootType _root_type;
+diff --git a/src/share/vm/memory/sharedHeap.cpp b/src/share/vm/memory/sharedHeap.cpp
+--- a/src/share/vm/memory/sharedHeap.cpp
++++ b/src/share/vm/memory/sharedHeap.cpp
+@@ -158,9 +158,12 @@
+ if (!_process_strong_tasks->is_task_claimed(SH_PS_CodeCache_oops_do)) {
+ if (so & SO_CodeCache) {
+ CodeCache::oops_do(roots);
++ } else {
++ // In any case, process the relatively sparse set of non-perm oops:
++ CodeCache::non_perm_oops_do(roots);
+ }
+ // Verify if the code cache contents are in the perm gen
+- NOT_PRODUCT(CodeCache::oops_do(&assert_is_perm_closure));
++ NOT_PRODUCT(CodeCache::asserted_perm_oops_do(&assert_is_perm_closure));
+ }
+
+ // Roots that should point only into permanent generation.
+diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp
+--- a/src/share/vm/oops/instanceKlass.cpp
++++ b/src/share/vm/oops/instanceKlass.cpp
+@@ -2013,7 +2013,7 @@
+ // This is a short non-blocking critical region, so the no safepoint check is ok.
+ OsrList_lock->lock_without_safepoint_check();
+ assert(n->is_osr_method(), "wrong kind of nmethod");
+- n->set_link(osr_nmethods_head());
++ n->set_osr_link(osr_nmethods_head());
+ set_osr_nmethods_head(n);
+ // Remember to unlock again
+ OsrList_lock->unlock();
+@@ -2029,17 +2029,17 @@
+ // Search for match
+ while(cur != NULL && cur != n) {
+ last = cur;
+- cur = cur->link();
++ cur = cur->osr_link();
+ }
+ if (cur == n) {
+ if (last == NULL) {
+ // Remove first element
+- set_osr_nmethods_head(osr_nmethods_head()->link());
++ set_osr_nmethods_head(osr_nmethods_head()->osr_link());
+ } else {
+- last->set_link(cur->link());
++ last->set_osr_link(cur->osr_link());
+ }
+ }
+- n->set_link(NULL);
++ n->set_osr_link(NULL);
+ // Remember to unlock again
+ OsrList_lock->unlock();
+ }
+@@ -2056,7 +2056,7 @@
+ OsrList_lock->unlock();
+ return osr;
+ }
+- osr = osr->link();
++ osr = osr->osr_link();
+ }
+ OsrList_lock->unlock();
+ return NULL;
+diff --git a/src/share/vm/opto/parse3.cpp b/src/share/vm/opto/parse3.cpp
+--- a/src/share/vm/opto/parse3.cpp
++++ b/src/share/vm/opto/parse3.cpp
+@@ -280,6 +280,7 @@
+ case T_ARRAY:
+ case T_OBJECT: {
+ // the oop is in perm space if the ciObject "has_encoding"
++ // or else NonPermCodeRefs must be true
+ ciObject* oop_constant = constant.as_object();
+ if (oop_constant->is_null_object()) {
+ push( zerocon(T_OBJECT) );
+diff --git a/src/share/vm/opto/type.cpp b/src/share/vm/opto/type.cpp
+--- a/src/share/vm/opto/type.cpp
++++ b/src/share/vm/opto/type.cpp
+@@ -2393,7 +2393,7 @@
+ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o) {
+ if (o->is_method_data() || o->is_method() || o->is_cpcache()) {
+ // Treat much like a typeArray of bytes, like below, but fake the type...
+- assert(o->has_encoding(), "must be a perm space object");
++ assert(o->is_perm(), "must be a perm space object");
+ const Type* etype = (Type*)get_const_basic_type(T_BYTE);
+ const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
+ ciKlass *klass = ciTypeArrayKlass::make((BasicType) T_BYTE);
+@@ -2407,7 +2407,6 @@
+ if (klass->is_instance_klass()) {
+ // Element is an instance
+ if (!o->has_encoding()) { // not a perm-space constant
+- // %%% remove this restriction by rewriting non-perm ConPNodes in a later phase
+ return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, 0);
+ }
+ return TypeInstPtr::make(o);
+@@ -2420,7 +2419,6 @@
+ // are all not-null. This is not true in generally, as code can
+ // slam NULLs down in the subarrays.
+ if (!o->has_encoding()) { // not a perm-space constant
+- // %%% remove this restriction by rewriting non-perm ConPNodes in a later phase
+ return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
+ }
+ const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
+@@ -2433,7 +2431,6 @@
+ // We used to pass NotNull in here, asserting that the array pointer
+ // is not-null. That was not true in general.
+ if (!o->has_encoding()) { // not a perm-space constant
+- // %%% remove this restriction by rewriting non-perm ConPNodes in a later phase
+ return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
+ }
+ const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
+diff --git a/src/share/vm/prims/jvmtiTagMap.cpp b/src/share/vm/prims/jvmtiTagMap.cpp
+--- a/src/share/vm/prims/jvmtiTagMap.cpp
++++ b/src/share/vm/prims/jvmtiTagMap.cpp
+@@ -3126,6 +3126,11 @@
+ // exceptions) will be visible.
+ blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER);
+ Universe::oops_do(&blk);
++
++ // If there are any non-perm roots in the code cache, visit them.
++ blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER);
++ CodeCache::non_perm_oops_do(&blk);
++
+ return true;
+ }
+
+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
+@@ -714,6 +714,9 @@
+ diagnostic(bool, TraceNMethodInstalls, false, \
+ "Trace nmethod intallation") \
+ \
++ diagnostic(bool, NonPermCodeRefs, true, \
++ "allow non-perm references in the code cache") \
++ \
+ diagnostic(bool, TraceOSRBreakpoint, false, \
+ "Trace OSR Breakpoint ") \
+ \
+diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp
+--- a/src/share/vm/runtime/vmStructs.cpp
++++ b/src/share/vm/runtime/vmStructs.cpp
+@@ -549,6 +549,7 @@
+ /********************************/ \
+ \
+ static_field(CodeCache, _heap, CodeHeap*) \
++ static_field(CodeCache, _non_perm_oop_nmethods, nmethod*) \
+ \
+ /*******************************/ \
+ /* CodeHeap (NOTE: incomplete) */ \
+@@ -617,7 +618,9 @@
+ static_field(nmethod, _zombie_instruction_size, int) \
+ nonstatic_field(nmethod, _method, methodOop) \
+ nonstatic_field(nmethod, _entry_bci, int) \
+- nonstatic_field(nmethod, _link, nmethod*) \
++ nonstatic_field(nmethod, _osr_link, nmethod*) \
++ nonstatic_field(nmethod, _non_perm_link, nmethod*) \
++ nonstatic_field(nmethod, _non_perm_oop_state, jbyte) \
+ nonstatic_field(nmethod, _exception_offset, int) \
+ nonstatic_field(nmethod, _deoptimize_offset, int) \
+ nonstatic_field(nmethod, _orig_pc_offset, int) \