提交 726fcc4e 编写于 作者: D dcubed

6670684: 4/5 SA command universe did not print out CMS space information

Summary: Forward port of Yumin's fix for 6670684 from HSX-11; Yumin verified the port was correct.
Reviewed-by: dcubed
上级 3598f463
...@@ -246,16 +246,16 @@ SA_PROPERTIES = $(OUTPUT_DIR)/sa.properties ...@@ -246,16 +246,16 @@ SA_PROPERTIES = $(OUTPUT_DIR)/sa.properties
all: filelist all: filelist
@mkdir -p $(OUTPUT_DIR) @mkdir -p $(OUTPUT_DIR)
@echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) @echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES)
@javac -source 1.4 -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist @${JDK_HOME}/bin/javac -source 1.4 -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist
@rmic -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer @${JDK_HOME}/bin/rmic -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer
rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql/sa.js rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql/sa.js
cp $(SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql cp $(SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql
allprof: filelist allprof: filelist
@mkdir -p $(OUTPUT_DIR) @mkdir -p $(OUTPUT_DIR)
@echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) @echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES)
@javac -source 1.4 -J-Xprof -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist @${JDK_HOME}/bin/javac -source 1.4 -J-Xprof -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist
@rmic -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer @${JDK_HOME}/bin/rmic -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer
rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql/sa.js rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql/sa.js
cp $(SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql cp $(SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql
......
...@@ -398,7 +398,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener { ...@@ -398,7 +398,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
frame.getContentPane().add(desktop); frame.getContentPane().add(desktop);
GraphicsUtilities.reshapeToAspectRatio(frame, 4.0f/3.0f, 0.75f, Toolkit.getDefaultToolkit().getScreenSize()); GraphicsUtilities.reshapeToAspectRatio(frame, 4.0f/3.0f, 0.75f, Toolkit.getDefaultToolkit().getScreenSize());
GraphicsUtilities.centerInContainer(frame, Toolkit.getDefaultToolkit().getScreenSize()); GraphicsUtilities.centerInContainer(frame, Toolkit.getDefaultToolkit().getScreenSize());
frame.show(); frame.setVisible(true);
Runtime.getRuntime().addShutdownHook(new java.lang.Thread() { Runtime.getRuntime().addShutdownHook(new java.lang.Thread() {
public void run() { public void run() {
......
...@@ -148,7 +148,7 @@ public class SALauncherLoader extends URLClassLoader { ...@@ -148,7 +148,7 @@ public class SALauncherLoader extends URLClassLoader {
} }
try { try {
return file.toURL(); return file.toURI().toURL();
} catch (MalformedURLException mue) { } catch (MalformedURLException mue) {
throw new InternalError(mue.getMessage()); throw new InternalError(mue.getMessage());
} }
......
...@@ -47,6 +47,6 @@ public class Main { ...@@ -47,6 +47,6 @@ public class Main {
4.0f/3.0f, 0.85f, Toolkit.getDefaultToolkit().getScreenSize()); 4.0f/3.0f, 0.85f, Toolkit.getDefaultToolkit().getScreenSize());
GraphicsUtilities.centerInContainer(frame, GraphicsUtilities.centerInContainer(frame,
Toolkit.getDefaultToolkit().getScreenSize()); Toolkit.getDefaultToolkit().getScreenSize());
frame.show(); frame.setVisible(true);
} }
} }
...@@ -78,7 +78,7 @@ class SAJDIClassLoader extends URLClassLoader { ...@@ -78,7 +78,7 @@ class SAJDIClassLoader extends URLClassLoader {
this(parent); this(parent);
this.classPathSet = true; this.classPathSet = true;
try { try {
addURL(new File(classPath).toURL()); addURL(new File(classPath).toURI().toURL());
} catch(MalformedURLException mue) { } catch(MalformedURLException mue) {
throw new RuntimeException(mue); throw new RuntimeException(mue);
} }
......
/*
* @(#)BinaryTreeDictionary.java
* Copyright 2000-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.
*
*/
package sun.jvm.hotspot.memory;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.runtime.*;
public class BinaryTreeDictionary extends VMObject {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private static synchronized void initialize(TypeDataBase db) {
Type type = db.lookupType("BinaryTreeDictionary");
totalSizeField = type.getCIntegerField("_totalSize");
}
// Fields
private static CIntegerField totalSizeField;
// Accessors
public long size() {
return totalSizeField.getValue(addr);
}
// Constructor
public BinaryTreeDictionary(Address addr) {
super(addr);
}
}
...@@ -35,6 +35,20 @@ import sun.jvm.hotspot.utilities.*; ...@@ -35,6 +35,20 @@ import sun.jvm.hotspot.utilities.*;
public class CompactibleFreeListSpace extends CompactibleSpace { public class CompactibleFreeListSpace extends CompactibleSpace {
private static AddressField collectorField; private static AddressField collectorField;
// for free size, three fields
// FreeBlockDictionary* _dictionary; // ptr to dictionary for large size blocks
// FreeList _indexedFreeList[IndexSetSize]; // indexed array for small size blocks
// LinearAllocBlock _smallLinearAllocBlock; // small linear alloc in TLAB
private static AddressField indexedFreeListField;
private static AddressField dictionaryField;
private static long smallLinearAllocBlockFieldOffset;
private static long indexedFreeListSizeOf;
private int heapWordSize; // 4 for 32bit, 8 for 64 bits
private int IndexSetStart; // for small indexed list
private int IndexSetSize;
private int IndexSetStride;
static { static {
VM.registerVMInitializedObserver(new Observer() { VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) { public void update(Observable o, Object data) {
...@@ -51,10 +65,26 @@ public class CompactibleFreeListSpace extends CompactibleSpace { ...@@ -51,10 +65,26 @@ public class CompactibleFreeListSpace extends CompactibleSpace {
Type type = db.lookupType("CompactibleFreeListSpace"); Type type = db.lookupType("CompactibleFreeListSpace");
collectorField = type.getAddressField("_collector"); collectorField = type.getAddressField("_collector");
collectorField = type.getAddressField("_collector");
dictionaryField = type.getAddressField("_dictionary");
indexedFreeListField = type.getAddressField("_indexedFreeList[0]");
smallLinearAllocBlockFieldOffset = type.getField("_smallLinearAllocBlock").getOffset();
} }
public CompactibleFreeListSpace(Address addr) { public CompactibleFreeListSpace(Address addr) {
super(addr); super(addr);
if ( VM.getVM().isLP64() ) {
heapWordSize = 8;
IndexSetStart = 1;
IndexSetStride = 1;
}
else {
heapWordSize = 4;
IndexSetStart = 2;
IndexSetStride = 2;
}
IndexSetSize = 257;
} }
// Accessing block offset table // Accessing block offset table
...@@ -62,9 +92,17 @@ public class CompactibleFreeListSpace extends CompactibleSpace { ...@@ -62,9 +92,17 @@ public class CompactibleFreeListSpace extends CompactibleSpace {
return (CMSCollector) VMObjectFactory.newObject( return (CMSCollector) VMObjectFactory.newObject(
CMSCollector.class, CMSCollector.class,
collectorField.getValue(addr)); collectorField.getValue(addr));
} }
public long free0() {
return capacity() - used0();
}
public long used() { public long used() {
return capacity() - free();
}
public long used0() {
List regions = getLiveRegions(); List regions = getLiveRegions();
long usedSize = 0L; long usedSize = 0L;
for (Iterator itr = regions.iterator(); itr.hasNext();) { for (Iterator itr = regions.iterator(); itr.hasNext();) {
...@@ -75,11 +113,41 @@ public class CompactibleFreeListSpace extends CompactibleSpace { ...@@ -75,11 +113,41 @@ public class CompactibleFreeListSpace extends CompactibleSpace {
} }
public long free() { public long free() {
return capacity() - used(); // small chunks
} long size = 0;
Address cur = addr.addOffsetTo( indexedFreeListField.getOffset() );
cur = cur.addOffsetTo(IndexSetStart*FreeList.sizeOf());
for (int i=IndexSetStart; i<IndexSetSize; i += IndexSetStride) {
FreeList freeList = (FreeList) VMObjectFactory.newObject(FreeList.class, cur);
size += i*freeList.count();
cur= cur.addOffsetTo(IndexSetStride*FreeList.sizeOf());
}
// large block
BinaryTreeDictionary bfbd = (BinaryTreeDictionary) VMObjectFactory.newObject(BinaryTreeDictionary.class,
dictionaryField.getValue(addr));
size += bfbd.size();
// linear block in TLAB
LinearAllocBlock lab = (LinearAllocBlock) VMObjectFactory.newObject(LinearAllocBlock.class,
addr.addOffsetTo(smallLinearAllocBlockFieldOffset));
size += lab.word_size();
return size*heapWordSize;
}
public void printOn(PrintStream tty) { public void printOn(PrintStream tty) {
tty.print("free-list-space"); tty.print("free-list-space");
tty.print("[ " + bottom() + " , " + end() + " ) ");
long cap = capacity();
long used_size = used();
long free_size = free();
int used_perc = (int)((double)used_size/cap*100);
tty.print("space capacity = " + cap + " used(" + used_perc + "%)= " + used_size + " ");
tty.print("free= " + free_size );
tty.print("\n");
} }
public Address skipBlockSizeUsingPrintezisBits(Address pos) { public Address skipBlockSizeUsingPrintezisBits(Address pos) {
......
...@@ -96,9 +96,9 @@ public class DefNewGeneration extends Generation { ...@@ -96,9 +96,9 @@ public class DefNewGeneration extends Generation {
public void printOn(PrintStream tty) { public void printOn(PrintStream tty) {
tty.print(" eden"); tty.print(" eden");
eden().printOn(tty); eden().printOn(tty);
tty.print(" from"); tty.print("\n from");
from().printOn(tty); from().printOn(tty);
tty.print(" to "); tty.print("\n to ");
to().printOn(tty); to().printOn(tty);
} }
} }
/*
* @(#)FreeList.java
*
* Copyright 2000-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.
*
*/
package sun.jvm.hotspot.memory;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.runtime.*;
public class FreeList extends VMObject {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private static synchronized void initialize(TypeDataBase db) {
Type type = db.lookupType("FreeList");
sizeField = type.getCIntegerField("_size");
countField = type.getCIntegerField("_count");
headerSize = type.getSize();
}
// Fields
private static CIntegerField sizeField;
private static CIntegerField countField;
private static long headerSize;
//Constructor
public FreeList(Address address) {
super(address);
}
// Accessors
public long size() {
return sizeField.getValue(addr);
}
public long count() {
return countField.getValue(addr);
}
public static long sizeOf() {
return headerSize;
}
}
/*
* @(#)BinaryTreeDictionary.java
* Copyright 2000-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.
*
*/
package sun.jvm.hotspot.memory;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.runtime.*;
public class LinearAllocBlock extends VMObject {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private static synchronized void initialize(TypeDataBase db) {
Type type = db.lookupType("LinearAllocBlock");
word_sizeField= type.getCIntegerField("_word_size");
}
// Fields
private static CIntegerField word_sizeField;
// Accessors
public long word_size() {
return word_sizeField.getValue(addr);
}
// Constructor
public LinearAllocBlock(Address addr) {
super(addr);
}
}
...@@ -648,6 +648,6 @@ public class AnnotatedMemoryPanel extends JPanel { ...@@ -648,6 +648,6 @@ public class AnnotatedMemoryPanel extends JPanel {
System.exit(0); System.exit(0);
} }
}); });
frame.show(); frame.setVisible(true);
} }
} }
...@@ -220,7 +220,7 @@ public class CommandProcessorPanel extends JPanel { ...@@ -220,7 +220,7 @@ public class CommandProcessorPanel extends JPanel {
} }
}); });
frame.setSize(500, 500); frame.setSize(500, 500);
frame.show(); frame.setVisible(true);
panel.requestFocus(); panel.requestFocus();
} }
} }
...@@ -226,7 +226,7 @@ public class DebuggerConsolePanel extends JPanel { ...@@ -226,7 +226,7 @@ public class DebuggerConsolePanel extends JPanel {
} }
}); });
frame.setSize(500, 500); frame.setSize(500, 500);
frame.show(); frame.setVisible(true);
panel.requestFocus(); panel.requestFocus();
} }
} }
...@@ -424,7 +424,7 @@ public class HighPrecisionJScrollBar extends JScrollBar { ...@@ -424,7 +424,7 @@ public class HighPrecisionJScrollBar extends JScrollBar {
} }
}); });
frame.getContentPane().add(hpsb); frame.getContentPane().add(hpsb);
frame.show(); frame.setVisible(true);
} }
} }
...@@ -43,7 +43,7 @@ public class JFrameWrapper implements FrameWrapper { ...@@ -43,7 +43,7 @@ public class JFrameWrapper implements FrameWrapper {
public void setVisible(boolean visible) { frame.setVisible(visible); } public void setVisible(boolean visible) { frame.setVisible(visible); }
public void setSize(int x, int y) { frame.setSize(x, y); } public void setSize(int x, int y) { frame.setSize(x, y); }
public void pack() { frame.pack(); } public void pack() { frame.pack(); }
public void show() { frame.show(); } public void show() { frame.setVisible(true); }
public void dispose() { frame.dispose(); } public void dispose() { frame.dispose(); }
public void setBackground(Color color) { frame.setBackground(color); } public void setBackground(Color color) { frame.setBackground(color); }
public void setResizable(boolean resizable) { frame.setResizable(resizable); } public void setResizable(boolean resizable) { frame.setResizable(resizable); }
......
...@@ -477,9 +477,9 @@ public class JTreeTable extends JTable { ...@@ -477,9 +477,9 @@ public class JTreeTable extends JTable {
static class TreeTableTextField extends JTextField { static class TreeTableTextField extends JTextField {
public int offset; public int offset;
public void reshape(int x, int y, int w, int h) { public void setBounds(int x, int y, int w, int h) {
int newX = Math.max(x, offset); int newX = Math.max(x, offset);
super.reshape(newX, y, w - (newX - x), h); super.setBounds(newX, y, w - (newX - x), h);
} }
} }
......
...@@ -130,6 +130,7 @@ class TreeChunk : public FreeChunk { ...@@ -130,6 +130,7 @@ class TreeChunk : public FreeChunk {
const size_t MIN_TREE_CHUNK_SIZE = sizeof(TreeChunk)/HeapWordSize; const size_t MIN_TREE_CHUNK_SIZE = sizeof(TreeChunk)/HeapWordSize;
class BinaryTreeDictionary: public FreeBlockDictionary { class BinaryTreeDictionary: public FreeBlockDictionary {
friend class VMStructs;
bool _splay; bool _splay;
size_t _totalSize; size_t _totalSize;
size_t _totalFreeBlocks; size_t _totalFreeBlocks;
......
...@@ -38,6 +38,7 @@ class Mutex; ...@@ -38,6 +38,7 @@ class Mutex;
class FreeList VALUE_OBJ_CLASS_SPEC { class FreeList VALUE_OBJ_CLASS_SPEC {
friend class CompactibleFreeListSpace; friend class CompactibleFreeListSpace;
friend class VMStructs;
friend class printTreeCensusClosure; friend class printTreeCensusClosure;
FreeChunk* _head; // List of free chunks FreeChunk* _head; // List of free chunks
FreeChunk* _tail; // Tail of list of free chunks FreeChunk* _tail; // Tail of list of free chunks
......
...@@ -38,7 +38,15 @@ ...@@ -38,7 +38,15 @@
static_field(ConcurrentMarkSweepThread, _collector, CMSCollector*) \ static_field(ConcurrentMarkSweepThread, _collector, CMSCollector*) \
nonstatic_field(FreeChunk, _next, FreeChunk*) \ nonstatic_field(FreeChunk, _next, FreeChunk*) \
nonstatic_field(FreeChunk, _prev, FreeChunk*) \ nonstatic_field(FreeChunk, _prev, FreeChunk*) \
nonstatic_field(FreeChunk, _size, size_t) nonstatic_field(FreeChunk, _size, size_t) \
nonstatic_field(LinearAllocBlock, _word_size, size_t) \
nonstatic_field(FreeList, _size, size_t) \
nonstatic_field(FreeList, _count, ssize_t) \
nonstatic_field(BinaryTreeDictionary, _totalSize, size_t) \
nonstatic_field(CompactibleFreeListSpace, _dictionary, FreeBlockDictionary*) \
nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], FreeList) \
nonstatic_field(CompactibleFreeListSpace, _smallLinearAllocBlock, LinearAllocBlock)
#define VM_TYPES_CMS(declare_type, \ #define VM_TYPES_CMS(declare_type, \
declare_toplevel_type) \ declare_toplevel_type) \
...@@ -57,7 +65,14 @@ ...@@ -57,7 +65,14 @@
declare_toplevel_type(SurrogateLockerThread*) \ declare_toplevel_type(SurrogateLockerThread*) \
declare_toplevel_type(CompactibleFreeListSpace*) \ declare_toplevel_type(CompactibleFreeListSpace*) \
declare_toplevel_type(CMSCollector*) \ declare_toplevel_type(CMSCollector*) \
declare_toplevel_type(FreeChunk*) declare_toplevel_type(FreeChunk*) \
declare_toplevel_type(BinaryTreeDictionary*) \
declare_toplevel_type(FreeBlockDictionary*) \
declare_toplevel_type(FreeList*) \
declare_toplevel_type(FreeList) \
declare_toplevel_type(LinearAllocBlock) \
declare_toplevel_type(FreeBlockDictionary) \
declare_type(BinaryTreeDictionary, FreeBlockDictionary)
#define VM_INT_CONSTANTS_CMS(declare_constant) \ #define VM_INT_CONSTANTS_CMS(declare_constant) \
declare_constant(Generation::ConcurrentMarkSweep) \ declare_constant(Generation::ConcurrentMarkSweep) \
......
...@@ -893,6 +893,7 @@ static inline uint64_t cast_uint64_t(size_t x) ...@@ -893,6 +893,7 @@ static inline uint64_t cast_uint64_t(size_t x)
/*******************************************************************/ \ /*******************************************************************/ \
\ \
declare_unsigned_integer_type(size_t) \ declare_unsigned_integer_type(size_t) \
declare_integer_type(ssize_t) \
declare_unsigned_integer_type(const size_t) \ declare_unsigned_integer_type(const size_t) \
declare_integer_type(intx) \ declare_integer_type(intx) \
declare_integer_type(intptr_t) \ declare_integer_type(intptr_t) \
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册