aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm/utilities
diff options
context:
space:
mode:
authorduke <none@none>2007-12-01 00:00:00 +0000
committerduke <none@none>2007-12-01 00:00:00 +0000
commitfa6b5a8027b86d2f8a200e72b4ef6a0d3f9189d3 (patch)
tree8376f6e5c41e70162b5867d9e1fea3f17f540473 /src/share/vm/utilities
Initial loadjdk7-b24
Diffstat (limited to 'src/share/vm/utilities')
-rw-r--r--src/share/vm/utilities/accessFlags.cpp73
-rw-r--r--src/share/vm/utilities/accessFlags.hpp204
-rw-r--r--src/share/vm/utilities/array.cpp88
-rw-r--r--src/share/vm/utilities/array.hpp264
-rw-r--r--src/share/vm/utilities/bitMap.cpp572
-rw-r--r--src/share/vm/utilities/bitMap.hpp396
-rw-r--r--src/share/vm/utilities/bitMap.inline.hpp105
-rw-r--r--src/share/vm/utilities/constantTag.cpp83
-rw-r--r--src/share/vm/utilities/constantTag.hpp86
-rw-r--r--src/share/vm/utilities/copy.cpp92
-rw-r--r--src/share/vm/utilities/copy.hpp332
-rw-r--r--src/share/vm/utilities/debug.cpp936
-rw-r--r--src/share/vm/utilities/debug.hpp129
-rw-r--r--src/share/vm/utilities/defaultStream.hpp90
-rw-r--r--src/share/vm/utilities/dtrace.hpp125
-rw-r--r--src/share/vm/utilities/events.cpp249
-rw-r--r--src/share/vm/utilities/events.hpp64
-rw-r--r--src/share/vm/utilities/exceptions.cpp388
-rw-r--r--src/share/vm/utilities/exceptions.hpp275
-rw-r--r--src/share/vm/utilities/globalDefinitions.cpp297
-rw-r--r--src/share/vm/utilities/globalDefinitions.hpp1101
-rw-r--r--src/share/vm/utilities/globalDefinitions_gcc.hpp275
-rw-r--r--src/share/vm/utilities/globalDefinitions_sparcWorks.hpp215
-rw-r--r--src/share/vm/utilities/globalDefinitions_visCPP.hpp193
-rw-r--r--src/share/vm/utilities/growableArray.cpp53
-rw-r--r--src/share/vm/utilities/growableArray.hpp331
-rw-r--r--src/share/vm/utilities/hashtable.cpp270
-rw-r--r--src/share/vm/utilities/hashtable.hpp280
-rw-r--r--src/share/vm/utilities/hashtable.inline.hpp126
-rw-r--r--src/share/vm/utilities/histogram.cpp100
-rw-r--r--src/share/vm/utilities/histogram.hpp91
-rw-r--r--src/share/vm/utilities/macros.hpp181
-rw-r--r--src/share/vm/utilities/ostream.cpp850
-rw-r--r--src/share/vm/utilities/ostream.hpp241
-rw-r--r--src/share/vm/utilities/preserveException.cpp89
-rw-r--r--src/share/vm/utilities/preserveException.hpp85
-rw-r--r--src/share/vm/utilities/sizes.cpp26
-rw-r--r--src/share/vm/utilities/sizes.hpp144
-rw-r--r--src/share/vm/utilities/taskqueue.cpp178
-rw-r--r--src/share/vm/utilities/taskqueue.hpp525
-rw-r--r--src/share/vm/utilities/top.hpp26
-rw-r--r--src/share/vm/utilities/utf8.cpp244
-rw-r--r--src/share/vm/utilities/utf8.hpp76
-rw-r--r--src/share/vm/utilities/vmError.cpp875
-rw-r--r--src/share/vm/utilities/vmError.hpp103
-rw-r--r--src/share/vm/utilities/workgroup.cpp444
-rw-r--r--src/share/vm/utilities/workgroup.hpp345
-rw-r--r--src/share/vm/utilities/xmlstream.cpp470
-rw-r--r--src/share/vm/utilities/xmlstream.hpp177
-rw-r--r--src/share/vm/utilities/yieldingWorkgroup.cpp396
-rw-r--r--src/share/vm/utilities/yieldingWorkgroup.hpp203
51 files changed, 13561 insertions, 0 deletions
diff --git a/src/share/vm/utilities/accessFlags.cpp b/src/share/vm/utilities/accessFlags.cpp
new file mode 100644
index 000000000..3ad8f1f00
--- /dev/null
+++ b/src/share/vm/utilities/accessFlags.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright 1997-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_accessFlags.cpp.incl"
+
+
+void AccessFlags::atomic_set_bits(jint bits) {
+ // Atomically update the flags with the bits given
+ jint old_flags, new_flags, f;
+ do {
+ old_flags = _flags;
+ new_flags = old_flags | bits;
+ f = Atomic::cmpxchg(new_flags, &_flags, old_flags);
+ } while(f != old_flags);
+}
+
+void AccessFlags::atomic_clear_bits(jint bits) {
+ // Atomically update the flags with the bits given
+ jint old_flags, new_flags, f;
+ do {
+ old_flags = _flags;
+ new_flags = old_flags & ~bits;
+ f = Atomic::cmpxchg(new_flags, &_flags, old_flags);
+ } while(f != old_flags);
+}
+
+#ifndef PRODUCT
+
+void AccessFlags::print_on(outputStream* st) const {
+ if (is_public ()) st->print("public " );
+ if (is_private ()) st->print("private " );
+ if (is_protected ()) st->print("protected " );
+ if (is_static ()) st->print("static " );
+ if (is_final ()) st->print("final " );
+ if (is_synchronized()) st->print("synchronized ");
+ if (is_volatile ()) st->print("volatile " );
+ if (is_transient ()) st->print("transient " );
+ if (is_native ()) st->print("native " );
+ if (is_interface ()) st->print("interface " );
+ if (is_abstract ()) st->print("abstract " );
+ if (is_strict ()) st->print("strict " );
+ if (is_synthetic ()) st->print("synthetic " );
+ if (is_old ()) st->print("{old} " );
+ if (is_obsolete ()) st->print("{obsolete} " );
+}
+
+#endif
+
+void accessFlags_init() {
+ assert(sizeof(AccessFlags) == sizeof(jint), "just checking size of flags");
+}
diff --git a/src/share/vm/utilities/accessFlags.hpp b/src/share/vm/utilities/accessFlags.hpp
new file mode 100644
index 000000000..4562be620
--- /dev/null
+++ b/src/share/vm/utilities/accessFlags.hpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// AccessFlags is an abstraction over Java access flags.
+
+
+enum {
+ // See jvm.h for shared JVM_ACC_XXX access flags
+
+ // HotSpot-specific access flags
+
+ // flags actually put in .class file
+ JVM_ACC_WRITTEN_FLAGS = 0x00007FFF,
+
+ // methodOop flags
+ JVM_ACC_MONITOR_MATCH = 0x10000000, // True if we know that monitorenter/monitorexit bytecodes match
+ JVM_ACC_HAS_MONITOR_BYTECODES = 0x20000000, // Method contains monitorenter/monitorexit bytecodes
+ JVM_ACC_HAS_LOOPS = 0x40000000, // Method has loops
+ JVM_ACC_LOOPS_FLAG_INIT = (int)0x80000000,// The loop flag has been initialized
+ JVM_ACC_QUEUED = 0x01000000, // Queued for compilation
+ JVM_ACC_NOT_TIER1_COMPILABLE = 0x04000000,
+ JVM_ACC_NOT_OSR_COMPILABLE = 0x08000000,
+ JVM_ACC_HAS_LINE_NUMBER_TABLE = 0x00100000,
+ JVM_ACC_HAS_CHECKED_EXCEPTIONS = 0x00400000,
+ JVM_ACC_HAS_JSRS = 0x00800000,
+ JVM_ACC_IS_OLD = 0x00010000, // RedefineClasses() has replaced this method
+ JVM_ACC_IS_OBSOLETE = 0x00020000, // RedefineClasses() has made method obsolete
+ JVM_ACC_IS_PREFIXED_NATIVE = 0x00040000, // JVMTI has prefixed this native method
+
+ // klassOop flags
+ JVM_ACC_HAS_MIRANDA_METHODS = 0x10000000, // True if this class has miranda methods in it's vtable
+ JVM_ACC_HAS_VANILLA_CONSTRUCTOR = 0x20000000, // True if klass has a vanilla default constructor
+ JVM_ACC_HAS_FINALIZER = 0x40000000, // True if klass has a non-empty finalize() method
+ JVM_ACC_IS_CLONEABLE = (int)0x80000000,// True if klass supports the Clonable interface
+ JVM_ACC_HAS_FINAL_METHOD = 0x01000000, // True if klass has final method
+
+ // klassOop and methodOop flags
+ JVM_ACC_HAS_LOCAL_VARIABLE_TABLE= 0x00200000,
+
+ JVM_ACC_PROMOTED_FLAGS = 0x00200000, // flags promoted from methods to the holding klass
+
+ // field flags
+ // Note: these flags must be defined in the low order 16 bits because
+ // instanceKlass only stores a ushort worth of information from the
+ // AccessFlags value.
+ // These bits must not conflict with any other field-related access flags
+ // (e.g., ACC_ENUM).
+ // Note that the class-related ACC_ANNOTATION bit conflicts with these flags.
+ JVM_ACC_FIELD_ACCESS_WATCHED = 0x00002000, // field access is watched by JVMTI
+ JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000, // field modification is watched by JVMTI
+
+ // flags accepted by set_field_flags()
+ JVM_ACC_FIELD_FLAGS = 0x00008000 | JVM_ACC_WRITTEN_FLAGS
+};
+
+
+class AccessFlags VALUE_OBJ_CLASS_SPEC {
+ friend class VMStructs;
+ private:
+ jint _flags;
+
+ public:
+ // Java access flags
+ bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; }
+ bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; }
+ bool is_protected () const { return (_flags & JVM_ACC_PROTECTED ) != 0; }
+ bool is_static () const { return (_flags & JVM_ACC_STATIC ) != 0; }
+ bool is_final () const { return (_flags & JVM_ACC_FINAL ) != 0; }
+ bool is_synchronized() const { return (_flags & JVM_ACC_SYNCHRONIZED) != 0; }
+ bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; }
+ bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; }
+ bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; }
+ bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; }
+ bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; }
+ bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; }
+ bool is_strict () const { return (_flags & JVM_ACC_STRICT ) != 0; }
+
+ // Attribute flags
+ bool is_synthetic () const { return (_flags & JVM_ACC_SYNTHETIC ) != 0; }
+
+ // methodOop flags
+ bool is_monitor_matching () const { return (_flags & JVM_ACC_MONITOR_MATCH ) != 0; }
+ bool has_monitor_bytecodes () const { return (_flags & JVM_ACC_HAS_MONITOR_BYTECODES ) != 0; }
+ bool has_loops () const { return (_flags & JVM_ACC_HAS_LOOPS ) != 0; }
+ bool loops_flag_init () const { return (_flags & JVM_ACC_LOOPS_FLAG_INIT ) != 0; }
+ bool queued_for_compilation () const { return (_flags & JVM_ACC_QUEUED ) != 0; }
+ bool is_not_tier1_compilable () const { return (_flags & JVM_ACC_NOT_TIER1_COMPILABLE ) != 0; }
+ bool is_not_osr_compilable () const { return (_flags & JVM_ACC_NOT_OSR_COMPILABLE ) != 0; }
+ bool has_linenumber_table () const { return (_flags & JVM_ACC_HAS_LINE_NUMBER_TABLE ) != 0; }
+ bool has_checked_exceptions () const { return (_flags & JVM_ACC_HAS_CHECKED_EXCEPTIONS ) != 0; }
+ bool has_jsrs () const { return (_flags & JVM_ACC_HAS_JSRS ) != 0; }
+ bool is_old () const { return (_flags & JVM_ACC_IS_OLD ) != 0; }
+ bool is_obsolete () const { return (_flags & JVM_ACC_IS_OBSOLETE ) != 0; }
+ bool is_prefixed_native () const { return (_flags & JVM_ACC_IS_PREFIXED_NATIVE ) != 0; }
+
+ // klassOop flags
+ bool has_miranda_methods () const { return (_flags & JVM_ACC_HAS_MIRANDA_METHODS ) != 0; }
+ bool has_vanilla_constructor () const { return (_flags & JVM_ACC_HAS_VANILLA_CONSTRUCTOR) != 0; }
+ bool has_finalizer () const { return (_flags & JVM_ACC_HAS_FINALIZER ) != 0; }
+ bool has_final_method () const { return (_flags & JVM_ACC_HAS_FINAL_METHOD ) != 0; }
+ bool is_cloneable () const { return (_flags & JVM_ACC_IS_CLONEABLE ) != 0; }
+ // klassOop and methodOop flags
+ bool has_localvariable_table () const { return (_flags & JVM_ACC_HAS_LOCAL_VARIABLE_TABLE) != 0; }
+ void set_has_localvariable_table() { atomic_set_bits(JVM_ACC_HAS_LOCAL_VARIABLE_TABLE); }
+ void clear_has_localvariable_table() { atomic_clear_bits(JVM_ACC_HAS_LOCAL_VARIABLE_TABLE); }
+
+ // field flags
+ bool is_field_access_watched() const { return (_flags & JVM_ACC_FIELD_ACCESS_WATCHED) != 0; }
+ bool is_field_modification_watched() const
+ { return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; }
+
+ // get .class file flags
+ jint get_flags () const { return (_flags & JVM_ACC_WRITTEN_FLAGS); }
+
+ // Initialization
+ void add_promoted_flags(jint flags) { _flags |= (flags & JVM_ACC_PROMOTED_FLAGS); }
+ void set_field_flags(jint flags) { _flags = (flags & JVM_ACC_FIELD_FLAGS); }
+ void set_flags(jint flags) { _flags = (flags & JVM_ACC_WRITTEN_FLAGS); }
+
+ void set_queued_for_compilation() { atomic_set_bits(JVM_ACC_QUEUED); }
+ void clear_queued_for_compilation() { atomic_clear_bits(JVM_ACC_QUEUED); }
+
+ // Atomic update of flags
+ void atomic_set_bits(jint bits);
+ void atomic_clear_bits(jint bits);
+
+ private:
+ friend class methodOopDesc;
+ friend class Klass;
+ friend class ClassFileParser;
+ // the functions below should only be called on the _access_flags inst var directly,
+ // otherwise they are just changing a copy of the flags
+
+ // attribute flags
+ void set_is_synthetic() { atomic_set_bits(JVM_ACC_SYNTHETIC); }
+
+ // methodOop flags
+ void set_monitor_matching() { atomic_set_bits(JVM_ACC_MONITOR_MATCH); }
+ void set_has_monitor_bytecodes() { atomic_set_bits(JVM_ACC_HAS_MONITOR_BYTECODES); }
+ void set_has_loops() { atomic_set_bits(JVM_ACC_HAS_LOOPS); }
+ void set_loops_flag_init() { atomic_set_bits(JVM_ACC_LOOPS_FLAG_INIT); }
+ void set_not_tier1_compilable() { atomic_set_bits(JVM_ACC_NOT_TIER1_COMPILABLE); }
+ void set_not_osr_compilable() { atomic_set_bits(JVM_ACC_NOT_OSR_COMPILABLE); }
+ void set_has_linenumber_table() { atomic_set_bits(JVM_ACC_HAS_LINE_NUMBER_TABLE); }
+ void set_has_checked_exceptions() { atomic_set_bits(JVM_ACC_HAS_CHECKED_EXCEPTIONS); }
+ void set_has_jsrs() { atomic_set_bits(JVM_ACC_HAS_JSRS); }
+ void set_is_old() { atomic_set_bits(JVM_ACC_IS_OLD); }
+ void set_is_obsolete() { atomic_set_bits(JVM_ACC_IS_OBSOLETE); }
+ void set_is_prefixed_native() { atomic_set_bits(JVM_ACC_IS_PREFIXED_NATIVE); }
+
+ // klassOop flags
+ void set_has_vanilla_constructor() { atomic_set_bits(JVM_ACC_HAS_VANILLA_CONSTRUCTOR); }
+ void set_has_finalizer() { atomic_set_bits(JVM_ACC_HAS_FINALIZER); }
+ void set_has_final_method() { atomic_set_bits(JVM_ACC_HAS_FINAL_METHOD); }
+ void set_is_cloneable() { atomic_set_bits(JVM_ACC_IS_CLONEABLE); }
+ void set_has_miranda_methods() { atomic_set_bits(JVM_ACC_HAS_MIRANDA_METHODS); }
+
+ public:
+ // field flags
+ void set_is_field_access_watched(const bool value)
+ {
+ if (value) {
+ atomic_set_bits(JVM_ACC_FIELD_ACCESS_WATCHED);
+ } else {
+ atomic_clear_bits(JVM_ACC_FIELD_ACCESS_WATCHED);
+ }
+ }
+ void set_is_field_modification_watched(const bool value)
+ {
+ if (value) {
+ atomic_set_bits(JVM_ACC_FIELD_MODIFICATION_WATCHED);
+ } else {
+ atomic_clear_bits(JVM_ACC_FIELD_MODIFICATION_WATCHED);
+ }
+ }
+
+ // Conversion
+ jshort as_short() { return (jshort)_flags; }
+ jint as_int() { return _flags; }
+
+ // Printing/debugging
+ void print_on(outputStream* st) const PRODUCT_RETURN;
+};
diff --git a/src/share/vm/utilities/array.cpp b/src/share/vm/utilities/array.cpp
new file mode 100644
index 000000000..22b452330
--- /dev/null
+++ b/src/share/vm/utilities/array.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_array.cpp.incl"
+
+
+#ifdef ASSERT
+void ResourceArray::init_nesting() {
+ _nesting = Thread::current()->resource_area()->nesting();
+}
+#endif
+
+
+void ResourceArray::sort(size_t esize, ftype f) {
+ if (!is_empty()) qsort(_data, length(), esize, f);
+}
+void CHeapArray::sort(size_t esize, ftype f) {
+ if (!is_empty()) qsort(_data, length(), esize, f);
+}
+
+
+void ResourceArray::expand(size_t esize, int i, int& size) {
+ // make sure we are expanding within the original resource mark
+ assert(
+ _nesting == Thread::current()->resource_area()->nesting(),
+ "allocating outside original resource mark"
+ );
+ // determine new size
+ if (size == 0) size = 4; // prevent endless loop
+ while (i >= size) size *= 2;
+ // allocate and initialize new data section
+ void* data = resource_allocate_bytes(esize * size);
+ memcpy(data, _data, esize * length());
+ _data = data;
+}
+
+
+void CHeapArray::expand(size_t esize, int i, int& size) {
+ // determine new size
+ if (size == 0) size = 4; // prevent endless loop
+ while (i >= size) size *= 2;
+ // allocate and initialize new data section
+ void* data = NEW_C_HEAP_ARRAY(char*, esize * size);
+ memcpy(data, _data, esize * length());
+ FREE_C_HEAP_ARRAY(char*, _data);
+ _data = data;
+}
+
+
+void ResourceArray::remove_at(size_t esize, int i) {
+ assert(0 <= i && i < length(), "index out of bounds");
+ _length--;
+ void* dst = (char*)_data + i*esize;
+ void* src = (char*)dst + esize;
+ size_t cnt = (length() - i)*esize;
+ memmove(dst, src, cnt);
+}
+
+void CHeapArray::remove_at(size_t esize, int i) {
+ assert(0 <= i && i < length(), "index out of bounds");
+ _length--;
+ void* dst = (char*)_data + i*esize;
+ void* src = (char*)dst + esize;
+ size_t cnt = (length() - i)*esize;
+ memmove(dst, src, cnt);
+}
diff --git a/src/share/vm/utilities/array.hpp b/src/share/vm/utilities/array.hpp
new file mode 100644
index 000000000..1c229505f
--- /dev/null
+++ b/src/share/vm/utilities/array.hpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2000-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// correct linkage required to compile w/o warnings
+// (must be on file level - cannot be local)
+extern "C" { typedef int (*ftype)(const void*, const void*); }
+
+
+class ResourceArray: public ResourceObj {
+ protected:
+ int _length; // the number of array elements
+ void* _data; // the array memory
+#ifdef ASSERT
+ int _nesting; // the resource area nesting level
+#endif
+
+ // creation
+ ResourceArray() {
+ _length = 0;
+ _data = NULL;
+ DEBUG_ONLY(init_nesting();)
+ }
+
+
+ ResourceArray(size_t esize, int length) {
+ assert(length >= 0, "illegal length");
+ _length = length;
+ _data = resource_allocate_bytes(esize * length);
+ DEBUG_ONLY(init_nesting();)
+ }
+
+#ifdef ASSERT
+ void init_nesting();
+#endif
+
+ // helper functions
+ void sort (size_t esize, ftype f); // sort the array
+ void expand (size_t esize, int i, int& size);// expand the array to include slot i
+ void remove_at(size_t esize, int i); // remove the element in slot i
+
+ public:
+ // standard operations
+ int length() const { return _length; }
+ bool is_empty() const { return length() == 0; }
+};
+
+
+class CHeapArray: public CHeapObj {
+ protected:
+ int _length; // the number of array elements
+ void* _data; // the array memory
+
+ // creation
+ CHeapArray() {
+ _length = 0;
+ _data = NULL;
+ }
+
+
+ CHeapArray(size_t esize, int length) {
+ assert(length >= 0, "illegal length");
+ _length = length;
+ _data = (void*) NEW_C_HEAP_ARRAY(char *, esize * length);
+ }
+
+#ifdef ASSERT
+ void init_nesting();
+#endif
+
+ // helper functions
+ void sort (size_t esize, ftype f); // sort the array
+ void expand (size_t esize, int i, int& size);// expand the array to include slot i
+ void remove_at(size_t esize, int i); // remove the element in slot i
+
+ public:
+ // standard operations
+ int length() const { return _length; }
+ bool is_empty() const { return length() == 0; }
+};
+
+#define define_generic_array(array_name,element_type, base_class) \
+ class array_name: public base_class { \
+ protected: \
+ typedef element_type etype; \
+ enum { esize = sizeof(etype) }; \
+ \
+ void base_remove_at(size_t size, int i) { base_class::remove_at(size, i); } \
+ \
+ public: \
+ /* creation */ \
+ array_name() : base_class() {} \
+ array_name(const int length) : base_class(esize, length) {} \
+ array_name(const int length, const etype fx) : base_class(esize, length) { \
+ for (int i = 0; i < length; i++) ((etype*)_data)[i] = fx; \
+ } \
+ \
+ /* standard operations */ \
+ etype& operator [] (const int i) const { \
+ assert(0 <= i && i < length(), "index out of bounds"); \
+ return ((etype*)_data)[i]; \
+ } \
+ \
+ int index_of(const etype x) const { \
+ int i = length(); \
+ while (i-- > 0 && ((etype*)_data)[i] != x) ; \
+ /* i < 0 || ((etype*)_data)_data[i] == x */ \
+ return i; \
+ } \
+ \
+ void sort(int f(etype*, etype*)) { base_class::sort(esize, (ftype)f); } \
+ bool contains(const etype x) const { return index_of(x) >= 0; } \
+ \
+ /* deprecated operations - for compatibility with GrowableArray only */ \
+ etype at(const int i) const { return (*this)[i]; } \
+ void at_put(const int i, const etype x) { (*this)[i] = x; } \
+ etype* adr_at(const int i) { return &(*this)[i]; } \
+ int find(const etype x) { return index_of(x); } \
+ }; \
+
+
+#define define_array(array_name,element_type) \
+ define_generic_array(array_name, element_type, ResourceArray)
+
+
+#define define_stack(stack_name,array_name) \
+ class stack_name: public array_name { \
+ protected: \
+ int _size; \
+ \
+ void grow(const int i, const etype fx) { \
+ assert(i >= length(), "index too small"); \
+ if (i >= size()) expand(esize, i, _size); \
+ for (int j = length(); j <= i; j++) ((etype*)_data)[j] = fx; \
+ _length = i+1; \
+ } \
+ \
+ public: \
+ /* creation */ \
+ stack_name() : array_name() { _size = 0; } \
+ stack_name(const int size) : array_name(size){ _length = 0; _size = size; } \
+ stack_name(const int size, const etype fx) : array_name(size, fx) { _size = size; } \
+ \
+ /* standard operations */ \
+ int size() const { return _size; } \
+ \
+ void push(const etype x) { \
+ if (length() >= size()) expand(esize, length(), _size); \
+ ((etype*)_data)[_length++] = x; \
+ } \
+ \
+ etype pop() { \
+ assert(!is_empty(), "stack is empty"); \
+ return ((etype*)_data)[--_length]; \
+ } \
+ \
+ etype top() const { \
+ assert(!is_empty(), "stack is empty"); \
+ return ((etype*)_data)[length() - 1]; \
+ } \
+ \
+ void push_all(const stack_name* stack) { \
+ const int l = stack->length(); \
+ for (int i = 0; i < l; i++) push(((etype*)(stack->_data))[i]); \
+ } \
+ \
+ etype at_grow(const int i, const etype fx) { \
+ if (i >= length()) grow(i, fx); \
+ return ((etype*)_data)[i]; \
+ } \
+ \
+ void at_put_grow(const int i, const etype x, const etype fx) { \
+ if (i >= length()) grow(i, fx); \
+ ((etype*)_data)[i] = x; \
+ } \
+ \
+ void truncate(const int length) { \
+ assert(0 <= length && length <= this->length(), "illegal length"); \
+ _length = length; \
+ } \
+ \
+ void remove_at(int i) { base_remove_at(esize, i); } \
+ void remove(etype x) { remove_at(index_of(x)); } \
+ \
+ /* inserts the given element before the element at index i */ \
+ void insert_before(const int i, const etype el) { \
+ int len = length(); \
+ int new_length = len + 1; \
+ if (new_length >= size()) expand(esize, new_length, _size); \
+ for (int j = len - 1; j >= i; j--) { \
+ ((etype*)_data)[j + 1] = ((etype*)_data)[j]; \
+ } \
+ _length = new_length; \
+ at_put(i, el); \
+ } \
+ \
+ /* inserts contents of the given stack before the element at index i */ \
+ void insert_before(const int i, const stack_name *st) { \
+ if (st->length() == 0) return; \
+ int len = length(); \
+ int st_len = st->length(); \
+ int new_length = len + st_len; \
+ if (new_length >= size()) expand(esize, new_length, _size); \
+ int j; \
+ for (j = len - 1; j >= i; j--) { \
+ ((etype*)_data)[j + st_len] = ((etype*)_data)[j]; \
+ } \
+ for (j = 0; j < st_len; j++) { \
+ ((etype*)_data)[i + j] = ((etype*)st->_data)[j]; \
+ } \
+ _length = new_length; \
+ } \
+ \
+ /* deprecated operations - for compatibility with GrowableArray only */ \
+ int capacity() const { return size(); } \
+ void clear() { truncate(0); } \
+ void trunc_to(const int length) { truncate(length); } \
+ void append(const etype x) { push(x); } \
+ void appendAll(const stack_name* stack) { push_all(stack); } \
+ etype last() const { return top(); } \
+ }; \
+
+
+#define define_resource_list(element_type) \
+ define_generic_array(element_type##Array, element_type, ResourceArray) \
+ define_stack(element_type##List, element_type##Array)
+
+#define define_resource_pointer_list(element_type) \
+ define_generic_array(element_type##Array, element_type *, ResourceArray) \
+ define_stack(element_type##List, element_type##Array)
+
+#define define_c_heap_list(element_type) \
+ define_generic_array(element_type##Array, element_type, CHeapArray) \
+ define_stack(element_type##List, element_type##Array)
+
+#define define_c_heap_pointer_list(element_type) \
+ define_generic_array(element_type##Array, element_type *, CHeapArray) \
+ define_stack(element_type##List, element_type##Array)
+
+
+// Arrays for basic types
+
+define_array(boolArray, bool) define_stack(boolStack, boolArray)
+define_array(intArray , int ) define_stack(intStack , intArray )
diff --git a/src/share/vm/utilities/bitMap.cpp b/src/share/vm/utilities/bitMap.cpp
new file mode 100644
index 000000000..b1d466b3e
--- /dev/null
+++ b/src/share/vm/utilities/bitMap.cpp
@@ -0,0 +1,572 @@
+/*
+ * Copyright 1997-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_bitMap.cpp.incl"
+
+
+BitMap::BitMap(idx_t* map, idx_t size_in_bits) {
+ assert(size_in_bits >= 0, "just checking");
+ _map = map;
+ _size = size_in_bits;
+}
+
+
+BitMap::BitMap(idx_t size_in_bits) {
+ assert(size_in_bits >= 0, "just checking");
+ _size = size_in_bits;
+ _map = NEW_RESOURCE_ARRAY(idx_t, size_in_words());
+}
+
+
+void BitMap::resize(idx_t size_in_bits) {
+ assert(size_in_bits >= 0, "just checking");
+ size_t old_size_in_words = size_in_words();
+ uintptr_t* old_map = map();
+ _size = size_in_bits;
+ size_t new_size_in_words = size_in_words();
+ _map = NEW_RESOURCE_ARRAY(idx_t, new_size_in_words);
+ Copy::disjoint_words((HeapWord*) old_map, (HeapWord*) _map, MIN2(old_size_in_words, new_size_in_words));
+ if (new_size_in_words > old_size_in_words) {
+ clear_range_of_words(old_size_in_words, size_in_words());
+ }
+}
+
+// Returns a bit mask for a range of bits [beg, end) within a single word. Each
+// bit in the mask is 0 if the bit is in the range, 1 if not in the range. The
+// returned mask can be used directly to clear the range, or inverted to set the
+// range. Note: end must not be 0.
+inline BitMap::idx_t
+BitMap::inverted_bit_mask_for_range(idx_t beg, idx_t end) const {
+ assert(end != 0, "does not work when end == 0");
+ assert(beg == end || word_index(beg) == word_index(end - 1),
+ "must be a single-word range");
+ idx_t mask = bit_mask(beg) - 1; // low (right) bits
+ if (bit_in_word(end) != 0) {
+ mask |= ~(bit_mask(end) - 1); // high (left) bits
+ }
+ return mask;
+}
+
+void BitMap::set_range_within_word(idx_t beg, idx_t end) {
+ // With a valid range (beg <= end), this test ensures that end != 0, as
+ // required by inverted_bit_mask_for_range. Also avoids an unnecessary write.
+ if (beg != end) {
+ idx_t mask = inverted_bit_mask_for_range(beg, end);
+ *word_addr(beg) |= ~mask;
+ }
+}
+
+void BitMap::clear_range_within_word(idx_t beg, idx_t end) {
+ // With a valid range (beg <= end), this test ensures that end != 0, as
+ // required by inverted_bit_mask_for_range. Also avoids an unnecessary write.
+ if (beg != end) {
+ idx_t mask = inverted_bit_mask_for_range(beg, end);
+ *word_addr(beg) &= mask;
+ }
+}
+
+void BitMap::par_put_range_within_word(idx_t beg, idx_t end, bool value) {
+ assert(value == 0 || value == 1, "0 for clear, 1 for set");
+ // With a valid range (beg <= end), this test ensures that end != 0, as
+ // required by inverted_bit_mask_for_range. Also avoids an unnecessary write.
+ if (beg != end) {
+ intptr_t* pw = (intptr_t*)word_addr(beg);
+ intptr_t w = *pw;
+ intptr_t mr = (intptr_t)inverted_bit_mask_for_range(beg, end);
+ intptr_t nw = value ? (w | ~mr) : (w & mr);
+ while (true) {
+ intptr_t res = Atomic::cmpxchg_ptr(nw, pw, w);
+ if (res == w) break;
+ w = *pw;
+ nw = value ? (w | ~mr) : (w & mr);
+ }
+ }
+}
+
+inline void BitMap::set_large_range_of_words(idx_t beg, idx_t end) {
+ memset(_map + beg, ~(unsigned char)0, (end - beg) * sizeof(uintptr_t));
+}
+
+inline void BitMap::clear_large_range_of_words(idx_t beg, idx_t end) {
+ memset(_map + beg, 0, (end - beg) * sizeof(uintptr_t));
+}
+
+inline BitMap::idx_t BitMap::word_index_round_up(idx_t bit) const {
+ idx_t bit_rounded_up = bit + (BitsPerWord - 1);
+ // Check for integer arithmetic overflow.
+ return bit_rounded_up > bit ? word_index(bit_rounded_up) : size_in_words();
+}
+
+void BitMap::set_range(idx_t beg, idx_t end) {
+ verify_range(beg, end);
+
+ idx_t beg_full_word = word_index_round_up(beg);
+ idx_t end_full_word = word_index(end);
+
+ if (beg_full_word < end_full_word) {
+ // The range includes at least one full word.
+ set_range_within_word(beg, bit_index(beg_full_word));
+ set_range_of_words(beg_full_word, end_full_word);
+ set_range_within_word(bit_index(end_full_word), end);
+ } else {
+ // The range spans at most 2 partial words.
+ idx_t boundary = MIN2(bit_index(beg_full_word), end);
+ set_range_within_word(beg, boundary);
+ set_range_within_word(boundary, end);
+ }
+}
+
+void BitMap::clear_range(idx_t beg, idx_t end) {
+ verify_range(beg, end);
+
+ idx_t beg_full_word = word_index_round_up(beg);
+ idx_t end_full_word = word_index(end);
+
+ if (beg_full_word < end_full_word) {
+ // The range includes at least one full word.
+ clear_range_within_word(beg, bit_index(beg_full_word));
+ clear_range_of_words(beg_full_word, end_full_word);
+ clear_range_within_word(bit_index(end_full_word), end);
+ } else {
+ // The range spans at most 2 partial words.
+ idx_t boundary = MIN2(bit_index(beg_full_word), end);
+ clear_range_within_word(beg, boundary);
+ clear_range_within_word(boundary, end);
+ }
+}
+
+void BitMap::set_large_range(idx_t beg, idx_t end) {
+ verify_range(beg, end);
+
+ idx_t beg_full_word = word_index_round_up(beg);
+ idx_t end_full_word = word_index(end);
+
+ assert(end_full_word - beg_full_word >= 32,
+ "the range must include at least 32 bytes");
+
+ // The range includes at least one full word.
+ set_range_within_word(beg, bit_index(beg_full_word));
+ set_large_range_of_words(beg_full_word, end_full_word);
+ set_range_within_word(bit_index(end_full_word), end);
+}
+
+void BitMap::clear_large_range(idx_t beg, idx_t end) {
+ verify_range(beg, end);
+
+ idx_t beg_full_word = word_index_round_up(beg);
+ idx_t end_full_word = word_index(end);
+
+ assert(end_full_word - beg_full_word >= 32,
+ "the range must include at least 32 bytes");
+
+ // The range includes at least one full word.
+ clear_range_within_word(beg, bit_index(beg_full_word));
+ clear_large_range_of_words(beg_full_word, end_full_word);
+ clear_range_within_word(bit_index(end_full_word), end);
+}
+
+void BitMap::at_put(idx_t offset, bool value) {
+ if (value) {
+ set_bit(offset);
+ } else {
+ clear_bit(offset);
+ }
+}
+
+// Return true to indicate that this thread changed
+// the bit, false to indicate that someone else did.
+// In either case, the requested bit is in the
+// requested state some time during the period that
+// this thread is executing this call. More importantly,
+// if no other thread is executing an action to
+// change the requested bit to a state other than
+// the one that this thread is trying to set it to,
+// then the the bit is in the expected state
+// at exit from this method. However, rather than
+// make such a strong assertion here, based on
+// assuming such constrained use (which though true
+// today, could change in the future to service some
+// funky parallel algorithm), we encourage callers
+// to do such verification, as and when appropriate.
+bool BitMap::par_at_put(idx_t bit, bool value) {
+ return value ? par_set_bit(bit) : par_clear_bit(bit);
+}
+
+void BitMap::at_put_grow(idx_t offset, bool value) {
+ if (offset >= size()) {
+ resize(2 * MAX2(size(), offset));
+ }
+ at_put(offset, value);
+}
+
+void BitMap::at_put_range(idx_t start_offset, idx_t end_offset, bool value) {
+ if (value) {
+ set_range(start_offset, end_offset);
+ } else {
+ clear_range(start_offset, end_offset);
+ }
+}
+
+void BitMap::par_at_put_range(idx_t beg, idx_t end, bool value) {
+ verify_range(beg, end);
+
+ idx_t beg_full_word = word_index_round_up(beg);
+ idx_t end_full_word = word_index(end);
+
+ if (beg_full_word < end_full_word) {
+ // The range includes at least one full word.
+ par_put_range_within_word(beg, bit_index(beg_full_word), value);
+ if (value) {
+ set_range_of_words(beg_full_word, end_full_word);
+ } else {
+ clear_range_of_words(beg_full_word, end_full_word);
+ }
+ par_put_range_within_word(bit_index(end_full_word), end, value);
+ } else {
+ // The range spans at most 2 partial words.
+ idx_t boundary = MIN2(bit_index(beg_full_word), end);
+ par_put_range_within_word(beg, boundary, value);
+ par_put_range_within_word(boundary, end, value);
+ }
+
+}
+
+void BitMap::at_put_large_range(idx_t beg, idx_t end, bool value) {
+ if (value) {
+ set_large_range(beg, end);
+ } else {
+ clear_large_range(beg, end);
+ }
+}
+
+void BitMap::par_at_put_large_range(idx_t beg, idx_t end, bool value) {
+ verify_range(beg, end);
+
+ idx_t beg_full_word = word_index_round_up(beg);
+ idx_t end_full_word = word_index(end);
+
+ assert(end_full_word - beg_full_word >= 32,
+ "the range must include at least 32 bytes");
+
+ // The range includes at least one full word.
+ par_put_range_within_word(beg, bit_index(beg_full_word), value);
+ if (value) {
+ set_large_range_of_words(beg_full_word, end_full_word);
+ } else {
+ clear_large_range_of_words(beg_full_word, end_full_word);
+ }
+ par_put_range_within_word(bit_index(end_full_word), end, value);
+}
+
+bool BitMap::contains(const BitMap other) const {
+ assert(size() == other.size(), "must have same size");
+ uintptr_t* dest_map = map();
+ uintptr_t* other_map = other.map();
+ idx_t size = size_in_words();
+ for (idx_t index = 0; index < size_in_words(); index++) {
+ uintptr_t word_union = dest_map[index] | other_map[index];
+ // If this has more bits set than dest_map[index], then other is not a
+ // subset.
+ if (word_union != dest_map[index]) return false;
+ }
+ return true;
+}
+
+bool BitMap::intersects(const BitMap other) const {
+ assert(size() == other.size(), "must have same size");
+ uintptr_t* dest_map = map();
+ uintptr_t* other_map = other.map();
+ idx_t size = size_in_words();
+ for (idx_t index = 0; index < size_in_words(); index++) {
+ if ((dest_map[index] & other_map[index]) != 0) return true;
+ }
+ // Otherwise, no intersection.
+ return false;
+}
+
+void BitMap::set_union(BitMap other) {
+ assert(size() == other.size(), "must have same size");
+ idx_t* dest_map = map();
+ idx_t* other_map = other.map();
+ idx_t size = size_in_words();
+ for (idx_t index = 0; index < size_in_words(); index++) {
+ dest_map[index] = dest_map[index] | other_map[index];
+ }
+}
+
+
+void BitMap::set_difference(BitMap other) {
+ assert(size() == other.size(), "must have same size");
+ idx_t* dest_map = map();
+ idx_t* other_map = other.map();
+ idx_t size = size_in_words();
+ for (idx_t index = 0; index < size_in_words(); index++) {
+ dest_map[index] = dest_map[index] & ~(other_map[index]);
+ }
+}
+
+
+void BitMap::set_intersection(BitMap other) {
+ assert(size() == other.size(), "must have same size");
+ idx_t* dest_map = map();
+ idx_t* other_map = other.map();
+ idx_t size = size_in_words();
+ for (idx_t index = 0; index < size; index++) {
+ dest_map[index] = dest_map[index] & other_map[index];
+ }
+}
+
+
+bool BitMap::set_union_with_result(BitMap other) {
+ assert(size() == other.size(), "must have same size");
+ bool changed = false;
+ idx_t* dest_map = map();
+ idx_t* other_map = other.map();
+ idx_t size = size_in_words();
+ for (idx_t index = 0; index < size; index++) {
+ idx_t temp = map(index) | other_map[index];
+ changed = changed || (temp != map(index));
+ map()[index] = temp;
+ }
+ return changed;
+}
+
+
+bool BitMap::set_difference_with_result(BitMap other) {
+ assert(size() == other.size(), "must have same size");
+ bool changed = false;
+ idx_t* dest_map = map();
+ idx_t* other_map = other.map();
+ idx_t size = size_in_words();
+ for (idx_t index = 0; index < size; index++) {
+ idx_t temp = dest_map[index] & ~(other_map[index]);
+ changed = changed || (temp != dest_map[index]);
+ dest_map[index] = temp;
+ }
+ return changed;
+}
+
+
+bool BitMap::set_intersection_with_result(BitMap other) {
+ assert(size() == other.size(), "must have same size");
+ bool changed = false;
+ idx_t* dest_map = map();
+ idx_t* other_map = other.map();
+ idx_t size = size_in_words();
+ for (idx_t index = 0; index < size; index++) {
+ idx_t orig = dest_map[index];
+ idx_t temp = orig & other_map[index];
+ changed = changed || (temp != orig);
+ dest_map[index] = temp;
+ }
+ return changed;
+}
+
+
+void BitMap::set_from(BitMap other) {
+ assert(size() == other.size(), "must have same size");
+ idx_t* dest_map = map();
+ idx_t* other_map = other.map();
+ idx_t size = size_in_words();
+ for (idx_t index = 0; index < size; index++) {
+ dest_map[index] = other_map[index];
+ }
+}
+
+
+bool BitMap::is_same(BitMap other) {
+ assert(size() == other.size(), "must have same size");
+ idx_t* dest_map = map();
+ idx_t* other_map = other.map();
+ idx_t size = size_in_words();
+ for (idx_t index = 0; index < size; index++) {
+ if (dest_map[index] != other_map[index]) return false;
+ }
+ return true;
+}
+
+bool BitMap::is_full() const {
+ uintptr_t* word = map();
+ idx_t rest = size();
+ for (; rest >= (idx_t) BitsPerWord; rest -= BitsPerWord) {
+ if (*word != (uintptr_t) AllBits) return false;
+ word++;
+ }
+ return rest == 0 || (*word | ~right_n_bits((int)rest)) == (uintptr_t) AllBits;
+}
+
+
+bool BitMap::is_empty() const {
+ uintptr_t* word = map();
+ idx_t rest = size();
+ for (; rest >= (idx_t) BitsPerWord; rest -= BitsPerWord) {
+ if (*word != (uintptr_t) NoBits) return false;
+ word++;
+ }
+ return rest == 0 || (*word & right_n_bits((int)rest)) == (uintptr_t) NoBits;
+}
+
+void BitMap::clear_large() {
+ clear_large_range_of_words(0, size_in_words());
+}
+
+// Note that if the closure itself modifies the bitmap
+// then modifications in and to the left of the _bit_ being
+// currently sampled will not be seen. Note also that the
+// interval [leftOffset, rightOffset) is right open.
+void BitMap::iterate(BitMapClosure* blk, idx_t leftOffset, idx_t rightOffset) {
+ verify_range(leftOffset, rightOffset);
+
+ idx_t startIndex = word_index(leftOffset);
+ idx_t endIndex = MIN2(word_index(rightOffset) + 1, size_in_words());
+ for (idx_t index = startIndex, offset = leftOffset;
+ offset < rightOffset && index < endIndex;
+ offset = (++index) << LogBitsPerWord) {
+ idx_t rest = map(index) >> (offset & (BitsPerWord - 1));
+ for (; offset < rightOffset && rest != (uintptr_t)NoBits; offset++) {
+ if (rest & 1) {
+ blk->do_bit(offset);
+ // resample at each closure application
+ // (see, for instance, CMS bug 4525989)
+ rest = map(index) >> (offset & (BitsPerWord -1));
+ // XXX debugging: remove
+ // The following assertion assumes that closure application
+ // doesn't clear bits (may not be true in general, e.g. G1).
+ assert(rest & 1,
+ "incorrect shift or closure application can clear bits?");
+ }
+ rest = rest >> 1;
+ }
+ }
+}
+
+BitMap::idx_t BitMap::get_next_one_offset(idx_t l_offset,
+ idx_t r_offset) const {
+ assert(l_offset <= size(), "BitMap index out of bounds");
+ assert(r_offset <= size(), "BitMap index out of bounds");
+ assert(l_offset <= r_offset, "l_offset > r_offset ?");
+
+ if (l_offset == r_offset) {
+ return l_offset;
+ }
+ idx_t index = word_index(l_offset);
+ idx_t r_index = word_index(r_offset-1) + 1;
+ idx_t res_offset = l_offset;
+
+ // check bits including and to the _left_ of offset's position
+ idx_t pos = bit_in_word(res_offset);
+ idx_t res = map(index) >> pos;
+ if (res != (uintptr_t)NoBits) {
+ // find the position of the 1-bit
+ for (; !(res & 1); res_offset++) {
+ res = res >> 1;
+ }
+ assert(res_offset >= l_offset, "just checking");
+ return MIN2(res_offset, r_offset);
+ }
+ // skip over all word length 0-bit runs
+ for (index++; index < r_index; index++) {
+ res = map(index);
+ if (res != (uintptr_t)NoBits) {
+ // found a 1, return the offset
+ for (res_offset = index << LogBitsPerWord; !(res & 1);
+ res_offset++) {
+ res = res >> 1;
+ }
+ assert(res & 1, "tautology; see loop condition");
+ assert(res_offset >= l_offset, "just checking");
+ return MIN2(res_offset, r_offset);
+ }
+ }
+ return r_offset;
+}
+
+BitMap::idx_t BitMap::get_next_zero_offset(idx_t l_offset,
+ idx_t r_offset) const {
+ assert(l_offset <= size(), "BitMap index out of bounds");
+ assert(r_offset <= size(), "BitMap index out of bounds");
+ assert(l_offset <= r_offset, "l_offset > r_offset ?");
+
+ if (l_offset == r_offset) {
+ return l_offset;
+ }
+ idx_t index = word_index(l_offset);
+ idx_t r_index = word_index(r_offset-1) + 1;
+ idx_t res_offset = l_offset;
+
+ // check bits including and to the _left_ of offset's position
+ idx_t pos = res_offset & (BitsPerWord - 1);
+ idx_t res = (map(index) >> pos) | left_n_bits((int)pos);
+
+ if (res != (uintptr_t)AllBits) {
+ // find the position of the 0-bit
+ for (; res & 1; res_offset++) {
+ res = res >> 1;
+ }
+ assert(res_offset >= l_offset, "just checking");
+ return MIN2(res_offset, r_offset);
+ }
+ // skip over all word length 1-bit runs
+ for (index++; index < r_index; index++) {
+ res = map(index);
+ if (res != (uintptr_t)AllBits) {
+ // found a 0, return the offset
+ for (res_offset = index << LogBitsPerWord; res & 1;
+ res_offset++) {
+ res = res >> 1;
+ }
+ assert(!(res & 1), "tautology; see loop condition");
+ assert(res_offset >= l_offset, "just checking");
+ return MIN2(res_offset, r_offset);
+ }
+ }
+ return r_offset;
+}
+
+#ifndef PRODUCT
+
+void BitMap::print_on(outputStream* st) const {
+ tty->print("Bitmap(%d):", size());
+ for (idx_t index = 0; index < size(); index++) {
+ tty->print("%c", at(index) ? '1' : '0');
+ }
+ tty->cr();
+}
+
+#endif
+
+
+BitMap2D::BitMap2D(uintptr_t* map, idx_t size_in_slots, idx_t bits_per_slot)
+ : _bits_per_slot(bits_per_slot)
+ , _map(map, size_in_slots * bits_per_slot)
+{
+}
+
+
+BitMap2D::BitMap2D(idx_t size_in_slots, idx_t bits_per_slot)
+ : _bits_per_slot(bits_per_slot)
+ , _map(size_in_slots * bits_per_slot)
+{
+}
diff --git a/src/share/vm/utilities/bitMap.hpp b/src/share/vm/utilities/bitMap.hpp
new file mode 100644
index 000000000..961a2f1b3
--- /dev/null
+++ b/src/share/vm/utilities/bitMap.hpp
@@ -0,0 +1,396 @@
+/*
+ * Copyright 1997-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// Closure for iterating over BitMaps
+
+class BitMapClosure VALUE_OBJ_CLASS_SPEC {
+ public:
+ // Callback when bit in map is set
+ virtual void do_bit(size_t offset) = 0;
+};
+
+
+// Operations for bitmaps represented as arrays of unsigned 32- or 64-bit
+// integers (uintptr_t).
+//
+// Bit offsets are numbered from 0 to size-1
+
+class BitMap VALUE_OBJ_CLASS_SPEC {
+ friend class BitMap2D;
+
+ public:
+ typedef size_t idx_t; // Type used for bit and word indices.
+
+ // Hints for range sizes.
+ typedef enum {
+ unknown_range, small_range, large_range
+ } RangeSizeHint;
+
+ private:
+ idx_t* _map; // First word in bitmap
+ idx_t _size; // Size of bitmap (in bits)
+
+ // Puts the given value at the given offset, using resize() to size
+ // the bitmap appropriately if needed using factor-of-two expansion.
+ void at_put_grow(idx_t index, bool value);
+
+ protected:
+ // Return the position of bit within the word that contains it (e.g., if
+ // bitmap words are 32 bits, return a number 0 <= n <= 31).
+ static idx_t bit_in_word(idx_t bit) { return bit & (BitsPerWord - 1); }
+
+ // Return a mask that will select the specified bit, when applied to the word
+ // containing the bit.
+ static idx_t bit_mask(idx_t bit) { return (idx_t)1 << bit_in_word(bit); }
+
+ // Return the index of the word containing the specified bit.
+ static idx_t word_index(idx_t bit) { return bit >> LogBitsPerWord; }
+
+ // Return the bit number of the first bit in the specified word.
+ static idx_t bit_index(idx_t word) { return word << LogBitsPerWord; }
+
+ // Return the array of bitmap words, or a specific word from it.
+ idx_t* map() const { return _map; }
+ idx_t map(idx_t word) const { return _map[word]; }
+
+ // Return a pointer to the word containing the specified bit.
+ idx_t* word_addr(idx_t bit) const { return map() + word_index(bit); }
+
+ // Set a word to a specified value or to all ones; clear a word.
+ void set_word (idx_t word, idx_t val) { _map[word] = val; }
+ void set_word (idx_t word) { set_word(word, ~(uintptr_t)0); }
+ void clear_word(idx_t word) { _map[word] = 0; }
+
+ // Utilities for ranges of bits. Ranges are half-open [beg, end).
+
+ // Ranges within a single word.
+ inline idx_t inverted_bit_mask_for_range(idx_t beg, idx_t end) const;
+ inline void set_range_within_word (idx_t beg, idx_t end);
+ inline void clear_range_within_word (idx_t beg, idx_t end);
+ inline void par_put_range_within_word (idx_t beg, idx_t end, bool value);
+
+ // Ranges spanning entire words.
+ inline void set_range_of_words (idx_t beg, idx_t end);
+ inline void clear_range_of_words (idx_t beg, idx_t end);
+ inline void set_large_range_of_words (idx_t beg, idx_t end);
+ inline void clear_large_range_of_words (idx_t beg, idx_t end);
+
+ // The index of the first full word in a range.
+ inline idx_t word_index_round_up(idx_t bit) const;
+
+ // Verification, statistics.
+ void verify_index(idx_t index) const {
+ assert(index < _size, "BitMap index out of bounds");
+ }
+
+ void verify_range(idx_t beg_index, idx_t end_index) const {
+#ifdef ASSERT
+ assert(beg_index <= end_index, "BitMap range error");
+ // Note that [0,0) and [size,size) are both valid ranges.
+ if (end_index != _size) verify_index(end_index);
+#endif
+ }
+
+ public:
+
+ // Constructs a bitmap with no map, and size 0.
+ BitMap() : _map(NULL), _size(0) {}
+
+ // Construction
+ BitMap(idx_t* map, idx_t size_in_bits);
+
+ // Allocates necessary data structure in resource area
+ BitMap(idx_t size_in_bits);
+
+ void set_map(idx_t* map) { _map = map; }
+ void set_size(idx_t size_in_bits) { _size = size_in_bits; }
+
+ // Allocates necessary data structure in resource area.
+ // Preserves state currently in bit map by copying data.
+ // Zeros any newly-addressable bits.
+ // Does not perform any frees (i.e., of current _map).
+ void resize(idx_t size_in_bits);
+
+ // Accessing
+ idx_t size() const { return _size; }
+ idx_t size_in_words() const {
+ return word_index(size() + BitsPerWord - 1);
+ }
+
+ bool at(idx_t index) const {
+ verify_index(index);
+ return (*word_addr(index) & bit_mask(index)) != 0;
+ }
+
+ // Align bit index up or down to the next bitmap word boundary, or check
+ // alignment.
+ static idx_t word_align_up(idx_t bit) {
+ return align_size_up(bit, BitsPerWord);
+ }
+ static idx_t word_align_down(idx_t bit) {
+ return align_size_down(bit, BitsPerWord);
+ }
+ static bool is_word_aligned(idx_t bit) {
+ return word_align_up(bit) == bit;
+ }
+
+ // Set or clear the specified bit.
+ inline void set_bit(idx_t bit);
+ inline void clear_bit(idx_t bit);
+
+ // Atomically set or clear the specified bit.
+ inline bool par_set_bit(idx_t bit);
+ inline bool par_clear_bit(idx_t bit);
+
+ // Put the given value at the given offset. The parallel version
+ // will CAS the value into the bitmap and is quite a bit slower.
+ // The parallel version also returns a value indicating if the
+ // calling thread was the one that changed the value of the bit.
+ void at_put(idx_t index, bool value);
+ bool par_at_put(idx_t index, bool value);
+
+ // Update a range of bits. Ranges are half-open [beg, end).
+ void set_range (idx_t beg, idx_t end);
+ void clear_range (idx_t beg, idx_t end);
+ void set_large_range (idx_t beg, idx_t end);
+ void clear_large_range (idx_t beg, idx_t end);
+ void at_put_range(idx_t beg, idx_t end, bool value);
+ void par_at_put_range(idx_t beg, idx_t end, bool value);
+ void at_put_large_range(idx_t beg, idx_t end, bool value);
+ void par_at_put_large_range(idx_t beg, idx_t end, bool value);
+
+ // Update a range of bits, using a hint about the size. Currently only
+ // inlines the predominant case of a 1-bit range. Works best when hint is a
+ // compile-time constant.
+ inline void set_range(idx_t beg, idx_t end, RangeSizeHint hint);
+ inline void clear_range(idx_t beg, idx_t end, RangeSizeHint hint);
+ inline void par_set_range(idx_t beg, idx_t end, RangeSizeHint hint);
+ inline void par_clear_range (idx_t beg, idx_t end, RangeSizeHint hint);
+
+ // Clearing
+ void clear();
+ void clear_large();
+
+ // Iteration support
+ void iterate(BitMapClosure* blk, idx_t leftIndex, idx_t rightIndex);
+ inline void iterate(BitMapClosure* blk) {
+ // call the version that takes an interval
+ iterate(blk, 0, size());
+ }
+
+ // Looking for 1's and 0's to the "right"
+ idx_t get_next_one_offset (idx_t l_index, idx_t r_index) const;
+ idx_t get_next_zero_offset(idx_t l_index, idx_t r_index) const;
+
+ idx_t get_next_one_offset(idx_t offset) const {
+ return get_next_one_offset(offset, size());
+ }
+ idx_t get_next_zero_offset(idx_t offset) const {
+ return get_next_zero_offset(offset, size());
+ }
+
+
+
+ // Find the next one bit in the range [beg_bit, end_bit), or return end_bit if
+ // no one bit is found. Equivalent to get_next_one_offset(), but inline for
+ // use in performance-critical code.
+ inline idx_t find_next_one_bit(idx_t beg_bit, idx_t end_bit) const;
+
+ // Set operations.
+ void set_union(BitMap bits);
+ void set_difference(BitMap bits);
+ void set_intersection(BitMap bits);
+ // Returns true iff "this" is a superset of "bits".
+ bool contains(const BitMap bits) const;
+ // Returns true iff "this and "bits" have a non-empty intersection.
+ bool intersects(const BitMap bits) const;
+
+ // Returns result of whether this map changed
+ // during the operation
+ bool set_union_with_result(BitMap bits);
+ bool set_difference_with_result(BitMap bits);
+ bool set_intersection_with_result(BitMap bits);
+
+ void set_from(BitMap bits);
+
+ bool is_same(BitMap bits);
+
+ // Test if all bits are set or cleared
+ bool is_full() const;
+ bool is_empty() const;
+
+
+#ifndef PRODUCT
+ public:
+ // Printing
+ void print_on(outputStream* st) const;
+#endif
+};
+
+inline void BitMap::set_bit(idx_t bit) {
+ verify_index(bit);
+ *word_addr(bit) |= bit_mask(bit);
+}
+
+inline void BitMap::clear_bit(idx_t bit) {
+ verify_index(bit);
+ *word_addr(bit) &= ~bit_mask(bit);
+}
+
+inline void BitMap::set_range(idx_t beg, idx_t end, RangeSizeHint hint) {
+ if (hint == small_range && end - beg == 1) {
+ set_bit(beg);
+ } else {
+ if (hint == large_range) {
+ set_large_range(beg, end);
+ } else {
+ set_range(beg, end);
+ }
+ }
+}
+
+inline void BitMap::clear_range(idx_t beg, idx_t end, RangeSizeHint hint) {
+ if (hint == small_range && end - beg == 1) {
+ clear_bit(beg);
+ } else {
+ if (hint == large_range) {
+ clear_large_range(beg, end);
+ } else {
+ clear_range(beg, end);
+ }
+ }
+}
+
+inline void BitMap::par_set_range(idx_t beg, idx_t end, RangeSizeHint hint) {
+ if (hint == small_range && end - beg == 1) {
+ par_at_put(beg, true);
+ } else {
+ if (hint == large_range) {
+ par_at_put_large_range(beg, end, true);
+ } else {
+ par_at_put_range(beg, end, true);
+ }
+ }
+}
+
+
+// Convenience class wrapping BitMap which provides multiple bits per slot.
+class BitMap2D VALUE_OBJ_CLASS_SPEC {
+ public:
+ typedef size_t idx_t; // Type used for bit and word indices.
+
+ private:
+ BitMap _map;
+ idx_t _bits_per_slot;
+
+ idx_t bit_index(idx_t slot_index, idx_t bit_within_slot_index) const {
+ return slot_index * _bits_per_slot + bit_within_slot_index;
+ }
+
+ void verify_bit_within_slot_index(idx_t index) const {
+ assert(index < _bits_per_slot, "bit_within_slot index out of bounds");
+ }
+
+ public:
+ // Construction. bits_per_slot must be greater than 0.
+ BitMap2D(uintptr_t* map, idx_t size_in_slots, idx_t bits_per_slot);
+
+ // Allocates necessary data structure in resource area. bits_per_slot must be greater than 0.
+ BitMap2D(idx_t size_in_slots, idx_t bits_per_slot);
+
+ idx_t size_in_bits() {
+ return _map.size();
+ }
+
+ // Returns number of full slots that have been allocated
+ idx_t size_in_slots() {
+ // Round down
+ return _map.size() / _bits_per_slot;
+ }
+
+ bool is_valid_index(idx_t slot_index, idx_t bit_within_slot_index) {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ return (bit_index(slot_index, bit_within_slot_index) < size_in_bits());
+ }
+
+ bool at(idx_t slot_index, idx_t bit_within_slot_index) const {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ return _map.at(bit_index(slot_index, bit_within_slot_index));
+ }
+
+ void set_bit(idx_t slot_index, idx_t bit_within_slot_index) {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ _map.set_bit(bit_index(slot_index, bit_within_slot_index));
+ }
+
+ void clear_bit(idx_t slot_index, idx_t bit_within_slot_index) {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ _map.clear_bit(bit_index(slot_index, bit_within_slot_index));
+ }
+
+ void at_put(idx_t slot_index, idx_t bit_within_slot_index, bool value) {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ _map.at_put(bit_index(slot_index, bit_within_slot_index), value);
+ }
+
+ void at_put_grow(idx_t slot_index, idx_t bit_within_slot_index, bool value) {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ _map.at_put_grow(bit_index(slot_index, bit_within_slot_index), value);
+ }
+
+ void clear() {
+ _map.clear();
+ }
+};
+
+
+
+inline void BitMap::set_range_of_words(idx_t beg, idx_t end) {
+ uintptr_t* map = _map;
+ for (idx_t i = beg; i < end; ++i) map[i] = ~(uintptr_t)0;
+}
+
+
+inline void BitMap::clear_range_of_words(idx_t beg, idx_t end) {
+ uintptr_t* map = _map;
+ for (idx_t i = beg; i < end; ++i) map[i] = 0;
+}
+
+
+inline void BitMap::clear() {
+ clear_range_of_words(0, size_in_words());
+}
+
+
+inline void BitMap::par_clear_range(idx_t beg, idx_t end, RangeSizeHint hint) {
+ if (hint == small_range && end - beg == 1) {
+ par_at_put(beg, false);
+ } else {
+ if (hint == large_range) {
+ par_at_put_large_range(beg, end, false);
+ } else {
+ par_at_put_range(beg, end, false);
+ }
+ }
+}
diff --git a/src/share/vm/utilities/bitMap.inline.hpp b/src/share/vm/utilities/bitMap.inline.hpp
new file mode 100644
index 000000000..5e656d99e
--- /dev/null
+++ b/src/share/vm/utilities/bitMap.inline.hpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2005-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+inline bool BitMap::par_set_bit(idx_t bit) {
+ verify_index(bit);
+ volatile idx_t* const addr = word_addr(bit);
+ const idx_t mask = bit_mask(bit);
+ idx_t old_val = *addr;
+
+ do {
+ const idx_t new_val = old_val | mask;
+ if (new_val == old_val) {
+ return false; // Someone else beat us to it.
+ }
+ const idx_t cur_val = (idx_t) Atomic::cmpxchg_ptr((void*) new_val,
+ (volatile void*) addr,
+ (void*) old_val);
+ if (cur_val == old_val) {
+ return true; // Success.
+ }
+ old_val = cur_val; // The value changed, try again.
+ } while (true);
+}
+
+inline bool BitMap::par_clear_bit(idx_t bit) {
+ verify_index(bit);
+ volatile idx_t* const addr = word_addr(bit);
+ const idx_t mask = ~bit_mask(bit);
+ idx_t old_val = *addr;
+
+ do {
+ const idx_t new_val = old_val & mask;
+ if (new_val == old_val) {
+ return false; // Someone else beat us to it.
+ }
+ const idx_t cur_val = (idx_t) Atomic::cmpxchg_ptr((void*) new_val,
+ (volatile void*) addr,
+ (void*) old_val);
+ if (cur_val == old_val) {
+ return true; // Success.
+ }
+ old_val = cur_val; // The value changed, try again.
+ } while (true);
+}
+
+inline BitMap::idx_t
+BitMap::find_next_one_bit(idx_t beg_bit, idx_t end_bit) const
+{
+ verify_range(beg_bit, end_bit);
+ assert(bit_in_word(end_bit) == 0, "end_bit not word-aligned");
+
+ if (beg_bit == end_bit) {
+ return beg_bit;
+ }
+
+ idx_t index = word_index(beg_bit);
+ idx_t r_index = word_index(end_bit);
+ idx_t res_bit = beg_bit;
+
+ // check bits including and to the _left_ of offset's position
+ idx_t res = map(index) >> bit_in_word(res_bit);
+ if (res != (uintptr_t) NoBits) {
+ // find the position of the 1-bit
+ for (; !(res & 1); res_bit++) {
+ res = res >> 1;
+ }
+ assert(res_bit >= beg_bit && res_bit < end_bit, "just checking");
+ return res_bit;
+ }
+ // skip over all word length 0-bit runs
+ for (index++; index < r_index; index++) {
+ res = map(index);
+ if (res != (uintptr_t) NoBits) {
+ // found a 1, return the offset
+ for (res_bit = bit_index(index); !(res & 1); res_bit++) {
+ res = res >> 1;
+ }
+ assert(res & 1, "tautology; see loop condition");
+ assert(res_bit >= beg_bit && res_bit < end_bit, "just checking");
+ return res_bit;
+ }
+ }
+ return end_bit;
+}
diff --git a/src/share/vm/utilities/constantTag.cpp b/src/share/vm/utilities/constantTag.cpp
new file mode 100644
index 000000000..e9cbace4f
--- /dev/null
+++ b/src/share/vm/utilities/constantTag.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 1997-1999 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_constantTag.cpp.incl"
+
+#ifndef PRODUCT
+
+void constantTag::print_on(outputStream* st) const {
+ switch (_tag) {
+ case JVM_CONSTANT_Class :
+ st->print("Class");
+ break;
+ case JVM_CONSTANT_Fieldref :
+ st->print("Field");
+ break;
+ case JVM_CONSTANT_Methodref :
+ st->print("Method");
+ break;
+ case JVM_CONSTANT_InterfaceMethodref :
+ st->print("InterfaceMethod");
+ break;
+ case JVM_CONSTANT_String :
+ st->print("String");
+ break;
+ case JVM_CONSTANT_Integer :
+ st->print("Integer");
+ break;
+ case JVM_CONSTANT_Float :
+ st->print("Float");
+ break;
+ case JVM_CONSTANT_Long :
+ st->print("Long");
+ break;
+ case JVM_CONSTANT_Double :
+ st->print("Double");
+ break;
+ case JVM_CONSTANT_NameAndType :
+ st->print("NameAndType");
+ break;
+ case JVM_CONSTANT_Utf8 :
+ st->print("Utf8");
+ break;
+ case JVM_CONSTANT_UnresolvedClass :
+ st->print("Unresolved class");
+ break;
+ case JVM_CONSTANT_ClassIndex :
+ st->print("Unresolved class index");
+ break;
+ case JVM_CONSTANT_UnresolvedString :
+ st->print("Unresolved string");
+ break;
+ case JVM_CONSTANT_StringIndex :
+ st->print("Unresolved string index");
+ break;
+ default:
+ ShouldNotReachHere();
+ break;
+ }
+}
+
+#endif // PRODUCT
diff --git a/src/share/vm/utilities/constantTag.hpp b/src/share/vm/utilities/constantTag.hpp
new file mode 100644
index 000000000..b8a213f8b
--- /dev/null
+++ b/src/share/vm/utilities/constantTag.hpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 1997-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// constant tags in Java .class files
+
+
+enum {
+ // See jvm.h for shared JVM_CONSTANT_XXX tags
+ // NOTE: replicated in SA in vm/agent/sun/jvm/hotspot/utilities/ConstantTag.java
+ // Hotspot specific tags
+ JVM_CONSTANT_Invalid = 0, // For bad value initialization
+ JVM_CONSTANT_InternalMin = 100, // First implementation tag (aside from bad value of course)
+ JVM_CONSTANT_UnresolvedClass = 100, // Temporary tag until actual use
+ JVM_CONSTANT_ClassIndex = 101, // Temporary tag while constructing constant pool
+ JVM_CONSTANT_UnresolvedString = 102, // Temporary tag until actual use
+ JVM_CONSTANT_StringIndex = 103, // Temporary tag while constructing constant pool
+ JVM_CONSTANT_UnresolvedClassInError = 104, // Error tag due to resolution error
+ JVM_CONSTANT_InternalMax = 104 // Last implementation tag
+};
+
+
+class constantTag VALUE_OBJ_CLASS_SPEC {
+ private:
+ jbyte _tag;
+ public:
+ bool is_klass() const { return _tag == JVM_CONSTANT_Class; }
+ bool is_field () const { return _tag == JVM_CONSTANT_Fieldref; }
+ bool is_method() const { return _tag == JVM_CONSTANT_Methodref; }
+ bool is_interface_method() const { return _tag == JVM_CONSTANT_InterfaceMethodref; }
+ bool is_string() const { return _tag == JVM_CONSTANT_String; }
+ bool is_int() const { return _tag == JVM_CONSTANT_Integer; }
+ bool is_float() const { return _tag == JVM_CONSTANT_Float; }
+ bool is_long() const { return _tag == JVM_CONSTANT_Long; }
+ bool is_double() const { return _tag == JVM_CONSTANT_Double; }
+ bool is_name_and_type() const { return _tag == JVM_CONSTANT_NameAndType; }
+ bool is_utf8() const { return _tag == JVM_CONSTANT_Utf8; }
+
+ bool is_invalid() const { return _tag == JVM_CONSTANT_Invalid; }
+
+ bool is_unresolved_klass() const {
+ return _tag == JVM_CONSTANT_UnresolvedClass || _tag == JVM_CONSTANT_UnresolvedClassInError;
+ }
+
+ bool is_unresolved_klass_in_error() const {
+ return _tag == JVM_CONSTANT_UnresolvedClassInError;
+ }
+
+ bool is_klass_index() const { return _tag == JVM_CONSTANT_ClassIndex; }
+ bool is_unresolved_string() const { return _tag == JVM_CONSTANT_UnresolvedString; }
+ bool is_string_index() const { return _tag == JVM_CONSTANT_StringIndex; }
+
+ bool is_klass_reference() const { return is_klass_index() || is_unresolved_klass(); }
+ bool is_field_or_method() const { return is_field() || is_method() || is_interface_method(); }
+ bool is_symbol() const { return is_utf8(); }
+
+ constantTag(jbyte tag) {
+ assert((tag >= 0 && tag <= JVM_CONSTANT_NameAndType) ||
+ (tag >= JVM_CONSTANT_InternalMin && tag <= JVM_CONSTANT_InternalMax), "Invalid constant tag");
+ _tag = tag;
+ }
+
+ jbyte value() { return _tag; }
+
+ void print_on(outputStream* st) const PRODUCT_RETURN;
+};
diff --git a/src/share/vm/utilities/copy.cpp b/src/share/vm/utilities/copy.cpp
new file mode 100644
index 000000000..1bfef0afe
--- /dev/null
+++ b/src/share/vm/utilities/copy.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2006-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_copy.cpp.incl"
+
+
+// Copy bytes; larger units are filled atomically if everything is aligned.
+void Copy::conjoint_memory_atomic(void* from, void* to, size_t size) {
+ address src = (address) from;
+ address dst = (address) to;
+ uintptr_t bits = (uintptr_t) src | (uintptr_t) dst | (uintptr_t) size;
+
+ // (Note: We could improve performance by ignoring the low bits of size,
+ // and putting a short cleanup loop after each bulk copy loop.
+ // There are plenty of other ways to make this faster also,
+ // and it's a slippery slope. For now, let's keep this code simple
+ // since the simplicity helps clarify the atomicity semantics of
+ // this operation. There are also CPU-specific assembly versions
+ // which may or may not want to include such optimizations.)
+
+ if (bits % sizeof(jlong) == 0) {
+ Copy::conjoint_jlongs_atomic((jlong*) src, (jlong*) dst, size / sizeof(jlong));
+ } else if (bits % sizeof(jint) == 0) {
+ Copy::conjoint_jints_atomic((jint*) src, (jint*) dst, size / sizeof(jint));
+ } else if (bits % sizeof(jshort) == 0) {
+ Copy::conjoint_jshorts_atomic((jshort*) src, (jshort*) dst, size / sizeof(jshort));
+ } else {
+ // Not aligned, so no need to be atomic.
+ Copy::conjoint_bytes((void*) src, (void*) dst, size);
+ }
+}
+
+
+// Fill bytes; larger units are filled atomically if everything is aligned.
+void Copy::fill_to_memory_atomic(void* to, size_t size, jubyte value) {
+ address dst = (address) to;
+ uintptr_t bits = (uintptr_t) to | (uintptr_t) size;
+ if (bits % sizeof(jlong) == 0) {
+ jlong fill = (julong)( (jubyte)value ); // zero-extend
+ if (fill != 0) {
+ fill += fill << 8;
+ fill += fill << 16;
+ fill += fill << 32;
+ }
+ //Copy::fill_to_jlongs_atomic((jlong*) dst, size / sizeof(jlong));
+ for (uintptr_t off = 0; off < size; off += sizeof(jlong)) {
+ *(jlong*)(dst + off) = fill;
+ }
+ } else if (bits % sizeof(jint) == 0) {
+ jint fill = (juint)( (jubyte)value ); // zero-extend
+ if (fill != 0) {
+ fill += fill << 8;
+ fill += fill << 16;
+ }
+ //Copy::fill_to_jints_atomic((jint*) dst, size / sizeof(jint));
+ for (uintptr_t off = 0; off < size; off += sizeof(jint)) {
+ *(jint*)(dst + off) = fill;
+ }
+ } else if (bits % sizeof(jshort) == 0) {
+ jshort fill = (jushort)( (jubyte)value ); // zero-extend
+ fill += fill << 8;
+ //Copy::fill_to_jshorts_atomic((jshort*) dst, size / sizeof(jshort));
+ for (uintptr_t off = 0; off < size; off += sizeof(jshort)) {
+ *(jshort*)(dst + off) = fill;
+ }
+ } else {
+ // Not aligned, so no need to be atomic.
+ Copy::fill_to_bytes(dst, size, value);
+ }
+}
diff --git a/src/share/vm/utilities/copy.hpp b/src/share/vm/utilities/copy.hpp
new file mode 100644
index 000000000..1bbea38ad
--- /dev/null
+++ b/src/share/vm/utilities/copy.hpp
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2003-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// Assembly code for platforms that need it.
+extern "C" {
+ void _Copy_conjoint_words(HeapWord* from, HeapWord* to, size_t count);
+ void _Copy_disjoint_words(HeapWord* from, HeapWord* to, size_t count);
+
+ void _Copy_conjoint_words_atomic(HeapWord* from, HeapWord* to, size_t count);
+ void _Copy_disjoint_words_atomic(HeapWord* from, HeapWord* to, size_t count);
+
+ void _Copy_aligned_conjoint_words(HeapWord* from, HeapWord* to, size_t count);
+ void _Copy_aligned_disjoint_words(HeapWord* from, HeapWord* to, size_t count);
+
+ void _Copy_conjoint_bytes(void* from, void* to, size_t count);
+
+ void _Copy_conjoint_bytes_atomic (void* from, void* to, size_t count);
+ void _Copy_conjoint_jshorts_atomic(jshort* from, jshort* to, size_t count);
+ void _Copy_conjoint_jints_atomic (jint* from, jint* to, size_t count);
+ void _Copy_conjoint_jlongs_atomic (jlong* from, jlong* to, size_t count);
+ void _Copy_conjoint_oops_atomic (oop* from, oop* to, size_t count);
+
+ void _Copy_arrayof_conjoint_bytes (HeapWord* from, HeapWord* to, size_t count);
+ void _Copy_arrayof_conjoint_jshorts(HeapWord* from, HeapWord* to, size_t count);
+ void _Copy_arrayof_conjoint_jints (HeapWord* from, HeapWord* to, size_t count);
+ void _Copy_arrayof_conjoint_jlongs (HeapWord* from, HeapWord* to, size_t count);
+ void _Copy_arrayof_conjoint_oops (HeapWord* from, HeapWord* to, size_t count);
+}
+
+class Copy : AllStatic {
+ public:
+ // Block copy methods have four attributes. We don't define all possibilities.
+ // alignment: aligned according to minimum Java object alignment (MinObjAlignment)
+ // arrayof: arraycopy operation with both operands aligned on the same
+ // boundary as the first element of an array of the copy unit.
+ // This is currently a HeapWord boundary on all platforms, except
+ // for long and double arrays, which are aligned on an 8-byte
+ // boundary on all platforms.
+ // arraycopy operations are implicitly atomic on each array element.
+ // overlap: disjoint or conjoint.
+ // copy unit: bytes or words (i.e., HeapWords) or oops (i.e., pointers).
+ // atomicity: atomic or non-atomic on the copy unit.
+ //
+ // Names are constructed thusly:
+ //
+ // [ 'aligned_' | 'arrayof_' ]
+ // ('conjoint_' | 'disjoint_')
+ // ('words' | 'bytes' | 'jshorts' | 'jints' | 'jlongs' | 'oops')
+ // [ '_atomic' ]
+ //
+ // Except in the arrayof case, whatever the alignment is, we assume we can copy
+ // whole alignment units. E.g., if MinObjAlignment is 2x word alignment, an odd
+ // count may copy an extra word. In the arrayof case, we are allowed to copy
+ // only the number of copy units specified.
+
+ // HeapWords
+
+ // Word-aligned words, conjoint, not atomic on each word
+ static void conjoint_words(HeapWord* from, HeapWord* to, size_t count) {
+ assert_params_ok(from, to, LogHeapWordSize);
+ pd_conjoint_words(from, to, count);
+ }
+
+ // Word-aligned words, disjoint, not atomic on each word
+ static void disjoint_words(HeapWord* from, HeapWord* to, size_t count) {
+ assert_params_ok(from, to, LogHeapWordSize);
+ assert_disjoint(from, to, count);
+ pd_disjoint_words(from, to, count);
+ }
+
+ // Word-aligned words, disjoint, atomic on each word
+ static void disjoint_words_atomic(HeapWord* from, HeapWord* to, size_t count) {
+ assert_params_ok(from, to, LogHeapWordSize);
+ assert_disjoint(from, to, count);
+ pd_disjoint_words_atomic(from, to, count);
+ }
+
+ // Object-aligned words, conjoint, not atomic on each word
+ static void aligned_conjoint_words(HeapWord* from, HeapWord* to, size_t count) {
+ assert_params_aligned(from, to);
+ assert_non_zero(count);
+ pd_aligned_conjoint_words(from, to, count);
+ }
+
+ // Object-aligned words, disjoint, not atomic on each word
+ static void aligned_disjoint_words(HeapWord* from, HeapWord* to, size_t count) {
+ assert_params_aligned(from, to);
+ assert_disjoint(from, to, count);
+ assert_non_zero(count);
+ pd_aligned_disjoint_words(from, to, count);
+ }
+
+ // bytes, jshorts, jints, jlongs, oops
+
+ // bytes, conjoint, not atomic on each byte (not that it matters)
+ static void conjoint_bytes(void* from, void* to, size_t count) {
+ assert_non_zero(count);
+ pd_conjoint_bytes(from, to, count);
+ }
+
+ // bytes, conjoint, atomic on each byte (not that it matters)
+ static void conjoint_bytes_atomic(void* from, void* to, size_t count) {
+ assert_non_zero(count);
+ pd_conjoint_bytes(from, to, count);
+ }
+
+ // jshorts, conjoint, atomic on each jshort
+ static void conjoint_jshorts_atomic(jshort* from, jshort* to, size_t count) {
+ assert_params_ok(from, to, LogBytesPerShort);
+ assert_non_zero(count);
+ pd_conjoint_jshorts_atomic(from, to, count);
+ }
+
+ // jints, conjoint, atomic on each jint
+ static void conjoint_jints_atomic(jint* from, jint* to, size_t count) {
+ assert_params_ok(from, to, LogBytesPerInt);
+ assert_non_zero(count);
+ pd_conjoint_jints_atomic(from, to, count);
+ }
+
+ // jlongs, conjoint, atomic on each jlong
+ static void conjoint_jlongs_atomic(jlong* from, jlong* to, size_t count) {
+ assert_params_ok(from, to, LogBytesPerLong);
+ assert_non_zero(count);
+ pd_conjoint_jlongs_atomic(from, to, count);
+ }
+
+ // oops, conjoint, atomic on each oop
+ static void conjoint_oops_atomic(oop* from, oop* to, size_t count) {
+ assert_params_ok(from, to, LogBytesPerOop);
+ assert_non_zero(count);
+ pd_conjoint_oops_atomic(from, to, count);
+ }
+
+ // Copy a span of memory. If the span is an integral number of aligned
+ // longs, words, or ints, copy those units atomically.
+ // The largest atomic transfer unit is 8 bytes, or the largest power
+ // of two which divides all of from, to, and size, whichever is smaller.
+ static void conjoint_memory_atomic(void* from, void* to, size_t size);
+
+ // bytes, conjoint array, atomic on each byte (not that it matters)
+ static void arrayof_conjoint_bytes(HeapWord* from, HeapWord* to, size_t count) {
+ assert_non_zero(count);
+ pd_arrayof_conjoint_bytes(from, to, count);
+ }
+
+ // jshorts, conjoint array, atomic on each jshort
+ static void arrayof_conjoint_jshorts(HeapWord* from, HeapWord* to, size_t count) {
+ assert_params_ok(from, to, LogBytesPerShort);
+ assert_non_zero(count);
+ pd_arrayof_conjoint_jshorts(from, to, count);
+ }
+
+ // jints, conjoint array, atomic on each jint
+ static void arrayof_conjoint_jints(HeapWord* from, HeapWord* to, size_t count) {
+ assert_params_ok(from, to, LogBytesPerInt);
+ assert_non_zero(count);
+ pd_arrayof_conjoint_jints(from, to, count);
+ }
+
+ // jlongs, conjoint array, atomic on each jlong
+ static void arrayof_conjoint_jlongs(HeapWord* from, HeapWord* to, size_t count) {
+ assert_params_ok(from, to, LogBytesPerLong);
+ assert_non_zero(count);
+ pd_arrayof_conjoint_jlongs(from, to, count);
+ }
+
+ // oops, conjoint array, atomic on each oop
+ static void arrayof_conjoint_oops(HeapWord* from, HeapWord* to, size_t count) {
+ assert_params_ok(from, to, LogBytesPerOop);
+ assert_non_zero(count);
+ pd_arrayof_conjoint_oops(from, to, count);
+ }
+
+ // Known overlap methods
+
+ // Copy word-aligned words from higher to lower addresses, not atomic on each word
+ inline static void conjoint_words_to_lower(HeapWord* from, HeapWord* to, size_t byte_count) {
+ // byte_count is in bytes to check its alignment
+ assert_params_ok(from, to, LogHeapWordSize);
+ assert_byte_count_ok(byte_count, HeapWordSize);
+
+ size_t count = (size_t)round_to(byte_count, HeapWordSize) >> LogHeapWordSize;
+ assert(to <= from || from + count <= to, "do not overwrite source data");
+
+ while (count-- > 0) {
+ *to++ = *from++;
+ }
+ }
+
+ // Copy word-aligned words from lower to higher addresses, not atomic on each word
+ inline static void conjoint_words_to_higher(HeapWord* from, HeapWord* to, size_t byte_count) {
+ // byte_count is in bytes to check its alignment
+ assert_params_ok(from, to, LogHeapWordSize);
+ assert_byte_count_ok(byte_count, HeapWordSize);
+
+ size_t count = (size_t)round_to(byte_count, HeapWordSize) >> LogHeapWordSize;
+ assert(from <= to || to + count <= from, "do not overwrite source data");
+
+ from += count - 1;
+ to += count - 1;
+ while (count-- > 0) {
+ *to-- = *from--;
+ }
+ }
+
+ // Fill methods
+
+ // Fill word-aligned words, not atomic on each word
+ // set_words
+ static void fill_to_words(HeapWord* to, size_t count, juint value = 0) {
+ assert_params_ok(to, LogHeapWordSize);
+ pd_fill_to_words(to, count, value);
+ }
+
+ static void fill_to_aligned_words(HeapWord* to, size_t count, juint value = 0) {
+ assert_params_aligned(to);
+ pd_fill_to_aligned_words(to, count, value);
+ }
+
+ // Fill bytes
+ static void fill_to_bytes(void* to, size_t count, jubyte value = 0) {
+ pd_fill_to_bytes(to, count, value);
+ }
+
+ // Fill a span of memory. If the span is an integral number of aligned
+ // longs, words, or ints, store to those units atomically.
+ // The largest atomic transfer unit is 8 bytes, or the largest power
+ // of two which divides both to and size, whichever is smaller.
+ static void fill_to_memory_atomic(void* to, size_t size, jubyte value = 0);
+
+ // Zero-fill methods
+
+ // Zero word-aligned words, not atomic on each word
+ static void zero_to_words(HeapWord* to, size_t count) {
+ assert_params_ok(to, LogHeapWordSize);
+ pd_zero_to_words(to, count);
+ }
+
+ // Zero bytes
+ static void zero_to_bytes(void* to, size_t count) {
+ pd_zero_to_bytes(to, count);
+ }
+
+ private:
+ static bool params_disjoint(HeapWord* from, HeapWord* to, size_t count) {
+ if (from < to) {
+ return pointer_delta(to, from) >= count;
+ }
+ return pointer_delta(from, to) >= count;
+ }
+
+ // These methods raise a fatal if they detect a problem.
+
+ static void assert_disjoint(HeapWord* from, HeapWord* to, size_t count) {
+#ifdef ASSERT
+ if (!params_disjoint(from, to, count))
+ basic_fatal("source and dest overlap");
+#endif
+ }
+
+ static void assert_params_ok(void* from, void* to, intptr_t log_align) {
+#ifdef ASSERT
+ if (mask_bits((uintptr_t)from, right_n_bits(log_align)) != 0)
+ basic_fatal("not aligned");
+ if (mask_bits((uintptr_t)to, right_n_bits(log_align)) != 0)
+ basic_fatal("not aligned");
+#endif
+ }
+
+ static void assert_params_ok(HeapWord* to, intptr_t log_align) {
+#ifdef ASSERT
+ if (mask_bits((uintptr_t)to, right_n_bits(log_align)) != 0)
+ basic_fatal("not word aligned");
+#endif
+ }
+ static void assert_params_aligned(HeapWord* from, HeapWord* to) {
+#ifdef ASSERT
+ if (mask_bits((uintptr_t)from, MinObjAlignmentInBytes-1) != 0)
+ basic_fatal("not object aligned");
+ if (mask_bits((uintptr_t)to, MinObjAlignmentInBytes-1) != 0)
+ basic_fatal("not object aligned");
+#endif
+ }
+
+ static void assert_params_aligned(HeapWord* to) {
+#ifdef ASSERT
+ if (mask_bits((uintptr_t)to, MinObjAlignmentInBytes-1) != 0)
+ basic_fatal("not object aligned");
+#endif
+ }
+
+ static void assert_non_zero(size_t count) {
+#ifdef ASSERT
+ if (count == 0) {
+ basic_fatal("count must be non-zero");
+ }
+#endif
+ }
+
+ static void assert_byte_count_ok(size_t byte_count, size_t unit_size) {
+#ifdef ASSERT
+ if ((size_t)round_to(byte_count, unit_size) != byte_count) {
+ basic_fatal("byte count must be aligned");
+ }
+#endif
+ }
+
+ // Platform dependent implementations of the above methods.
+ #include "incls/_copy_pd.hpp.incl"
+};
diff --git a/src/share/vm/utilities/debug.cpp b/src/share/vm/utilities/debug.cpp
new file mode 100644
index 000000000..8eb84cddc
--- /dev/null
+++ b/src/share/vm/utilities/debug.cpp
@@ -0,0 +1,936 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_debug.cpp.incl"
+
+#ifndef ASSERT
+# ifdef _DEBUG
+ // NOTE: don't turn the lines below into a comment -- if you're getting
+ // a compile error here, change the settings to define ASSERT
+ ASSERT should be defined when _DEBUG is defined. It is not intended to be used for debugging
+ functions that do not slow down the system too much and thus can be left in optimized code.
+ On the other hand, the code should not be included in a production version.
+# endif // _DEBUG
+#endif // ASSERT
+
+
+#ifdef _DEBUG
+# ifndef ASSERT
+ configuration error: ASSERT must be defined in debug version
+# endif // ASSERT
+#endif // _DEBUG
+
+
+#ifdef PRODUCT
+# if -defined _DEBUG || -defined ASSERT
+ configuration error: ASSERT et al. must not be defined in PRODUCT version
+# endif
+#endif // PRODUCT
+
+
+void warning(const char* format, ...) {
+ // In case error happens before init or during shutdown
+ if (tty == NULL) ostream_init();
+
+ tty->print("%s warning: ", VM_Version::vm_name());
+ va_list ap;
+ va_start(ap, format);
+ tty->vprint_cr(format, ap);
+ va_end(ap);
+ if (BreakAtWarning) BREAKPOINT;
+}
+
+#ifndef PRODUCT
+
+#define is_token_break(ch) (isspace(ch) || (ch) == ',')
+
+static const char* last_file_name = NULL;
+static int last_line_no = -1;
+
+// assert/guarantee/... may happen very early during VM initialization.
+// Don't rely on anything that is initialized by Threads::create_vm(). For
+// example, don't use tty.
+bool assert_is_suppressed(const char* file_name, int line_no) {
+ // The following 1-element cache requires that passed-in
+ // file names are always only constant literals.
+ if (file_name == last_file_name && line_no == last_line_no) return true;
+
+ int file_name_len = (int)strlen(file_name);
+ char separator = os::file_separator()[0];
+ const char* base_name = strrchr(file_name, separator);
+ if (base_name == NULL)
+ base_name = file_name;
+
+ // scan the SuppressErrorAt option
+ const char* cp = SuppressErrorAt;
+ for (;;) {
+ const char* sfile;
+ int sfile_len;
+ int sline;
+ bool noisy;
+ while ((*cp) != '\0' && is_token_break(*cp)) cp++;
+ if ((*cp) == '\0') break;
+ sfile = cp;
+ while ((*cp) != '\0' && !is_token_break(*cp) && (*cp) != ':') cp++;
+ sfile_len = cp - sfile;
+ if ((*cp) == ':') cp++;
+ sline = 0;
+ while ((*cp) != '\0' && isdigit(*cp)) {
+ sline *= 10;
+ sline += (*cp) - '0';
+ cp++;
+ }
+ // "file:line!" means the assert suppression is not silent
+ noisy = ((*cp) == '!');
+ while ((*cp) != '\0' && !is_token_break(*cp)) cp++;
+ // match the line
+ if (sline != 0) {
+ if (sline != line_no) continue;
+ }
+ // match the file
+ if (sfile_len > 0) {
+ const char* look = file_name;
+ const char* look_max = file_name + file_name_len - sfile_len;
+ const char* foundp;
+ bool match = false;
+ while (!match
+ && (foundp = strchr(look, sfile[0])) != NULL
+ && foundp <= look_max) {
+ match = true;
+ for (int i = 1; i < sfile_len; i++) {
+ if (sfile[i] != foundp[i]) {
+ match = false;
+ break;
+ }
+ }
+ look = foundp + 1;
+ }
+ if (!match) continue;
+ }
+ // got a match!
+ if (noisy) {
+ fdStream out(defaultStream::output_fd());
+ out.print_raw("[error suppressed at ");
+ out.print_raw(base_name);
+ char buf[16];
+ jio_snprintf(buf, sizeof(buf), ":%d]", line_no);
+ out.print_raw_cr(buf);
+ } else {
+ // update 1-element cache for fast silent matches
+ last_file_name = file_name;
+ last_line_no = line_no;
+ }
+ return true;
+ }
+
+ if (!is_error_reported()) {
+ // print a friendly hint:
+ fdStream out(defaultStream::output_fd());
+ out.print_raw_cr("# To suppress the following error report, specify this argument");
+ out.print_raw ("# after -XX: or in .hotspotrc: SuppressErrorAt=");
+ out.print_raw (base_name);
+ char buf[16];
+ jio_snprintf(buf, sizeof(buf), ":%d", line_no);
+ out.print_raw_cr(buf);
+ }
+ return false;
+}
+
+#undef is_token_break
+
+#else
+
+// Place-holder for non-existent suppression check:
+#define assert_is_suppressed(file_name, line_no) (false)
+
+#endif //PRODUCT
+
+void report_assertion_failure(const char* file_name, int line_no, const char* message) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+ VMError err(ThreadLocalStorage::get_thread_slow(), message, file_name, line_no);
+ err.report_and_die();
+}
+
+void report_fatal(const char* file_name, int line_no, const char* message) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+ VMError err(ThreadLocalStorage::get_thread_slow(), message, file_name, line_no);
+ err.report_and_die();
+}
+
+void report_fatal_vararg(const char* file_name, int line_no, const char* format, ...) {
+ char buffer[256];
+ va_list ap;
+ va_start(ap, format);
+ jio_vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+ report_fatal(file_name, line_no, buffer);
+}
+
+
+// Used by report_vm_out_of_memory to detect recursion.
+static jint _exiting_out_of_mem = 0;
+
+// Just passing the flow to VMError to handle error
+void report_vm_out_of_memory(const char* file_name, int line_no, size_t size, const char* message) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+
+ // We try to gather additional information for the first out of memory
+ // error only; gathering additional data might cause an allocation and a
+ // recursive out_of_memory condition.
+
+ const jint exiting = 1;
+ // If we succeed in changing the value, we're the first one in.
+ bool first_time_here = Atomic::xchg(exiting, &_exiting_out_of_mem) != exiting;
+
+ if (first_time_here) {
+ Thread* thread = ThreadLocalStorage::get_thread_slow();
+ VMError(thread, size, message, file_name, line_no).report_and_die();
+ }
+ vm_abort();
+}
+
+void report_vm_out_of_memory_vararg(const char* file_name, int line_no, size_t size, const char* format, ...) {
+ char buffer[256];
+ va_list ap;
+ va_start(ap, format);
+ jio_vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+ report_vm_out_of_memory(file_name, line_no, size, buffer);
+}
+
+void report_should_not_call(const char* file_name, int line_no) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+ VMError err(ThreadLocalStorage::get_thread_slow(), "ShouldNotCall()", file_name, line_no);
+ err.report_and_die();
+}
+
+
+void report_should_not_reach_here(const char* file_name, int line_no) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+ VMError err(ThreadLocalStorage::get_thread_slow(), "ShouldNotReachHere()", file_name, line_no);
+ err.report_and_die();
+}
+
+
+void report_unimplemented(const char* file_name, int line_no) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+ VMError err(ThreadLocalStorage::get_thread_slow(), "Unimplemented()", file_name, line_no);
+ err.report_and_die();
+}
+
+
+void report_untested(const char* file_name, int line_no, const char* msg) {
+#ifndef PRODUCT
+ warning("Untested: %s in %s: %d\n", msg, file_name, line_no);
+#endif // PRODUCT
+}
+
+void report_java_out_of_memory(const char* message) {
+ static jint out_of_memory_reported = 0;
+
+ // A number of threads may attempt to report OutOfMemoryError at around the
+ // same time. To avoid dumping the heap or executing the data collection
+ // commands multiple times we just do it once when the first threads reports
+ // the error.
+ if (Atomic::cmpxchg(1, &out_of_memory_reported, 0) == 0) {
+ // create heap dump before OnOutOfMemoryError commands are executed
+ if (HeapDumpOnOutOfMemoryError) {
+ tty->print_cr("java.lang.OutOfMemoryError: %s", message);
+ HeapDumper::dump_heap();
+ }
+
+ if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
+ VMError err(message);
+ err.report_java_out_of_memory();
+ }
+ }
+}
+
+
+extern "C" void ps();
+
+static bool error_reported = false;
+
+// call this when the VM is dying--it might loosen some asserts
+void set_error_reported() {
+ error_reported = true;
+}
+
+bool is_error_reported() {
+ return error_reported;
+}
+
+// ------ helper functions for debugging go here ------------
+
+#ifndef PRODUCT
+// All debug entries should be wrapped with a stack allocated
+// Command object. It makes sure a resource mark is set and
+// flushes the logfile to prevent file sharing problems.
+
+class Command : public StackObj {
+ private:
+ ResourceMark rm;
+ ResetNoHandleMark rnhm;
+ HandleMark hm;
+ bool debug_save;
+ public:
+ static int level;
+ Command(const char* str) {
+ debug_save = Debugging;
+ Debugging = true;
+ if (level++ > 0) return;
+ tty->cr();
+ tty->print_cr("\"Executing %s\"", str);
+ }
+
+ ~Command() { tty->flush(); Debugging = debug_save; level--; }
+};
+
+int Command::level = 0;
+
+extern "C" void blob(CodeBlob* cb) {
+ Command c("blob");
+ cb->print();
+}
+
+
+extern "C" void dump_vtable(address p) {
+ Command c("dump_vtable");
+ klassOop k = (klassOop)p;
+ instanceKlass::cast(k)->vtable()->print();
+}
+
+
+extern "C" void nm(intptr_t p) {
+ // Actually we look through all CodeBlobs (the nm name has been kept for backwards compatability)
+ Command c("nm");
+ CodeBlob* cb = CodeCache::find_blob((address)p);
+ if (cb == NULL) {
+ tty->print_cr("NULL");
+ } else {
+ cb->print();
+ }
+}
+
+
+extern "C" void disnm(intptr_t p) {
+ Command c("disnm");
+ CodeBlob* cb = CodeCache::find_blob((address) p);
+ cb->print();
+ Disassembler::decode(cb);
+}
+
+
+extern "C" void printnm(intptr_t p) {
+ char buffer[256];
+ sprintf(buffer, "printnm: " INTPTR_FORMAT, p);
+ Command c(buffer);
+ CodeBlob* cb = CodeCache::find_blob((address) p);
+ if (cb->is_nmethod()) {
+ nmethod* nm = (nmethod*)cb;
+ nm->print_nmethod(true);
+ }
+}
+
+
+extern "C" void universe() {
+ Command c("universe");
+ Universe::print();
+}
+
+
+extern "C" void verify() {
+ // try to run a verify on the entire system
+ // note: this may not be safe if we're not at a safepoint; for debugging,
+ // this manipulates the safepoint settings to avoid assertion failures
+ Command c("universe verify");
+ bool safe = SafepointSynchronize::is_at_safepoint();
+ if (!safe) {
+ tty->print_cr("warning: not at safepoint -- verify may fail");
+ SafepointSynchronize::set_is_at_safepoint();
+ }
+ // Ensure Eden top is correct before verification
+ Universe::heap()->prepare_for_verify();
+ Universe::verify(true);
+ if (!safe) SafepointSynchronize::set_is_not_at_safepoint();
+}
+
+
+extern "C" void pp(void* p) {
+ Command c("pp");
+ FlagSetting fl(PrintVMMessages, true);
+ if (Universe::heap()->is_in(p)) {
+ oop obj = oop(p);
+ obj->print();
+ } else {
+ tty->print("%#p", p);
+ }
+}
+
+
+// pv: print vm-printable object
+extern "C" void pa(intptr_t p) { ((AllocatedObj*) p)->print(); }
+extern "C" void findpc(intptr_t x);
+
+extern "C" void ps() { // print stack
+ Command c("ps");
+
+
+ // Prints the stack of the current Java thread
+ JavaThread* p = JavaThread::active();
+ tty->print(" for thread: ");
+ p->print();
+ tty->cr();
+
+ if (p->has_last_Java_frame()) {
+ // If the last_Java_fp is set we are in C land and
+ // can call the standard stack_trace function.
+ p->trace_stack();
+ } else {
+ frame f = os::current_frame();
+ RegisterMap reg_map(p);
+ f = f.sender(&reg_map);
+ tty->print("(guessing starting frame id=%#p based on current fp)\n", f.id());
+ p->trace_stack_from(vframe::new_vframe(&f, &reg_map, p));
+ pd_ps(f);
+ }
+
+}
+
+
+extern "C" void psf() { // print stack frames
+ {
+ Command c("psf");
+ JavaThread* p = JavaThread::active();
+ tty->print(" for thread: ");
+ p->print();
+ tty->cr();
+ if (p->has_last_Java_frame()) {
+ p->trace_frames();
+ }
+ }
+}
+
+
+extern "C" void threads() {
+ Command c("threads");
+ Threads::print(false, true);
+}
+
+
+extern "C" void psd() {
+ Command c("psd");
+ SystemDictionary::print();
+}
+
+
+extern "C" void safepoints() {
+ Command c("safepoints");
+ SafepointSynchronize::print_state();
+}
+
+
+extern "C" void pss() { // print all stacks
+ Command c("pss");
+ Threads::print(true, true);
+}
+
+
+extern "C" void debug() { // to set things up for compiler debugging
+ Command c("debug");
+ WizardMode = true;
+ PrintVMMessages = PrintCompilation = true;
+ PrintInlining = PrintAssembly = true;
+ tty->flush();
+}
+
+
+extern "C" void ndebug() { // undo debug()
+ Command c("ndebug");
+ PrintCompilation = false;
+ PrintInlining = PrintAssembly = false;
+ tty->flush();
+}
+
+
+extern "C" void flush() {
+ Command c("flush");
+ tty->flush();
+}
+
+
+extern "C" void events() {
+ Command c("events");
+ Events::print_last(tty, 50);
+}
+
+
+extern "C" void nevents(int n) {
+ Command c("events");
+ Events::print_last(tty, n);
+}
+
+
+// Given a heap address that was valid before the most recent GC, if
+// the oop that used to contain it is still live, prints the new
+// location of the oop and the address. Useful for tracking down
+// certain kinds of naked oop and oop map bugs.
+extern "C" void pnl(intptr_t old_heap_addr) {
+ // Print New Location of old heap address
+ Command c("pnl");
+#ifndef VALIDATE_MARK_SWEEP
+ tty->print_cr("Requires build with VALIDATE_MARK_SWEEP defined (debug build) and RecordMarkSweepCompaction enabled");
+#else
+ MarkSweep::print_new_location_of_heap_address((HeapWord*) old_heap_addr);
+#endif
+}
+
+
+extern "C" methodOop findm(intptr_t pc) {
+ Command c("findm");
+ nmethod* nm = CodeCache::find_nmethod((address)pc);
+ return (nm == NULL) ? (methodOop)NULL : nm->method();
+}
+
+
+extern "C" nmethod* findnm(intptr_t addr) {
+ Command c("findnm");
+ return CodeCache::find_nmethod((address)addr);
+}
+
+static address same_page(address x, address y) {
+ intptr_t page_bits = -os::vm_page_size();
+ if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) {
+ return x;
+ } else if (x > y) {
+ return (address)(intptr_t(y) | ~page_bits) + 1;
+ } else {
+ return (address)(intptr_t(y) & page_bits);
+ }
+}
+
+
+static void find(intptr_t x, bool print_pc) {
+ address addr = (address)x;
+
+ CodeBlob* b = CodeCache::find_blob_unsafe(addr);
+ if (b != NULL) {
+ if (b->is_buffer_blob()) {
+ // the interpreter is generated into a buffer blob
+ InterpreterCodelet* i = Interpreter::codelet_containing(addr);
+ if (i != NULL) {
+ i->print();
+ return;
+ }
+ if (Interpreter::contains(addr)) {
+ tty->print_cr(INTPTR_FORMAT " is pointing into interpreter code (not bytecode specific)", addr);
+ return;
+ }
+ //
+ if (AdapterHandlerLibrary::contains(b)) {
+ AdapterHandlerLibrary::print_handler(b);
+ }
+ // the stubroutines are generated into a buffer blob
+ StubCodeDesc* d = StubCodeDesc::desc_for(addr);
+ if (d != NULL) {
+ d->print();
+ if (print_pc) tty->cr();
+ return;
+ }
+ if (StubRoutines::contains(addr)) {
+ tty->print_cr(INTPTR_FORMAT " is pointing to an (unnamed) stub routine", addr);
+ return;
+ }
+ // the InlineCacheBuffer is using stubs generated into a buffer blob
+ if (InlineCacheBuffer::contains(addr)) {
+ tty->print_cr(INTPTR_FORMAT "is pointing into InlineCacheBuffer", addr);
+ return;
+ }
+ VtableStub* v = VtableStubs::stub_containing(addr);
+ if (v != NULL) {
+ v->print();
+ return;
+ }
+ }
+ if (print_pc && b->is_nmethod()) {
+ ResourceMark rm;
+ tty->print("%#p: Compiled ", addr);
+ ((nmethod*)b)->method()->print_value_on(tty);
+ tty->print(" = (CodeBlob*)" INTPTR_FORMAT, b);
+ tty->cr();
+ return;
+ }
+ if ( b->is_nmethod()) {
+ if (b->is_zombie()) {
+ tty->print_cr(INTPTR_FORMAT " is zombie nmethod", b);
+ } else if (b->is_not_entrant()) {
+ tty->print_cr(INTPTR_FORMAT " is non-entrant nmethod", b);
+ }
+ }
+ b->print();
+ return;
+ }
+
+ if (Universe::heap()->is_in_reserved(addr)) {
+ HeapWord* p = Universe::heap()->block_start(addr);
+ bool print = false;
+ // If we couldn't find it it just may mean that heap wasn't parseable
+ // See if we were just given an oop directly
+ if (p != NULL && Universe::heap()->block_is_obj(p)) {
+ print = true;
+ } else if (p == NULL && ((oopDesc*)addr)->is_oop()) {
+ p = (HeapWord*) addr;
+ print = true;
+ }
+ if (print) {
+ oop(p)->print();
+ if (p != (HeapWord*)x && oop(p)->is_constMethod() &&
+ constMethodOop(p)->contains(addr)) {
+ Thread *thread = Thread::current();
+ HandleMark hm(thread);
+ methodHandle mh (thread, constMethodOop(p)->method());
+ if (!mh->is_native()) {
+ tty->print_cr("bci_from(%p) = %d; print_codes():",
+ addr, mh->bci_from(address(x)));
+ mh->print_codes();
+ }
+ }
+ return;
+ }
+ }
+ if (JNIHandles::is_global_handle((jobject) addr)) {
+ tty->print_cr(INTPTR_FORMAT "is a global jni handle", addr);
+ return;
+ }
+ if (JNIHandles::is_weak_global_handle((jobject) addr)) {
+ tty->print_cr(INTPTR_FORMAT "is a weak global jni handle", addr);
+ return;
+ }
+ if (JNIHandleBlock::any_contains((jobject) addr)) {
+ tty->print_cr(INTPTR_FORMAT "is a local jni handle", addr);
+ return;
+ }
+
+ for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
+ // Check for priviledge stack
+ if (thread->privileged_stack_top() != NULL && thread->privileged_stack_top()->contains(addr)) {
+ tty->print_cr(INTPTR_FORMAT "is pointing into the priviledge stack for thread: " INTPTR_FORMAT, addr, thread);
+ return;
+ }
+ // If the addr is a java thread print information about that.
+ if (addr == (address)thread) {
+ thread->print();
+ return;
+ }
+ }
+
+ // Try an OS specific find
+ if (os::find(addr)) {
+ return;
+ }
+
+ if (print_pc) {
+ tty->print_cr(INTPTR_FORMAT ": probably in C++ code; check debugger", addr);
+ Disassembler::decode(same_page(addr-40,addr),same_page(addr+40,addr));
+ return;
+ }
+
+ tty->print_cr(INTPTR_FORMAT "is pointing to unknown location", addr);
+}
+
+
+class LookForRefInGenClosure : public OopsInGenClosure {
+public:
+ oop target;
+ void do_oop(oop* o) {
+ if (o != NULL && *o == target) {
+ tty->print_cr("0x%08x", o);
+ }
+ }
+};
+
+
+class LookForRefInObjectClosure : public ObjectClosure {
+private:
+ LookForRefInGenClosure look_in_object;
+public:
+ LookForRefInObjectClosure(oop target) { look_in_object.target = target; }
+ void do_object(oop obj) {
+ obj->oop_iterate(&look_in_object);
+ }
+};
+
+
+static void findref(intptr_t x) {
+ GenCollectedHeap *gch = GenCollectedHeap::heap();
+ LookForRefInGenClosure lookFor;
+ lookFor.target = (oop) x;
+ LookForRefInObjectClosure look_in_object((oop) x);
+
+ tty->print_cr("Searching heap:");
+ gch->object_iterate(&look_in_object);
+
+ tty->print_cr("Searching strong roots:");
+ Universe::oops_do(&lookFor, false);
+ JNIHandles::oops_do(&lookFor); // Global (strong) JNI handles
+ Threads::oops_do(&lookFor);
+ ObjectSynchronizer::oops_do(&lookFor);
+ //FlatProfiler::oops_do(&lookFor);
+ SystemDictionary::oops_do(&lookFor);
+
+ tty->print_cr("Done.");
+}
+
+class FindClassObjectClosure: public ObjectClosure {
+ private:
+ const char* _target;
+ public:
+ FindClassObjectClosure(const char name[]) { _target = name; }
+
+ virtual void do_object(oop obj) {
+ if (obj->is_klass()) {
+ Klass* k = klassOop(obj)->klass_part();
+ if (k->name() != NULL) {
+ ResourceMark rm;
+ const char* ext = k->external_name();
+ if ( strcmp(_target, ext) == 0 ) {
+ tty->print_cr("Found " INTPTR_FORMAT, obj);
+ obj->print();
+ }
+ }
+ }
+ }
+};
+
+//
+extern "C" void findclass(const char name[]) {
+ Command c("findclass");
+ if (name != NULL) {
+ tty->print_cr("Finding class %s -> ", name);
+ FindClassObjectClosure srch(name);
+ Universe::heap()->permanent_object_iterate(&srch);
+ }
+}
+
+// Another interface that isn't ambiguous in dbx.
+// Can we someday rename the other find to hsfind?
+extern "C" void hsfind(intptr_t x) {
+ Command c("hsfind");
+ find(x, false);
+}
+
+
+extern "C" void hsfindref(intptr_t x) {
+ Command c("hsfindref");
+ findref(x);
+}
+
+extern "C" void find(intptr_t x) {
+ Command c("find");
+ find(x, false);
+}
+
+
+extern "C" void findpc(intptr_t x) {
+ Command c("findpc");
+ find(x, true);
+}
+
+
+// int versions of all methods to avoid having to type type casts in the debugger
+
+void pp(intptr_t p) { pp((void*)p); }
+void pp(oop p) { pp((void*)p); }
+
+void help() {
+ Command c("help");
+ tty->print_cr("basic");
+ tty->print_cr(" pp(void* p) - try to make sense of p");
+ tty->print_cr(" pv(intptr_t p)- ((PrintableResourceObj*) p)->print()");
+ tty->print_cr(" ps() - print current thread stack");
+ tty->print_cr(" pss() - print all thread stacks");
+ tty->print_cr(" pm(int pc) - print methodOop given compiled PC");
+ tty->print_cr(" findm(intptr_t pc) - finds methodOop");
+ tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it");
+
+ tty->print_cr("misc.");
+ tty->print_cr(" flush() - flushes the log file");
+ tty->print_cr(" events() - dump last 50 events");
+
+
+ tty->print_cr("compiler debugging");
+ tty->print_cr(" debug() - to set things up for compiler debugging");
+ tty->print_cr(" ndebug() - undo debug");
+}
+
+#if 0
+
+// BobV's command parser for debugging on windows when nothing else works.
+
+enum CommandID {
+ CMDID_HELP,
+ CMDID_QUIT,
+ CMDID_HSFIND,
+ CMDID_PSS,
+ CMDID_PS,
+ CMDID_PSF,
+ CMDID_FINDM,
+ CMDID_FINDNM,
+ CMDID_PP,
+ CMDID_BPT,
+ CMDID_EXIT,
+ CMDID_VERIFY,
+ CMDID_THREADS,
+ CMDID_ILLEGAL = 99
+};
+
+struct CommandParser {
+ char *name;
+ CommandID code;
+ char *description;
+};
+
+struct CommandParser CommandList[] = {
+ (char *)"help", CMDID_HELP, " Dump this list",
+ (char *)"quit", CMDID_QUIT, " Return from this routine",
+ (char *)"hsfind", CMDID_HSFIND, "Perform an hsfind on an address",
+ (char *)"ps", CMDID_PS, " Print Current Thread Stack Trace",
+ (char *)"pss", CMDID_PSS, " Print All Thread Stack Trace",
+ (char *)"psf", CMDID_PSF, " Print All Stack Frames",
+ (char *)"findm", CMDID_FINDM, " Find a methodOop from a PC",
+ (char *)"findnm", CMDID_FINDNM, "Find an nmethod from a PC",
+ (char *)"pp", CMDID_PP, " Find out something about a pointer",
+ (char *)"break", CMDID_BPT, " Execute a breakpoint",
+ (char *)"exitvm", CMDID_EXIT, "Exit the VM",
+ (char *)"verify", CMDID_VERIFY, "Perform a Heap Verify",
+ (char *)"thread", CMDID_THREADS, "Dump Info on all Threads",
+ (char *)0, CMDID_ILLEGAL
+};
+
+
+// get_debug_command()
+//
+// Read a command from standard input.
+// This is useful when you have a debugger
+// which doesn't support calling into functions.
+//
+void get_debug_command()
+{
+ ssize_t count;
+ int i,j;
+ bool gotcommand;
+ intptr_t addr;
+ char buffer[256];
+ nmethod *nm;
+ methodOop m;
+
+ tty->print_cr("You have entered the diagnostic command interpreter");
+ tty->print("The supported commands are:\n");
+ for ( i=0; ; i++ ) {
+ if ( CommandList[i].code == CMDID_ILLEGAL )
+ break;
+ tty->print_cr(" %s \n", CommandList[i].name );
+ }
+
+ while ( 1 ) {
+ gotcommand = false;
+ tty->print("Please enter a command: ");
+ count = scanf("%s", buffer) ;
+ if ( count >=0 ) {
+ for ( i=0; ; i++ ) {
+ if ( CommandList[i].code == CMDID_ILLEGAL ) {
+ if (!gotcommand) tty->print("Invalid command, please try again\n");
+ break;
+ }
+ if ( strcmp(buffer, CommandList[i].name) == 0 ) {
+ gotcommand = true;
+ switch ( CommandList[i].code ) {
+ case CMDID_PS:
+ ps();
+ break;
+ case CMDID_PSS:
+ pss();
+ break;
+ case CMDID_PSF:
+ psf();
+ break;
+ case CMDID_FINDM:
+ tty->print("Please enter the hex addr to pass to findm: ");
+ scanf("%I64X", &addr);
+ m = (methodOop)findm(addr);
+ tty->print("findm(0x%I64X) returned 0x%I64X\n", addr, m);
+ break;
+ case CMDID_FINDNM:
+ tty->print("Please enter the hex addr to pass to findnm: ");
+ scanf("%I64X", &addr);
+ nm = (nmethod*)findnm(addr);
+ tty->print("findnm(0x%I64X) returned 0x%I64X\n", addr, nm);
+ break;
+ case CMDID_PP:
+ tty->print("Please enter the hex addr to pass to pp: ");
+ scanf("%I64X", &addr);
+ pp((void*)addr);
+ break;
+ case CMDID_EXIT:
+ exit(0);
+ case CMDID_HELP:
+ tty->print("Here are the supported commands: ");
+ for ( j=0; ; j++ ) {
+ if ( CommandList[j].code == CMDID_ILLEGAL )
+ break;
+ tty->print_cr(" %s -- %s\n", CommandList[j].name,
+ CommandList[j].description );
+ }
+ break;
+ case CMDID_QUIT:
+ return;
+ break;
+ case CMDID_BPT:
+ BREAKPOINT;
+ break;
+ case CMDID_VERIFY:
+ verify();;
+ break;
+ case CMDID_THREADS:
+ threads();;
+ break;
+ case CMDID_HSFIND:
+ tty->print("Please enter the hex addr to pass to hsfind: ");
+ scanf("%I64X", &addr);
+ tty->print("Calling hsfind(0x%I64X)\n", addr);
+ hsfind(addr);
+ break;
+ default:
+ case CMDID_ILLEGAL:
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+#endif // PRODUCT
diff --git a/src/share/vm/utilities/debug.hpp b/src/share/vm/utilities/debug.hpp
new file mode 100644
index 000000000..98d3e6226
--- /dev/null
+++ b/src/share/vm/utilities/debug.hpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// assertions
+#ifdef ASSERT
+// Turn this off by default:
+//#define USE_REPEATED_ASSERTS
+#ifdef USE_REPEATED_ASSERTS
+ #define assert(p,msg) \
+ { for (int __i = 0; __i < AssertRepeat; __i++) { \
+ if (!(p)) { \
+ report_assertion_failure(__FILE__, __LINE__, \
+ "assert(" XSTR(p) ",\"" msg "\")");\
+ BREAKPOINT; \
+ } \
+ } \
+ }
+#else
+ #define assert(p,msg) \
+ if (!(p)) { \
+ report_assertion_failure(__FILE__, __LINE__, \
+ "assert(" XSTR(p) ",\"" msg "\")");\
+ BREAKPOINT; \
+ }
+#endif
+
+// This version of assert is for use with checking return status from
+// library calls that return actual error values eg. EINVAL,
+// ENOMEM etc, rather than returning -1 and setting errno.
+// When the status is not what is expected it is very useful to know
+// what status was actually returned, so we pass the status variable as
+// an extra arg and use strerror to convert it to a meaningful string
+// like "Invalid argument", "out of memory" etc
+#define assert_status(p, status, msg) \
+ do { \
+ if (!(p)) { \
+ char buf[128]; \
+ snprintf(buf, 127, \
+ "assert_status(" XSTR(p) ", error: %s(%d), \"" msg "\")" , \
+ strerror((status)), (status)); \
+ report_assertion_failure(__FILE__, __LINE__, buf); \
+ BREAKPOINT; \
+ } \
+ } while (0)
+
+// Another version of assert where the message is not a string literal
+// The boolean condition is not printed out because cpp doesn't like it.
+#define assert_msg(p, msg) \
+ if (!(p)) { \
+ report_assertion_failure(__FILE__, __LINE__, msg); \
+ BREAKPOINT; \
+ }
+
+// Do not assert this condition if there's already another error reported.
+#define assert_if_no_error(cond,msg) assert((cond) || is_error_reported(), msg)
+#else
+ #define assert(p,msg)
+ #define assert_status(p,status,msg)
+ #define assert_if_no_error(cond,msg)
+ #define assert_msg(cond,msg)
+#endif
+
+
+// fatals
+#define fatal(m) { report_fatal(__FILE__, __LINE__, m ); BREAKPOINT; }
+#define fatal1(m,x1) { report_fatal_vararg(__FILE__, __LINE__, m, x1 ); BREAKPOINT; }
+#define fatal2(m,x1,x2) { report_fatal_vararg(__FILE__, __LINE__, m, x1, x2 ); BREAKPOINT; }
+#define fatal3(m,x1,x2,x3) { report_fatal_vararg(__FILE__, __LINE__, m, x1, x2, x3 ); BREAKPOINT; }
+#define fatal4(m,x1,x2,x3,x4) { report_fatal_vararg(__FILE__, __LINE__, m, x1, x2, x3, x4 ); BREAKPOINT; }
+
+// out of memory
+#define vm_exit_out_of_memory(s,m) { report_vm_out_of_memory(__FILE__, __LINE__, s, m ); BREAKPOINT; }
+#define vm_exit_out_of_memory1(s,m,x1) { report_vm_out_of_memory_vararg(__FILE__, __LINE__, s, m, x1 ); BREAKPOINT; }
+#define vm_exit_out_of_memory2(s,m,x1,x2) { report_vm_out_of_memory_vararg(__FILE__, __LINE__, s, m, x1, x2 ); BREAKPOINT; }
+#define vm_exit_out_of_memory3(s,m,x1,x2,x3) { report_vm_out_of_memory_vararg(__FILE__, __LINE__, s, m, x1, x2, x3 ); BREAKPOINT; }
+#define vm_exit_out_of_memory4(s,m,x1,x2,x3,x4) { report_vm_out_of_memory_vararg(__FILE__, __LINE__, s, m, x1, x2, x3, x4); BREAKPOINT; }
+
+// guarantee is like assert except it's always executed -- use it for
+// cheap tests that catch errors that would otherwise be hard to find
+// guarantee is also used for Verify options.
+#define guarantee(b,msg) { if (!(b)) fatal("guarantee(" XSTR(b) ",\"" msg "\")"); }
+
+#define ShouldNotCallThis() { report_should_not_call (__FILE__, __LINE__); BREAKPOINT; }
+#define ShouldNotReachHere() { report_should_not_reach_here (__FILE__, __LINE__); BREAKPOINT; }
+#define Unimplemented() { report_unimplemented (__FILE__, __LINE__); BREAKPOINT; }
+#define Untested(msg) { report_untested (__FILE__, __LINE__, msg); BREAKPOINT; }
+
+// error reporting helper functions
+void report_assertion_failure(const char* file_name, int line_no, const char* message);
+void report_fatal_vararg(const char* file_name, int line_no, const char* format, ...);
+void report_fatal(const char* file_name, int line_no, const char* message);
+void report_vm_out_of_memory_vararg(const char* file_name, int line_no, size_t size, const char* format, ...);
+void report_vm_out_of_memory(const char* file_name, int line_no, size_t size, const char* message);
+void report_should_not_call(const char* file_name, int line_no);
+void report_should_not_reach_here(const char* file_name, int line_no);
+void report_unimplemented(const char* file_name, int line_no);
+void report_untested(const char* file_name, int line_no, const char* msg);
+void warning(const char* format, ...);
+
+// out of memory reporting
+void report_java_out_of_memory(const char* message);
+
+// Support for self-destruct
+bool is_error_reported();
+void set_error_reported();
+
+void pd_ps(frame f);
+void pd_obfuscate_location(char *buf, size_t buflen);
diff --git a/src/share/vm/utilities/defaultStream.hpp b/src/share/vm/utilities/defaultStream.hpp
new file mode 100644
index 000000000..979f5cd74
--- /dev/null
+++ b/src/share/vm/utilities/defaultStream.hpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2003-2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+class defaultStream : public xmlTextStream {
+ friend void ostream_abort();
+ public:
+ enum { NO_WRITER = -1 };
+ private:
+ bool _inited;
+ fileStream* _log_file; // XML-formatted file shared by all threads
+ static int _output_fd;
+ static int _error_fd;
+ static FILE* _output_stream;
+ static FILE* _error_stream;
+
+ void init();
+ void init_log();
+ void finish_log();
+ void finish_log_on_error(char *buf, int buflen);
+ public:
+ // must defer time stamp due to the fact that os::init() hasn't
+ // yet been called and os::elapsed_counter() may not be valid
+ defaultStream() {
+ _log_file = NULL;
+ _inited = false;
+ _writer = -1;
+ _last_writer = -1;
+ }
+
+ ~defaultStream() {
+ if (has_log_file()) finish_log();
+ }
+
+ static inline FILE* output_stream() {
+ return DisplayVMOutputToStderr ? _error_stream : _output_stream;
+ }
+ static inline FILE* error_stream() {
+ return DisplayVMOutputToStdout ? _output_stream : _error_stream;
+ }
+ static inline int output_fd() {
+ return DisplayVMOutputToStderr ? _error_fd : _output_fd;
+ }
+ static inline int error_fd() {
+ return DisplayVMOutputToStdout ? _output_fd : _error_fd;
+ }
+
+ virtual void write(const char* s, size_t len);
+
+ void flush() {
+ // once we can determine whether we are in a signal handler, we
+ // should add the following assert here:
+ // assert(xxxxxx, "can not flush buffer inside signal handler");
+ xmlTextStream::flush();
+ fflush(output_stream());
+ if (has_log_file()) _log_file->flush();
+ }
+
+ // advisory lock/unlock of _writer field:
+ private:
+ intx _writer; // thread_id with current rights to output
+ intx _last_writer;
+ public:
+ intx hold(intx writer_id);
+ void release(intx holder);
+ intx writer() { return _writer; }
+ bool has_log_file();
+
+ static defaultStream* instance; // sole instance
+};
diff --git a/src/share/vm/utilities/dtrace.hpp b/src/share/vm/utilities/dtrace.hpp
new file mode 100644
index 000000000..e4e9f03a4
--- /dev/null
+++ b/src/share/vm/utilities/dtrace.hpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2005-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#if defined(SOLARIS) && defined(DTRACE_ENABLED)
+
+#include <sys/sdt.h>
+
+#define DTRACE_ONLY(x) x
+#define NOT_DTRACE(x)
+
+#else // ndef SOLARIS || ndef DTRACE_ENABLED
+
+#define DTRACE_ONLY(x)
+#define NOT_DTRACE(x) x
+
+#define DTRACE_PROBE(a,b) {;}
+#define DTRACE_PROBE1(a,b,c) {;}
+#define DTRACE_PROBE2(a,b,c,d) {;}
+#define DTRACE_PROBE3(a,b,c,d,e) {;}
+#define DTRACE_PROBE4(a,b,c,d,e,f) {;}
+#define DTRACE_PROBE5(a,b,c,d,e,f,g) {;}
+
+#endif
+
+#define HS_DTRACE_PROBE_FN(provider,name)\
+ __dtrace_##provider##___##name
+
+#define HS_DTRACE_PROBE_DECL_N(provider,name,args) \
+ DTRACE_ONLY(extern "C" void HS_DTRACE_PROBE_FN(provider,name) args)
+#define HS_DTRACE_PROBE_CDECL_N(provider,name,args) \
+ DTRACE_ONLY(extern void HS_DTRACE_PROBE_FN(provider,name) args)
+
+/* Dtrace probe declarations */
+#define HS_DTRACE_PROBE_DECL(provider,name) \
+ HS_DTRACE_PROBE_DECL0(provider,name)
+#define HS_DTRACE_PROBE_DECL0(provider,name)\
+ HS_DTRACE_PROBE_DECL_N(provider,name,(void))
+#define HS_DTRACE_PROBE_DECL1(provider,name,t0)\
+ HS_DTRACE_PROBE_DECL_N(provider,name,(uintptr_t))
+#define HS_DTRACE_PROBE_DECL2(provider,name,t0,t1)\
+ HS_DTRACE_PROBE_DECL_N(provider,name,(uintptr_t,uintptr_t))
+#define HS_DTRACE_PROBE_DECL3(provider,name,t0,t1,t2)\
+ HS_DTRACE_PROBE_DECL_N(provider,name,(uintptr_t,uintptr_t,uintptr_t))
+#define HS_DTRACE_PROBE_DECL4(provider,name,t0,t1,t2,t3)\
+ HS_DTRACE_PROBE_DECL_N(provider,name,(uintptr_t,uintptr_t,uintptr_t,\
+ uintptr_t))
+#define HS_DTRACE_PROBE_DECL5(provider,name,t0,t1,t2,t3,t4)\
+ HS_DTRACE_PROBE_DECL_N(provider,name,(\
+ uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t))
+#define HS_DTRACE_PROBE_DECL6(provider,name,t0,t1,t2,t3,t4,t5)\
+ HS_DTRACE_PROBE_DECL_N(provider,name,(\
+ uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t))
+#define HS_DTRACE_PROBE_DECL7(provider,name,t0,t1,t2,t3,t4,t5,t6)\
+ HS_DTRACE_PROBE_DECL_N(provider,name,(\
+ uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t))
+#define HS_DTRACE_PROBE_DECL8(provider,name,t0,t1,t2,t3,t4,t5,t6,t7)\
+ HS_DTRACE_PROBE_DECL_N(provider,name,(\
+ uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,\
+ uintptr_t))
+#define HS_DTRACE_PROBE_DECL9(provider,name,t0,t1,t2,t3,t4,t5,t6,t7,t8)\
+ HS_DTRACE_PROBE_DECL_N(provider,name,(\
+ uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,\
+ uintptr_t,uintptr_t))
+#define HS_DTRACE_PROBE_DECL10(provider,name,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9)\
+ HS_DTRACE_PROBE_DECL_N(provider,name,(\
+ uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,\
+ uintptr_t,uintptr_t,uintptr_t))
+
+/* Dtrace probe definitions */
+#define HS_DTRACE_PROBE_N(provider,name, args) \
+ DTRACE_ONLY(HS_DTRACE_PROBE_FN(provider,name) args)
+
+#define HS_DTRACE_PROBE(provider,name) HS_DTRACE_PROBE0(provider,name)
+#define HS_DTRACE_PROBE0(provider,name)\
+ HS_DTRACE_PROBE_N(provider,name,())
+#define HS_DTRACE_PROBE1(provider,name,a0)\
+ HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0))
+#define HS_DTRACE_PROBE2(provider,name,a0,a1)\
+ HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1))
+#define HS_DTRACE_PROBE3(provider,name,a0,a1,a2)\
+ HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2))
+#define HS_DTRACE_PROBE4(provider,name,a0,a1,a2,a3)\
+ HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
+ (uintptr_t)a3))
+#define HS_DTRACE_PROBE5(provider,name,a0,a1,a2,a3,a4)\
+ HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
+ (uintptr_t)a3,(uintptr_t)a4))
+#define HS_DTRACE_PROBE6(provider,name,a0,a1,a2,a3,a4,a5)\
+ HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
+ (uintptr_t)a3,(uintptr_t)a4,(uintptr_t)a5))
+#define HS_DTRACE_PROBE7(provider,name,a0,a1,a2,a3,a4,a5,a6)\
+ HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
+ (uintptr_t)a3,(uintptr_t)a4,(uintptr_t)a5,(uintptr_t)a6))
+#define HS_DTRACE_PROBE8(provider,name,a0,a1,a2,a3,a4,a5,a6,a7)\
+ HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
+ (uintptr_t)a3,(uintptr_t)a4,(uintptr_t)a5,(uintptr_t)a6,(uintptr_t)a7))
+#define HS_DTRACE_PROBE9(provider,name,a0,a1,a2,a3,a4,a5,a6,a7,a8)\
+ HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
+ (uintptr_t)a3,(uintptr_t)a4,(uintptr_t)a5,(uintptr_t)a6,(uintptr_t)a7,\
+ (uintptr_t)a8))
+#define HS_DTRACE_PROBE10(provider,name,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)\
+ HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
+ (uintptr_t)a3,(uintptr_t)a4,(uintptr_t)a5,(uintptr_t)a6,(uintptr_t)a7,\
+ (uintptr_t)a8,(uintptr_t)a9))
diff --git a/src/share/vm/utilities/events.cpp b/src/share/vm/utilities/events.cpp
new file mode 100644
index 000000000..b24452e83
--- /dev/null
+++ b/src/share/vm/utilities/events.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright 1997-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include "incls/_precompiled.incl"
+#include "incls/_events.cpp.incl"
+
+
+#ifndef PRODUCT
+
+////////////////////////////////////////////////////////////////////////////
+// Event
+
+typedef u4 EventID;
+
+class Event VALUE_OBJ_CLASS_SPEC {
+ private:
+ jlong _time_tick;
+ intx _thread_id;
+ const char* _format;
+ int _indent;
+ intptr_t _arg_1;
+ intptr_t _arg_2;
+ intptr_t _arg_3;
+
+ // only EventBuffer::add_event() can assign event id
+ friend class EventBuffer;
+ EventID _id;
+
+ public:
+
+ void clear() { _format = NULL; }
+
+ EventID id() const { return _id; }
+
+ void fill(int indent, const char* format, intptr_t arg_1, intptr_t arg_2, intptr_t arg_3) {
+ _format = format;
+ _arg_1 = arg_1;
+ _arg_2 = arg_2;
+ _arg_3 = arg_3;
+
+ _indent = indent;
+
+ _thread_id = os::current_thread_id();
+ _time_tick = os::elapsed_counter();
+ }
+
+ void print_on(outputStream *st) {
+ if (_format == NULL) return;
+ st->print(" %d", _thread_id);
+ st->print(" %3.2g ", (double)_time_tick / os::elapsed_frequency());
+ st->fill_to(20);
+ for (int index = 0; index < _indent; index++) {
+ st->print("| ");
+ }
+ st->print_cr(_format, _arg_1, _arg_2, _arg_3);
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////
+// EventBuffer
+//
+// Simple lock-free event queue. Every event has a unique 32-bit id.
+// It's fine if two threads add events at the same time, because they
+// will get different event id, and then write to different buffer location.
+// However, it is assumed that add_event() is quick enough (or buffer size
+// is big enough), so when one thread is adding event, there can't be more
+// than "size" events created by other threads; otherwise we'll end up having
+// two threads writing to the same location.
+
+class EventBuffer : AllStatic {
+ private:
+ static Event* buffer;
+ static int size;
+ static jint indent;
+ static volatile EventID _current_event_id;
+
+ static EventID get_next_event_id() {
+ return (EventID)Atomic::add(1, (jint*)&_current_event_id);
+ }
+
+ public:
+ static void inc_indent() { Atomic::inc(&indent); }
+ static void dec_indent() { Atomic::dec(&indent); }
+
+ static bool get_event(EventID id, Event* event) {
+ int index = (int)(id % size);
+ if (buffer[index].id() == id) {
+ memcpy(event, &buffer[index], sizeof(Event));
+ // check id again; if buffer[index] is being updated by another thread,
+ // event->id() will contain different value.
+ return (event->id() == id);
+ } else {
+ // id does not match - id is invalid, or event is overwritten
+ return false;
+ }
+ }
+
+ // add a new event to the queue; if EventBuffer is full, this call will
+ // overwrite the oldest event in the queue
+ static EventID add_event(const char* format,
+ intptr_t arg_1, intptr_t arg_2, intptr_t arg_3) {
+ // assign a unique id
+ EventID id = get_next_event_id();
+
+ // event will be copied to buffer[index]
+ int index = (int)(id % size);
+
+ // first, invalidate id, buffer[index] can't have event with id = index + 2
+ buffer[index]._id = index + 2;
+
+ // make sure everyone has seen that buffer[index] is invalid
+ OrderAccess::fence();
+
+ // ... before updating its value
+ buffer[index].fill(indent, format, arg_1, arg_2, arg_3);
+
+ // finally, set up real event id, now buffer[index] contains valid event
+ OrderAccess::release_store(&(buffer[index]._id), id);
+
+ return id;
+ }
+
+ static void print_last(outputStream *st, int number) {
+ st->print_cr("[Last %d events in the event buffer]", number);
+ st->print_cr("-<thd>-<elapsed sec>-<description>---------------------");
+
+ int count = 0;
+ EventID id = _current_event_id;
+ while (count < number) {
+ Event event;
+ if (get_event(id, &event)) {
+ event.print_on(st);
+ }
+ id--;
+ count++;
+ }
+ }
+
+ static void print_all(outputStream* st) {
+ print_last(st, size);
+ }
+
+ static void init() {
+ // Allocate the event buffer
+ size = EventLogLength;
+ buffer = NEW_C_HEAP_ARRAY(Event, size);
+
+ _current_event_id = 0;
+
+ // Clear the event buffer
+ for (int index = 0; index < size; index++) {
+ buffer[index]._id = index + 1; // index + 1 is invalid id
+ buffer[index].clear();
+ }
+ }
+};
+
+Event* EventBuffer::buffer;
+int EventBuffer::size;
+volatile EventID EventBuffer::_current_event_id;
+int EventBuffer::indent;
+
+////////////////////////////////////////////////////////////////////////////
+// Events
+
+// Events::log() is safe for signal handlers
+void Events::log(const char* format, ...) {
+ if (LogEvents) {
+ va_list ap;
+ va_start(ap, format);
+ intptr_t arg_1 = va_arg(ap, intptr_t);
+ intptr_t arg_2 = va_arg(ap, intptr_t);
+ intptr_t arg_3 = va_arg(ap, intptr_t);
+ va_end(ap);
+
+ EventBuffer::add_event(format, arg_1, arg_2, arg_3);
+ }
+}
+
+void Events::print_all(outputStream *st) {
+ EventBuffer::print_all(st);
+}
+
+void Events::print_last(outputStream *st, int number) {
+ EventBuffer::print_last(st, number);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// EventMark
+
+EventMark::EventMark(const char* format, ...) {
+ if (LogEvents) {
+ va_list ap;
+ va_start(ap, format);
+ intptr_t arg_1 = va_arg(ap, intptr_t);
+ intptr_t arg_2 = va_arg(ap, intptr_t);
+ intptr_t arg_3 = va_arg(ap, intptr_t);
+ va_end(ap);
+
+ EventBuffer::add_event(format, arg_1, arg_2, arg_3);
+ EventBuffer::inc_indent();
+ }
+}
+
+EventMark::~EventMark() {
+ if (LogEvents) {
+ EventBuffer::dec_indent();
+ EventBuffer::add_event("done", 0, 0, 0);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+void eventlog_init() {
+ EventBuffer::init();
+}
+
+int print_all_events(outputStream *st) {
+ EventBuffer::print_all(st);
+ return 1;
+}
+
+#else
+
+void eventlog_init() {}
+int print_all_events(outputStream *st) { return 0; }
+
+#endif // PRODUCT
diff --git a/src/share/vm/utilities/events.hpp b/src/share/vm/utilities/events.hpp
new file mode 100644
index 000000000..fa76807aa
--- /dev/null
+++ b/src/share/vm/utilities/events.hpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1997-2003 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// Events and EventMark provide interfaces to log events taking place in the vm.
+// This facility is extremly useful for post-mortem debugging. The eventlog
+// often provides crucial information about events leading up to the crash.
+//
+// All arguments past the format string must be passed as an intptr_t.
+//
+// To log a single event use:
+// Events::log("New nmethod has been created " INTPTR_FORMAT, nm);
+//
+// To log a block of events use:
+// EventMark m("GarbageCollecting %d", (intptr_t)gc_number);
+//
+// The constructor to eventlog indents the eventlog until the
+// destructor has been executed.
+//
+// IMPLEMENTATION RESTRICTION:
+// Max 3 arguments are saved for each logged event.
+//
+
+class Events : AllStatic {
+ public:
+ // Logs an event, format as printf
+ static void log(const char* format, ...) PRODUCT_RETURN;
+
+ // Prints all events in the buffer
+ static void print_all(outputStream* st) PRODUCT_RETURN;
+
+ // Prints last number events from the event buffer
+ static void print_last(outputStream *st, int number) PRODUCT_RETURN;
+};
+
+class EventMark : public StackObj {
+ public:
+ // log a begin event, format as printf
+ EventMark(const char* format, ...) PRODUCT_RETURN;
+ // log an end event
+ ~EventMark() PRODUCT_RETURN;
+};
+
+int print_all_events(outputStream *st);
diff --git a/src/share/vm/utilities/exceptions.cpp b/src/share/vm/utilities/exceptions.cpp
new file mode 100644
index 000000000..91c3cd733
--- /dev/null
+++ b/src/share/vm/utilities/exceptions.cpp
@@ -0,0 +1,388 @@
+/*
+ * Copyright 1998-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include "incls/_precompiled.incl"
+#include "incls/_exceptions.cpp.incl"
+
+
+// Implementation of ThreadShadow
+void check_ThreadShadow() {
+ const ByteSize offset1 = byte_offset_of(ThreadShadow, _pending_exception);
+ const ByteSize offset2 = Thread::pending_exception_offset();
+ if (offset1 != offset2) fatal("ThreadShadow::_pending_exception is not positioned correctly");
+}
+
+
+void ThreadShadow::set_pending_exception(oop exception, const char* file, int line) {
+ assert(exception != NULL && exception->is_oop(), "invalid exception oop");
+ _pending_exception = exception;
+ _exception_file = file;
+ _exception_line = line;
+}
+
+void ThreadShadow::clear_pending_exception() {
+ if (TraceClearedExceptions) {
+ if (_pending_exception != NULL) {
+ tty->print_cr("Thread::clear_pending_exception: cleared exception:");
+ _pending_exception->print();
+ }
+ }
+ _pending_exception = NULL;
+ _exception_file = NULL;
+ _exception_line = 0;
+}
+// Implementation of Exceptions
+
+bool Exceptions::special_exception(Thread* thread, const char* file, int line, Handle h_exception) {
+ // bootstrapping check
+ if (!Universe::is_fully_initialized()) {
+ vm_exit_during_initialization(h_exception);
+ ShouldNotReachHere();
+ }
+
+ if (thread->is_VM_thread()
+ || thread->is_Compiler_thread() ) {
+ // We do not care what kind of exception we get for the vm-thread or a thread which
+ // is compiling. We just install a dummy exception object
+ thread->set_pending_exception(Universe::vm_exception(), file, line);
+ return true;
+ }
+
+ return false;
+}
+
+bool Exceptions::special_exception(Thread* thread, const char* file, int line, symbolHandle h_name, const char* message) {
+ // bootstrapping check
+ if (!Universe::is_fully_initialized()) {
+ if (h_name.is_null()) {
+ // atleast an informative message.
+ vm_exit_during_initialization("Exception", message);
+ } else {
+ vm_exit_during_initialization(h_name, message);
+ }
+ ShouldNotReachHere();
+ }
+
+ if (thread->is_VM_thread()
+ || thread->is_Compiler_thread() ) {
+ // We do not care what kind of exception we get for the vm-thread or a thread which
+ // is compiling. We just install a dummy exception object
+ thread->set_pending_exception(Universe::vm_exception(), file, line);
+ return true;
+ }
+
+ return false;
+}
+
+// This method should only be called from generated code,
+// therefore the exception oop should be in the oopmap.
+void Exceptions::_throw_oop(Thread* thread, const char* file, int line, oop exception) {
+ assert(exception != NULL, "exception should not be NULL");
+ Handle h_exception = Handle(thread, exception);
+ _throw(thread, file, line, h_exception);
+}
+
+void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exception) {
+ assert(h_exception() != NULL, "exception should not be NULL");
+
+ // tracing (do this up front - so it works during boot strapping)
+ if (TraceExceptions) {
+ ttyLocker ttyl;
+ ResourceMark rm;
+ tty->print_cr("Exception <%s> (" INTPTR_FORMAT " ) \nthrown [%s, line %d]\nfor thread " INTPTR_FORMAT,
+ h_exception->print_value_string(), (address)h_exception(), file, line, thread);
+ }
+ // for AbortVMOnException flag
+ NOT_PRODUCT(Exceptions::debug_check_abort(h_exception));
+
+ // Check for special boot-strapping/vm-thread handling
+ if (special_exception(thread, file, line, h_exception)) return;
+
+ assert(h_exception->is_a(SystemDictionary::throwable_klass()), "exception is not a subclass of java/lang/Throwable");
+
+ // set the pending exception
+ thread->set_pending_exception(h_exception(), file, line);
+
+ // vm log
+ Events::log("throw_exception " INTPTR_FORMAT, (address)h_exception());
+}
+
+
+void Exceptions::_throw_msg(Thread* thread, const char* file, int line, symbolHandle h_name, const char* message, Handle h_loader, Handle h_protection_domain) {
+ // Check for special boot-strapping/vm-thread handling
+ if (special_exception(thread, file, line, h_name, message)) return;
+ // Create and throw exception
+ Handle h_cause(thread, NULL);
+ Handle h_exception = new_exception(thread, h_name, message, h_cause, h_loader, h_protection_domain);
+ _throw(thread, file, line, h_exception);
+}
+
+// Throw an exception with a message and a cause
+void Exceptions::_throw_msg_cause(Thread* thread, const char* file, int line, symbolHandle h_name, const char* message, Handle h_cause, Handle h_loader, Handle h_protection_domain) {
+ // Check for special boot-strapping/vm-thread handling
+ if (special_exception(thread, file, line, h_name, message)) return;
+ // Create and throw exception and init cause
+ Handle h_exception = new_exception(thread, h_name, message, h_cause, h_loader, h_protection_domain);
+ _throw(thread, file, line, h_exception);
+}
+
+// This version creates handles and calls the other version
+void Exceptions::_throw_msg(Thread* thread, const char* file, int line,
+ symbolOop name, const char* message) {
+ symbolHandle h_name(thread, name);
+ Handle h_loader(thread, NULL);
+ Handle h_protection_domain(thread, NULL);
+ Exceptions::_throw_msg(thread, file, line, h_name, message, h_loader, h_protection_domain);
+}
+
+// This version already has a handle for name
+void Exceptions::_throw_msg(Thread* thread, const char* file, int line,
+ symbolHandle name, const char* message) {
+ Handle h_loader(thread, NULL);
+ Handle h_protection_domain(thread, NULL);
+ Exceptions::_throw_msg(thread, file, line, name, message, h_loader, h_protection_domain);
+}
+
+// This version already has a handle for name
+void Exceptions::_throw_msg_cause(Thread* thread, const char* file, int line,
+ symbolHandle name, const char* message, Handle cause) {
+ Handle h_loader(thread, NULL);
+ Handle h_protection_domain(thread, NULL);
+ Exceptions::_throw_msg_cause(thread, file, line, name, message, cause, h_loader, h_protection_domain);
+}
+
+void Exceptions::_throw_args(Thread* thread, const char* file, int line, symbolHandle h_name, symbolHandle h_signature, JavaCallArguments *args) {
+ // Check for special boot-strapping/vm-thread handling
+ if (special_exception(thread, file, line, h_name, NULL)) return;
+ // Create and throw exception
+ Handle h_loader(thread, NULL);
+ Handle h_prot(thread, NULL);
+ Handle h_cause(thread, NULL);
+ Handle exception = new_exception(thread, h_name, h_signature, args, h_cause, h_loader, h_prot);
+ _throw(thread, file, line, exception);
+}
+
+
+void Exceptions::throw_stack_overflow_exception(Thread* THREAD, const char* file, int line) {
+ Handle exception;
+ if (!THREAD->has_pending_exception()) {
+ klassOop k = SystemDictionary::StackOverflowError_klass();
+ oop e = instanceKlass::cast(k)->allocate_instance(CHECK);
+ exception = Handle(THREAD, e); // fill_in_stack trace does gc
+ if (StackTraceInThrowable) {
+ java_lang_Throwable::fill_in_stack_trace(exception);
+ }
+ } else {
+ // if prior exception, throw that one instead
+ exception = Handle(THREAD, THREAD->pending_exception());
+ }
+ _throw_oop(THREAD, file, line, exception());
+}
+
+void Exceptions::fthrow(Thread* thread, const char* file, int line, symbolHandle h_name, const char* format, ...) {
+ const int max_msg_size = 1024;
+ va_list ap;
+ va_start(ap, format);
+ char msg[max_msg_size];
+ vsnprintf(msg, max_msg_size, format, ap);
+ msg[max_msg_size-1] = '\0';
+ va_end(ap);
+ _throw_msg(thread, file, line, h_name, msg);
+}
+
+// Creates an exception oop, calls the <init> method with the given signature.
+// and returns a Handle
+// Initializes the cause if cause non-null
+Handle Exceptions::new_exception(Thread *thread, symbolHandle h_name,
+ symbolHandle signature,
+ JavaCallArguments *args,
+ Handle h_cause, Handle h_loader,
+ Handle h_protection_domain) {
+ assert(Universe::is_fully_initialized(),
+ "cannot be called during initialization");
+ assert(thread->is_Java_thread(), "can only be called by a Java thread");
+ assert(!thread->has_pending_exception(), "already has exception");
+
+ Handle h_exception;
+
+ // Resolve exception klass
+ klassOop ik = SystemDictionary::resolve_or_fail(h_name, h_loader, h_protection_domain, true, thread);
+ instanceKlassHandle klass (thread, ik);
+
+ if (!thread->has_pending_exception()) {
+ assert(klass.not_null(), "klass must exist");
+ // We are about to create an instance - so make sure that klass is initialized
+ klass->initialize(thread);
+ if (!thread->has_pending_exception()) {
+ // Allocate new exception
+ h_exception = klass->allocate_instance_handle(thread);
+ if (!thread->has_pending_exception()) {
+ JavaValue result(T_VOID);
+ args->set_receiver(h_exception);
+ // Call constructor
+ JavaCalls::call_special(&result, klass,
+ vmSymbolHandles::object_initializer_name(),
+ signature,
+ args,
+ thread);
+
+ }
+ }
+
+ // Future: object initializer should take a cause argument
+ if (h_cause() != NULL) {
+ assert(h_cause->is_a(SystemDictionary::throwable_klass()),
+ "exception cause is not a subclass of java/lang/Throwable");
+ JavaValue result1(T_OBJECT);
+ JavaCallArguments args1;
+ args1.set_receiver(h_exception);
+ args1.push_oop(h_cause);
+ JavaCalls::call_virtual(&result1, klass,
+ vmSymbolHandles::initCause_name(),
+ vmSymbolHandles::throwable_throwable_signature(),
+ &args1,
+ thread);
+ }
+ }
+
+ // Check if another exception was thrown in the process, if so rethrow that one
+ if (thread->has_pending_exception()) {
+ h_exception = Handle(thread, thread->pending_exception());
+ thread->clear_pending_exception();
+ }
+ return h_exception;
+}
+
+// Convenience method. Calls either the <init>() or <init>(String) method when
+// creating a new exception
+Handle Exceptions::new_exception(Thread* thread, symbolHandle h_name,
+ const char* message, Handle h_cause,
+ Handle h_loader,
+ Handle h_protection_domain,
+ ExceptionMsgToUtf8Mode to_utf8_safe) {
+ JavaCallArguments args;
+ symbolHandle signature;
+ if (message == NULL) {
+ signature = vmSymbolHandles::void_method_signature();
+ } else {
+ // We want to allocate storage, but we can't do that if there's
+ // a pending exception, so we preserve any pending exception
+ // around the allocation.
+ // If we get an exception from the allocation, prefer that to
+ // the exception we are trying to build, or the pending exception.
+ // This is sort of like what PRESERVE_EXCEPTION_MARK does, except
+ // for the preferencing and the early returns.
+ Handle incoming_exception (thread, NULL);
+ if (thread->has_pending_exception()) {
+ incoming_exception = Handle(thread, thread->pending_exception());
+ thread->clear_pending_exception();
+ }
+ Handle msg;
+ if (to_utf8_safe == safe_to_utf8) {
+ // Make a java UTF8 string.
+ msg = java_lang_String::create_from_str(message, thread);
+ } else {
+ // Make a java string keeping the encoding scheme of the original string.
+ msg = java_lang_String::create_from_platform_dependent_str(message, thread);
+ }
+ if (thread->has_pending_exception()) {
+ Handle exception(thread, thread->pending_exception());
+ thread->clear_pending_exception();
+ return exception;
+ }
+ if (incoming_exception.not_null()) {
+ return incoming_exception;
+ }
+ args.push_oop(msg);
+ signature = vmSymbolHandles::string_void_signature();
+ }
+ return new_exception(thread, h_name, signature, &args, h_cause, h_loader, h_protection_domain);
+}
+
+// Another convenience method that creates handles for null class loaders and
+// protection domains and null causes.
+// If the last parameter 'to_utf8_mode' is safe_to_utf8,
+// it means we can safely ignore the encoding scheme of the message string and
+// convert it directly to a java UTF8 string. Otherwise, we need to take the
+// encoding scheme of the string into account. One thing we should do at some
+// point is to push this flag down to class java_lang_String since other
+// classes may need similar functionalities.
+Handle Exceptions::new_exception(Thread* thread,
+ symbolOop name,
+ const char* message,
+ ExceptionMsgToUtf8Mode to_utf8_safe) {
+
+ symbolHandle h_name(thread, name);
+ Handle h_loader(thread, NULL);
+ Handle h_prot(thread, NULL);
+ Handle h_cause(thread, NULL);
+ return Exceptions::new_exception(thread, h_name, message, h_cause, h_loader,
+ h_prot, to_utf8_safe);
+}
+
+// Implementation of ExceptionMark
+
+ExceptionMark::ExceptionMark(Thread*& thread) {
+ thread = Thread::current();
+ _thread = thread;
+ if (_thread->has_pending_exception()) {
+ oop exception = _thread->pending_exception();
+ _thread->clear_pending_exception(); // Needed to avoid infinite recursion
+ exception->print();
+ fatal("ExceptionMark constructor expects no pending exceptions");
+ }
+}
+
+
+ExceptionMark::~ExceptionMark() {
+ if (_thread->has_pending_exception()) {
+ Handle exception(_thread, _thread->pending_exception());
+ _thread->clear_pending_exception(); // Needed to avoid infinite recursion
+ if (is_init_completed()) {
+ exception->print();
+ fatal("ExceptionMark destructor expects no pending exceptions");
+ } else {
+ vm_exit_during_initialization(exception);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+
+#ifndef PRODUCT
+// caller frees value_string if necessary
+void Exceptions::debug_check_abort(const char *value_string) {
+ if (AbortVMOnException != NULL && value_string != NULL &&
+ strstr(value_string, AbortVMOnException)) {
+ fatal1("Saw %s, aborting", value_string);
+ }
+}
+
+void Exceptions::debug_check_abort(Handle exception) {
+ if (AbortVMOnException != NULL) {
+ ResourceMark rm;
+ debug_check_abort(instanceKlass::cast(exception()->klass())->external_name());
+ }
+}
+#endif
diff --git a/src/share/vm/utilities/exceptions.hpp b/src/share/vm/utilities/exceptions.hpp
new file mode 100644
index 000000000..e8388ad4a
--- /dev/null
+++ b/src/share/vm/utilities/exceptions.hpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright 1998-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// This file provides the basic support for exception handling in the VM.
+// Note: We do not use C++ exceptions to avoid compiler dependencies and
+// unpredictable performance.
+//
+// Scheme: Exceptions are stored with the thread. There is never more
+// than one pending exception per thread. All functions that can throw
+// an exception carry a THREAD argument (usually the last argument and
+// declared with the TRAPS macro). Throwing an exception means setting
+// a pending exception in the thread. Upon return from a function that
+// can throw an exception, we must check if an exception is pending.
+// The CHECK macros do this in a convenient way. Carrying around the
+// thread provides also convenient access to it (e.g. for Handle
+// creation, w/o the need for recomputation).
+
+
+
+// Forward declarations to be independent of the include structure.
+// This allows us to have exceptions.hpp included in top.hpp.
+
+class Thread;
+class Handle;
+class symbolHandle;
+class symbolOopDesc;
+class JavaCallArguments;
+
+// The ThreadShadow class is a helper class to access the _pending_exception
+// field of the Thread class w/o having access to the Thread's interface (for
+// include hierachy reasons).
+
+class ThreadShadow: public CHeapObj {
+ protected:
+ oop _pending_exception; // Thread has gc actions.
+ const char* _exception_file; // file information for exception (debugging only)
+ int _exception_line; // line information for exception (debugging only)
+ friend void check_ThreadShadow(); // checks _pending_exception offset
+
+ // The following virtual exists only to force creation of a vtable.
+ // We need ThreadShadow to have a vtable, even in product builds,
+ // so that its layout will start at an offset of zero relative to Thread.
+ // Some C++ compilers are so "clever" that they put the ThreadShadow
+ // base class at offset 4 in Thread (after Thread's vtable), if they
+ // notice that Thread has a vtable but ThreadShadow does not.
+ virtual void unused_initial_virtual() { }
+
+ public:
+ oop pending_exception() const { return _pending_exception; }
+ bool has_pending_exception() const { return _pending_exception != NULL; }
+ const char* exception_file() const { return _exception_file; }
+ int exception_line() const { return _exception_line; }
+
+ // Code generation support
+ static ByteSize pending_exception_offset() { return byte_offset_of(ThreadShadow, _pending_exception); }
+
+ // use THROW whenever possible!
+ void set_pending_exception(oop exception, const char* file, int line);
+
+ // use CLEAR_PENDING_EXCEPTION whenever possible!
+ void clear_pending_exception();
+
+ ThreadShadow() : _pending_exception(NULL),
+ _exception_file(NULL), _exception_line(0) {}
+};
+
+
+// Exceptions is a helper class that encapsulates all operations
+// that require access to the thread interface and which are
+// relatively rare. The Exceptions operations should only be
+// used directly if the macros below are insufficient.
+
+class Exceptions {
+ static bool special_exception(Thread *thread, const char* file, int line, Handle exception);
+ static bool special_exception(Thread* thread, const char* file, int line, symbolHandle name, const char* message);
+ public:
+ // this enum is defined to indicate whether it is safe to
+ // ignore the encoding scheme of the original message string.
+ typedef enum {
+ safe_to_utf8 = 0,
+ unsafe_to_utf8 = 1
+ } ExceptionMsgToUtf8Mode;
+ // Throw exceptions: w/o message, w/ message & with formatted message.
+ static void _throw_oop(Thread* thread, const char* file, int line, oop exception);
+ static void _throw(Thread* thread, const char* file, int line, Handle exception);
+ static void _throw_msg(Thread* thread, const char* file, int line,
+ symbolHandle name, const char* message, Handle loader,
+ Handle protection_domain);
+ static void _throw_msg(Thread* thread, const char* file, int line,
+ symbolOop name, const char* message);
+ static void _throw_msg(Thread* thread, const char* file, int line,
+ symbolHandle name, const char* message);
+ static void _throw_args(Thread* thread, const char* file, int line,
+ symbolHandle name, symbolHandle signature,
+ JavaCallArguments* args);
+ static void _throw_msg_cause(Thread* thread, const char* file,
+ int line, symbolHandle h_name, const char* message,
+ Handle h_cause, Handle h_loader, Handle h_protection_domain);
+ static void _throw_msg_cause(Thread* thread, const char* file, int line,
+ symbolHandle name, const char* message, Handle cause);
+
+ // There is no THROW... macro for this method. Caller should remember
+ // to do a return after calling it.
+ static void fthrow(Thread* thread, const char* file, int line, symbolHandle name,
+ const char* format, ...);
+
+ // Create and initialize a new exception
+ static Handle new_exception(Thread* thread, symbolHandle name,
+ symbolHandle signature, JavaCallArguments* args,
+ Handle cause, Handle loader,
+ Handle protection_domain);
+
+ static Handle new_exception(Thread* thread, symbolHandle name,
+ const char* message, Handle cause, Handle loader,
+ Handle protection_domain,
+ ExceptionMsgToUtf8Mode to_utf8_safe = safe_to_utf8);
+
+ static Handle new_exception(Thread* thread, symbolOop name,
+ const char* message,
+ ExceptionMsgToUtf8Mode to_utf8_safe = safe_to_utf8);
+
+ static void throw_stack_overflow_exception(Thread* thread, const char* file, int line);
+
+ // for AbortVMOnException flag
+ NOT_PRODUCT(static void debug_check_abort(Handle exception);)
+ NOT_PRODUCT(static void debug_check_abort(const char *value_string);)
+};
+
+
+// The THREAD & TRAPS macros facilitate the declaration of functions that throw exceptions.
+// Convention: Use the TRAPS macro as the last argument of such a function; e.g.:
+//
+// int this_function_may_trap(int x, float y, TRAPS)
+
+#define THREAD __the_thread__
+#define TRAPS Thread* THREAD
+
+
+// The CHECK... macros should be used to pass along a THREAD reference and to check for pending
+// exceptions. In special situations it is necessary to handle pending exceptions explicitly,
+// in these cases the PENDING_EXCEPTION helper macros should be used.
+//
+// Macro naming conventions: Macros that end with _ require a result value to be returned. They
+// are for functions with non-void result type. The result value is usually ignored because of
+// the exception and is only needed for syntactic correctness. The _0 ending is a shortcut for
+// _(0) since this is a frequent case. Example:
+//
+// int result = this_function_may_trap(x_arg, y_arg, CHECK_0);
+//
+// CAUTION: make sure that the function call using a CHECK macro is not the only statement of a
+// conditional branch w/o enclosing {} braces, since the CHECK macros expand into several state-
+// ments!
+
+#define PENDING_EXCEPTION (((ThreadShadow*)THREAD)->pending_exception())
+#define HAS_PENDING_EXCEPTION (((ThreadShadow*)THREAD)->has_pending_exception())
+#define CLEAR_PENDING_EXCEPTION (((ThreadShadow*)THREAD)->clear_pending_exception())
+
+#define CHECK THREAD); if (HAS_PENDING_EXCEPTION) return ; (0
+#define CHECK_(result) THREAD); if (HAS_PENDING_EXCEPTION) return result; (0
+#define CHECK_0 CHECK_(0)
+#define CHECK_NH CHECK_(Handle())
+#define CHECK_NULL CHECK_(NULL)
+#define CHECK_false CHECK_(false)
+
+// The THROW... macros should be used to throw an exception. They require a THREAD variable to be
+// visible within the scope containing the THROW. Usually this is achieved by declaring the function
+// with a TRAPS argument.
+
+#define THREAD_AND_LOCATION THREAD, __FILE__, __LINE__
+
+#define THROW_OOP(e) \
+ { Exceptions::_throw_oop(THREAD_AND_LOCATION, e); return; }
+
+#define THROW_HANDLE(e) \
+ { Exceptions::_throw(THREAD_AND_LOCATION, e); return; }
+
+#define THROW(name) \
+ { Exceptions::_throw_msg(THREAD_AND_LOCATION, name, NULL); return; }
+
+#define THROW_MSG(name, message) \
+ { Exceptions::_throw_msg(THREAD_AND_LOCATION, name, message); return; }
+
+#define THROW_MSG_LOADER(name, message, loader, protection_domain) \
+ { Exceptions::_throw_msg(THREAD_AND_LOCATION, name, message, loader, protection_domain); return; }
+
+#define THROW_ARG(name, signature, args) \
+ { Exceptions::_throw_args(THREAD_AND_LOCATION, name, signature, args); return; }
+
+#define THROW_OOP_(e, result) \
+ { Exceptions::_throw_oop(THREAD_AND_LOCATION, e); return result; }
+
+#define THROW_HANDLE_(e, result) \
+ { Exceptions::_throw(THREAD_AND_LOCATION, e); return result; }
+
+#define THROW_(name, result) \
+ { Exceptions::_throw_msg(THREAD_AND_LOCATION, name, NULL); return result; }
+
+#define THROW_MSG_(name, message, result) \
+ { Exceptions::_throw_msg(THREAD_AND_LOCATION, name, message); return result; }
+
+#define THROW_MSG_LOADER_(name, message, loader, protection_domain, result) \
+ { Exceptions::_throw_msg(THREAD_AND_LOCATION, name, message, loader, protection_domain); return result; }
+
+#define THROW_ARG_(name, signature, args, result) \
+ { Exceptions::_throw_args(THREAD_AND_LOCATION, name, signature, args); return result; }
+
+#define THROW_MSG_CAUSE_(name, message, cause, result) \
+ { Exceptions::_throw_msg_cause(THREAD_AND_LOCATION, name, message, cause); return result; }
+
+
+#define THROW_OOP_0(e) THROW_OOP_(e, 0)
+#define THROW_HANDLE_0(e) THROW_HANDLE_(e, 0)
+#define THROW_0(name) THROW_(name, 0)
+#define THROW_MSG_0(name, message) THROW_MSG_(name, message, 0)
+#define THROW_WRAPPED_0(name, oop_to_wrap) THROW_WRAPPED_(name, oop_to_wrap, 0)
+#define THROW_ARG_0(name, signature, arg) THROW_ARG_(name, signature, arg, 0)
+#define THROW_MSG_CAUSE_0(name, message, cause) THROW_MSG_CAUSE_(name, message, cause, 0)
+
+// The CATCH macro checks that no exception has been thrown by a function; it is used at
+// call sites about which is statically known that the callee cannot throw an exception
+// even though it is declared with TRAPS.
+
+#define CATCH \
+ THREAD); if (HAS_PENDING_EXCEPTION) { \
+ oop ex = PENDING_EXCEPTION; \
+ CLEAR_PENDING_EXCEPTION; \
+ ex->print(); \
+ ShouldNotReachHere(); \
+ } (0
+
+
+// ExceptionMark is a stack-allocated helper class for local exception handling.
+// It is used with the EXCEPTION_MARK macro.
+
+class ExceptionMark {
+ private:
+ Thread* _thread;
+
+ public:
+ ExceptionMark(Thread*& thread);
+ ~ExceptionMark();
+};
+
+
+
+// Use an EXCEPTION_MARK for 'local' exceptions. EXCEPTION_MARK makes sure that no
+// pending exception exists upon entering its scope and tests that no pending exception
+// exists when leaving the scope.
+
+// See also preserveException.hpp for PRESERVE_EXCEPTION_MARK macro,
+// which preserves pre-existing exceptions and does not allow new
+// exceptions.
+
+#define EXCEPTION_MARK Thread* THREAD; ExceptionMark __em(THREAD);
diff --git a/src/share/vm/utilities/globalDefinitions.cpp b/src/share/vm/utilities/globalDefinitions.cpp
new file mode 100644
index 000000000..12edbeff7
--- /dev/null
+++ b/src/share/vm/utilities/globalDefinitions.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright 1997-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_globalDefinitions.cpp.incl"
+
+
+// Basic error support
+
+void basic_fatal(const char* msg) {
+ fatal(msg);
+}
+
+
+// Something to help porters sleep at night
+
+void check_basic_types() {
+#ifdef ASSERT
+#ifdef _LP64
+ assert(min_intx == (intx)CONST64(0x8000000000000000), "correct constant");
+ assert(max_intx == CONST64(0x7FFFFFFFFFFFFFFF), "correct constant");
+ assert(max_uintx == CONST64(0xFFFFFFFFFFFFFFFF), "correct constant");
+ assert( 8 == sizeof( intx), "wrong size for basic type");
+ assert( 8 == sizeof( jobject), "wrong size for basic type");
+#else
+ assert(min_intx == (intx)0x80000000, "correct constant");
+ assert(max_intx == 0x7FFFFFFF, "correct constant");
+ assert(max_uintx == 0xFFFFFFFF, "correct constant");
+ assert( 4 == sizeof( intx), "wrong size for basic type");
+ assert( 4 == sizeof( jobject), "wrong size for basic type");
+#endif
+ assert( (~max_juint) == 0, "max_juint has all its bits");
+ assert( (~max_uintx) == 0, "max_uintx has all its bits");
+ assert( (~max_julong) == 0, "max_julong has all its bits");
+ assert( 1 == sizeof( jbyte), "wrong size for basic type");
+ assert( 2 == sizeof( jchar), "wrong size for basic type");
+ assert( 2 == sizeof( jshort), "wrong size for basic type");
+ assert( 4 == sizeof( juint), "wrong size for basic type");
+ assert( 4 == sizeof( jint), "wrong size for basic type");
+ assert( 1 == sizeof( jboolean), "wrong size for basic type");
+ assert( 8 == sizeof( jlong), "wrong size for basic type");
+ assert( 4 == sizeof( jfloat), "wrong size for basic type");
+ assert( 8 == sizeof( jdouble), "wrong size for basic type");
+ assert( 1 == sizeof( u1), "wrong size for basic type");
+ assert( 2 == sizeof( u2), "wrong size for basic type");
+ assert( 4 == sizeof( u4), "wrong size for basic type");
+
+ int num_type_chars = 0;
+ for (int i = 0; i < 99; i++) {
+ if (type2char((BasicType)i) != 0) {
+ assert(char2type(type2char((BasicType)i)) == i, "proper inverses");
+ num_type_chars++;
+ }
+ }
+ assert(num_type_chars == 11, "must have tested the right number of mappings");
+ assert(char2type(0) == T_ILLEGAL, "correct illegality");
+
+ {
+ for (int i = T_BOOLEAN; i <= T_CONFLICT; i++) {
+ BasicType vt = (BasicType)i;
+ BasicType ft = type2field[vt];
+ switch (vt) {
+ // the following types might plausibly show up in memory layouts:
+ case T_BOOLEAN:
+ case T_BYTE:
+ case T_CHAR:
+ case T_SHORT:
+ case T_INT:
+ case T_FLOAT:
+ case T_DOUBLE:
+ case T_LONG:
+ case T_OBJECT:
+ case T_ADDRESS: // random raw pointer
+ case T_CONFLICT: // might as well support a bottom type
+ case T_VOID: // padding or other unaddressed word
+ // layout type must map to itself
+ assert(vt == ft, "");
+ break;
+ default:
+ // non-layout type must map to a (different) layout type
+ assert(vt != ft, "");
+ assert(ft == type2field[ft], "");
+ }
+ // every type must map to same-sized layout type:
+ assert(type2size[vt] == type2size[ft], "");
+ }
+ }
+ // These are assumed, e.g., when filling HeapWords with juints.
+ assert(is_power_of_2(sizeof(juint)), "juint must be power of 2");
+ assert(is_power_of_2(HeapWordSize), "HeapWordSize must be power of 2");
+ assert((size_t)HeapWordSize >= sizeof(juint),
+ "HeapWord should be at least as large as juint");
+ assert(sizeof(NULL) == sizeof(char*), "NULL must be same size as pointer");
+#endif
+
+ if( JavaPriority1_To_OSPriority != -1 )
+ os::java_to_os_priority[1] = JavaPriority1_To_OSPriority;
+ if( JavaPriority2_To_OSPriority != -1 )
+ os::java_to_os_priority[2] = JavaPriority2_To_OSPriority;
+ if( JavaPriority3_To_OSPriority != -1 )
+ os::java_to_os_priority[3] = JavaPriority3_To_OSPriority;
+ if( JavaPriority4_To_OSPriority != -1 )
+ os::java_to_os_priority[4] = JavaPriority4_To_OSPriority;
+ if( JavaPriority5_To_OSPriority != -1 )
+ os::java_to_os_priority[5] = JavaPriority5_To_OSPriority;
+ if( JavaPriority6_To_OSPriority != -1 )
+ os::java_to_os_priority[6] = JavaPriority6_To_OSPriority;
+ if( JavaPriority7_To_OSPriority != -1 )
+ os::java_to_os_priority[7] = JavaPriority7_To_OSPriority;
+ if( JavaPriority8_To_OSPriority != -1 )
+ os::java_to_os_priority[8] = JavaPriority8_To_OSPriority;
+ if( JavaPriority9_To_OSPriority != -1 )
+ os::java_to_os_priority[9] = JavaPriority9_To_OSPriority;
+ if(JavaPriority10_To_OSPriority != -1 )
+ os::java_to_os_priority[10] = JavaPriority10_To_OSPriority;
+}
+
+
+// Map BasicType to signature character
+char type2char_tab[T_CONFLICT+1]={ 0, 0, 0, 0, 'Z', 'C', 'F', 'D', 'B', 'S', 'I', 'J', 'L', '[', 'V', 0, 0};
+
+// Map BasicType to Java type name
+const char* type2name_tab[T_CONFLICT+1] = {
+ NULL, NULL, NULL, NULL,
+ "boolean",
+ "char",
+ "float",
+ "double",
+ "byte",
+ "short",
+ "int",
+ "long",
+ "object",
+ "array",
+ "void",
+ "*address*",
+ "*conflict*"
+};
+
+
+BasicType name2type(const char* name) {
+ for (int i = T_BOOLEAN; i <= T_VOID; i++) {
+ BasicType t = (BasicType)i;
+ if (type2name_tab[t] != NULL && 0 == strcmp(type2name_tab[t], name))
+ return t;
+ }
+ return T_ILLEGAL;
+}
+
+
+// Map BasicType to size in words
+int type2size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, -1};
+
+BasicType type2field[T_CONFLICT+1] = {
+ (BasicType)0, // 0,
+ (BasicType)0, // 1,
+ (BasicType)0, // 2,
+ (BasicType)0, // 3,
+ T_BOOLEAN, // T_BOOLEAN = 4,
+ T_CHAR, // T_CHAR = 5,
+ T_FLOAT, // T_FLOAT = 6,
+ T_DOUBLE, // T_DOUBLE = 7,
+ T_BYTE, // T_BYTE = 8,
+ T_SHORT, // T_SHORT = 9,
+ T_INT, // T_INT = 10,
+ T_LONG, // T_LONG = 11,
+ T_OBJECT, // T_OBJECT = 12,
+ T_OBJECT, // T_ARRAY = 13,
+ T_VOID, // T_VOID = 14,
+ T_ADDRESS, // T_ADDRESS = 15,
+ T_CONFLICT // T_CONFLICT = 16,
+};
+
+
+BasicType type2wfield[T_CONFLICT+1] = {
+ (BasicType)0, // 0,
+ (BasicType)0, // 1,
+ (BasicType)0, // 2,
+ (BasicType)0, // 3,
+ T_INT, // T_BOOLEAN = 4,
+ T_INT, // T_CHAR = 5,
+ T_FLOAT, // T_FLOAT = 6,
+ T_DOUBLE, // T_DOUBLE = 7,
+ T_INT, // T_BYTE = 8,
+ T_INT, // T_SHORT = 9,
+ T_INT, // T_INT = 10,
+ T_LONG, // T_LONG = 11,
+ T_OBJECT, // T_OBJECT = 12,
+ T_OBJECT, // T_ARRAY = 13,
+ T_VOID, // T_VOID = 14,
+ T_ADDRESS, // T_ADDRESS = 15,
+ T_CONFLICT // T_CONFLICT = 16,
+};
+
+
+int type2aelembytes[T_CONFLICT+1] = {
+ 0, // 0
+ 0, // 1
+ 0, // 2
+ 0, // 3
+ T_BOOLEAN_aelem_bytes, // T_BOOLEAN = 4,
+ T_CHAR_aelem_bytes, // T_CHAR = 5,
+ T_FLOAT_aelem_bytes, // T_FLOAT = 6,
+ T_DOUBLE_aelem_bytes, // T_DOUBLE = 7,
+ T_BYTE_aelem_bytes, // T_BYTE = 8,
+ T_SHORT_aelem_bytes, // T_SHORT = 9,
+ T_INT_aelem_bytes, // T_INT = 10,
+ T_LONG_aelem_bytes, // T_LONG = 11,
+ T_OBJECT_aelem_bytes, // T_OBJECT = 12,
+ T_ARRAY_aelem_bytes, // T_ARRAY = 13,
+ 0, // T_VOID = 14,
+ T_INT_aelem_bytes, // T_ADDRESS = 15,
+ 0 // T_CONFLICT = 16,
+};
+
+
+// Support for 64-bit integer arithmetic
+
+// The following code is mostly taken from JVM typedefs_md.h and system_md.c
+
+static const jlong high_bit = (jlong)1 << (jlong)63;
+static const jlong other_bits = ~high_bit;
+
+jlong float2long(jfloat f) {
+ jlong tmp = (jlong) f;
+ if (tmp != high_bit) {
+ return tmp;
+ } else {
+ if (g_isnan((jdouble)f)) {
+ return 0;
+ }
+ if (f < 0) {
+ return high_bit;
+ } else {
+ return other_bits;
+ }
+ }
+}
+
+
+jlong double2long(jdouble f) {
+ jlong tmp = (jlong) f;
+ if (tmp != high_bit) {
+ return tmp;
+ } else {
+ if (g_isnan(f)) {
+ return 0;
+ }
+ if (f < 0) {
+ return high_bit;
+ } else {
+ return other_bits;
+ }
+ }
+}
+
+// least common multiple
+size_t lcm(size_t a, size_t b) {
+ size_t cur, div, next;
+
+ cur = MAX2(a, b);
+ div = MIN2(a, b);
+
+ assert(div != 0, "lcm requires positive arguments");
+
+
+ while ((next = cur % div) != 0) {
+ cur = div; div = next;
+ }
+
+
+ julong result = julong(a) * b / div;
+ assert(result <= (size_t)max_uintx, "Integer overflow in lcm");
+
+ return size_t(result);
+}
diff --git a/src/share/vm/utilities/globalDefinitions.hpp b/src/share/vm/utilities/globalDefinitions.hpp
new file mode 100644
index 000000000..460cd1f34
--- /dev/null
+++ b/src/share/vm/utilities/globalDefinitions.hpp
@@ -0,0 +1,1101 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// This file holds all globally used constants & types, class (forward)
+// declarations and a few frequently used utility functions.
+
+//----------------------------------------------------------------------------------------------------
+// Constants
+
+const int LogBytesPerShort = 1;
+const int LogBytesPerInt = 2;
+#ifdef _LP64
+const int LogBytesPerWord = 3;
+#else
+const int LogBytesPerWord = 2;
+#endif
+const int LogBytesPerLong = 3;
+
+const int BytesPerShort = 1 << LogBytesPerShort;
+const int BytesPerInt = 1 << LogBytesPerInt;
+const int BytesPerWord = 1 << LogBytesPerWord;
+const int BytesPerLong = 1 << LogBytesPerLong;
+
+const int LogBitsPerByte = 3;
+const int LogBitsPerShort = LogBitsPerByte + LogBytesPerShort;
+const int LogBitsPerInt = LogBitsPerByte + LogBytesPerInt;
+const int LogBitsPerWord = LogBitsPerByte + LogBytesPerWord;
+const int LogBitsPerLong = LogBitsPerByte + LogBytesPerLong;
+
+const int BitsPerByte = 1 << LogBitsPerByte;
+const int BitsPerShort = 1 << LogBitsPerShort;
+const int BitsPerInt = 1 << LogBitsPerInt;
+const int BitsPerWord = 1 << LogBitsPerWord;
+const int BitsPerLong = 1 << LogBitsPerLong;
+
+const int WordAlignmentMask = (1 << LogBytesPerWord) - 1;
+const int LongAlignmentMask = (1 << LogBytesPerLong) - 1;
+
+const int WordsPerLong = 2; // Number of stack entries for longs
+
+const int oopSize = sizeof(char*);
+const int wordSize = sizeof(char*);
+const int longSize = sizeof(jlong);
+const int jintSize = sizeof(jint);
+const int size_tSize = sizeof(size_t);
+
+// Size of a char[] needed to represent a jint as a string in decimal.
+const int jintAsStringSize = 12;
+
+const int LogBytesPerOop = LogBytesPerWord;
+const int LogBitsPerOop = LogBitsPerWord;
+const int BytesPerOop = 1 << LogBytesPerOop;
+const int BitsPerOop = 1 << LogBitsPerOop;
+
+const int BitsPerJavaInteger = 32;
+const int BitsPerSize_t = size_tSize * BitsPerByte;
+
+// In fact this should be
+// log2_intptr(sizeof(class JavaThread)) - log2_intptr(64);
+// see os::set_memory_serialize_page()
+#ifdef _LP64
+const int SerializePageShiftCount = 4;
+#else
+const int SerializePageShiftCount = 3;
+#endif
+
+// An opaque struct of heap-word width, so that HeapWord* can be a generic
+// pointer into the heap. We require that object sizes be measured in
+// units of heap words, so that that
+// HeapWord* hw;
+// hw += oop(hw)->foo();
+// works, where foo is a method (like size or scavenge) that returns the
+// object size.
+class HeapWord {
+ friend class VMStructs;
+private:
+ char* i;
+};
+
+// HeapWordSize must be 2^LogHeapWordSize.
+const int HeapWordSize = sizeof(HeapWord);
+#ifdef _LP64
+const int LogHeapWordSize = 3;
+#else
+const int LogHeapWordSize = 2;
+#endif
+const int HeapWordsPerOop = oopSize / HeapWordSize;
+const int HeapWordsPerLong = BytesPerLong / HeapWordSize;
+
+// The larger HeapWordSize for 64bit requires larger heaps
+// for the same application running in 64bit. See bug 4967770.
+// The minimum alignment to a heap word size is done. Other
+// parts of the memory system may required additional alignment
+// and are responsible for those alignments.
+#ifdef _LP64
+#define ScaleForWordSize(x) align_size_down_((x) * 13 / 10, HeapWordSize)
+#else
+#define ScaleForWordSize(x) (x)
+#endif
+
+// The minimum number of native machine words necessary to contain "byte_size"
+// bytes.
+inline size_t heap_word_size(size_t byte_size) {
+ return (byte_size + (HeapWordSize-1)) >> LogHeapWordSize;
+}
+
+
+const size_t K = 1024;
+const size_t M = K*K;
+const size_t G = M*K;
+const size_t HWperKB = K / sizeof(HeapWord);
+
+const jint min_jint = (jint)1 << (sizeof(jint)*BitsPerByte-1); // 0x80000000 == smallest jint
+const jint max_jint = (juint)min_jint - 1; // 0x7FFFFFFF == largest jint
+
+// Constants for converting from a base unit to milli-base units. For
+// example from seconds to milliseconds and microseconds
+
+const int MILLIUNITS = 1000; // milli units per base unit
+const int MICROUNITS = 1000000; // micro units per base unit
+const int NANOUNITS = 1000000000; // nano units per base unit
+
+inline const char* proper_unit_for_byte_size(size_t s) {
+ if (s >= 10*M) {
+ return "M";
+ } else if (s >= 10*K) {
+ return "K";
+ } else {
+ return "B";
+ }
+}
+
+inline size_t byte_size_in_proper_unit(size_t s) {
+ if (s >= 10*M) {
+ return s/M;
+ } else if (s >= 10*K) {
+ return s/K;
+ } else {
+ return s;
+ }
+}
+
+
+//----------------------------------------------------------------------------------------------------
+// VM type definitions
+
+// intx and uintx are the 'extended' int and 'extended' unsigned int types;
+// they are 32bit wide on a 32-bit platform, and 64bit wide on a 64bit platform.
+
+typedef intptr_t intx;
+typedef uintptr_t uintx;
+
+const intx min_intx = (intx)1 << (sizeof(intx)*BitsPerByte-1);
+const intx max_intx = (uintx)min_intx - 1;
+const uintx max_uintx = (uintx)-1;
+
+// Table of values:
+// sizeof intx 4 8
+// min_intx 0x80000000 0x8000000000000000
+// max_intx 0x7FFFFFFF 0x7FFFFFFFFFFFFFFF
+// max_uintx 0xFFFFFFFF 0xFFFFFFFFFFFFFFFF
+
+typedef unsigned int uint; NEEDS_CLEANUP
+
+
+//----------------------------------------------------------------------------------------------------
+// Java type definitions
+
+// All kinds of 'plain' byte addresses
+typedef signed char s_char;
+typedef unsigned char u_char;
+typedef u_char* address;
+typedef uintptr_t address_word; // unsigned integer which will hold a pointer
+ // except for some implementations of a C++
+ // linkage pointer to function. Should never
+ // need one of those to be placed in this
+ // type anyway.
+
+// Utility functions to "portably" (?) bit twiddle pointers
+// Where portable means keep ANSI C++ compilers quiet
+
+inline address set_address_bits(address x, int m) { return address(intptr_t(x) | m); }
+inline address clear_address_bits(address x, int m) { return address(intptr_t(x) & ~m); }
+
+// Utility functions to "portably" make cast to/from function pointers.
+
+inline address_word mask_address_bits(address x, int m) { return address_word(x) & m; }
+inline address_word castable_address(address x) { return address_word(x) ; }
+inline address_word castable_address(void* x) { return address_word(x) ; }
+
+// Pointer subtraction.
+// The idea here is to avoid ptrdiff_t, which is signed and so doesn't have
+// the range we might need to find differences from one end of the heap
+// to the other.
+// A typical use might be:
+// if (pointer_delta(end(), top()) >= size) {
+// // enough room for an object of size
+// ...
+// and then additions like
+// ... top() + size ...
+// are safe because we know that top() is at least size below end().
+inline size_t pointer_delta(const void* left,
+ const void* right,
+ size_t element_size) {
+ return (((uintptr_t) left) - ((uintptr_t) right)) / element_size;
+}
+// A version specialized for HeapWord*'s.
+inline size_t pointer_delta(const HeapWord* left, const HeapWord* right) {
+ return pointer_delta(left, right, sizeof(HeapWord));
+}
+
+//
+// ANSI C++ does not allow casting from one pointer type to a function pointer
+// directly without at best a warning. This macro accomplishes it silently
+// In every case that is present at this point the value be cast is a pointer
+// to a C linkage function. In somecase the type used for the cast reflects
+// that linkage and a picky compiler would not complain. In other cases because
+// there is no convenient place to place a typedef with extern C linkage (i.e
+// a platform dependent header file) it doesn't. At this point no compiler seems
+// picky enough to catch these instances (which are few). It is possible that
+// using templates could fix these for all cases. This use of templates is likely
+// so far from the middle of the road that it is likely to be problematic in
+// many C++ compilers.
+//
+#define CAST_TO_FN_PTR(func_type, value) ((func_type)(castable_address(value)))
+#define CAST_FROM_FN_PTR(new_type, func_ptr) ((new_type)((address_word)(func_ptr)))
+
+// Unsigned byte types for os and stream.hpp
+
+// Unsigned one, two, four and eigth byte quantities used for describing
+// the .class file format. See JVM book chapter 4.
+
+typedef jubyte u1;
+typedef jushort u2;
+typedef juint u4;
+typedef julong u8;
+
+const jubyte max_jubyte = (jubyte)-1; // 0xFF largest jubyte
+const jushort max_jushort = (jushort)-1; // 0xFFFF largest jushort
+const juint max_juint = (juint)-1; // 0xFFFFFFFF largest juint
+const julong max_julong = (julong)-1; // 0xFF....FF largest julong
+
+//----------------------------------------------------------------------------------------------------
+// JVM spec restrictions
+
+const int max_method_code_size = 64*K - 1; // JVM spec, 2nd ed. section 4.8.1 (p.134)
+
+
+//----------------------------------------------------------------------------------------------------
+// HotSwap - for JVMTI aka Class File Replacement and PopFrame
+//
+// Determines whether on-the-fly class replacement and frame popping are enabled.
+
+#define HOTSWAP
+
+//----------------------------------------------------------------------------------------------------
+// Object alignment, in units of HeapWords.
+//
+// Minimum is max(BytesPerLong, BytesPerDouble, BytesPerOop) / HeapWordSize, so jlong, jdouble and
+// reference fields can be naturally aligned.
+
+const int MinObjAlignment = HeapWordsPerLong;
+const int MinObjAlignmentInBytes = MinObjAlignment * HeapWordSize;
+const int MinObjAlignmentInBytesMask = MinObjAlignmentInBytes - 1;
+
+// Machine dependent stuff
+
+#include "incls/_globalDefinitions_pd.hpp.incl"
+
+// The byte alignment to be used by Arena::Amalloc. See bugid 4169348.
+// Note: this value must be a power of 2
+
+#define ARENA_AMALLOC_ALIGNMENT (2*BytesPerWord)
+
+// Signed variants of alignment helpers. There are two versions of each, a macro
+// for use in places like enum definitions that require compile-time constant
+// expressions and a function for all other places so as to get type checking.
+
+#define align_size_up_(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1))
+
+inline intptr_t align_size_up(intptr_t size, intptr_t alignment) {
+ return align_size_up_(size, alignment);
+}
+
+#define align_size_down_(size, alignment) ((size) & ~((alignment) - 1))
+
+inline intptr_t align_size_down(intptr_t size, intptr_t alignment) {
+ return align_size_down_(size, alignment);
+}
+
+// Align objects by rounding up their size, in HeapWord units.
+
+#define align_object_size_(size) align_size_up_(size, MinObjAlignment)
+
+inline intptr_t align_object_size(intptr_t size) {
+ return align_size_up(size, MinObjAlignment);
+}
+
+// Pad out certain offsets to jlong alignment, in HeapWord units.
+
+#define align_object_offset_(offset) align_size_up_(offset, HeapWordsPerLong)
+
+inline intptr_t align_object_offset(intptr_t offset) {
+ return align_size_up(offset, HeapWordsPerLong);
+}
+
+inline bool is_object_aligned(intptr_t offset) {
+ return offset == align_object_offset(offset);
+}
+
+
+//----------------------------------------------------------------------------------------------------
+// Utility macros for compilers
+// used to silence compiler warnings
+
+#define Unused_Variable(var) var
+
+
+//----------------------------------------------------------------------------------------------------
+// Miscellaneous
+
+// 6302670 Eliminate Hotspot __fabsf dependency
+// All fabs() callers should call this function instead, which will implicitly
+// convert the operand to double, avoiding a dependency on __fabsf which
+// doesn't exist in early versions of Solaris 8.
+inline double fabsd(double value) {
+ return fabs(value);
+}
+
+inline jint low (jlong value) { return jint(value); }
+inline jint high(jlong value) { return jint(value >> 32); }
+
+// the fancy casts are a hopefully portable way
+// to do unsigned 32 to 64 bit type conversion
+inline void set_low (jlong* value, jint low ) { *value &= (jlong)0xffffffff << 32;
+ *value |= (jlong)(julong)(juint)low; }
+
+inline void set_high(jlong* value, jint high) { *value &= (jlong)(julong)(juint)0xffffffff;
+ *value |= (jlong)high << 32; }
+
+inline jlong jlong_from(jint h, jint l) {
+ jlong result = 0; // initialization to avoid warning
+ set_high(&result, h);
+ set_low(&result, l);
+ return result;
+}
+
+union jlong_accessor {
+ jint words[2];
+ jlong long_value;
+};
+
+void check_basic_types(); // cannot define here; uses assert
+
+
+// NOTE: replicated in SA in vm/agent/sun/jvm/hotspot/runtime/BasicType.java
+enum BasicType {
+ T_BOOLEAN = 4,
+ T_CHAR = 5,
+ T_FLOAT = 6,
+ T_DOUBLE = 7,
+ T_BYTE = 8,
+ T_SHORT = 9,
+ T_INT = 10,
+ T_LONG = 11,
+ T_OBJECT = 12,
+ T_ARRAY = 13,
+ T_VOID = 14,
+ T_ADDRESS = 15,
+ T_CONFLICT = 16, // for stack value type with conflicting contents
+ T_ILLEGAL = 99
+};
+
+// Convert a char from a classfile signature to a BasicType
+inline BasicType char2type(char c) {
+ switch( c ) {
+ case 'B': return T_BYTE;
+ case 'C': return T_CHAR;
+ case 'D': return T_DOUBLE;
+ case 'F': return T_FLOAT;
+ case 'I': return T_INT;
+ case 'J': return T_LONG;
+ case 'S': return T_SHORT;
+ case 'Z': return T_BOOLEAN;
+ case 'V': return T_VOID;
+ case 'L': return T_OBJECT;
+ case '[': return T_ARRAY;
+ }
+ return T_ILLEGAL;
+}
+
+extern char type2char_tab[T_CONFLICT+1]; // Map a BasicType to a jchar
+inline char type2char(BasicType t) { return (uint)t < T_CONFLICT+1 ? type2char_tab[t] : 0; }
+extern int type2size[T_CONFLICT+1]; // Map BasicType to result stack elements
+extern const char* type2name_tab[T_CONFLICT+1]; // Map a BasicType to a jchar
+inline const char* type2name(BasicType t) { return (uint)t < T_CONFLICT+1 ? type2name_tab[t] : NULL; }
+extern BasicType name2type(const char* name);
+
+// Auxilary math routines
+// least common multiple
+extern size_t lcm(size_t a, size_t b);
+
+
+// NOTE: replicated in SA in vm/agent/sun/jvm/hotspot/runtime/BasicType.java
+enum BasicTypeSize {
+ T_BOOLEAN_size = 1,
+ T_CHAR_size = 1,
+ T_FLOAT_size = 1,
+ T_DOUBLE_size = 2,
+ T_BYTE_size = 1,
+ T_SHORT_size = 1,
+ T_INT_size = 1,
+ T_LONG_size = 2,
+ T_OBJECT_size = 1,
+ T_ARRAY_size = 1,
+ T_VOID_size = 0
+};
+
+
+// maps a BasicType to its instance field storage type:
+// all sub-word integral types are widened to T_INT
+extern BasicType type2field[T_CONFLICT+1];
+extern BasicType type2wfield[T_CONFLICT+1];
+
+
+// size in bytes
+enum ArrayElementSize {
+ T_BOOLEAN_aelem_bytes = 1,
+ T_CHAR_aelem_bytes = 2,
+ T_FLOAT_aelem_bytes = 4,
+ T_DOUBLE_aelem_bytes = 8,
+ T_BYTE_aelem_bytes = 1,
+ T_SHORT_aelem_bytes = 2,
+ T_INT_aelem_bytes = 4,
+ T_LONG_aelem_bytes = 8,
+#ifdef _LP64
+ T_OBJECT_aelem_bytes = 8,
+ T_ARRAY_aelem_bytes = 8,
+#else
+ T_OBJECT_aelem_bytes = 4,
+ T_ARRAY_aelem_bytes = 4,
+#endif
+ T_VOID_aelem_bytes = 0
+};
+
+extern int type2aelembytes[T_CONFLICT+1]; // maps a BasicType to nof bytes used by its array element
+
+
+// JavaValue serves as a container for arbitrary Java values.
+
+class JavaValue {
+
+ public:
+ typedef union JavaCallValue {
+ jfloat f;
+ jdouble d;
+ jint i;
+ jlong l;
+ jobject h;
+ } JavaCallValue;
+
+ private:
+ BasicType _type;
+ JavaCallValue _value;
+
+ public:
+ JavaValue(BasicType t = T_ILLEGAL) { _type = t; }
+
+ JavaValue(jfloat value) {
+ _type = T_FLOAT;
+ _value.f = value;
+ }
+
+ JavaValue(jdouble value) {
+ _type = T_DOUBLE;
+ _value.d = value;
+ }
+
+ jfloat get_jfloat() const { return _value.f; }
+ jdouble get_jdouble() const { return _value.d; }
+ jint get_jint() const { return _value.i; }
+ jlong get_jlong() const { return _value.l; }
+ jobject get_jobject() const { return _value.h; }
+ JavaCallValue* get_value_addr() { return &_value; }
+ BasicType get_type() const { return _type; }
+
+ void set_jfloat(jfloat f) { _value.f = f;}
+ void set_jdouble(jdouble d) { _value.d = d;}
+ void set_jint(jint i) { _value.i = i;}
+ void set_jlong(jlong l) { _value.l = l;}
+ void set_jobject(jobject h) { _value.h = h;}
+ void set_type(BasicType t) { _type = t; }
+
+ jboolean get_jboolean() const { return (jboolean) (_value.i);}
+ jbyte get_jbyte() const { return (jbyte) (_value.i);}
+ jchar get_jchar() const { return (jchar) (_value.i);}
+ jshort get_jshort() const { return (jshort) (_value.i);}
+
+};
+
+
+#define STACK_BIAS 0
+// V9 Sparc CPU's running in 64 Bit mode use a stack bias of 7ff
+// in order to extend the reach of the stack pointer.
+#if defined(SPARC) && defined(_LP64)
+#undef STACK_BIAS
+#define STACK_BIAS 0x7ff
+#endif
+
+
+// TosState describes the top-of-stack state before and after the execution of
+// a bytecode or method. The top-of-stack value may be cached in one or more CPU
+// registers. The TosState corresponds to the 'machine represention' of this cached
+// value. There's 4 states corresponding to the JAVA types int, long, float & double
+// as well as a 5th state in case the top-of-stack value is actually on the top
+// of stack (in memory) and thus not cached. The atos state corresponds to the itos
+// state when it comes to machine representation but is used separately for (oop)
+// type specific operations (e.g. verification code).
+
+enum TosState { // describes the tos cache contents
+ btos = 0, // byte, bool tos cached
+ ctos = 1, // short, char tos cached
+ stos = 2, // short, char tos cached
+ itos = 3, // int tos cached
+ ltos = 4, // long tos cached
+ ftos = 5, // float tos cached
+ dtos = 6, // double tos cached
+ atos = 7, // object cached
+ vtos = 8, // tos not cached
+ number_of_states,
+ ilgl // illegal state: should not occur
+};
+
+
+inline TosState as_TosState(BasicType type) {
+ switch (type) {
+ case T_BYTE : return btos;
+ case T_BOOLEAN: return btos;
+ case T_CHAR : return ctos;
+ case T_SHORT : return stos;
+ case T_INT : return itos;
+ case T_LONG : return ltos;
+ case T_FLOAT : return ftos;
+ case T_DOUBLE : return dtos;
+ case T_VOID : return vtos;
+ case T_ARRAY : // fall through
+ case T_OBJECT : return atos;
+ }
+ return ilgl;
+}
+
+
+// Helper function to convert BasicType info into TosState
+// Note: Cannot define here as it uses global constant at the time being.
+TosState as_TosState(BasicType type);
+
+
+// ReferenceType is used to distinguish between java/lang/ref/Reference subclasses
+
+enum ReferenceType {
+ REF_NONE, // Regular class
+ REF_OTHER, // Subclass of java/lang/ref/Reference, but not subclass of one of the classes below
+ REF_SOFT, // Subclass of java/lang/ref/SoftReference
+ REF_WEAK, // Subclass of java/lang/ref/WeakReference
+ REF_FINAL, // Subclass of java/lang/ref/FinalReference
+ REF_PHANTOM // Subclass of java/lang/ref/PhantomReference
+};
+
+
+// JavaThreadState keeps track of which part of the code a thread is executing in. This
+// information is needed by the safepoint code.
+//
+// There are 4 essential states:
+//
+// _thread_new : Just started, but not executed init. code yet (most likely still in OS init code)
+// _thread_in_native : In native code. This is a safepoint region, since all oops will be in jobject handles
+// _thread_in_vm : Executing in the vm
+// _thread_in_Java : Executing either interpreted or compiled Java code (or could be in a stub)
+//
+// Each state has an associated xxxx_trans state, which is an intermediate state used when a thread is in
+// a transition from one state to another. These extra states makes it possible for the safepoint code to
+// handle certain thread_states without having to suspend the thread - making the safepoint code faster.
+//
+// Given a state, the xxx_trans state can always be found by adding 1.
+//
+enum JavaThreadState {
+ _thread_uninitialized = 0, // should never happen (missing initialization)
+ _thread_new = 2, // just starting up, i.e., in process of being initialized
+ _thread_new_trans = 3, // corresponding transition state (not used, included for completness)
+ _thread_in_native = 4, // running in native code
+ _thread_in_native_trans = 5, // corresponding transition state
+ _thread_in_vm = 6, // running in VM
+ _thread_in_vm_trans = 7, // corresponding transition state
+ _thread_in_Java = 8, // running in Java or in stub code
+ _thread_in_Java_trans = 9, // corresponding transition state (not used, included for completness)
+ _thread_blocked = 10, // blocked in vm
+ _thread_blocked_trans = 11, // corresponding transition state
+ _thread_max_state = 12 // maximum thread state+1 - used for statistics allocation
+};
+
+
+// Handy constants for deciding which compiler mode to use.
+enum MethodCompilation {
+ InvocationEntryBci = -1, // i.e., not a on-stack replacement compilation
+ InvalidOSREntryBci = -2
+};
+
+// Enumeration to distinguish tiers of compilation
+enum CompLevel {
+ CompLevel_none = 0,
+ CompLevel_fast_compile = 1,
+ CompLevel_full_optimization = 2,
+
+ CompLevel_highest_tier = CompLevel_full_optimization,
+#ifdef TIERED
+ CompLevel_initial_compile = CompLevel_fast_compile
+#else
+ CompLevel_initial_compile = CompLevel_full_optimization
+#endif // TIERED
+};
+
+inline bool is_tier1_compile(int comp_level) {
+ return comp_level == CompLevel_fast_compile;
+}
+inline bool is_tier2_compile(int comp_level) {
+ return comp_level == CompLevel_full_optimization;
+}
+inline bool is_highest_tier_compile(int comp_level) {
+ return comp_level == CompLevel_highest_tier;
+}
+
+//----------------------------------------------------------------------------------------------------
+// 'Forward' declarations of frequently used classes
+// (in order to reduce interface dependencies & reduce
+// number of unnecessary compilations after changes)
+
+class symbolTable;
+class ClassFileStream;
+
+class Event;
+
+class Thread;
+class VMThread;
+class JavaThread;
+class Threads;
+
+class VM_Operation;
+class VMOperationQueue;
+
+class CodeBlob;
+class nmethod;
+class OSRAdapter;
+class I2CAdapter;
+class C2IAdapter;
+class CompiledIC;
+class relocInfo;
+class ScopeDesc;
+class PcDesc;
+
+class Recompiler;
+class Recompilee;
+class RecompilationPolicy;
+class RFrame;
+class CompiledRFrame;
+class InterpretedRFrame;
+
+class frame;
+
+class vframe;
+class javaVFrame;
+class interpretedVFrame;
+class compiledVFrame;
+class deoptimizedVFrame;
+class externalVFrame;
+class entryVFrame;
+
+class RegisterMap;
+
+class Mutex;
+class Monitor;
+class BasicLock;
+class BasicObjectLock;
+
+class PeriodicTask;
+
+class JavaCallWrapper;
+
+class oopDesc;
+
+class NativeCall;
+
+class zone;
+
+class StubQueue;
+
+class outputStream;
+
+class ResourceArea;
+
+class DebugInformationRecorder;
+class ScopeValue;
+class CompressedStream;
+class DebugInfoReadStream;
+class DebugInfoWriteStream;
+class LocationValue;
+class ConstantValue;
+class IllegalValue;
+
+class PrivilegedElement;
+class MonitorArray;
+
+class MonitorInfo;
+
+class OffsetClosure;
+class OopMapCache;
+class InterpreterOopMap;
+class OopMapCacheEntry;
+class OSThread;
+
+typedef int (*OSThreadStartFunc)(void*);
+
+class Space;
+
+class JavaValue;
+class methodHandle;
+class JavaCallArguments;
+
+// Basic support for errors (general debug facilities not defined at this point fo the include phase)
+
+extern void basic_fatal(const char* msg);
+
+
+//----------------------------------------------------------------------------------------------------
+// Special constants for debugging
+
+const jint badInt = -3; // generic "bad int" value
+const long badAddressVal = -2; // generic "bad address" value
+const long badOopVal = -1; // generic "bad oop" value
+const intptr_t badHeapOopVal = (intptr_t) CONST64(0x2BAD4B0BBAADBABE); // value used to zap heap after GC
+const int badHandleValue = 0xBC; // value used to zap vm handle area
+const int badResourceValue = 0xAB; // value used to zap resource area
+const int freeBlockPad = 0xBA; // value used to pad freed blocks.
+const int uninitBlockPad = 0xF1; // value used to zap newly malloc'd blocks.
+const intptr_t badJNIHandleVal = (intptr_t) CONST64(0xFEFEFEFEFEFEFEFE); // value used to zap jni handle area
+const juint badHeapWordVal = 0xBAADBABE; // value used to zap heap after GC
+const int badCodeHeapNewVal= 0xCC; // value used to zap Code heap at allocation
+const int badCodeHeapFreeVal = 0xDD; // value used to zap Code heap at deallocation
+
+
+// (These must be implemented as #defines because C++ compilers are
+// not obligated to inline non-integral constants!)
+#define badAddress ((address)::badAddressVal)
+#define badOop ((oop)::badOopVal)
+#define badHeapWord (::badHeapWordVal)
+#define badJNIHandle ((oop)::badJNIHandleVal)
+
+
+//----------------------------------------------------------------------------------------------------
+// Utility functions for bitfield manipulations
+
+const intptr_t AllBits = ~0; // all bits set in a word
+const intptr_t NoBits = 0; // no bits set in a word
+const jlong NoLongBits = 0; // no bits set in a long
+const intptr_t OneBit = 1; // only right_most bit set in a word
+
+// get a word with the n.th or the right-most or left-most n bits set
+// (note: #define used only so that they can be used in enum constant definitions)
+#define nth_bit(n) (n >= BitsPerWord ? 0 : OneBit << (n))
+#define right_n_bits(n) (nth_bit(n) - 1)
+#define left_n_bits(n) (right_n_bits(n) << (n >= BitsPerWord ? 0 : (BitsPerWord - n)))
+
+// bit-operations using a mask m
+inline void set_bits (intptr_t& x, intptr_t m) { x |= m; }
+inline void clear_bits (intptr_t& x, intptr_t m) { x &= ~m; }
+inline intptr_t mask_bits (intptr_t x, intptr_t m) { return x & m; }
+inline jlong mask_long_bits (jlong x, jlong m) { return x & m; }
+inline bool mask_bits_are_true (intptr_t flags, intptr_t mask) { return (flags & mask) == mask; }
+
+// bit-operations using the n.th bit
+inline void set_nth_bit(intptr_t& x, int n) { set_bits (x, nth_bit(n)); }
+inline void clear_nth_bit(intptr_t& x, int n) { clear_bits(x, nth_bit(n)); }
+inline bool is_set_nth_bit(intptr_t x, int n) { return mask_bits (x, nth_bit(n)) != NoBits; }
+
+// returns the bitfield of x starting at start_bit_no with length field_length (no sign-extension!)
+inline intptr_t bitfield(intptr_t x, int start_bit_no, int field_length) {
+ return mask_bits(x >> start_bit_no, right_n_bits(field_length));
+}
+
+
+//----------------------------------------------------------------------------------------------------
+// Utility functions for integers
+
+// Avoid use of global min/max macros which may cause unwanted double
+// evaluation of arguments.
+#ifdef max
+#undef max
+#endif
+
+#ifdef min
+#undef min
+#endif
+
+#define max(a,b) Do_not_use_max_use_MAX2_instead
+#define min(a,b) Do_not_use_min_use_MIN2_instead
+
+// It is necessary to use templates here. Having normal overloaded
+// functions does not work because it is necessary to provide both 32-
+// and 64-bit overloaded functions, which does not work, and having
+// explicitly-typed versions of these routines (i.e., MAX2I, MAX2L)
+// will be even more error-prone than macros.
+template<class T> inline T MAX2(T a, T b) { return (a > b) ? a : b; }
+template<class T> inline T MIN2(T a, T b) { return (a < b) ? a : b; }
+template<class T> inline T MAX3(T a, T b, T c) { return MAX2(MAX2(a, b), c); }
+template<class T> inline T MIN3(T a, T b, T c) { return MIN2(MIN2(a, b), c); }
+template<class T> inline T MAX4(T a, T b, T c, T d) { return MAX2(MAX3(a, b, c), d); }
+template<class T> inline T MIN4(T a, T b, T c, T d) { return MIN2(MIN3(a, b, c), d); }
+
+template<class T> inline T ABS(T x) { return (x > 0) ? x : -x; }
+
+// true if x is a power of 2, false otherwise
+inline bool is_power_of_2(intptr_t x) {
+ return ((x != NoBits) && (mask_bits(x, x - 1) == NoBits));
+}
+
+// long version of is_power_of_2
+inline bool is_power_of_2_long(jlong x) {
+ return ((x != NoLongBits) && (mask_long_bits(x, x - 1) == NoLongBits));
+}
+
+//* largest i such that 2^i <= x
+// A negative value of 'x' will return '31'
+inline int log2_intptr(intptr_t x) {
+ int i = -1;
+ uintptr_t p = 1;
+ while (p != 0 && p <= (uintptr_t)x) {
+ // p = 2^(i+1) && p <= x (i.e., 2^(i+1) <= x)
+ i++; p *= 2;
+ }
+ // p = 2^(i+1) && x < p (i.e., 2^i <= x < 2^(i+1))
+ // (if p = 0 then overflow occured and i = 31)
+ return i;
+}
+
+//* largest i such that 2^i <= x
+// A negative value of 'x' will return '63'
+inline int log2_long(jlong x) {
+ int i = -1;
+ julong p = 1;
+ while (p != 0 && p <= (julong)x) {
+ // p = 2^(i+1) && p <= x (i.e., 2^(i+1) <= x)
+ i++; p *= 2;
+ }
+ // p = 2^(i+1) && x < p (i.e., 2^i <= x < 2^(i+1))
+ // (if p = 0 then overflow occured and i = 31)
+ return i;
+}
+
+//* the argument must be exactly a power of 2
+inline int exact_log2(intptr_t x) {
+ #ifdef ASSERT
+ if (!is_power_of_2(x)) basic_fatal("x must be a power of 2");
+ #endif
+ return log2_intptr(x);
+}
+
+
+// returns integer round-up to the nearest multiple of s (s must be a power of two)
+inline intptr_t round_to(intptr_t x, uintx s) {
+ #ifdef ASSERT
+ if (!is_power_of_2(s)) basic_fatal("s must be a power of 2");
+ #endif
+ const uintx m = s - 1;
+ return mask_bits(x + m, ~m);
+}
+
+// returns integer round-down to the nearest multiple of s (s must be a power of two)
+inline intptr_t round_down(intptr_t x, uintx s) {
+ #ifdef ASSERT
+ if (!is_power_of_2(s)) basic_fatal("s must be a power of 2");
+ #endif
+ const uintx m = s - 1;
+ return mask_bits(x, ~m);
+}
+
+
+inline bool is_odd (intx x) { return x & 1; }
+inline bool is_even(intx x) { return !is_odd(x); }
+
+// "to" should be greater than "from."
+inline intx byte_size(void* from, void* to) {
+ return (address)to - (address)from;
+}
+
+//----------------------------------------------------------------------------------------------------
+// Avoid non-portable casts with these routines (DEPRECATED)
+
+// NOTE: USE Bytes class INSTEAD WHERE POSSIBLE
+// Bytes is optimized machine-specifically and may be much faster then the portable routines below.
+
+// Given sequence of four bytes, build into a 32-bit word
+// following the conventions used in class files.
+// On the 386, this could be realized with a simple address cast.
+//
+
+// This routine takes eight bytes:
+inline u8 build_u8_from( u1 c1, u1 c2, u1 c3, u1 c4, u1 c5, u1 c6, u1 c7, u1 c8 ) {
+ return ( u8(c1) << 56 ) & ( u8(0xff) << 56 )
+ | ( u8(c2) << 48 ) & ( u8(0xff) << 48 )
+ | ( u8(c3) << 40 ) & ( u8(0xff) << 40 )
+ | ( u8(c4) << 32 ) & ( u8(0xff) << 32 )
+ | ( u8(c5) << 24 ) & ( u8(0xff) << 24 )
+ | ( u8(c6) << 16 ) & ( u8(0xff) << 16 )
+ | ( u8(c7) << 8 ) & ( u8(0xff) << 8 )
+ | ( u8(c8) << 0 ) & ( u8(0xff) << 0 );
+}
+
+// This routine takes four bytes:
+inline u4 build_u4_from( u1 c1, u1 c2, u1 c3, u1 c4 ) {
+ return ( u4(c1) << 24 ) & 0xff000000
+ | ( u4(c2) << 16 ) & 0x00ff0000
+ | ( u4(c3) << 8 ) & 0x0000ff00
+ | ( u4(c4) << 0 ) & 0x000000ff;
+}
+
+// And this one works if the four bytes are contiguous in memory:
+inline u4 build_u4_from( u1* p ) {
+ return build_u4_from( p[0], p[1], p[2], p[3] );
+}
+
+// Ditto for two-byte ints:
+inline u2 build_u2_from( u1 c1, u1 c2 ) {
+ return u2(( u2(c1) << 8 ) & 0xff00
+ | ( u2(c2) << 0 ) & 0x00ff);
+}
+
+// And this one works if the two bytes are contiguous in memory:
+inline u2 build_u2_from( u1* p ) {
+ return build_u2_from( p[0], p[1] );
+}
+
+// Ditto for floats:
+inline jfloat build_float_from( u1 c1, u1 c2, u1 c3, u1 c4 ) {
+ u4 u = build_u4_from( c1, c2, c3, c4 );
+ return *(jfloat*)&u;
+}
+
+inline jfloat build_float_from( u1* p ) {
+ u4 u = build_u4_from( p );
+ return *(jfloat*)&u;
+}
+
+
+// now (64-bit) longs
+
+inline jlong build_long_from( u1 c1, u1 c2, u1 c3, u1 c4, u1 c5, u1 c6, u1 c7, u1 c8 ) {
+ return ( jlong(c1) << 56 ) & ( jlong(0xff) << 56 )
+ | ( jlong(c2) << 48 ) & ( jlong(0xff) << 48 )
+ | ( jlong(c3) << 40 ) & ( jlong(0xff) << 40 )
+ | ( jlong(c4) << 32 ) & ( jlong(0xff) << 32 )
+ | ( jlong(c5) << 24 ) & ( jlong(0xff) << 24 )
+ | ( jlong(c6) << 16 ) & ( jlong(0xff) << 16 )
+ | ( jlong(c7) << 8 ) & ( jlong(0xff) << 8 )
+ | ( jlong(c8) << 0 ) & ( jlong(0xff) << 0 );
+}
+
+inline jlong build_long_from( u1* p ) {
+ return build_long_from( p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7] );
+}
+
+
+// Doubles, too!
+inline jdouble build_double_from( u1 c1, u1 c2, u1 c3, u1 c4, u1 c5, u1 c6, u1 c7, u1 c8 ) {
+ jlong u = build_long_from( c1, c2, c3, c4, c5, c6, c7, c8 );
+ return *(jdouble*)&u;
+}
+
+inline jdouble build_double_from( u1* p ) {
+ jlong u = build_long_from( p );
+ return *(jdouble*)&u;
+}
+
+
+// Portable routines to go the other way:
+
+inline void explode_short_to( u2 x, u1& c1, u1& c2 ) {
+ c1 = u1(x >> 8);
+ c2 = u1(x);
+}
+
+inline void explode_short_to( u2 x, u1* p ) {
+ explode_short_to( x, p[0], p[1]);
+}
+
+inline void explode_int_to( u4 x, u1& c1, u1& c2, u1& c3, u1& c4 ) {
+ c1 = u1(x >> 24);
+ c2 = u1(x >> 16);
+ c3 = u1(x >> 8);
+ c4 = u1(x);
+}
+
+inline void explode_int_to( u4 x, u1* p ) {
+ explode_int_to( x, p[0], p[1], p[2], p[3]);
+}
+
+
+// Pack and extract shorts to/from ints:
+
+inline int extract_low_short_from_int(jint x) {
+ return x & 0xffff;
+}
+
+inline int extract_high_short_from_int(jint x) {
+ return (x >> 16) & 0xffff;
+}
+
+inline int build_int_from_shorts( jushort low, jushort high ) {
+ return ((int)((unsigned int)high << 16) | (unsigned int)low);
+}
+
+// Printf-style formatters for fixed- and variable-width types as pointers and
+// integers.
+//
+// Each compiler-specific definitions file (e.g., globalDefinitions_gcc.hpp)
+// must define the macro FORMAT64_MODIFIER, which is the modifier for '%x' or
+// '%d' formats to indicate a 64-bit quantity; commonly "l" (in LP64) or "ll"
+// (in ILP32).
+
+// Format 32-bit quantities.
+#define INT32_FORMAT "%d"
+#define UINT32_FORMAT "%u"
+#define INT32_FORMAT_W(width) "%" #width "d"
+#define UINT32_FORMAT_W(width) "%" #width "u"
+
+#define PTR32_FORMAT "0x%08x"
+
+// Format 64-bit quantities.
+#define INT64_FORMAT "%" FORMAT64_MODIFIER "d"
+#define UINT64_FORMAT "%" FORMAT64_MODIFIER "u"
+#define PTR64_FORMAT "0x%016" FORMAT64_MODIFIER "x"
+
+#define INT64_FORMAT_W(width) "%" #width FORMAT64_MODIFIER "d"
+#define UINT64_FORMAT_W(width) "%" #width FORMAT64_MODIFIER "u"
+
+// Format macros that allow the field width to be specified. The width must be
+// a string literal (e.g., "8") or a macro that evaluates to one.
+#ifdef _LP64
+#define SSIZE_FORMAT_W(width) INT64_FORMAT_W(width)
+#define SIZE_FORMAT_W(width) UINT64_FORMAT_W(width)
+#else
+#define SSIZE_FORMAT_W(width) INT32_FORMAT_W(width)
+#define SIZE_FORMAT_W(width) UINT32_FORMAT_W(width)
+#endif // _LP64
+
+// Format pointers and size_t (or size_t-like integer types) which change size
+// between 32- and 64-bit.
+#ifdef _LP64
+#define PTR_FORMAT PTR64_FORMAT
+#define UINTX_FORMAT UINT64_FORMAT
+#define INTX_FORMAT INT64_FORMAT
+#define SIZE_FORMAT UINT64_FORMAT
+#define SSIZE_FORMAT INT64_FORMAT
+#else // !_LP64
+#define PTR_FORMAT PTR32_FORMAT
+#define UINTX_FORMAT UINT32_FORMAT
+#define INTX_FORMAT INT32_FORMAT
+#define SIZE_FORMAT UINT32_FORMAT
+#define SSIZE_FORMAT INT32_FORMAT
+#endif // _LP64
+
+#define INTPTR_FORMAT PTR_FORMAT
+
+// Enable zap-a-lot if in debug version.
+
+# ifdef ASSERT
+# ifdef COMPILER2
+# define ENABLE_ZAP_DEAD_LOCALS
+#endif /* COMPILER2 */
+# endif /* ASSERT */
+
+#define ARRAY_SIZE(array) (sizeof(array)/sizeof((array)[0]))
diff --git a/src/share/vm/utilities/globalDefinitions_gcc.hpp b/src/share/vm/utilities/globalDefinitions_gcc.hpp
new file mode 100644
index 000000000..417978f08
--- /dev/null
+++ b/src/share/vm/utilities/globalDefinitions_gcc.hpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright 1998-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// This file holds compiler-dependent includes,
+// globally used constants & types, class (forward)
+// declarations and a few frequently used utility functions.
+
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+#ifdef SOLARIS
+#include <ieeefp.h>
+#endif // SOLARIS
+
+#include <math.h>
+#ifndef FP_PZERO
+// Linux doesn't have positive/negative zero
+#define FP_PZERO FP_ZERO
+#endif
+#if (!defined fpclass) && ((!defined SPARC) || (!defined SOLARIS))
+#define fpclass fpclassify
+#endif
+
+#include <time.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <pthread.h>
+
+#ifdef SOLARIS
+#include <thread.h>
+#endif // SOLARIS
+
+#include <limits.h>
+#include <errno.h>
+
+#ifdef SOLARIS
+#include <sys/trap.h>
+#include <sys/regset.h>
+#include <sys/procset.h>
+#include <ucontext.h>
+#include <setjmp.h>
+#endif // SOLARIS
+
+# ifdef SOLARIS_MUTATOR_LIBTHREAD
+# include <sys/procfs.h>
+# endif
+
+#ifdef LINUX
+#include <inttypes.h>
+#include <signal.h>
+#include <ucontext.h>
+#include <sys/time.h>
+#endif // LINUX
+
+// 4810578: varargs unsafe on 32-bit integer/64-bit pointer architectures
+// When __cplusplus is defined, NULL is defined as 0 (32-bit constant) in
+// system header files. On 32-bit architectures, there is no problem.
+// On 64-bit architectures, defining NULL as a 32-bit constant can cause
+// problems with varargs functions: C++ integral promotion rules say for
+// varargs, we pass the argument 0 as an int. So, if NULL was passed to a
+// varargs function it will remain 32-bits. Depending on the calling
+// convention of the machine, if the argument is passed on the stack then
+// only 32-bits of the "NULL" pointer may be initialized to zero. The
+// other 32-bits will be garbage. If the varargs function is expecting a
+// pointer when it extracts the argument, then we have a problem.
+//
+// Solution: For 64-bit architectures, redefine NULL as 64-bit constant 0.
+//
+// Note: this fix doesn't work well on Linux because NULL will be overwritten
+// whenever a system header file is included. Linux handles NULL correctly
+// through a special type '__null'.
+#ifdef SOLARIS
+ #ifdef _LP64
+ #undef NULL
+ #define NULL 0L
+ #else
+ #ifndef NULL
+ #define NULL 0
+ #endif
+ #endif
+#endif
+
+// NULL vs NULL_WORD:
+// On Linux NULL is defined as a special type '__null'. Assigning __null to
+// integer variable will cause gcc warning. Use NULL_WORD in places where a
+// pointer is stored as integer value. On some platforms, sizeof(intptr_t) >
+// sizeof(void*), so here we want something which is integer type, but has the
+// same size as a pointer.
+#ifdef LINUX
+ #ifdef _LP64
+ #define NULL_WORD 0L
+ #else
+ #define NULL_WORD 0
+ #endif
+#else
+ #define NULL_WORD NULL
+#endif
+
+#ifndef LINUX
+// Compiler-specific primitive types
+typedef unsigned short uint16_t;
+#ifndef _UINT32_T
+#define _UINT32_T
+typedef unsigned int uint32_t;
+#endif // _UINT32_T
+
+#if !defined(_SYS_INT_TYPES_H)
+#ifndef _UINT64_T
+#define _UINT64_T
+typedef unsigned long long uint64_t;
+#endif // _UINT64_T
+// %%%% how to access definition of intptr_t portably in 5.5 onward?
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+// If this gets an error, figure out a symbol XXX that implies the
+// prior definition of intptr_t, and add "&& !defined(XXX)" above.
+#endif // _SYS_INT_TYPES_H
+
+#endif // !LINUX
+
+// Additional Java basic types
+
+typedef uint8_t jubyte;
+typedef uint16_t jushort;
+typedef uint32_t juint;
+typedef uint64_t julong;
+
+//----------------------------------------------------------------------------------------------------
+// Special (possibly not-portable) casts
+// Cast floats into same-size integers and vice-versa w/o changing bit-pattern
+// %%%%%% These seem like standard C++ to me--how about factoring them out? - Ungar
+
+inline jint jint_cast (jfloat x) { return *(jint* )&x; }
+inline jlong jlong_cast (jdouble x) { return *(jlong* )&x; }
+
+inline jfloat jfloat_cast (jint x) { return *(jfloat* )&x; }
+inline jdouble jdouble_cast(jlong x) { return *(jdouble*)&x; }
+
+//----------------------------------------------------------------------------------------------------
+// Constant for jlong (specifying an long long canstant is C++ compiler specific)
+
+// Build a 64bit integer constant
+#define CONST64(x) (x ## LL)
+#define UCONST64(x) (x ## ULL)
+
+const jlong min_jlong = CONST64(0x8000000000000000);
+const jlong max_jlong = CONST64(0x7fffffffffffffff);
+
+
+#ifdef SOLARIS
+//----------------------------------------------------------------------------------------------------
+// ANSI C++ fixes
+// NOTE:In the ANSI committee's continuing attempt to make each version
+// of C++ incompatible with the previous version, you can no longer cast
+// pointers to functions without specifying linkage unless you want to get
+// warnings.
+//
+// This also means that pointers to functions can no longer be "hidden"
+// in opaque types like void * because at the invokation point warnings
+// will be generated. While this makes perfect sense from a type safety
+// point of view it causes a lot of warnings on old code using C header
+// files. Here are some typedefs to make the job of silencing warnings
+// a bit easier.
+//
+// The final kick in the teeth is that you can only have extern "C" linkage
+// specified at file scope. So these typedefs are here rather than in the
+// .hpp for the class (os:Solaris usually) that needs them.
+
+extern "C" {
+ typedef int (*int_fnP_thread_t_iP_uP_stack_tP_gregset_t)(thread_t, int*, unsigned *, stack_t*, gregset_t);
+ typedef int (*int_fnP_thread_t_i_gregset_t)(thread_t, int, gregset_t);
+ typedef int (*int_fnP_thread_t_i)(thread_t, int);
+ typedef int (*int_fnP_thread_t)(thread_t);
+
+ typedef int (*int_fnP_cond_tP_mutex_tP_timestruc_tP)(cond_t *cv, mutex_t *mx, timestruc_t *abst);
+ typedef int (*int_fnP_cond_tP_mutex_tP)(cond_t *cv, mutex_t *mx);
+
+ // typedef for missing API in libc
+ typedef int (*int_fnP_mutex_tP_i_vP)(mutex_t *, int, void *);
+ typedef int (*int_fnP_mutex_tP)(mutex_t *);
+ typedef int (*int_fnP_cond_tP_i_vP)(cond_t *cv, int scope, void *arg);
+ typedef int (*int_fnP_cond_tP)(cond_t *cv);
+};
+#endif // SOLARIS
+
+//----------------------------------------------------------------------------------------------------
+// Debugging
+
+#define DEBUG_EXCEPTION ::abort();
+
+extern "C" void breakpoint();
+#define BREAKPOINT ::breakpoint()
+
+// checking for nanness
+#ifdef SOLARIS
+#ifdef SPARC
+inline int g_isnan(float f) { return isnanf(f); }
+#else
+// isnanf() broken on Intel Solaris use isnand()
+inline int g_isnan(float f) { return isnand(f); }
+#endif
+inline int g_isnan(double f) { return isnand(f); }
+#elif LINUX
+inline int g_isnan(float f) { return isnanf(f); }
+inline int g_isnan(double f) { return isnan(f); }
+#else
+#error "missing platform-specific definition here"
+#endif
+
+// Checking for finiteness
+
+inline int g_isfinite(jfloat f) { return finite(f); }
+inline int g_isfinite(jdouble f) { return finite(f); }
+
+
+// Wide characters
+
+inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); }
+
+
+// Portability macros
+#define PRAGMA_INTERFACE #pragma interface
+#define PRAGMA_IMPLEMENTATION #pragma implementation
+#define VALUE_OBJ_CLASS_SPEC
+
+#if (__GNUC__ == 2) && (__GNUC_MINOR__ < 95)
+#define TEMPLATE_TABLE_BUG
+#endif
+#if (__GNUC__ == 2) && (__GNUC_MINOR__ >= 96)
+#define CONST_SDM_BUG
+#endif
+
+// Formatting.
+#ifdef _LP64
+#define FORMAT64_MODIFIER "l"
+#else // !_LP64
+#define FORMAT64_MODIFIER "ll"
+#endif // _LP64
+
+// HACK: gcc warns about applying offsetof() to non-POD object or calculating
+// offset directly when base address is NULL. Use 16 to get around the
+// warning. gcc-3.4 has an option -Wno-invalid-offsetof to suppress
+// this warning.
+#define offset_of(klass,field) (size_t)((intx)&(((klass*)16)->field) - 16)
+
+#ifdef offsetof
+# undef offsetof
+#endif
+#define offsetof(klass,field) offset_of(klass,field)
diff --git a/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp b/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp
new file mode 100644
index 000000000..16ae1ce9b
--- /dev/null
+++ b/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// This file holds compiler-dependent includes,
+// globally used constants & types, class (forward)
+// declarations and a few frequently used utility functions.
+
+
+# include <ctype.h>
+# include <dirent.h>
+# include <string.h>
+# include <strings.h> // for bsd'isms
+# include <stdarg.h>
+# include <stddef.h> // for offsetof
+# include <stdio.h>
+# include <stdlib.h>
+# include <wchar.h>
+# include <stdarg.h>
+# include <ieeefp.h>
+# include <math.h>
+# include <time.h>
+# include <fcntl.h>
+# include <dlfcn.h>
+# include <pthread.h>
+# include <thread.h>
+# include <limits.h>
+# include <errno.h>
+# include <sys/trap.h>
+# include <sys/regset.h>
+# include <sys/procset.h>
+# include <ucontext.h>
+# include <setjmp.h>
+# ifdef SOLARIS_MUTATOR_LIBTHREAD
+# include <sys/procfs.h>
+# endif
+
+// 4810578: varargs unsafe on 32-bit integer/64-bit pointer architectures
+// When __cplusplus is defined, NULL is defined as 0 (32-bit constant) in
+// system header files. On 32-bit architectures, there is no problem.
+// On 64-bit architectures, defining NULL as a 32-bit constant can cause
+// problems with varargs functions: C++ integral promotion rules say for
+// varargs, we pass the argument 0 as an int. So, if NULL was passed to a
+// varargs function it will remain 32-bits. Depending on the calling
+// convention of the machine, if the argument is passed on the stack then
+// only 32-bits of the "NULL" pointer may be initialized to zero. The
+// other 32-bits will be garbage. If the varargs function is expecting a
+// pointer when it extracts the argument, then we have a problem.
+//
+// Solution: For 64-bit architectures, redefine NULL as 64-bit constant 0.
+#ifdef _LP64
+#undef NULL
+#define NULL 0L
+#else
+#ifndef NULL
+#define NULL 0
+#endif
+#endif
+
+// NULL vs NULL_WORD:
+// On Linux NULL is defined as a special type '__null'. Assigning __null to
+// integer variable will cause gcc warning. Use NULL_WORD in places where a
+// pointer is stored as integer value.
+#define NULL_WORD NULL
+
+// Compiler-specific primitive types
+typedef unsigned short uint16_t;
+#ifndef _UINT32_T
+#define _UINT32_T
+typedef unsigned int uint32_t;
+#endif
+#if !defined(_SYS_INT_TYPES_H)
+#ifndef _UINT64_T
+#define _UINT64_T
+typedef unsigned long long uint64_t;
+#endif
+// %%%% how to access definition of intptr_t portably in 5.5 onward?
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+// If this gets an error, figure out a symbol XXX that implies the
+// prior definition of intptr_t, and add "&& !defined(XXX)" above.
+#endif
+
+// Additional Java basic types
+
+typedef unsigned char jubyte;
+typedef unsigned short jushort;
+typedef unsigned int juint;
+typedef unsigned long long julong;
+
+//----------------------------------------------------------------------------------------------------
+// Special (possibly not-portable) casts
+// Cast floats into same-size integers and vice-versa w/o changing bit-pattern
+
+inline jint jint_cast (jfloat x) { return *(jint* )&x; }
+inline jlong jlong_cast (jdouble x) { return *(jlong* )&x; }
+
+inline jfloat jfloat_cast (jint x) { return *(jfloat* )&x; }
+inline jdouble jdouble_cast(jlong x) { return *(jdouble*)&x; }
+
+//----------------------------------------------------------------------------------------------------
+// Constant for jlong (specifying an long long constant is C++ compiler specific)
+
+// Build a 64bit integer constant
+#define CONST64(x) (x ## LL)
+#define UCONST64(x) (x ## ULL)
+
+const jlong min_jlong = CONST64(0x8000000000000000);
+const jlong max_jlong = CONST64(0x7fffffffffffffff);
+
+
+//----------------------------------------------------------------------------------------------------
+// ANSI C++ fixes
+// NOTE:In the ANSI committee's continuing attempt to make each version
+// of C++ incompatible with the previous version, you can no longer cast
+// pointers to functions without specifying linkage unless you want to get
+// warnings.
+//
+// This also means that pointers to functions can no longer be "hidden"
+// in opaque types like void * because at the invokation point warnings
+// will be generated. While this makes perfect sense from a type safety
+// point of view it causes a lot of warnings on old code using C header
+// files. Here are some typedefs to make the job of silencing warnings
+// a bit easier.
+//
+// The final kick in the teeth is that you can only have extern "C" linkage
+// specified at file scope. So these typedefs are here rather than in the
+// .hpp for the class (os:Solaris usually) that needs them.
+
+extern "C" {
+ typedef int (*int_fnP_thread_t_iP_uP_stack_tP_gregset_t)(thread_t, int*, unsigned *, stack_t*, gregset_t);
+ typedef int (*int_fnP_thread_t_i_gregset_t)(thread_t, int, gregset_t);
+ typedef int (*int_fnP_thread_t_i)(thread_t, int);
+ typedef int (*int_fnP_thread_t)(thread_t);
+
+ typedef int (*int_fnP_cond_tP_mutex_tP_timestruc_tP)(cond_t *cv, mutex_t *mx, timestruc_t *abst);
+ typedef int (*int_fnP_cond_tP_mutex_tP)(cond_t *cv, mutex_t *mx);
+
+ // typedef for missing API in libc
+ typedef int (*int_fnP_mutex_tP_i_vP)(mutex_t *, int, void *);
+ typedef int (*int_fnP_mutex_tP)(mutex_t *);
+ typedef int (*int_fnP_cond_tP_i_vP)(cond_t *cv, int scope, void *arg);
+ typedef int (*int_fnP_cond_tP)(cond_t *cv);
+};
+
+
+//----------------------------------------------------------------------------------------------------
+// Debugging
+
+#define DEBUG_EXCEPTION ::abort();
+
+extern "C" void breakpoint();
+#define BREAKPOINT ::breakpoint()
+
+// checking for nanness
+
+#ifdef SPARC
+inline int g_isnan(float f) { return isnanf(f); }
+#else
+// isnanf() broken on Intel Solaris use isnand()
+inline int g_isnan(float f) { return isnand(f); }
+#endif
+
+inline int g_isnan(double f) { return isnand(f); }
+
+// Checking for finiteness
+
+inline int g_isfinite(jfloat f) { return finite(f); }
+inline int g_isfinite(jdouble f) { return finite(f); }
+
+
+// Wide characters
+
+inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); }
+
+
+// Misc
+int local_vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr);
+#define vsnprintf local_vsnprintf
+
+
+// Portability macros
+#define PRAGMA_INTERFACE
+#define PRAGMA_IMPLEMENTATION
+#define PRAGMA_IMPLEMENTATION_(arg)
+#define VALUE_OBJ_CLASS_SPEC : public _ValueObj
+
+// Formatting.
+#ifdef _LP64
+#define FORMAT64_MODIFIER "l"
+#else // !_LP64
+#define FORMAT64_MODIFIER "ll"
+#endif // _LP64
+
+#define offset_of(klass,field) offsetof(klass,field)
diff --git a/src/share/vm/utilities/globalDefinitions_visCPP.hpp b/src/share/vm/utilities/globalDefinitions_visCPP.hpp
new file mode 100644
index 000000000..6b4804ec5
--- /dev/null
+++ b/src/share/vm/utilities/globalDefinitions_visCPP.hpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// This file holds compiler-dependent includes,
+// globally used constants & types, class (forward)
+// declarations and a few frequently used utility functions.
+
+# include <ctype.h>
+# include <string.h>
+# include <stdarg.h>
+# include <stdlib.h>
+# include <stddef.h>// for offsetof
+# include <io.h> // for stream.cpp
+# include <float.h> // for _isnan
+# include <stdio.h> // for va_list
+# include <time.h>
+# include <fcntl.h>
+// Need this on windows to get the math constants (e.g., M_PI).
+#define _USE_MATH_DEFINES
+# include <math.h>
+
+// 4810578: varargs unsafe on 32-bit integer/64-bit pointer architectures
+// When __cplusplus is defined, NULL is defined as 0 (32-bit constant) in
+// system header files. On 32-bit architectures, there is no problem.
+// On 64-bit architectures, defining NULL as a 32-bit constant can cause
+// problems with varargs functions: C++ integral promotion rules say for
+// varargs, we pass the argument 0 as an int. So, if NULL was passed to a
+// varargs function it will remain 32-bits. Depending on the calling
+// convention of the machine, if the argument is passed on the stack then
+// only 32-bits of the "NULL" pointer may be initialized to zero. The
+// other 32-bits will be garbage. If the varargs function is expecting a
+// pointer when it extracts the argument, then we may have a problem.
+//
+// Solution: For 64-bit architectures, redefine NULL as 64-bit constant 0.
+#ifdef _LP64
+#undef NULL
+// 64-bit Windows uses a P64 data model (not LP64, although we define _LP64)
+// Since longs are 32-bit we cannot use 0L here. Use the Visual C++ specific
+// 64-bit integer-suffix (i64) instead.
+#define NULL 0i64
+#else
+#ifndef NULL
+#define NULL 0
+#endif
+#endif
+
+// NULL vs NULL_WORD:
+// On Linux NULL is defined as a special type '__null'. Assigning __null to
+// integer variable will cause gcc warning. Use NULL_WORD in places where a
+// pointer is stored as integer value.
+#define NULL_WORD NULL
+
+// Compiler-specific primitive types
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+
+#ifdef _WIN64
+typedef unsigned __int64 uintptr_t;
+#else
+typedef unsigned int uintptr_t;
+#endif
+typedef signed __int8 int8_t;
+typedef signed __int16 int16_t;
+typedef signed __int32 int32_t;
+typedef signed __int64 int64_t;
+#ifdef _WIN64
+typedef signed __int64 intptr_t;
+typedef signed __int64 ssize_t;
+#else
+typedef signed int intptr_t;
+typedef signed int ssize_t;
+#endif
+
+//----------------------------------------------------------------------------------------------------
+// Additional Java basic types
+
+typedef unsigned char jubyte;
+typedef unsigned short jushort;
+typedef unsigned int juint;
+typedef unsigned __int64 julong;
+
+//----------------------------------------------------------------------------------------------------
+// Special (possibly not-portable) casts
+// Cast floats into same-size integers and vice-versa w/o changing bit-pattern
+
+inline jint jint_cast (jfloat x) { return *(jint* )&x; }
+inline jlong jlong_cast (jdouble x) { return *(jlong* )&x; }
+
+inline jfloat jfloat_cast (jint x) { return *(jfloat* )&x; }
+inline jdouble jdouble_cast(jlong x) { return *(jdouble*)&x; }
+
+
+//----------------------------------------------------------------------------------------------------
+// Non-standard stdlib-like stuff:
+inline int strcasecmp(const char *s1, const char *s2) { return _stricmp(s1,s2); }
+
+
+//----------------------------------------------------------------------------------------------------
+// Debugging
+
+#if _WIN64
+extern "C" void breakpoint();
+#define BREAKPOINT ::breakpoint()
+#else
+#define BREAKPOINT __asm { int 3 }
+#endif
+
+//----------------------------------------------------------------------------------------------------
+// Checking for nanness
+
+inline int g_isnan(jfloat f) { return _isnan(f); }
+inline int g_isnan(jdouble f) { return _isnan(f); }
+
+//----------------------------------------------------------------------------------------------------
+// Checking for finiteness
+
+inline int g_isfinite(jfloat f) { return _finite(f); }
+inline int g_isfinite(jdouble f) { return _finite(f); }
+
+//----------------------------------------------------------------------------------------------------
+// Constant for jlong (specifying an long long constant is C++ compiler specific)
+
+// Build a 64bit integer constant on with Visual C++
+#define CONST64(x) (x ## i64)
+#define UCONST64(x) ((uint64_t)CONST64(x))
+
+const jlong min_jlong = CONST64(0x8000000000000000);
+const jlong max_jlong = CONST64(0x7fffffffffffffff);
+
+//----------------------------------------------------------------------------------------------------
+// Miscellaneous
+
+inline int vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr) {
+ // If number of characters written == count, Windows doesn't write a
+ // terminating NULL, so we do it ourselves.
+ int ret = _vsnprintf(buf, count, fmt, argptr);
+ if (count > 0) buf[count-1] = '\0';
+ return ret;
+}
+
+// Visual Studio 2005 deprecates POSIX names - use ISO C++ names instead
+#if _MSC_VER >= 1400 && !defined(_WIN64)
+#define open _open
+#define close _close
+#define read _read
+#define write _write
+#define lseek _lseek
+#define unlink _unlink
+#define strdup _strdup
+#endif
+
+#pragma warning( disable : 4100 ) // unreferenced formal parameter
+#pragma warning( disable : 4127 ) // conditional expression is constant
+#pragma warning( disable : 4514 ) // unreferenced inline function has been removed
+#pragma warning( disable : 4244 ) // possible loss of data
+#pragma warning( disable : 4512 ) // assignment operator could not be generated
+#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union (needed in windows.h)
+#pragma warning( disable : 4511 ) // copy constructor could not be generated
+#pragma warning( disable : 4291 ) // no matching operator delete found; memory will not be freed if initialization thows an exception
+
+// Portability macros
+#define PRAGMA_INTERFACE
+#define PRAGMA_IMPLEMENTATION
+#define PRAGMA_IMPLEMENTATION_(arg)
+#define VALUE_OBJ_CLASS_SPEC : public _ValueObj
+
+// Formatting.
+#define FORMAT64_MODIFIER "I64"
+
+#define offset_of(klass,field) offsetof(klass,field)
diff --git a/src/share/vm/utilities/growableArray.cpp b/src/share/vm/utilities/growableArray.cpp
new file mode 100644
index 000000000..eeb259c53
--- /dev/null
+++ b/src/share/vm/utilities/growableArray.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1997-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+# include "incls/_precompiled.incl"
+# include "incls/_growableArray.cpp.incl"
+
+#ifdef ASSERT
+void GenericGrowableArray::set_nesting() {
+ if (on_stack()) {
+ _nesting = Thread::current()->resource_area()->nesting();
+ }
+}
+
+void GenericGrowableArray::check_nesting() {
+ // Check for insidious allocation bug: if a GrowableArray overflows, the
+ // grown array must be allocated under the same ResourceMark as the original.
+ // Otherwise, the _data array will be deallocated too early.
+ if (on_stack() &&
+ _nesting != Thread::current()->resource_area()->nesting()) {
+ fatal("allocation bug: GrowableArray could grow within nested ResourceMark");
+ }
+}
+#endif
+
+void* GenericGrowableArray::raw_allocate(int elementSize) {
+ if (on_stack()) {
+ return (void*)resource_allocate_bytes(elementSize * _max);
+ } else if (on_C_heap()) {
+ return (void*)AllocateHeap(elementSize * _max, "GrET in " __FILE__);
+ } else {
+ return _arena->Amalloc(elementSize * _max);
+ }
+}
diff --git a/src/share/vm/utilities/growableArray.hpp b/src/share/vm/utilities/growableArray.hpp
new file mode 100644
index 000000000..208b14518
--- /dev/null
+++ b/src/share/vm/utilities/growableArray.hpp
@@ -0,0 +1,331 @@
+/*
+ * Copyright 1997-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// A growable array.
+
+/*************************************************************************/
+/* */
+/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */
+/* */
+/* Should you use GrowableArrays to contain handles you must be certain */
+/* the the GrowableArray does not outlive the HandleMark that contains */
+/* the handles. Since GrowableArrays are typically resource allocated */
+/* the following is an example of INCORRECT CODE, */
+/* */
+/* ResourceMark rm; */
+/* GrowableArray<Handle>* arr = new GrowableArray<Handle>(size); */
+/* if (blah) { */
+/* while (...) { */
+/* HandleMark hm; */
+/* ... */
+/* Handle h(THREAD, some_oop); */
+/* arr->append(h); */
+/* } */
+/* } */
+/* if (arr->length() != 0 ) { */
+/* oop bad_oop = arr->at(0)(); // Handle is BAD HERE. */
+/* ... */
+/* } */
+/* */
+/* If the GrowableArrays you are creating is C_Heap allocated then it */
+/* hould not old handles since the handles could trivially try and */
+/* outlive their HandleMark. In some situations you might need to do */
+/* this and it would be legal but be very careful and see if you can do */
+/* the code in some other manner. */
+/* */
+/*************************************************************************/
+
+// To call default constructor the placement operator new() is used.
+// It should be empty (it only returns the passed void* pointer).
+// The definition of placement operator new(size_t, void*) in the <new>.
+
+#include <new>
+
+// Need the correct linkage to call qsort without warnings
+extern "C" {
+ typedef int (*_sort_Fn)(const void *, const void *);
+}
+
+class GenericGrowableArray : public ResourceObj {
+ protected:
+ int _len; // current length
+ int _max; // maximum length
+ Arena* _arena; // Indicates where allocation occurs:
+ // 0 means default ResourceArea
+ // 1 means on C heap
+ // otherwise, allocate in _arena
+#ifdef ASSERT
+ int _nesting; // resource area nesting at creation
+ void set_nesting();
+ void check_nesting();
+#else
+#define set_nesting();
+#define check_nesting();
+#endif
+
+ // Where are we going to allocate memory?
+ bool on_C_heap() { return _arena == (Arena*)1; }
+ bool on_stack () { return _arena == NULL; }
+ bool on_arena () { return _arena > (Arena*)1; }
+
+ // This GA will use the resource stack for storage if c_heap==false,
+ // Else it will use the C heap. Use clear_and_deallocate to avoid leaks.
+ GenericGrowableArray(int initial_size, int initial_len, bool c_heap) {
+ _len = initial_len;
+ _max = initial_size;
+ assert(_len >= 0 && _len <= _max, "initial_len too big");
+ _arena = (c_heap ? (Arena*)1 : NULL);
+ set_nesting();
+ assert(!c_heap || allocated_on_C_heap(), "growable array must be on C heap if elements are");
+ }
+
+ // This GA will use the given arena for storage.
+ // Consider using new(arena) GrowableArray<T> to allocate the header.
+ GenericGrowableArray(Arena* arena, int initial_size, int initial_len) {
+ _len = initial_len;
+ _max = initial_size;
+ assert(_len >= 0 && _len <= _max, "initial_len too big");
+ _arena = arena;
+ assert(on_arena(), "arena has taken on reserved value 0 or 1");
+ }
+
+ void* raw_allocate(int elementSize);
+};
+
+template<class E> class GrowableArray : public GenericGrowableArray {
+ private:
+ E* _data; // data array
+
+ void grow(int j);
+ void raw_at_put_grow(int i, const E& p, const E& fill);
+ void clear_and_deallocate();
+ public:
+ GrowableArray(int initial_size, bool C_heap = false) : GenericGrowableArray(initial_size, 0, C_heap) {
+ _data = (E*)raw_allocate(sizeof(E));
+ for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();
+ }
+
+ GrowableArray(int initial_size, int initial_len, const E& filler, bool C_heap = false) : GenericGrowableArray(initial_size, initial_len, C_heap) {
+ _data = (E*)raw_allocate(sizeof(E));
+ int i = 0;
+ for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler);
+ for (; i < _max; i++) ::new ((void*)&_data[i]) E();
+ }
+
+ GrowableArray(Arena* arena, int initial_size, int initial_len, const E& filler) : GenericGrowableArray(arena, initial_size, initial_len) {
+ _data = (E*)raw_allocate(sizeof(E));
+ int i = 0;
+ for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler);
+ for (; i < _max; i++) ::new ((void*)&_data[i]) E();
+ }
+
+ GrowableArray() : GenericGrowableArray(2, 0, false) {
+ _data = (E*)raw_allocate(sizeof(E));
+ ::new ((void*)&_data[0]) E();
+ ::new ((void*)&_data[1]) E();
+ }
+
+ // Does nothing for resource and arena objects
+ ~GrowableArray() { if (on_C_heap()) clear_and_deallocate(); }
+
+ void clear() { _len = 0; }
+ int length() const { return _len; }
+ void trunc_to(int l) { assert(l <= _len,"cannot increase length"); _len = l; }
+ bool is_empty() const { return _len == 0; }
+ bool is_nonempty() const { return _len != 0; }
+ bool is_full() const { return _len == _max; }
+ DEBUG_ONLY(E* data_addr() const { return _data; })
+
+ void print();
+
+ void append(const E& elem) {
+ check_nesting();
+ if (_len == _max) grow(_len);
+ _data[_len++] = elem;
+ }
+
+ void append_if_missing(const E& elem) {
+ if (!contains(elem)) append(elem);
+ }
+
+ E at(int i) const {
+ assert(0 <= i && i < _len, "illegal index");
+ return _data[i];
+ }
+
+ E* adr_at(int i) const {
+ assert(0 <= i && i < _len, "illegal index");
+ return &_data[i];
+ }
+
+ E first() const {
+ assert(_len > 0, "empty list");
+ return _data[0];
+ }
+
+ E top() const {
+ assert(_len > 0, "empty list");
+ return _data[_len-1];
+ }
+
+ void push(const E& elem) { append(elem); }
+
+ E pop() {
+ assert(_len > 0, "empty list");
+ return _data[--_len];
+ }
+
+ void at_put(int i, const E& elem) {
+ assert(0 <= i && i < _len, "illegal index");
+ _data[i] = elem;
+ }
+
+ E at_grow(int i, const E& fill = E()) {
+ assert(0 <= i, "negative index");
+ check_nesting();
+ if (i >= _len) {
+ if (i >= _max) grow(i);
+ for (int j = _len; j <= i; j++)
+ _data[j] = fill;
+ _len = i+1;
+ }
+ return _data[i];
+ }
+
+ void at_put_grow(int i, const E& elem, const E& fill = E()) {
+ assert(0 <= i, "negative index");
+ check_nesting();
+ raw_at_put_grow(i, elem, fill);
+ }
+
+ bool contains(const E& elem) const {
+ for (int i = 0; i < _len; i++) {
+ if (_data[i] == elem) return true;
+ }
+ return false;
+ }
+
+ int find(const E& elem) const {
+ for (int i = 0; i < _len; i++) {
+ if (_data[i] == elem) return i;
+ }
+ return -1;
+ }
+
+ int find(void* token, bool f(void*, E)) const {
+ for (int i = 0; i < _len; i++) {
+ if (f(token, _data[i])) return i;
+ }
+ return -1;
+ }
+
+ int find_at_end(void* token, bool f(void*, E)) const {
+ // start at the end of the array
+ for (int i = _len-1; i >= 0; i--) {
+ if (f(token, _data[i])) return i;
+ }
+ return -1;
+ }
+
+ void remove(const E& elem) {
+ for (int i = 0; i < _len; i++) {
+ if (_data[i] == elem) {
+ for (int j = i + 1; j < _len; j++) _data[j-1] = _data[j];
+ _len--;
+ return;
+ }
+ }
+ ShouldNotReachHere();
+ }
+
+ void remove_at(int index) {
+ assert(0 <= index && index < _len, "illegal index");
+ for (int j = index + 1; j < _len; j++) _data[j-1] = _data[j];
+ _len--;
+ }
+
+ void appendAll(const GrowableArray<E>* l) {
+ for (int i = 0; i < l->_len; i++) {
+ raw_at_put_grow(_len, l->_data[i], 0);
+ }
+ }
+
+ void sort(int f(E*,E*)) {
+ qsort(_data, length(), sizeof(E), (_sort_Fn)f);
+ }
+ // sort by fixed-stride sub arrays:
+ void sort(int f(E*,E*), int stride) {
+ qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f);
+ }
+};
+
+// Global GrowableArray methods (one instance in the library per each 'E' type).
+
+template<class E> void GrowableArray<E>::grow(int j) {
+ // grow the array by doubling its size (amortized growth)
+ int old_max = _max;
+ if (_max == 0) _max = 1; // prevent endless loop
+ while (j >= _max) _max = _max*2;
+ // j < _max
+ E* newData = (E*)raw_allocate(sizeof(E));
+ int i = 0;
+ for ( ; i < _len; i++) ::new ((void*)&newData[i]) E(_data[i]);
+ for ( ; i < _max; i++) ::new ((void*)&newData[i]) E();
+ for (i = 0; i < old_max; i++) _data[i].~E();
+ if (on_C_heap() && _data != NULL) {
+ FreeHeap(_data);
+ }
+ _data = newData;
+}
+
+template<class E> void GrowableArray<E>::raw_at_put_grow(int i, const E& p, const E& fill) {
+ if (i >= _len) {
+ if (i >= _max) grow(i);
+ for (int j = _len; j < i; j++)
+ _data[j] = fill;
+ _len = i+1;
+ }
+ _data[i] = p;
+}
+
+// This function clears and deallocate the data in the growable array that
+// has been allocated on the C heap. It's not public - called by the
+// destructor.
+template<class E> void GrowableArray<E>::clear_and_deallocate() {
+ assert(on_C_heap(),
+ "clear_and_deallocate should only be called when on C heap");
+ clear();
+ if (_data != NULL) {
+ for (int i = 0; i < _max; i++) _data[i].~E();
+ FreeHeap(_data);
+ _data = NULL;
+ }
+}
+
+template<class E> void GrowableArray<E>::print() {
+ tty->print("Growable Array " INTPTR_FORMAT, this);
+ tty->print(": length %ld (_max %ld) { ", _len, _max);
+ for (int i = 0; i < _len; i++) tty->print(INTPTR_FORMAT " ", *(intptr_t*)&(_data[i]));
+ tty->print("}\n");
+}
diff --git a/src/share/vm/utilities/hashtable.cpp b/src/share/vm/utilities/hashtable.cpp
new file mode 100644
index 000000000..58d675d00
--- /dev/null
+++ b/src/share/vm/utilities/hashtable.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2003-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_hashtable.cpp.incl"
+
+HS_DTRACE_PROBE_DECL4(hs_private, hashtable__new_entry,
+ void*, unsigned int, oop, void*);
+
+// This is a generic hashtable, designed to be used for the symbol
+// and string tables.
+//
+// It is implemented as an open hash table with a fixed number of buckets.
+//
+// %note:
+// - HashtableEntrys are allocated in blocks to reduce the space overhead.
+
+BasicHashtableEntry* BasicHashtable::new_entry(unsigned int hashValue) {
+ BasicHashtableEntry* entry;
+
+ if (_free_list) {
+ entry = _free_list;
+ _free_list = _free_list->next();
+ } else {
+ const int block_size = 500;
+ if (_first_free_entry == _end_block) {
+ int len = _entry_size * block_size;
+ _first_free_entry = NEW_C_HEAP_ARRAY(char, len);
+ _end_block = _first_free_entry + len;
+ }
+ entry = (BasicHashtableEntry*)_first_free_entry;
+ _first_free_entry += _entry_size;
+ }
+
+ entry->set_hash(hashValue);
+ return entry;
+}
+
+
+HashtableEntry* Hashtable::new_entry(unsigned int hashValue, oop obj) {
+ HashtableEntry* entry;
+
+ entry = (HashtableEntry*)BasicHashtable::new_entry(hashValue);
+ entry->set_literal(obj); // clears literal string field
+ HS_DTRACE_PROBE4(hs_private, hashtable__new_entry,
+ this, hashValue, obj, entry);
+ return entry;
+}
+
+
+// GC support
+
+void Hashtable::unlink(BoolObjectClosure* is_alive) {
+ // Readers of the table are unlocked, so we should only be removing
+ // entries at a safepoint.
+ assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+ for (int i = 0; i < table_size(); ++i) {
+ for (HashtableEntry** p = bucket_addr(i); *p != NULL; ) {
+ HashtableEntry* entry = *p;
+ if (entry->is_shared()) {
+ break;
+ }
+ assert(entry->literal() != NULL, "just checking");
+ if (is_alive->do_object_b(entry->literal())) {
+ p = entry->next_addr();
+ } else {
+ *p = entry->next();
+ free_entry(entry);
+ }
+ }
+ }
+}
+
+
+void Hashtable::oops_do(OopClosure* f) {
+ for (int i = 0; i < table_size(); ++i) {
+ HashtableEntry** p = bucket_addr(i);
+ HashtableEntry* entry = bucket(i);
+ while (entry != NULL) {
+ f->do_oop(entry->literal_addr());
+
+ // Did the closure remove the literal from the table?
+ if (entry->literal() == NULL) {
+ assert(!entry->is_shared(), "immutable hashtable entry?");
+ *p = entry->next();
+ free_entry(entry);
+ } else {
+ p = entry->next_addr();
+ }
+ entry = (HashtableEntry*)HashtableEntry::make_ptr(*p);
+ }
+ }
+}
+
+
+// Reverse the order of elements in the hash buckets.
+
+void BasicHashtable::reverse() {
+
+ for (int i = 0; i < _table_size; ++i) {
+ BasicHashtableEntry* new_list = NULL;
+ BasicHashtableEntry* p = bucket(i);
+ while (p != NULL) {
+ BasicHashtableEntry* next = p->next();
+ p->set_next(new_list);
+ new_list = p;
+ p = next;
+ }
+ *bucket_addr(i) = new_list;
+ }
+}
+
+
+// Copy the table to the shared space.
+
+void BasicHashtable::copy_table(char** top, char* end) {
+
+ // Dump the hash table entries.
+
+ intptr_t *plen = (intptr_t*)(*top);
+ *top += sizeof(*plen);
+
+ int i;
+ for (i = 0; i < _table_size; ++i) {
+ for (BasicHashtableEntry** p = _buckets[i].entry_addr();
+ *p != NULL;
+ p = (*p)->next_addr()) {
+ if (*top + entry_size() > end) {
+ warning("\nThe shared miscellaneous data space is not large "
+ "enough to \npreload requested classes. Use "
+ "-XX:SharedMiscDataSize= to increase \nthe initial "
+ "size of the miscellaneous data space.\n");
+ exit(2);
+ }
+ *p = (BasicHashtableEntry*)memcpy(*top, *p, entry_size());
+ *top += entry_size();
+ }
+ }
+ *plen = (char*)(*top) - (char*)plen - sizeof(*plen);
+
+ // Set the shared bit.
+
+ for (i = 0; i < _table_size; ++i) {
+ for (BasicHashtableEntry* p = bucket(i); p != NULL; p = p->next()) {
+ p->set_shared();
+ }
+ }
+}
+
+
+
+// Reverse the order of elements in the hash buckets.
+
+void Hashtable::reverse(void* boundary) {
+
+ for (int i = 0; i < table_size(); ++i) {
+ HashtableEntry* high_list = NULL;
+ HashtableEntry* low_list = NULL;
+ HashtableEntry* last_low_entry = NULL;
+ HashtableEntry* p = bucket(i);
+ while (p != NULL) {
+ HashtableEntry* next = p->next();
+ if ((void*)p->literal() >= boundary) {
+ p->set_next(high_list);
+ high_list = p;
+ } else {
+ p->set_next(low_list);
+ low_list = p;
+ if (last_low_entry == NULL) {
+ last_low_entry = p;
+ }
+ }
+ p = next;
+ }
+ if (low_list != NULL) {
+ *bucket_addr(i) = low_list;
+ last_low_entry->set_next(high_list);
+ } else {
+ *bucket_addr(i) = high_list;
+ }
+ }
+}
+
+
+// Dump the hash table buckets.
+
+void BasicHashtable::copy_buckets(char** top, char* end) {
+ intptr_t len = _table_size * sizeof(HashtableBucket);
+ *(intptr_t*)(*top) = len;
+ *top += sizeof(intptr_t);
+
+ *(intptr_t*)(*top) = _number_of_entries;
+ *top += sizeof(intptr_t);
+
+ if (*top + len > end) {
+ warning("\nThe shared miscellaneous data space is not large "
+ "enough to \npreload requested classes. Use "
+ "-XX:SharedMiscDataSize= to increase \nthe initial "
+ "size of the miscellaneous data space.\n");
+ exit(2);
+ }
+ _buckets = (HashtableBucket*)memcpy(*top, _buckets, len);
+ *top += len;
+}
+
+
+#ifndef PRODUCT
+
+void Hashtable::print() {
+ ResourceMark rm;
+
+ for (int i = 0; i < table_size(); i++) {
+ HashtableEntry* entry = bucket(i);
+ while(entry != NULL) {
+ tty->print("%d : ", i);
+ entry->literal()->print();
+ tty->cr();
+ entry = entry->next();
+ }
+ }
+}
+
+
+void BasicHashtable::verify() {
+ int count = 0;
+ for (int i = 0; i < table_size(); i++) {
+ for (BasicHashtableEntry* p = bucket(i); p != NULL; p = p->next()) {
+ ++count;
+ }
+ }
+ assert(count == number_of_entries(), "number of hashtable entries incorrect");
+}
+
+
+#endif // PRODUCT
+
+
+#ifdef ASSERT
+
+void BasicHashtable::verify_lookup_length(double load) {
+ if ((double)_lookup_length / (double)_lookup_count > load * 2.0) {
+ warning("Performance bug: SystemDictionary lookup_count=%d "
+ "lookup_length=%d average=%lf load=%f",
+ _lookup_count, _lookup_length,
+ (double) _lookup_length / _lookup_count, load);
+ }
+}
+
+#endif
diff --git a/src/share/vm/utilities/hashtable.hpp b/src/share/vm/utilities/hashtable.hpp
new file mode 100644
index 000000000..dd30d250d
--- /dev/null
+++ b/src/share/vm/utilities/hashtable.hpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2003-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// This is a generic hashtable, designed to be used for the symbol
+// and string tables.
+//
+// It is implemented as an open hash table with a fixed number of buckets.
+//
+// %note:
+// - TableEntrys are allocated in blocks to reduce the space overhead.
+
+
+
+class BasicHashtableEntry : public CHeapObj {
+ friend class VMStructs;
+private:
+ unsigned int _hash; // 32-bit hash for item
+
+ // Link to next element in the linked list for this bucket. EXCEPT
+ // bit 0 set indicates that this entry is shared and must not be
+ // unlinked from the table. Bit 0 is set during the dumping of the
+ // archive. Since shared entries are immutable, _next fields in the
+ // shared entries will not change. New entries will always be
+ // unshared and since pointers are align, bit 0 will always remain 0
+ // with no extra effort.
+ BasicHashtableEntry* _next;
+
+ // Windows IA64 compiler requires subclasses to be able to access these
+protected:
+ // Entry objects should not be created, they should be taken from the
+ // free list with BasicHashtable.new_entry().
+ BasicHashtableEntry() { ShouldNotReachHere(); }
+ // Entry objects should not be destroyed. They should be placed on
+ // the free list instead with BasicHashtable.free_entry().
+ ~BasicHashtableEntry() { ShouldNotReachHere(); }
+
+public:
+
+ unsigned int hash() const { return _hash; }
+ void set_hash(unsigned int hash) { _hash = hash; }
+ unsigned int* hash_addr() { return &_hash; }
+
+ static BasicHashtableEntry* make_ptr(BasicHashtableEntry* p) {
+ return (BasicHashtableEntry*)((intptr_t)p & -2);
+ }
+
+ BasicHashtableEntry* next() const {
+ return make_ptr(_next);
+ }
+
+ void set_next(BasicHashtableEntry* next) {
+ _next = next;
+ }
+
+ BasicHashtableEntry** next_addr() {
+ return &_next;
+ }
+
+ bool is_shared() const {
+ return ((intptr_t)_next & 1) != 0;
+ }
+
+ void set_shared() {
+ _next = (BasicHashtableEntry*)((intptr_t)_next | 1);
+ }
+};
+
+
+
+class HashtableEntry : public BasicHashtableEntry {
+ friend class VMStructs;
+private:
+ oop _literal; // ref to item in table.
+
+public:
+ // Literal
+ oop literal() const { return _literal; }
+ oop* literal_addr() { return &_literal; }
+ void set_literal(oop s) { _literal = s; }
+
+ HashtableEntry* next() const {
+ return (HashtableEntry*)BasicHashtableEntry::next();
+ }
+ HashtableEntry** next_addr() {
+ return (HashtableEntry**)BasicHashtableEntry::next_addr();
+ }
+};
+
+
+
+class HashtableBucket : public CHeapObj {
+ friend class VMStructs;
+private:
+ // Instance variable
+ BasicHashtableEntry* _entry;
+
+public:
+ // Accessing
+ void clear() { _entry = NULL; }
+
+ // The following methods use order access methods to avoid race
+ // conditions in multiprocessor systems.
+ BasicHashtableEntry* get_entry() const;
+ void set_entry(BasicHashtableEntry* l);
+
+ // The following method is not MT-safe and must be done under lock.
+ BasicHashtableEntry** entry_addr() { return &_entry; }
+};
+
+
+class BasicHashtable : public CHeapObj {
+ friend class VMStructs;
+
+public:
+ BasicHashtable(int table_size, int entry_size);
+ BasicHashtable(int table_size, int entry_size,
+ HashtableBucket* buckets, int number_of_entries);
+
+ // Sharing support.
+ void copy_buckets(char** top, char* end);
+ void copy_table(char** top, char* end);
+
+ // Bucket handling
+ int hash_to_index(unsigned int full_hash) {
+ int h = full_hash % _table_size;
+ assert(h >= 0 && h < _table_size, "Illegal hash value");
+ return h;
+ }
+
+ // Reverse the order of elements in each of the buckets.
+ void reverse();
+
+private:
+ // Instance variables
+ int _table_size;
+ HashtableBucket* _buckets;
+ BasicHashtableEntry* _free_list;
+ char* _first_free_entry;
+ char* _end_block;
+ int _entry_size;
+ int _number_of_entries;
+
+protected:
+
+#ifdef ASSERT
+ int _lookup_count;
+ int _lookup_length;
+ void verify_lookup_length(double load);
+#endif
+
+ void initialize(int table_size, int entry_size, int number_of_entries);
+
+ // Accessor
+ int entry_size() const { return _entry_size; }
+ int table_size() { return _table_size; }
+
+ // The following method is MT-safe and may be used with caution.
+ BasicHashtableEntry* bucket(int i);
+
+ // The following method is not MT-safe and must be done under lock.
+ BasicHashtableEntry** bucket_addr(int i) { return _buckets[i].entry_addr(); }
+
+ // Table entry management
+ BasicHashtableEntry* new_entry(unsigned int hashValue);
+
+public:
+ void set_entry(int index, BasicHashtableEntry* entry);
+
+ void add_entry(int index, BasicHashtableEntry* entry);
+
+ void free_entry(BasicHashtableEntry* entry);
+
+ int number_of_entries() { return _number_of_entries; }
+
+ void verify() PRODUCT_RETURN;
+};
+
+
+class Hashtable : public BasicHashtable {
+ friend class VMStructs;
+
+public:
+ Hashtable(int table_size, int entry_size)
+ : BasicHashtable(table_size, entry_size) { }
+
+ Hashtable(int table_size, int entry_size,
+ HashtableBucket* buckets, int number_of_entries)
+ : BasicHashtable(table_size, entry_size, buckets, number_of_entries) { }
+
+ // Invoke "f->do_oop" on the locations of all oops in the table.
+ void oops_do(OopClosure* f);
+
+ // Debugging
+ void print() PRODUCT_RETURN;
+
+ // GC support
+ // Delete pointers to otherwise-unreachable objects.
+ void unlink(BoolObjectClosure* cl);
+
+ // Reverse the order of elements in each of the buckets. Hashtable
+ // entries which refer to objects at a lower address than 'boundary'
+ // are separated from those which refer to objects at higher
+ // addresses, and appear first in the list.
+ void reverse(void* boundary = NULL);
+
+protected:
+
+ static unsigned int hash_symbol(const char* s, int len);
+
+ unsigned int compute_hash(symbolHandle name) {
+ return (unsigned int) name->identity_hash();
+ }
+
+ int index_for(symbolHandle name) {
+ return hash_to_index(compute_hash(name));
+ }
+
+ // Table entry management
+ HashtableEntry* new_entry(unsigned int hashValue, oop obj);
+
+ // The following method is MT-safe and may be used with caution.
+ HashtableEntry* bucket(int i) {
+ return (HashtableEntry*)BasicHashtable::bucket(i);
+ }
+
+ // The following method is not MT-safe and must be done under lock.
+ HashtableEntry** bucket_addr(int i) {
+ return (HashtableEntry**)BasicHashtable::bucket_addr(i);
+ }
+};
+
+
+// Verions of hashtable where two handles are used to compute the index.
+
+class TwoOopHashtable : public Hashtable {
+ friend class VMStructs;
+protected:
+ TwoOopHashtable(int table_size, int entry_size)
+ : Hashtable(table_size, entry_size) {}
+
+ TwoOopHashtable(int table_size, int entry_size, HashtableBucket* t,
+ int number_of_entries)
+ : Hashtable(table_size, entry_size, t, number_of_entries) {}
+
+public:
+ unsigned int compute_hash(symbolHandle name, Handle loader) {
+ // Be careful with identity_hash(), it can safepoint and if this
+ // were one expression, the compiler could choose to unhandle each
+ // oop before calling identity_hash() for either of them. If the first
+ // causes a GC, the next would fail.
+ unsigned int name_hash = name->identity_hash();
+ unsigned int loader_hash = loader.is_null() ? 0 : loader->identity_hash();
+ return name_hash ^ loader_hash;
+ }
+
+ int index_for(symbolHandle name, Handle loader) {
+ return hash_to_index(compute_hash(name, loader));
+ }
+};
diff --git a/src/share/vm/utilities/hashtable.inline.hpp b/src/share/vm/utilities/hashtable.inline.hpp
new file mode 100644
index 000000000..9d8980632
--- /dev/null
+++ b/src/share/vm/utilities/hashtable.inline.hpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// Inline function definitions for hashtable.hpp.
+
+
+// --------------------------------------------------------------------------
+// Hash function
+
+// We originally used hashpjw, but hash P(31) gives just as good results
+// and is slighly faster. We would like a hash function that looks at every
+// character, since package names have large common prefixes, and also because
+// hash_or_fail does error checking while iterating.
+
+// hash P(31) from Kernighan & Ritchie
+
+inline unsigned int Hashtable::hash_symbol(const char* s, int len) {
+ unsigned int h = 0;
+ while (len-- > 0) {
+ h = 31*h + (unsigned) *s;
+ s++;
+ }
+ return h;
+}
+
+
+// --------------------------------------------------------------------------
+
+// Initialize a table.
+
+inline BasicHashtable::BasicHashtable(int table_size, int entry_size) {
+ // Called on startup, no locking needed
+ initialize(table_size, entry_size, 0);
+ _buckets = NEW_C_HEAP_ARRAY(HashtableBucket, table_size);
+ for (int index = 0; index < _table_size; index++) {
+ _buckets[index].clear();
+ }
+}
+
+
+inline BasicHashtable::BasicHashtable(int table_size, int entry_size,
+ HashtableBucket* buckets,
+ int number_of_entries) {
+ // Called on startup, no locking needed
+ initialize(table_size, entry_size, number_of_entries);
+ _buckets = buckets;
+}
+
+
+inline void BasicHashtable::initialize(int table_size, int entry_size,
+ int number_of_entries) {
+ // Called on startup, no locking needed
+ _table_size = table_size;
+ _entry_size = entry_size;
+ _free_list = NULL;
+ _first_free_entry = NULL;
+ _end_block = NULL;
+ _number_of_entries = number_of_entries;
+#ifdef ASSERT
+ _lookup_count = 0;
+ _lookup_length = 0;
+#endif
+}
+
+
+// The following method is MT-safe and may be used with caution.
+inline BasicHashtableEntry* BasicHashtable::bucket(int i) {
+ return _buckets[i].get_entry();
+}
+
+
+inline void HashtableBucket::set_entry(BasicHashtableEntry* l) {
+ // Warning: Preserve store ordering. The SystemDictionary is read
+ // without locks. The new SystemDictionaryEntry must be
+ // complete before other threads can be allowed to see it
+ // via a store to _buckets[index].
+ OrderAccess::release_store_ptr(&_entry, l);
+}
+
+
+inline BasicHashtableEntry* HashtableBucket::get_entry() const {
+ // Warning: Preserve load ordering. The SystemDictionary is read
+ // without locks. The new SystemDictionaryEntry must be
+ // complete before other threads can be allowed to see it
+ // via a store to _buckets[index].
+ return (BasicHashtableEntry*) OrderAccess::load_ptr_acquire(&_entry);
+}
+
+
+inline void BasicHashtable::set_entry(int index, BasicHashtableEntry* entry) {
+ _buckets[index].set_entry(entry);
+}
+
+
+inline void BasicHashtable::add_entry(int index, BasicHashtableEntry* entry) {
+ entry->set_next(bucket(index));
+ _buckets[index].set_entry(entry);
+ ++_number_of_entries;
+}
+
+inline void BasicHashtable::free_entry(BasicHashtableEntry* entry) {
+ entry->set_next(_free_list);
+ _free_list = entry;
+ --_number_of_entries;
+}
diff --git a/src/share/vm/utilities/histogram.cpp b/src/share/vm/utilities/histogram.cpp
new file mode 100644
index 000000000..f60269f1c
--- /dev/null
+++ b/src/share/vm/utilities/histogram.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright 1998-2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_histogram.cpp.incl"
+
+#ifdef ASSERT
+
+////////////////// HistogramElement ////////////////////////
+
+HistogramElement::HistogramElement() {
+ _count = 0;
+}
+
+int HistogramElement::count() {
+ return _count;
+}
+
+const char* HistogramElement::name() {
+ return _name;
+}
+
+void HistogramElement::increment_count() {
+ // We can't use the accessor :-(.
+ Atomic::inc(&_count);
+}
+
+int HistogramElement::compare(HistogramElement* e1,HistogramElement* e2) {
+ if(e1->count() > e2->count()) {
+ return -1;
+ } else if(e1->count() < e2->count()) {
+ return 1;
+ }
+ return 0;
+}
+
+void HistogramElement::print_on(outputStream* st) const {
+ st->print("%10d ",((HistogramElement*)this)->count());
+ st->print_cr("%s",((HistogramElement*)this)->name());
+}
+
+////////////////// Histogram ////////////////////////
+
+int Histogram::sort_helper(HistogramElement** e1, HistogramElement** e2) {
+ return (*e1)->compare(*e1,*e2);
+}
+
+Histogram::Histogram(const char* title,int estimatedCount) {
+ _title = title;
+ _elements = new (ResourceObj::C_HEAP) GrowableArray<HistogramElement*>(estimatedCount,true);
+}
+
+void Histogram::add_element(HistogramElement* element) {
+ // Note, we need to add locking !
+ elements()->append(element);
+}
+
+void Histogram::print_header(outputStream* st) {
+ st->print_cr("%s",title());
+ st->print_cr("--------------------------------------------------");
+}
+
+void Histogram::print_elements(outputStream* st) {
+ elements()->sort(Histogram::sort_helper);
+ jint total = 0;
+ for(int i=0; i < elements()->length(); i++) {
+ elements()->at(i)->print();
+ total += elements()->at(i)->count();
+ }
+ st->print("%10d ", total);
+ st->print_cr("Total");
+}
+
+void Histogram::print_on(outputStream* st) const {
+ ((Histogram*)this)->print_header(st);
+ ((Histogram*)this)->print_elements(st);
+}
+
+#endif
diff --git a/src/share/vm/utilities/histogram.hpp b/src/share/vm/utilities/histogram.hpp
new file mode 100644
index 000000000..0e15d8207
--- /dev/null
+++ b/src/share/vm/utilities/histogram.hpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 1998-2000 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// This class provides a framework for collecting various statistics.
+// The current implementation is oriented towards counting invocations
+// of various types, but that can be easily changed.
+//
+// To use it, you need to declare a Histogram*, and a subtype of
+// HistogramElement:
+//
+// HistogramElement* MyHistogram;
+//
+// class MyHistogramElement : public HistogramElement {
+// public:
+// MyHistogramElement(char* name);
+// };
+//
+// MyHistogramElement::MyHistogramElement(char* elementName) {
+// _name = elementName;
+//
+// if(MyHistogram == NULL)
+// MyHistogram = new Histogram("My Call Counts",100);
+//
+// MyHistogram->add_element(this);
+// }
+//
+// #define MyCountWrapper(arg) static MyHistogramElement* e = new MyHistogramElement(arg); e->increment_count()
+//
+// This gives you a simple way to count invocations of specfic functions:
+//
+// void a_function_that_is_being_counted() {
+// MyCountWrapper("FunctionName");
+// ...
+// }
+//
+// To print the results, invoke print() on your Histogram*.
+
+#ifdef ASSERT
+
+class HistogramElement : public CHeapObj {
+ protected:
+ jint _count;
+ const char* _name;
+
+ public:
+ HistogramElement();
+ virtual int count();
+ virtual const char* name();
+ virtual void increment_count();
+ void print_on(outputStream* st) const;
+ virtual int compare(HistogramElement* e1,HistogramElement* e2);
+};
+
+class Histogram : public CHeapObj {
+ protected:
+ GrowableArray<HistogramElement*>* _elements;
+ GrowableArray<HistogramElement*>* elements() { return _elements; }
+ const char* _title;
+ const char* title() { return _title; }
+ static int sort_helper(HistogramElement** e1,HistogramElement** e2);
+ virtual void print_header(outputStream* st);
+ virtual void print_elements(outputStream* st);
+
+ public:
+ Histogram(const char* title,int estimatedSize);
+ virtual void add_element(HistogramElement* element);
+ void print_on(outputStream* st) const;
+};
+
+#endif
diff --git a/src/share/vm/utilities/macros.hpp b/src/share/vm/utilities/macros.hpp
new file mode 100644
index 000000000..2f495efac
--- /dev/null
+++ b/src/share/vm/utilities/macros.hpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// Use this to mark code that needs to be cleaned up (for development only)
+#define NEEDS_CLEANUP
+
+// Makes a string of the argument (which is not macro-expanded)
+#define STR(a) #a
+
+// Makes a string of the macro expansion of a
+#define XSTR(a) STR(a)
+
+// KERNEL variant
+#ifdef KERNEL
+#define COMPILER1
+#define SERIALGC
+
+#define JVMTI_KERNEL
+#define FPROF_KERNEL
+#define VM_STRUCTS_KERNEL
+#define JNICHECK_KERNEL
+#define SERVICES_KERNEL
+
+#define KERNEL_RETURN {}
+#define KERNEL_RETURN_(code) { code }
+
+#else // KERNEL
+
+#define KERNEL_RETURN /* next token must be ; */
+#define KERNEL_RETURN_(code) /* next token must be ; */
+
+#endif // KERNEL
+
+// COMPILER1 variant
+#ifdef COMPILER1
+#ifdef COMPILER2
+ #define TIERED
+#endif
+#define COMPILER1_PRESENT(code) code
+#else // COMPILER1
+#define COMPILER1_PRESENT(code)
+#endif // COMPILER1
+
+// COMPILER2 variant
+#ifdef COMPILER2
+#define COMPILER2_PRESENT(code) code
+#else // COMPILER2
+#define COMPILER2_PRESENT(code)
+#endif // COMPILER2
+
+
+// PRODUCT variant
+#ifdef PRODUCT
+#define PRODUCT_ONLY(code) code
+#define NOT_PRODUCT(code)
+#define PRODUCT_RETURN {}
+#define PRODUCT_RETURN0 { return 0; }
+#define PRODUCT_RETURN_(code) { code }
+#else // PRODUCT
+#define PRODUCT_ONLY(code)
+#define NOT_PRODUCT(code) code
+#define PRODUCT_RETURN /*next token must be ;*/
+#define PRODUCT_RETURN0 /*next token must be ;*/
+#define PRODUCT_RETURN_(code) /*next token must be ;*/
+#endif // PRODUCT
+
+#ifdef CHECK_UNHANDLED_OOPS
+#define CHECK_UNHANDLED_OOPS_ONLY(code) code
+#define NOT_CHECK_UNHANDLED_OOPS(code)
+#else
+#define CHECK_UNHANDLED_OOPS_ONLY(code)
+#define NOT_CHECK_UNHANDLED_OOPS(code) code
+#endif // CHECK_UNHANDLED_OOPS
+
+#ifdef CC_INTERP
+#define CC_INTERP_ONLY(code) code
+#define NOT_CC_INTERP(code)
+#else
+#define CC_INTERP_ONLY(code)
+#define NOT_CC_INTERP(code) code
+#endif // CC_INTERP
+
+#ifdef ASSERT
+#define DEBUG_ONLY(code) code
+#define NOT_DEBUG(code)
+// Historical.
+#define debug_only(code) code
+#else // ASSERT
+#define DEBUG_ONLY(code)
+#define NOT_DEBUG(code) code
+#define debug_only(code)
+#endif // ASSERT
+
+#ifdef _LP64
+#define LP64_ONLY(code) code
+#define NOT_LP64(code)
+#else // !_LP64
+#define LP64_ONLY(code)
+#define NOT_LP64(code) code
+#endif // _LP64
+
+#ifdef LINUX
+#define LINUX_ONLY(code) code
+#define NOT_LINUX(code)
+#else
+#define LINUX_ONLY(code)
+#define NOT_LINUX(code) code
+#endif
+
+#ifdef SOLARIS
+#define SOLARIS_ONLY(code) code
+#define NOT_SOLARIS(code)
+#else
+#define SOLARIS_ONLY(code)
+#define NOT_SOLARIS(code) code
+#endif
+
+#ifdef _WINDOWS
+#define WINDOWS_ONLY(code) code
+#define NOT_WINDOWS(code)
+#else
+#define WINDOWS_ONLY(code)
+#define NOT_WINDOWS(code) code
+#endif
+
+#ifdef IA32
+#define IA32_ONLY(code) code
+#define NOT_IA32(code)
+#else
+#define IA32_ONLY(code)
+#define NOT_IA32(code) code
+#endif
+
+#ifdef IA64
+#define IA64_ONLY(code) code
+#define NOT_IA64(code)
+#else
+#define IA64_ONLY(code)
+#define NOT_IA64(code) code
+#endif
+
+#ifdef AMD64
+#define AMD64_ONLY(code) code
+#define NOT_AMD64(code)
+#else
+#define AMD64_ONLY(code)
+#define NOT_AMD64(code) code
+#endif
+
+#ifdef SPARC
+#define SPARC_ONLY(code) code
+#define NOT_SPARC(code)
+#else
+#define SPARC_ONLY(code)
+#define NOT_SPARC(code) code
+#endif
+
+#define FIX_THIS(code) report_assertion_failure("FIX_THIS",__FILE__, __LINE__, "")
+
+#define define_pd_global(type, name, value) const type pd_##name = value;
diff --git a/src/share/vm/utilities/ostream.cpp b/src/share/vm/utilities/ostream.cpp
new file mode 100644
index 000000000..d5ad211fc
--- /dev/null
+++ b/src/share/vm/utilities/ostream.cpp
@@ -0,0 +1,850 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_ostream.cpp.incl"
+
+extern "C" void jio_print(const char* s); // Declarationtion of jvm method
+
+outputStream::outputStream(int width) {
+ _width = width;
+ _position = 0;
+ _newlines = 0;
+ _precount = 0;
+ _indentation = 0;
+}
+
+outputStream::outputStream(int width, bool has_time_stamps) {
+ _width = width;
+ _position = 0;
+ _newlines = 0;
+ _precount = 0;
+ _indentation = 0;
+ if (has_time_stamps) _stamp.update();
+}
+
+void outputStream::update_position(const char* s, size_t len) {
+ for (size_t i = 0; i < len; i++) {
+ char ch = s[i];
+ if (ch == '\n') {
+ _newlines += 1;
+ _precount += _position + 1;
+ _position = 0;
+ } else if (ch == '\t') {
+ _position += 8;
+ _precount -= 7; // invariant: _precount + _position == total count
+ } else {
+ _position += 1;
+ }
+ }
+}
+
+// Execute a vsprintf, using the given buffer if necessary.
+// Return a pointer to the formatted string.
+const char* outputStream::do_vsnprintf(char* buffer, size_t buflen,
+ const char* format, va_list ap,
+ bool add_cr,
+ size_t& result_len) {
+ const char* result;
+ if (add_cr) buflen--;
+ if (!strchr(format, '%')) {
+ // constant format string
+ result = format;
+ result_len = strlen(result);
+ if (add_cr && result_len >= buflen) result_len = buflen-1; // truncate
+ } else if (format[0] == '%' && format[1] == 's' && format[2] == '\0') {
+ // trivial copy-through format string
+ result = va_arg(ap, const char*);
+ result_len = strlen(result);
+ if (add_cr && result_len >= buflen) result_len = buflen-1; // truncate
+ } else if (vsnprintf(buffer, buflen, format, ap) >= 0) {
+ result = buffer;
+ result_len = strlen(result);
+ } else {
+ DEBUG_ONLY(warning("increase O_BUFLEN in ostream.hpp -- output truncated");)
+ result = buffer;
+ result_len = buflen - 1;
+ buffer[result_len] = 0;
+ }
+ if (add_cr) {
+ if (result != buffer) {
+ strncpy(buffer, result, buflen);
+ result = buffer;
+ }
+ buffer[result_len++] = '\n';
+ buffer[result_len] = 0;
+ }
+ return result;
+}
+
+void outputStream::print(const char* format, ...) {
+ char buffer[O_BUFLEN];
+ va_list ap;
+ va_start(ap, format);
+ size_t len;
+ const char* str = do_vsnprintf(buffer, O_BUFLEN, format, ap, false, len);
+ write(str, len);
+ va_end(ap);
+}
+
+void outputStream::print_cr(const char* format, ...) {
+ char buffer[O_BUFLEN];
+ va_list ap;
+ va_start(ap, format);
+ size_t len;
+ const char* str = do_vsnprintf(buffer, O_BUFLEN, format, ap, true, len);
+ write(str, len);
+ va_end(ap);
+}
+
+void outputStream::vprint(const char *format, va_list argptr) {
+ char buffer[O_BUFLEN];
+ size_t len;
+ const char* str = do_vsnprintf(buffer, O_BUFLEN, format, argptr, false, len);
+ write(str, len);
+}
+
+void outputStream::vprint_cr(const char* format, va_list argptr) {
+ char buffer[O_BUFLEN];
+ size_t len;
+ const char* str = do_vsnprintf(buffer, O_BUFLEN, format, argptr, true, len);
+ write(str, len);
+}
+
+void outputStream::fill_to(int col) {
+ while (position() < col) sp();
+}
+
+void outputStream::put(char ch) {
+ assert(ch != 0, "please fix call site");
+ char buf[] = { ch, '\0' };
+ write(buf, 1);
+}
+
+void outputStream::sp() {
+ this->write(" ", 1);
+}
+
+void outputStream::cr() {
+ this->write("\n", 1);
+}
+
+void outputStream::stamp() {
+ if (! _stamp.is_updated()) {
+ _stamp.update(); // start at 0 on first call to stamp()
+ }
+
+ // outputStream::stamp() may get called by ostream_abort(), use snprintf
+ // to avoid allocating large stack buffer in print().
+ char buf[40];
+ jio_snprintf(buf, sizeof(buf), "%.3f", _stamp.seconds());
+ print_raw(buf);
+}
+
+void outputStream::date_stamp(bool guard,
+ const char* prefix,
+ const char* suffix) {
+ if (!guard) {
+ return;
+ }
+ print_raw(prefix);
+ static const char error_time[] = "yyyy-mm-ddThh:mm:ss.mmm+zzzz";
+ static const int buffer_length = 32;
+ char buffer[buffer_length];
+ const char* iso8601_result = os::iso8601_time(buffer, buffer_length);
+ if (iso8601_result != NULL) {
+ print_raw(buffer);
+ } else {
+ print_raw(error_time);
+ }
+ print_raw(suffix);
+ return;
+}
+
+void outputStream::indent() {
+ while (_position < _indentation) sp();
+}
+
+void outputStream::print_jlong(jlong value) {
+ // N.B. Same as INT64_FORMAT
+ print(os::jlong_format_specifier(), value);
+}
+
+void outputStream::print_julong(julong value) {
+ // N.B. Same as UINT64_FORMAT
+ print(os::julong_format_specifier(), value);
+}
+
+stringStream::stringStream(size_t initial_size) : outputStream() {
+ buffer_length = initial_size;
+ buffer = NEW_RESOURCE_ARRAY(char, buffer_length);
+ buffer_pos = 0;
+ buffer_fixed = false;
+}
+
+// useful for output to fixed chunks of memory, such as performance counters
+stringStream::stringStream(char* fixed_buffer, size_t fixed_buffer_size) : outputStream() {
+ buffer_length = fixed_buffer_size;
+ buffer = fixed_buffer;
+ buffer_pos = 0;
+ buffer_fixed = true;
+}
+
+void stringStream::write(const char* s, size_t len) {
+ size_t write_len = len; // number of non-null bytes to write
+ size_t end = buffer_pos + len + 1; // position after write and final '\0'
+ if (end > buffer_length) {
+ if (buffer_fixed) {
+ // if buffer cannot resize, silently truncate
+ end = buffer_length;
+ write_len = end - buffer_pos - 1; // leave room for the final '\0'
+ } else {
+ // For small overruns, double the buffer. For larger ones,
+ // increase to the requested size.
+ if (end < buffer_length * 2) {
+ end = buffer_length * 2;
+ }
+ char* oldbuf = buffer;
+ buffer = NEW_RESOURCE_ARRAY(char, end);
+ strncpy(buffer, oldbuf, buffer_pos);
+ buffer_length = end;
+ }
+ }
+ // invariant: buffer is always null-terminated
+ guarantee(buffer_pos + write_len + 1 <= buffer_length, "stringStream oob");
+ buffer[buffer_pos + write_len] = 0;
+ strncpy(buffer + buffer_pos, s, write_len);
+ buffer_pos += write_len;
+
+ // Note that the following does not depend on write_len.
+ // This means that position and count get updated
+ // even when overflow occurs.
+ update_position(s, len);
+}
+
+char* stringStream::as_string() {
+ char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos+1);
+ strncpy(copy, buffer, buffer_pos);
+ copy[buffer_pos] = 0; // terminating null
+ return copy;
+}
+
+stringStream::~stringStream() {}
+
+xmlStream* xtty;
+outputStream* tty;
+outputStream* gclog_or_tty;
+extern Mutex* tty_lock;
+
+fileStream::fileStream(const char* file_name) {
+ _file = fopen(file_name, "w");
+ _need_close = true;
+}
+
+void fileStream::write(const char* s, size_t len) {
+ if (_file != NULL) fwrite(s, 1, len, _file);
+ update_position(s, len);
+}
+
+fileStream::~fileStream() {
+ if (_file != NULL) {
+ if (_need_close) fclose(_file);
+ _file = NULL;
+ }
+}
+
+void fileStream::flush() {
+ fflush(_file);
+}
+
+fdStream::fdStream(const char* file_name) {
+ _fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ _need_close = true;
+}
+
+fdStream::~fdStream() {
+ if (_fd != -1) {
+ if (_need_close) close(_fd);
+ _fd = -1;
+ }
+}
+
+void fdStream::write(const char* s, size_t len) {
+ if (_fd != -1) ::write(_fd, s, (int)len);
+ update_position(s, len);
+}
+
+defaultStream* defaultStream::instance = NULL;
+int defaultStream::_output_fd = 1;
+int defaultStream::_error_fd = 2;
+FILE* defaultStream::_output_stream = stdout;
+FILE* defaultStream::_error_stream = stderr;
+
+#define LOG_MAJOR_VERSION 160
+#define LOG_MINOR_VERSION 1
+
+void defaultStream::init() {
+ _inited = true;
+ if (LogVMOutput || LogCompilation) {
+ init_log();
+ }
+}
+
+bool defaultStream::has_log_file() {
+ // lazily create log file (at startup, LogVMOutput is false even
+ // if +LogVMOutput is used, because the flags haven't been parsed yet)
+ // For safer printing during fatal error handling, do not init logfile
+ // if a VM error has been reported.
+ if (!_inited && !is_error_reported()) init();
+ return _log_file != NULL;
+}
+
+static const char* make_log_name(const char* log_name, const char* force_directory, char* buf) {
+ const char* basename = log_name;
+ char file_sep = os::file_separator()[0];
+ const char* cp;
+ for (cp = log_name; *cp != '\0'; cp++) {
+ if (*cp == '/' || *cp == file_sep) {
+ basename = cp+1;
+ }
+ }
+ const char* nametail = log_name;
+
+ strcpy(buf, "");
+ if (force_directory != NULL) {
+ strcat(buf, force_directory);
+ strcat(buf, os::file_separator());
+ nametail = basename; // completely skip directory prefix
+ }
+
+ const char* star = strchr(basename, '*');
+ int star_pos = (star == NULL) ? -1 : (star - nametail);
+
+ if (star_pos >= 0) {
+ // convert foo*bar.log to foo123bar.log
+ int buf_pos = (int) strlen(buf);
+ strncpy(&buf[buf_pos], nametail, star_pos);
+ sprintf(&buf[buf_pos + star_pos], "%u", os::current_process_id());
+ nametail += star_pos + 1; // skip prefix and star
+ }
+
+ strcat(buf, nametail); // append rest of name, or all of name
+ return buf;
+}
+
+void defaultStream::init_log() {
+ // %%% Need a MutexLocker?
+ const char* log_name = LogFile != NULL ? LogFile : "hotspot.log";
+ char buf[O_BUFLEN*2];
+ const char* try_name = make_log_name(log_name, NULL, buf);
+ fileStream* file = new(ResourceObj::C_HEAP) fileStream(try_name);
+ if (!file->is_open()) {
+ // Try again to open the file.
+ char warnbuf[O_BUFLEN*2];
+ sprintf(warnbuf, "Warning: Cannot open log file: %s\n", try_name);
+ // Note: This feature is for maintainer use only. No need for L10N.
+ jio_print(warnbuf);
+ try_name = make_log_name("hs_pid*.log", os::get_temp_directory(), buf);
+ sprintf(warnbuf, "Warning: Forcing option -XX:LogFile=%s\n", try_name);
+ jio_print(warnbuf);
+ delete file;
+ file = new(ResourceObj::C_HEAP) fileStream(try_name);
+ }
+ if (file->is_open()) {
+ _log_file = file;
+ xmlStream* xs = new(ResourceObj::C_HEAP) xmlStream(file);
+ _outer_xmlStream = xs;
+ if (this == tty) xtty = xs;
+ // Write XML header.
+ xs->print_cr("<?xml version='1.0' encoding='UTF-8'?>");
+ // (For now, don't bother to issue a DTD for this private format.)
+ jlong time_ms = os::javaTimeMillis() - tty->time_stamp().milliseconds();
+ // %%% Should be: jlong time_ms = os::start_time_milliseconds(), if
+ // we ever get round to introduce that method on the os class
+ xs->head("hotspot_log version='%d %d'"
+ " process='%d' time_ms='"INT64_FORMAT"'",
+ LOG_MAJOR_VERSION, LOG_MINOR_VERSION,
+ os::current_process_id(), time_ms);
+ // Write VM version header immediately.
+ xs->head("vm_version");
+ xs->head("name"); xs->text("%s", VM_Version::vm_name()); xs->cr();
+ xs->tail("name");
+ xs->head("release"); xs->text("%s", VM_Version::vm_release()); xs->cr();
+ xs->tail("release");
+ xs->head("info"); xs->text("%s", VM_Version::internal_vm_info_string()); xs->cr();
+ xs->tail("info");
+ xs->tail("vm_version");
+ // Record information about the command-line invocation.
+ xs->head("vm_arguments"); // Cf. Arguments::print_on()
+ if (Arguments::num_jvm_flags() > 0) {
+ xs->head("flags");
+ Arguments::print_jvm_flags_on(xs->text());
+ xs->tail("flags");
+ }
+ if (Arguments::num_jvm_args() > 0) {
+ xs->head("args");
+ Arguments::print_jvm_args_on(xs->text());
+ xs->tail("args");
+ }
+ if (Arguments::java_command() != NULL) {
+ xs->head("command"); xs->text()->print_cr("%s", Arguments::java_command());
+ xs->tail("command");
+ }
+ if (Arguments::sun_java_launcher() != NULL) {
+ xs->head("launcher"); xs->text()->print_cr("%s", Arguments::sun_java_launcher());
+ xs->tail("launcher");
+ }
+ if (Arguments::system_properties() != NULL) {
+ xs->head("properties");
+ // Print it as a java-style property list.
+ // System properties don't generally contain newlines, so don't bother with unparsing.
+ for (SystemProperty* p = Arguments::system_properties(); p != NULL; p = p->next()) {
+ xs->text()->print_cr("%s=%s", p->key(), p->value());
+ }
+ xs->tail("properties");
+ }
+ xs->tail("vm_arguments");
+ // tty output per se is grouped under the <tty>...</tty> element.
+ xs->head("tty");
+ // All further non-markup text gets copied to the tty:
+ xs->_text = this; // requires friend declaration!
+ } else {
+ delete(file);
+ // and leave xtty as NULL
+ LogVMOutput = false;
+ DisplayVMOutput = true;
+ LogCompilation = false;
+ }
+}
+
+// finish_log() is called during normal VM shutdown. finish_log_on_error() is
+// called by ostream_abort() after a fatal error.
+//
+void defaultStream::finish_log() {
+ xmlStream* xs = _outer_xmlStream;
+ xs->done("tty");
+
+ // Other log forks are appended here, at the End of Time:
+ CompileLog::finish_log(xs->out()); // write compile logging, if any, now
+
+ xs->done("hotspot_log");
+ xs->flush();
+
+ fileStream* file = _log_file;
+ _log_file = NULL;
+
+ delete _outer_xmlStream;
+ _outer_xmlStream = NULL;
+
+ file->flush();
+ delete file;
+}
+
+void defaultStream::finish_log_on_error(char *buf, int buflen) {
+ xmlStream* xs = _outer_xmlStream;
+
+ if (xs && xs->out()) {
+
+ xs->done_raw("tty");
+
+ // Other log forks are appended here, at the End of Time:
+ CompileLog::finish_log_on_error(xs->out(), buf, buflen); // write compile logging, if any, now
+
+ xs->done_raw("hotspot_log");
+ xs->flush();
+
+ fileStream* file = _log_file;
+ _log_file = NULL;
+ _outer_xmlStream = NULL;
+
+ if (file) {
+ file->flush();
+
+ // Can't delete or close the file because delete and fclose aren't
+ // async-safe. We are about to die, so leave it to the kernel.
+ // delete file;
+ }
+ }
+}
+
+intx defaultStream::hold(intx writer_id) {
+ bool has_log = has_log_file(); // check before locking
+ if (// impossible, but who knows?
+ writer_id == NO_WRITER ||
+
+ // bootstrap problem
+ tty_lock == NULL ||
+
+ // can't grab a lock or call Thread::current() if TLS isn't initialized
+ ThreadLocalStorage::thread() == NULL ||
+
+ // developer hook
+ !SerializeVMOutput ||
+
+ // VM already unhealthy
+ is_error_reported() ||
+
+ // safepoint == global lock (for VM only)
+ (SafepointSynchronize::is_synchronizing() &&
+ Thread::current()->is_VM_thread())
+ ) {
+ // do not attempt to lock unless we know the thread and the VM is healthy
+ return NO_WRITER;
+ }
+ if (_writer == writer_id) {
+ // already held, no need to re-grab the lock
+ return NO_WRITER;
+ }
+ tty_lock->lock_without_safepoint_check();
+ // got the lock
+ if (writer_id != _last_writer) {
+ if (has_log) {
+ _log_file->bol();
+ // output a hint where this output is coming from:
+ _log_file->print_cr("<writer thread='"INTX_FORMAT"'/>", writer_id);
+ }
+ _last_writer = writer_id;
+ }
+ _writer = writer_id;
+ return writer_id;
+}
+
+void defaultStream::release(intx holder) {
+ if (holder == NO_WRITER) {
+ // nothing to release: either a recursive lock, or we scribbled (too bad)
+ return;
+ }
+ if (_writer != holder) {
+ return; // already unlocked, perhaps via break_tty_lock_for_safepoint
+ }
+ _writer = NO_WRITER;
+ tty_lock->unlock();
+}
+
+
+// Yuck: jio_print does not accept char*/len.
+static void call_jio_print(const char* s, size_t len) {
+ char buffer[O_BUFLEN+100];
+ if (len > sizeof(buffer)-1) {
+ warning("increase O_BUFLEN in ostream.cpp -- output truncated");
+ len = sizeof(buffer)-1;
+ }
+ strncpy(buffer, s, len);
+ buffer[len] = '\0';
+ jio_print(buffer);
+}
+
+
+void defaultStream::write(const char* s, size_t len) {
+ intx thread_id = os::current_thread_id();
+ intx holder = hold(thread_id);
+
+ if (DisplayVMOutput &&
+ (_outer_xmlStream == NULL || !_outer_xmlStream->inside_attrs())) {
+ // print to output stream. It can be redirected by a vfprintf hook
+ if (s[len] == '\0') {
+ jio_print(s);
+ } else {
+ call_jio_print(s, len);
+ }
+ }
+
+ // print to log file
+ if (has_log_file()) {
+ int nl0 = _newlines;
+ xmlTextStream::write(s, len);
+ // flush the log file too, if there were any newlines
+ if (nl0 != _newlines){
+ flush();
+ }
+ } else {
+ update_position(s, len);
+ }
+
+ release(holder);
+}
+
+intx ttyLocker::hold_tty() {
+ if (defaultStream::instance == NULL) return defaultStream::NO_WRITER;
+ intx thread_id = os::current_thread_id();
+ return defaultStream::instance->hold(thread_id);
+}
+
+void ttyLocker::release_tty(intx holder) {
+ if (holder == defaultStream::NO_WRITER) return;
+ defaultStream::instance->release(holder);
+}
+
+void ttyLocker::break_tty_lock_for_safepoint(intx holder) {
+ if (defaultStream::instance != NULL &&
+ defaultStream::instance->writer() == holder) {
+ if (xtty != NULL) {
+ xtty->print_cr("<!-- safepoint while printing -->");
+ }
+ defaultStream::instance->release(holder);
+ }
+ // (else there was no lock to break)
+}
+
+void ostream_init() {
+ if (defaultStream::instance == NULL) {
+ defaultStream::instance = new(ResourceObj::C_HEAP) defaultStream();
+ tty = defaultStream::instance;
+
+ // We want to ensure that time stamps in GC logs consider time 0
+ // the time when the JVM is initialized, not the first time we ask
+ // for a time stamp. So, here, we explicitly update the time stamp
+ // of tty.
+ tty->time_stamp().update_to(1);
+ }
+}
+
+void ostream_init_log() {
+ // For -Xloggc:<file> option - called in runtime/thread.cpp
+ // Note : this must be called AFTER ostream_init()
+
+ gclog_or_tty = tty; // default to tty
+ if (Arguments::gc_log_filename() != NULL) {
+ fileStream * gclog = new(ResourceObj::C_HEAP)
+ fileStream(Arguments::gc_log_filename());
+ if (gclog->is_open()) {
+ // now we update the time stamp of the GC log to be synced up
+ // with tty.
+ gclog->time_stamp().update_to(tty->time_stamp().ticks());
+ gclog_or_tty = gclog;
+ }
+ }
+
+ // If we haven't lazily initialized the logfile yet, do it now,
+ // to avoid the possibility of lazy initialization during a VM
+ // crash, which can affect the stability of the fatal error handler.
+ defaultStream::instance->has_log_file();
+}
+
+// ostream_exit() is called during normal VM exit to finish log files, flush
+// output and free resource.
+void ostream_exit() {
+ static bool ostream_exit_called = false;
+ if (ostream_exit_called) return;
+ ostream_exit_called = true;
+ if (gclog_or_tty != tty) {
+ delete gclog_or_tty;
+ }
+ {
+ // we temporaly disable PrintMallocFree here
+ // as otherwise it'll lead to using of almost deleted
+ // tty or defaultStream::instance in logging facility
+ // of HeapFree(), see 6391258
+ DEBUG_ONLY(FlagSetting fs(PrintMallocFree, false);)
+ if (tty != defaultStream::instance) {
+ delete tty;
+ }
+ if (defaultStream::instance != NULL) {
+ delete defaultStream::instance;
+ }
+ }
+ tty = NULL;
+ xtty = NULL;
+ gclog_or_tty = NULL;
+ defaultStream::instance = NULL;
+}
+
+// ostream_abort() is called by os::abort() when VM is about to die.
+void ostream_abort() {
+ // Here we can't delete gclog_or_tty and tty, just flush their output
+ if (gclog_or_tty) gclog_or_tty->flush();
+ if (tty) tty->flush();
+
+ if (defaultStream::instance != NULL) {
+ static char buf[4096];
+ defaultStream::instance->finish_log_on_error(buf, sizeof(buf));
+ }
+}
+
+staticBufferStream::staticBufferStream(char* buffer, size_t buflen,
+ outputStream *outer_stream) {
+ _buffer = buffer;
+ _buflen = buflen;
+ _outer_stream = outer_stream;
+}
+
+void staticBufferStream::write(const char* c, size_t len) {
+ _outer_stream->print_raw(c, (int)len);
+}
+
+void staticBufferStream::flush() {
+ _outer_stream->flush();
+}
+
+void staticBufferStream::print(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ size_t len;
+ const char* str = do_vsnprintf(_buffer, _buflen, format, ap, false, len);
+ write(str, len);
+ va_end(ap);
+}
+
+void staticBufferStream::print_cr(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ size_t len;
+ const char* str = do_vsnprintf(_buffer, _buflen, format, ap, true, len);
+ write(str, len);
+ va_end(ap);
+}
+
+void staticBufferStream::vprint(const char *format, va_list argptr) {
+ size_t len;
+ const char* str = do_vsnprintf(_buffer, _buflen, format, argptr, false, len);
+ write(str, len);
+}
+
+void staticBufferStream::vprint_cr(const char* format, va_list argptr) {
+ size_t len;
+ const char* str = do_vsnprintf(_buffer, _buflen, format, argptr, true, len);
+ write(str, len);
+}
+
+bufferedStream::bufferedStream(size_t initial_size) : outputStream() {
+ buffer_length = initial_size;
+ buffer = NEW_C_HEAP_ARRAY(char, buffer_length);
+ buffer_pos = 0;
+ buffer_fixed = false;
+}
+
+bufferedStream::bufferedStream(char* fixed_buffer, size_t fixed_buffer_size) : outputStream() {
+ buffer_length = fixed_buffer_size;
+ buffer = fixed_buffer;
+ buffer_pos = 0;
+ buffer_fixed = true;
+}
+
+void bufferedStream::write(const char* s, size_t len) {
+ size_t end = buffer_pos + len;
+ if (end >= buffer_length) {
+ if (buffer_fixed) {
+ // if buffer cannot resize, silently truncate
+ len = buffer_length - buffer_pos - 1;
+ } else {
+ // For small overruns, double the buffer. For larger ones,
+ // increase to the requested size.
+ if (end < buffer_length * 2) {
+ end = buffer_length * 2;
+ }
+ buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end);
+ buffer_length = end;
+ }
+ }
+ memcpy(buffer + buffer_pos, s, len);
+ buffer_pos += len;
+ update_position(s, len);
+}
+
+char* bufferedStream::as_string() {
+ char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos+1);
+ strncpy(copy, buffer, buffer_pos);
+ copy[buffer_pos] = 0; // terminating null
+ return copy;
+}
+
+bufferedStream::~bufferedStream() {
+ if (!buffer_fixed) {
+ FREE_C_HEAP_ARRAY(char, buffer);
+ }
+}
+
+#ifndef PRODUCT
+
+#if defined(SOLARIS) || defined(LINUX)
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+// Network access
+networkStream::networkStream() {
+
+ _socket = -1;
+
+ hpi::initialize_socket_library();
+
+ int result = hpi::socket(AF_INET, SOCK_STREAM, 0);
+ if (result <= 0) {
+ assert(false, "Socket could not be created!");
+ } else {
+ _socket = result;
+ }
+}
+
+int networkStream::read(char *buf, size_t len) {
+ return hpi::recv(_socket, buf, (int)len, 0);
+}
+
+void networkStream::flush() {
+ if (size() != 0) {
+ hpi::send(_socket, (char *)base(), (int)size(), 0);
+ }
+ reset();
+}
+
+networkStream::~networkStream() {
+ close();
+}
+
+void networkStream::close() {
+ if (_socket != -1) {
+ flush();
+ hpi::socket_close(_socket);
+ _socket = -1;
+ }
+}
+
+bool networkStream::connect(const char *ip, short port) {
+
+ struct sockaddr_in server;
+ server.sin_family = AF_INET;
+ server.sin_port = htons(port);
+
+ server.sin_addr.s_addr = inet_addr(ip);
+ if (server.sin_addr.s_addr == (unsigned long)-1) {
+#ifdef _WINDOWS
+ struct hostent* host = hpi::get_host_by_name((char*)ip);
+#else
+ struct hostent* host = gethostbyname(ip);
+#endif
+ if (host != NULL) {
+ memcpy(&server.sin_addr, host->h_addr_list[0], host->h_length);
+ } else {
+ return false;
+ }
+ }
+
+
+ int result = hpi::connect(_socket, (struct sockaddr*)&server, sizeof(struct sockaddr_in));
+ return (result >= 0);
+}
+
+#endif
diff --git a/src/share/vm/utilities/ostream.hpp b/src/share/vm/utilities/ostream.hpp
new file mode 100644
index 000000000..3d50c6988
--- /dev/null
+++ b/src/share/vm/utilities/ostream.hpp
@@ -0,0 +1,241 @@
+/*
+ * Copyright 1997-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// Output streams for printing
+//
+// Printing guidelines:
+// Where possible, please use tty->print() and tty->print_cr().
+// For product mode VM warnings use warning() which internally uses tty.
+// In places where tty is not initialized yet or too much overhead,
+// we may use jio_printf:
+// jio_fprintf(defaultStream::output_stream(), "Message");
+// This allows for redirection via -XX:+DisplayVMOutputToStdout and
+// -XX:+DisplayVMOutputToStderr
+class outputStream : public ResourceObj {
+ protected:
+ int _indentation; // current indentation
+ int _width; // width of the page
+ int _position; // position on the current line
+ int _newlines; // number of '\n' output so far
+ julong _precount; // number of chars output, less _position
+ TimeStamp _stamp; // for time stamps
+
+ void update_position(const char* s, size_t len);
+ static const char* do_vsnprintf(char* buffer, size_t buflen,
+ const char* format, va_list ap,
+ bool add_cr,
+ size_t& result_len);
+
+ public:
+ // creation
+ outputStream(int width = 80);
+ outputStream(int width, bool has_time_stamps);
+
+ // indentation
+ void indent();
+ void inc() { _indentation++; };
+ void dec() { _indentation--; };
+ int indentation() const { return _indentation; }
+ void set_indentation(int i) { _indentation = i; }
+ void fill_to(int col);
+
+ // sizing
+ int width() const { return _width; }
+ int position() const { return _position; }
+ int newlines() const { return _newlines; }
+ julong count() const { return _precount + _position; }
+ void set_count(julong count) { _precount = count - _position; }
+ void set_position(int pos) { _position = pos; }
+
+ // printing
+ void print(const char* format, ...);
+ void print_cr(const char* format, ...);
+ void vprint(const char *format, va_list argptr);
+ void vprint_cr(const char* format, va_list argptr);
+ void print_raw(const char* str) { write(str, strlen(str)); }
+ void print_raw(const char* str, int len) { write(str, len); }
+ void print_raw_cr(const char* str) { write(str, strlen(str)); cr(); }
+ void print_raw_cr(const char* str, int len){ write(str, len); cr(); }
+ void put(char ch);
+ void sp();
+ void cr();
+ void bol() { if (_position > 0) cr(); }
+
+ // Time stamp
+ TimeStamp& time_stamp() { return _stamp; }
+ void stamp();
+ // Date stamp
+ void date_stamp(bool guard, const char* prefix, const char* suffix);
+ // A simplified call that includes a suffix of ": "
+ void date_stamp(bool guard) {
+ date_stamp(guard, "", ": ");
+ }
+
+ // portable printing of 64 bit integers
+ void print_jlong(jlong value);
+ void print_julong(julong value);
+
+ // flushing
+ virtual void flush() {}
+ virtual void write(const char* str, size_t len) = 0;
+ virtual ~outputStream() {} // close properly on deletion
+
+ void dec_cr() { dec(); cr(); }
+ void inc_cr() { inc(); cr(); }
+};
+
+// standard output
+ // ANSI C++ name collision
+extern outputStream* tty; // tty output
+extern outputStream* gclog_or_tty; // stream for gc log if -Xloggc:<f>, or tty
+
+// advisory locking for the shared tty stream:
+class ttyLocker: StackObj {
+ private:
+ intx _holder;
+
+ public:
+ static intx hold_tty(); // returns a "holder" token
+ static void release_tty(intx holder); // must witness same token
+ static void break_tty_lock_for_safepoint(intx holder);
+
+ ttyLocker() { _holder = hold_tty(); }
+ ~ttyLocker() { release_tty(_holder); }
+};
+
+// for writing to strings; buffer will expand automatically
+class stringStream : public outputStream {
+ protected:
+ char* buffer;
+ size_t buffer_pos;
+ size_t buffer_length;
+ bool buffer_fixed;
+ public:
+ stringStream(size_t initial_bufsize = 256);
+ stringStream(char* fixed_buffer, size_t fixed_buffer_size);
+ ~stringStream();
+ virtual void write(const char* c, size_t len);
+ size_t size() { return buffer_pos; }
+ const char* base() { return buffer; }
+ void reset() { buffer_pos = 0; _precount = 0; _position = 0; }
+ char* as_string();
+};
+
+class fileStream : public outputStream {
+ protected:
+ FILE* _file;
+ bool _need_close;
+ public:
+ fileStream(const char* file_name);
+ fileStream(FILE* file) { _file = file; _need_close = false; }
+ ~fileStream();
+ bool is_open() const { return _file != NULL; }
+ virtual void write(const char* c, size_t len);
+ void flush();
+};
+
+// unlike fileStream, fdStream does unbuffered I/O by calling
+// open() and write() directly. It is async-safe, but output
+// from multiple thread may be mixed together. Used by fatal
+// error handler.
+class fdStream : public outputStream {
+ protected:
+ int _fd;
+ bool _need_close;
+ public:
+ fdStream(const char* file_name);
+ fdStream(int fd = -1) { _fd = fd; _need_close = false; }
+ ~fdStream();
+ bool is_open() const { return _fd != -1; }
+ void set_fd(int fd) { _fd = fd; _need_close = false; }
+ int fd() const { return _fd; }
+ virtual void write(const char* c, size_t len);
+ void flush() {};
+};
+
+void ostream_init();
+void ostream_init_log();
+void ostream_exit();
+void ostream_abort();
+
+// staticBufferStream uses a user-supplied buffer for all formatting.
+// Used for safe formatting during fatal error handling. Not MT safe.
+// Do not share the stream between multiple threads.
+class staticBufferStream : public outputStream {
+ private:
+ char* _buffer;
+ size_t _buflen;
+ outputStream* _outer_stream;
+ public:
+ staticBufferStream(char* buffer, size_t buflen,
+ outputStream *outer_stream);
+ ~staticBufferStream() {};
+ virtual void write(const char* c, size_t len);
+ void flush();
+ void print(const char* format, ...);
+ void print_cr(const char* format, ...);
+ void vprint(const char *format, va_list argptr);
+ void vprint_cr(const char* format, va_list argptr);
+};
+
+// In the non-fixed buffer case an underlying buffer will be created and
+// managed in C heap. Not MT-safe.
+class bufferedStream : public outputStream {
+ protected:
+ char* buffer;
+ size_t buffer_pos;
+ size_t buffer_length;
+ bool buffer_fixed;
+ public:
+ bufferedStream(size_t initial_bufsize = 256);
+ bufferedStream(char* fixed_buffer, size_t fixed_buffer_size);
+ ~bufferedStream();
+ virtual void write(const char* c, size_t len);
+ size_t size() { return buffer_pos; }
+ const char* base() { return buffer; }
+ void reset() { buffer_pos = 0; _precount = 0; _position = 0; }
+ char* as_string();
+};
+
+#define O_BUFLEN 2000 // max size of output of individual print() methods
+
+#ifndef PRODUCT
+
+class networkStream : public bufferedStream {
+
+ private:
+ int _socket;
+
+ public:
+ networkStream();
+ ~networkStream();
+
+ bool connect(const char *host, short port);
+ bool is_open() const { return _socket != -1; }
+ int read(char *buf, size_t len);
+ void close();
+ virtual void flush();
+};
+
+#endif
diff --git a/src/share/vm/utilities/preserveException.cpp b/src/share/vm/utilities/preserveException.cpp
new file mode 100644
index 000000000..46d8dc96a
--- /dev/null
+++ b/src/share/vm/utilities/preserveException.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 1998-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include "incls/_precompiled.incl"
+#include "incls/_preserveException.cpp.incl"
+
+// TODO: These three classes should be refactored
+
+PreserveExceptionMark::PreserveExceptionMark(Thread*& thread) {
+ thread = Thread::current();
+ _thread = thread;
+ _preserved_exception_oop = Handle(thread, _thread->pending_exception());
+ _thread->clear_pending_exception(); // Needed to avoid infinite recursion
+ _preserved_exception_line = _thread->exception_line();
+ _preserved_exception_file = _thread->exception_file();
+}
+
+
+PreserveExceptionMark::~PreserveExceptionMark() {
+ if (_thread->has_pending_exception()) {
+ oop exception = _thread->pending_exception();
+ _thread->clear_pending_exception(); // Needed to avoid infinite recursion
+ exception->print();
+ fatal("PreserveExceptionMark destructor expects no pending exceptions");
+ }
+ if (_preserved_exception_oop() != NULL) {
+ _thread->set_pending_exception(_preserved_exception_oop(), _preserved_exception_file, _preserved_exception_line);
+ }
+}
+
+
+// This code is cloned from PreserveExceptionMark, except that:
+// returned pending exceptions do not cause a crash.
+// thread is passed in, not set (not a reference parameter)
+// and bug 6431341 has been addressed.
+
+CautiouslyPreserveExceptionMark::CautiouslyPreserveExceptionMark(Thread* thread) {
+ _thread = thread;
+ _preserved_exception_oop = Handle(thread, _thread->pending_exception());
+ _preserved_exception_line = _thread->exception_line();
+ _preserved_exception_file = _thread->exception_file();
+ _thread->clear_pending_exception(); // Pending exceptions are checked in the destructor
+}
+
+
+CautiouslyPreserveExceptionMark::~CautiouslyPreserveExceptionMark() {
+ assert(!_thread->has_pending_exception(), "unexpected exception generated");
+ if (_thread->has_pending_exception()) {
+ _thread->clear_pending_exception();
+ }
+ if (_preserved_exception_oop() != NULL) {
+ _thread->set_pending_exception(_preserved_exception_oop(), _preserved_exception_file, _preserved_exception_line);
+ }
+}
+
+
+void WeakPreserveExceptionMark::preserve() {
+ _preserved_exception_oop = Handle(_thread, _thread->pending_exception());
+ _preserved_exception_line = _thread->exception_line();
+ _preserved_exception_file = _thread->exception_file();
+ _thread->clear_pending_exception();
+}
+
+void WeakPreserveExceptionMark::restore() {
+ if (!_thread->has_pending_exception()) {
+ _thread->set_pending_exception(_preserved_exception_oop(), _preserved_exception_file, _preserved_exception_line);
+ }
+}
diff --git a/src/share/vm/utilities/preserveException.hpp b/src/share/vm/utilities/preserveException.hpp
new file mode 100644
index 000000000..9ed3797d3
--- /dev/null
+++ b/src/share/vm/utilities/preserveException.hpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1998-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// This file provides more support for exception handling; see also exceptions.hpp
+class PreserveExceptionMark {
+ private:
+ Thread* _thread;
+ Handle _preserved_exception_oop;
+ int _preserved_exception_line;
+ const char* _preserved_exception_file;
+
+ public:
+ PreserveExceptionMark(Thread*& thread);
+ ~PreserveExceptionMark();
+};
+
+
+// This is a clone of PreserveExceptionMark which asserts instead
+// of failing when what it wraps generates a pending exception.
+// It also addresses bug 6431341.
+class CautiouslyPreserveExceptionMark {
+ private:
+ Thread* _thread;
+ Handle _preserved_exception_oop;
+ int _preserved_exception_line;
+ const char* _preserved_exception_file;
+
+ public:
+ CautiouslyPreserveExceptionMark(Thread* thread);
+ ~CautiouslyPreserveExceptionMark();
+};
+
+
+// Like PreserveExceptionMark but allows new exceptions to be generated in
+// the body of the mark. If a new exception is generated then the original one
+// is discarded.
+class WeakPreserveExceptionMark {
+private:
+ Thread* _thread;
+ Handle _preserved_exception_oop;
+ int _preserved_exception_line;
+ const char* _preserved_exception_file;
+
+ void preserve();
+ void restore();
+
+ public:
+ WeakPreserveExceptionMark(Thread* pThread) : _thread(pThread), _preserved_exception_oop() {
+ if (pThread->has_pending_exception()) {
+ preserve();
+ }
+ }
+ ~WeakPreserveExceptionMark() {
+ if (_preserved_exception_oop.not_null()) {
+ restore();
+ }
+ }
+};
+
+
+
+// use global exception mark when allowing pending exception to be set and
+// saving and restoring them
+#define PRESERVE_EXCEPTION_MARK Thread* THREAD; PreserveExceptionMark __em(THREAD);
diff --git a/src/share/vm/utilities/sizes.cpp b/src/share/vm/utilities/sizes.cpp
new file mode 100644
index 000000000..62d02473a
--- /dev/null
+++ b/src/share/vm/utilities/sizes.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_sizes.cpp.incl"
diff --git a/src/share/vm/utilities/sizes.hpp b/src/share/vm/utilities/sizes.hpp
new file mode 100644
index 000000000..7b805f18a
--- /dev/null
+++ b/src/share/vm/utilities/sizes.hpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2000-2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// The following two classes are used to represent 'sizes' and 'offsets' in the VM;
+// they serve as 'unit' types. ByteSize is used for sizes measured in bytes, while
+// WordSize is used for sizes measured in machine words (i.e., 32bit or 64bit words
+// depending on platform).
+//
+// The classes are defined with friend functions operating on them instead of member
+// functions so that they (the classes) can be re-#define'd to int types in optimized
+// mode. This allows full type checking and maximum safety in debug mode, and full
+// optimizations (constant folding) and zero overhead (time and space wise) in the
+// optimized build (some compilers do not optimize one-element value classes but
+// instead create an object in memory - thus the overhead may be significant).
+//
+// Note: 1) DO NOT add new overloaded friend functions that do not have a unique function
+// function name but require signature types for resolution. This will not work
+// in optimized mode as both, ByteSize and WordSize are mapped to the same type
+// and thus the distinction would not be possible anymore (=> compiler errors).
+//
+// 2) DO NOT add non-static member functions as they cannot be mapped so something
+// compilable in the optimized build. Static member functions could be added
+// but require a corresponding class definition in the optimized build.
+//
+// These classes should help doing a transition from (currently) word-size based offsets
+// to byte-size based offsets in the VM (this will be important if we desire to pack
+// objects more densely in the VM for 64bit machines). Such a transition should proceed
+// in two steps to minimize the risk of introducing hard-to-find bugs:
+//
+// a) first transition the whole VM into a form where all sizes are strongly typed
+// b) change all WordSize's to ByteSize's where desired and fix the compilation errors
+
+
+#ifdef ASSERT
+
+class ByteSize VALUE_OBJ_CLASS_SPEC {
+ private:
+ int _size;
+
+ // Note: This constructor must be private to avoid implicit conversions!
+ ByteSize(int size) { _size = size; }
+
+ public:
+ // constructors
+ inline friend ByteSize in_ByteSize(int size);
+
+ // accessors
+ inline friend int in_bytes(ByteSize x);
+
+ // operators
+ friend ByteSize operator + (ByteSize x, ByteSize y) { return ByteSize(in_bytes(x) + in_bytes(y)); }
+ friend ByteSize operator - (ByteSize x, ByteSize y) { return ByteSize(in_bytes(x) - in_bytes(y)); }
+ friend ByteSize operator * (ByteSize x, int y) { return ByteSize(in_bytes(x) * y ); }
+
+ // comparison
+ friend bool operator == (ByteSize x, ByteSize y) { return in_bytes(x) == in_bytes(y); }
+ friend bool operator != (ByteSize x, ByteSize y) { return in_bytes(x) != in_bytes(y); }
+ friend bool operator < (ByteSize x, ByteSize y) { return in_bytes(x) < in_bytes(y); }
+ friend bool operator <= (ByteSize x, ByteSize y) { return in_bytes(x) <= in_bytes(y); }
+ friend bool operator > (ByteSize x, ByteSize y) { return in_bytes(x) > in_bytes(y); }
+ friend bool operator >= (ByteSize x, ByteSize y) { return in_bytes(x) >= in_bytes(y); }
+};
+
+inline ByteSize in_ByteSize(int size) { return ByteSize(size); }
+inline int in_bytes(ByteSize x) { return x._size; }
+
+
+class WordSize VALUE_OBJ_CLASS_SPEC {
+ private:
+ int _size;
+
+ // Note: This constructor must be private to avoid implicit conversions!
+ WordSize(int size) { _size = size; }
+
+ public:
+ // constructors
+ inline friend WordSize in_WordSize(int size);
+
+ // accessors
+ inline friend int in_words(WordSize x);
+
+ // operators
+ friend WordSize operator + (WordSize x, WordSize y) { return WordSize(in_words(x) + in_words(y)); }
+ friend WordSize operator - (WordSize x, WordSize y) { return WordSize(in_words(x) - in_words(y)); }
+ friend WordSize operator * (WordSize x, int y) { return WordSize(in_words(x) * y ); }
+
+ // comparison
+ friend bool operator == (WordSize x, WordSize y) { return in_words(x) == in_words(y); }
+ friend bool operator != (WordSize x, WordSize y) { return in_words(x) != in_words(y); }
+ friend bool operator < (WordSize x, WordSize y) { return in_words(x) < in_words(y); }
+ friend bool operator <= (WordSize x, WordSize y) { return in_words(x) <= in_words(y); }
+ friend bool operator > (WordSize x, WordSize y) { return in_words(x) > in_words(y); }
+ friend bool operator >= (WordSize x, WordSize y) { return in_words(x) >= in_words(y); }
+};
+
+inline WordSize in_WordSize(int size) { return WordSize(size); }
+inline int in_words(WordSize x) { return x._size; }
+
+
+#else // ASSERT
+
+// The following definitions must match the corresponding friend declarations
+// in the Byte/WordSize classes if they are typedef'ed to be int. This will
+// be the case in optimized mode to ensure zero overhead for these types.
+//
+// Note: If a compiler does not inline these function calls away, one may
+// want to use #define's to make sure full optimization (constant
+// folding in particular) is possible.
+
+typedef int ByteSize;
+inline ByteSize in_ByteSize(int size) { return size; }
+inline int in_bytes (ByteSize x) { return x; }
+
+typedef int WordSize;
+inline WordSize in_WordSize(int size) { return size; }
+inline int in_words (WordSize x) { return x; }
+
+#endif // ASSERT
+
+
+// Use the following #define to get C++ field member offsets
+
+#define byte_offset_of(klass,field) in_ByteSize((int)offset_of(klass, field))
diff --git a/src/share/vm/utilities/taskqueue.cpp b/src/share/vm/utilities/taskqueue.cpp
new file mode 100644
index 000000000..691a85031
--- /dev/null
+++ b/src/share/vm/utilities/taskqueue.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2001-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_taskqueue.cpp.incl"
+
+bool TaskQueueSuper::peek() {
+ return _bottom != _age.top();
+}
+
+int TaskQueueSetSuper::randomParkAndMiller(int *seed0) {
+ const int a = 16807;
+ const int m = 2147483647;
+ const int q = 127773; /* m div a */
+ const int r = 2836; /* m mod a */
+ assert(sizeof(int) == 4, "I think this relies on that");
+ int seed = *seed0;
+ int hi = seed / q;
+ int lo = seed % q;
+ int test = a * lo - r * hi;
+ if (test > 0)
+ seed = test;
+ else
+ seed = test + m;
+ *seed0 = seed;
+ return seed;
+}
+
+ParallelTaskTerminator::
+ParallelTaskTerminator(int n_threads, TaskQueueSetSuper* queue_set) :
+ _n_threads(n_threads),
+ _queue_set(queue_set),
+ _offered_termination(0) {}
+
+bool ParallelTaskTerminator::peek_in_queue_set() {
+ return _queue_set->peek();
+}
+
+void ParallelTaskTerminator::yield() {
+ os::yield();
+}
+
+void ParallelTaskTerminator::sleep(uint millis) {
+ os::sleep(Thread::current(), millis, false);
+}
+
+bool ParallelTaskTerminator::offer_termination() {
+ Atomic::inc(&_offered_termination);
+
+ juint yield_count = 0;
+ while (true) {
+ if (_offered_termination == _n_threads) {
+ //inner_termination_loop();
+ return true;
+ } else {
+ if (yield_count <= WorkStealingYieldsBeforeSleep) {
+ yield_count++;
+ yield();
+ } else {
+ if (PrintGCDetails && Verbose) {
+ gclog_or_tty->print_cr("ParallelTaskTerminator::offer_termination() "
+ "thread %d sleeps after %d yields",
+ Thread::current(), yield_count);
+ }
+ yield_count = 0;
+ // A sleep will cause this processor to seek work on another processor's
+ // runqueue, if it has nothing else to run (as opposed to the yield
+ // which may only move the thread to the end of the this processor's
+ // runqueue).
+ sleep(WorkStealingSleepMillis);
+ }
+
+ if (peek_in_queue_set()) {
+ Atomic::dec(&_offered_termination);
+ return false;
+ }
+ }
+ }
+}
+
+void ParallelTaskTerminator::reset_for_reuse() {
+ if (_offered_termination != 0) {
+ assert(_offered_termination == _n_threads,
+ "Terminator may still be in use");
+ _offered_termination = 0;
+ }
+}
+
+bool ChunkTaskQueueWithOverflow::is_empty() {
+ return (_chunk_queue.size() == 0) &&
+ (_overflow_stack->length() == 0);
+}
+
+bool ChunkTaskQueueWithOverflow::stealable_is_empty() {
+ return _chunk_queue.size() == 0;
+}
+
+bool ChunkTaskQueueWithOverflow::overflow_is_empty() {
+ return _overflow_stack->length() == 0;
+}
+
+void ChunkTaskQueueWithOverflow::initialize() {
+ _chunk_queue.initialize();
+ assert(_overflow_stack == 0, "Creating memory leak");
+ _overflow_stack =
+ new (ResourceObj::C_HEAP) GrowableArray<ChunkTask>(10, true);
+}
+
+void ChunkTaskQueueWithOverflow::save(ChunkTask t) {
+ if (TraceChunkTasksQueuing && Verbose) {
+ gclog_or_tty->print_cr("CTQ: save " PTR_FORMAT, t);
+ }
+ if(!_chunk_queue.push(t)) {
+ _overflow_stack->push(t);
+ }
+}
+
+// Note that using this method will retrieve all chunks
+// that have been saved but that it will always check
+// the overflow stack. It may be more efficient to
+// check the stealable queue and the overflow stack
+// separately.
+bool ChunkTaskQueueWithOverflow::retrieve(ChunkTask& chunk_task) {
+ bool result = retrieve_from_overflow(chunk_task);
+ if (!result) {
+ result = retrieve_from_stealable_queue(chunk_task);
+ }
+ if (TraceChunkTasksQueuing && Verbose && result) {
+ gclog_or_tty->print_cr(" CTQ: retrieve " PTR_FORMAT, result);
+ }
+ return result;
+}
+
+bool ChunkTaskQueueWithOverflow::retrieve_from_stealable_queue(
+ ChunkTask& chunk_task) {
+ bool result = _chunk_queue.pop_local(chunk_task);
+ if (TraceChunkTasksQueuing && Verbose) {
+ gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, chunk_task);
+ }
+ return result;
+}
+
+bool ChunkTaskQueueWithOverflow::retrieve_from_overflow(
+ ChunkTask& chunk_task) {
+ bool result;
+ if (!_overflow_stack->is_empty()) {
+ chunk_task = _overflow_stack->pop();
+ result = true;
+ } else {
+ chunk_task = (ChunkTask) NULL;
+ result = false;
+ }
+ if (TraceChunkTasksQueuing && Verbose) {
+ gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, chunk_task);
+ }
+ return result;
+}
diff --git a/src/share/vm/utilities/taskqueue.hpp b/src/share/vm/utilities/taskqueue.hpp
new file mode 100644
index 000000000..7fa983f82
--- /dev/null
+++ b/src/share/vm/utilities/taskqueue.hpp
@@ -0,0 +1,525 @@
+/*
+ * Copyright 2001-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+class TaskQueueSuper: public CHeapObj {
+protected:
+ // The first free element after the last one pushed (mod _n).
+ // (For now we'll assume only 32-bit CAS).
+ volatile juint _bottom;
+
+ // log2 of the size of the queue.
+ enum SomeProtectedConstants {
+ Log_n = 14
+ };
+
+ // Size of the queue.
+ juint n() { return (1 << Log_n); }
+ // For computing "x mod n" efficiently.
+ juint n_mod_mask() { return n() - 1; }
+
+ struct Age {
+ jushort _top;
+ jushort _tag;
+
+ jushort tag() const { return _tag; }
+ jushort top() const { return _top; }
+
+ Age() { _tag = 0; _top = 0; }
+
+ friend bool operator ==(const Age& a1, const Age& a2) {
+ return a1.tag() == a2.tag() && a1.top() == a2.top();
+ }
+
+ };
+ Age _age;
+ // These make sure we do single atomic reads and writes.
+ Age get_age() {
+ jint res = *(volatile jint*)(&_age);
+ return *(Age*)(&res);
+ }
+ void set_age(Age a) {
+ *(volatile jint*)(&_age) = *(int*)(&a);
+ }
+
+ jushort get_top() {
+ return get_age().top();
+ }
+
+ // These both operate mod _n.
+ juint increment_index(juint ind) {
+ return (ind + 1) & n_mod_mask();
+ }
+ juint decrement_index(juint ind) {
+ return (ind - 1) & n_mod_mask();
+ }
+
+ // Returns a number in the range [0.._n). If the result is "n-1", it
+ // should be interpreted as 0.
+ juint dirty_size(juint bot, juint top) {
+ return ((jint)bot - (jint)top) & n_mod_mask();
+ }
+
+ // Returns the size corresponding to the given "bot" and "top".
+ juint size(juint bot, juint top) {
+ juint sz = dirty_size(bot, top);
+ // Has the queue "wrapped", so that bottom is less than top?
+ // There's a complicated special case here. A pair of threads could
+ // perform pop_local and pop_global operations concurrently, starting
+ // from a state in which _bottom == _top+1. The pop_local could
+ // succeed in decrementing _bottom, and the pop_global in incrementing
+ // _top (in which case the pop_global will be awarded the contested
+ // queue element.) The resulting state must be interpreted as an empty
+ // queue. (We only need to worry about one such event: only the queue
+ // owner performs pop_local's, and several concurrent threads
+ // attempting to perform the pop_global will all perform the same CAS,
+ // and only one can succeed. Any stealing thread that reads after
+ // either the increment or decrement will seen an empty queue, and will
+ // not join the competitors. The "sz == -1 || sz == _n-1" state will
+ // not be modified by concurrent queues, so the owner thread can reset
+ // the state to _bottom == top so subsequent pushes will be performed
+ // normally.
+ if (sz == (n()-1)) return 0;
+ else return sz;
+ }
+
+public:
+ TaskQueueSuper() : _bottom(0), _age() {}
+
+ // Return "true" if the TaskQueue contains any tasks.
+ bool peek();
+
+ // Return an estimate of the number of elements in the queue.
+ // The "careful" version admits the possibility of pop_local/pop_global
+ // races.
+ juint size() {
+ return size(_bottom, get_top());
+ }
+
+ juint dirty_size() {
+ return dirty_size(_bottom, get_top());
+ }
+
+ // Maximum number of elements allowed in the queue. This is two less
+ // than the actual queue size, for somewhat complicated reasons.
+ juint max_elems() { return n() - 2; }
+
+};
+
+template<class E> class GenericTaskQueue: public TaskQueueSuper {
+private:
+ // Slow paths for push, pop_local. (pop_global has no fast path.)
+ bool push_slow(E t, juint dirty_n_elems);
+ bool pop_local_slow(juint localBot, Age oldAge);
+
+public:
+ // Initializes the queue to empty.
+ GenericTaskQueue();
+
+ void initialize();
+
+ // Push the task "t" on the queue. Returns "false" iff the queue is
+ // full.
+ inline bool push(E t);
+
+ // If succeeds in claiming a task (from the 'local' end, that is, the
+ // most recently pushed task), returns "true" and sets "t" to that task.
+ // Otherwise, the queue is empty and returns false.
+ inline bool pop_local(E& t);
+
+ // If succeeds in claiming a task (from the 'global' end, that is, the
+ // least recently pushed task), returns "true" and sets "t" to that task.
+ // Otherwise, the queue is empty and returns false.
+ bool pop_global(E& t);
+
+ // Delete any resource associated with the queue.
+ ~GenericTaskQueue();
+
+private:
+ // Element array.
+ volatile E* _elems;
+};
+
+template<class E>
+GenericTaskQueue<E>::GenericTaskQueue():TaskQueueSuper() {
+ assert(sizeof(Age) == sizeof(jint), "Depends on this.");
+}
+
+template<class E>
+void GenericTaskQueue<E>::initialize() {
+ _elems = NEW_C_HEAP_ARRAY(E, n());
+ guarantee(_elems != NULL, "Allocation failed.");
+}
+
+template<class E>
+bool GenericTaskQueue<E>::push_slow(E t, juint dirty_n_elems) {
+ if (dirty_n_elems == n() - 1) {
+ // Actually means 0, so do the push.
+ juint localBot = _bottom;
+ _elems[localBot] = t;
+ _bottom = increment_index(localBot);
+ return true;
+ } else
+ return false;
+}
+
+template<class E>
+bool GenericTaskQueue<E>::
+pop_local_slow(juint localBot, Age oldAge) {
+ // This queue was observed to contain exactly one element; either this
+ // thread will claim it, or a competing "pop_global". In either case,
+ // the queue will be logically empty afterwards. Create a new Age value
+ // that represents the empty queue for the given value of "_bottom". (We
+ // must also increment "tag" because of the case where "bottom == 1",
+ // "top == 0". A pop_global could read the queue element in that case,
+ // then have the owner thread do a pop followed by another push. Without
+ // the incrementing of "tag", the pop_global's CAS could succeed,
+ // allowing it to believe it has claimed the stale element.)
+ Age newAge;
+ newAge._top = localBot;
+ newAge._tag = oldAge.tag() + 1;
+ // Perhaps a competing pop_global has already incremented "top", in which
+ // case it wins the element.
+ if (localBot == oldAge.top()) {
+ Age tempAge;
+ // No competing pop_global has yet incremented "top"; we'll try to
+ // install new_age, thus claiming the element.
+ assert(sizeof(Age) == sizeof(jint) && sizeof(jint) == sizeof(juint),
+ "Assumption about CAS unit.");
+ *(jint*)&tempAge = Atomic::cmpxchg(*(jint*)&newAge, (volatile jint*)&_age, *(jint*)&oldAge);
+ if (tempAge == oldAge) {
+ // We win.
+ assert(dirty_size(localBot, get_top()) != n() - 1,
+ "Shouldn't be possible...");
+ return true;
+ }
+ }
+ // We fail; a completing pop_global gets the element. But the queue is
+ // empty (and top is greater than bottom.) Fix this representation of
+ // the empty queue to become the canonical one.
+ set_age(newAge);
+ assert(dirty_size(localBot, get_top()) != n() - 1,
+ "Shouldn't be possible...");
+ return false;
+}
+
+template<class E>
+bool GenericTaskQueue<E>::pop_global(E& t) {
+ Age newAge;
+ Age oldAge = get_age();
+ juint localBot = _bottom;
+ juint n_elems = size(localBot, oldAge.top());
+ if (n_elems == 0) {
+ return false;
+ }
+ t = _elems[oldAge.top()];
+ newAge = oldAge;
+ newAge._top = increment_index(newAge.top());
+ if ( newAge._top == 0 ) newAge._tag++;
+ Age resAge;
+ *(jint*)&resAge = Atomic::cmpxchg(*(jint*)&newAge, (volatile jint*)&_age, *(jint*)&oldAge);
+ // Note that using "_bottom" here might fail, since a pop_local might
+ // have decremented it.
+ assert(dirty_size(localBot, newAge._top) != n() - 1,
+ "Shouldn't be possible...");
+ return (resAge == oldAge);
+}
+
+template<class E>
+GenericTaskQueue<E>::~GenericTaskQueue() {
+ FREE_C_HEAP_ARRAY(E, _elems);
+}
+
+// Inherits the typedef of "Task" from above.
+class TaskQueueSetSuper: public CHeapObj {
+protected:
+ static int randomParkAndMiller(int* seed0);
+public:
+ // Returns "true" if some TaskQueue in the set contains a task.
+ virtual bool peek() = 0;
+};
+
+template<class E> class GenericTaskQueueSet: public TaskQueueSetSuper {
+private:
+ int _n;
+ GenericTaskQueue<E>** _queues;
+
+public:
+ GenericTaskQueueSet(int n) : _n(n) {
+ typedef GenericTaskQueue<E>* GenericTaskQueuePtr;
+ _queues = NEW_C_HEAP_ARRAY(GenericTaskQueuePtr, n);
+ guarantee(_queues != NULL, "Allocation failure.");
+ for (int i = 0; i < n; i++) {
+ _queues[i] = NULL;
+ }
+ }
+
+ bool steal_1_random(int queue_num, int* seed, E& t);
+ bool steal_best_of_2(int queue_num, int* seed, E& t);
+ bool steal_best_of_all(int queue_num, int* seed, E& t);
+
+ void register_queue(int i, GenericTaskQueue<E>* q);
+
+ GenericTaskQueue<E>* queue(int n);
+
+ // The thread with queue number "queue_num" (and whose random number seed
+ // is at "seed") is trying to steal a task from some other queue. (It
+ // may try several queues, according to some configuration parameter.)
+ // If some steal succeeds, returns "true" and sets "t" the stolen task,
+ // otherwise returns false.
+ bool steal(int queue_num, int* seed, E& t);
+
+ bool peek();
+};
+
+template<class E>
+void GenericTaskQueueSet<E>::register_queue(int i, GenericTaskQueue<E>* q) {
+ assert(0 <= i && i < _n, "index out of range.");
+ _queues[i] = q;
+}
+
+template<class E>
+GenericTaskQueue<E>* GenericTaskQueueSet<E>::queue(int i) {
+ return _queues[i];
+}
+
+template<class E>
+bool GenericTaskQueueSet<E>::steal(int queue_num, int* seed, E& t) {
+ for (int i = 0; i < 2 * _n; i++)
+ if (steal_best_of_2(queue_num, seed, t))
+ return true;
+ return false;
+}
+
+template<class E>
+bool GenericTaskQueueSet<E>::steal_best_of_all(int queue_num, int* seed, E& t) {
+ if (_n > 2) {
+ int best_k;
+ jint best_sz = 0;
+ for (int k = 0; k < _n; k++) {
+ if (k == queue_num) continue;
+ jint sz = _queues[k]->size();
+ if (sz > best_sz) {
+ best_sz = sz;
+ best_k = k;
+ }
+ }
+ return best_sz > 0 && _queues[best_k]->pop_global(t);
+ } else if (_n == 2) {
+ // Just try the other one.
+ int k = (queue_num + 1) % 2;
+ return _queues[k]->pop_global(t);
+ } else {
+ assert(_n == 1, "can't be zero.");
+ return false;
+ }
+}
+
+template<class E>
+bool GenericTaskQueueSet<E>::steal_1_random(int queue_num, int* seed, E& t) {
+ if (_n > 2) {
+ int k = queue_num;
+ while (k == queue_num) k = randomParkAndMiller(seed) % _n;
+ return _queues[2]->pop_global(t);
+ } else if (_n == 2) {
+ // Just try the other one.
+ int k = (queue_num + 1) % 2;
+ return _queues[k]->pop_global(t);
+ } else {
+ assert(_n == 1, "can't be zero.");
+ return false;
+ }
+}
+
+template<class E>
+bool GenericTaskQueueSet<E>::steal_best_of_2(int queue_num, int* seed, E& t) {
+ if (_n > 2) {
+ int k1 = queue_num;
+ while (k1 == queue_num) k1 = randomParkAndMiller(seed) % _n;
+ int k2 = queue_num;
+ while (k2 == queue_num || k2 == k1) k2 = randomParkAndMiller(seed) % _n;
+ // Sample both and try the larger.
+ juint sz1 = _queues[k1]->size();
+ juint sz2 = _queues[k2]->size();
+ if (sz2 > sz1) return _queues[k2]->pop_global(t);
+ else return _queues[k1]->pop_global(t);
+ } else if (_n == 2) {
+ // Just try the other one.
+ int k = (queue_num + 1) % 2;
+ return _queues[k]->pop_global(t);
+ } else {
+ assert(_n == 1, "can't be zero.");
+ return false;
+ }
+}
+
+template<class E>
+bool GenericTaskQueueSet<E>::peek() {
+ // Try all the queues.
+ for (int j = 0; j < _n; j++) {
+ if (_queues[j]->peek())
+ return true;
+ }
+ return false;
+}
+
+// A class to aid in the termination of a set of parallel tasks using
+// TaskQueueSet's for work stealing.
+
+class ParallelTaskTerminator: public StackObj {
+private:
+ int _n_threads;
+ TaskQueueSetSuper* _queue_set;
+ jint _offered_termination;
+
+ bool peek_in_queue_set();
+protected:
+ virtual void yield();
+ void sleep(uint millis);
+
+public:
+
+ // "n_threads" is the number of threads to be terminated. "queue_set" is a
+ // queue sets of work queues of other threads.
+ ParallelTaskTerminator(int n_threads, TaskQueueSetSuper* queue_set);
+
+ // The current thread has no work, and is ready to terminate if everyone
+ // else is. If returns "true", all threads are terminated. If returns
+ // "false", available work has been observed in one of the task queues,
+ // so the global task is not complete.
+ bool offer_termination();
+
+ // Reset the terminator, so that it may be reused again.
+ // The caller is responsible for ensuring that this is done
+ // in an MT-safe manner, once the previous round of use of
+ // the terminator is finished.
+ void reset_for_reuse();
+
+};
+
+#define SIMPLE_STACK 0
+
+template<class E> inline bool GenericTaskQueue<E>::push(E t) {
+#if SIMPLE_STACK
+ juint localBot = _bottom;
+ if (_bottom < max_elems()) {
+ _elems[localBot] = t;
+ _bottom = localBot + 1;
+ return true;
+ } else {
+ return false;
+ }
+#else
+ juint localBot = _bottom;
+ assert((localBot >= 0) && (localBot < n()), "_bottom out of range.");
+ jushort top = get_top();
+ juint dirty_n_elems = dirty_size(localBot, top);
+ assert((dirty_n_elems >= 0) && (dirty_n_elems < n()),
+ "n_elems out of range.");
+ if (dirty_n_elems < max_elems()) {
+ _elems[localBot] = t;
+ _bottom = increment_index(localBot);
+ return true;
+ } else {
+ return push_slow(t, dirty_n_elems);
+ }
+#endif
+}
+
+template<class E> inline bool GenericTaskQueue<E>::pop_local(E& t) {
+#if SIMPLE_STACK
+ juint localBot = _bottom;
+ assert(localBot > 0, "precondition.");
+ localBot--;
+ t = _elems[localBot];
+ _bottom = localBot;
+ return true;
+#else
+ juint localBot = _bottom;
+ // This value cannot be n-1. That can only occur as a result of
+ // the assignment to bottom in this method. If it does, this method
+ // resets the size( to 0 before the next call (which is sequential,
+ // since this is pop_local.)
+ juint dirty_n_elems = dirty_size(localBot, get_top());
+ assert(dirty_n_elems != n() - 1, "Shouldn't be possible...");
+ if (dirty_n_elems == 0) return false;
+ localBot = decrement_index(localBot);
+ _bottom = localBot;
+ // This is necessary to prevent any read below from being reordered
+ // before the store just above.
+ OrderAccess::fence();
+ t = _elems[localBot];
+ // This is a second read of "age"; the "size()" above is the first.
+ // If there's still at least one element in the queue, based on the
+ // "_bottom" and "age" we've read, then there can be no interference with
+ // a "pop_global" operation, and we're done.
+ juint tp = get_top();
+ if (size(localBot, tp) > 0) {
+ assert(dirty_size(localBot, tp) != n() - 1,
+ "Shouldn't be possible...");
+ return true;
+ } else {
+ // Otherwise, the queue contained exactly one element; we take the slow
+ // path.
+ return pop_local_slow(localBot, get_age());
+ }
+#endif
+}
+
+typedef oop Task;
+typedef GenericTaskQueue<Task> OopTaskQueue;
+typedef GenericTaskQueueSet<Task> OopTaskQueueSet;
+
+typedef oop* StarTask;
+typedef GenericTaskQueue<StarTask> OopStarTaskQueue;
+typedef GenericTaskQueueSet<StarTask> OopStarTaskQueueSet;
+
+typedef size_t ChunkTask; // index for chunk
+typedef GenericTaskQueue<ChunkTask> ChunkTaskQueue;
+typedef GenericTaskQueueSet<ChunkTask> ChunkTaskQueueSet;
+
+class ChunkTaskQueueWithOverflow: public CHeapObj {
+ protected:
+ ChunkTaskQueue _chunk_queue;
+ GrowableArray<ChunkTask>* _overflow_stack;
+
+ public:
+ ChunkTaskQueueWithOverflow() : _overflow_stack(NULL) {}
+ // Initialize both stealable queue and overflow
+ void initialize();
+ // Save first to stealable queue and then to overflow
+ void save(ChunkTask t);
+ // Retrieve first from overflow and then from stealable queue
+ bool retrieve(ChunkTask& chunk_index);
+ // Retrieve from stealable queue
+ bool retrieve_from_stealable_queue(ChunkTask& chunk_index);
+ // Retrieve from overflow
+ bool retrieve_from_overflow(ChunkTask& chunk_index);
+ bool is_empty();
+ bool stealable_is_empty();
+ bool overflow_is_empty();
+ juint stealable_size() { return _chunk_queue.size(); }
+ ChunkTaskQueue* task_queue() { return &_chunk_queue; }
+};
+
+#define USE_ChunkTaskQueueWithOverflow
diff --git a/src/share/vm/utilities/top.hpp b/src/share/vm/utilities/top.hpp
new file mode 100644
index 000000000..2b709bb33
--- /dev/null
+++ b/src/share/vm/utilities/top.hpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 1997 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// THIS FILE IS INTESIONALLY LEFT EMPTY
+// IT IS USED TO MINIMIZE THE NUMBER OF DEPENDENCIES IN includeDB
diff --git a/src/share/vm/utilities/utf8.cpp b/src/share/vm/utilities/utf8.cpp
new file mode 100644
index 000000000..120b55277
--- /dev/null
+++ b/src/share/vm/utilities/utf8.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright 1997-2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_utf8.cpp.incl"
+
+// Assume the utf8 string is in legal form and has been
+// checked in the class file parser/format checker.
+char* UTF8::next(const char* str, jchar* value) {
+ unsigned const char *ptr = (const unsigned char *)str;
+ unsigned char ch, ch2, ch3;
+ int length = -1; /* bad length */
+ jchar result;
+ switch ((ch = ptr[0]) >> 4) {
+ default:
+ result = ch;
+ length = 1;
+ break;
+
+ case 0x8: case 0x9: case 0xA: case 0xB: case 0xF:
+ /* Shouldn't happen. */
+ break;
+
+ case 0xC: case 0xD:
+ /* 110xxxxx 10xxxxxx */
+ if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
+ unsigned char high_five = ch & 0x1F;
+ unsigned char low_six = ch2 & 0x3F;
+ result = (high_five << 6) + low_six;
+ length = 2;
+ break;
+ }
+ break;
+
+ case 0xE:
+ /* 1110xxxx 10xxxxxx 10xxxxxx */
+ if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
+ if (((ch3 = ptr[2]) & 0xC0) == 0x80) {
+ unsigned char high_four = ch & 0x0f;
+ unsigned char mid_six = ch2 & 0x3f;
+ unsigned char low_six = ch3 & 0x3f;
+ result = (((high_four << 6) + mid_six) << 6) + low_six;
+ length = 3;
+ }
+ }
+ break;
+ } /* end of switch */
+
+ if (length <= 0) {
+ *value = ptr[0]; /* default bad result; */
+ return (char*)(ptr + 1); // make progress somehow
+ }
+
+ *value = result;
+
+ // The assert is correct but the .class file is wrong
+ // assert(UNICODE::utf8_size(result) == length, "checking reverse computation");
+ return (char *)(ptr + length);
+}
+
+char* UTF8::next_character(const char* str, jint* value) {
+ unsigned const char *ptr = (const unsigned char *)str;
+ /* See if it's legal supplementary character:
+ 11101101 1010xxxx 10xxxxxx 11101101 1011xxxx 10xxxxxx */
+ if (is_supplementary_character(ptr)) {
+ *value = get_supplementary_character(ptr);
+ return (char *)(ptr + 6);
+ }
+ jchar result;
+ char* next_ch = next(str, &result);
+ *value = result;
+ return next_ch;
+}
+
+// Count bytes of the form 10xxxxxx and deduct this count
+// from the total byte count. The utf8 string must be in
+// legal form which has been verified in the format checker.
+int UTF8::unicode_length(const char* str, int len) {
+ int num_chars = len;
+ for (int i = 0; i < len; i++) {
+ if ((str[i] & 0xC0) == 0x80) {
+ --num_chars;
+ }
+ }
+ return num_chars;
+}
+
+// Count bytes of the utf8 string except those in form
+// 10xxxxxx which only appear in multibyte characters.
+// The utf8 string must be in legal form and has been
+// verified in the format checker.
+int UTF8::unicode_length(const char* str) {
+ int num_chars = 0;
+ for (const char* p = str; *p; p++) {
+ if (((*p) & 0xC0) != 0x80) {
+ num_chars++;
+ }
+ }
+ return num_chars;
+}
+
+// Writes a jchar a utf8 and returns the end
+static u_char* utf8_write(u_char* base, jchar ch) {
+ if ((ch != 0) && (ch <=0x7f)) {
+ base[0] = (u_char) ch;
+ return base + 1;
+ }
+
+ if (ch <= 0x7FF) {
+ /* 11 bits or less. */
+ unsigned char high_five = ch >> 6;
+ unsigned char low_six = ch & 0x3F;
+ base[0] = high_five | 0xC0; /* 110xxxxx */
+ base[1] = low_six | 0x80; /* 10xxxxxx */
+ return base + 2;
+ }
+ /* possibly full 16 bits. */
+ char high_four = ch >> 12;
+ char mid_six = (ch >> 6) & 0x3F;
+ char low_six = ch & 0x3f;
+ base[0] = high_four | 0xE0; /* 1110xxxx */
+ base[1] = mid_six | 0x80; /* 10xxxxxx */
+ base[2] = low_six | 0x80; /* 10xxxxxx */
+ return base + 3;
+}
+
+void UTF8::convert_to_unicode(const char* utf8_str, jchar* unicode_str, int unicode_length) {
+ unsigned char ch;
+ const char *ptr = (const char *)utf8_str;
+ int index = 0;
+
+ /* ASCII case loop optimization */
+ for (; index < unicode_length; index++) {
+ if((ch = ptr[0]) > 0x7F) { break; }
+ unicode_str[index] = ch;
+ ptr = (const char *)(ptr + 1);
+ }
+
+ for (; index < unicode_length; index++) {
+ ptr = UTF8::next(ptr, &unicode_str[index]);
+ }
+}
+
+// Returns NULL if 'c' it not found. This only works as long
+// as 'c' is an ASCII character
+jbyte* UTF8::strrchr(jbyte* base, int length, jbyte c) {
+ assert(length >= 0, "sanity check");
+ assert(c >= 0, "does not work for non-ASCII characters");
+ // Skip backwards in string until 'c' is found or end is reached
+ while(--length >= 0 && base[length] != c);
+ return (length < 0) ? NULL : &base[length];
+}
+
+bool UTF8::equal(jbyte* base1, int length1, jbyte* base2, int length2) {
+ // Length must be the same
+ if (length1 != length2) return false;
+ for (int i = 0; i < length1; i++) {
+ if (base1[i] != base2[i]) return false;
+ }
+ return true;
+}
+
+bool UTF8::is_supplementary_character(const unsigned char* str) {
+ return ((str[0] & 0xFF) == 0xED) && ((str[1] & 0xF0) == 0xA0) && ((str[2] & 0xC0) == 0x80)
+ && ((str[3] & 0xFF) == 0xED) && ((str[4] & 0xF0) == 0xB0) && ((str[5] & 0xC0) == 0x80);
+}
+
+jint UTF8::get_supplementary_character(const unsigned char* str) {
+ return 0x10000 + ((str[1] & 0x0f) << 16) + ((str[2] & 0x3f) << 10)
+ + ((str[4] & 0x0f) << 6) + (str[5] & 0x3f);
+}
+
+
+//-------------------------------------------------------------------------------------
+
+
+int UNICODE::utf8_size(jchar c) {
+ if ((0x0001 <= c) && (c <= 0x007F)) return 1;
+ if (c <= 0x07FF) return 2;
+ return 3;
+}
+
+int UNICODE::utf8_length(jchar* base, int length) {
+ int result = 0;
+ for (int index = 0; index < length; index++) {
+ jchar c = base[index];
+ if ((0x0001 <= c) && (c <= 0x007F)) result += 1;
+ else if (c <= 0x07FF) result += 2;
+ else result += 3;
+ }
+ return result;
+}
+
+char* UNICODE::as_utf8(jchar* base, int length) {
+ int utf8_len = utf8_length(base, length);
+ u_char* result = NEW_RESOURCE_ARRAY(u_char, utf8_len + 1);
+ u_char* p = result;
+ for (int index = 0; index < length; index++) {
+ p = utf8_write(p, base[index]);
+ }
+ *p = '\0';
+ assert(p == &result[utf8_len], "length prediction must be correct");
+ return (char*) result;
+}
+
+char* UNICODE::as_utf8(jchar* base, int length, char* buf, int buflen) {
+ u_char* p = (u_char*)buf;
+ u_char* end = (u_char*)buf + buflen;
+ for (int index = 0; index < length; index++) {
+ jchar c = base[index];
+ if (p + utf8_size(c) >= end) break; // string is truncated
+ p = utf8_write(p, base[index]);
+ }
+ *p = '\0';
+ return buf;
+}
+
+void UNICODE::convert_to_utf8(const jchar* base, int length, char* utf8_buffer) {
+ for(int index = 0; index < length; index++) {
+ utf8_buffer = (char*)utf8_write((u_char*)utf8_buffer, base[index]);
+ }
+ *utf8_buffer = '\0';
+}
diff --git a/src/share/vm/utilities/utf8.hpp b/src/share/vm/utilities/utf8.hpp
new file mode 100644
index 000000000..baa8e7795
--- /dev/null
+++ b/src/share/vm/utilities/utf8.hpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1997-2003 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// Low-level interface for UTF8 strings
+
+class UTF8 : AllStatic {
+ public:
+ // returns the unicode length of a 0-terminated uft8 string
+ static int unicode_length(const char* uft8_str);
+
+ // returns the unicode length of a non-0-terminated uft8 string
+ static int unicode_length(const char* uft8_str, int len);
+
+ // converts a uft8 string to a unicode string
+ static void convert_to_unicode(const char* utf8_str, jchar* unicode_buffer, int unicode_length);
+
+ // decodes the current utf8 character, stores the result in value,
+ // and returns the end of the current uft8 chararacter.
+ static char* next(const char* str, jchar* value);
+
+ // decodes the current utf8 character, gets the supplementary character instead of
+ // the surrogate pair when seeing a supplementary character in string,
+ // stores the result in value, and returns the end of the current uft8 chararacter.
+ static char* next_character(const char* str, jint* value);
+
+ // Utility methods
+ static jbyte* strrchr(jbyte* base, int length, jbyte c);
+ static bool equal(jbyte* base1, int length1, jbyte* base2, int length2);
+ static bool is_supplementary_character(const unsigned char* str);
+ static jint get_supplementary_character(const unsigned char* str);
+};
+
+
+// Low-level interface for UNICODE strings
+
+// A unicode string represents a string in the UTF-16 format in which supplementary
+// characters are represented by surrogate pairs. Index values refer to char code
+// units, so a supplementary character uses two positions in a unicode string.
+
+class UNICODE : AllStatic {
+ public:
+ // returns the utf8 size of a unicode character
+ static int utf8_size(jchar c);
+
+ // returns the utf8 length of a unicode string
+ static int utf8_length(jchar* base, int length);
+
+ // converts a unicode string to utf8 string
+ static void convert_to_utf8(const jchar* base, int length, char* utf8_buffer);
+
+ // converts a unicode string to a utf8 string; result is allocated
+ // in resource area unless a buffer is provided.
+ static char* as_utf8(jchar* base, int length);
+ static char* as_utf8(jchar* base, int length, char* buf, int buflen);
+};
diff --git a/src/share/vm/utilities/vmError.cpp b/src/share/vm/utilities/vmError.cpp
new file mode 100644
index 000000000..17dfb6b0c
--- /dev/null
+++ b/src/share/vm/utilities/vmError.cpp
@@ -0,0 +1,875 @@
+/*
+ * Copyright 2003-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_vmError.cpp.incl"
+
+// List of environment variables that should be reported in error log file.
+const char *env_list[] = {
+ // All platforms
+ "JAVA_HOME", "JRE_HOME", "JAVA_TOOL_OPTIONS", "_JAVA_OPTIONS", "CLASSPATH",
+ "JAVA_COMPILER", "PATH", "USERNAME",
+
+ // Env variables that are defined on Solaris/Linux
+ "LD_LIBRARY_PATH", "LD_PRELOAD", "SHELL", "DISPLAY",
+ "HOSTTYPE", "OSTYPE", "ARCH", "MACHTYPE",
+
+ // defined on Linux
+ "LD_ASSUME_KERNEL", "_JAVA_SR_SIGNUM",
+
+ // defined on Windows
+ "OS", "PROCESSOR_IDENTIFIER", "_ALT_JAVA_HOME_DIR",
+
+ (const char *)0
+};
+
+// Fatal error handler for internal errors and crashes.
+//
+// The default behavior of fatal error handler is to print a brief message
+// to standard out (defaultStream::output_fd()), then save detailed information
+// into an error report file (hs_err_pid<pid>.log) and abort VM. If multiple
+// threads are having troubles at the same time, only one error is reported.
+// The thread that is reporting error will abort VM when it is done, all other
+// threads are blocked forever inside report_and_die().
+
+// Constructor for crashes
+VMError::VMError(Thread* thread, int sig, address pc, void* siginfo, void* context) {
+ _thread = thread;
+ _id = sig;
+ _pc = pc;
+ _siginfo = siginfo;
+ _context = context;
+
+ _verbose = false;
+ _current_step = 0;
+ _current_step_info = NULL;
+
+ _message = "";
+ _filename = NULL;
+ _lineno = 0;
+
+ _size = 0;
+}
+
+// Constructor for internal errors
+VMError::VMError(Thread* thread, const char* message, const char* filename, int lineno) {
+ _thread = thread;
+ _id = internal_error; // set it to a value that's not an OS exception/signal
+ _filename = filename;
+ _lineno = lineno;
+ _message = message;
+
+ _verbose = false;
+ _current_step = 0;
+ _current_step_info = NULL;
+
+ _pc = NULL;
+ _siginfo = NULL;
+ _context = NULL;
+
+ _size = 0;
+}
+
+// Constructor for OOM errors
+VMError::VMError(Thread* thread, size_t size, const char* message, const char* filename, int lineno) {
+ _thread = thread;
+ _id = oom_error; // set it to a value that's not an OS exception/signal
+ _filename = filename;
+ _lineno = lineno;
+ _message = message;
+
+ _verbose = false;
+ _current_step = 0;
+ _current_step_info = NULL;
+
+ _pc = NULL;
+ _siginfo = NULL;
+ _context = NULL;
+
+ _size = size;
+}
+
+
+// Constructor for non-fatal errors
+VMError::VMError(const char* message) {
+ _thread = NULL;
+ _id = internal_error; // set it to a value that's not an OS exception/signal
+ _filename = NULL;
+ _lineno = 0;
+ _message = message;
+
+ _verbose = false;
+ _current_step = 0;
+ _current_step_info = NULL;
+
+ _pc = NULL;
+ _siginfo = NULL;
+ _context = NULL;
+
+ _size = 0;
+}
+
+// -XX:OnError=<string>, where <string> can be a list of commands, separated
+// by ';'. "%p" is replaced by current process id (pid); "%%" is replaced by
+// a single "%". Some examples:
+//
+// -XX:OnError="pmap %p" // show memory map
+// -XX:OnError="gcore %p; dbx - %p" // dump core and launch debugger
+// -XX:OnError="cat hs_err_pid%p.log | mail my_email@sun.com"
+// -XX:OnError="kill -9 %p" // ?#!@#
+
+// A simple parser for -XX:OnError, usage:
+// ptr = OnError;
+// while ((cmd = next_OnError_command(buffer, sizeof(buffer), &ptr) != NULL)
+// ... ...
+static char* next_OnError_command(char* buf, int buflen, const char** ptr) {
+ if (ptr == NULL || *ptr == NULL) return NULL;
+
+ const char* cmd = *ptr;
+
+ // skip leading blanks or ';'
+ while (*cmd == ' ' || *cmd == ';') cmd++;
+
+ if (*cmd == '\0') return NULL;
+
+ const char * cmdend = cmd;
+ while (*cmdend != '\0' && *cmdend != ';') cmdend++;
+
+ Arguments::copy_expand_pid(cmd, cmdend - cmd, buf, buflen);
+
+ *ptr = (*cmdend == '\0' ? cmdend : cmdend + 1);
+ return buf;
+}
+
+
+static void print_bug_submit_message(outputStream *out, Thread *thread) {
+ if (out == NULL) return;
+ out->print_raw_cr("# If you would like to submit a bug report, please visit:");
+ out->print_raw ("# ");
+ out->print_raw_cr(Arguments::java_vendor_url_bug());
+ // If the crash is in native code, encourage user to submit a bug to the
+ // provider of that code.
+ if (thread && thread->is_Java_thread()) {
+ JavaThread* jt = (JavaThread*)thread;
+ if (jt->thread_state() == _thread_in_native) {
+ out->print_cr("# The crash happened outside the Java Virtual Machine in native code.\n# See problematic frame for where to report the bug.");
+ }
+ }
+ out->print_raw_cr("#");
+}
+
+
+// Return a string to describe the error
+char* VMError::error_string(char* buf, int buflen) {
+ char signame_buf[64];
+ const char *signame = os::exception_name(_id, signame_buf, sizeof(signame_buf));
+
+ if (signame) {
+ jio_snprintf(buf, buflen,
+ "%s (0x%x) at pc=" PTR_FORMAT ", pid=%d, tid=" UINTX_FORMAT,
+ signame, _id, _pc,
+ os::current_process_id(), os::current_thread_id());
+ } else {
+ if (_filename != NULL && _lineno > 0) {
+ // skip directory names
+ char separator = os::file_separator()[0];
+ const char *p = strrchr(_filename, separator);
+
+ jio_snprintf(buf, buflen,
+ "Internal Error at %s:%d, pid=%d, tid=" UINTX_FORMAT " \nError: %s",
+ p ? p + 1 : _filename, _lineno,
+ os::current_process_id(), os::current_thread_id(),
+ _message ? _message : "");
+ } else {
+ jio_snprintf(buf, buflen,
+ "Internal Error (0x%x), pid=%d, tid=" UINTX_FORMAT,
+ _id, os::current_process_id(), os::current_thread_id());
+ }
+ }
+
+ return buf;
+}
+
+
+// This is the main function to report a fatal error. Only one thread can
+// call this function, so we don't need to worry about MT-safety. But it's
+// possible that the error handler itself may crash or die on an internal
+// error, for example, when the stack/heap is badly damaged. We must be
+// able to handle recursive errors that happen inside error handler.
+//
+// Error reporting is done in several steps. If a crash or internal error
+// occurred when reporting an error, the nested signal/exception handler
+// can skip steps that are already (or partially) done. Error reporting will
+// continue from the next step. This allows us to retrieve and print
+// information that may be unsafe to get after a fatal error. If it happens,
+// you may find nested report_and_die() frames when you look at the stack
+// in a debugger.
+//
+// In general, a hang in error handler is much worse than a crash or internal
+// error, as it's harder to recover from a hang. Deadlock can happen if we
+// try to grab a lock that is already owned by current thread, or if the
+// owner is blocked forever (e.g. in os::infinite_sleep()). If possible, the
+// error handler and all the functions it called should avoid grabbing any
+// lock. An important thing to notice is that memory allocation needs a lock.
+//
+// We should avoid using large stack allocated buffers. Many errors happen
+// when stack space is already low. Making things even worse is that there
+// could be nested report_and_die() calls on stack (see above). Only one
+// thread can report error, so large buffers are statically allocated in data
+// segment.
+
+void VMError::report(outputStream* st) {
+# define BEGIN if (_current_step == 0) { _current_step = 1;
+# define STEP(n, s) } if (_current_step < n) { _current_step = n; _current_step_info = s;
+# define END }
+
+ // don't allocate large buffer on stack
+ static char buf[O_BUFLEN];
+
+ BEGIN
+
+ STEP(10, "(printing unexpected error message)")
+
+ st->print_cr("#");
+ st->print_cr("# An unexpected error has been detected by Java Runtime Environment:");
+
+ STEP(15, "(printing type of error)")
+
+ switch(_id) {
+ case oom_error:
+ st->print_cr("#");
+ st->print("# java.lang.OutOfMemoryError: ");
+ if (_size) {
+ st->print("requested ");
+ sprintf(buf,"%d",_size);
+ st->print(buf);
+ st->print(" bytes");
+ if (_message != NULL) {
+ st->print(" for ");
+ st->print(_message);
+ }
+ st->print_cr(". Out of swap space?");
+ } else {
+ if (_message != NULL)
+ st->print_cr(_message);
+ }
+ break;
+ case internal_error:
+ default:
+ break;
+ }
+
+ STEP(20, "(printing exception/signal name)")
+
+ st->print_cr("#");
+ st->print("# ");
+ // Is it an OS exception/signal?
+ if (os::exception_name(_id, buf, sizeof(buf))) {
+ st->print("%s", buf);
+ st->print(" (0x%x)", _id); // signal number
+ st->print(" at pc=" PTR_FORMAT, _pc);
+ } else {
+ st->print("Internal Error");
+ if (_filename != NULL && _lineno > 0) {
+#ifdef PRODUCT
+ // In product mode chop off pathname?
+ char separator = os::file_separator()[0];
+ const char *p = strrchr(_filename, separator);
+ const char *file = p ? p+1 : _filename;
+#else
+ const char *file = _filename;
+#endif
+ size_t len = strlen(file);
+ size_t buflen = sizeof(buf);
+
+ strncpy(buf, file, buflen);
+ if (len + 10 < buflen) {
+ sprintf(buf + len, ":" SIZE_FORMAT, _lineno);
+ }
+ st->print(" (%s)", buf);
+ } else {
+ st->print(" (0x%x)", _id);
+ }
+ }
+
+ STEP(30, "(printing current thread and pid)")
+
+ // process id, thread id
+ st->print(", pid=%d", os::current_process_id());
+ st->print(", tid=" UINTX_FORMAT, os::current_thread_id());
+ st->cr();
+
+ STEP(40, "(printing error message)")
+
+ // error message
+ if (_message && _message[0] != '\0') {
+ st->print_cr("# Error: %s", _message);
+ }
+
+ STEP(50, "(printing Java version string)")
+
+ // VM version
+ st->print_cr("#");
+ st->print_cr("# Java VM: %s (%s %s %s)",
+ Abstract_VM_Version::vm_name(),
+ Abstract_VM_Version::vm_release(),
+ Abstract_VM_Version::vm_info_string(),
+ Abstract_VM_Version::vm_platform_string()
+ );
+
+ STEP(60, "(printing problematic frame)")
+
+ // Print current frame if we have a context (i.e. it's a crash)
+ if (_context) {
+ st->print_cr("# Problematic frame:");
+ st->print("# ");
+ frame fr = os::fetch_frame_from_context(_context);
+ fr.print_on_error(st, buf, sizeof(buf));
+ st->cr();
+ st->print_cr("#");
+ }
+
+ STEP(65, "(printing bug submit message)")
+
+ if (_verbose) print_bug_submit_message(st, _thread);
+
+ STEP(70, "(printing thread)" )
+
+ if (_verbose) {
+ st->cr();
+ st->print_cr("--------------- T H R E A D ---------------");
+ st->cr();
+ }
+
+ STEP(80, "(printing current thread)" )
+
+ // current thread
+ if (_verbose) {
+ if (_thread) {
+ st->print("Current thread (" PTR_FORMAT "): ", _thread);
+ _thread->print_on_error(st, buf, sizeof(buf));
+ st->cr();
+ } else {
+ st->print_cr("Current thread is native thread");
+ }
+ st->cr();
+ }
+
+ STEP(90, "(printing siginfo)" )
+
+ // signal no, signal code, address that caused the fault
+ if (_verbose && _siginfo) {
+ os::print_siginfo(st, _siginfo);
+ st->cr();
+ }
+
+ STEP(100, "(printing registers, top of stack, instructions near pc)")
+
+ // registers, top of stack, instructions near pc
+ if (_verbose && _context) {
+ os::print_context(st, _context);
+ st->cr();
+ }
+
+ STEP(110, "(printing stack bounds)" )
+
+ if (_verbose) {
+ st->print("Stack: ");
+
+ address stack_top;
+ size_t stack_size;
+
+ if (_thread) {
+ stack_top = _thread->stack_base();
+ stack_size = _thread->stack_size();
+ } else {
+ stack_top = os::current_stack_base();
+ stack_size = os::current_stack_size();
+ }
+
+ address stack_bottom = stack_top - stack_size;
+ st->print("[" PTR_FORMAT "," PTR_FORMAT "]", stack_bottom, stack_top);
+
+ frame fr = _context ? os::fetch_frame_from_context(_context)
+ : os::current_frame();
+
+ if (fr.sp()) {
+ st->print(", sp=" PTR_FORMAT, fr.sp());
+ st->print(", free space=%dk",
+ ((intptr_t)fr.sp() - (intptr_t)stack_bottom) >> 10);
+ }
+
+ st->cr();
+ }
+
+ STEP(120, "(printing native stack)" )
+
+ if (_verbose) {
+ frame fr = _context ? os::fetch_frame_from_context(_context)
+ : os::current_frame();
+
+ // see if it's a valid frame
+ if (fr.pc()) {
+ st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
+
+ int count = 0;
+
+ while (count++ < StackPrintLimit) {
+ fr.print_on_error(st, buf, sizeof(buf));
+ st->cr();
+ if (os::is_first_C_frame(&fr)) break;
+ fr = os::get_sender_for_C_frame(&fr);
+ }
+
+ if (count > StackPrintLimit) {
+ st->print_cr("...<more frames>...");
+ }
+
+ st->cr();
+ }
+ }
+
+ STEP(130, "(printing Java stack)" )
+
+ if (_verbose && _thread && _thread->is_Java_thread()) {
+ JavaThread* jt = (JavaThread*)_thread;
+ if (jt->has_last_Java_frame()) {
+ st->print_cr("Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)");
+ for(StackFrameStream sfs(jt); !sfs.is_done(); sfs.next()) {
+ sfs.current()->print_on_error(st, buf, sizeof(buf));
+ st->cr();
+ }
+ }
+ }
+
+ STEP(140, "(printing VM operation)" )
+
+ if (_verbose && _thread && _thread->is_VM_thread()) {
+ VMThread* t = (VMThread*)_thread;
+ VM_Operation* op = t->vm_operation();
+ if (op) {
+ op->print_on_error(st);
+ st->cr();
+ st->cr();
+ }
+ }
+
+ STEP(150, "(printing current compile task)" )
+
+ if (_verbose && _thread && _thread->is_Compiler_thread()) {
+ CompilerThread* t = (CompilerThread*)_thread;
+ if (t->task()) {
+ st->cr();
+ st->print_cr("Current CompileTask:");
+ t->task()->print_line_on_error(st, buf, sizeof(buf));
+ st->cr();
+ }
+ }
+
+ STEP(160, "(printing process)" )
+
+ if (_verbose) {
+ st->cr();
+ st->print_cr("--------------- P R O C E S S ---------------");
+ st->cr();
+ }
+
+ STEP(170, "(printing all threads)" )
+
+ // all threads
+ if (_verbose && _thread) {
+ Threads::print_on_error(st, _thread, buf, sizeof(buf));
+ st->cr();
+ }
+
+ STEP(175, "(printing VM state)" )
+
+ if (_verbose) {
+ // Safepoint state
+ st->print("VM state:");
+
+ if (SafepointSynchronize::is_synchronizing()) st->print("synchronizing");
+ else if (SafepointSynchronize::is_at_safepoint()) st->print("at safepoint");
+ else st->print("not at safepoint");
+
+ // Also see if error occurred during initialization or shutdown
+ if (!Universe::is_fully_initialized()) {
+ st->print(" (not fully initialized)");
+ } else if (VM_Exit::vm_exited()) {
+ st->print(" (shutting down)");
+ } else {
+ st->print(" (normal execution)");
+ }
+ st->cr();
+ st->cr();
+ }
+
+ STEP(180, "(printing owned locks on error)" )
+
+ // mutexes/monitors that currently have an owner
+ if (_verbose) {
+ print_owned_locks_on_error(st);
+ st->cr();
+ }
+
+ STEP(190, "(printing heap information)" )
+
+ if (_verbose && Universe::is_fully_initialized()) {
+ // print heap information before vm abort
+ Universe::print_on(st);
+ st->cr();
+ }
+
+ STEP(200, "(printing dynamic libraries)" )
+
+ if (_verbose) {
+ // dynamic libraries, or memory map
+ os::print_dll_info(st);
+ st->cr();
+ }
+
+ STEP(210, "(printing VM options)" )
+
+ if (_verbose) {
+ // VM options
+ Arguments::print_on(st);
+ st->cr();
+ }
+
+ STEP(220, "(printing environment variables)" )
+
+ if (_verbose) {
+ os::print_environment_variables(st, env_list, buf, sizeof(buf));
+ st->cr();
+ }
+
+ STEP(225, "(printing signal handlers)" )
+
+ if (_verbose) {
+ os::print_signal_handlers(st, buf, sizeof(buf));
+ st->cr();
+ }
+
+ STEP(230, "" )
+
+ if (_verbose) {
+ st->cr();
+ st->print_cr("--------------- S Y S T E M ---------------");
+ st->cr();
+ }
+
+ STEP(240, "(printing OS information)" )
+
+ if (_verbose) {
+ os::print_os_info(st);
+ st->cr();
+ }
+
+ STEP(250, "(printing CPU info)" )
+ if (_verbose) {
+ os::print_cpu_info(st);
+ st->cr();
+ }
+
+ STEP(260, "(printing memory info)" )
+
+ if (_verbose) {
+ os::print_memory_info(st);
+ st->cr();
+ }
+
+ STEP(270, "(printing internal vm info)" )
+
+ if (_verbose) {
+ st->print_cr("vm_info: %s", Abstract_VM_Version::internal_vm_info_string());
+ st->cr();
+ }
+
+ STEP(280, "(printing date and time)" )
+
+ if (_verbose) {
+ os::print_date_and_time(st);
+ st->cr();
+ }
+
+ END
+
+# undef BEGIN
+# undef STEP
+# undef END
+}
+
+
+void VMError::report_and_die() {
+ // Don't allocate large buffer on stack
+ static char buffer[O_BUFLEN];
+
+ // First error, and its thread id. We must be able to handle native thread,
+ // so use thread id instead of Thread* to identify thread.
+ static VMError* first_error;
+ static jlong first_error_tid;
+
+ // An error could happen before tty is initialized or after it has been
+ // destroyed. Here we use a very simple unbuffered fdStream for printing.
+ // Only out.print_raw() and out.print_raw_cr() should be used, as other
+ // printing methods need to allocate large buffer on stack. To format a
+ // string, use jio_snprintf() with a static buffer or use staticBufferStream.
+ static fdStream out(defaultStream::output_fd());
+
+ // How many errors occurred in error handler when reporting first_error.
+ static int recursive_error_count;
+
+ // We will first print a brief message to standard out (verbose = false),
+ // then save detailed information in log file (verbose = true).
+ static bool out_done = false; // done printing to standard out
+ static bool log_done = false; // done saving error log
+ static fdStream log; // error log
+
+ if (SuppressFatalErrorMessage) {
+ os::abort();
+ }
+ jlong mytid = os::current_thread_id();
+ if (first_error == NULL &&
+ Atomic::cmpxchg_ptr(this, &first_error, NULL) == NULL) {
+
+ // first time
+ first_error_tid = mytid;
+ set_error_reported();
+
+ if (ShowMessageBoxOnError) {
+ show_message_box(buffer, sizeof(buffer));
+
+ // User has asked JVM to abort. Reset ShowMessageBoxOnError so the
+ // WatcherThread can kill JVM if the error handler hangs.
+ ShowMessageBoxOnError = false;
+ }
+
+ // reset signal handlers or exception filter; make sure recursive crashes
+ // are handled properly.
+ reset_signal_handlers();
+
+ } else {
+ // This is not the first error, see if it happened in a different thread
+ // or in the same thread during error reporting.
+ if (first_error_tid != mytid) {
+ jio_snprintf(buffer, sizeof(buffer),
+ "[thread " INT64_FORMAT " also had an error]",
+ mytid);
+ out.print_raw_cr(buffer);
+
+ // error reporting is not MT-safe, block current thread
+ os::infinite_sleep();
+
+ } else {
+ if (recursive_error_count++ > 30) {
+ out.print_raw_cr("[Too many errors, abort]");
+ os::die();
+ }
+
+ jio_snprintf(buffer, sizeof(buffer),
+ "[error occurred during error reporting %s, id 0x%x]",
+ first_error ? first_error->_current_step_info : "",
+ _id);
+ if (log.is_open()) {
+ log.cr();
+ log.print_raw_cr(buffer);
+ log.cr();
+ } else {
+ out.cr();
+ out.print_raw_cr(buffer);
+ out.cr();
+ }
+ }
+ }
+
+ // print to screen
+ if (!out_done) {
+ first_error->_verbose = false;
+
+ staticBufferStream sbs(buffer, sizeof(buffer), &out);
+ first_error->report(&sbs);
+
+ out_done = true;
+
+ first_error->_current_step = 0; // reset current_step
+ first_error->_current_step_info = ""; // reset current_step string
+ }
+
+ // print to error log file
+ if (!log_done) {
+ first_error->_verbose = true;
+
+ // see if log file is already open
+ if (!log.is_open()) {
+ // open log file
+ int fd = -1;
+
+ if (ErrorFile != NULL) {
+ bool copy_ok =
+ Arguments::copy_expand_pid(ErrorFile, strlen(ErrorFile), buffer, sizeof(buffer));
+ if (copy_ok) {
+ fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ }
+ }
+
+ if (fd == -1) {
+ const char *cwd = os::get_current_directory(buffer, sizeof(buffer));
+ size_t len = strlen(cwd);
+ // either user didn't specify, or the user's location failed,
+ // so use the default name in the current directory
+ jio_snprintf(&buffer[len], sizeof(buffer)-len, "%shs_err_pid%u.log",
+ os::file_separator(), os::current_process_id());
+ fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ }
+
+ if (fd == -1) {
+ // try temp directory
+ const char * tmpdir = os::get_temp_directory();
+ jio_snprintf(buffer, sizeof(buffer), "%shs_err_pid%u.log",
+ (tmpdir ? tmpdir : ""), os::current_process_id());
+ fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ }
+
+ if (fd != -1) {
+ out.print_raw("# An error report file with more information is saved as:\n# ");
+ out.print_raw_cr(buffer);
+ os::set_error_file(buffer);
+
+ log.set_fd(fd);
+ } else {
+ out.print_raw_cr("# Can not save log file, dump to screen..");
+ log.set_fd(defaultStream::output_fd());
+ }
+ }
+
+ staticBufferStream sbs(buffer, O_BUFLEN, &log);
+ first_error->report(&sbs);
+ first_error->_current_step = 0; // reset current_step
+ first_error->_current_step_info = ""; // reset current_step string
+
+ if (log.fd() != defaultStream::output_fd()) {
+ close(log.fd());
+ }
+
+ log.set_fd(-1);
+ log_done = true;
+ }
+
+
+ static bool skip_OnError = false;
+ if (!skip_OnError && OnError && OnError[0]) {
+ skip_OnError = true;
+
+ out.print_raw_cr("#");
+ out.print_raw ("# -XX:OnError=\"");
+ out.print_raw (OnError);
+ out.print_raw_cr("\"");
+
+ char* cmd;
+ const char* ptr = OnError;
+ while ((cmd = next_OnError_command(buffer, sizeof(buffer), &ptr)) != NULL){
+ out.print_raw ("# Executing ");
+#if defined(LINUX)
+ out.print_raw ("/bin/sh -c ");
+#elif defined(SOLARIS)
+ out.print_raw ("/usr/bin/sh -c ");
+#endif
+ out.print_raw ("\"");
+ out.print_raw (cmd);
+ out.print_raw_cr("\" ...");
+
+ os::fork_and_exec(cmd);
+ }
+
+ // done with OnError
+ OnError = NULL;
+ }
+
+ static bool skip_bug_url = false;
+ if (!skip_bug_url) {
+ skip_bug_url = true;
+
+ out.print_raw_cr("#");
+ print_bug_submit_message(&out, _thread);
+ }
+
+ if (!UseOSErrorReporting) {
+ // os::abort() will call abort hooks, try it first.
+ static bool skip_os_abort = false;
+ if (!skip_os_abort) {
+ skip_os_abort = true;
+ os::abort();
+ }
+
+ // if os::abort() doesn't abort, try os::die();
+ os::die();
+ }
+}
+
+/*
+ * OnOutOfMemoryError scripts/commands executed while VM is a safepoint - this
+ * ensures utilities such as jmap can observe the process is a consistent state.
+ */
+class VM_ReportJavaOutOfMemory : public VM_Operation {
+ private:
+ VMError *_err;
+ public:
+ VM_ReportJavaOutOfMemory(VMError *err) { _err = err; }
+ VMOp_Type type() const { return VMOp_ReportJavaOutOfMemory; }
+ void doit();
+};
+
+void VM_ReportJavaOutOfMemory::doit() {
+ // Don't allocate large buffer on stack
+ static char buffer[O_BUFLEN];
+
+ tty->print_cr("#");
+ tty->print_cr("# java.lang.OutOfMemoryError: %s", _err->message());
+ tty->print_cr("# -XX:OnOutOfMemoryError=\"%s\"", OnOutOfMemoryError);
+
+ // make heap parsability
+ Universe::heap()->ensure_parsability(false); // no need to retire TLABs
+
+ char* cmd;
+ const char* ptr = OnOutOfMemoryError;
+ while ((cmd = next_OnError_command(buffer, sizeof(buffer), &ptr)) != NULL){
+ tty->print("# Executing ");
+#if defined(LINUX)
+ tty->print ("/bin/sh -c ");
+#elif defined(SOLARIS)
+ tty->print ("/usr/bin/sh -c ");
+#endif
+ tty->print_cr("\"%s\"...", cmd);
+
+ os::fork_and_exec(cmd);
+ }
+}
+
+void VMError::report_java_out_of_memory() {
+ if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
+ MutexLocker ml(Heap_lock);
+ VM_ReportJavaOutOfMemory op(this);
+ VMThread::execute(&op);
+ }
+}
diff --git a/src/share/vm/utilities/vmError.hpp b/src/share/vm/utilities/vmError.hpp
new file mode 100644
index 000000000..414bc7f21
--- /dev/null
+++ b/src/share/vm/utilities/vmError.hpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2003-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+class VM_ReportJavaOutOfMemory;
+
+class VMError : public StackObj {
+ friend class VM_ReportJavaOutOfMemory;
+
+ enum ErrorType {
+ internal_error = 0xe0000000,
+ oom_error = 0xe0000001
+ };
+ int _id; // Solaris/Linux signals: 0 - SIGRTMAX
+ // Windows exceptions: 0xCxxxxxxx system errors
+ // 0x8xxxxxxx system warnings
+
+ const char * _message;
+
+ Thread * _thread; // NULL if it's native thread
+
+
+ // additional info for crashes
+ address _pc; // faulting PC
+ void * _siginfo; // ExceptionRecord on Windows,
+ // siginfo_t on Solaris/Linux
+ void * _context; // ContextRecord on Windows,
+ // ucontext_t on Solaris/Linux
+
+ // additional info for VM internal errors
+ const char * _filename;
+ int _lineno;
+
+ // used by fatal error handler
+ int _current_step;
+ const char * _current_step_info;
+ int _verbose;
+
+ // used by reporting about OOM
+ size_t _size;
+
+ // set signal handlers on Solaris/Linux or the default exception filter
+ // on Windows, to handle recursive crashes.
+ void reset_signal_handlers();
+
+ // handle -XX:+ShowMessageBoxOnError. buf is used to format the message string
+ void show_message_box(char* buf, int buflen);
+
+ // generate an error report
+ void report(outputStream* st);
+
+ // accessor
+ const char* message() { return _message; }
+
+public:
+ // Constructor for crashes
+ VMError(Thread* thread, int sig, address pc, void* siginfo, void* context);
+ // Constructor for VM internal errors
+ VMError(Thread* thread, const char* message, const char* filename, int lineno);
+
+ // Constructors for VM OOM errors
+ VMError(Thread* thread, size_t size, const char* message, const char* filename, int lineno);
+ // Constructor for non-fatal errors
+ VMError(const char* message);
+
+ // return a string to describe the error
+ char *error_string(char* buf, int buflen);
+
+ // main error reporting function
+ void report_and_die();
+
+ // reporting OutOfMemoryError
+ void report_java_out_of_memory();
+
+ // returns original flags for signal, if it was resetted, or -1 if
+ // signal was not changed by error reporter
+ static int get_resetted_sigflags(int sig);
+
+ // returns original handler for signal, if it was resetted, or NULL if
+ // signal was not changed by error reporter
+ static address get_resetted_sighandler(int sig);
+};
diff --git a/src/share/vm/utilities/workgroup.cpp b/src/share/vm/utilities/workgroup.cpp
new file mode 100644
index 000000000..bdf650bbc
--- /dev/null
+++ b/src/share/vm/utilities/workgroup.cpp
@@ -0,0 +1,444 @@
+/*
+ * Copyright 2001-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_workgroup.cpp.incl"
+
+// Definitions of WorkGang methods.
+
+AbstractWorkGang::AbstractWorkGang(const char* name,
+ bool are_GC_threads) :
+ _name(name),
+ _are_GC_threads(are_GC_threads) {
+ // Other initialization.
+ _monitor = new Monitor(/* priority */ Mutex::leaf,
+ /* name */ "WorkGroup monitor",
+ /* allow_vm_block */ are_GC_threads);
+ assert(monitor() != NULL, "Failed to allocate monitor");
+ _terminate = false;
+ _task = NULL;
+ _sequence_number = 0;
+ _started_workers = 0;
+ _finished_workers = 0;
+}
+
+WorkGang::WorkGang(const char* name,
+ int workers,
+ bool are_GC_threads) :
+ AbstractWorkGang(name, are_GC_threads) {
+ // Save arguments.
+ _total_workers = workers;
+ if (TraceWorkGang) {
+ tty->print_cr("Constructing work gang %s with %d threads", name, workers);
+ }
+ _gang_workers = NEW_C_HEAP_ARRAY(GangWorker*, workers);
+ assert(gang_workers() != NULL, "Failed to allocate gang workers");
+ for (int worker = 0; worker < total_workers(); worker += 1) {
+ GangWorker* new_worker = new GangWorker(this, worker);
+ assert(new_worker != NULL, "Failed to allocate GangWorker");
+ _gang_workers[worker] = new_worker;
+ if (new_worker == NULL || !os::create_thread(new_worker, os::pgc_thread))
+ vm_exit_out_of_memory(0, "Cannot create worker GC thread. Out of system resources.");
+ if (!DisableStartThread) {
+ os::start_thread(new_worker);
+ }
+ }
+}
+
+AbstractWorkGang::~AbstractWorkGang() {
+ if (TraceWorkGang) {
+ tty->print_cr("Destructing work gang %s", name());
+ }
+ stop(); // stop all the workers
+ for (int worker = 0; worker < total_workers(); worker += 1) {
+ delete gang_worker(worker);
+ }
+ delete gang_workers();
+ delete monitor();
+}
+
+GangWorker* AbstractWorkGang::gang_worker(int i) const {
+ // Array index bounds checking.
+ GangWorker* result = NULL;
+ assert(gang_workers() != NULL, "No workers for indexing");
+ assert(((i >= 0) && (i < total_workers())), "Worker index out of bounds");
+ result = _gang_workers[i];
+ assert(result != NULL, "Indexing to null worker");
+ return result;
+}
+
+void WorkGang::run_task(AbstractGangTask* task) {
+ // This thread is executed by the VM thread which does not block
+ // on ordinary MutexLocker's.
+ MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
+ if (TraceWorkGang) {
+ tty->print_cr("Running work gang %s task %s", name(), task->name());
+ }
+ // Tell all the workers to run a task.
+ assert(task != NULL, "Running a null task");
+ // Initialize.
+ _task = task;
+ _sequence_number += 1;
+ _started_workers = 0;
+ _finished_workers = 0;
+ // Tell the workers to get to work.
+ monitor()->notify_all();
+ // Wait for them to be finished
+ while (finished_workers() < total_workers()) {
+ if (TraceWorkGang) {
+ tty->print_cr("Waiting in work gang %s: %d/%d finished sequence %d",
+ name(), finished_workers(), total_workers(),
+ _sequence_number);
+ }
+ monitor()->wait(/* no_safepoint_check */ true);
+ }
+ _task = NULL;
+ if (TraceWorkGang) {
+ tty->print_cr("/nFinished work gang %s: %d/%d sequence %d",
+ name(), finished_workers(), total_workers(),
+ _sequence_number);
+ }
+}
+
+void AbstractWorkGang::stop() {
+ // Tell all workers to terminate, then wait for them to become inactive.
+ MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
+ if (TraceWorkGang) {
+ tty->print_cr("Stopping work gang %s task %s", name(), task()->name());
+ }
+ _task = NULL;
+ _terminate = true;
+ monitor()->notify_all();
+ while (finished_workers() < total_workers()) {
+ if (TraceWorkGang) {
+ tty->print_cr("Waiting in work gang %s: %d/%d finished",
+ name(), finished_workers(), total_workers());
+ }
+ monitor()->wait(/* no_safepoint_check */ true);
+ }
+}
+
+void AbstractWorkGang::internal_worker_poll(WorkData* data) const {
+ assert(monitor()->owned_by_self(), "worker_poll is an internal method");
+ assert(data != NULL, "worker data is null");
+ data->set_terminate(terminate());
+ data->set_task(task());
+ data->set_sequence_number(sequence_number());
+}
+
+void AbstractWorkGang::internal_note_start() {
+ assert(monitor()->owned_by_self(), "note_finish is an internal method");
+ _started_workers += 1;
+}
+
+void AbstractWorkGang::internal_note_finish() {
+ assert(monitor()->owned_by_self(), "note_finish is an internal method");
+ _finished_workers += 1;
+}
+
+void AbstractWorkGang::print_worker_threads_on(outputStream* st) const {
+ uint num_thr = total_workers();
+ for (uint i = 0; i < num_thr; i++) {
+ gang_worker(i)->print_on(st);
+ st->cr();
+ }
+}
+
+void AbstractWorkGang::threads_do(ThreadClosure* tc) const {
+ assert(tc != NULL, "Null ThreadClosure");
+ uint num_thr = total_workers();
+ for (uint i = 0; i < num_thr; i++) {
+ tc->do_thread(gang_worker(i));
+ }
+}
+
+// GangWorker methods.
+
+GangWorker::GangWorker(AbstractWorkGang* gang, uint id) {
+ _gang = gang;
+ set_id(id);
+ set_name("Gang worker#%d (%s)", id, gang->name());
+}
+
+void GangWorker::run() {
+ initialize();
+ loop();
+}
+
+void GangWorker::initialize() {
+ this->initialize_thread_local_storage();
+ assert(_gang != NULL, "No gang to run in");
+ os::set_priority(this, NearMaxPriority);
+ if (TraceWorkGang) {
+ tty->print_cr("Running gang worker for gang %s id %d",
+ gang()->name(), id());
+ }
+ // The VM thread should not execute here because MutexLocker's are used
+ // as (opposed to MutexLockerEx's).
+ assert(!Thread::current()->is_VM_thread(), "VM thread should not be part"
+ " of a work gang");
+}
+
+void GangWorker::loop() {
+ int previous_sequence_number = 0;
+ Monitor* gang_monitor = gang()->monitor();
+ for ( ; /* !terminate() */; ) {
+ WorkData data;
+ int part; // Initialized below.
+ {
+ // Grab the gang mutex.
+ MutexLocker ml(gang_monitor);
+ // Wait for something to do.
+ // Polling outside the while { wait } avoids missed notifies
+ // in the outer loop.
+ gang()->internal_worker_poll(&data);
+ if (TraceWorkGang) {
+ tty->print("Polled outside for work in gang %s worker %d",
+ gang()->name(), id());
+ tty->print(" terminate: %s",
+ data.terminate() ? "true" : "false");
+ tty->print(" sequence: %d (prev: %d)",
+ data.sequence_number(), previous_sequence_number);
+ if (data.task() != NULL) {
+ tty->print(" task: %s", data.task()->name());
+ } else {
+ tty->print(" task: NULL");
+ }
+ tty->cr();
+ }
+ for ( ; /* break or return */; ) {
+ // Terminate if requested.
+ if (data.terminate()) {
+ gang()->internal_note_finish();
+ gang_monitor->notify_all();
+ return;
+ }
+ // Check for new work.
+ if ((data.task() != NULL) &&
+ (data.sequence_number() != previous_sequence_number)) {
+ gang()->internal_note_start();
+ gang_monitor->notify_all();
+ part = gang()->started_workers() - 1;
+ break;
+ }
+ // Nothing to do.
+ gang_monitor->wait(/* no_safepoint_check */ true);
+ gang()->internal_worker_poll(&data);
+ if (TraceWorkGang) {
+ tty->print("Polled inside for work in gang %s worker %d",
+ gang()->name(), id());
+ tty->print(" terminate: %s",
+ data.terminate() ? "true" : "false");
+ tty->print(" sequence: %d (prev: %d)",
+ data.sequence_number(), previous_sequence_number);
+ if (data.task() != NULL) {
+ tty->print(" task: %s", data.task()->name());
+ } else {
+ tty->print(" task: NULL");
+ }
+ tty->cr();
+ }
+ }
+ // Drop gang mutex.
+ }
+ if (TraceWorkGang) {
+ tty->print("Work for work gang %s id %d task %s part %d",
+ gang()->name(), id(), data.task()->name(), part);
+ }
+ assert(data.task() != NULL, "Got null task");
+ data.task()->work(part);
+ {
+ if (TraceWorkGang) {
+ tty->print("Finish for work gang %s id %d task %s part %d",
+ gang()->name(), id(), data.task()->name(), part);
+ }
+ // Grab the gang mutex.
+ MutexLocker ml(gang_monitor);
+ gang()->internal_note_finish();
+ // Tell the gang you are done.
+ gang_monitor->notify_all();
+ // Drop the gang mutex.
+ }
+ previous_sequence_number = data.sequence_number();
+ }
+}
+
+bool GangWorker::is_GC_task_thread() const {
+ return gang()->are_GC_threads();
+}
+
+void GangWorker::print_on(outputStream* st) const {
+ st->print("\"%s\" ", name());
+ Thread::print_on(st);
+ st->cr();
+}
+
+// Printing methods
+
+const char* AbstractWorkGang::name() const {
+ return _name;
+}
+
+#ifndef PRODUCT
+
+const char* AbstractGangTask::name() const {
+ return _name;
+}
+
+#endif /* PRODUCT */
+
+// *** WorkGangBarrierSync
+
+WorkGangBarrierSync::WorkGangBarrierSync()
+ : _monitor(Mutex::safepoint, "work gang barrier sync", true),
+ _n_workers(0), _n_completed(0) {
+}
+
+WorkGangBarrierSync::WorkGangBarrierSync(int n_workers, const char* name)
+ : _monitor(Mutex::safepoint, name, true),
+ _n_workers(n_workers), _n_completed(0) {
+}
+
+void WorkGangBarrierSync::set_n_workers(int n_workers) {
+ _n_workers = n_workers;
+ _n_completed = 0;
+}
+
+void WorkGangBarrierSync::enter() {
+ MutexLockerEx x(monitor(), Mutex::_no_safepoint_check_flag);
+ inc_completed();
+ if (n_completed() == n_workers()) {
+ monitor()->notify_all();
+ }
+ else {
+ while (n_completed() != n_workers()) {
+ monitor()->wait(/* no_safepoint_check */ true);
+ }
+ }
+}
+
+// SubTasksDone functions.
+
+SubTasksDone::SubTasksDone(int n) :
+ _n_tasks(n), _n_threads(1), _tasks(NULL) {
+ _tasks = NEW_C_HEAP_ARRAY(jint, n);
+ guarantee(_tasks != NULL, "alloc failure");
+ clear();
+}
+
+bool SubTasksDone::valid() {
+ return _tasks != NULL;
+}
+
+void SubTasksDone::set_par_threads(int t) {
+#ifdef ASSERT
+ assert(_claimed == 0 || _threads_completed == _n_threads,
+ "should not be called while tasks are being processed!");
+#endif
+ _n_threads = (t == 0 ? 1 : t);
+}
+
+void SubTasksDone::clear() {
+ for (int i = 0; i < _n_tasks; i++) {
+ _tasks[i] = 0;
+ }
+ _threads_completed = 0;
+#ifdef ASSERT
+ _claimed = 0;
+#endif
+}
+
+bool SubTasksDone::is_task_claimed(int t) {
+ assert(0 <= t && t < _n_tasks, "bad task id.");
+ jint old = _tasks[t];
+ if (old == 0) {
+ old = Atomic::cmpxchg(1, &_tasks[t], 0);
+ }
+ assert(_tasks[t] == 1, "What else?");
+ bool res = old != 0;
+#ifdef ASSERT
+ if (!res) {
+ assert(_claimed < _n_tasks, "Too many tasks claimed; missing clear?");
+ Atomic::inc(&_claimed);
+ }
+#endif
+ return res;
+}
+
+void SubTasksDone::all_tasks_completed() {
+ jint observed = _threads_completed;
+ jint old;
+ do {
+ old = observed;
+ observed = Atomic::cmpxchg(old+1, &_threads_completed, old);
+ } while (observed != old);
+ // If this was the last thread checking in, clear the tasks.
+ if (observed+1 == _n_threads) clear();
+}
+
+
+SubTasksDone::~SubTasksDone() {
+ if (_tasks != NULL) FREE_C_HEAP_ARRAY(jint, _tasks);
+}
+
+// *** SequentialSubTasksDone
+
+void SequentialSubTasksDone::clear() {
+ _n_tasks = _n_claimed = 0;
+ _n_threads = _n_completed = 0;
+}
+
+bool SequentialSubTasksDone::valid() {
+ return _n_threads > 0;
+}
+
+bool SequentialSubTasksDone::is_task_claimed(int& t) {
+ jint* n_claimed_ptr = &_n_claimed;
+ t = *n_claimed_ptr;
+ while (t < _n_tasks) {
+ jint res = Atomic::cmpxchg(t+1, n_claimed_ptr, t);
+ if (res == t) {
+ return false;
+ }
+ t = *n_claimed_ptr;
+ }
+ return true;
+}
+
+bool SequentialSubTasksDone::all_tasks_completed() {
+ jint* n_completed_ptr = &_n_completed;
+ jint complete = *n_completed_ptr;
+ while (true) {
+ jint res = Atomic::cmpxchg(complete+1, n_completed_ptr, complete);
+ if (res == complete) {
+ break;
+ }
+ complete = res;
+ }
+ if (complete+1 == _n_threads) {
+ clear();
+ return true;
+ }
+ return false;
+}
diff --git a/src/share/vm/utilities/workgroup.hpp b/src/share/vm/utilities/workgroup.hpp
new file mode 100644
index 000000000..3797a3f76
--- /dev/null
+++ b/src/share/vm/utilities/workgroup.hpp
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2002-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// Forward declarations of classes defined here
+
+class WorkGang;
+class GangWorker;
+class YieldingFlexibleGangWorker;
+class YieldingFlexibleGangTask;
+class WorkData;
+
+// An abstract task to be worked on by a gang.
+// You subclass this to supply your own work() method
+class AbstractGangTask: public CHeapObj {
+public:
+ // The abstract work method.
+ // The argument tells you which member of the gang you are.
+ virtual void work(int i) = 0;
+
+ // Debugging accessor for the name.
+ const char* name() const PRODUCT_RETURN_(return NULL;);
+ int counter() { return _counter; }
+ void set_counter(int value) { _counter = value; }
+ int *address_of_counter() { return &_counter; }
+
+ // RTTI
+ NOT_PRODUCT(virtual bool is_YieldingFlexibleGang_task() const {
+ return false;
+ })
+
+private:
+ NOT_PRODUCT(const char* _name;)
+ // ??? Should a task have a priority associated with it?
+ // ??? Or can the run method adjust priority as needed?
+ int _counter;
+
+protected:
+ // Constructor and desctructor: only construct subclasses.
+ AbstractGangTask(const char* name) {
+ NOT_PRODUCT(_name = name);
+ _counter = 0;
+ }
+ virtual ~AbstractGangTask() { }
+};
+
+
+// Class AbstractWorkGang:
+// An abstract class representing a gang of workers.
+// You subclass this to supply an implementation of run_task().
+class AbstractWorkGang: public CHeapObj {
+ // Here's the public interface to this class.
+public:
+ // Constructor and destructor.
+ AbstractWorkGang(const char* name, bool are_GC_threads);
+ ~AbstractWorkGang();
+ // Run a task, returns when the task is done (or terminated).
+ virtual void run_task(AbstractGangTask* task) = 0;
+ // Stop and terminate all workers.
+ virtual void stop();
+public:
+ // Debugging.
+ const char* name() const;
+protected:
+ // Initialize only instance data.
+ const bool _are_GC_threads;
+ // Printing support.
+ const char* _name;
+ // The monitor which protects these data,
+ // and notifies of changes in it.
+ Monitor* _monitor;
+ // The count of the number of workers in the gang.
+ int _total_workers;
+ // Whether the workers should terminate.
+ bool _terminate;
+ // The array of worker threads for this gang.
+ // This is only needed for cleaning up.
+ GangWorker** _gang_workers;
+ // The task for this gang.
+ AbstractGangTask* _task;
+ // A sequence number for the current task.
+ int _sequence_number;
+ // The number of started workers.
+ int _started_workers;
+ // The number of finished workers.
+ int _finished_workers;
+public:
+ // Accessors for fields
+ Monitor* monitor() const {
+ return _monitor;
+ }
+ int total_workers() const {
+ return _total_workers;
+ }
+ bool terminate() const {
+ return _terminate;
+ }
+ GangWorker** gang_workers() const {
+ return _gang_workers;
+ }
+ AbstractGangTask* task() const {
+ return _task;
+ }
+ int sequence_number() const {
+ return _sequence_number;
+ }
+ int started_workers() const {
+ return _started_workers;
+ }
+ int finished_workers() const {
+ return _finished_workers;
+ }
+ bool are_GC_threads() const {
+ return _are_GC_threads;
+ }
+ // Predicates.
+ bool is_idle() const {
+ return (task() == NULL);
+ }
+ // Return the Ith gang worker.
+ GangWorker* gang_worker(int i) const;
+
+ void threads_do(ThreadClosure* tc) const;
+
+ // Printing
+ void print_worker_threads_on(outputStream *st) const;
+ void print_worker_threads() const {
+ print_worker_threads_on(tty);
+ }
+
+protected:
+ friend class GangWorker;
+ friend class YieldingFlexibleGangWorker;
+ // Note activation and deactivation of workers.
+ // These methods should only be called with the mutex held.
+ void internal_worker_poll(WorkData* data) const;
+ void internal_note_start();
+ void internal_note_finish();
+};
+
+class WorkData: public StackObj {
+ // This would be a struct, but I want accessor methods.
+private:
+ bool _terminate;
+ AbstractGangTask* _task;
+ int _sequence_number;
+public:
+ // Constructor and destructor
+ WorkData() {
+ _terminate = false;
+ _task = NULL;
+ _sequence_number = 0;
+ }
+ ~WorkData() {
+ }
+ // Accessors and modifiers
+ bool terminate() const { return _terminate; }
+ void set_terminate(bool value) { _terminate = value; }
+ AbstractGangTask* task() const { return _task; }
+ void set_task(AbstractGangTask* value) { _task = value; }
+ int sequence_number() const { return _sequence_number; }
+ void set_sequence_number(int value) { _sequence_number = value; }
+
+ YieldingFlexibleGangTask* yf_task() const {
+ return (YieldingFlexibleGangTask*)_task;
+ }
+};
+
+// Class WorkGang:
+class WorkGang: public AbstractWorkGang {
+public:
+ // Constructor
+ WorkGang(const char* name, int workers, bool are_GC_threads);
+ // Run a task, returns when the task is done (or terminated).
+ virtual void run_task(AbstractGangTask* task);
+};
+
+// Class GangWorker:
+// Several instances of this class run in parallel as workers for a gang.
+class GangWorker: public WorkerThread {
+public:
+ // Constructors and destructor.
+ GangWorker(AbstractWorkGang* gang, uint id);
+
+ // The only real method: run a task for the gang.
+ virtual void run();
+ // Predicate for Thread
+ virtual bool is_GC_task_thread() const;
+ // Printing
+ void print_on(outputStream* st) const;
+ virtual void print() const { print_on(tty); }
+protected:
+ AbstractWorkGang* _gang;
+
+ virtual void initialize();
+ virtual void loop();
+
+public:
+ AbstractWorkGang* gang() const { return _gang; }
+};
+
+// A class that acts as a synchronisation barrier. Workers enter
+// the barrier and must wait until all other workers have entered
+// before any of them may leave.
+
+class WorkGangBarrierSync : public StackObj {
+protected:
+ Monitor _monitor;
+ int _n_workers;
+ int _n_completed;
+
+ Monitor* monitor() { return &_monitor; }
+ int n_workers() { return _n_workers; }
+ int n_completed() { return _n_completed; }
+
+ void inc_completed() { _n_completed++; }
+
+public:
+ WorkGangBarrierSync();
+ WorkGangBarrierSync(int n_workers, const char* name);
+
+ // Set the number of workers that will use the barrier.
+ // Must be called before any of the workers start running.
+ void set_n_workers(int n_workers);
+
+ // Enter the barrier. A worker that enters the barrier will
+ // not be allowed to leave until all other threads have
+ // also entered the barrier.
+ void enter();
+};
+
+// A class to manage claiming of subtasks within a group of tasks. The
+// subtasks will be identified by integer indices, usually elements of an
+// enumeration type.
+
+class SubTasksDone: public CHeapObj {
+ jint* _tasks;
+ int _n_tasks;
+ int _n_threads;
+ jint _threads_completed;
+#ifdef ASSERT
+ jint _claimed;
+#endif
+
+ // Set all tasks to unclaimed.
+ void clear();
+
+public:
+ // Initializes "this" to a state in which there are "n" tasks to be
+ // processed, none of the which are originally claimed. The number of
+ // threads doing the tasks is initialized 1.
+ SubTasksDone(int n);
+
+ // True iff the object is in a valid state.
+ bool valid();
+
+ // Set the number of parallel threads doing the tasks to "t". Can only
+ // be called before tasks start or after they are complete.
+ void set_par_threads(int t);
+
+ // Returns "false" if the task "t" is unclaimed, and ensures that task is
+ // claimed. The task "t" is required to be within the range of "this".
+ bool is_task_claimed(int t);
+
+ // The calling thread asserts that it has attempted to claim all the
+ // tasks that it will try to claim. Every thread in the parallel task
+ // must execute this. (When the last thread does so, the task array is
+ // cleared.)
+ void all_tasks_completed();
+
+ // Destructor.
+ ~SubTasksDone();
+};
+
+// As above, but for sequential tasks, i.e. instead of claiming
+// sub-tasks from a set (possibly an enumeration), claim sub-tasks
+// in sequential order. This is ideal for claiming dynamically
+// partitioned tasks (like striding in the parallel remembered
+// set scanning). Note that unlike the above class this is
+// a stack object - is there any reason for it not to be?
+
+class SequentialSubTasksDone : public StackObj {
+protected:
+ jint _n_tasks; // Total number of tasks available.
+ jint _n_claimed; // Number of tasks claimed.
+ jint _n_threads; // Total number of parallel threads.
+ jint _n_completed; // Number of completed threads.
+
+ void clear();
+
+public:
+ SequentialSubTasksDone() { clear(); }
+ ~SequentialSubTasksDone() {}
+
+ // True iff the object is in a valid state.
+ bool valid();
+
+ // number of tasks
+ jint n_tasks() const { return _n_tasks; }
+
+ // Set the number of parallel threads doing the tasks to t.
+ // Should be called before the task starts but it is safe
+ // to call this once a task is running provided that all
+ // threads agree on the number of threads.
+ void set_par_threads(int t) { _n_threads = t; }
+
+ // Set the number of tasks to be claimed to t. As above,
+ // should be called before the tasks start but it is safe
+ // to call this once a task is running provided all threads
+ // agree on the number of tasks.
+ void set_n_tasks(int t) { _n_tasks = t; }
+
+ // Returns false if the next task in the sequence is unclaimed,
+ // and ensures that it is claimed. Will set t to be the index
+ // of the claimed task in the sequence. Will return true if
+ // the task cannot be claimed and there are none left to claim.
+ bool is_task_claimed(int& t);
+
+ // The calling thread asserts that it has attempted to claim
+ // all the tasks it possibly can in the sequence. Every thread
+ // claiming tasks must promise call this. Returns true if this
+ // is the last thread to complete so that the thread can perform
+ // cleanup if necessary.
+ bool all_tasks_completed();
+};
diff --git a/src/share/vm/utilities/xmlstream.cpp b/src/share/vm/utilities/xmlstream.cpp
new file mode 100644
index 000000000..b7098c857
--- /dev/null
+++ b/src/share/vm/utilities/xmlstream.cpp
@@ -0,0 +1,470 @@
+/*
+ * Copyright 2002-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include "incls/_precompiled.incl"
+#include "incls/_xmlstream.cpp.incl"
+
+void xmlStream::initialize(outputStream* out) {
+ _out = out;
+ _last_flush = 0;
+ _markup_state = BODY;
+ _text_init._outer_xmlStream = this;
+ _text = &_text_init;
+
+#ifdef ASSERT
+ _element_depth = 0;
+ int init_len = 100;
+ char* init_buf = NEW_C_HEAP_ARRAY(char, init_len);
+ _element_close_stack_low = init_buf;
+ _element_close_stack_high = init_buf + init_len;
+ _element_close_stack_ptr = init_buf + init_len - 1;
+ _element_close_stack_ptr[0] = '\0';
+#endif
+
+ // Make sure each log uses the same base for time stamps.
+ if (is_open()) {
+ _out->time_stamp().update_to(1);
+ }
+}
+
+#ifdef ASSERT
+xmlStream::~xmlStream() {
+ FREE_C_HEAP_ARRAY(char, _element_close_stack_low);
+}
+#endif
+
+// Pass the given chars directly to _out.
+void xmlStream::write(const char* s, size_t len) {
+ if (!is_open()) return;
+
+ out()->write(s, len);
+}
+
+
+// Pass the given chars directly to _out, except that
+// we watch for special "<&>" chars.
+// This is suitable for either attribute text or for body text.
+// We don't fool with "<![CDATA[" quotes, just single-character entities.
+// This makes it easier for dumb tools to parse the output.
+void xmlStream::write_text(const char* s, size_t len) {
+ if (!is_open()) return;
+
+ size_t written = 0;
+ // All normally printed material goes inside XML quotes.
+ // This leaves the output free to include markup also.
+ // Scan the string looking for inadvertant "<&>" chars
+ for (size_t i = 0; i < len; i++) {
+ char ch = s[i];
+ // Escape special chars.
+ const char* esc = NULL;
+ switch (ch) {
+ // These are important only in attrs, but we do them always:
+ case '\'': esc = "&apos;"; break;
+ case '"': esc = "&quot;"; break;
+ case '<': esc = "&lt;"; break;
+ case '&': esc = "&amp;"; break;
+ // This is a freebie.
+ case '>': esc = "&gt;"; break;
+ }
+ if (esc != NULL) {
+ if (written < i) {
+ out()->write(&s[written], i - written);
+ written = i;
+ }
+ out()->print_raw(esc);
+ written++;
+ }
+ }
+
+ // Print the clean remainder. Usually, it is all of s.
+ if (written < len) {
+ out()->write(&s[written], len - written);
+ }
+}
+
+// ------------------------------------------------------------------
+// Outputs XML text, with special characters quoted.
+void xmlStream::text(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ va_text(format, ap);
+ va_end(ap);
+}
+
+#define BUFLEN 2*K /* max size of output of individual print methods */
+
+// ------------------------------------------------------------------
+void xmlStream::va_tag(bool push, const char* format, va_list ap) {
+ assert_if_no_error(!inside_attrs(), "cannot print tag inside attrs");
+ char buffer[BUFLEN];
+ size_t len;
+ const char* kind = do_vsnprintf(buffer, BUFLEN, format, ap, false, len);
+ see_tag(kind, push);
+ print_raw("<");
+ write(kind, len);
+ _markup_state = (push ? HEAD : ELEM);
+}
+
+#ifdef ASSERT
+/// Debugging goo to make sure element tags nest properly.
+
+// ------------------------------------------------------------------
+void xmlStream::see_tag(const char* tag, bool push) {
+ assert_if_no_error(!inside_attrs(), "cannot start new element inside attrs");
+ if (!push) return;
+
+ // tag goes up until either null or space:
+ const char* tag_end = strchr(tag, ' ');
+ size_t tag_len = (tag_end == NULL) ? strlen(tag) : tag_end - tag;
+ assert(tag_len > 0, "tag must not be empty");
+ // push the tag onto the stack, pulling down the pointer
+ char* old_ptr = _element_close_stack_ptr;
+ char* old_low = _element_close_stack_low;
+ char* push_ptr = old_ptr - (tag_len+1);
+ if (push_ptr < old_low) {
+ int old_len = _element_close_stack_high - old_ptr;
+ int new_len = old_len * 2;
+ if (new_len < 100) new_len = 100;
+ char* new_low = NEW_C_HEAP_ARRAY(char, new_len);
+ char* new_high = new_low + new_len;
+ char* new_ptr = new_high - old_len;
+ memcpy(new_ptr, old_ptr, old_len);
+ _element_close_stack_high = new_high;
+ _element_close_stack_low = new_low;
+ _element_close_stack_ptr = new_ptr;
+ FREE_C_HEAP_ARRAY(char, old_low);
+ push_ptr = new_ptr - (tag_len+1);
+ }
+ assert(push_ptr >= _element_close_stack_low, "in range");
+ memcpy(push_ptr, tag, tag_len);
+ push_ptr[tag_len] = 0;
+ _element_close_stack_ptr = push_ptr;
+ _element_depth += 1;
+}
+
+// ------------------------------------------------------------------
+void xmlStream::pop_tag(const char* tag) {
+ assert_if_no_error(!inside_attrs(), "cannot close element inside attrs");
+ assert(_element_depth > 0, "must be in an element to close");
+ assert(*tag != 0, "tag must not be empty");
+ char* cur_tag = _element_close_stack_ptr;
+ bool bad_tag = false;
+ while (*cur_tag != 0 && strcmp(cur_tag, tag) != 0) {
+ this->print_cr("</%s> <!-- missing closing tag -->", cur_tag);
+ _element_close_stack_ptr = (cur_tag += strlen(cur_tag) + 1);
+ _element_depth -= 1;
+ bad_tag = true;
+ }
+ if (*cur_tag == 0) {
+ bad_tag = true;
+ } else {
+ // Pop the stack, by skipping over the tag and its null.
+ _element_close_stack_ptr = cur_tag + strlen(cur_tag) + 1;
+ _element_depth -= 1;
+ }
+ if (bad_tag && !VMThread::should_terminate() && !is_error_reported())
+ assert(false, "bad tag in log");
+}
+#endif
+
+
+// ------------------------------------------------------------------
+// First word in formatted string is element kind, and any subsequent
+// words must be XML attributes. Outputs "<kind .../>".
+void xmlStream::elem(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ va_elem(format, ap);
+ va_end(ap);
+}
+
+// ------------------------------------------------------------------
+void xmlStream::va_elem(const char* format, va_list ap) {
+ va_begin_elem(format, ap);
+ end_elem();
+}
+
+
+// ------------------------------------------------------------------
+// First word in formatted string is element kind, and any subsequent
+// words must be XML attributes. Outputs "<kind ...", not including "/>".
+void xmlStream::begin_elem(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ va_tag(false, format, ap);
+ va_end(ap);
+}
+
+// ------------------------------------------------------------------
+void xmlStream::va_begin_elem(const char* format, va_list ap) {
+ va_tag(false, format, ap);
+}
+
+// ------------------------------------------------------------------
+// Outputs "/>".
+void xmlStream::end_elem() {
+ assert(_markup_state == ELEM, "misplaced end_elem");
+ print_raw("/>\n");
+ _markup_state = BODY;
+}
+
+// ------------------------------------------------------------------
+// Outputs formatted text, followed by "/>".
+void xmlStream::end_elem(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ out()->vprint(format, ap);
+ va_end(ap);
+ end_elem();
+}
+
+
+// ------------------------------------------------------------------
+// First word in formatted string is element kind, and any subsequent
+// words must be XML attributes. Outputs "<kind ...>".
+void xmlStream::head(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ va_head(format, ap);
+ va_end(ap);
+}
+
+// ------------------------------------------------------------------
+void xmlStream::va_head(const char* format, va_list ap) {
+ va_begin_head(format, ap);
+ end_head();
+}
+
+// ------------------------------------------------------------------
+// First word in formatted string is element kind, and any subsequent
+// words must be XML attributes. Outputs "<kind ...", not including ">".
+void xmlStream::begin_head(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ va_tag(true, format, ap);
+ va_end(ap);
+}
+
+// ------------------------------------------------------------------
+void xmlStream::va_begin_head(const char* format, va_list ap) {
+ va_tag(true, format, ap);
+}
+
+// ------------------------------------------------------------------
+// Outputs ">".
+void xmlStream::end_head() {
+ assert(_markup_state == HEAD, "misplaced end_head");
+ print_raw(">\n");
+ _markup_state = BODY;
+}
+
+
+// ------------------------------------------------------------------
+// Outputs formatted text, followed by ">".
+void xmlStream::end_head(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ out()->vprint(format, ap);
+ va_end(ap);
+ end_head();
+}
+
+
+// ------------------------------------------------------------------
+// Outputs "</kind>".
+void xmlStream::tail(const char* kind) {
+ pop_tag(kind);
+ print_raw("</");
+ print_raw(kind);
+ print_raw(">\n");
+}
+
+// ------------------------------------------------------------------
+// Outputs "<kind_done ... stamp='D.DD'/> </kind>".
+void xmlStream::done(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ va_done(format, ap);
+ va_end(ap);
+}
+
+// ------------------------------------------------------------------
+// Outputs "<kind_done stamp='D.DD'/> </kind>".
+// Because done_raw() doesn't need to format strings, it's simpler than
+// done(), and can be called safely by fatal error handler.
+void xmlStream::done_raw(const char* kind) {
+ print_raw("<");
+ print_raw(kind);
+ print_raw("_done stamp='");
+ out()->stamp();
+ print_raw_cr("'/>");
+ print_raw("</");
+ print_raw(kind);
+ print_raw_cr(">");
+}
+
+// ------------------------------------------------------------------
+void xmlStream::va_done(const char* format, va_list ap) {
+ char buffer[200];
+ guarantee(strlen(format) + 10 < sizeof(buffer), "bigger format buffer")
+ const char* kind = format;
+ const char* kind_end = strchr(kind, ' ');
+ size_t kind_len = (kind_end != NULL) ? (kind_end - kind) : strlen(kind);
+ strncpy(buffer, kind, kind_len);
+ strcpy(buffer + kind_len, "_done");
+ strcat(buffer, format + kind_len);
+ // Output the trailing event with the timestamp.
+ va_begin_elem(buffer, ap);
+ stamp();
+ end_elem();
+ // Output the tail-tag of the enclosing element.
+ buffer[kind_len] = 0;
+ tail(buffer);
+}
+
+// Output a timestamp attribute.
+void xmlStream::stamp() {
+ assert_if_no_error(inside_attrs(), "stamp must be an attribute");
+ print_raw(" stamp='");
+ out()->stamp();
+ print_raw("'");
+}
+
+
+// ------------------------------------------------------------------
+// Output a method attribute, in the form " method='pkg/cls name sig'".
+// This is used only when there is no ciMethod available.
+void xmlStream::method(methodHandle method) {
+ assert_if_no_error(inside_attrs(), "printing attributes");
+ if (method.is_null()) return;
+ print_raw(" method='");
+ method_text(method);
+ print("' bytes='%d'", method->code_size());
+ print(" count='%d'", method->invocation_count());
+ int bec = method->backedge_count();
+ if (bec != 0) print(" backedge_count='%d'", bec);
+ print(" iicount='%d'", method->interpreter_invocation_count());
+ int throwouts = method->interpreter_throwout_count();
+ if (throwouts != 0) print(" throwouts='%d'", throwouts);
+ methodDataOop mdo = method->method_data();
+ if (mdo != NULL) {
+ uint cnt;
+ cnt = mdo->decompile_count();
+ if (cnt != 0) print(" decompiles='%d'", cnt);
+ for (uint reason = 0; reason < mdo->trap_reason_limit(); reason++) {
+ cnt = mdo->trap_count(reason);
+ if (cnt != 0) print(" %s_traps='%d'", Deoptimization::trap_reason_name(reason), cnt);
+ }
+ cnt = mdo->overflow_trap_count();
+ if (cnt != 0) print(" overflow_traps='%d'", cnt);
+ cnt = mdo->overflow_recompile_count();
+ if (cnt != 0) print(" overflow_recompiles='%d'", cnt);
+ }
+}
+
+void xmlStream::method_text(methodHandle method) {
+ assert_if_no_error(inside_attrs(), "printing attributes");
+ if (method.is_null()) return;
+ //method->print_short_name(text());
+ method->method_holder()->klass_part()->name()->print_symbol_on(text());
+ print_raw(" "); // " " is easier for tools to parse than "::"
+ method->name()->print_symbol_on(text());
+ print_raw(" "); // separator
+ method->signature()->print_symbol_on(text());
+}
+
+
+// ------------------------------------------------------------------
+// Output a klass attribute, in the form " klass='pkg/cls'".
+// This is used only when there is no ciKlass available.
+void xmlStream::klass(KlassHandle klass) {
+ assert_if_no_error(inside_attrs(), "printing attributes");
+ if (klass.is_null()) return;
+ print_raw(" klass='");
+ klass_text(klass);
+ print_raw("'");
+}
+
+void xmlStream::klass_text(KlassHandle klass) {
+ assert_if_no_error(inside_attrs(), "printing attributes");
+ if (klass.is_null()) return;
+ //klass->print_short_name(log->out());
+ klass->name()->print_symbol_on(out());
+}
+
+void xmlStream::name(symbolHandle name) {
+ assert_if_no_error(inside_attrs(), "printing attributes");
+ if (name.is_null()) return;
+ print_raw(" name='");
+ name_text(name);
+ print_raw("'");
+}
+
+void xmlStream::name_text(symbolHandle name) {
+ assert_if_no_error(inside_attrs(), "printing attributes");
+ if (name.is_null()) return;
+ //name->print_short_name(text());
+ name->print_symbol_on(text());
+}
+
+void xmlStream::object(const char* attr, Handle x) {
+ assert_if_no_error(inside_attrs(), "printing attributes");
+ if (x.is_null()) return;
+ print_raw(" ");
+ print_raw(attr);
+ print_raw("='");
+ object_text(x);
+ print_raw("'");
+}
+
+void xmlStream::object_text(Handle x) {
+ assert_if_no_error(inside_attrs(), "printing attributes");
+ if (x.is_null()) return;
+ //x->print_value_on(text());
+ if (x->is_method())
+ method_text(methodOop(x()));
+ else if (x->is_klass())
+ klass_text(klassOop(x()));
+ else if (x->is_symbol())
+ name_text(symbolOop(x()));
+ else
+ x->print_value_on(text());
+}
+
+
+void xmlStream::flush() {
+ out()->flush();
+ _last_flush = count();
+}
+
+void xmlTextStream::flush() {
+ if (_outer_xmlStream == NULL) return;
+ _outer_xmlStream->flush();
+}
+
+void xmlTextStream::write(const char* str, size_t len) {
+ if (_outer_xmlStream == NULL) return;
+ _outer_xmlStream->write_text(str, len);
+ update_position(str, len);
+}
diff --git a/src/share/vm/utilities/xmlstream.hpp b/src/share/vm/utilities/xmlstream.hpp
new file mode 100644
index 000000000..27839700f
--- /dev/null
+++ b/src/share/vm/utilities/xmlstream.hpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2002-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+class xmlStream;
+class defaultStream;
+
+// Sub-stream for writing quoted text, as opposed to markup.
+// Characters written to this stream are subject to quoting,
+// as '<' => "&lt;", etc.
+class xmlTextStream : public outputStream {
+ friend class xmlStream;
+ friend class defaultStream; // tty
+ private:
+
+ xmlStream* _outer_xmlStream;
+
+ xmlTextStream() { _outer_xmlStream = NULL; }
+
+ public:
+ virtual void flush(); // _outer.flush();
+ virtual void write(const char* str, size_t len); // _outer->write_text()
+};
+
+
+// Output stream for writing XML-structured logs.
+// To write markup, use special calls elem, head/tail, etc.
+// Use the xmlStream::text() stream to write unmarked text.
+// Text written that way will be quoted as necessary using '&lt;', etc.
+// Characters written directly to an xmlStream via print_cr, etc.,
+// are directly written to the encapsulated stream, xmlStream::out().
+// This can be used to produce markup directly, character by character.
+// (Such writes are not checked for markup syntax errors.)
+
+class xmlStream : public outputStream {
+ friend class defaultStream; // tty
+ public:
+ enum MarkupState { BODY, // after end_head() call, in text
+ HEAD, // after begin_head() call, in attrs
+ ELEM }; // after begin_elem() call, in attrs
+
+ protected:
+ outputStream* _out; // file stream by which it goes
+ julong _last_flush; // last position of flush
+ MarkupState _markup_state; // where in the elem/head/tail dance
+ outputStream* _text; // text stream
+ xmlTextStream _text_init;
+
+ // for subclasses
+ xmlStream() {}
+ void initialize(outputStream* out);
+
+ // protect this from public use:
+ outputStream* out() { return _out; }
+
+ // helpers for writing XML elements
+ void va_tag(bool push, const char* format, va_list ap);
+ virtual void see_tag(const char* tag, bool push) NOT_DEBUG({});
+ virtual void pop_tag(const char* tag) NOT_DEBUG({});
+
+#ifdef ASSERT
+ // in debug mode, we verify matching of opening and closing tags
+ int _element_depth; // number of unfinished elements
+ char* _element_close_stack_high; // upper limit of down-growing stack
+ char* _element_close_stack_low; // upper limit of down-growing stack
+ char* _element_close_stack_ptr; // pointer of down-growing stack
+#endif
+
+ public:
+ // creation
+ xmlStream(outputStream* out) { initialize(out); }
+ DEBUG_ONLY(virtual ~xmlStream();)
+
+ bool is_open() { return _out != NULL; }
+
+ // text output
+ bool inside_attrs() { return _markup_state != BODY; }
+
+ // flushing
+ virtual void flush(); // flushes out, sets _last_flush = count()
+ virtual void write(const char* s, size_t len);
+ void write_text(const char* s, size_t len); // used by xmlTextStream
+ int unflushed_count() { return (int)(out()->count() - _last_flush); }
+
+ // writing complete XML elements
+ void elem(const char* format, ...);
+ void begin_elem(const char* format, ...);
+ void end_elem(const char* format, ...);
+ void end_elem();
+ void head(const char* format, ...);
+ void begin_head(const char* format, ...);
+ void end_head(const char* format, ...);
+ void end_head();
+ void done(const char* format, ...); // xxx_done event, plus tail
+ void done_raw(const char * kind);
+ void tail(const char* kind);
+
+ // va_list versions
+ void va_elem(const char* format, va_list ap);
+ void va_begin_elem(const char* format, va_list ap);
+ void va_head(const char* format, va_list ap);
+ void va_begin_head(const char* format, va_list ap);
+ void va_done(const char* format, va_list ap);
+
+ // write text (with quoting of special XML characters <>&'" etc.)
+ outputStream* text() { return _text; }
+ void text(const char* format, ...);
+ void va_text(const char* format, va_list ap) {
+ text()->vprint(format, ap);
+ }
+
+ // commonly used XML attributes
+ void stamp(); // stamp='1.234'
+ void method(methodHandle m); // method='k n s' ...
+ void klass(KlassHandle k); // klass='name'
+ void name(symbolHandle s); // name='name'
+ void object(const char* attr, Handle val);
+
+ // print the text alone (sans ''):
+ void method_text(methodHandle m);
+ void klass_text(KlassHandle k); // klass='name'
+ void name_text(symbolHandle s); // name='name'
+ void object_text(Handle x);
+
+ /* Example uses:
+
+ // Empty element, simple case.
+ elem("X Y='Z'"); <X Y='Z'/> \n
+
+ // Empty element, general case.
+ begin_elem("X Y='Z'"); <X Y='Z'
+ ...attrs... ...attrs...
+ end_elem(); />
+
+ // Compound element, simple case.
+ head("X Y='Z'"); <X Y='Z'> \n
+ ...body... ...body...
+ tail("X"); </X> \n
+
+ // Compound element, general case.
+ begin_head("X Y='Z'"); <X Y='Z'
+ ...attrs... ...attrs...
+ end_head(); > \n
+ ...body... ...body...
+ tail("X"); </X> \n
+
+ // Printf-style formatting:
+ elem("X Y='%s'", "Z"); <X Y='Z'/> \n
+
+ */
+
+};
+
+// Standard log file, null if no logging is happening.
+extern xmlStream* xtty;
+
+// Note: If ::xtty != NULL, ::tty == ::xtty->text().
diff --git a/src/share/vm/utilities/yieldingWorkgroup.cpp b/src/share/vm/utilities/yieldingWorkgroup.cpp
new file mode 100644
index 000000000..d4c0ea92d
--- /dev/null
+++ b/src/share/vm/utilities/yieldingWorkgroup.cpp
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_yieldingWorkgroup.cpp.incl"
+
+// Forward declaration of classes declared here.
+
+class GangWorker;
+class WorkData;
+
+YieldingFlexibleWorkGang::YieldingFlexibleWorkGang(
+ const char* name, int workers, bool are_GC_threads) :
+ AbstractWorkGang(name, are_GC_threads) {
+ // Save arguments.
+ _total_workers = workers;
+ assert(_total_workers > 0, "Must have more than 1 worker");
+
+ _yielded_workers = 0;
+
+ if (TraceWorkGang) {
+ tty->print_cr("Constructing work gang %s with %d threads", name, workers);
+ }
+ _gang_workers = NEW_C_HEAP_ARRAY(GangWorker*, workers);
+ assert(gang_workers() != NULL, "Failed to allocate gang workers");
+ for (int worker = 0; worker < total_workers(); worker += 1) {
+ YieldingFlexibleGangWorker* new_worker =
+ new YieldingFlexibleGangWorker(this, worker);
+ assert(new_worker != NULL, "Failed to allocate YieldingFlexibleGangWorker");
+ _gang_workers[worker] = new_worker;
+ if (new_worker == NULL || !os::create_thread(new_worker, os::pgc_thread))
+ vm_exit_out_of_memory(0, "Cannot create worker GC thread. Out of system resources.");
+ if (!DisableStartThread) {
+ os::start_thread(new_worker);
+ }
+ }
+}
+
+// Run a task; returns when the task is done, or the workers yield,
+// or the task is aborted, or the work gang is terminated via stop().
+// A task that has been yielded can be continued via this interface
+// by using the same task repeatedly as the argument to the call.
+// It is expected that the YieldingFlexibleGangTask carries the appropriate
+// continuation information used by workers to continue the task
+// from its last yield point. Thus, a completed task will return
+// immediately with no actual work having been done by the workers.
+/////////////////////
+// Implementatiuon notes: remove before checking XXX
+/*
+Each gang is working on a task at a certain time.
+Some subset of workers may have yielded and some may
+have finished their quota of work. Until this task has
+been completed, the workers are bound to that task.
+Once the task has been completed, the gang unbounds
+itself from the task.
+
+The yielding work gang thus exports two invokation
+interfaces: run_task() and continue_task(). The
+first is used to initiate a new task and bind it
+to the workers; the second is used to continue an
+already bound task that has yielded. Upon completion
+the binding is released and a new binding may be
+created.
+
+The shape of a yielding work gang is as follows:
+
+Overseer invokes run_task(*task).
+ Lock gang monitor
+ Check that there is no existing binding for the gang
+ If so, abort with an error
+ Else, create a new binding of this gang to the given task
+ Set number of active workers (as asked)
+ Notify workers that work is ready to be done
+ [the requisite # workers would then start up
+ and do the task]
+ Wait on the monitor until either
+ all work is completed or the task has yielded
+ -- this is normally done through
+ yielded + completed == active
+ [completed workers are rest to idle state by overseer?]
+ return appropriate status to caller
+
+Overseer invokes continue_task(*task),
+ Lock gang monitor
+ Check that task is the same as current binding
+ If not, abort with an error
+ Else, set the number of active workers as requested?
+ Notify workers that they can continue from yield points
+ New workers can also start up as required
+ while satisfying the constraint that
+ active + yielded does not exceed required number
+ Wait (as above).
+
+NOTE: In the above, for simplicity in a first iteration
+ our gangs will be of fixed population and will not
+ therefore be flexible work gangs, just yielding work
+ gangs. Once this works well, we will in a second
+ iteration.refinement introduce flexibility into
+ the work gang.
+
+NOTE: we can always create a new gang per each iteration
+ in order to get the flexibility, but we will for now
+ desist that simplified route.
+
+ */
+/////////////////////
+void YieldingFlexibleWorkGang::start_task(YieldingFlexibleGangTask* new_task) {
+ MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
+ assert(task() == NULL, "Gang currently tied to a task");
+ assert(new_task != NULL, "Null task");
+ // Bind task to gang
+ _task = new_task;
+ new_task->set_gang(this); // Establish 2-way binding to support yielding
+ _sequence_number++;
+
+ int requested_size = new_task->requested_size();
+ assert(requested_size >= 0, "Should be non-negative");
+ if (requested_size != 0) {
+ _active_workers = MIN2(requested_size, total_workers());
+ } else {
+ _active_workers = total_workers();
+ }
+ new_task->set_actual_size(_active_workers);
+
+ assert(_started_workers == 0, "Tabula rasa non");
+ assert(_finished_workers == 0, "Tabula rasa non");
+ assert(_yielded_workers == 0, "Tabula rasa non");
+ yielding_task()->set_status(ACTIVE);
+
+ // Wake up all the workers, the first few will get to work,
+ // and the rest will go back to sleep
+ monitor()->notify_all();
+ wait_for_gang();
+}
+
+void YieldingFlexibleWorkGang::wait_for_gang() {
+
+ assert(monitor()->owned_by_self(), "Data race");
+ // Wait for task to complete or yield
+ for (Status status = yielding_task()->status();
+ status != COMPLETED && status != YIELDED && status != ABORTED;
+ status = yielding_task()->status()) {
+ assert(started_workers() <= active_workers(), "invariant");
+ assert(finished_workers() <= active_workers(), "invariant");
+ assert(yielded_workers() <= active_workers(), "invariant");
+ monitor()->wait(Mutex::_no_safepoint_check_flag);
+ }
+ switch (yielding_task()->status()) {
+ case COMPLETED:
+ case ABORTED: {
+ assert(finished_workers() == active_workers(), "Inconsistent status");
+ assert(yielded_workers() == 0, "Invariant");
+ reset(); // for next task; gang<->task binding released
+ break;
+ }
+ case YIELDED: {
+ assert(yielded_workers() > 0, "Invariant");
+ assert(yielded_workers() + finished_workers() == active_workers(),
+ "Inconsistent counts");
+ break;
+ }
+ case ACTIVE:
+ case INACTIVE:
+ case COMPLETING:
+ case YIELDING:
+ case ABORTING:
+ default:
+ ShouldNotReachHere();
+ }
+}
+
+void YieldingFlexibleWorkGang::continue_task(
+ YieldingFlexibleGangTask* gang_task) {
+
+ MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
+ assert(task() != NULL && task() == gang_task, "Incorrect usage");
+ // assert(_active_workers == total_workers(), "For now");
+ assert(_started_workers == _active_workers, "Precondition");
+ assert(_yielded_workers > 0 && yielding_task()->status() == YIELDED,
+ "Else why are we calling continue_task()");
+ // Restart the yielded gang workers
+ yielding_task()->set_status(ACTIVE);
+ monitor()->notify_all();
+ wait_for_gang();
+}
+
+void YieldingFlexibleWorkGang::reset() {
+ _started_workers = 0;
+ _finished_workers = 0;
+ _active_workers = 0;
+ yielding_task()->set_gang(NULL);
+ _task = NULL; // unbind gang from task
+}
+
+void YieldingFlexibleWorkGang::yield() {
+ assert(task() != NULL, "Inconsistency; should have task binding");
+ MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
+ assert(yielded_workers() < active_workers(), "Consistency check");
+ if (yielding_task()->status() == ABORTING) {
+ // Do not yield; we need to abort as soon as possible
+ // XXX NOTE: This can cause a performance pathology in the
+ // current implementation in Mustang, as of today, and
+ // pre-Mustang in that as soon as an overflow occurs,
+ // yields will not be honoured. The right way to proceed
+ // of course is to fix bug # TBF, so that abort's cause
+ // us to return at each potential yield point.
+ return;
+ }
+ if (++_yielded_workers + finished_workers() == active_workers()) {
+ yielding_task()->set_status(YIELDED);
+ monitor()->notify_all();
+ } else {
+ yielding_task()->set_status(YIELDING);
+ }
+
+ while (true) {
+ switch (yielding_task()->status()) {
+ case YIELDING:
+ case YIELDED: {
+ monitor()->wait(Mutex::_no_safepoint_check_flag);
+ break; // from switch
+ }
+ case ACTIVE:
+ case ABORTING:
+ case COMPLETING: {
+ assert(_yielded_workers > 0, "Else why am i here?");
+ _yielded_workers--;
+ return;
+ }
+ case INACTIVE:
+ case ABORTED:
+ case COMPLETED:
+ default: {
+ ShouldNotReachHere();
+ }
+ }
+ }
+ // Only return is from inside switch statement above
+ ShouldNotReachHere();
+}
+
+void YieldingFlexibleWorkGang::abort() {
+ assert(task() != NULL, "Inconsistency; should have task binding");
+ MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
+ assert(yielded_workers() < active_workers(), "Consistency check");
+ #ifndef PRODUCT
+ switch (yielding_task()->status()) {
+ // allowed states
+ case ACTIVE:
+ case ABORTING:
+ case COMPLETING:
+ case YIELDING:
+ break;
+ // not allowed states
+ case INACTIVE:
+ case ABORTED:
+ case COMPLETED:
+ case YIELDED:
+ default:
+ ShouldNotReachHere();
+ }
+ #endif // !PRODUCT
+ Status prev_status = yielding_task()->status();
+ yielding_task()->set_status(ABORTING);
+ if (prev_status == YIELDING) {
+ assert(yielded_workers() > 0, "Inconsistency");
+ // At least one thread has yielded, wake it up
+ // so it can go back to waiting stations ASAP.
+ monitor()->notify_all();
+ }
+}
+
+///////////////////////////////
+// YieldingFlexibleGangTask
+///////////////////////////////
+void YieldingFlexibleGangTask::yield() {
+ assert(gang() != NULL, "No gang to signal");
+ gang()->yield();
+}
+
+void YieldingFlexibleGangTask::abort() {
+ assert(gang() != NULL, "No gang to signal");
+ gang()->abort();
+}
+
+///////////////////////////////
+// YieldingFlexibleGangWorker
+///////////////////////////////
+void YieldingFlexibleGangWorker::loop() {
+ int previous_sequence_number = 0;
+ Monitor* gang_monitor = gang()->monitor();
+ MutexLockerEx ml(gang_monitor, Mutex::_no_safepoint_check_flag);
+ WorkData data;
+ int id;
+ while (true) {
+ // Check if there is work to do or if we have been asked
+ // to terminate
+ gang()->internal_worker_poll(&data);
+ if (data.terminate()) {
+ // We have been asked to terminate.
+ assert(gang()->task() == NULL, "No task binding");
+ // set_status(TERMINATED);
+ return;
+ } else if (data.task() != NULL &&
+ data.sequence_number() != previous_sequence_number) {
+ // There is work to be done.
+ // First check if we need to become active or if there
+ // are already the requisite number of workers
+ if (gang()->started_workers() == yf_gang()->active_workers()) {
+ // There are already enough workers, we do not need to
+ // to run; fall through and wait on monitor.
+ } else {
+ // We need to pitch in and do the work.
+ assert(gang()->started_workers() < yf_gang()->active_workers(),
+ "Unexpected state");
+ id = gang()->started_workers();
+ gang()->internal_note_start();
+ // Now, release the gang mutex and do the work.
+ {
+ MutexUnlockerEx mul(gang_monitor, Mutex::_no_safepoint_check_flag);
+ data.task()->work(id); // This might include yielding
+ }
+ // Reacquire monitor and note completion of this worker
+ gang()->internal_note_finish();
+ // Update status of task based on whether all workers have
+ // finished or some have yielded
+ assert(data.task() == gang()->task(), "Confused task binding");
+ if (gang()->finished_workers() == yf_gang()->active_workers()) {
+ switch (data.yf_task()->status()) {
+ case ABORTING: {
+ data.yf_task()->set_status(ABORTED);
+ break;
+ }
+ case ACTIVE:
+ case COMPLETING: {
+ data.yf_task()->set_status(COMPLETED);
+ break;
+ }
+ default:
+ ShouldNotReachHere();
+ }
+ gang_monitor->notify_all(); // Notify overseer
+ } else { // at least one worker is still working or yielded
+ assert(gang()->finished_workers() < yf_gang()->active_workers(),
+ "Counts inconsistent");
+ switch (data.yf_task()->status()) {
+ case ACTIVE: {
+ // first, but not only thread to complete
+ data.yf_task()->set_status(COMPLETING);
+ break;
+ }
+ case YIELDING: {
+ if (gang()->finished_workers() + yf_gang()->yielded_workers()
+ == yf_gang()->active_workers()) {
+ data.yf_task()->set_status(YIELDED);
+ gang_monitor->notify_all(); // notify overseer
+ }
+ break;
+ }
+ case ABORTING:
+ case COMPLETING: {
+ break; // nothing to do
+ }
+ default: // everything else: INACTIVE, YIELDED, ABORTED, COMPLETED
+ ShouldNotReachHere();
+ }
+ }
+ }
+ }
+ // Remember the sequence number
+ previous_sequence_number = data.sequence_number();
+ // Wait for more work
+ gang_monitor->wait(Mutex::_no_safepoint_check_flag);
+ }
+}
diff --git a/src/share/vm/utilities/yieldingWorkgroup.hpp b/src/share/vm/utilities/yieldingWorkgroup.hpp
new file mode 100644
index 000000000..d7890f17d
--- /dev/null
+++ b/src/share/vm/utilities/yieldingWorkgroup.hpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+// Forward declarations
+class YieldingFlexibleWorkGang;
+
+// Status of tasks
+enum Status {
+ INACTIVE,
+ ACTIVE,
+ YIELDING,
+ YIELDED,
+ ABORTING,
+ ABORTED,
+ COMPLETING,
+ COMPLETED
+};
+
+// Class YieldingFlexibleGangWorker:
+// Several instances of this class run in parallel as workers for a gang.
+class YieldingFlexibleGangWorker: public GangWorker {
+public:
+ // Ctor
+ YieldingFlexibleGangWorker(AbstractWorkGang* gang, int id) :
+ GangWorker(gang, id) { }
+
+public:
+ YieldingFlexibleWorkGang* yf_gang() const
+ { return (YieldingFlexibleWorkGang*)gang(); }
+
+protected: // Override from parent class
+ virtual void loop();
+};
+
+// An abstract task to be worked on by a flexible work gang,
+// and where the workers will periodically yield, usually
+// in response to some condition that is signalled by means
+// that are specific to the task at hand.
+// You subclass this to supply your own work() method.
+// A second feature of this kind of work gang is that
+// it allows for the signalling of certain exceptional
+// conditions that may be encountered during the performance
+// of the task and that may require the task at hand to be
+// `aborted' forthwith. Finally, these gangs are `flexible'
+// in that they can operate at partial capacity with some
+// gang workers waiting on the bench; in other words, the
+// size of the active worker pool can flex (up to an apriori
+// maximum) in response to task requests at certain points.
+// The last part (the flexible part) has not yet been fully
+// fleshed out and is a work in progress.
+class YieldingFlexibleGangTask: public AbstractGangTask {
+ Status _status;
+ YieldingFlexibleWorkGang* _gang;
+ int _actual_size; // size of gang obtained
+
+protected:
+ int _requested_size; // size of gang requested
+
+ // Constructor and desctructor: only construct subclasses.
+ YieldingFlexibleGangTask(const char* name): AbstractGangTask(name),
+ _status(INACTIVE),
+ _gang(NULL),
+ _requested_size(0) { }
+
+ virtual ~YieldingFlexibleGangTask() { }
+
+ friend class YieldingFlexibleWorkGang;
+ friend class YieldingFlexibleGangWorker;
+ NOT_PRODUCT(virtual bool is_YieldingFlexibleGang_task() const {
+ return true;
+ })
+
+ void set_status(Status s) {
+ _status = s;
+ }
+ YieldingFlexibleWorkGang* gang() {
+ return _gang;
+ }
+ void set_gang(YieldingFlexibleWorkGang* gang) {
+ assert(_gang == NULL || gang == NULL, "Clobber without intermediate reset?");
+ _gang = gang;
+ }
+
+public:
+ // The abstract work method.
+ // The argument tells you which member of the gang you are.
+ virtual void work(int i) = 0;
+
+ // Subclasses should call the parent's yield() method
+ // after having done any work specific to the subclass.
+ virtual void yield();
+
+ // An abstract method supplied by
+ // a concrete sub-class which is used by the coordinator
+ // to do any "central yielding" work.
+ virtual void coordinator_yield() = 0;
+
+ // Subclasses should call the parent's abort() method
+ // after having done any work specific to the sunbclass.
+ virtual void abort();
+
+ Status status() const { return _status; }
+ bool yielded() const { return _status == YIELDED; }
+ bool completed() const { return _status == COMPLETED; }
+ bool aborted() const { return _status == ABORTED; }
+ bool active() const { return _status == ACTIVE; }
+
+ int requested_size() const { return _requested_size; }
+ int actual_size() const { return _actual_size; }
+
+ void set_requested_size(int sz) { _requested_size = sz; }
+ void set_actual_size(int sz) { _actual_size = sz; }
+};
+
+// Class YieldingWorkGang: A subclass of WorkGang.
+// In particular, a YieldingWorkGang is made up of
+// YieldingGangWorkers, and provides infrastructure
+// supporting yielding to the "GangOverseer",
+// being the thread that orchestrates the WorkGang via run_task().
+class YieldingFlexibleWorkGang: public AbstractWorkGang {
+ // Here's the public interface to this class.
+public:
+ // Constructor and destructor.
+ YieldingFlexibleWorkGang(const char* name, int workers, bool are_GC_threads);
+
+ YieldingFlexibleGangTask* yielding_task() const {
+ assert(task() == NULL || task()->is_YieldingFlexibleGang_task(),
+ "Incorrect cast");
+ return (YieldingFlexibleGangTask*)task();
+ }
+ // Run a task; returns when the task is done, or the workers yield,
+ // or the task is aborted, or the work gang is terminated via stop().
+ // A task that has been yielded can be continued via this same interface
+ // by using the same task repeatedly as the argument to the call.
+ // It is expected that the YieldingFlexibleGangTask carries the appropriate
+ // continuation information used by workers to continue the task
+ // from its last yield point. Thus, a completed task will return
+ // immediately with no actual work having been done by the workers.
+ void run_task(AbstractGangTask* task) {
+ guarantee(false, "Use start_task instead");
+ }
+ void start_task(YieldingFlexibleGangTask* new_task);
+ void continue_task(YieldingFlexibleGangTask* gang_task);
+
+ // Abort a currently running task, if any; returns when all the workers
+ // have stopped working on the current task and have returned to their
+ // waiting stations.
+ void abort_task();
+
+ // Yield: workers wait at their current working stations
+ // until signalled to proceed by the overseer.
+ void yield();
+
+ // Abort: workers are expected to return to their waiting
+ // stations, whence they are ready for the next task dispatched
+ // by the overseer.
+ void abort();
+
+private:
+ // The currently active workers in this gang.
+ // This is a number that is dynamically adjusted by
+ // the run_task() method at each subsequent invocation,
+ // using data in the YieldingFlexibleGangTask.
+ int _active_workers;
+ int _yielded_workers;
+ void wait_for_gang();
+
+public:
+ // Accessors for fields
+ int active_workers() const {
+ return _active_workers;
+ }
+
+ int yielded_workers() const {
+ return _yielded_workers;
+ }
+
+private:
+ friend class YieldingFlexibleGangWorker;
+ void reset(); // NYI
+};