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.
*** 40,49 **** --- 40,50 ---- class StringConcat : public ResourceObj { private: PhaseStringOpts* _stringopts; Node* _string_alloc; AllocateNode* _begin; // The allocation the begins the pattern + Node* _constructor; // Constructor of StringBuffer CallStaticJavaNode* _end; // The final call of the pattern. Will either be // SB.toString or or String.<init>(SB.toString) bool _multiple; // indicates this is a fusion of two or more // separate StringBuilders
*** 52,61 **** --- 53,63 ---- // 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,
*** 71,80 **** --- 73,83 ---- _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
*** 101,111 **** StringConcat* merge(StringConcat* other, Node* arg); void set_allocation(AllocateNode* alloc) { _begin = alloc; } ! void append(Node* value, int mode) { _arguments->add_req(value); _mode.append(mode); } void push(Node* value, int mode) { --- 104,116 ---- StringConcat* merge(StringConcat* other, Node* arg); void set_allocation(AllocateNode* alloc) { _begin = alloc; } ! void set_constructor(Node* init) { ! _constructor = init; ! } void append(Node* value, int mode) { _arguments->add_req(value); _mode.append(mode); } void push(Node* value, int mode) {
*** 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) { --- 513,524 ---- // 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->set_constructor(constructor); ! if (sc->validate_control_flow() && sc->validate_mem_flow()) { return sc; } else { return NULL; } } else if (cnode->method() == NULL) {
*** 569,579 **** PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*): Phase(StringOpts), _gvn(gvn), ! _visited(Thread::current()->resource_area()) { assert(OptimizeStringConcat, "shouldn't be here"); size_table_field = C->env()->Integer_klass()->get_field_by_name(ciSymbol::make("sizeTable"), ciSymbol::make("[I"), true); --- 575,586 ---- PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*): Phase(StringOpts), _gvn(gvn), ! _visited(Thread::current()->resource_area()), ! _path(memory_flow_iteration_limit) { assert(OptimizeStringConcat, "shouldn't be here"); size_table_field = C->env()->Integer_klass()->get_field_by_name(ciSymbol::make("sizeTable"), ciSymbol::make("[I"), true);
*** 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 --- 625,635 ---- 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
*** 705,714 **** --- 712,850 ---- break; } } } + // Find all simple paths from start_mem to any node in end_set, check if any of the paths + // has side effects. + bool StringConcat::validate_mem_flow() { + Node* start_mem = _end; + Node* end_mem = _constructor; + assert(start_mem->is_Call() && end_mem->is_Call(), "precondition"); + assert(_control.contains(start_mem) && _control.contains(end_mem), "precondition"); + + Node_Stack& path = _stringopts->_path; + path.clear(); + + // Interested in simple paths, so we'll track the nodes visited + VectorSet& visited = _stringopts->_visited; + visited.Clear(); + + Compile* C = _stringopts->C; + path.push(start_mem, 0); + visited.set(start_mem->_idx); + visited.set(C->top()->_idx); + + int nodes_processed = 0; + // Do DFS up the memory graph, storing the result in path, + // use next_edge to track the last edge taken for the node. + while (path.is_nonempty()) { + if (nodes_processed++ > PhaseStringOpts::memory_flow_iteration_limit) { + // We're spending too much time here, going to be pessimistic + // and say we have found a side effect + #ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("Giving up on memory flow analysis due to iteration cutoff"); + } + #endif + return false; + } + + Node* curr = path.node(); + uint edge_idx = path.index(); + bool is_not_visited = (edge_idx == 0); + Node* next = NULL; + + if (curr->is_Proj()) { + assert(curr->as_Proj()->_con == TypeFunc::Memory, "must be a memory projection"); + if (is_not_visited) { + next = curr->in(0); + } + } else if (curr->is_Mem()) { + if (curr->is_Store() || curr->is_LoadStore()) { + #ifndef PRODUCT + if (PrintOptimizeStringConcat) { + ttyLocker ttyl; + tty->print("fusion has incorrect memory flow (side effects) for "); + _begin->jvms()->dump_spec(tty); tty->cr(); + for (uint i = 0; i < path.size(); i++) { + path.node_at(i)->dump(); + } + tty->cr(); + } + #endif // !PRODUCT + return false; + } + if (is_not_visited) { + next = curr->in(MemNode::Memory); + assert(next != NULL, "should have memory edge"); + } + } else if (curr->is_Call()) { + if (is_not_visited) { + next = curr->in(TypeFunc::Memory); + assert(next != NULL, "should have memory edge"); + } + if (curr == end_mem) { + // Terminate this search branch + next = NULL; + } + } else if (curr->is_MergeMem()) { + while (edge_idx + 1 < curr->req() && next == NULL) { + next = curr->in(edge_idx + 1); + bool dup = false; + if (next != NULL) { + // skip duplicate edges + for (uint i = 1; i < edge_idx + 1; i++) { + if (next == curr->in(i)) { + edge_idx++; + next = NULL; + break; + } + } + } else { + edge_idx++; + } + } + } else if (curr->is_MemBar()) { + if (edge_idx < 1) { + next = curr->in(TypeFunc::Memory); + assert(next != NULL, "should have memory edge"); + } else if (curr->is_Initialize() && edge_idx < 2) { + next = curr->as_Initialize()->allocation(); + } + } else { + assert(false, err_msg_res("Unexpected node type: %s", curr->Name())); + return false; + } + edge_idx++; + + if (next == NULL) { + // Can't go any further, need to pop off the node + visited.remove(curr->_idx); + path.pop(); + } else { + // Update the last visited edge number + path.set_index(edge_idx); + // Check if the next node was already visited + if (!visited.test_set(next->_idx)) { + // If not add it to the path + path.push(next, 0); + } + } + } + + #ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("fusion has correct memory flow for "); + _begin->jvms()->dump_spec(tty); tty->cr(); + tty->cr(); + } + #endif + + // No interesing paths + 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.
*** 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(); --- 1070,1080 ---- #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