src/share/vm/opto/stringopts.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
hotspot-comp Cdiff src/share/vm/opto/stringopts.cpp
src/share/vm/opto/stringopts.cpp
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2009, 2012, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
--- 1,7 ----
/*
! * Copyright (c) 2009, 2013, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*** 48,61 ****
// separate StringBuilders
Node* _arguments; // The list of arguments to be concatenated
GrowableArray<int> _mode; // into a String along with a mode flag
// indicating how to treat the value.
!
Node_List _control; // List of control nodes that will be deleted
Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten
// to restart at the initial JVMState.
public:
// Mode for converting arguments to Strings
enum {
StringMode,
IntMode,
--- 48,62 ----
// separate StringBuilders
Node* _arguments; // The list of arguments to be concatenated
GrowableArray<int> _mode; // into a String along with a mode flag
// indicating how to treat the value.
! Node_List _constructors; // List of constructors (many in case of stacked concat)
Node_List _control; // List of control nodes that will be deleted
Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten
// to restart at the initial JVMState.
+
public:
// Mode for converting arguments to Strings
enum {
StringMode,
IntMode,
*** 71,80 ****
--- 72,82 ----
_stringopts(stringopts) {
_arguments = new (_stringopts->C) Node(1);
_arguments->del_req(0);
}
+ bool validate_mem_flow();
bool validate_control_flow();
void merge_add() {
#if 0
// XXX This is place holder code for reusing an existing String
*** 187,196 ****
--- 189,202 ----
}
void add_control(Node* ctrl) {
assert(!_control.contains(ctrl), "only push once");
_control.push(ctrl);
}
+ void add_constructor(Node* init) {
+ assert(!_constructors.contains(init), "only push once");
+ _constructors.push(init);
+ }
CallStaticJavaNode* end() { return _end; }
AllocateNode* begin() { return _begin; }
Node* string_alloc() { return _string_alloc; }
void eliminate_unneeded_control();
*** 299,308 ****
--- 305,320 ----
} else {
result->append(argx, mode(x));
}
}
result->set_allocation(other->_begin);
+ for (uint i = 0; i < _constructors.size(); i++) {
+ result->add_constructor(_constructors.at(i));
+ }
+ for (uint i = 0; i < other->_constructors.size(); i++) {
+ result->add_constructor(other->_constructors.at(i));
+ }
result->_multiple = true;
return result;
}
*** 508,518 ****
// if this call converted into a direct string concatenation.
sc->add_control(call);
sc->add_control(constructor);
sc->add_control(alloc);
sc->set_allocation(alloc);
! if (sc->validate_control_flow()) {
return sc;
} else {
return NULL;
}
} else if (cnode->method() == NULL) {
--- 520,531 ----
// if this call converted into a direct string concatenation.
sc->add_control(call);
sc->add_control(constructor);
sc->add_control(alloc);
sc->set_allocation(alloc);
! sc->add_constructor(constructor);
! if (sc->validate_control_flow() && sc->validate_mem_flow()) {
return sc;
} else {
return NULL;
}
} else if (cnode->method() == NULL) {
*** 618,628 ****
tty->print_cr("considering stacked concats");
}
#endif
StringConcat* merged = sc->merge(other, arg);
! if (merged->validate_control_flow()) {
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
tty->print_cr("stacking would succeed");
}
#endif
--- 631,641 ----
tty->print_cr("considering stacked concats");
}
#endif
StringConcat* merged = sc->merge(other, arg);
! if (merged->validate_control_flow() && merged->validate_mem_flow()) {
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
tty->print_cr("stacking would succeed");
}
#endif
*** 706,715 ****
--- 719,805 ----
}
}
}
+ bool StringConcat::validate_mem_flow() {
+ Compile* C = _stringopts->C;
+
+ for (uint i = 0; i < _control.size(); i++) {
+ #ifndef PRODUCT
+ Node_List path;
+ #endif
+ Node* curr = _control.at(i);
+ if (curr->is_Call() && curr != _begin) { // For all calls except the first allocation
+ // Now here's the main invariant in our case:
+ // For memory between the constructor, and appends, and toString we should only see bottom memory,
+ // produced by the previous call we know about.
+ if (!_constructors.contains(curr)) {
+ NOT_PRODUCT(path.push(curr);)
+ Node* mem = curr->in(TypeFunc::Memory);
+ assert(mem != NULL, "calls should have memory edge");
+ assert(!mem->is_Phi(), "should be handled by control flow validation");
+ NOT_PRODUCT(path.push(mem);)
+ if (mem->is_MergeMem()) {
+ while (mem->is_MergeMem()) {
+ for (uint i = 1; i < mem->req(); i++) {
+ if (i != Compile::AliasIdxBot && mem->in(i) != C->top()) {
+ #ifndef PRODUCT
+ tty->print("fusion has incorrect memory flow (side effects) for ");
+ _begin->jvms()->dump_spec(tty); tty->cr();
+ path.dump();
+ #endif
+ return false;
+ }
+ }
+ // skip through a potential MergeMem chain, linked through Bot
+ mem = mem->in(Compile::AliasIdxBot);
+ NOT_PRODUCT(path.push(mem);)
+ }
+ // now let it fall though, and see if the have a projection
+ }
+ if (mem->is_Proj()) {
+ // Should point to a previous known call
+ Node *prev = mem->in(0);
+ NOT_PRODUCT(path.push(prev);)
+ if (!prev->is_Call() || !_control.contains(prev)) {
+ #ifndef PRODUCT
+ tty->print("fusion has incorrect memory flow (unknown call) for ");
+ _begin->jvms()->dump_spec(tty); tty->cr();
+ path.dump();
+ #endif
+ return false;
+ }
+ } else {
+ assert(mem->is_Store() || mem->is_LoadStore(), err_msg_res("Unexpected node type: %s", mem->Name()));
+ #ifndef PRODUCT
+ tty->print("fusion has incorrect memory flow (unexpected source) for ");
+ _begin->jvms()->dump_spec(tty); tty->cr();
+ path.dump();
+ #endif
+ return false;
+ }
+ } else {
+ // For memory that feeds into constructors it's more complicated.
+ // However the advantage is that any side effect that happens between the Allocate/Initialize and
+ // the constructor will have to be control-dependent on Initialize.
+ // So we actually don't have to do anything, since it's going to be caught by the control flow
+ // analysis.
+ }
+ }
+ }
+
+ #ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ tty->print("fusion has correct memory flow for ");
+ _begin->jvms()->dump_spec(tty); tty->cr();
+ tty->cr();
+ }
+ #endif
+ return true;
+ }
+
bool StringConcat::validate_control_flow() {
// We found all the calls and arguments now lets see if it's
// safe to transform the graph as we would expect.
// Check to see if this resulted in too many uncommon traps previously
*** 751,761 ****
} else {
ShouldNotReachHere();
}
}
! // Skip backwards through the control checking for unexpected contro flow
Node* ptr = _end;
bool fail = false;
while (ptr != _begin) {
if (ptr->is_Call() && ctrl_path.member(ptr)) {
ptr = ptr->in(0);
--- 841,851 ----
} else {
ShouldNotReachHere();
}
}
! // Skip backwards through the control checking for unexpected control flow
Node* ptr = _end;
bool fail = false;
while (ptr != _begin) {
if (ptr->is_Call() && ctrl_path.member(ptr)) {
ptr = ptr->in(0);
*** 934,944 ****
#ifndef PRODUCT
if (PrintOptimizeStringConcat && !fail) {
ttyLocker ttyl;
tty->cr();
! tty->print("fusion would succeed (%d %d) for ", null_check_count, _uncommon_traps.size());
_begin->jvms()->dump_spec(tty); tty->cr();
for (int i = 0; i < num_arguments(); i++) {
argument(i)->dump();
}
_control.dump();
--- 1024,1034 ----
#ifndef PRODUCT
if (PrintOptimizeStringConcat && !fail) {
ttyLocker ttyl;
tty->cr();
! tty->print("fusion has correct control flow (%d %d) for ", null_check_count, _uncommon_traps.size());
_begin->jvms()->dump_spec(tty); tty->cr();
for (int i = 0; i < num_arguments(); i++) {
argument(i)->dump();
}
_control.dump();
src/share/vm/opto/stringopts.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File