Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
5526a0ac
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
5526a0ac
编写于
10月 29, 2014
作者:
V
vlivanov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8059877: GWT branch frequencies pollution due to LF sharing
Reviewed-by: psandoz, jrose
上级
99975b6d
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
210 addition
and
41 deletion
+210
-41
src/share/classes/java/lang/invoke/DelegatingMethodHandle.java
...hare/classes/java/lang/invoke/DelegatingMethodHandle.java
+28
-9
src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
...re/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+7
-2
src/share/classes/java/lang/invoke/LambdaForm.java
src/share/classes/java/lang/invoke/LambdaForm.java
+22
-5
src/share/classes/java/lang/invoke/MethodHandle.java
src/share/classes/java/lang/invoke/MethodHandle.java
+2
-3
src/share/classes/java/lang/invoke/MethodHandleImpl.java
src/share/classes/java/lang/invoke/MethodHandleImpl.java
+126
-1
src/share/classes/java/lang/invoke/MethodHandleStatics.java
src/share/classes/java/lang/invoke/MethodHandleStatics.java
+6
-3
src/share/classes/java/lang/invoke/MethodTypeForm.java
src/share/classes/java/lang/invoke/MethodTypeForm.java
+19
-18
未找到文件。
src/share/classes/java/lang/invoke/DelegatingMethodHandle.java
浏览文件 @
5526a0ac
...
...
@@ -44,6 +44,10 @@ abstract class DelegatingMethodHandle extends MethodHandle {
super
(
type
,
chooseDelegatingForm
(
target
));
}
protected
DelegatingMethodHandle
(
MethodType
type
,
LambdaForm
form
)
{
super
(
type
,
form
);
}
/** Define this to extract the delegated target which supplies the invocation behavior. */
abstract
protected
MethodHandle
getTarget
();
...
...
@@ -88,14 +92,31 @@ abstract class DelegatingMethodHandle extends MethodHandle {
return
makeReinvokerForm
(
target
,
MethodTypeForm
.
LF_DELEGATE
,
DelegatingMethodHandle
.
class
,
NF_getTarget
);
}
/** Create a LF which simply reinvokes a target of the given basic type. */
static
LambdaForm
makeReinvokerForm
(
MethodHandle
target
,
int
whichCache
,
Object
constraint
,
NamedFunction
getTargetFn
)
{
String
debugString
;
switch
(
whichCache
)
{
case
MethodTypeForm
.
LF_REBIND
:
debugString
=
"BMH.reinvoke"
;
break
;
case
MethodTypeForm
.
LF_DELEGATE
:
debugString
=
"MH.delegate"
;
break
;
default
:
debugString
=
"MH.reinvoke"
;
break
;
}
// No pre-action needed.
return
makeReinvokerForm
(
target
,
whichCache
,
constraint
,
debugString
,
true
,
getTargetFn
,
null
);
}
/** Create a LF which simply reinvokes a target of the given basic type. */
static
LambdaForm
makeReinvokerForm
(
MethodHandle
target
,
int
whichCache
,
Object
constraint
,
String
debugString
,
boolean
forceInline
,
NamedFunction
getTargetFn
,
NamedFunction
preActionFn
)
{
MethodType
mtype
=
target
.
type
().
basicType
();
boolean
customized
=
(
whichCache
<
0
||
mtype
.
parameterSlotCount
()
>
MethodType
.
MAX_MH_INVOKER_ARITY
);
boolean
hasPreAction
=
(
preActionFn
!=
null
);
LambdaForm
form
;
if
(!
customized
)
{
form
=
mtype
.
form
().
cachedLambdaForm
(
whichCache
);
...
...
@@ -105,12 +126,16 @@ abstract class DelegatingMethodHandle extends MethodHandle {
final
int
ARG_BASE
=
1
;
final
int
ARG_LIMIT
=
ARG_BASE
+
mtype
.
parameterCount
();
int
nameCursor
=
ARG_LIMIT
;
final
int
PRE_ACTION
=
hasPreAction
?
nameCursor
++
:
-
1
;
final
int
NEXT_MH
=
customized
?
-
1
:
nameCursor
++;
final
int
REINVOKE
=
nameCursor
++;
LambdaForm
.
Name
[]
names
=
LambdaForm
.
arguments
(
nameCursor
-
ARG_LIMIT
,
mtype
.
invokerType
());
assert
(
names
.
length
==
nameCursor
);
names
[
THIS_DMH
]
=
names
[
THIS_DMH
].
withConstraint
(
constraint
);
Object
[]
targetArgs
;
if
(
hasPreAction
)
{
names
[
PRE_ACTION
]
=
new
LambdaForm
.
Name
(
preActionFn
,
names
[
THIS_DMH
]);
}
if
(
customized
)
{
targetArgs
=
Arrays
.
copyOfRange
(
names
,
ARG_BASE
,
ARG_LIMIT
,
Object
[].
class
);
names
[
REINVOKE
]
=
new
LambdaForm
.
Name
(
target
,
targetArgs
);
// the invoker is the target itself
...
...
@@ -120,20 +145,14 @@ abstract class DelegatingMethodHandle extends MethodHandle {
targetArgs
[
0
]
=
names
[
NEXT_MH
];
// overwrite this MH with next MH
names
[
REINVOKE
]
=
new
LambdaForm
.
Name
(
mtype
,
targetArgs
);
}
String
debugString
;
switch
(
whichCache
)
{
case
MethodTypeForm
.
LF_REBIND
:
debugString
=
"BMH.reinvoke"
;
break
;
case
MethodTypeForm
.
LF_DELEGATE
:
debugString
=
"MH.delegate"
;
break
;
default
:
debugString
=
"MH.reinvoke"
;
break
;
}
form
=
new
LambdaForm
(
debugString
,
ARG_LIMIT
,
names
);
form
=
new
LambdaForm
(
debugString
,
ARG_LIMIT
,
names
,
forceInline
);
if
(!
customized
)
{
form
=
mtype
.
form
().
setCachedLambdaForm
(
whichCache
,
form
);
}
return
form
;
}
private
static
final
NamedFunction
NF_getTarget
;
static
final
NamedFunction
NF_getTarget
;
static
{
try
{
NF_getTarget
=
new
NamedFunction
(
DelegatingMethodHandle
.
class
...
...
src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
浏览文件 @
5526a0ac
...
...
@@ -628,8 +628,13 @@ class InvokerBytecodeGenerator {
// Mark this method as a compiled LambdaForm
mv
.
visitAnnotation
(
"Ljava/lang/invoke/LambdaForm$Compiled;"
,
true
);
// Force inlining of this invoker method.
mv
.
visitAnnotation
(
"Ljava/lang/invoke/ForceInline;"
,
true
);
if
(
lambdaForm
.
forceInline
)
{
// Force inlining of this invoker method.
mv
.
visitAnnotation
(
"Ljava/lang/invoke/ForceInline;"
,
true
);
}
else
{
mv
.
visitAnnotation
(
"Ljava/lang/invoke/DontInline;"
,
true
);
}
// iterate over the form's names, generating bytecode instructions for each
// start iterating at the first name following the arguments
...
...
src/share/classes/java/lang/invoke/LambdaForm.java
浏览文件 @
5526a0ac
...
...
@@ -119,6 +119,7 @@ import static java.lang.invoke.MethodHandleNatives.Constants.*;
class
LambdaForm
{
final
int
arity
;
final
int
result
;
final
boolean
forceInline
;
@Stable
final
Name
[]
names
;
final
String
debugName
;
MemberName
vmentry
;
// low-level behavior, or null if not yet prepared
...
...
@@ -243,11 +244,16 @@ class LambdaForm {
LambdaForm
(
String
debugName
,
int
arity
,
Name
[]
names
,
int
result
)
{
this
(
debugName
,
arity
,
names
,
result
,
true
);
}
LambdaForm
(
String
debugName
,
int
arity
,
Name
[]
names
,
int
result
,
boolean
forceInline
)
{
assert
(
namesOK
(
arity
,
names
));
this
.
arity
=
arity
;
this
.
result
=
fixResult
(
result
,
names
);
this
.
names
=
names
.
clone
();
this
.
debugName
=
fixDebugName
(
debugName
);
this
.
forceInline
=
forceInline
;
int
maxOutArity
=
normalize
();
if
(
maxOutArity
>
MethodType
.
MAX_MH_INVOKER_ARITY
)
{
// Cannot use LF interpreter on very high arity expressions.
...
...
@@ -255,17 +261,23 @@ class LambdaForm {
compileToBytecode
();
}
}
LambdaForm
(
String
debugName
,
int
arity
,
Name
[]
names
)
{
this
(
debugName
,
arity
,
names
,
LAST_RESULT
);
this
(
debugName
,
arity
,
names
,
LAST_RESULT
,
true
);
}
LambdaForm
(
String
debugName
,
int
arity
,
Name
[]
names
,
boolean
forceInline
)
{
this
(
debugName
,
arity
,
names
,
LAST_RESULT
,
forceInline
);
}
LambdaForm
(
String
debugName
,
Name
[]
formals
,
Name
[]
temps
,
Name
result
)
{
this
(
debugName
,
formals
.
length
,
buildNames
(
formals
,
temps
,
result
),
LAST_RESULT
);
formals
.
length
,
buildNames
(
formals
,
temps
,
result
),
LAST_RESULT
,
true
);
}
LambdaForm
(
String
debugName
,
Name
[]
formals
,
Name
[]
temps
,
Name
result
,
boolean
forceInline
)
{
this
(
debugName
,
formals
.
length
,
buildNames
(
formals
,
temps
,
result
),
LAST_RESULT
,
forceInline
);
}
private
static
Name
[]
buildNames
(
Name
[]
formals
,
Name
[]
temps
,
Name
result
)
{
...
...
@@ -279,6 +291,10 @@ class LambdaForm {
}
private
LambdaForm
(
String
sig
)
{
this
(
sig
,
true
);
}
private
LambdaForm
(
String
sig
,
boolean
forceInline
)
{
// Make a blank lambda form, which returns a constant zero or null.
// It is used as a template for managing the invocation of similar forms that are non-empty.
// Called only from getPreparedForm.
...
...
@@ -287,6 +303,7 @@ class LambdaForm {
this
.
result
=
(
signatureReturn
(
sig
)
==
V_TYPE
?
-
1
:
arity
);
this
.
names
=
buildEmptyNames
(
arity
,
sig
);
this
.
debugName
=
"LF.zero"
;
this
.
forceInline
=
forceInline
;
assert
(
nameRefsAreLegal
());
assert
(
isEmpty
());
assert
(
sig
.
equals
(
basicTypeSignature
()))
:
sig
+
" != "
+
basicTypeSignature
();
...
...
src/share/classes/java/lang/invoke/MethodHandle.java
浏览文件 @
5526a0ac
...
...
@@ -1438,10 +1438,9 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
/*non-public*/
void
updateForm
(
LambdaForm
newForm
)
{
if
(
form
==
newForm
)
return
;
assert
(
this
instanceof
DirectMethodHandle
&&
this
.
internalMemberName
().
isStatic
());
// ISSUE: Should we have a memory fence here?
newForm
.
prepare
();
// as in MethodHandle.<init>
UNSAFE
.
putObject
(
this
,
FORM_OFFSET
,
newForm
);
this
.
form
.
prepare
();
// as in MethodHandle.<init>
UNSAFE
.
fullFence
();
}
private
static
final
long
FORM_OFFSET
;
...
...
src/share/classes/java/lang/invoke/MethodHandleImpl.java
浏览文件 @
5526a0ac
...
...
@@ -30,6 +30,7 @@ import java.security.PrivilegedAction;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.function.Function
;
import
sun.invoke.empty.Empty
;
import
sun.invoke.util.ValueConversions
;
...
...
@@ -713,10 +714,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
LambdaForm
form
=
makeGuardWithTestForm
(
basicType
);
BoundMethodHandle
.
SpeciesData
data
=
BoundMethodHandle
.
speciesData_LLL
();
BoundMethodHandle
mh
;
try
{
mh
=
(
BoundMethodHandle
)
data
.
constructor
().
invokeBasic
(
type
,
form
,
(
Object
)
test
,
(
Object
)
target
,
(
Object
)
fallback
);
(
Object
)
test
,
(
Object
)
profile
(
target
),
(
Object
)
profile
(
fallback
)
);
}
catch
(
Throwable
ex
)
{
throw
uncaughtException
(
ex
);
}
...
...
@@ -724,6 +726,129 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return
mh
;
}
static
MethodHandle
profile
(
MethodHandle
target
)
{
if
(
DONT_INLINE_THRESHOLD
>=
0
)
{
return
makeBlockInlningWrapper
(
target
);
}
else
{
return
target
;
}
}
/**
* Block inlining during JIT-compilation of a target method handle if it hasn't been invoked enough times.
* Corresponding LambdaForm has @DontInline when compiled into bytecode.
*/
static
MethodHandle
makeBlockInlningWrapper
(
MethodHandle
target
)
{
LambdaForm
lform
=
PRODUCE_BLOCK_INLINING_FORM
.
apply
(
target
);
return
new
CountingWrapper
(
target
,
lform
,
PRODUCE_BLOCK_INLINING_FORM
,
PRODUCE_REINVOKER_FORM
,
DONT_INLINE_THRESHOLD
);
}
/** Constructs reinvoker lambda form which block inlining during JIT-compilation for a particular method handle */
private
static
final
Function
<
MethodHandle
,
LambdaForm
>
PRODUCE_BLOCK_INLINING_FORM
=
new
Function
<
MethodHandle
,
LambdaForm
>()
{
@Override
public
LambdaForm
apply
(
MethodHandle
target
)
{
return
DelegatingMethodHandle
.
makeReinvokerForm
(
target
,
MethodTypeForm
.
LF_DELEGATE_BLOCK_INLINING
,
CountingWrapper
.
class
,
"reinvoker.dontInline"
,
false
,
DelegatingMethodHandle
.
NF_getTarget
,
CountingWrapper
.
NF_maybeStopCounting
);
}
};
/** Constructs simple reinvoker lambda form for a particular method handle */
private
static
final
Function
<
MethodHandle
,
LambdaForm
>
PRODUCE_REINVOKER_FORM
=
new
Function
<
MethodHandle
,
LambdaForm
>()
{
@Override
public
LambdaForm
apply
(
MethodHandle
target
)
{
return
DelegatingMethodHandle
.
makeReinvokerForm
(
target
,
MethodTypeForm
.
LF_DELEGATE
,
DelegatingMethodHandle
.
class
,
DelegatingMethodHandle
.
NF_getTarget
);
}
};
/**
* Counting method handle. It has 2 states: counting and non-counting.
* It is in counting state for the first n invocations and then transitions to non-counting state.
* Behavior in counting and non-counting states is determined by lambda forms produced by
* countingFormProducer & nonCountingFormProducer respectively.
*/
static
class
CountingWrapper
extends
DelegatingMethodHandle
{
private
final
MethodHandle
target
;
private
int
count
;
private
Function
<
MethodHandle
,
LambdaForm
>
countingFormProducer
;
private
Function
<
MethodHandle
,
LambdaForm
>
nonCountingFormProducer
;
private
volatile
boolean
isCounting
;
private
CountingWrapper
(
MethodHandle
target
,
LambdaForm
lform
,
Function
<
MethodHandle
,
LambdaForm
>
countingFromProducer
,
Function
<
MethodHandle
,
LambdaForm
>
nonCountingFormProducer
,
int
count
)
{
super
(
target
.
type
(),
lform
);
this
.
target
=
target
;
this
.
count
=
count
;
this
.
countingFormProducer
=
countingFromProducer
;
this
.
nonCountingFormProducer
=
nonCountingFormProducer
;
this
.
isCounting
=
(
count
>
0
);
}
@Hidden
@Override
protected
MethodHandle
getTarget
()
{
return
target
;
}
@Override
public
MethodHandle
asTypeUncached
(
MethodType
newType
)
{
MethodHandle
newTarget
=
target
.
asType
(
newType
);
MethodHandle
wrapper
;
if
(
isCounting
)
{
LambdaForm
lform
;
lform
=
countingFormProducer
.
apply
(
target
);
wrapper
=
new
CountingWrapper
(
newTarget
,
lform
,
countingFormProducer
,
nonCountingFormProducer
,
DONT_INLINE_THRESHOLD
);
}
else
{
wrapper
=
newTarget
;
// no need for a counting wrapper anymore
}
return
(
asTypeCache
=
wrapper
);
}
boolean
countDown
()
{
if
(
count
<=
0
)
{
// Try to limit number of updates. MethodHandle.updateForm() doesn't guarantee LF update visibility.
if
(
isCounting
)
{
isCounting
=
false
;
return
true
;
}
else
{
return
false
;
}
}
else
{
--
count
;
return
false
;
}
}
@Hidden
static
void
maybeStopCounting
(
Object
o1
)
{
CountingWrapper
wrapper
=
(
CountingWrapper
)
o1
;
if
(
wrapper
.
countDown
())
{
// Reached invocation threshold. Replace counting behavior with a non-counting one.
LambdaForm
lform
=
wrapper
.
nonCountingFormProducer
.
apply
(
wrapper
.
target
);
lform
.
compileToBytecode
();
// speed up warmup by avoiding LF interpretation again after transition
wrapper
.
updateForm
(
lform
);
}
}
static
final
NamedFunction
NF_maybeStopCounting
;
static
{
Class
<?>
THIS_CLASS
=
CountingWrapper
.
class
;
try
{
NF_maybeStopCounting
=
new
NamedFunction
(
THIS_CLASS
.
getDeclaredMethod
(
"maybeStopCounting"
,
Object
.
class
));
}
catch
(
ReflectiveOperationException
ex
)
{
throw
newInternalError
(
ex
);
}
}
}
static
LambdaForm
makeGuardWithTestForm
(
MethodType
basicType
)
{
LambdaForm
lform
=
basicType
.
form
().
cachedLambdaForm
(
MethodTypeForm
.
LF_GWT
);
...
...
src/share/classes/java/lang/invoke/MethodHandleStatics.java
浏览文件 @
5526a0ac
...
...
@@ -47,10 +47,11 @@ import sun.misc.Unsafe;
static
final
boolean
TRACE_METHOD_LINKAGE
;
static
final
boolean
USE_LAMBDA_FORM_EDITOR
;
static
final
int
COMPILE_THRESHOLD
;
static
final
int
DONT_INLINE_THRESHOLD
;
static
final
int
PROFILE_LEVEL
;
static
{
final
Object
[]
values
=
{
false
,
false
,
false
,
false
,
false
,
null
,
null
}
;
final
Object
[]
values
=
new
Object
[
8
]
;
AccessController
.
doPrivileged
(
new
PrivilegedAction
<
Void
>()
{
public
Void
run
()
{
values
[
0
]
=
Boolean
.
getBoolean
(
"java.lang.invoke.MethodHandle.DEBUG_NAMES"
);
...
...
@@ -59,7 +60,8 @@ import sun.misc.Unsafe;
values
[
3
]
=
Boolean
.
getBoolean
(
"java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE"
);
values
[
4
]
=
Boolean
.
getBoolean
(
"java.lang.invoke.MethodHandle.USE_LF_EDITOR"
);
values
[
5
]
=
Integer
.
getInteger
(
"java.lang.invoke.MethodHandle.COMPILE_THRESHOLD"
,
30
);
values
[
6
]
=
Integer
.
getInteger
(
"java.lang.invoke.MethodHandle.PROFILE_LEVEL"
,
0
);
values
[
6
]
=
Integer
.
getInteger
(
"java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD"
,
30
);
values
[
7
]
=
Integer
.
getInteger
(
"java.lang.invoke.MethodHandle.PROFILE_LEVEL"
,
0
);
return
null
;
}
});
...
...
@@ -69,7 +71,8 @@ import sun.misc.Unsafe;
TRACE_METHOD_LINKAGE
=
(
Boolean
)
values
[
3
];
USE_LAMBDA_FORM_EDITOR
=
(
Boolean
)
values
[
4
];
COMPILE_THRESHOLD
=
(
Integer
)
values
[
5
];
PROFILE_LEVEL
=
(
Integer
)
values
[
6
];
DONT_INLINE_THRESHOLD
=
(
Integer
)
values
[
6
];
PROFILE_LEVEL
=
(
Integer
)
values
[
7
];
}
/** Tell if any of the debugging switches are turned on.
...
...
src/share/classes/java/lang/invoke/MethodTypeForm.java
浏览文件 @
5526a0ac
...
...
@@ -63,24 +63,25 @@ final class MethodTypeForm {
final
@Stable
LambdaForm
[]
lambdaForms
;
// Indexes into lambdaForms:
static
final
int
LF_INVVIRTUAL
=
0
,
// DMH invokeVirtual
LF_INVSTATIC
=
1
,
LF_INVSPECIAL
=
2
,
LF_NEWINVSPECIAL
=
3
,
LF_INVINTERFACE
=
4
,
LF_INVSTATIC_INIT
=
5
,
// DMH invokeStatic with <clinit> barrier
LF_INTERPRET
=
6
,
// LF interpreter
LF_REBIND
=
7
,
// BoundMethodHandle
LF_DELEGATE
=
8
,
// DelegatingMethodHandle
LF_EX_LINKER
=
9
,
// invokeExact_MT (for invokehandle)
LF_EX_INVOKER
=
10
,
// MHs.invokeExact
LF_GEN_LINKER
=
11
,
// generic invoke_MT (for invokehandle)
LF_GEN_INVOKER
=
12
,
// generic MHs.invoke
LF_CS_LINKER
=
13
,
// linkToCallSite_CS
LF_MH_LINKER
=
14
,
// linkToCallSite_MH
LF_GWC
=
15
,
// guardWithCatch (catchException)
LF_GWT
=
16
,
// guardWithTest
LF_LIMIT
=
17
;
LF_INVVIRTUAL
=
0
,
// DMH invokeVirtual
LF_INVSTATIC
=
1
,
LF_INVSPECIAL
=
2
,
LF_NEWINVSPECIAL
=
3
,
LF_INVINTERFACE
=
4
,
LF_INVSTATIC_INIT
=
5
,
// DMH invokeStatic with <clinit> barrier
LF_INTERPRET
=
6
,
// LF interpreter
LF_REBIND
=
7
,
// BoundMethodHandle
LF_DELEGATE
=
8
,
// DelegatingMethodHandle
LF_DELEGATE_BLOCK_INLINING
=
9
,
// Counting DelegatingMethodHandle w/ @DontInline
LF_EX_LINKER
=
10
,
// invokeExact_MT (for invokehandle)
LF_EX_INVOKER
=
11
,
// MHs.invokeExact
LF_GEN_LINKER
=
12
,
// generic invoke_MT (for invokehandle)
LF_GEN_INVOKER
=
13
,
// generic MHs.invoke
LF_CS_LINKER
=
14
,
// linkToCallSite_CS
LF_MH_LINKER
=
15
,
// linkToCallSite_MH
LF_GWC
=
16
,
// guardWithCatch (catchException)
LF_GWT
=
17
,
// guardWithTest
LF_LIMIT
=
18
;
/** Return the type corresponding uniquely (1-1) to this MT-form.
* It might have any primitive returns or arguments, but will have no references except Object.
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录