Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_hotspot
提交
147bbce4
D
dragonwell8_hotspot
项目概览
openanolis
/
dragonwell8_hotspot
通知
2
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_hotspot
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
147bbce4
编写于
11月 26, 2012
作者:
T
twisti
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
7172640: C2: instrinsic implementations in LibraryCallKit should use argument() instead of pop()
Reviewed-by: kvn, jrose
上级
b12abdd2
变更
16
展开全部
隐藏空白更改
内联
并排
Showing
16 changed file
with
792 addition
and
1085 deletion
+792
-1085
src/share/vm/ci/ciMethod.cpp
src/share/vm/ci/ciMethod.cpp
+18
-0
src/share/vm/ci/ciMethod.hpp
src/share/vm/ci/ciMethod.hpp
+3
-0
src/share/vm/ci/ciSignature.hpp
src/share/vm/ci/ciSignature.hpp
+4
-2
src/share/vm/interpreter/bytecodes.hpp
src/share/vm/interpreter/bytecodes.hpp
+3
-1
src/share/vm/opto/callGenerator.cpp
src/share/vm/opto/callGenerator.cpp
+5
-5
src/share/vm/opto/callnode.hpp
src/share/vm/opto/callnode.hpp
+12
-3
src/share/vm/opto/doCall.cpp
src/share/vm/opto/doCall.cpp
+4
-2
src/share/vm/opto/graphKit.cpp
src/share/vm/opto/graphKit.cpp
+43
-38
src/share/vm/opto/graphKit.hpp
src/share/vm/opto/graphKit.hpp
+48
-26
src/share/vm/opto/library_call.cpp
src/share/vm/opto/library_call.cpp
+587
-957
src/share/vm/opto/locknode.cpp
src/share/vm/opto/locknode.cpp
+1
-1
src/share/vm/opto/parse1.cpp
src/share/vm/opto/parse1.cpp
+2
-2
src/share/vm/opto/parse2.cpp
src/share/vm/opto/parse2.cpp
+18
-18
src/share/vm/opto/parse3.cpp
src/share/vm/opto/parse3.cpp
+6
-6
src/share/vm/opto/parseHelper.cpp
src/share/vm/opto/parseHelper.cpp
+6
-6
src/share/vm/opto/type.hpp
src/share/vm/opto/type.hpp
+32
-18
未找到文件。
src/share/vm/ci/ciMethod.cpp
浏览文件 @
147bbce4
...
...
@@ -741,6 +741,24 @@ int ciMethod::interpreter_call_site_count(int bci) {
return
-
1
;
// unknown
}
// ------------------------------------------------------------------
// ciMethod::get_field_at_bci
ciField
*
ciMethod
::
get_field_at_bci
(
int
bci
,
bool
&
will_link
)
{
ciBytecodeStream
iter
(
this
);
iter
.
reset_to_bci
(
bci
);
iter
.
next
();
return
iter
.
get_field
(
will_link
);
}
// ------------------------------------------------------------------
// ciMethod::get_method_at_bci
ciMethod
*
ciMethod
::
get_method_at_bci
(
int
bci
,
bool
&
will_link
,
ciSignature
*
*
declared_signature
)
{
ciBytecodeStream
iter
(
this
);
iter
.
reset_to_bci
(
bci
);
iter
.
next
();
return
iter
.
get_method
(
will_link
,
declared_signature
);
}
// ------------------------------------------------------------------
// Adjust a CounterData count to be commensurate with
// interpreter_invocation_count. If the MDO exists for
...
...
src/share/vm/ci/ciMethod.hpp
浏览文件 @
147bbce4
...
...
@@ -226,6 +226,9 @@ class ciMethod : public ciMetadata {
ciCallProfile
call_profile_at_bci
(
int
bci
);
int
interpreter_call_site_count
(
int
bci
);
ciField
*
get_field_at_bci
(
int
bci
,
bool
&
will_link
);
ciMethod
*
get_method_at_bci
(
int
bci
,
bool
&
will_link
,
ciSignature
*
*
declared_signature
);
// Given a certain calling environment, find the monomorphic target
// for the call. Return NULL if the call is not monomorphic in
// its calling environment.
...
...
src/share/vm/ci/ciSignature.hpp
浏览文件 @
147bbce4
...
...
@@ -57,12 +57,14 @@ public:
ciSymbol
*
as_symbol
()
const
{
return
_symbol
;
}
ciKlass
*
accessing_klass
()
const
{
return
_accessing_klass
;
}
ciType
*
return_type
()
const
;
ciType
*
type_at
(
int
index
)
const
;
ciType
*
return_type
()
const
;
ciType
*
type_at
(
int
index
)
const
;
int
size
()
const
{
return
_size
;
}
int
count
()
const
{
return
_count
;
}
int
arg_size_for_bc
(
Bytecodes
::
Code
bc
)
{
return
size
()
+
(
Bytecodes
::
has_receiver
(
bc
)
?
1
:
0
);
}
bool
equals
(
ciSignature
*
that
);
void
print_signature
();
...
...
src/share/vm/interpreter/bytecodes.hpp
浏览文件 @
147bbce4
...
...
@@ -423,7 +423,9 @@ class Bytecodes: AllStatic {
static
bool
is_zero_const
(
Code
code
)
{
return
(
code
==
_aconst_null
||
code
==
_iconst_0
||
code
==
_fconst_0
||
code
==
_dconst_0
);
}
static
bool
is_invoke
(
Code
code
)
{
return
(
_invokevirtual
<=
code
&&
code
<=
_invokedynamic
);
}
static
bool
has_receiver
(
Code
code
)
{
assert
(
is_invoke
(
code
),
""
);
return
code
==
_invokevirtual
||
code
==
_invokespecial
||
code
==
_invokeinterface
;
}
static
bool
has_optional_appendix
(
Code
code
)
{
return
code
==
_invokedynamic
||
code
==
_invokehandle
;
}
static
int
compute_flags
(
const
char
*
format
,
int
more_flags
=
0
);
// compute the flags
...
...
src/share/vm/opto/callGenerator.cpp
浏览文件 @
147bbce4
...
...
@@ -139,7 +139,7 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) {
if
(
!
is_static
)
{
// Make an explicit receiver null_check as part of this call.
// Since we share a map with the caller, his JVMS gets adjusted.
kit
.
null_check_receiver
(
method
());
kit
.
null_check_receiver
_before_call
(
method
());
if
(
kit
.
stopped
())
{
// And dump it back to the caller, decorated with any exceptions:
return
kit
.
transfer_exceptions_into_jvms
();
...
...
@@ -207,7 +207,7 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms) {
>=
(
uint
)
ImplicitNullCheckThreshold
)))
{
// Make an explicit receiver null_check as part of this call.
// Since we share a map with the caller, his JVMS gets adjusted.
receiver
=
kit
.
null_check_receiver
(
method
());
receiver
=
kit
.
null_check_receiver
_before_call
(
method
());
if
(
kit
.
stopped
())
{
// And dump it back to the caller, decorated with any exceptions:
return
kit
.
transfer_exceptions_into_jvms
();
...
...
@@ -491,7 +491,7 @@ JVMState* PredictedCallGenerator::generate(JVMState* jvms) {
jvms
->
bci
(),
log
->
identify
(
_predicted_receiver
));
}
receiver
=
kit
.
null_check_receiver
(
method
());
receiver
=
kit
.
null_check_receiver
_before_call
(
method
());
if
(
kit
.
stopped
())
{
return
kit
.
transfer_exceptions_into_jvms
();
}
...
...
@@ -597,7 +597,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
switch
(
iid
)
{
case
vmIntrinsics
::
_invokeBasic
:
{
//
get MethodHandle receiver
//
Get MethodHandle receiver:
Node
*
receiver
=
kit
.
argument
(
0
);
if
(
receiver
->
Opcode
()
==
Op_ConP
)
{
const
TypeOopPtr
*
oop_ptr
=
receiver
->
bottom_type
()
->
is_oopptr
();
...
...
@@ -618,7 +618,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
case
vmIntrinsics
::
_linkToSpecial
:
case
vmIntrinsics
::
_linkToInterface
:
{
//
pop MemberName argument
//
Get MemberName argument:
Node
*
member_name
=
kit
.
argument
(
callee
->
arg_size
()
-
1
);
if
(
member_name
->
Opcode
()
==
Op_ConP
)
{
const
TypeOopPtr
*
oop_ptr
=
member_name
->
bottom_type
()
->
is_oopptr
();
...
...
src/share/vm/opto/callnode.hpp
浏览文件 @
147bbce4
...
...
@@ -344,17 +344,26 @@ public:
OopMap
*
oop_map
()
const
{
return
_oop_map
;
}
void
set_oop_map
(
OopMap
*
om
)
{
_oop_map
=
om
;
}
private:
void
verify_input
(
JVMState
*
jvms
,
uint
idx
)
const
{
assert
(
verify_jvms
(
jvms
),
"jvms must match"
);
Node
*
n
=
in
(
idx
);
assert
((
!
n
->
bottom_type
()
->
isa_long
()
&&
!
n
->
bottom_type
()
->
isa_double
())
||
in
(
idx
+
1
)
->
is_top
(),
"2nd half of long/double"
);
}
public:
// Functionality from old debug nodes which has changed
Node
*
local
(
JVMState
*
jvms
,
uint
idx
)
const
{
assert
(
verify_jvms
(
jvms
),
"jvms must match"
);
verify_input
(
jvms
,
jvms
->
locoff
()
+
idx
);
return
in
(
jvms
->
locoff
()
+
idx
);
}
Node
*
stack
(
JVMState
*
jvms
,
uint
idx
)
const
{
assert
(
verify_jvms
(
jvms
),
"jvms must match"
);
verify_input
(
jvms
,
jvms
->
stkoff
()
+
idx
);
return
in
(
jvms
->
stkoff
()
+
idx
);
}
Node
*
argument
(
JVMState
*
jvms
,
uint
idx
)
const
{
assert
(
verify_jvms
(
jvms
),
"jvms must match"
);
verify_input
(
jvms
,
jvms
->
argoff
()
+
idx
);
return
in
(
jvms
->
argoff
()
+
idx
);
}
Node
*
monitor_box
(
JVMState
*
jvms
,
uint
idx
)
const
{
...
...
src/share/vm/opto/doCall.cpp
浏览文件 @
147bbce4
...
...
@@ -350,7 +350,7 @@ void Parse::do_call() {
// Set frequently used booleans
const
bool
is_virtual
=
bc
()
==
Bytecodes
::
_invokevirtual
;
const
bool
is_virtual_or_interface
=
is_virtual
||
bc
()
==
Bytecodes
::
_invokeinterface
;
const
bool
has_receiver
=
is_virtual_or_interface
||
bc
()
==
Bytecodes
::
_invokespecial
;
const
bool
has_receiver
=
Bytecodes
::
has_receiver
(
bc
())
;
// Find target being called
bool
will_link
;
...
...
@@ -380,6 +380,8 @@ void Parse::do_call() {
// Note: In the absence of miranda methods, an abstract class K can perform
// an invokevirtual directly on an interface method I.m if K implements I.
// orig_callee is the resolved callee which's signature includes the
// appendix argument.
const
int
nargs
=
orig_callee
->
arg_size
();
// Push appendix argument (MethodType, CallSite, etc.), if one.
...
...
@@ -572,7 +574,7 @@ void Parse::do_call() {
}
// If there is going to be a trap, put it at the next bytecode:
set_bci
(
iter
().
next_bci
());
do_null_assert
(
peek
(),
T_OBJECT
);
null_assert
(
peek
()
);
set_bci
(
iter
().
cur_bci
());
// put it back
}
}
...
...
src/share/vm/opto/graphKit.cpp
浏览文件 @
147bbce4
...
...
@@ -93,6 +93,16 @@ JVMState* GraphKit::sync_jvms() const {
return
jvms
;
}
//--------------------------------sync_jvms_for_reexecute---------------------
// Make sure our current jvms agrees with our parse state. This version
// uses the reexecute_sp for reexecuting bytecodes.
JVMState
*
GraphKit
::
sync_jvms_for_reexecute
()
{
JVMState
*
jvms
=
this
->
jvms
();
jvms
->
set_bci
(
bci
());
// Record the new bci in the JVMState
jvms
->
set_sp
(
reexecute_sp
());
// Record the new sp in the JVMState
return
jvms
;
}
#ifdef ASSERT
bool
GraphKit
::
jvms_in_sync
()
const
{
Parse
*
parse
=
is_Parse
();
...
...
@@ -826,7 +836,16 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) {
// Walk the inline list to fill in the correct set of JVMState's
// Also fill in the associated edges for each JVMState.
JVMState
*
youngest_jvms
=
sync_jvms
();
// If the bytecode needs to be reexecuted we need to put
// the arguments back on the stack.
const
bool
should_reexecute
=
jvms
()
->
should_reexecute
();
JVMState
*
youngest_jvms
=
should_reexecute
?
sync_jvms_for_reexecute
()
:
sync_jvms
();
// NOTE: set_bci (called from sync_jvms) might reset the reexecute bit to
// undefined if the bci is different. This is normal for Parse but it
// should not happen for LibraryCallKit because only one bci is processed.
assert
(
!
is_LibraryCallKit
()
||
(
jvms
()
->
should_reexecute
()
==
should_reexecute
),
"in LibraryCallKit the reexecute bit should not change"
);
// If we are guaranteed to throw, we can prune everything but the
// input to the current bytecode.
...
...
@@ -860,7 +879,7 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) {
}
// Presize the call:
debug_only
(
uint
non_debug_edges
=
call
->
req
());
DEBUG_ONLY
(
uint
non_debug_edges
=
call
->
req
());
call
->
add_req_batch
(
top
(),
youngest_jvms
->
debug_depth
());
assert
(
call
->
req
()
==
non_debug_edges
+
youngest_jvms
->
debug_depth
(),
""
);
...
...
@@ -965,7 +984,7 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) {
assert
(
call
->
jvms
()
->
debug_depth
()
==
call
->
req
()
-
non_debug_edges
,
""
);
}
bool
GraphKit
::
compute_stack_effects
(
int
&
inputs
,
int
&
depth
,
bool
for_parse
)
{
bool
GraphKit
::
compute_stack_effects
(
int
&
inputs
,
int
&
depth
)
{
Bytecodes
::
Code
code
=
java_bc
();
if
(
code
==
Bytecodes
::
_wide
)
{
code
=
method
()
->
java_code_at_bci
(
bci
()
+
1
);
...
...
@@ -1005,14 +1024,11 @@ bool GraphKit::compute_stack_effects(int& inputs, int& depth, bool for_parse) {
case
Bytecodes
::
_getfield
:
case
Bytecodes
::
_putfield
:
{
bool
is_get
=
(
depth
>=
0
),
is_static
=
(
depth
&
1
);
ciBytecodeStream
iter
(
method
());
iter
.
reset_to_bci
(
bci
());
iter
.
next
();
bool
ignored_will_link
;
ciField
*
field
=
iter
.
get_field
(
ignored_will_link
);
ciField
*
field
=
method
()
->
get_field_at_bci
(
bci
(),
ignored_will_link
);
int
size
=
field
->
type
()
->
size
();
inputs
=
(
is_static
?
0
:
1
);
bool
is_get
=
(
depth
>=
0
),
is_static
=
(
depth
&
1
);
inputs
=
(
is_static
?
0
:
1
);
if
(
is_get
)
{
depth
=
size
-
inputs
;
}
else
{
...
...
@@ -1028,26 +1044,11 @@ bool GraphKit::compute_stack_effects(int& inputs, int& depth, bool for_parse) {
case
Bytecodes
::
_invokedynamic
:
case
Bytecodes
::
_invokeinterface
:
{
ciBytecodeStream
iter
(
method
());
iter
.
reset_to_bci
(
bci
());
iter
.
next
();
bool
ignored_will_link
;
ciSignature
*
declared_signature
=
NULL
;
ciMethod
*
callee
=
iter
.
get_method
(
ignored_will_link
,
&
declared_signature
);
ciMethod
*
ignored_callee
=
method
()
->
get_method_at_bci
(
bci
(),
ignored_will_link
,
&
declared_signature
);
assert
(
declared_signature
!=
NULL
,
"cannot be null"
);
// (Do not use ciMethod::arg_size(), because
// it might be an unloaded method, which doesn't
// know whether it is static or not.)
if
(
for_parse
)
{
// Case 1: When called from parse we are *before* the invoke (in the
// caller) and need to to adjust the inputs by an appendix
// argument that will be pushed implicitly.
inputs
=
callee
->
invoke_arg_size
(
code
)
-
(
iter
.
has_appendix
()
?
1
:
0
);
}
else
{
// Case 2: Here we are *after* the invoke (in the callee) and need to
// remove any appendix arguments that were popped.
inputs
=
callee
->
invoke_arg_size
(
code
)
-
(
callee
->
has_member_arg
()
?
1
:
0
);
}
inputs
=
declared_signature
->
arg_size_for_bc
(
code
);
int
size
=
declared_signature
->
return_type
()
->
size
();
depth
=
size
-
inputs
;
}
...
...
@@ -1178,7 +1179,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type,
Node
*
chk
=
NULL
;
switch
(
type
)
{
case
T_LONG
:
chk
=
new
(
C
)
CmpLNode
(
value
,
_gvn
.
zerocon
(
T_LONG
));
break
;
case
T_INT
:
chk
=
new
(
C
)
CmpINode
(
value
,
_gvn
.
intcon
(
0
));
break
;
case
T_INT
:
chk
=
new
(
C
)
CmpINode
(
value
,
_gvn
.
intcon
(
0
));
break
;
case
T_ARRAY
:
// fall through
type
=
T_OBJECT
;
// simplify further tests
case
T_OBJECT
:
{
...
...
@@ -1229,7 +1230,8 @@ Node* GraphKit::null_check_common(Node* value, BasicType type,
break
;
}
default
:
ShouldNotReachHere
();
default:
fatal
(
err_msg_res
(
"unexpected type: %s"
,
type2name
(
type
)));
}
assert
(
chk
!=
NULL
,
"sanity check"
);
chk
=
_gvn
.
transform
(
chk
);
...
...
@@ -1861,15 +1863,17 @@ void GraphKit::uncommon_trap(int trap_request,
// occurs here, the runtime will make sure an MDO exists. There is
// no need to call method()->ensure_method_data() at this point.
// Set the stack pointer to the right value for reexecution:
set_sp
(
reexecute_sp
());
#ifdef ASSERT
if
(
!
must_throw
)
{
// Make sure the stack has at least enough depth to execute
// the current bytecode.
int
inputs
,
ignore
;
if
(
compute_stack_effects
(
inputs
,
ignore
))
{
assert
(
sp
()
>=
inputs
,
"must have enough JVMS stack to execute"
);
// It is a frequent error in library_call.cpp to issue an
// uncommon trap with the _sp value already popped.
int
inputs
,
ignored_depth
;
if
(
compute_stack_effects
(
inputs
,
ignored_depth
))
{
assert
(
sp
()
>=
inputs
,
err_msg_res
(
"must have enough JVMS stack to execute %s: sp=%d, inputs=%d"
,
Bytecodes
::
name
(
java_bc
()),
sp
(),
inputs
));
}
}
#endif
...
...
@@ -1900,7 +1904,8 @@ void GraphKit::uncommon_trap(int trap_request,
case
Deoptimization
::
Action_make_not_compilable
:
break
;
default:
assert
(
false
,
"bad action"
);
fatal
(
err_msg_res
(
"unknown action %d: %s"
,
action
,
Deoptimization
::
trap_action_name
(
action
)));
break
;
#endif
}
...
...
@@ -2667,7 +2672,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
case
SSC_always_false
:
// It needs a null check because a null will *pass* the cast check.
// A non-null value will always produce an exception.
return
do_null_assert
(
obj
,
T_OBJECT
);
return
null_assert
(
obj
);
}
}
}
...
...
@@ -2786,7 +2791,7 @@ Node* GraphKit::insert_mem_bar(int opcode, Node* precedent) {
mb
->
init_req
(
TypeFunc
::
Control
,
control
());
mb
->
init_req
(
TypeFunc
::
Memory
,
reset_memory
());
Node
*
membar
=
_gvn
.
transform
(
mb
);
set_control
(
_gvn
.
transform
(
new
(
C
)
ProjNode
(
membar
,
TypeFunc
::
Control
)
));
set_control
(
_gvn
.
transform
(
new
(
C
)
ProjNode
(
membar
,
TypeFunc
::
Control
)
));
set_all_memory_call
(
membar
);
return
membar
;
}
...
...
@@ -3148,7 +3153,7 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
Node
*
cmp_lh
=
_gvn
.
transform
(
new
(
C
)
CmpINode
(
layout_val
,
intcon
(
layout_con
))
);
Node
*
bol_lh
=
_gvn
.
transform
(
new
(
C
)
BoolNode
(
cmp_lh
,
BoolTest
::
eq
)
);
{
BuildCutout
unless
(
this
,
bol_lh
,
PROB_MAX
);
_sp
+=
nargs
;
inc_sp
(
nargs
)
;
uncommon_trap
(
Deoptimization
::
Reason_class_check
,
Deoptimization
::
Action_maybe_recompile
);
}
...
...
@@ -3391,7 +3396,7 @@ void GraphKit::add_predicate_impl(Deoptimization::DeoptReason reason, int nargs)
{
PreserveJVMState
pjvms
(
this
);
set_control
(
iffalse
);
_sp
+=
nargs
;
inc_sp
(
nargs
)
;
uncommon_trap
(
reason
,
Deoptimization
::
Action_maybe_recompile
);
}
Node
*
iftrue
=
_gvn
.
transform
(
new
(
C
)
IfTrueNode
(
iff
));
...
...
src/share/vm/opto/graphKit.hpp
浏览文件 @
147bbce4
...
...
@@ -41,6 +41,7 @@
class
FastLockNode
;
class
FastUnlockNode
;
class
IdealKit
;
class
LibraryCallKit
;
class
Parse
;
class
RootNode
;
...
...
@@ -60,10 +61,12 @@ class GraphKit : public Phase {
PhaseGVN
&
_gvn
;
// Some optimizations while parsing
SafePointNode
*
_map
;
// Parser map from JVM to Nodes
SafePointNode
*
_exceptions
;
// Parser map(s) for exception state(s)
int
_sp
;
// JVM Expression Stack Pointer
int
_bci
;
// JVM Bytecode Pointer
ciMethod
*
_method
;
// JVM Current Method
private:
int
_sp
;
// JVM Expression Stack Pointer; don't modify directly!
private:
SafePointNode
*
map_not_null
()
const
{
assert
(
_map
!=
NULL
,
"must call stopped() to test for reset compiler map"
);
...
...
@@ -80,7 +83,8 @@ class GraphKit : public Phase {
}
#endif
virtual
Parse
*
is_Parse
()
const
{
return
NULL
;
}
virtual
Parse
*
is_Parse
()
const
{
return
NULL
;
}
virtual
LibraryCallKit
*
is_LibraryCallKit
()
const
{
return
NULL
;
}
ciEnv
*
env
()
const
{
return
_env
;
}
PhaseGVN
&
gvn
()
const
{
return
_gvn
;
}
...
...
@@ -141,7 +145,7 @@ class GraphKit : public Phase {
_bci
=
jvms
->
bci
();
_method
=
jvms
->
has_method
()
?
jvms
->
method
()
:
NULL
;
}
void
set_map
(
SafePointNode
*
m
)
{
_map
=
m
;
debug_only
(
verify_map
());
}
void
set_sp
(
int
i
)
{
assert
(
i
>=
0
,
"must be non-negative"
);
_sp
=
i
;
}
void
set_sp
(
int
sp
)
{
assert
(
sp
>=
0
,
err_msg_res
(
"sp must be non-negative: %d"
,
sp
));
_sp
=
sp
;
}
void
clean_stack
(
int
from_sp
);
// clear garbage beyond from_sp to top
void
inc_sp
(
int
i
)
{
set_sp
(
sp
()
+
i
);
}
...
...
@@ -149,7 +153,9 @@ class GraphKit : public Phase {
void
set_bci
(
int
bci
)
{
_bci
=
bci
;
}
// Make sure jvms has current bci & sp.
JVMState
*
sync_jvms
()
const
;
JVMState
*
sync_jvms
()
const
;
JVMState
*
sync_jvms_for_reexecute
();
#ifdef ASSERT
// Make sure JVMS has an updated copy of bci and sp.
// Also sanity-check method, depth, and monitor depth.
...
...
@@ -286,7 +292,7 @@ class GraphKit : public Phase {
// How many stack inputs does the current BC consume?
// And, how does the stack change after the bytecode?
// Returns false if unknown.
bool
compute_stack_effects
(
int
&
inputs
,
int
&
depth
,
bool
for_parse
=
false
);
bool
compute_stack_effects
(
int
&
inputs
,
int
&
depth
);
// Add a fixed offset to a pointer
Node
*
basic_plus_adr
(
Node
*
base
,
Node
*
ptr
,
intptr_t
offset
)
{
...
...
@@ -337,20 +343,37 @@ class GraphKit : public Phase {
Node
*
load_object_klass
(
Node
*
object
);
// Find out the length of an array.
Node
*
load_array_length
(
Node
*
array
);
// Helper function to do a NULL pointer check or ZERO check based on type.
Node
*
null_check_common
(
Node
*
value
,
BasicType
type
,
bool
assert_null
,
Node
*
*
null_control
);
// Throw an exception if a given value is null.
// Return the value cast to not-null.
// Be clever about equivalent dominating null checks.
Node
*
do_null_check
(
Node
*
value
,
BasicType
type
)
{
return
null_check_common
(
value
,
type
,
false
,
NULL
);
Node
*
null_check_common
(
Node
*
value
,
BasicType
type
,
bool
assert_null
=
false
,
Node
*
*
null_control
=
NULL
);
Node
*
null_check
(
Node
*
value
,
BasicType
type
=
T_OBJECT
)
{
return
null_check_common
(
value
,
type
);
}
Node
*
null_check_receiver
()
{
assert
(
argument
(
0
)
->
bottom_type
()
->
isa_ptr
(),
"must be"
);
return
null_check
(
argument
(
0
));
}
Node
*
zero_check_int
(
Node
*
value
)
{
assert
(
value
->
bottom_type
()
->
basic_type
()
==
T_INT
,
err_msg_res
(
"wrong type: %s"
,
type2name
(
value
->
bottom_type
()
->
basic_type
())));
return
null_check_common
(
value
,
T_INT
);
}
Node
*
zero_check_long
(
Node
*
value
)
{
assert
(
value
->
bottom_type
()
->
basic_type
()
==
T_LONG
,
err_msg_res
(
"wrong type: %s"
,
type2name
(
value
->
bottom_type
()
->
basic_type
())));
return
null_check_common
(
value
,
T_LONG
);
}
// Throw an uncommon trap if a given value is __not__ null.
// Return the value cast to null, and be clever about dominating checks.
Node
*
do_null_assert
(
Node
*
value
,
BasicType
type
)
{
return
null_check_common
(
value
,
type
,
true
,
NULL
);
Node
*
null_assert
(
Node
*
value
,
BasicType
type
=
T_OBJECT
)
{
return
null_check_common
(
value
,
type
,
true
);
}
// Null check oop. Return null-path control into (*null_control).
// Return a cast-not-null node which depends on the not-null control.
// If never_see_null, use an uncommon trap (*null_control sees a top).
...
...
@@ -371,9 +394,9 @@ class GraphKit : public Phase {
// Replace all occurrences of one node by another.
void
replace_in_map
(
Node
*
old
,
Node
*
neww
);
void
push
(
Node
*
n
)
{
map_not_null
();
_map
->
set_stack
(
_map
->
_jvms
,
_sp
++
,
n
);
}
Node
*
pop
()
{
map_not_null
();
return
_map
->
stack
(
_map
->
_jvms
,
--
_sp
);
}
Node
*
peek
(
int
off
=
0
)
{
map_not_null
();
return
_map
->
stack
(
_map
->
_jvms
,
_sp
-
off
-
1
);
}
void
push
(
Node
*
n
)
{
map_not_null
();
_map
->
set_stack
(
_map
->
_jvms
,
_sp
++
,
n
);
}
Node
*
pop
()
{
map_not_null
();
return
_map
->
stack
(
_map
->
_jvms
,
--
_sp
);
}
Node
*
peek
(
int
off
=
0
)
{
map_not_null
();
return
_map
->
stack
(
_map
->
_jvms
,
_sp
-
off
-
1
);
}
void
push_pair
(
Node
*
ldval
)
{
push
(
ldval
);
...
...
@@ -580,19 +603,15 @@ class GraphKit : public Phase {
//---------- help for generating calls --------------
// Do a null check on the receiver, which is in argument(0).
Node
*
null_check_receiver
(
ciMethod
*
callee
)
{
// Do a null check on the receiver as it would happen before the call to
// callee (with all arguments still on the stack).
Node
*
null_check_receiver_before_call
(
ciMethod
*
callee
)
{
assert
(
!
callee
->
is_static
(),
"must be a virtual method"
);
int
nargs
=
1
+
callee
->
signature
()
->
size
();
// Null check on self without removing any arguments. The argument
// null check technically happens in the wrong place, which can lead to
// invalid stack traces when the primitive is inlined into a method
// which handles NullPointerExceptions.
Node
*
receiver
=
argument
(
0
);
_sp
+=
nargs
;
receiver
=
do_null_check
(
receiver
,
T_OBJECT
);
_sp
-=
nargs
;
return
receiver
;
const
int
nargs
=
callee
->
arg_size
();
inc_sp
(
nargs
);
Node
*
n
=
null_check_receiver
();
dec_sp
(
nargs
);
return
n
;
}
// Fill in argument edges for the call from argument(0), argument(1), ...
...
...
@@ -645,6 +664,9 @@ class GraphKit : public Phase {
klass
,
reason_string
,
must_throw
,
keep_exact_action
);
}
// SP when bytecode needs to be reexecuted.
virtual
int
reexecute_sp
()
{
return
sp
();
}
// Report if there were too many traps at the current method and bci.
// Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded.
// If there is no MDO at all, report no trap unless told to assume it.
...
...
src/share/vm/opto/library_call.cpp
浏览文件 @
147bbce4
此差异已折叠。
点击以展开。
src/share/vm/opto/locknode.cpp
浏览文件 @
147bbce4
...
...
@@ -165,7 +165,7 @@ void Parse::do_monitor_enter() {
kill_dead_locals
();
// Null check; get casted pointer.
Node
*
obj
=
do_null_check
(
peek
(),
T_OBJECT
);
Node
*
obj
=
null_check
(
peek
()
);
// Check for locking null object
if
(
stopped
())
return
;
...
...
src/share/vm/opto/parse1.cpp
浏览文件 @
147bbce4
...
...
@@ -1008,7 +1008,7 @@ SafePointNode* Parse::create_entry_map() {
// If this is an inlined method, we may have to do a receiver null check.
if
(
_caller
->
has_method
()
&&
is_normal_parse
()
&&
!
method
()
->
is_static
())
{
GraphKit
kit
(
_caller
);
kit
.
null_check_receiver
(
method
());
kit
.
null_check_receiver
_before_call
(
method
());
_caller
=
kit
.
transfer_exceptions_into_jvms
();
if
(
kit
.
stopped
())
{
_exits
.
add_exception_states_from
(
_caller
);
...
...
@@ -1398,7 +1398,7 @@ void Parse::do_one_block() {
#ifdef ASSERT
int
pre_bc_sp
=
sp
();
int
inputs
,
depth
;
bool
have_se
=
!
stopped
()
&&
compute_stack_effects
(
inputs
,
depth
,
/*for_parse*/
true
);
bool
have_se
=
!
stopped
()
&&
compute_stack_effects
(
inputs
,
depth
);
assert
(
!
have_se
||
pre_bc_sp
>=
inputs
,
err_msg_res
(
"have enough stack to execute this BC: pre_bc_sp=%d, inputs=%d"
,
pre_bc_sp
,
inputs
));
#endif //ASSERT
...
...
src/share/vm/opto/parse2.cpp
浏览文件 @
147bbce4
...
...
@@ -48,7 +48,7 @@ void Parse::array_load(BasicType elem_type) {
const
Type
*
elem
=
Type
::
TOP
;
Node
*
adr
=
array_addressing
(
elem_type
,
0
,
&
elem
);
if
(
stopped
())
return
;
// guaranteed null or range check
_sp
-=
2
;
// Pop array and index
dec_sp
(
2
);
// Pop array and index
const
TypeAryPtr
*
adr_type
=
TypeAryPtr
::
get_array_body_type
(
elem_type
);
Node
*
ld
=
make_load
(
control
(),
adr
,
elem
,
elem_type
,
adr_type
);
push
(
ld
);
...
...
@@ -60,7 +60,7 @@ void Parse::array_store(BasicType elem_type) {
Node
*
adr
=
array_addressing
(
elem_type
,
1
);
if
(
stopped
())
return
;
// guaranteed null or range check
Node
*
val
=
pop
();
_sp
-=
2
;
// Pop array and index
dec_sp
(
2
);
// Pop array and index
const
TypeAryPtr
*
adr_type
=
TypeAryPtr
::
get_array_body_type
(
elem_type
);
store_to_memory
(
control
(),
adr
,
val
,
elem_type
,
adr_type
);
}
...
...
@@ -73,7 +73,7 @@ Node* Parse::array_addressing(BasicType type, int vals, const Type* *result2) {
Node
*
ary
=
peek
(
1
+
vals
);
// in case of exception
// Null check the array base, with correct stack contents
ary
=
do_
null_check
(
ary
,
T_ARRAY
);
ary
=
null_check
(
ary
,
T_ARRAY
);
// Compile-time detect of null-exception?
if
(
stopped
())
return
top
();
...
...
@@ -681,7 +681,7 @@ void Parse::l2f() {
void
Parse
::
do_irem
()
{
// Must keep both values on the expression-stack during null-check
do_null_check
(
peek
(),
T_INT
);
zero_check_int
(
peek
()
);
// Compile-time detect of null-exception?
if
(
stopped
())
return
;
...
...
@@ -958,7 +958,7 @@ inline int Parse::repush_if_args() {
DEBUG_ONLY
(
sync_jvms
());
// argument(n) requires a synced jvms
assert
(
argument
(
0
)
!=
NULL
,
"must exist"
);
assert
(
bc_depth
==
1
||
argument
(
1
)
!=
NULL
,
"two must exist"
);
_sp
+=
bc_depth
;
inc_sp
(
bc_depth
)
;
return
bc_depth
;
}
...
...
@@ -1581,8 +1581,8 @@ void Parse::do_one_bytecode() {
set_pair_local
(
iter
().
get_index
(),
dstore_rounding
(
pop_pair
())
);
break
;
case
Bytecodes
::
_pop
:
_sp
-=
1
;
break
;
case
Bytecodes
::
_pop2
:
_sp
-=
2
;
break
;
case
Bytecodes
::
_pop
:
dec_sp
(
1
)
;
break
;
case
Bytecodes
::
_pop2
:
dec_sp
(
2
)
;
break
;
case
Bytecodes
::
_swap
:
a
=
pop
();
b
=
pop
();
...
...
@@ -1650,7 +1650,7 @@ void Parse::do_one_bytecode() {
case
Bytecodes
::
_arraylength
:
{
// Must do null-check with value on expression stack
Node
*
ary
=
do_
null_check
(
peek
(),
T_ARRAY
);
Node
*
ary
=
null_check
(
peek
(),
T_ARRAY
);
// Compile-time detect of null-exception?
if
(
stopped
())
return
;
a
=
pop
();
...
...
@@ -1667,15 +1667,15 @@ void Parse::do_one_bytecode() {
case
Bytecodes
::
_laload
:
{
a
=
array_addressing
(
T_LONG
,
0
);
if
(
stopped
())
return
;
// guaranteed null or range check
_sp
-=
2
;
// Pop array and index
push_pair
(
make_load
(
control
(),
a
,
TypeLong
::
LONG
,
T_LONG
,
TypeAryPtr
::
LONGS
));
dec_sp
(
2
);
// Pop array and index
push_pair
(
make_load
(
control
(),
a
,
TypeLong
::
LONG
,
T_LONG
,
TypeAryPtr
::
LONGS
));
break
;
}
case
Bytecodes
::
_daload
:
{
a
=
array_addressing
(
T_DOUBLE
,
0
);
if
(
stopped
())
return
;
// guaranteed null or range check
_sp
-=
2
;
// Pop array and index
push_pair
(
make_load
(
control
(),
a
,
Type
::
DOUBLE
,
T_DOUBLE
,
TypeAryPtr
::
DOUBLES
));
dec_sp
(
2
);
// Pop array and index
push_pair
(
make_load
(
control
(),
a
,
Type
::
DOUBLE
,
T_DOUBLE
,
TypeAryPtr
::
DOUBLES
));
break
;
}
case
Bytecodes
::
_bastore
:
array_store
(
T_BYTE
);
break
;
...
...
@@ -1699,7 +1699,7 @@ void Parse::do_one_bytecode() {
a
=
array_addressing
(
T_LONG
,
2
);
if
(
stopped
())
return
;
// guaranteed null or range check
c
=
pop_pair
();
_sp
-=
2
;
// Pop array and index
dec_sp
(
2
);
// Pop array and index
store_to_memory
(
control
(),
a
,
c
,
T_LONG
,
TypeAryPtr
::
LONGS
);
break
;
}
...
...
@@ -1707,7 +1707,7 @@ void Parse::do_one_bytecode() {
a
=
array_addressing
(
T_DOUBLE
,
2
);
if
(
stopped
())
return
;
// guaranteed null or range check
c
=
pop_pair
();
_sp
-=
2
;
// Pop array and index
dec_sp
(
2
);
// Pop array and index
c
=
dstore_rounding
(
c
);
store_to_memory
(
control
(),
a
,
c
,
T_DOUBLE
,
TypeAryPtr
::
DOUBLES
);
break
;
...
...
@@ -1733,7 +1733,7 @@ void Parse::do_one_bytecode() {
break
;
case
Bytecodes
::
_idiv
:
// Must keep both values on the expression-stack during null-check
do_null_check
(
peek
(),
T_INT
);
zero_check_int
(
peek
()
);
// Compile-time detect of null-exception?
if
(
stopped
())
return
;
b
=
pop
();
...
...
@@ -2041,7 +2041,7 @@ void Parse::do_one_bytecode() {
case
Bytecodes
::
_lrem
:
// Must keep both values on the expression-stack during null-check
assert
(
peek
(
0
)
==
top
(),
"long word order"
);
do_null_check
(
peek
(
1
),
T_LONG
);
zero_check_long
(
peek
(
1
)
);
// Compile-time detect of null-exception?
if
(
stopped
())
return
;
b
=
pop_pair
();
...
...
@@ -2053,7 +2053,7 @@ void Parse::do_one_bytecode() {
case
Bytecodes
::
_ldiv
:
// Must keep both values on the expression-stack during null-check
assert
(
peek
(
0
)
==
top
(),
"long word order"
);
do_null_check
(
peek
(
1
),
T_LONG
);
zero_check_long
(
peek
(
1
)
);
// Compile-time detect of null-exception?
if
(
stopped
())
return
;
b
=
pop_pair
();
...
...
@@ -2175,7 +2175,7 @@ void Parse::do_one_bytecode() {
case
Bytecodes
::
_athrow
:
// null exception oop throws NULL pointer exception
do_null_check
(
peek
(),
T_OBJECT
);
null_check
(
peek
()
);
if
(
stopped
())
return
;
// Hook the thrown exception directly to subsequent handlers.
if
(
BailoutToInterpreterForThrows
)
{
...
...
src/share/vm/opto/parse3.cpp
浏览文件 @
147bbce4
...
...
@@ -116,7 +116,7 @@ void Parse::do_field_access(bool is_get, bool is_field) {
Node
*
obj
;
if
(
is_field
)
{
int
obj_depth
=
is_get
?
0
:
field
->
type
()
->
size
();
obj
=
do_null_check
(
peek
(
obj_depth
),
T_OBJECT
);
obj
=
null_check
(
peek
(
obj_depth
)
);
// Compile-time detect of null-exception?
if
(
stopped
())
return
;
...
...
@@ -126,11 +126,11 @@ void Parse::do_field_access(bool is_get, bool is_field) {
#endif
if
(
is_get
)
{
--
_sp
;
// pop receiver before getting
(
void
)
pop
()
;
// pop receiver before getting
do_get_xxx
(
obj
,
field
,
is_field
);
}
else
{
do_put_xxx
(
obj
,
field
,
is_field
);
--
_sp
;
// pop receiver after putting
(
void
)
pop
()
;
// pop receiver after putting
}
}
else
{
const
TypeInstPtr
*
tip
=
TypeInstPtr
::
make
(
field_holder
->
java_mirror
());
...
...
@@ -230,7 +230,7 @@ void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
}
// If there is going to be a trap, put it at the next bytecode:
set_bci
(
iter
().
next_bci
());
do_null_assert
(
peek
(),
T_OBJECT
);
null_assert
(
peek
()
);
set_bci
(
iter
().
cur_bci
());
// put it back
}
...
...
@@ -463,7 +463,7 @@ void Parse::do_multianewarray() {
// Note: the reexecute bit will be set in GraphKit::add_safepoint_edges()
// when AllocateArray node for newarray is created.
{
PreserveReexecuteState
preexecs
(
this
);
_sp
+=
ndimensions
;
inc_sp
(
ndimensions
)
;
// Pass 0 as nargs since uncommon trap code does not need to restore stack.
obj
=
expand_multianewarray
(
array_klass
,
&
length
[
0
],
ndimensions
,
0
);
}
//original reexecute and sp are set back here
...
...
@@ -492,7 +492,7 @@ void Parse::do_multianewarray() {
// Create a java array for dimension sizes
Node
*
dims
=
NULL
;
{
PreserveReexecuteState
preexecs
(
this
);
_sp
+=
ndimensions
;
inc_sp
(
ndimensions
)
;
Node
*
dims_array_klass
=
makecon
(
TypeKlassPtr
::
make
(
ciArrayKlass
::
make
(
ciType
::
make
(
T_INT
))));
dims
=
new_array
(
dims_array_klass
,
intcon
(
ndimensions
),
0
);
...
...
src/share/vm/opto/parseHelper.cpp
浏览文件 @
147bbce4
...
...
@@ -84,7 +84,7 @@ void Parse::do_checkcast() {
C
->
log
()
->
identify
(
tp
->
klass
()));
}
}
do_null_assert
(
obj
,
T_OBJECT
);
null_assert
(
obj
);
assert
(
stopped
()
||
_gvn
.
type
(
peek
())
->
higher_equal
(
TypePtr
::
NULL_PTR
),
"what's left behind is null"
);
if
(
!
stopped
())
{
profile_null_checkcast
();
...
...
@@ -116,7 +116,7 @@ void Parse::do_instanceof() {
C
->
log
()
->
elem
(
"assert_null reason='instanceof' klass='%d'"
,
C
->
log
()
->
identify
(
klass
));
}
do_null_assert
(
peek
(),
T_OBJECT
);
null_assert
(
peek
()
);
assert
(
stopped
()
||
_gvn
.
type
(
peek
())
->
higher_equal
(
TypePtr
::
NULL_PTR
),
"what's left behind is null"
);
if
(
!
stopped
())
{
// The object is now known to be null.
...
...
@@ -139,10 +139,10 @@ void Parse::do_instanceof() {
// pull array from stack and check that the store is valid
void
Parse
::
array_store_check
()
{
// Shorthand access to array store elements
Node
*
obj
=
stack
(
_sp
-
1
);
Node
*
idx
=
stack
(
_sp
-
2
);
Node
*
ary
=
stack
(
_sp
-
3
);
// Shorthand access to array store elements
without popping them.
Node
*
obj
=
peek
(
0
);
Node
*
idx
=
peek
(
1
);
Node
*
ary
=
peek
(
2
);
if
(
_gvn
.
type
(
obj
)
==
TypePtr
::
NULL_PTR
)
{
// There's never a type check on null values.
...
...
src/share/vm/opto/type.hpp
浏览文件 @
147bbce4
...
...
@@ -242,8 +242,10 @@ public:
const
TypeInt
*
isa_int
()
const
;
// Returns NULL if not an Int
const
TypeLong
*
is_long
()
const
;
const
TypeLong
*
isa_long
()
const
;
// Returns NULL if not a Long
const
TypeD
*
isa_double
()
const
;
// Returns NULL if not a Double{Top,Con,Bot}
const
TypeD
*
is_double_constant
()
const
;
// Asserts it is a DoubleCon
const
TypeD
*
isa_double_constant
()
const
;
// Returns NULL if not a DoubleCon
const
TypeF
*
isa_float
()
const
;
// Returns NULL if not a Float{Top,Con,Bot}
const
TypeF
*
is_float_constant
()
const
;
// Asserts it is a FloatCon
const
TypeF
*
isa_float_constant
()
const
;
// Returns NULL if not a FloatCon
const
TypeTuple
*
is_tuple
()
const
;
// Collection of fields, NOT a pointer
...
...
@@ -1320,24 +1322,6 @@ inline double Type::getd() const {
return
((
TypeD
*
)
this
)
->
_d
;
}
inline
const
TypeF
*
Type
::
is_float_constant
()
const
{
assert
(
_base
==
FloatCon
,
"Not a Float"
);
return
(
TypeF
*
)
this
;
}
inline
const
TypeF
*
Type
::
isa_float_constant
()
const
{
return
(
_base
==
FloatCon
?
(
TypeF
*
)
this
:
NULL
);
}
inline
const
TypeD
*
Type
::
is_double_constant
()
const
{
assert
(
_base
==
DoubleCon
,
"Not a Double"
);
return
(
TypeD
*
)
this
;
}
inline
const
TypeD
*
Type
::
isa_double_constant
()
const
{
return
(
_base
==
DoubleCon
?
(
TypeD
*
)
this
:
NULL
);
}
inline
const
TypeInt
*
Type
::
is_int
()
const
{
assert
(
_base
==
Int
,
"Not an Int"
);
return
(
TypeInt
*
)
this
;
...
...
@@ -1356,6 +1340,36 @@ inline const TypeLong *Type::isa_long() const {
return
(
_base
==
Long
?
(
TypeLong
*
)
this
:
NULL
);
}
inline
const
TypeF
*
Type
::
isa_float
()
const
{
return
((
_base
==
FloatTop
||
_base
==
FloatCon
||
_base
==
FloatBot
)
?
(
TypeF
*
)
this
:
NULL
);
}
inline
const
TypeF
*
Type
::
is_float_constant
()
const
{
assert
(
_base
==
FloatCon
,
"Not a Float"
);
return
(
TypeF
*
)
this
;
}
inline
const
TypeF
*
Type
::
isa_float_constant
()
const
{
return
(
_base
==
FloatCon
?
(
TypeF
*
)
this
:
NULL
);
}
inline
const
TypeD
*
Type
::
isa_double
()
const
{
return
((
_base
==
DoubleTop
||
_base
==
DoubleCon
||
_base
==
DoubleBot
)
?
(
TypeD
*
)
this
:
NULL
);
}
inline
const
TypeD
*
Type
::
is_double_constant
()
const
{
assert
(
_base
==
DoubleCon
,
"Not a Double"
);
return
(
TypeD
*
)
this
;
}
inline
const
TypeD
*
Type
::
isa_double_constant
()
const
{
return
(
_base
==
DoubleCon
?
(
TypeD
*
)
this
:
NULL
);
}
inline
const
TypeTuple
*
Type
::
is_tuple
()
const
{
assert
(
_base
==
Tuple
,
"Not a Tuple"
);
return
(
TypeTuple
*
)
this
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录