Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_hotspot
提交
a5b2c84c
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看板
体验新版 GitCode,发现更多精彩内容 >>
提交
a5b2c84c
编写于
7月 07, 2010
作者:
N
never
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
5416cce2
96753056
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
102 addition
and
241 deletion
+102
-241
src/share/vm/opto/callnode.cpp
src/share/vm/opto/callnode.cpp
+2
-2
src/share/vm/opto/compile.cpp
src/share/vm/opto/compile.cpp
+14
-28
src/share/vm/opto/compile.hpp
src/share/vm/opto/compile.hpp
+1
-0
src/share/vm/opto/escape.cpp
src/share/vm/opto/escape.cpp
+51
-26
src/share/vm/opto/escape.hpp
src/share/vm/opto/escape.hpp
+9
-4
src/share/vm/prims/jvmtiCodeBlobEvents.cpp
src/share/vm/prims/jvmtiCodeBlobEvents.cpp
+25
-181
未找到文件。
src/share/vm/opto/callnode.cpp
浏览文件 @
a5b2c84c
...
...
@@ -1524,7 +1524,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
ConnectionGraph
*
cgr
=
phase
->
C
->
congraph
();
PointsToNode
::
EscapeState
es
=
PointsToNode
::
GlobalEscape
;
if
(
cgr
!=
NULL
)
es
=
cgr
->
escape_state
(
obj_node
()
,
phase
);
es
=
cgr
->
escape_state
(
obj_node
());
if
(
es
!=
PointsToNode
::
UnknownEscape
&&
es
!=
PointsToNode
::
GlobalEscape
)
{
// Mark it eliminated to update any counters
this
->
set_eliminated
();
...
...
@@ -1627,7 +1627,7 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
ConnectionGraph
*
cgr
=
phase
->
C
->
congraph
();
PointsToNode
::
EscapeState
es
=
PointsToNode
::
GlobalEscape
;
if
(
cgr
!=
NULL
)
es
=
cgr
->
escape_state
(
obj_node
()
,
phase
);
es
=
cgr
->
escape_state
(
obj_node
());
if
(
es
!=
PointsToNode
::
UnknownEscape
&&
es
!=
PointsToNode
::
GlobalEscape
)
{
// Mark it eliminated to update any counters
this
->
set_eliminated
();
...
...
src/share/vm/opto/compile.cpp
浏览文件 @
a5b2c84c
...
...
@@ -637,34 +637,6 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
if
(
failing
())
return
;
NOT_PRODUCT
(
verify_graph_edges
();
)
// Perform escape analysis
if
(
_do_escape_analysis
&&
ConnectionGraph
::
has_candidates
(
this
))
{
TracePhase
t2
(
"escapeAnalysis"
,
&
_t_escapeAnalysis
,
true
);
// Add ConP#NULL and ConN#NULL nodes before ConnectionGraph construction.
PhaseGVN
*
igvn
=
initial_gvn
();
Node
*
oop_null
=
igvn
->
zerocon
(
T_OBJECT
);
Node
*
noop_null
=
igvn
->
zerocon
(
T_NARROWOOP
);
_congraph
=
new
(
comp_arena
())
ConnectionGraph
(
this
);
bool
has_non_escaping_obj
=
_congraph
->
compute_escape
();
#ifndef PRODUCT
if
(
PrintEscapeAnalysis
)
{
_congraph
->
dump
();
}
#endif
// Cleanup.
if
(
oop_null
->
outcnt
()
==
0
)
igvn
->
hash_delete
(
oop_null
);
if
(
noop_null
->
outcnt
()
==
0
)
igvn
->
hash_delete
(
noop_null
);
if
(
!
has_non_escaping_obj
)
{
_congraph
=
NULL
;
}
if
(
failing
())
return
;
}
// Now optimize
Optimize
();
if
(
failing
())
return
;
...
...
@@ -1601,6 +1573,20 @@ void Compile::Optimize() {
if
(
failing
())
return
;
// Perform escape analysis
if
(
_do_escape_analysis
&&
ConnectionGraph
::
has_candidates
(
this
))
{
TracePhase
t2
(
"escapeAnalysis"
,
&
_t_escapeAnalysis
,
true
);
ConnectionGraph
::
do_analysis
(
this
,
&
igvn
);
if
(
failing
())
return
;
igvn
.
optimize
();
print_method
(
"Iter GVN 3"
,
2
);
if
(
failing
())
return
;
}
// Loop transforms on the ideal graph. Range Check Elimination,
// peeling, unrolling, etc.
...
...
src/share/vm/opto/compile.hpp
浏览文件 @
a5b2c84c
...
...
@@ -362,6 +362,7 @@ class Compile : public Phase {
Node
*
macro_node
(
int
idx
)
{
return
_macro_nodes
->
at
(
idx
);
}
Node
*
predicate_opaque1_node
(
int
idx
)
{
return
_predicate_opaqs
->
at
(
idx
);}
ConnectionGraph
*
congraph
()
{
return
_congraph
;}
void
set_congraph
(
ConnectionGraph
*
congraph
)
{
_congraph
=
congraph
;}
void
add_macro_node
(
Node
*
n
)
{
//assert(n->is_macro(), "must be a macro node");
assert
(
!
_macro_nodes
->
contains
(
n
),
" duplicate entry in expand list"
);
...
...
src/share/vm/opto/escape.cpp
浏览文件 @
a5b2c84c
...
...
@@ -81,18 +81,18 @@ void PointsToNode::dump(bool print_state) const {
}
#endif
ConnectionGraph
::
ConnectionGraph
(
Compile
*
C
)
:
ConnectionGraph
::
ConnectionGraph
(
Compile
*
C
,
PhaseIterGVN
*
igvn
)
:
_nodes
(
C
->
comp_arena
(),
C
->
unique
(),
C
->
unique
(),
PointsToNode
()),
_processed
(
C
->
comp_arena
()),
_collecting
(
true
),
_compile
(
C
),
_igvn
(
igvn
),
_node_map
(
C
->
comp_arena
())
{
_phantom_object
=
C
->
top
()
->
_idx
,
add_node
(
C
->
top
(),
PointsToNode
::
JavaObject
,
PointsToNode
::
GlobalEscape
,
true
);
// Add ConP(#NULL) and ConN(#NULL) nodes.
PhaseGVN
*
igvn
=
C
->
initial_gvn
();
Node
*
oop_null
=
igvn
->
zerocon
(
T_OBJECT
);
_oop_null
=
oop_null
->
_idx
;
assert
(
_oop_null
<
C
->
unique
(),
"should be created already"
);
...
...
@@ -182,7 +182,7 @@ void ConnectionGraph::add_node(Node *n, PointsToNode::NodeType nt,
_processed
.
set
(
n
->
_idx
);
}
PointsToNode
::
EscapeState
ConnectionGraph
::
escape_state
(
Node
*
n
,
PhaseTransform
*
phase
)
{
PointsToNode
::
EscapeState
ConnectionGraph
::
escape_state
(
Node
*
n
)
{
uint
idx
=
n
->
_idx
;
PointsToNode
::
EscapeState
es
;
...
...
@@ -207,22 +207,26 @@ PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n, PhaseTransform
if
(
n
->
uncast
()
->
_idx
>=
nodes_size
())
return
PointsToNode
::
UnknownEscape
;
PointsToNode
::
EscapeState
orig_es
=
es
;
// compute max escape state of anything this node could point to
VectorSet
ptset
(
Thread
::
current
()
->
resource_area
());
PointsTo
(
ptset
,
n
,
phase
);
PointsTo
(
ptset
,
n
);
for
(
VectorSetI
i
(
&
ptset
);
i
.
test
()
&&
es
!=
PointsToNode
::
GlobalEscape
;
++
i
)
{
uint
pt
=
i
.
elem
;
PointsToNode
::
EscapeState
pes
=
ptnode_adr
(
pt
)
->
escape_state
();
if
(
pes
>
es
)
es
=
pes
;
}
// cache the computed escape state
assert
(
es
!=
PointsToNode
::
UnknownEscape
,
"should have computed an escape state"
);
ptnode_adr
(
idx
)
->
set_escape_state
(
es
);
if
(
orig_es
!=
es
)
{
// cache the computed escape state
assert
(
es
!=
PointsToNode
::
UnknownEscape
,
"should have computed an escape state"
);
ptnode_adr
(
idx
)
->
set_escape_state
(
es
);
}
// orig_es could be PointsToNode::UnknownEscape
return
es
;
}
void
ConnectionGraph
::
PointsTo
(
VectorSet
&
ptset
,
Node
*
n
,
PhaseTransform
*
phase
)
{
void
ConnectionGraph
::
PointsTo
(
VectorSet
&
ptset
,
Node
*
n
)
{
VectorSet
visited
(
Thread
::
current
()
->
resource_area
());
GrowableArray
<
uint
>
worklist
;
...
...
@@ -990,7 +994,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
GrowableArray
<
Node
*>
memnode_worklist
;
GrowableArray
<
PhiNode
*>
orig_phis
;
PhaseGVN
*
igvn
=
_
compile
->
initial_gvn
()
;
PhaseGVN
*
igvn
=
_
igvn
;
uint
new_index_start
=
(
uint
)
_compile
->
num_alias_types
();
Arena
*
arena
=
Thread
::
current
()
->
resource_area
();
VectorSet
visited
(
arena
);
...
...
@@ -1012,7 +1016,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
CallNode
*
alloc
=
n
->
as_Call
();
// copy escape information to call node
PointsToNode
*
ptn
=
ptnode_adr
(
alloc
->
_idx
);
PointsToNode
::
EscapeState
es
=
escape_state
(
alloc
,
igvn
);
PointsToNode
::
EscapeState
es
=
escape_state
(
alloc
);
// We have an allocation or call which returns a Java object,
// see if it is unescaped.
if
(
es
!=
PointsToNode
::
NoEscape
||
!
ptn
->
_scalar_replaceable
)
...
...
@@ -1123,7 +1127,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
}
}
else
if
(
n
->
is_AddP
())
{
ptset
.
Clear
();
PointsTo
(
ptset
,
get_addp_base
(
n
)
,
igvn
);
PointsTo
(
ptset
,
get_addp_base
(
n
));
assert
(
ptset
.
Size
()
==
1
,
"AddP address is unique"
);
uint
elem
=
ptset
.
getelem
();
// Allocation node's index
if
(
elem
==
_phantom_object
)
{
...
...
@@ -1143,7 +1147,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
continue
;
// already processed
}
ptset
.
Clear
();
PointsTo
(
ptset
,
n
,
igvn
);
PointsTo
(
ptset
,
n
);
if
(
ptset
.
Size
()
==
1
)
{
uint
elem
=
ptset
.
getelem
();
// Allocation node's index
if
(
elem
==
_phantom_object
)
{
...
...
@@ -1478,6 +1482,26 @@ bool ConnectionGraph::has_candidates(Compile *C) {
return
false
;
}
void
ConnectionGraph
::
do_analysis
(
Compile
*
C
,
PhaseIterGVN
*
igvn
)
{
// Add ConP#NULL and ConN#NULL nodes before ConnectionGraph construction
// to create space for them in ConnectionGraph::_nodes[].
Node
*
oop_null
=
igvn
->
zerocon
(
T_OBJECT
);
Node
*
noop_null
=
igvn
->
zerocon
(
T_NARROWOOP
);
ConnectionGraph
*
congraph
=
new
(
C
->
comp_arena
())
ConnectionGraph
(
C
,
igvn
);
// Perform escape analysis
if
(
congraph
->
compute_escape
())
{
// There are non escaping objects.
C
->
set_congraph
(
congraph
);
}
// Cleanup.
if
(
oop_null
->
outcnt
()
==
0
)
igvn
->
hash_delete
(
oop_null
);
if
(
noop_null
->
outcnt
()
==
0
)
igvn
->
hash_delete
(
noop_null
);
}
bool
ConnectionGraph
::
compute_escape
()
{
Compile
*
C
=
_compile
;
...
...
@@ -1492,7 +1516,7 @@ bool ConnectionGraph::compute_escape() {
}
GrowableArray
<
int
>
cg_worklist
;
PhaseGVN
*
igvn
=
C
->
initial_gvn
()
;
PhaseGVN
*
igvn
=
_igvn
;
bool
has_allocations
=
false
;
// Push all useful nodes onto CG list and set their type.
...
...
@@ -1661,6 +1685,12 @@ bool ConnectionGraph::compute_escape() {
_collecting
=
false
;
assert
(
C
->
unique
()
==
nodes_size
(),
"there should be no new ideal nodes during ConnectionGraph build"
);
#ifndef PRODUCT
if
(
PrintEscapeAnalysis
)
{
dump
();
// Dump ConnectionGraph
}
#endif
bool
has_scalar_replaceable_candidates
=
alloc_worklist
.
length
()
>
0
;
if
(
has_scalar_replaceable_candidates
&&
C
->
AliasLevel
()
>=
3
&&
EliminateAllocations
)
{
...
...
@@ -1671,10 +1701,6 @@ bool ConnectionGraph::compute_escape() {
if
(
C
->
failing
())
return
false
;
// Clean up after split unique types.
ResourceMark
rm
;
PhaseRemoveUseless
pru
(
C
->
initial_gvn
(),
C
->
for_igvn
());
C
->
print_method
(
"After Escape Analysis"
,
2
);
#ifdef ASSERT
...
...
@@ -1711,7 +1737,7 @@ void ConnectionGraph::verify_escape_state(int nidx, VectorSet& ptset, PhaseTrans
int
offset
=
ptn
->
offset
();
Node
*
base
=
get_addp_base
(
n
);
ptset
.
Clear
();
PointsTo
(
ptset
,
base
,
phase
);
PointsTo
(
ptset
,
base
);
int
ptset_size
=
ptset
.
Size
();
// Check if a oop field's initializing value is recorded and add
...
...
@@ -1889,7 +1915,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
arg
=
get_addp_base
(
arg
);
}
ptset
.
Clear
();
PointsTo
(
ptset
,
arg
,
phase
);
PointsTo
(
ptset
,
arg
);
for
(
VectorSetI
j
(
&
ptset
);
j
.
test
();
++
j
)
{
uint
pt
=
j
.
elem
;
set_escape_state
(
pt
,
PointsToNode
::
ArgEscape
);
...
...
@@ -1934,7 +1960,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
}
ptset
.
Clear
();
PointsTo
(
ptset
,
arg
,
phase
);
PointsTo
(
ptset
,
arg
);
for
(
VectorSetI
j
(
&
ptset
);
j
.
test
();
++
j
)
{
uint
pt
=
j
.
elem
;
if
(
global_escapes
)
{
...
...
@@ -1970,7 +1996,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
Node
*
arg
=
call
->
in
(
i
)
->
uncast
();
set_escape_state
(
arg
->
_idx
,
PointsToNode
::
GlobalEscape
);
ptset
.
Clear
();
PointsTo
(
ptset
,
arg
,
phase
);
PointsTo
(
ptset
,
arg
);
for
(
VectorSetI
j
(
&
ptset
);
j
.
test
();
++
j
)
{
uint
pt
=
j
.
elem
;
set_escape_state
(
pt
,
PointsToNode
::
GlobalEscape
);
...
...
@@ -2433,7 +2459,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
Node
*
base
=
get_addp_base
(
n
);
// Create a field edge to this node from everything base could point to.
VectorSet
ptset
(
Thread
::
current
()
->
resource_area
());
PointsTo
(
ptset
,
base
,
phase
);
PointsTo
(
ptset
,
base
);
for
(
VectorSetI
i
(
&
ptset
);
i
.
test
();
++
i
)
{
uint
pt
=
i
.
elem
;
add_field_edge
(
pt
,
n_idx
,
address_offset
(
n
,
phase
));
...
...
@@ -2501,7 +2527,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
// For everything "adr_base" could point to, create a deferred edge from
// this node to each field with the same offset.
VectorSet
ptset
(
Thread
::
current
()
->
resource_area
());
PointsTo
(
ptset
,
adr_base
,
phase
);
PointsTo
(
ptset
,
adr_base
);
int
offset
=
address_offset
(
adr
,
phase
);
for
(
VectorSetI
i
(
&
ptset
);
i
.
test
();
++
i
)
{
uint
pt
=
i
.
elem
;
...
...
@@ -2594,7 +2620,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
// For everything "adr_base" could point to, create a deferred edge
// to "val" from each field with the same offset.
VectorSet
ptset
(
Thread
::
current
()
->
resource_area
());
PointsTo
(
ptset
,
adr_base
,
phase
);
PointsTo
(
ptset
,
adr_base
);
for
(
VectorSetI
i
(
&
ptset
);
i
.
test
();
++
i
)
{
uint
pt
=
i
.
elem
;
add_edge_from_fields
(
pt
,
val
->
_idx
,
address_offset
(
adr
,
phase
));
...
...
@@ -2638,7 +2664,6 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
#ifndef PRODUCT
void
ConnectionGraph
::
dump
()
{
PhaseGVN
*
igvn
=
_compile
->
initial_gvn
();
bool
first
=
true
;
uint
size
=
nodes_size
();
...
...
@@ -2648,7 +2673,7 @@ void ConnectionGraph::dump() {
if
(
ptn_type
!=
PointsToNode
::
JavaObject
||
ptn
->
_node
==
NULL
)
continue
;
PointsToNode
::
EscapeState
es
=
escape_state
(
ptn
->
_node
,
igvn
);
PointsToNode
::
EscapeState
es
=
escape_state
(
ptn
->
_node
);
if
(
ptn
->
_node
->
is_Allocate
()
&&
(
es
==
PointsToNode
::
NoEscape
||
Verbose
))
{
if
(
first
)
{
tty
->
cr
();
...
...
src/share/vm/opto/escape.hpp
浏览文件 @
a5b2c84c
...
...
@@ -227,6 +227,7 @@ private:
uint
_noop_null
;
// ConN(#NULL)
Compile
*
_compile
;
// Compile object for current compilation
PhaseIterGVN
*
_igvn
;
// Value numbering
// Address of an element in _nodes. Used when the element is to be modified
PointsToNode
*
ptnode_adr
(
uint
idx
)
const
{
...
...
@@ -257,7 +258,7 @@ private:
// walk the connection graph starting at the node corresponding to "n" and
// add the index of everything it could point to, to "ptset". This may cause
// Phi's encountered to get (re)processed (which requires "phase".)
void
PointsTo
(
VectorSet
&
ptset
,
Node
*
n
,
PhaseTransform
*
phase
);
void
PointsTo
(
VectorSet
&
ptset
,
Node
*
n
);
// Edge manipulation. The "from_i" and "to_i" arguments are the
// node indices of the source and destination of the edge
...
...
@@ -310,7 +311,7 @@ private:
// Node: This assumes that escape analysis is run before
// PhaseIterGVN creation
void
record_for_optimizer
(
Node
*
n
)
{
_
compile
->
record_for_igvn
(
n
);
_
igvn
->
_worklist
.
push
(
n
);
}
// Set the escape state of a node
...
...
@@ -320,16 +321,20 @@ private:
void
verify_escape_state
(
int
nidx
,
VectorSet
&
ptset
,
PhaseTransform
*
phase
);
public:
ConnectionGraph
(
Compile
*
C
);
ConnectionGraph
(
Compile
*
C
,
PhaseIterGVN
*
igvn
);
// Check for non-escaping candidates
static
bool
has_candidates
(
Compile
*
C
);
// Perform escape analysis
static
void
do_analysis
(
Compile
*
C
,
PhaseIterGVN
*
igvn
);
// Compute the escape information
bool
compute_escape
();
// escape state of a node
PointsToNode
::
EscapeState
escape_state
(
Node
*
n
,
PhaseTransform
*
phase
);
PointsToNode
::
EscapeState
escape_state
(
Node
*
n
);
// other information we have collected
bool
is_scalar_replaceable
(
Node
*
n
)
{
if
(
_collecting
||
(
n
->
_idx
>=
nodes_size
()))
...
...
src/share/vm/prims/jvmtiCodeBlobEvents.cpp
浏览文件 @
a5b2c84c
/*
* Copyright (c) 2003, 20
09
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 20
10
, 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
...
...
@@ -118,34 +118,13 @@ void CodeBlobCollector::do_blob(CodeBlob* cb) {
for
(
int
i
=
0
;
i
<
_global_code_blobs
->
length
();
i
++
)
{
JvmtiCodeBlobDesc
*
scb
=
_global_code_blobs
->
at
(
i
);
if
(
addr
==
scb
->
code_begin
())
{
ShouldNotReachHere
();
return
;
}
}
// we must name the CodeBlob - some CodeBlobs already have names :-
// - stubs used by compiled code to call a (static) C++ runtime routine
// - non-relocatable machine code such as the interpreter, stubroutines, etc.
// - various singleton blobs
//
// others are unnamed so we create a name :-
// - OSR adapter (interpreter frame that has been on-stack replaced)
// - I2C and C2I adapters
const
char
*
name
=
NULL
;
if
(
cb
->
is_runtime_stub
())
{
name
=
((
RuntimeStub
*
)
cb
)
->
name
();
}
if
(
cb
->
is_buffer_blob
())
{
name
=
((
BufferBlob
*
)
cb
)
->
name
();
}
if
(
cb
->
is_deoptimization_stub
()
||
cb
->
is_safepoint_stub
())
{
name
=
((
SingletonBlob
*
)
cb
)
->
name
();
}
if
(
cb
->
is_uncommon_trap_stub
()
||
cb
->
is_exception_stub
())
{
name
=
((
SingletonBlob
*
)
cb
)
->
name
();
}
// record the CodeBlob details as a JvmtiCodeBlobDesc
JvmtiCodeBlobDesc
*
scb
=
new
JvmtiCodeBlobDesc
(
name
,
cb
->
instructions_begin
(),
JvmtiCodeBlobDesc
*
scb
=
new
JvmtiCodeBlobDesc
(
cb
->
name
()
,
cb
->
instructions_begin
(),
cb
->
instructions_end
());
_global_code_blobs
->
append
(
scb
);
}
...
...
@@ -197,7 +176,10 @@ void CodeBlobCollector::collect() {
jvmtiError
JvmtiCodeBlobEvents
::
generate_dynamic_code_events
(
JvmtiEnv
*
env
)
{
CodeBlobCollector
collector
;
// first collect all the code blobs
// First collect all the code blobs. This has to be done in a
// single pass over the code cache with CodeCache_lock held because
// there isn't any safe way to iterate over regular CodeBlobs since
// they can be freed at any point.
{
MutexLockerEx
mu
(
CodeCache_lock
,
Mutex
::
_no_safepoint_check_flag
);
collector
.
collect
();
...
...
@@ -213,166 +195,28 @@ jvmtiError JvmtiCodeBlobEvents::generate_dynamic_code_events(JvmtiEnv* env) {
}
// Support class to describe a nmethod in the CodeCache
class
nmethodDesc
:
public
CHeapObj
{
private:
jmethodID
_jmethod_id
;
address
_code_begin
;
address
_code_end
;
jvmtiAddrLocationMap
*
_map
;
jint
_map_length
;
public:
nmethodDesc
(
jmethodID
jmethod_id
,
address
code_begin
,
address
code_end
,
jvmtiAddrLocationMap
*
map
,
jint
map_length
)
{
_jmethod_id
=
jmethod_id
;
_code_begin
=
code_begin
;
_code_end
=
code_end
;
_map
=
map
;
_map_length
=
map_length
;
}
jmethodID
jmethod_id
()
const
{
return
_jmethod_id
;
}
address
code_begin
()
const
{
return
_code_begin
;
}
address
code_end
()
const
{
return
_code_end
;
}
jvmtiAddrLocationMap
*
map
()
const
{
return
_map
;
}
jint
map_length
()
const
{
return
_map_length
;
}
};
// Support class to collect a list of the nmethod CodeBlobs in
// the CodeCache.
//
// Usage :-
//
// nmethodCollector collector;
//
// collector.collect();
// JvmtiCodeBlobDesc* blob = collector.first();
// while (blob != NULL) {
// :
// blob = collector.next();
// }
//
class
nmethodCollector
:
StackObj
{
private:
GrowableArray
<
nmethodDesc
*>*
_nmethods
;
// collect nmethods
int
_pos
;
// iteration support
// used during a collection
static
GrowableArray
<
nmethodDesc
*>*
_global_nmethods
;
static
void
do_nmethod
(
nmethod
*
nm
);
public:
nmethodCollector
()
{
_nmethods
=
NULL
;
_pos
=
-
1
;
}
~
nmethodCollector
()
{
if
(
_nmethods
!=
NULL
)
{
for
(
int
i
=
0
;
i
<
_nmethods
->
length
();
i
++
)
{
nmethodDesc
*
blob
=
_nmethods
->
at
(
i
);
if
(
blob
->
map
()
!=
NULL
)
{
FREE_C_HEAP_ARRAY
(
jvmtiAddrLocationMap
,
blob
->
map
());
}
}
delete
_nmethods
;
}
}
// collect list of nmethods in the cache
void
collect
();
// iteration support - return first code blob
nmethodDesc
*
first
()
{
assert
(
_nmethods
!=
NULL
,
"not collected"
);
if
(
_nmethods
->
length
()
==
0
)
{
return
NULL
;
}
_pos
=
0
;
return
_nmethods
->
at
(
0
);
}
// iteration support - return next code blob
nmethodDesc
*
next
()
{
assert
(
_pos
>=
0
,
"iteration not started"
);
if
(
_pos
+
1
>=
_nmethods
->
length
())
{
return
NULL
;
}
return
_nmethods
->
at
(
++
_pos
);
}
};
// used during collection
GrowableArray
<
nmethodDesc
*>*
nmethodCollector
::
_global_nmethods
;
// called for each nmethod in the CodeCache
//
// This function simply adds a descriptor for each nmethod to the global list.
void
nmethodCollector
::
do_nmethod
(
nmethod
*
nm
)
{
// ignore zombies
if
(
!
nm
->
is_alive
())
{
return
;
}
assert
(
nm
->
method
()
!=
NULL
,
"checking"
);
// create the location map for the nmethod.
jvmtiAddrLocationMap
*
map
;
jint
map_length
;
JvmtiCodeBlobEvents
::
build_jvmti_addr_location_map
(
nm
,
&
map
,
&
map_length
);
// record the nmethod details
nmethodDesc
*
snm
=
new
nmethodDesc
(
nm
->
get_and_cache_jmethod_id
(),
nm
->
code_begin
(),
nm
->
code_end
(),
map
,
map_length
);
_global_nmethods
->
append
(
snm
);
}
// collects a list of nmethod in the CodeCache.
//
// The created list is growable array of nmethodDesc - each one describes
// a nmethod and includs its JVMTI address location map.
void
nmethodCollector
::
collect
()
{
assert_locked_or_safepoint
(
CodeCache_lock
);
assert
(
_global_nmethods
==
NULL
,
"checking"
);
// create the list
_global_nmethods
=
new
(
ResourceObj
::
C_HEAP
)
GrowableArray
<
nmethodDesc
*>
(
100
,
true
);
// any a descriptor for each nmethod to the list.
CodeCache
::
nmethods_do
(
do_nmethod
);
// make the list the instance list
_nmethods
=
_global_nmethods
;
_global_nmethods
=
NULL
;
}
// Generate a COMPILED_METHOD_LOAD event for each nnmethod
jvmtiError
JvmtiCodeBlobEvents
::
generate_compiled_method_load_events
(
JvmtiEnv
*
env
)
{
HandleMark
hm
;
nmethodCollector
collector
;
// first collect all nmethods
{
MutexLockerEx
mu
(
CodeCache_lock
,
Mutex
::
_no_safepoint_check_flag
);
collector
.
collect
();
}
// iterate over the list and post an event for each nmethod
nmethodDesc
*
nm_desc
=
collector
.
first
();
while
(
nm_desc
!=
NULL
)
{
jmethodID
mid
=
nm_desc
->
jmethod_id
();
assert
(
mid
!=
NULL
,
"checking"
);
JvmtiExport
::
post_compiled_method_load
(
env
,
mid
,
(
jint
)(
nm_desc
->
code_end
()
-
nm_desc
->
code_begin
()),
nm_desc
->
code_begin
(),
nm_desc
->
map_length
(),
nm_desc
->
map
());
nm_desc
=
collector
.
next
();
// Walk the CodeCache notifying for live nmethods. The code cache
// may be changing while this is happening which is ok since newly
// created nmethod will notify normally and nmethods which are freed
// can be safely skipped.
MutexLockerEx
mu
(
CodeCache_lock
,
Mutex
::
_no_safepoint_check_flag
);
nmethod
*
current
=
CodeCache
::
first_nmethod
();
while
(
current
!=
NULL
)
{
// Lock the nmethod so it can't be freed
nmethodLocker
nml
(
current
);
// Only notify for live nmethods
if
(
current
->
is_alive
())
{
// Don't hold the lock over the notify or jmethodID creation
MutexUnlockerEx
mu
(
CodeCache_lock
,
Mutex
::
_no_safepoint_check_flag
);
current
->
get_and_cache_jmethod_id
();
JvmtiExport
::
post_compiled_method_load
(
current
);
}
current
=
CodeCache
::
next_nmethod
(
current
);
}
return
JVMTI_ERROR_NONE
;
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录