# HG changeset patch # User coleenp # Date 1358955269 18000 # Node ID 5daaddd917a1a4f8c0d9c7c1f7227a5a09ea60ac # Parent 2ef7061f13b4d8ffb9aa640cad72bb38f70bd126 8006040: NPG: on_stack processing wastes space in ConstantPool Summary: Added on_stack bit to flags. Also MetadataMarkOnStack is used for more than JVMTI so had to be moved. Reviewed-by: dholmes, stefank diff -r 2ef7061f13b4 -r 5daaddd917a1 src/share/vm/classfile/classLoaderData.cpp --- a/src/share/vm/classfile/classLoaderData.cpp Tue Jan 22 11:54:16 2013 -0800 +++ b/src/share/vm/classfile/classLoaderData.cpp Wed Jan 23 10:34:29 2013 -0500 @@ -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 -r 2ef7061f13b4 -r 5daaddd917a1 src/share/vm/classfile/metadataOnStackMark.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/metadataOnStackMark.cpp Wed Jan 23 10:34:29 2013 -0500 @@ -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* _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(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 -r 2ef7061f13b4 -r 5daaddd917a1 src/share/vm/classfile/metadataOnStackMark.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/metadataOnStackMark.hpp Wed Jan 23 10:34:29 2013 -0500 @@ -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 -r 2ef7061f13b4 -r 5daaddd917a1 src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Tue Jan 22 11:54:16 2013 -0800 +++ b/src/share/vm/interpreter/linkResolver.cpp Wed Jan 23 10:34:29 2013 -0500 @@ -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(, method_name, method_signature, current_klass, pool, index, CHECK); Symbol* method_name = pool->name_ref_at(index); diff -r 2ef7061f13b4 -r 5daaddd917a1 src/share/vm/oops/constantPool.cpp --- a/src/share/vm/oops/constantPool.cpp Tue Jan 22 11:54:16 2013 -0800 +++ b/src/share/vm/oops/constantPool.cpp Wed Jan 23 10:34:29 2013 -0500 @@ -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 -r 2ef7061f13b4 -r 5daaddd917a1 src/share/vm/oops/constantPool.hpp --- a/src/share/vm/oops/constantPool.hpp Tue Jan 22 11:54:16 2013 -0800 +++ b/src/share/vm/oops/constantPool.hpp Wed Jan 23 10:34:29 2013 -0500 @@ -95,11 +95,16 @@ jobject _resolved_references; Array* _reference_map; - int _flags; // a few header bits to describe contents for GC + enum { + _has_invokedynamic = 1, // Flags + _has_pseudo_string = 2, + _has_preresolution = 4, + _on_stack = 8 + }; + + int _flags; // old fashioned bit twiddling int _length; // number of elements in the array - bool _on_stack; // Redefined method still executing refers to this constant pool. - union { // set for CDS to restore resolved references int _resolved_reference_length; @@ -115,17 +120,8 @@ void set_operands(Array* 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* tags() const { return _tags; } Array* 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 -r 2ef7061f13b4 -r 5daaddd917a1 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Tue Jan 22 11:54:16 2013 -0800 +++ b/src/share/vm/oops/method.cpp Wed Jan 23 10:34:29 2013 -0500 @@ -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 -r 2ef7061f13b4 -r 5daaddd917a1 src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Tue Jan 22 11:54:16 2013 -0800 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Jan 23 10:34:29 2013 -0500 @@ -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* _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(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 -r 2ef7061f13b4 -r 5daaddd917a1 src/share/vm/prims/jvmtiRedefineClasses.hpp --- a/src/share/vm/prims/jvmtiRedefineClasses.hpp Tue Jan 22 11:54:16 2013 -0800 +++ b/src/share/vm/prims/jvmtiRedefineClasses.hpp Wed Jan 23 10:34:29 2013 -0500 @@ -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