src/share/vm/opto/stringopts.cpp

changeset 5928
90abdd727e64
parent 4409
d092d1b31229
child 6479
2113136690bc
     1.1 --- a/src/share/vm/opto/stringopts.cpp	Fri Oct 11 12:06:14 2013 +0200
     1.2 +++ b/src/share/vm/opto/stringopts.cpp	Wed Oct 16 11:13:15 2013 -0700
     1.3 @@ -1,5 +1,5 @@
     1.4  /*
     1.5 - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
     1.6 + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
     1.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.8   *
     1.9   * This code is free software; you can redistribute it and/or modify it
    1.10 @@ -50,10 +50,11 @@
    1.11    Node*               _arguments;      // The list of arguments to be concatenated
    1.12    GrowableArray<int>  _mode;           // into a String along with a mode flag
    1.13                                         // indicating how to treat the value.
    1.14 -
    1.15 +  Node_List           _constructors;   // List of constructors (many in case of stacked concat)
    1.16    Node_List           _control;        // List of control nodes that will be deleted
    1.17    Node_List           _uncommon_traps; // Uncommon traps that needs to be rewritten
    1.18                                         // to restart at the initial JVMState.
    1.19 +
    1.20   public:
    1.21    // Mode for converting arguments to Strings
    1.22    enum {
    1.23 @@ -73,6 +74,7 @@
    1.24      _arguments->del_req(0);
    1.25    }
    1.26  
    1.27 +  bool validate_mem_flow();
    1.28    bool validate_control_flow();
    1.29  
    1.30    void merge_add() {
    1.31 @@ -189,6 +191,10 @@
    1.32      assert(!_control.contains(ctrl), "only push once");
    1.33      _control.push(ctrl);
    1.34    }
    1.35 +  void add_constructor(Node* init) {
    1.36 +    assert(!_constructors.contains(init), "only push once");
    1.37 +    _constructors.push(init);
    1.38 +  }
    1.39    CallStaticJavaNode* end() { return _end; }
    1.40    AllocateNode* begin() { return _begin; }
    1.41    Node* string_alloc() { return _string_alloc; }
    1.42 @@ -301,6 +307,12 @@
    1.43      }
    1.44    }
    1.45    result->set_allocation(other->_begin);
    1.46 +  for (uint i = 0; i < _constructors.size(); i++) {
    1.47 +    result->add_constructor(_constructors.at(i));
    1.48 +  }
    1.49 +  for (uint i = 0; i < other->_constructors.size(); i++) {
    1.50 +    result->add_constructor(other->_constructors.at(i));
    1.51 +  }
    1.52    result->_multiple = true;
    1.53    return result;
    1.54  }
    1.55 @@ -510,7 +522,8 @@
    1.56        sc->add_control(constructor);
    1.57        sc->add_control(alloc);
    1.58        sc->set_allocation(alloc);
    1.59 -      if (sc->validate_control_flow()) {
    1.60 +      sc->add_constructor(constructor);
    1.61 +      if (sc->validate_control_flow() && sc->validate_mem_flow()) {
    1.62          return sc;
    1.63        } else {
    1.64          return NULL;
    1.65 @@ -620,7 +633,7 @@
    1.66  #endif
    1.67  
    1.68              StringConcat* merged = sc->merge(other, arg);
    1.69 -            if (merged->validate_control_flow()) {
    1.70 +            if (merged->validate_control_flow() && merged->validate_mem_flow()) {
    1.71  #ifndef PRODUCT
    1.72                if (PrintOptimizeStringConcat) {
    1.73                  tty->print_cr("stacking would succeed");
    1.74 @@ -708,6 +721,139 @@
    1.75  }
    1.76  
    1.77  
    1.78 +bool StringConcat::validate_mem_flow() {
    1.79 +  Compile* C = _stringopts->C;
    1.80 +
    1.81 +  for (uint i = 0; i < _control.size(); i++) {
    1.82 +#ifndef PRODUCT
    1.83 +    Node_List path;
    1.84 +#endif
    1.85 +    Node* curr = _control.at(i);
    1.86 +    if (curr->is_Call() && curr != _begin) { // For all calls except the first allocation
    1.87 +      // Now here's the main invariant in our case:
    1.88 +      // For memory between the constructor, and appends, and toString we should only see bottom memory,
    1.89 +      // produced by the previous call we know about.
    1.90 +      if (!_constructors.contains(curr)) {
    1.91 +        NOT_PRODUCT(path.push(curr);)
    1.92 +        Node* mem = curr->in(TypeFunc::Memory);
    1.93 +        assert(mem != NULL, "calls should have memory edge");
    1.94 +        assert(!mem->is_Phi(), "should be handled by control flow validation");
    1.95 +        NOT_PRODUCT(path.push(mem);)
    1.96 +        while (mem->is_MergeMem()) {
    1.97 +          for (uint i = 1; i < mem->req(); i++) {
    1.98 +            if (i != Compile::AliasIdxBot && mem->in(i) != C->top()) {
    1.99 +#ifndef PRODUCT
   1.100 +              if (PrintOptimizeStringConcat) {
   1.101 +                tty->print("fusion has incorrect memory flow (side effects) for ");
   1.102 +                _begin->jvms()->dump_spec(tty); tty->cr();
   1.103 +                path.dump();
   1.104 +              }
   1.105 +#endif
   1.106 +              return false;
   1.107 +            }
   1.108 +          }
   1.109 +          // skip through a potential MergeMem chain, linked through Bot
   1.110 +          mem = mem->in(Compile::AliasIdxBot);
   1.111 +          NOT_PRODUCT(path.push(mem);)
   1.112 +        }
   1.113 +        // now let it fall through, and see if we have a projection
   1.114 +        if (mem->is_Proj()) {
   1.115 +          // Should point to a previous known call
   1.116 +          Node *prev = mem->in(0);
   1.117 +          NOT_PRODUCT(path.push(prev);)
   1.118 +          if (!prev->is_Call() || !_control.contains(prev)) {
   1.119 +#ifndef PRODUCT
   1.120 +            if (PrintOptimizeStringConcat) {
   1.121 +              tty->print("fusion has incorrect memory flow (unknown call) for ");
   1.122 +              _begin->jvms()->dump_spec(tty); tty->cr();
   1.123 +              path.dump();
   1.124 +            }
   1.125 +#endif
   1.126 +            return false;
   1.127 +          }
   1.128 +        } else {
   1.129 +          assert(mem->is_Store() || mem->is_LoadStore(), err_msg_res("unexpected node type: %s", mem->Name()));
   1.130 +#ifndef PRODUCT
   1.131 +          if (PrintOptimizeStringConcat) {
   1.132 +            tty->print("fusion has incorrect memory flow (unexpected source) for ");
   1.133 +            _begin->jvms()->dump_spec(tty); tty->cr();
   1.134 +            path.dump();
   1.135 +          }
   1.136 +#endif
   1.137 +          return false;
   1.138 +        }
   1.139 +      } else {
   1.140 +        // For memory that feeds into constructors it's more complicated.
   1.141 +        // However the advantage is that any side effect that happens between the Allocate/Initialize and
   1.142 +        // the constructor will have to be control-dependent on Initialize.
   1.143 +        // So we actually don't have to do anything, since it's going to be caught by the control flow
   1.144 +        // analysis.
   1.145 +#ifdef ASSERT
   1.146 +        // Do a quick verification of the control pattern between the constructor and the initialize node
   1.147 +        assert(curr->is_Call(), "constructor should be a call");
   1.148 +        // Go up the control starting from the constructor call
   1.149 +        Node* ctrl = curr->in(0);
   1.150 +        IfNode* iff = NULL;
   1.151 +        RegionNode* copy = NULL;
   1.152 +
   1.153 +        while (true) {
   1.154 +          // skip known check patterns
   1.155 +          if (ctrl->is_Region()) {
   1.156 +            if (ctrl->as_Region()->is_copy()) {
   1.157 +              copy = ctrl->as_Region();
   1.158 +              ctrl = copy->is_copy();
   1.159 +            } else { // a cast
   1.160 +              assert(ctrl->req() == 3 &&
   1.161 +                     ctrl->in(1) != NULL && ctrl->in(1)->is_Proj() &&
   1.162 +                     ctrl->in(2) != NULL && ctrl->in(2)->is_Proj() &&
   1.163 +                     ctrl->in(1)->in(0) == ctrl->in(2)->in(0) &&
   1.164 +                     ctrl->in(1)->in(0) != NULL && ctrl->in(1)->in(0)->is_If(),
   1.165 +                     "must be a simple diamond");
   1.166 +              Node* true_proj = ctrl->in(1)->is_IfTrue() ? ctrl->in(1) : ctrl->in(2);
   1.167 +              for (SimpleDUIterator i(true_proj); i.has_next(); i.next()) {
   1.168 +                Node* use = i.get();
   1.169 +                assert(use == ctrl || use->is_ConstraintCast(),
   1.170 +                       err_msg_res("unexpected user: %s", use->Name()));
   1.171 +              }
   1.172 +
   1.173 +              iff = ctrl->in(1)->in(0)->as_If();
   1.174 +              ctrl = iff->in(0);
   1.175 +            }
   1.176 +          } else if (ctrl->is_IfTrue()) { // null checks, class checks
   1.177 +            iff = ctrl->in(0)->as_If();
   1.178 +            assert(iff->is_If(), "must be if");
   1.179 +            // Verify that the other arm is an uncommon trap
   1.180 +            Node* otherproj = iff->proj_out(1 - ctrl->as_Proj()->_con);
   1.181 +            CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava();
   1.182 +            assert(strcmp(call->_name, "uncommon_trap") == 0, "must be uncommond trap");
   1.183 +            ctrl = iff->in(0);
   1.184 +          } else {
   1.185 +            break;
   1.186 +          }
   1.187 +        }
   1.188 +
   1.189 +        assert(ctrl->is_Proj(), "must be a projection");
   1.190 +        assert(ctrl->in(0)->is_Initialize(), "should be initialize");
   1.191 +        for (SimpleDUIterator i(ctrl); i.has_next(); i.next()) {
   1.192 +          Node* use = i.get();
   1.193 +          assert(use == copy || use == iff || use == curr || use->is_CheckCastPP() || use->is_Load(),
   1.194 +                 err_msg_res("unexpected user: %s", use->Name()));
   1.195 +        }
   1.196 +#endif // ASSERT
   1.197 +      }
   1.198 +    }
   1.199 +  }
   1.200 +
   1.201 +#ifndef PRODUCT
   1.202 +  if (PrintOptimizeStringConcat) {
   1.203 +    tty->print("fusion has correct memory flow for ");
   1.204 +    _begin->jvms()->dump_spec(tty); tty->cr();
   1.205 +    tty->cr();
   1.206 +  }
   1.207 +#endif
   1.208 +  return true;
   1.209 +}
   1.210 +
   1.211  bool StringConcat::validate_control_flow() {
   1.212    // We found all the calls and arguments now lets see if it's
   1.213    // safe to transform the graph as we would expect.
   1.214 @@ -753,7 +899,7 @@
   1.215      }
   1.216    }
   1.217  
   1.218 -  // Skip backwards through the control checking for unexpected contro flow
   1.219 +  // Skip backwards through the control checking for unexpected control flow
   1.220    Node* ptr = _end;
   1.221    bool fail = false;
   1.222    while (ptr != _begin) {
   1.223 @@ -936,7 +1082,7 @@
   1.224    if (PrintOptimizeStringConcat && !fail) {
   1.225      ttyLocker ttyl;
   1.226      tty->cr();
   1.227 -    tty->print("fusion would succeed (%d %d) for ", null_check_count, _uncommon_traps.size());
   1.228 +    tty->print("fusion has correct control flow (%d %d) for ", null_check_count, _uncommon_traps.size());
   1.229      _begin->jvms()->dump_spec(tty); tty->cr();
   1.230      for (int i = 0; i < num_arguments(); i++) {
   1.231        argument(i)->dump();

mercurial