提交 c6a62a43 编写于 作者: A amurillo

Merge

...@@ -29,11 +29,10 @@ public interface JVMTIThreadState { ...@@ -29,11 +29,10 @@ public interface JVMTIThreadState {
public static final int JVMTI_THREAD_STATE_ALIVE = 0x0001; public static final int JVMTI_THREAD_STATE_ALIVE = 0x0001;
public static final int JVMTI_THREAD_STATE_TERMINATED = 0x0002; public static final int JVMTI_THREAD_STATE_TERMINATED = 0x0002;
public static final int JVMTI_THREAD_STATE_RUNNABLE = 0x0004; public static final int JVMTI_THREAD_STATE_RUNNABLE = 0x0004;
public static final int JVMTI_THREAD_STATE_WAITING = 0x0008; public static final int JVMTI_THREAD_STATE_WAITING = 0x0080;
public static final int JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010; public static final int JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010;
public static final int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020; public static final int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020;
public static final int JVMTI_THREAD_STATE_SLEEPING = 0x0040; public static final int JVMTI_THREAD_STATE_SLEEPING = 0x0040;
public static final int JVMTI_THREAD_STATE_WAITING_FOR_NOTIFICATION = 0x0080;
public static final int JVMTI_THREAD_STATE_IN_OBJECT_WAIT = 0x0100; public static final int JVMTI_THREAD_STATE_IN_OBJECT_WAIT = 0x0100;
public static final int JVMTI_THREAD_STATE_PARKED = 0x0200; public static final int JVMTI_THREAD_STATE_PARKED = 0x0200;
public static final int JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER = 0x0400; public static final int JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER = 0x0400;
......
...@@ -32,7 +32,7 @@ import sun.jvm.hotspot.types.*; ...@@ -32,7 +32,7 @@ import sun.jvm.hotspot.types.*;
// to the sys_thread_t structure of the classic JVM implementation. // to the sys_thread_t structure of the classic JVM implementation.
public class OSThread extends VMObject { public class OSThread extends VMObject {
private static JIntField interruptedField; private static JIntField interruptedField;
private static JIntField threadIdField; private static Field threadIdField;
static { static {
VM.registerVMInitializedObserver(new Observer() { VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) { public void update(Observable o, Object data) {
...@@ -44,7 +44,7 @@ public class OSThread extends VMObject { ...@@ -44,7 +44,7 @@ public class OSThread extends VMObject {
private static synchronized void initialize(TypeDataBase db) { private static synchronized void initialize(TypeDataBase db) {
Type type = db.lookupType("OSThread"); Type type = db.lookupType("OSThread");
interruptedField = type.getJIntField("_interrupted"); interruptedField = type.getJIntField("_interrupted");
threadIdField = type.getJIntField("_thread_id"); threadIdField = type.getField("_thread_id");
} }
public OSThread(Address addr) { public OSThread(Address addr) {
...@@ -56,7 +56,7 @@ public class OSThread extends VMObject { ...@@ -56,7 +56,7 @@ public class OSThread extends VMObject {
} }
public int threadId() { public int threadId() {
return (int)threadIdField.getValue(addr); return threadIdField.getJInt(addr);
} }
} }
/* /*
* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -74,23 +74,24 @@ public class ClassDump extends Tool { ...@@ -74,23 +74,24 @@ public class ClassDump extends Tool {
public void run() { public void run() {
// Ready to go with the database... // Ready to go with the database...
try { try {
// The name of the filter always comes from a System property. if (classFilter == null) {
// If we have a pkgList, pass it, otherwise let the filter read // If not already set, the name of the filter comes from a System property.
// its own System property for the list of classes. // If we have a pkgList, pass it, otherwise let the filter read
String filterClassName = System.getProperty("sun.jvm.hotspot.tools.jcore.filter", // its own System property for the list of classes.
"sun.jvm.hotspot.tools.jcore.PackageNameFilter"); String filterClassName = System.getProperty("sun.jvm.hotspot.tools.jcore.filter",
try { "sun.jvm.hotspot.tools.jcore.PackageNameFilter");
Class filterClass = Class.forName(filterClassName); try {
if (pkgList == null) { Class filterClass = Class.forName(filterClassName);
classFilter = (ClassFilter) filterClass.newInstance(); if (pkgList == null) {
} else { classFilter = (ClassFilter) filterClass.newInstance();
Constructor con = filterClass.getConstructor(String.class); } else {
classFilter = (ClassFilter) con.newInstance(pkgList); Constructor con = filterClass.getConstructor(String.class);
classFilter = (ClassFilter) con.newInstance(pkgList);
}
} catch(Exception exp) {
System.err.println("Warning: Can not create class filter!");
} }
} catch(Exception exp) {
System.err.println("Warning: Can not create class filter!");
} }
String outputDirectory = System.getProperty("sun.jvm.hotspot.tools.jcore.outputDir", "."); String outputDirectory = System.getProperty("sun.jvm.hotspot.tools.jcore.outputDir", ".");
setOutputDirectory(outputDirectory); setOutputDirectory(outputDirectory);
......
...@@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013 ...@@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013
HS_MAJOR_VER=25 HS_MAJOR_VER=25
HS_MINOR_VER=0 HS_MINOR_VER=0
HS_BUILD_NUMBER=44 HS_BUILD_NUMBER=45
JDK_MAJOR_VER=1 JDK_MAJOR_VER=1
JDK_MINOR_VER=8 JDK_MINOR_VER=8
......
...@@ -2295,7 +2295,7 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { ...@@ -2295,7 +2295,7 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) {
if (gen_type_check) { if (gen_type_check) {
// We have determined that offset == referent_offset && src != null. // We have determined that offset == referent_offset && src != null.
// if (src->_klass->_reference_type == REF_NONE) -> continue // if (src->_klass->_reference_type == REF_NONE) -> continue
__ move(new LIR_Address(src.result(), oopDesc::klass_offset_in_bytes(), UseCompressedKlassPointers ? T_OBJECT : T_ADDRESS), src_klass); __ move(new LIR_Address(src.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), src_klass);
LIR_Address* reference_type_addr = new LIR_Address(src_klass, in_bytes(InstanceKlass::reference_type_offset()), T_BYTE); LIR_Address* reference_type_addr = new LIR_Address(src_klass, in_bytes(InstanceKlass::reference_type_offset()), T_BYTE);
LIR_Opr reference_type = new_register(T_INT); LIR_Opr reference_type = new_register(T_INT);
__ move(reference_type_addr, reference_type); __ move(reference_type_addr, reference_type);
......
...@@ -878,7 +878,7 @@ objArrayOop ClassLoader::get_system_packages(TRAPS) { ...@@ -878,7 +878,7 @@ objArrayOop ClassLoader::get_system_packages(TRAPS) {
instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) { instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
EventMark m("loading class " INTPTR_FORMAT, (address)h_name); EventMark m("loading class %s", h_name->as_C_string());
ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion); ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);
stringStream st; stringStream st;
......
...@@ -60,6 +60,28 @@ ...@@ -60,6 +60,28 @@
#define DEFAULT_VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/crash.jsp" #define DEFAULT_VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/crash.jsp"
#define DEFAULT_JAVA_LAUNCHER "generic" #define DEFAULT_JAVA_LAUNCHER "generic"
// Disable options not supported in this release, with a warning if they
// were explicitly requested on the command-line
#define UNSUPPORTED_OPTION(opt, description) \
do { \
if (opt) { \
if (FLAG_IS_CMDLINE(opt)) { \
warning(description " is disabled in this release."); \
} \
FLAG_SET_DEFAULT(opt, false); \
} \
} while(0)
#define UNSUPPORTED_GC_OPTION(gc) \
do { \
if (gc) { \
if (FLAG_IS_CMDLINE(gc)) { \
warning(#gc " is not supported in this VM. Using Serial GC."); \
} \
FLAG_SET_DEFAULT(gc, false); \
} \
} while(0)
char** Arguments::_jvm_flags_array = NULL; char** Arguments::_jvm_flags_array = NULL;
int Arguments::_num_jvm_flags = 0; int Arguments::_num_jvm_flags = 0;
char** Arguments::_jvm_args_array = NULL; char** Arguments::_jvm_args_array = NULL;
...@@ -3128,14 +3150,17 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req ...@@ -3128,14 +3150,17 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req
FLAG_SET_DEFAULT(UseLargePages, false); FLAG_SET_DEFAULT(UseLargePages, false);
} }
// Tiered compilation is undefined with C1.
TieredCompilation = false;
#else #else
if (!FLAG_IS_DEFAULT(OptoLoopAlignment) && FLAG_IS_DEFAULT(MaxLoopPad)) { if (!FLAG_IS_DEFAULT(OptoLoopAlignment) && FLAG_IS_DEFAULT(MaxLoopPad)) {
FLAG_SET_DEFAULT(MaxLoopPad, OptoLoopAlignment-1); FLAG_SET_DEFAULT(MaxLoopPad, OptoLoopAlignment-1);
} }
#endif #endif
#ifndef TIERED
// Tiered compilation is undefined.
UNSUPPORTED_OPTION(TieredCompilation, "TieredCompilation");
#endif
// If we are running in a headless jre, force java.awt.headless property // If we are running in a headless jre, force java.awt.headless property
// to be true unless the property has already been set. // to be true unless the property has already been set.
// Also allow the OS environment variable JAVA_AWT_HEADLESS to set headless state. // Also allow the OS environment variable JAVA_AWT_HEADLESS to set headless state.
...@@ -3278,29 +3303,6 @@ void Arguments::set_shared_spaces_flags() { ...@@ -3278,29 +3303,6 @@ void Arguments::set_shared_spaces_flags() {
} }
} }
// Disable options not supported in this release, with a warning if they
// were explicitly requested on the command-line
#define UNSUPPORTED_OPTION(opt, description) \
do { \
if (opt) { \
if (FLAG_IS_CMDLINE(opt)) { \
warning(description " is disabled in this release."); \
} \
FLAG_SET_DEFAULT(opt, false); \
} \
} while(0)
#define UNSUPPORTED_GC_OPTION(gc) \
do { \
if (gc) { \
if (FLAG_IS_CMDLINE(gc)) { \
warning(#gc " is not supported in this VM. Using Serial GC."); \
} \
FLAG_SET_DEFAULT(gc, false); \
} \
} while(0)
#if !INCLUDE_ALL_GCS #if !INCLUDE_ALL_GCS
static void force_serial_gc() { static void force_serial_gc() {
FLAG_SET_DEFAULT(UseSerialGC, true); FLAG_SET_DEFAULT(UseSerialGC, true);
......
/* /*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -211,9 +211,9 @@ void GCNotifier::sendNotificationInternal(TRAPS) { ...@@ -211,9 +211,9 @@ void GCNotifier::sendNotificationInternal(TRAPS) {
NotificationMark nm(request); NotificationMark nm(request);
Handle objGcInfo = createGcInfo(request->gcManager, request->gcStatInfo, THREAD); Handle objGcInfo = createGcInfo(request->gcManager, request->gcStatInfo, THREAD);
Handle objName = java_lang_String::create_from_platform_dependent_str(request->gcManager->name(), CHECK); Handle objName = java_lang_String::create_from_str(request->gcManager->name(), CHECK);
Handle objAction = java_lang_String::create_from_platform_dependent_str(request->gcAction, CHECK); Handle objAction = java_lang_String::create_from_str(request->gcAction, CHECK);
Handle objCause = java_lang_String::create_from_platform_dependent_str(request->gcCause, CHECK); Handle objCause = java_lang_String::create_from_str(request->gcCause, CHECK);
Klass* k = Management::sun_management_GarbageCollectorImpl_klass(CHECK); Klass* k = Management::sun_management_GarbageCollectorImpl_klass(CHECK);
instanceKlassHandle gc_mbean_klass(THREAD, k); instanceKlassHandle gc_mbean_klass(THREAD, k);
......
...@@ -1831,13 +1831,13 @@ class ThreadTimesClosure: public ThreadClosure { ...@@ -1831,13 +1831,13 @@ class ThreadTimesClosure: public ThreadClosure {
private: private:
objArrayHandle _names_strings; objArrayHandle _names_strings;
char **_names_chars; char **_names_chars;
typeArrayOop _times; typeArrayHandle _times;
int _names_len; int _names_len;
int _times_len; int _times_len;
int _count; int _count;
public: public:
ThreadTimesClosure(objArrayHandle names, typeArrayOop times); ThreadTimesClosure(objArrayHandle names, typeArrayHandle times);
~ThreadTimesClosure(); ~ThreadTimesClosure();
virtual void do_thread(Thread* thread); virtual void do_thread(Thread* thread);
void do_unlocked(); void do_unlocked();
...@@ -1845,9 +1845,9 @@ class ThreadTimesClosure: public ThreadClosure { ...@@ -1845,9 +1845,9 @@ class ThreadTimesClosure: public ThreadClosure {
}; };
ThreadTimesClosure::ThreadTimesClosure(objArrayHandle names, ThreadTimesClosure::ThreadTimesClosure(objArrayHandle names,
typeArrayOop times) { typeArrayHandle times) {
assert(names() != NULL, "names was NULL"); assert(names() != NULL, "names was NULL");
assert(times != NULL, "times was NULL"); assert(times() != NULL, "times was NULL");
_names_strings = names; _names_strings = names;
_names_len = names->length(); _names_len = names->length();
_names_chars = NEW_C_HEAP_ARRAY(char*, _names_len, mtInternal); _names_chars = NEW_C_HEAP_ARRAY(char*, _names_len, mtInternal);
...@@ -1925,7 +1925,7 @@ JVM_ENTRY(jint, jmm_GetInternalThreadTimes(JNIEnv *env, ...@@ -1925,7 +1925,7 @@ JVM_ENTRY(jint, jmm_GetInternalThreadTimes(JNIEnv *env,
typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(times)); typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(times));
typeArrayHandle times_ah(THREAD, ta); typeArrayHandle times_ah(THREAD, ta);
ThreadTimesClosure ttc(names_ah, times_ah()); ThreadTimesClosure ttc(names_ah, times_ah);
{ {
MutexLockerEx ml(Threads_lock); MutexLockerEx ml(Threads_lock);
Threads::threads_do(&ttc); Threads::threads_do(&ttc);
......
...@@ -125,13 +125,13 @@ void Exceptions::_throw_oop(Thread* thread, const char* file, int line, oop exce ...@@ -125,13 +125,13 @@ void Exceptions::_throw_oop(Thread* thread, const char* file, int line, oop exce
} }
void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exception, const char* message) { void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exception, const char* message) {
ResourceMark rm;
assert(h_exception() != NULL, "exception should not be NULL"); assert(h_exception() != NULL, "exception should not be NULL");
// tracing (do this up front - so it works during boot strapping) // tracing (do this up front - so it works during boot strapping)
if (TraceExceptions) { if (TraceExceptions) {
ttyLocker ttyl; ttyLocker ttyl;
ResourceMark rm; tty->print_cr("Exception <%s%s%s> (" INTPTR_FORMAT ") \n"
tty->print_cr("Exception <%s>%s%s (" INTPTR_FORMAT " ) \n"
"thrown [%s, line %d]\nfor thread " INTPTR_FORMAT, "thrown [%s, line %d]\nfor thread " INTPTR_FORMAT,
h_exception->print_value_string(), h_exception->print_value_string(),
message ? ": " : "", message ? message : "", message ? ": " : "", message ? message : "",
...@@ -141,7 +141,9 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc ...@@ -141,7 +141,9 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc
NOT_PRODUCT(Exceptions::debug_check_abort(h_exception, message)); NOT_PRODUCT(Exceptions::debug_check_abort(h_exception, message));
// Check for special boot-strapping/vm-thread handling // Check for special boot-strapping/vm-thread handling
if (special_exception(thread, file, line, h_exception)) return; 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"); assert(h_exception->is_a(SystemDictionary::Throwable_klass()), "exception is not a subclass of java/lang/Throwable");
...@@ -149,7 +151,9 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc ...@@ -149,7 +151,9 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc
thread->set_pending_exception(h_exception(), file, line); thread->set_pending_exception(h_exception(), file, line);
// vm log // vm log
Events::log_exception(thread, "Threw " INTPTR_FORMAT " at %s:%d", (address)h_exception(), file, line); Events::log_exception(thread, "Exception <%s%s%s> (" INTPTR_FORMAT ") thrown at [%s, line %d]",
h_exception->print_value_string(), message ? ": " : "", message ? message : "",
(address)h_exception(), file, line);
} }
......
...@@ -395,7 +395,13 @@ bool GenericTaskQueue<E, F, N>::pop_local_slow(uint localBot, Age oldAge) { ...@@ -395,7 +395,13 @@ bool GenericTaskQueue<E, F, N>::pop_local_slow(uint localBot, Age oldAge) {
template<class E, MEMFLAGS F, unsigned int N> template<class E, MEMFLAGS F, unsigned int N>
bool GenericTaskQueue<E, F, N>::pop_global(E& t) { bool GenericTaskQueue<E, F, N>::pop_global(E& t) {
Age oldAge = _age.get(); Age oldAge = _age.get();
uint localBot = _bottom; // Architectures with weak memory model require a barrier here
// to guarantee that bottom is not older than age,
// which is crucial for the correctness of the algorithm.
#if !(defined SPARC || defined IA32 || defined AMD64)
OrderAccess::fence();
#endif
uint localBot = OrderAccess::load_acquire((volatile juint*)&_bottom);
uint n_elems = size(localBot, oldAge.top()); uint n_elems = size(localBot, oldAge.top());
if (n_elems == 0) { if (n_elems == 0) {
return false; return false;
...@@ -644,7 +650,7 @@ public: ...@@ -644,7 +650,7 @@ public:
template<class E, MEMFLAGS F, unsigned int N> inline bool template<class E, MEMFLAGS F, unsigned int N> inline bool
GenericTaskQueue<E, F, N>::push(E t) { GenericTaskQueue<E, F, N>::push(E t) {
uint localBot = _bottom; uint localBot = _bottom;
assert((localBot >= 0) && (localBot < N), "_bottom out of range."); assert(localBot < N, "_bottom out of range.");
idx_t top = _age.top(); idx_t top = _age.top();
uint dirty_n_elems = dirty_size(localBot, top); uint dirty_n_elems = dirty_size(localBot, top);
assert(dirty_n_elems < N, "n_elems out of range."); assert(dirty_n_elems < N, "n_elems out of range.");
......
...@@ -35,10 +35,6 @@ public class CheckUpperLimit { ...@@ -35,10 +35,6 @@ public class CheckUpperLimit {
ProcessBuilder pb; ProcessBuilder pb;
OutputAnalyzer out; OutputAnalyzer out;
pb = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=2048m", "-version");
out = new OutputAnalyzer(pb.start());
out.shouldHaveExitValue(0);
pb = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=2049m", "-version"); pb = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=2049m", "-version");
out = new OutputAnalyzer(pb.start()); out = new OutputAnalyzer(pb.start());
out.shouldContain("Invalid ReservedCodeCacheSize="); out.shouldContain("Invalid ReservedCodeCacheSize=");
......
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8016474
* @summary The bug only happens with C1 and G1 using a different ObjectAlignmentInBytes than KlassAlignmentInBytes (which is 8)
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=32 GetUnsafeObjectG1PreBarrier
*/
import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class GetUnsafeObjectG1PreBarrier {
private static final Unsafe unsafe;
private static final int N = 100_000;
static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
public Object a;
public static void main(String[] args) throws Throwable {
new GetUnsafeObjectG1PreBarrier();
}
public GetUnsafeObjectG1PreBarrier() throws Throwable {
doit();
}
private void doit() throws Throwable {
Field field = GetUnsafeObjectG1PreBarrier.class.getField("a");
long fieldOffset = unsafe.objectFieldOffset(field);
for (int i = 0; i < N; i++) {
readField(this, fieldOffset);
}
}
private void readField(Object o, long fieldOffset) {
unsafe.getObject(o, fieldOffset);
}
}
#
# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# @test Test8000968.sh
# @bug 8000968
# @summary NPG: UseCompressedKlassPointers asserts with ObjectAlignmentInBytes=32
# @run shell Test8000968.sh
#
if [ "${TESTJAVA}" = "" ]
then
PARENT=`dirname \`which java\``
TESTJAVA=`dirname ${PARENT}`
printf "TESTJAVA not set, selecting " ${TESTJAVA}
printf " If this is incorrect, try setting the variable manually.\n"
fi
# set platform-dependent variables
OS=`uname -s`
case "$OS" in
Windows_* )
FS="\\"
NULL=NUL
;;
* )
FS="/"
NULL=/dev/null
;;
esac
JAVA=${TESTJAVA}${FS}bin${FS}java
#
# See if platform has 64 bit java.
#
${JAVA} ${TESTVMOPTS} -d64 -version 2>&1 | grep -i "does not support" > ${NULL}
if [ "$?" != "1" ]
then
printf "Platform is 32 bit, does not support -XX:ObjectAlignmentInBytes= option.\n"
printf "Passed.\n"
exit 0
fi
#
# Test -XX:ObjectAlignmentInBytes with -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops.
#
${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=16 -version 2>&1 > ${NULL}
if [ "$?" != "0" ]
then
printf "FAILED: -XX:ObjectAlignmentInBytes=16 option did not work.\n"
exit 1
fi
${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=32 -version 2>&1 > ${NULL}
if [ "$?" != "0" ]
then
printf "FAILED: -XX:ObjectAlignmentInBytes=32 option did not work.\n"
exit 1
fi
${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=64 -version 2>&1 > ${NULL}
if [ "$?" != "0" ]
then
printf "FAILED: -XX:ObjectAlignmentInBytes=64 option did not work.\n"
exit 1
fi
${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=128 -version 2>&1 > ${NULL}
if [ "$?" != "0" ]
then
printf "FAILED: -XX:ObjectAlignmentInBytes=128 option did not work.\n"
exit 1
fi
printf "Passed.\n"
exit 0
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8000968
* @key regression
* @summary NPG: UseCompressedKlassPointers asserts with ObjectAlignmentInBytes=32
* @library /testlibrary
*/
import com.oracle.java.testlibrary.*;
public class CompressedKlassPointerAndOops {
public static void main(String[] args) throws Exception {
if (!Platform.is64bit()) {
// Can't test this on 32 bit, just pass
System.out.println("Skipping test on 32bit");
return;
}
runWithAlignment(16);
runWithAlignment(32);
runWithAlignment(64);
runWithAlignment(128);
}
private static void runWithAlignment(int alignment) throws Exception {
ProcessBuilder pb;
OutputAnalyzer output;
pb = ProcessTools.createJavaProcessBuilder(
"-XX:+UseCompressedKlassPointers",
"-XX:+UseCompressedOops",
"-XX:ObjectAlignmentInBytes=" + alignment,
"-version");
output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
}
}
/* /*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -25,8 +25,9 @@ ...@@ -25,8 +25,9 @@
/* /*
* @test * @test
* @bug 7196045 * @bug 7196045
* @bug 8014294
* @summary Possible JVM deadlock in ThreadTimesClosure when using HotspotInternal non-public API. * @summary Possible JVM deadlock in ThreadTimesClosure when using HotspotInternal non-public API.
* @run main/othervm -XX:+UsePerfData Test7196045 * @run main/othervm -XX:+UsePerfData -Xmx32m ThreadCpuTimesDeadlock
*/ */
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
...@@ -35,9 +36,10 @@ import javax.management.MBeanServer; ...@@ -35,9 +36,10 @@ import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException; import javax.management.MalformedObjectNameException;
import javax.management.ObjectName; import javax.management.ObjectName;
public class Test7196045 { public class ThreadCpuTimesDeadlock {
public static long duration = 1000 * 60 * 2; public static byte[] dummy;
public static long duration = 10 * 1000;
private static final String HOTSPOT_INTERNAL = "sun.management:type=HotspotInternal"; private static final String HOTSPOT_INTERNAL = "sun.management:type=HotspotInternal";
public static void main(String[] args) { public static void main(String[] args) {
...@@ -57,6 +59,18 @@ public class Test7196045 { ...@@ -57,6 +59,18 @@ public class Test7196045 {
throw new RuntimeException("Bad object name" + e1); throw new RuntimeException("Bad object name" + e1);
} }
// Thread that allocs memory to generate GC's
Thread allocThread = new Thread() {
public void run() {
while (true) {
dummy = new byte[4096];
}
}
};
allocThread.setDaemon(true);
allocThread.start();
long endTime = System.currentTimeMillis() + duration; long endTime = System.currentTimeMillis() + duration;
long i = 0; long i = 0;
while (true) { while (true) {
......
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Test the OutputAnalyzer reporting functionality,
* such as printing additional diagnostic info
* (exit code, stdout, stderr, command line, etc.)
* @library /testlibrary
*/
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import com.oracle.java.testlibrary.OutputAnalyzer;
import com.oracle.java.testlibrary.ProcessTools;
public class OutputAnalyzerReportingTest {
public static void main(String[] args) throws Exception {
// Create the output analyzer under test
String stdout = "aaaaaa";
String stderr = "bbbbbb";
OutputAnalyzer output = new OutputAnalyzer(stdout, stderr);
// Expected summary values should be the same for all cases,
// since the outputAnalyzer object is the same
String expectedExitValue = "-1";
String expectedSummary =
" stdout: [" + stdout + "];\n" +
" stderr: [" + stderr + "]\n" +
" exitValue = " + expectedExitValue + "\n";
DiagnosticSummaryTestRunner testRunner =
new DiagnosticSummaryTestRunner();
// should have exit value
testRunner.init(expectedSummary);
int unexpectedExitValue = 2;
try {
output.shouldHaveExitValue(unexpectedExitValue);
} catch (RuntimeException e) { }
testRunner.closeAndCheckResults();
// should not contain
testRunner.init(expectedSummary);
try {
output.shouldNotContain(stdout);
} catch (RuntimeException e) { }
testRunner.closeAndCheckResults();
// should contain
testRunner.init(expectedSummary);
try {
output.shouldContain("unexpected-stuff");
} catch (RuntimeException e) { }
testRunner.closeAndCheckResults();
// should not match
testRunner.init(expectedSummary);
try {
output.shouldNotMatch("[a]");
} catch (RuntimeException e) { }
testRunner.closeAndCheckResults();
// should match
testRunner.init(expectedSummary);
try {
output.shouldMatch("[qwerty]");
} catch (RuntimeException e) { }
testRunner.closeAndCheckResults();
}
private static class DiagnosticSummaryTestRunner {
private ByteArrayOutputStream byteStream =
new ByteArrayOutputStream(10000);
private String expectedSummary = "";
private PrintStream errStream;
public void init(String expectedSummary) {
this.expectedSummary = expectedSummary;
byteStream.reset();
errStream = new PrintStream(byteStream);
System.setErr(errStream);
}
public void closeAndCheckResults() {
// check results
errStream.close();
String stdErrStr = byteStream.toString();
if (!stdErrStr.contains(expectedSummary)) {
throw new RuntimeException("The output does not contain "
+ "the diagnostic message, or the message is incorrect");
}
}
}
}
...@@ -76,7 +76,8 @@ public final class OutputAnalyzer { ...@@ -76,7 +76,8 @@ public final class OutputAnalyzer {
*/ */
public void shouldContain(String expectedString) { public void shouldContain(String expectedString) {
if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) { if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) {
throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr: [" + stdout + stderr + "]\n"); reportDiagnosticSummary();
throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr \n");
} }
} }
...@@ -88,7 +89,8 @@ public final class OutputAnalyzer { ...@@ -88,7 +89,8 @@ public final class OutputAnalyzer {
*/ */
public void stdoutShouldContain(String expectedString) { public void stdoutShouldContain(String expectedString) {
if (!stdout.contains(expectedString)) { if (!stdout.contains(expectedString)) {
throw new RuntimeException("'" + expectedString + "' missing from stdout: [" + stdout + "]\n"); reportDiagnosticSummary();
throw new RuntimeException("'" + expectedString + "' missing from stdout \n");
} }
} }
...@@ -100,7 +102,8 @@ public final class OutputAnalyzer { ...@@ -100,7 +102,8 @@ public final class OutputAnalyzer {
*/ */
public void stderrShouldContain(String expectedString) { public void stderrShouldContain(String expectedString) {
if (!stderr.contains(expectedString)) { if (!stderr.contains(expectedString)) {
throw new RuntimeException("'" + expectedString + "' missing from stderr: [" + stderr + "]\n"); reportDiagnosticSummary();
throw new RuntimeException("'" + expectedString + "' missing from stderr \n");
} }
} }
...@@ -112,10 +115,12 @@ public final class OutputAnalyzer { ...@@ -112,10 +115,12 @@ public final class OutputAnalyzer {
*/ */
public void shouldNotContain(String notExpectedString) { public void shouldNotContain(String notExpectedString) {
if (stdout.contains(notExpectedString)) { if (stdout.contains(notExpectedString)) {
throw new RuntimeException("'" + notExpectedString + "' found in stdout: [" + stdout + "]\n"); reportDiagnosticSummary();
throw new RuntimeException("'" + notExpectedString + "' found in stdout \n");
} }
if (stderr.contains(notExpectedString)) { if (stderr.contains(notExpectedString)) {
throw new RuntimeException("'" + notExpectedString + "' found in stderr: [" + stderr + "]\n"); reportDiagnosticSummary();
throw new RuntimeException("'" + notExpectedString + "' found in stderr \n");
} }
} }
...@@ -127,7 +132,8 @@ public final class OutputAnalyzer { ...@@ -127,7 +132,8 @@ public final class OutputAnalyzer {
*/ */
public void stdoutShouldNotContain(String notExpectedString) { public void stdoutShouldNotContain(String notExpectedString) {
if (stdout.contains(notExpectedString)) { if (stdout.contains(notExpectedString)) {
throw new RuntimeException("'" + notExpectedString + "' found in stdout: [" + stdout + "]\n"); reportDiagnosticSummary();
throw new RuntimeException("'" + notExpectedString + "' found in stdout \n");
} }
} }
...@@ -139,7 +145,8 @@ public final class OutputAnalyzer { ...@@ -139,7 +145,8 @@ public final class OutputAnalyzer {
*/ */
public void stderrShouldNotContain(String notExpectedString) { public void stderrShouldNotContain(String notExpectedString) {
if (stderr.contains(notExpectedString)) { if (stderr.contains(notExpectedString)) {
throw new RuntimeException("'" + notExpectedString + "' found in stderr: [" + stderr + "]\n"); reportDiagnosticSummary();
throw new RuntimeException("'" + notExpectedString + "' found in stderr \n");
} }
} }
...@@ -154,9 +161,9 @@ public final class OutputAnalyzer { ...@@ -154,9 +161,9 @@ public final class OutputAnalyzer {
Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
if (!stdoutMatcher.find() && !stderrMatcher.find()) { if (!stdoutMatcher.find() && !stderrMatcher.find()) {
reportDiagnosticSummary();
throw new RuntimeException("'" + pattern throw new RuntimeException("'" + pattern
+ "' missing from stdout/stderr: [" + stdout + stderr + "' missing from stdout/stderr \n");
+ "]\n");
} }
} }
...@@ -170,8 +177,9 @@ public final class OutputAnalyzer { ...@@ -170,8 +177,9 @@ public final class OutputAnalyzer {
public void stdoutShouldMatch(String pattern) { public void stdoutShouldMatch(String pattern) {
Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
if (!matcher.find()) { if (!matcher.find()) {
reportDiagnosticSummary();
throw new RuntimeException("'" + pattern throw new RuntimeException("'" + pattern
+ "' missing from stdout: [" + stdout + "]\n"); + "' missing from stdout \n");
} }
} }
...@@ -185,8 +193,9 @@ public final class OutputAnalyzer { ...@@ -185,8 +193,9 @@ public final class OutputAnalyzer {
public void stderrShouldMatch(String pattern) { public void stderrShouldMatch(String pattern) {
Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
if (!matcher.find()) { if (!matcher.find()) {
reportDiagnosticSummary();
throw new RuntimeException("'" + pattern throw new RuntimeException("'" + pattern
+ "' missing from stderr: [" + stderr + "]\n"); + "' missing from stderr \n");
} }
} }
...@@ -200,13 +209,15 @@ public final class OutputAnalyzer { ...@@ -200,13 +209,15 @@ public final class OutputAnalyzer {
public void shouldNotMatch(String pattern) { public void shouldNotMatch(String pattern) {
Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
if (matcher.find()) { if (matcher.find()) {
reportDiagnosticSummary();
throw new RuntimeException("'" + pattern throw new RuntimeException("'" + pattern
+ "' found in stdout: [" + stdout + "]\n"); + "' found in stdout \n");
} }
matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
if (matcher.find()) { if (matcher.find()) {
reportDiagnosticSummary();
throw new RuntimeException("'" + pattern throw new RuntimeException("'" + pattern
+ "' found in stderr: [" + stderr + "]\n"); + "' found in stderr \n");
} }
} }
...@@ -220,8 +231,9 @@ public final class OutputAnalyzer { ...@@ -220,8 +231,9 @@ public final class OutputAnalyzer {
public void stdoutShouldNotMatch(String pattern) { public void stdoutShouldNotMatch(String pattern) {
Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
if (matcher.find()) { if (matcher.find()) {
reportDiagnosticSummary();
throw new RuntimeException("'" + pattern throw new RuntimeException("'" + pattern
+ "' found in stdout: [" + stdout + "]\n"); + "' found in stdout \n");
} }
} }
...@@ -235,23 +247,45 @@ public final class OutputAnalyzer { ...@@ -235,23 +247,45 @@ public final class OutputAnalyzer {
public void stderrShouldNotMatch(String pattern) { public void stderrShouldNotMatch(String pattern) {
Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
if (matcher.find()) { if (matcher.find()) {
reportDiagnosticSummary();
throw new RuntimeException("'" + pattern throw new RuntimeException("'" + pattern
+ "' found in stderr: [" + stderr + "]\n"); + "' found in stderr \n");
} }
} }
/** /**
* Verifiy the exit value of the process * Verify the exit value of the process
* *
* @param expectedExitValue Expected exit value from process * @param expectedExitValue Expected exit value from process
* @throws RuntimeException If the exit value from the process did not match the expected value * @throws RuntimeException If the exit value from the process did not match the expected value
*/ */
public void shouldHaveExitValue(int expectedExitValue) { public void shouldHaveExitValue(int expectedExitValue) {
if (getExitValue() != expectedExitValue) { if (getExitValue() != expectedExitValue) {
throw new RuntimeException("Exit value " + getExitValue() + " , expected to get " + expectedExitValue); reportDiagnosticSummary();
throw new RuntimeException("Expected to get exit value of ["
+ expectedExitValue + "]\n");
} }
} }
/**
* Report summary that will help to diagnose the problem
* Currently includes:
* - standard input produced by the process under test
* - standard output
* - exit code
* Note: the command line is printed by the ProcessTools
*/
private void reportDiagnosticSummary() {
String msg =
" stdout: [" + stdout + "];\n" +
" stderr: [" + stderr + "]\n" +
" exitValue = " + getExitValue() + "\n";
System.err.println(msg);
}
/** /**
* Get the contents of the output buffer (stdout and stderr) * Get the contents of the output buffer (stdout and stderr)
* *
......
...@@ -27,6 +27,7 @@ public class Platform { ...@@ -27,6 +27,7 @@ public class Platform {
private static final String osName = System.getProperty("os.name"); private static final String osName = System.getProperty("os.name");
private static final String dataModel = System.getProperty("sun.arch.data.model"); private static final String dataModel = System.getProperty("sun.arch.data.model");
private static final String vmVersion = System.getProperty("java.vm.version"); private static final String vmVersion = System.getProperty("java.vm.version");
private static final String osArch = System.getProperty("os.arch");
public static boolean is64bit() { public static boolean is64bit() {
return dataModel.equals("64"); return dataModel.equals("64");
...@@ -59,4 +60,14 @@ public class Platform { ...@@ -59,4 +60,14 @@ public class Platform {
public static String getVMVersion() { public static String getVMVersion() {
return vmVersion; return vmVersion;
} }
// Returns true for sparc and sparcv9.
public static boolean isSparc() {
return osArch.toLowerCase().startsWith("sparc");
}
public static String getOsArch() {
return osArch;
}
} }
...@@ -31,6 +31,7 @@ import java.lang.reflect.Field; ...@@ -31,6 +31,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import sun.management.VMManagement; import sun.management.VMManagement;
...@@ -106,6 +107,22 @@ public final class ProcessTools { ...@@ -106,6 +107,22 @@ public final class ProcessTools {
return pid; return pid;
} }
/**
* Get the string containing input arguments passed to the VM
*
* @return arguments
*/
public static String getVmInputArguments() {
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
List<String> args = runtime.getInputArguments();
StringBuilder result = new StringBuilder();
for (String arg : args)
result.append(arg).append(' ');
return result.toString();
}
/** /**
* Get platform specific VM arguments (e.g. -d64 on 64bit Solaris) * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris)
* *
...@@ -132,8 +149,13 @@ public final class ProcessTools { ...@@ -132,8 +149,13 @@ public final class ProcessTools {
Collections.addAll(args, getPlatformSpecificVMArgs()); Collections.addAll(args, getPlatformSpecificVMArgs());
Collections.addAll(args, command); Collections.addAll(args, command);
return new ProcessBuilder(args.toArray(new String[args.size()])); // Reporting
StringBuilder cmdLine = new StringBuilder();
for (String cmd : args)
cmdLine.append(cmd).append(' ');
System.out.println("Command line: [" + cmdLine.toString() + "]");
return new ProcessBuilder(args.toArray(new String[args.size()]));
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册