Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8261731: shallow copy the internal buffer of a scalar-replaced java.lang.String object #2570

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
8e69016
add a new bucket afterea_late_inlines
Dec 24, 2020
c4112da
Allows EA to calculate escapeness information for String.substring
Dec 26, 2020
80496b0
identify the pattern of temporary String in ArrayCopy.
Jan 13, 2021
784619f
tmp
Jan 20, 2021
a49e346
8260198: TypeInstPtr::dump2() emits multiple lines if Verbose is set
Jan 21, 2021
10226bf
SIM-JVM-449: debug sun.nio.fs.UnixFileSystemProvider::isHidden
Jan 23, 2021
67f4ad1
disable OptimizeSubstring by defualt
Jan 23, 2021
7ac5315
fix random crash because of is_Mem() assertion
Jan 25, 2021
caee971
broken
Jan 25, 2021
9dfea7a
add a flag to control this optimization.
Jan 25, 2021
adcfc7d
delete ArrayCopy in its own ideal(). It happens earlier than eliminat…
Jan 26, 2021
7af8cfc
add all ArrayCopy nodes to the worklist in EA.
Jan 29, 2021
dea551f
add an unittest and a micro benchmark
Jan 30, 2021
6d224d1
accept src of ArrayCopy is ConP.
Jan 30, 2021
fd22818
Accept more code shapes
Jan 31, 2021
4fe3e3b
handle uses of AllocateArrayNode
Feb 3, 2021
2496dff
move the logic from ArrayCopyNode::ideal to PhaseMacroExpansion
Feb 3, 2021
f07ab45
can_eliminate_allocation is true for the obsolete AllocateArray
Feb 4, 2021
17bae1c
[SIM-JVM-479] handle G1's post-write barrier when eliminating both Al…
Feb 4, 2021
e53d540
[SIM-JVM-450]: handle deoptimization non-escaped frozen array
Feb 4, 2021
9a39f5b
keep LoadB and LoadUB. update their inputs
Feb 4, 2021
366eb93
support Op_StrEquals as an use of AllocateArray
Feb 6, 2021
b90b7e9
[SIM-JVM-482] handle code shape of cascading arraycopy
Feb 7, 2021
0db7952
handle the second AddP of user of AllocateArray
Feb 8, 2021
49fd46b
[SIM-487] Check all store and phi nodes of encodeP
Feb 9, 2021
7ccdb57
[SIM-JVM-450] support deoptimization
Feb 10, 2021
5644424
Revert "add a new bucket afterea_late_inlines"
Feb 11, 2021
91abf69
Revert "8260198: TypeInstPtr::dump2() emits multiple lines if Verbose…
Feb 11, 2021
7ae0c28
Merge branch 'master' into optimize_substring
Feb 11, 2021
d75f0ae
enable OptimizeTempArray by default
Feb 11, 2021
b5d1bb3
[SIM-JVM-450] support deoptimization part2
Feb 12, 2021
4541a5c
add a unit test for deoptimization
Feb 12, 2021
ab6c912
[SIM-JVM-450] support deoptimization v2
Feb 13, 2021
804a3e3
add a statistical counter for OptimizeTempArray.
Feb 14, 2021
fd9ca4b
fix regression for x86-32
Feb 15, 2021
21693dd
Merge branch 'master' into optimize_substring
Feb 15, 2021
359cdc9
Merge branch 'master' into optimize_substring
Feb 16, 2021
9bf0b26
Merge branch 'master' into optimize_substring
Feb 22, 2021
9218d43
[SIM-JVM-509] Check the source of ArrayCopy is from java.lang.String:…
Mar 2, 2021
ea660ee
[SIM-JVM-522] improve second AddP nodes and ArrayCopy node.
Mar 3, 2021
672bf3c
fix a typo introduced in prior change.
Mar 3, 2021
6bd99e8
[SIM-JVM-526] fix a crash in scalar replacement
Mar 6, 2021
94626e8
Handle more StrIntrinsic nodes which use AllocateArray of String.
Mar 13, 2021
fcccdee
eliminate AllocateArray node early.
Mar 18, 2021
800ddc9
Merge branch 'master' into optimize_substring
Mar 18, 2021
File filter
Filter file types
Jump to
Jump to file
Failed to load files.

Always

Just for now

@@ -692,6 +692,10 @@ void G1BarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) c
assert(cmpx->is_Cmp() && cmpx->unique_out()->is_Bool() &&
cmpx->unique_out()->as_Bool()->_test._test == BoolTest::ne,
"missing region check in G1 post barrier");
Node* sibling = xorx->in(1);
if (sibling == node) {
sibling = xorx->in(2);
}
macro->replace_node(cmpx, macro->makecon(TypeInt::CC_EQ));

// Remove G1 pre barrier.
@@ -722,6 +726,12 @@ void G1BarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) c
}
}
}

// handle XorL's the other input
// it may invoke eliminate_gc_barrier() if it's a CastP2X too
if (sibling->Opcode() == Op_CastP2X) {
macro->replace_node(sibling, macro->top());
}
} else {
assert(!use_ReduceInitialCardMarks(), "can only happen with card marking");
// This is a G1 post barrier emitted by the Object.clone() intrinsic.
@@ -1264,7 +1264,7 @@ C2V_VMENTRY_NULL(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, job
}
}
bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), fst.register_map(), objects, CHECK_NULL);
Deoptimization::reassign_fields(fst.current(), fst.register_map(), objects, realloc_failures, false);
Deoptimization::reassign_fields(fst.current(), fst.register_map(), objects, realloc_failures, false, CHECK_NULL);
realloc_called = true;

GrowableArray<ScopeValue*>* local_values = scope->locals();
@@ -1524,7 +1524,7 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv* env, jobject, jobject _hs_
}

bool realloc_failures = Deoptimization::realloc_objects(thread, fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, CHECK);
Deoptimization::reassign_fields(fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, realloc_failures, false);
Deoptimization::reassign_fields(fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, realloc_failures, false, CHECK);

for (int frame_index = 0; frame_index < virtualFrames->length(); frame_index++) {
compiledVFrame* cvf = virtualFrames->at(frame_index);
@@ -23,11 +23,14 @@
*/

#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/c2/barrierSetC2.hpp"
#include "gc/shared/c2/cardTableBarrierSetC2.hpp"
#include "gc/shared/gc_globals.hpp"
#include "opto/arraycopynode.hpp"
#include "opto/castnode.hpp"
#include "opto/convertnode.hpp"
#include "opto/graphKit.hpp"
#include "runtime/sharedRuntime.hpp"
#include "utilities/macros.hpp"
@@ -499,7 +502,56 @@ bool ArrayCopyNode::finish_transform(PhaseGVN *phase, bool can_reshape,
}
return true;
}
// return true if the current ArrayCopy copy from byte[] to byte[] and the source is j.l.String::value.
bool ArrayCopyNode::is_string_copy(PhaseGVN* phase) const {
if (_kind == ArrayCopy && _alloc_tightly_coupled && _arguments_validated) {
const TypeAryPtr* src_type = nullptr;
const TypeAryPtr* dst_type = nullptr;
const Node* n;

n = in(ArrayCopyNode::Src);
if (n->Opcode() == Op_ConP) {
src_type = n->as_Type()->type()->isa_aryptr();
} else if (n->isa_ConstraintCast()) {
// if n is CastPP or CheckCastPP, check the instance field of load node.
// j.l.String::value must be loaded using getfield.
//
// Expecting DU-chains:
// -UseCompressedOops: CastPP -> LoadP -> AddP
// +UseCompressedOops: CastPP -> DecodeN -> LoadN -> AddP
// ^p
Node* p = n->in(1);

if (p->is_DecodeN()) {
p = p->in(1);
}

if (p->is_Load()) { // LoadN or LoadP
p = p->in(2); // adr
const TypePtr* tp = phase->type(p)->isa_ptr();

assert(tp != nullptr, "TypePtr* tp is NULL!");
const TypeOopPtr* tinst = tp->isa_instptr();
if (tinst != nullptr && tinst->klass() == CURRENT_ENV->String_klass() &&
tinst->offset() == java_lang_String::value_offset()) {
src_type = n->as_Type()->type()->isa_aryptr();
}
}
}

n = in(ArrayCopyNode::Dest);
if (n->is_ConstraintCast()) {
dst_type = n->as_ConstraintCast()->type()->isa_aryptr();
}

if (src_type != nullptr && src_type->elem() == TypeInt::BYTE &&
dst_type != nullptr && dst_type->elem() == TypeInt::BYTE) {
return true;
}
}

return false;
}

Node *ArrayCopyNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (remove_dead_region(phase, can_reshape)) return this;
@@ -161,6 +161,7 @@ class ArrayCopyNode : public CallNode {
bool is_copyofrange() const { assert(_kind != None, "should bet set"); return _kind == CopyOfRange; }
bool is_copyofrange_validated() const { assert(_kind != None, "should bet set"); return _kind == CopyOfRange && _arguments_validated; }

bool is_string_copy(PhaseGVN* phase) const;
void set_arraycopy(bool validated) { assert(_kind == None, "shouldn't bet set yet"); _kind = ArrayCopy; _arguments_validated = validated; }
void set_clone_inst() { assert(_kind == None, "shouldn't bet set yet"); _kind = CloneInst; }
void set_clone_array() { assert(_kind == None, "shouldn't bet set yet"); _kind = CloneArray; }
@@ -559,6 +559,9 @@
product(bool, OptimizeStringConcat, true, \
"Optimize the construction of Strings by StringBuilder") \
\
product(bool, OptimizeTempArray, true, \
"Optimize temporary Array if it's not escaped") \
\
notproduct(bool, PrintOptimizeStringConcat, false, \
"Print information about transformations performed on Strings") \
\
@@ -989,13 +989,16 @@ class AllocateNode : public CallNode {
// High-level array allocation
//
class AllocateArrayNode : public AllocateNode {
// this is java.lang.String::byte[] value and it's has been obsolete
// MacroExpansion eliminate this node in expand_macro_nodes()
bool _str_alloc_obsolete;
public:
AllocateArrayNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio,
Node* size, Node* klass_node, Node* initial_test,
Node* count_val
)
: AllocateNode(C, atype, ctrl, mem, abio, size, klass_node,
initial_test)
initial_test), _str_alloc_obsolete(false)
{
init_class_id(Class_AllocateArray);
set_req(AllocateNode::ALength, count_val);
@@ -1011,7 +1014,8 @@ class AllocateArrayNode : public AllocateNode {
// Dig the length operand out of a array allocation site and narrow the
// type with a CastII, if necesssary
Node* make_ideal_length(const TypeOopPtr* ary_type, PhaseTransform *phase, bool can_create = true);

bool is_str_alloc_obsolete() const { return _str_alloc_obsolete; }
void set_str_alloc_obsolete(bool obsolete) { _str_alloc_obsolete = obsolete; }
// Pattern-match a possible usage of AllocateArrayNode.
// Return null if no allocation is recognized.
static AllocateArrayNode* Ideal_array_allocation(Node* ptr, PhaseTransform* phase) {
@@ -255,6 +255,7 @@ void Compile::print_statistics() {
PhaseOutput::print_statistics();
PhasePeephole::print_statistics();
PhaseIdealLoop::print_statistics();
PhaseMacroExpand::print_statistics();
if (xtty != NULL) xtty->tail("statistics");
}
if (_intrinsic_hist_flags[as_int(vmIntrinsics::_none)] != 0) {
@@ -662,6 +662,7 @@ class Compile : public Phase {
int expensive_count() const { return _expensive_nodes.length(); }

Node* macro_node(int idx) const { return _macro_nodes.at(idx); }
void macro_node_swap(int a, int b) { ::swap(_macro_nodes.at(a), _macro_nodes.at(b)); }
Node* predicate_opaque1_node(int idx) const { return _predicate_opaqs.at(idx); }
Node* skeleton_predicate_opaque4_node(int idx) const { return _skeleton_predicate_opaqs.at(idx); }
Node* expensive_node(int idx) const { return _expensive_nodes.at(idx); }
@@ -319,6 +319,7 @@ class BaseIterator: public PointsToIterator {

class ConnectionGraph: public ResourceObj {
friend class PointsToNode;
friend class PhaseMacroExpand;
private:
GrowableArray<PointsToNode*> _nodes; // Map from ideal nodes to
// ConnectionGraph nodes.
@@ -348,6 +349,8 @@ class ConnectionGraph: public ResourceObj {
private:
// Address of an element in _nodes. Used when the element is to be modified
PointsToNode* ptnode_adr(int idx) const {
if (idx >= _nodes.length()) return nullptr;

// There should be no new ideal nodes during ConnectionGraph build,
// growableArray::at() will throw assert otherwise.
return _nodes.at(idx);
ProTip! Use n and p to navigate between commits in a pull request.