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