8006040: NPG: on_stack processing wastes space in ConstantPool
Added on_stack bit to flags. Also MetadataMarkOnStack is used for more than JVMTI so had to be moved.
Reviewed-by: dholmes, stefank
diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp
index 22cc8cf..0560d3f 100644
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -50,11 +50,12 @@
#include "classfile/classLoaderData.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.hpp"
+#include "classfile/metadataOnStackMark.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
-#include "prims/jvmtiRedefineClasses.hpp"
+#include "memory/oopFactory.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/mutex.hpp"
#include "runtime/safepoint.hpp"
diff --git a/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp b/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp
new file mode 100644
index 0000000..1f24042
--- /dev/null
+++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/metadataOnStackMark.hpp"
+#include "code/codeCache.hpp"
+#include "compiler/compileBroker.hpp"
+#include "oops/metadata.hpp"
+#include "runtime/synchronizer.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/growableArray.hpp"
+
+
+// Keep track of marked on-stack metadata so it can be cleared.
+GrowableArray<Metadata*>* _marked_objects = NULL;
+NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;)
+
+// Walk metadata on the stack and mark it so that redefinition doesn't delete
+// it. Class unloading also walks the previous versions and might try to
+// delete it, so this class is used by class unloading also.
+MetadataOnStackMark::MetadataOnStackMark() {
+ assert(SafepointSynchronize::is_at_safepoint(), "sanity check");
+ NOT_PRODUCT(_is_active = true;)
+ if (_marked_objects == NULL) {
+ _marked_objects = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(1000, true);
+ }
+ Threads::metadata_do(Metadata::mark_on_stack);
+ CodeCache::alive_nmethods_do(nmethod::mark_on_stack);
+ CompileBroker::mark_on_stack();
+}
+
+MetadataOnStackMark::~MetadataOnStackMark() {
+ assert(SafepointSynchronize::is_at_safepoint(), "sanity check");
+ // Unmark everything that was marked. Can't do the same walk because
+ // redefine classes messes up the code cache so the set of methods
+ // might not be the same.
+ for (int i = 0; i< _marked_objects->length(); i++) {
+ _marked_objects->at(i)->set_on_stack(false);
+ }
+ _marked_objects->clear(); // reuse growable array for next time.
+ NOT_PRODUCT(_is_active = false;)
+}
+
+// Record which objects are marked so we can unmark the same objects.
+void MetadataOnStackMark::record(Metadata* m) {
+ assert(_is_active, "metadata on stack marking is active");
+ _marked_objects->push(m);
+}
diff --git a/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp b/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp
new file mode 100644
index 0000000..5a4fda2
--- /dev/null
+++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP
+#define SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP
+
+#include "memory/allocation.hpp"
+
+class Metadata;
+
+// Helper class to mark and unmark metadata used on the stack as either handles
+// or executing methods, so that it can't be deleted during class redefinition
+// and class unloading.
+// This is also used for other things that can be deallocated, like class
+// metadata during parsing, relocated methods, and methods in backtraces.
+class MetadataOnStackMark : public StackObj {
+ NOT_PRODUCT(static bool _is_active;)
+ public:
+ MetadataOnStackMark();
+ ~MetadataOnStackMark();
+ static void record(Metadata* m);
+};
+
+#endif // SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP
diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp
index 959388f..efb2a16 100644
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -1241,7 +1241,7 @@
void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) {
assert(EnableInvokeDynamic, "");
- pool->set_invokedynamic(); // mark header to flag active call sites
+ pool->set_has_invokedynamic(); // mark header to flag active call sites
//resolve_pool(<resolved_klass>, method_name, method_signature, current_klass, pool, index, CHECK);
Symbol* method_name = pool->name_ref_at(index);
diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp
index 770510c..d4fa720 100644
--- a/hotspot/src/share/vm/oops/constantPool.cpp
+++ b/hotspot/src/share/vm/oops/constantPool.cpp
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/javaClasses.hpp"
+#include "classfile/metadataOnStackMark.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
@@ -34,7 +35,6 @@
#include "oops/constantPool.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/objArrayKlass.hpp"
-#include "prims/jvmtiRedefineClasses.hpp"
#include "runtime/fieldType.hpp"
#include "runtime/init.hpp"
#include "runtime/javaCalls.hpp"
@@ -65,11 +65,10 @@
set_operands(NULL);
set_pool_holder(NULL);
set_flags(0);
+
// only set to non-zero if constant pool is merged by RedefineClasses
set_version(0);
set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock"));
- // all fields are initialized; needed for GC
- set_on_stack(false);
// initialize tag array
int length = tags->length();
@@ -100,18 +99,6 @@
set_lock(NULL);
}
-void ConstantPool::set_flag_at(FlagBit fb) {
- const int MAX_STATE_CHANGES = 2;
- for (int i = MAX_STATE_CHANGES + 10; i > 0; i--) {
- int oflags = _flags;
- int nflags = oflags | (1 << (int)fb);
- if (Atomic::cmpxchg(nflags, &_flags, oflags) == oflags)
- return;
- }
- assert(false, "failed to cmpxchg flags");
- _flags |= (1 << (int)fb); // better than nothing
-}
-
objArrayOop ConstantPool::resolved_references() const {
return (objArrayOop)JNIHandles::resolve(_resolved_references);
}
@@ -1755,7 +1742,11 @@
void ConstantPool::set_on_stack(const bool value) {
- _on_stack = value;
+ if (value) {
+ _flags |= _on_stack;
+ } else {
+ _flags &= ~_on_stack;
+ }
if (value) MetadataOnStackMark::record(this);
}
@@ -1827,6 +1818,7 @@
if (has_pseudo_string()) st->print(" has_pseudo_string");
if (has_invokedynamic()) st->print(" has_invokedynamic");
if (has_preresolution()) st->print(" has_preresolution");
+ if (on_stack()) st->print(" on_stack");
st->cr();
}
if (pool_holder() != NULL) {
diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp
index 6554602..ea4b13f 100644
--- a/hotspot/src/share/vm/oops/constantPool.hpp
+++ b/hotspot/src/share/vm/oops/constantPool.hpp
@@ -95,10 +95,15 @@
jobject _resolved_references;
Array<u2>* _reference_map;
- int _flags; // a few header bits to describe contents for GC
- int _length; // number of elements in the array
+ enum {
+ _has_invokedynamic = 1, // Flags
+ _has_pseudo_string = 2,
+ _has_preresolution = 4,
+ _on_stack = 8
+ };
- bool _on_stack; // Redefined method still executing refers to this constant pool.
+ int _flags; // old fashioned bit twiddling
+ int _length; // number of elements in the array
union {
// set for CDS to restore resolved references
@@ -115,17 +120,8 @@
void set_operands(Array<u2>* operands) { _operands = operands; }
- enum FlagBit {
- FB_has_invokedynamic = 1,
- FB_has_pseudo_string = 2,
- FB_has_preresolution = 3
- };
-
- int flags() const { return _flags; }
- void set_flags(int f) { _flags = f; }
- 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
+ int flags() const { return _flags; }
+ void set_flags(int f) { _flags = f; }
private:
intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(ConstantPool)); }
@@ -178,18 +174,20 @@
Array<u1>* tags() const { return _tags; }
Array<u2>* operands() const { return _operands; }
- bool has_pseudo_string() const { return flag_at(FB_has_pseudo_string); }
- bool has_invokedynamic() const { return flag_at(FB_has_invokedynamic); }
- bool has_preresolution() const { return flag_at(FB_has_preresolution); }
- void set_pseudo_string() { set_flag_at(FB_has_pseudo_string); }
- void set_invokedynamic() { set_flag_at(FB_has_invokedynamic); }
- void set_preresolution() { set_flag_at(FB_has_preresolution); }
+ bool has_invokedynamic() const { return (_flags & _has_invokedynamic) != 0; }
+ void set_has_invokedynamic() { _flags |= _has_invokedynamic; }
+
+ bool has_pseudo_string() const { return (_flags & _has_pseudo_string) != 0; }
+ void set_has_pseudo_string() { _flags |= _has_pseudo_string; }
+
+ bool has_preresolution() const { return (_flags & _has_preresolution) != 0; }
+ void set_has_preresolution() { _flags |= _has_preresolution; }
// Redefine classes support. If a method refering to this constant pool
// is on the executing stack, or as a handle in vm code, this constant pool
// can't be removed from the set of previous versions saved in the instance
// class.
- bool on_stack() const { return _on_stack; }
+ bool on_stack() const { return (_flags &_on_stack) != 0; }
void set_on_stack(const bool value);
// Klass holding pool
@@ -457,7 +455,7 @@
void pseudo_string_at_put(int which, int obj_index, oop x) {
assert(EnableInvokeDynamic, "");
- set_pseudo_string(); // mark header
+ set_has_pseudo_string(); // mark header
assert(tag_at(which).is_string(), "Corrupted constant pool");
string_at_put(which, obj_index, x); // this works just fine
}
diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp
index 936090f..88645cb 100644
--- a/hotspot/src/share/vm/oops/method.cpp
+++ b/hotspot/src/share/vm/oops/method.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/metadataOnStackMark.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/debugInfoRec.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
@@ -41,7 +42,6 @@
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "prims/jvmtiExport.hpp"
-#include "prims/jvmtiRedefineClasses.hpp"
#include "prims/methodHandles.hpp"
#include "prims/nativeLookup.hpp"
#include "runtime/arguments.hpp"
@@ -1027,7 +1027,7 @@
cp->set_pool_holder(InstanceKlass::cast(holder()));
cp->symbol_at_put(_imcp_invoke_name, name);
cp->symbol_at_put(_imcp_invoke_signature, signature);
- cp->set_preresolution();
+ cp->set_has_preresolution();
// decide on access bits: public or not?
int flags_bits = (JVM_ACC_NATIVE | JVM_ACC_SYNTHETIC | JVM_ACC_FINAL);
diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
index 7e68f2b..7255579 100644
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/metadataOnStackMark.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verifier.hpp"
#include "code/codeCache.hpp"
@@ -115,43 +116,6 @@
return true;
}
-// Keep track of marked on-stack metadata so it can be cleared.
-GrowableArray<Metadata*>* _marked_objects = NULL;
-NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;)
-
-// Walk metadata on the stack and mark it so that redefinition doesn't delete
-// it. Class unloading also walks the previous versions and might try to
-// delete it, so this class is used by class unloading also.
-MetadataOnStackMark::MetadataOnStackMark() {
- assert(SafepointSynchronize::is_at_safepoint(), "sanity check");
- NOT_PRODUCT(_is_active = true;)
- if (_marked_objects == NULL) {
- _marked_objects = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(1000, true);
- }
- Threads::metadata_do(Metadata::mark_on_stack);
- CodeCache::alive_nmethods_do(nmethod::mark_on_stack);
- CompileBroker::mark_on_stack();
-}
-
-MetadataOnStackMark::~MetadataOnStackMark() {
- assert(SafepointSynchronize::is_at_safepoint(), "sanity check");
- // Unmark everything that was marked. Can't do the same walk because
- // redefine classes messes up the code cache so the set of methods
- // might not be the same.
- for (int i = 0; i< _marked_objects->length(); i++) {
- _marked_objects->at(i)->set_on_stack(false);
- }
- _marked_objects->clear(); // reuse growable array for next time.
- NOT_PRODUCT(_is_active = false;)
-}
-
-// Record which objects are marked so we can unmark the same objects.
-void MetadataOnStackMark::record(Metadata* m) {
- assert(_is_active, "metadata on stack marking is active");
- _marked_objects->push(m);
-}
-
-
void VM_RedefineClasses::doit() {
Thread *thread = Thread::current();
diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp
index 7164413..2383967 100644
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, 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
@@ -487,17 +487,4 @@
// and redefine implementation
static bool is_modifiable_class(oop klass_mirror);
};
-
-
-// Helper class to mark and unmark metadata used on the stack as either handles
-// or executing methods, so that it can't be deleted during class redefinition
-// and class unloading.
-class MetadataOnStackMark : public StackObj {
- NOT_PRODUCT(static bool _is_active;)
- public:
- MetadataOnStackMark() NOT_JVMTI_RETURN;
- ~MetadataOnStackMark() NOT_JVMTI_RETURN;
- static void record(Metadata* m) NOT_JVMTI_RETURN;
-};
-
#endif // SHARE_VM_PRIMS_JVMTIREDEFINECLASSES_HPP