提交 114e70e3 编写于 作者: D duke

Merge

......@@ -432,3 +432,6 @@ b94be69cbb1d2943b886bf2d458745756df146e4 jdk-10+9
8d4ed1e06fe184c9cb08c5b708e7d6f5c066644f jdk-10+12
8f7227c6012b0051ea4e0bcee040c627bf699b88 jdk-9+175
d67a3f1f057f7e31e12f33ebe3667cb73d252268 jdk-10+13
1fd5901544acc50bb30fde9388c8e53cb7c449e4 jdk-10+14
84777531d994ef70163d35078ec9c4127f2eadb5 jdk-9+176
a4371edb589c60db01142e45c317adb9ccbcb083 jdk-9+177
......@@ -615,6 +615,8 @@ var getJibProfilesProfiles = function (input, common, data) {
}
var testOnlyProfilesPrebuilt = {
"run-test-prebuilt": {
target_os: input.build_os,
target_cpu: input.build_cpu,
src: "src.conf",
dependencies: [ "jtreg", "gnumake", "boot_jdk", testedProfile + ".jdk",
testedProfile + ".test", "src.full"
......@@ -635,13 +637,14 @@ var getJibProfilesProfiles = function (input, common, data) {
if (input.profile == "run-test-prebuilt") {
if (profiles[testedProfile] == null) {
error("testedProfile is not defined: " + testedProfile);
} else {
testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_os"]
= profiles[testedProfile]["target_os"];
testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_cpu"]
= profiles[testedProfile]["target_cpu"];
}
}
if (profiles[testedProfile] != null) {
testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_os"]
= profiles[testedProfile]["target_os"];
testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_cpu"]
= profiles[testedProfile]["target_cpu"];
}
profiles = concatObjects(profiles, testOnlyProfilesPrebuilt);
// On macosx add the devkit bin dir to the path in all the run-test profiles.
......
此差异已折叠。
此差异已折叠。
......@@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>Testing OpenJDK</title>
<style type="text/css">code{white-space: pre;}</style>
<link rel="stylesheet" href="../../jdk/make/data/docs-resources/specs/resources/jdk-default.css">
<link rel="stylesheet" href="../../jdk/make/data/docs-resources/resources/jdk-default.css">
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
......
......@@ -432,3 +432,6 @@ c62e5964cfcf144d8f72e9ba69757897785349a9 jdk-9+171
00ae6307d78bac49883ddc85d687aa88c49f3971 jdk-10+12
dc78a3dd6b3a4f11cdae8a3e3d160e6a78bc7838 jdk-9+175
564fced058bd2c8375e9104aa8f9494642cd7bdd jdk-10+13
25d991a67cba240eeaf15c19c5857b40fdd71561 jdk-10+14
40fb9f229471ef357d493813d34b15afcce9f32b jdk-9+176
c72e9d3823f04cb3ef3166646dfea9e4c2769133 jdk-9+177
......@@ -26,7 +26,7 @@
/**
* Defines the Java binding of the OMG CORBA APIs, and the RMI-IIOP API.
*
* <p> This module is upgradeble.
* <p> This module is upgradeable.
*
* @moduleGraph
* @since 9
......
......@@ -592,3 +592,6 @@ e64b1cb48d6e7703928a9d1da106fc27f8cb65fd jdk-9+173
070aa7a2eb14c4645f7eb31384cba0a2ba72a4b5 jdk-10+12
8f04d457168b9f1f4a1b2c37f49e0513ca9d33a7 jdk-9+175
a9da03357f190807591177fe9846d6e68ad64fc0 jdk-10+13
e920b4d008d914f3414bd4630b58837cf0b7f08d jdk-10+14
2ab74e5dbdc2b6a962c865500cafd23cf387dc60 jdk-9+176
1ca8f038fceb88c640badf9bd18905205bc63b43 jdk-9+177
......@@ -748,41 +748,3 @@ bool ArrayCopyNode::modifies(intptr_t offset_lo, intptr_t offset_hi, PhaseTransf
return false;
}
// We try to replace a load from the destination of an arraycopy with
// a load from the source so the arraycopy has a chance to be
// eliminated. It's only valid if the arraycopy doesn't change the
// element that would be loaded from the source array.
bool ArrayCopyNode::can_replace_dest_load_with_src_load(intptr_t offset_lo, intptr_t offset_hi, PhaseTransform* phase) const {
assert(_kind == ArrayCopy || _kind == CopyOf || _kind == CopyOfRange, "only for real array copies");
Node* src = in(Src);
Node* dest = in(Dest);
// Check whether, assuming source and destination are the same
// array, the arraycopy modifies the element from the source we
// would load.
if ((src != dest && in(SrcPos) == in(DestPos)) || !modifies(offset_lo, offset_hi, phase, false)) {
// if not the transformation is legal
return true;
}
AllocateNode* src_alloc = AllocateNode::Ideal_allocation(src, phase);
AllocateNode* dest_alloc = AllocateNode::Ideal_allocation(dest, phase);
// Check whether source and destination can be proved to be
// different arrays
const TypeOopPtr* t_src = phase->type(src)->isa_oopptr();
const TypeOopPtr* t_dest = phase->type(dest)->isa_oopptr();
if (t_src != NULL && t_dest != NULL &&
(t_src->is_known_instance() || t_dest->is_known_instance()) &&
t_src->instance_id() != t_dest->instance_id()) {
return true;
}
if (MemNode::detect_ptr_independence(src->uncast(), src_alloc, dest->uncast(), dest_alloc, phase)) {
return true;
}
return false;
}
......@@ -168,7 +168,6 @@ public:
static bool may_modify(const TypeOopPtr *t_oop, MemBarNode* mb, PhaseTransform *phase, ArrayCopyNode*& ac);
bool modifies(intptr_t offset_lo, intptr_t offset_hi, PhaseTransform* phase, bool must_modify) const;
bool can_replace_dest_load_with_src_load(intptr_t offset_lo, intptr_t offset_hi, PhaseTransform* phase) const;
#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
......
......@@ -5171,6 +5171,10 @@ bool LibraryCallKit::inline_arraycopy() {
Deoptimization::Action_make_not_entrant);
assert(stopped(), "Should be stopped");
}
const TypeKlassPtr* dest_klass_t = _gvn.type(dest_klass)->is_klassptr();
const Type *toop = TypeOopPtr::make_from_klass(dest_klass_t->klass());
src = _gvn.transform(new CheckCastPPNode(control(), src, toop));
}
arraycopy_move_allocation_here(alloc, dest, saved_jvms, saved_reexecute_sp, new_idx);
......
......@@ -885,7 +885,7 @@ static bool skip_through_membars(Compile::AliasType* atp, const TypeInstPtr* tp,
// Is the value loaded previously stored by an arraycopy? If so return
// a load node that reads from the source array so we may be able to
// optimize out the ArrayCopy node later.
Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseTransform* phase) const {
Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseGVN* phase) const {
Node* ld_adr = in(MemNode::Address);
intptr_t ld_off = 0;
AllocateNode* ld_alloc = AllocateNode::Ideal_allocation(ld_adr, phase, ld_off);
......@@ -893,23 +893,27 @@ Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseTransform* phase) const {
if (ac != NULL) {
assert(ac->is_ArrayCopy(), "what kind of node can this be?");
Node* ld = clone();
Node* mem = ac->in(TypeFunc::Memory);
Node* ctl = ac->in(0);
Node* src = ac->in(ArrayCopyNode::Src);
if (!ac->as_ArrayCopy()->is_clonebasic() && !phase->type(src)->isa_aryptr()) {
return NULL;
}
LoadNode* ld = clone()->as_Load();
Node* addp = in(MemNode::Address)->clone();
if (ac->as_ArrayCopy()->is_clonebasic()) {
assert(ld_alloc != NULL, "need an alloc");
Node* addp = in(MemNode::Address)->clone();
assert(addp->is_AddP(), "address must be addp");
assert(addp->in(AddPNode::Base) == ac->in(ArrayCopyNode::Dest)->in(AddPNode::Base), "strange pattern");
assert(addp->in(AddPNode::Address) == ac->in(ArrayCopyNode::Dest)->in(AddPNode::Address), "strange pattern");
addp->set_req(AddPNode::Base, ac->in(ArrayCopyNode::Src)->in(AddPNode::Base));
addp->set_req(AddPNode::Address, ac->in(ArrayCopyNode::Src)->in(AddPNode::Address));
ld->set_req(MemNode::Address, phase->transform(addp));
if (in(0) != NULL) {
assert(ld_alloc->in(0) != NULL, "alloc must have control");
ld->set_req(0, ld_alloc->in(0));
}
addp->set_req(AddPNode::Base, src->in(AddPNode::Base));
addp->set_req(AddPNode::Address, src->in(AddPNode::Address));
} else {
Node* src = ac->in(ArrayCopyNode::Src);
Node* addp = in(MemNode::Address)->clone();
assert(ac->as_ArrayCopy()->is_arraycopy_validated() ||
ac->as_ArrayCopy()->is_copyof_validated() ||
ac->as_ArrayCopy()->is_copyofrange_validated(), "only supported cases");
assert(addp->in(AddPNode::Base) == addp->in(AddPNode::Address), "should be");
addp->set_req(AddPNode::Base, src);
addp->set_req(AddPNode::Address, src);
......@@ -927,21 +931,17 @@ Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseTransform* phase) const {
Node* offset = phase->transform(new AddXNode(addp->in(AddPNode::Offset), diff));
addp->set_req(AddPNode::Offset, offset);
ld->set_req(MemNode::Address, phase->transform(addp));
const TypeX *ld_offs_t = phase->type(offset)->isa_intptr_t();
if (!ac->as_ArrayCopy()->can_replace_dest_load_with_src_load(ld_offs_t->_lo, ld_offs_t->_hi, phase)) {
return NULL;
}
if (in(0) != NULL) {
assert(ac->in(0) != NULL, "alloc must have control");
ld->set_req(0, ac->in(0));
}
}
addp = phase->transform(addp);
#ifdef ASSERT
const TypePtr* adr_type = phase->type(addp)->is_ptr();
ld->_adr_type = adr_type;
#endif
ld->set_req(MemNode::Address, addp);
ld->set_req(0, ctl);
ld->set_req(MemNode::Memory, mem);
// load depends on the tests that validate the arraycopy
ld->as_Load()->_control_dependency = Pinned;
ld->_control_dependency = Pinned;
return ld;
}
return NULL;
......
......@@ -270,7 +270,7 @@ protected:
const Type* load_array_final_field(const TypeKlassPtr *tkls,
ciKlass* klass) const;
Node* can_see_arraycopy_value(Node* st, PhaseTransform* phase) const;
Node* can_see_arraycopy_value(Node* st, PhaseGVN* phase) const;
// depends_only_on_test is almost always true, and needs to be almost always
// true to enable key hoisting & commoning optimizations. However, for the
......
/*
* Copyright (c) 2017, Red Hat, 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 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 8181742
* @summary Loads that bypass arraycopy ends up with wrong memory state
*
* @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+StressGCM -XX:+StressLCM TestLoadBypassACWithWrongMem
*
*/
import java.util.Arrays;
public class TestLoadBypassACWithWrongMem {
static int test1(int[] src) {
int[] dst = new int[10];
System.arraycopy(src, 0, dst, 0, 10);
src[1] = 0x42;
// dst[1] is transformed to src[1], src[1] must use the
// correct memory state (not the store above).
return dst[1];
}
static int test2(int[] src) {
int[] dst = (int[])src.clone();
src[1] = 0x42;
// Same as above for clone
return dst[1];
}
static Object test5_src = null;
static int test3() {
int[] dst = new int[10];
System.arraycopy(test5_src, 0, dst, 0, 10);
((int[])test5_src)[1] = 0x42;
System.arraycopy(test5_src, 0, dst, 0, 10);
// dst[1] is transformed to test5_src[1]. test5_src is Object
// but test5_src[1] must be on the slice for int[] not
// Object+some offset.
return dst[1];
}
static public void main(String[] args) {
int[] src = new int[10];
for (int i = 0; i < 20000; i++) {
Arrays.fill(src, 0);
int res = test1(src);
if (res != 0) {
throw new RuntimeException("bad result: " + res + " != " + 0);
}
Arrays.fill(src, 0);
res = test2(src);
if (res != 0) {
throw new RuntimeException("bad result: " + res + " != " + 0);
}
Arrays.fill(src, 0);
test5_src = src;
res = test3();
if (res != 0x42) {
throw new RuntimeException("bad result: " + res + " != " + 0x42);
}
}
}
}
......@@ -108,8 +108,8 @@ public class TestAnonymousClassUnloading {
*/
static public void main(String[] args) throws Exception {
// (1) Load an anonymous version of this class using the corresponding Unsafe method
URL classUrl = TestAnonymousClassUnloading.class.getResource(
TestAnonymousClassUnloading.class.getName().replace('.', '/') + ".class");
String rn = TestAnonymousClassUnloading.class.getSimpleName() + ".class";
URL classUrl = TestAnonymousClassUnloading.class.getResource(rn);
URLConnection connection = classUrl.openConnection();
int length = connection.getContentLength();
......
......@@ -74,7 +74,7 @@ public class ClassLoadUnloadTest {
List<String> argsList = new ArrayList<>();
Collections.addAll(argsList, args);
Collections.addAll(argsList, "-Xmn8m");
Collections.addAll(argsList, "-Dtest.classes=" + System.getProperty("test.classes","."));
Collections.addAll(argsList, "-Dtest.class.path=" + System.getProperty("test.class.path", "."));
Collections.addAll(argsList, ClassUnloadTestMain.class.getName());
return ProcessTools.createJavaProcessBuilder(argsList.toArray(new String[argsList.size()]));
}
......
......@@ -31,8 +31,10 @@ import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.stream.Stream;
public class ClassUnloadCommon {
public static class TestFailure extends RuntimeException {
......@@ -61,14 +63,45 @@ public class ClassUnloadCommon {
System.gc();
}
/**
* Creates a class loader that loads classes from {@code ${test.class.path}}
* before delegating to the system class loader.
*/
public static ClassLoader newClassLoader() {
String cp = System.getProperty("test.class.path", ".");
URL[] urls = Stream.of(cp.split(File.pathSeparator))
.map(Paths::get)
.map(ClassUnloadCommon::toURL)
.toArray(URL[]::new);
return new URLClassLoader(urls) {
@Override
public Class<?> loadClass(String cn, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(cn)) {
Class<?> c = findLoadedClass(cn);
if (c == null) {
try {
c = findClass(cn);
} catch (ClassNotFoundException e) {
c = getParent().loadClass(cn);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
};
}
static URL toURL(Path path) {
try {
return new URLClassLoader(new URL[] {
Paths.get(System.getProperty("test.classes",".") + File.separatorChar + "classes").toUri().toURL(),
}, null);
} catch (MalformedURLException e){
throw new RuntimeException("Unexpected URL conversion failure", e);
return path.toUri().toURL();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
}
......@@ -432,3 +432,6 @@ b9c0b105002272d7414c8b34af9aded151f9cad6 jdk-9+174
ff293e39e83366c40a5687dacd1ccb2305ed2c1e jdk-10+12
736412a8dccee9d439044e6b1af2e7470d0a3563 jdk-9+175
5d374af9e78d02976e0e7f8dc2706f91a020f025 jdk-10+13
4d05f673cf773f1c20e8f5a879d64115d2f741d9 jdk-10+14
38cf34e2328070cc691c4f136e6dde1a44c04171 jdk-9+176
332ad9f92632f56f337b8c40edef9a95a42b26bc jdk-9+177
/*
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2017, 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
......@@ -114,7 +114,7 @@ public class virtual_parse_stack {
real_next++;
/* put the state number from the Symbol onto the virtual stack */
vstack.push(new Integer(stack_sym.parse_state));
vstack.push(stack_sym.parse_state);
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
......@@ -161,7 +161,7 @@ public class virtual_parse_stack {
/** Push a state number onto the stack. */
public void push(int state_num)
{
vstack.push(new Integer(state_num));
vstack.push(state_num);
}
/*-----------------------------------------------------------*/
......
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
......@@ -104,6 +103,6 @@ public final class ConstantDouble extends Constant implements ConstantObject {
/** @return Double object
*/
public Object getConstantValue(ConstantPool cp) {
return new Double(bytes);
return bytes;
}
}
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
......@@ -103,6 +102,6 @@ public final class ConstantFloat extends Constant implements ConstantObject {
/** @return Float object
*/
public Object getConstantValue(ConstantPool cp) {
return new Float(bytes);
return bytes;
}
}
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
......@@ -109,6 +108,6 @@ public final class ConstantInteger extends Constant implements ConstantObject {
/** @return Integer object
*/
public Object getConstantValue(ConstantPool cp) {
return new Integer(bytes);
return bytes;
}
}
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
......@@ -101,6 +100,6 @@ public final class ConstantLong extends Constant implements ConstantObject {
/** @return Long object
*/
public Object getConstantValue(ConstantPool cp) {
return new Long(bytes);
return bytes;
}
}
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
......@@ -425,7 +424,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node {
}
if(debug != null)
JavaClass.debug = new Boolean(debug).booleanValue();
JavaClass.debug = Boolean.valueOf(debug);
if(sep != null)
try {
......
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
......@@ -72,7 +71,7 @@ public class BIPUSH extends Instruction implements ConstantPushInstruction {
b = bytes.readByte();
}
public Number getValue() { return new Integer(b); }
public Number getValue() { return Integer.valueOf(b); }
/** @return Type.BYTE
*/
......
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
......@@ -52,7 +51,7 @@ public class DCONST extends Instruction
value = f;
}
public Number getValue() { return new Double(value); }
public Number getValue() { return Double.valueOf(value); }
/** @return Type.DOUBLE
*/
......
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
......@@ -54,7 +53,7 @@ public class FCONST extends Instruction
value = f;
}
public Number getValue() { return new Float(value); }
public Number getValue() { return Float.valueOf(value); }
/** @return Type.FLOAT
*/
......
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
......@@ -50,7 +49,7 @@ public class ICONST extends Instruction
value = i;
}
public Number getValue() { return new Integer(value); }
public Number getValue() { return Integer.valueOf(value); }
/** @return Type.INT
*/
......
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
......@@ -23,7 +22,6 @@ package com.sun.org.apache.bcel.internal.generic;
import com.sun.org.apache.bcel.internal.Constants;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.classfile.ConstantPool;
import java.io.*;
import com.sun.org.apache.bcel.internal.util.ByteSequence;
......@@ -165,7 +163,7 @@ public abstract class Instruction implements Cloneable, Serializable {
}
try {
obj = (Instruction)clazz.newInstance();
obj = (Instruction)clazz.getConstructor().newInstance();
if(wide && !((obj instanceof LocalVariableInstruction) ||
(obj instanceof IINC) ||
......
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
......@@ -1005,7 +1005,7 @@ public class Parser implements Constants, ContentHandler {
if (className != null) {
try {
final Class<?> clazz = ObjectFactory.findProviderClass(className, true);
node = (SyntaxTreeNode)clazz.newInstance();
node = (SyntaxTreeNode)clazz.getDeclaredConstructor().newInstance();
node.setQName(qname);
node.setParser(this);
if (_locator != null) {
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册