7129284: +DoEscapeAnalysis regression w/ early build of 7u4 (HotSpot 23) on Linux

Fri, 10 Feb 2012 12:53:43 -0800

author
kvn
date
Fri, 10 Feb 2012 12:53:43 -0800
changeset 3564
73df3733f2eb
parent 3523
2f985b6ce7ff
child 3565
de34c646c3f7

7129284: +DoEscapeAnalysis regression w/ early build of 7u4 (HotSpot 23) on Linux
Summary: Removed code which tried to create edges from fields of destination objects of arraycopy to fields of source objects. Added 30 sec time limit for EA graph construction.
Reviewed-by: never

src/share/vm/opto/escape.cpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/opto/escape.cpp	Thu Feb 09 18:01:20 2012 -0800
     1.2 +++ b/src/share/vm/opto/escape.cpp	Fri Feb 10 12:53:43 2012 -0800
     1.3 @@ -1,5 +1,5 @@
     1.4  /*
     1.5 - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
     1.6 + * Copyright (c) 2005, 2012, 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 @@ -1687,12 +1687,23 @@
    1.11    // Observed 8 passes in jvm2008 compiler.compiler.
    1.12    // Set limit to 20 to catch situation when something
    1.13    // did go wrong and recompile the method without EA.
    1.14 +  // Also limit build time to 30 sec (60 in debug VM).
    1.15  
    1.16  #define CG_BUILD_ITER_LIMIT 20
    1.17  
    1.18 +#ifdef ASSERT
    1.19 +#define CG_BUILD_TIME_LIMIT 60.0
    1.20 +#else
    1.21 +#define CG_BUILD_TIME_LIMIT 30.0
    1.22 +#endif
    1.23 +
    1.24    uint length = worklist.length();
    1.25    int iterations = 0;
    1.26 -  while(_progress && (iterations++ < CG_BUILD_ITER_LIMIT)) {
    1.27 +  elapsedTimer time;
    1.28 +  while(_progress &&
    1.29 +        (iterations++   < CG_BUILD_ITER_LIMIT) &&
    1.30 +        (time.seconds() < CG_BUILD_TIME_LIMIT)) {
    1.31 +    time.start();
    1.32      _progress = false;
    1.33      for( uint next = 0; next < length; ++next ) {
    1.34        int ni = worklist.at(next);
    1.35 @@ -1701,18 +1712,19 @@
    1.36        assert(n != NULL, "should be known node");
    1.37        build_connection_graph(n, igvn);
    1.38      }
    1.39 +    time.stop();
    1.40    }
    1.41 -  if (iterations >= CG_BUILD_ITER_LIMIT) {
    1.42 -    assert(iterations < CG_BUILD_ITER_LIMIT,
    1.43 -           err_msg("infinite EA connection graph build with %d nodes and worklist size %d",
    1.44 -           nodes_size(), length));
    1.45 +  if ((iterations     >= CG_BUILD_ITER_LIMIT) ||
    1.46 +      (time.seconds() >= CG_BUILD_TIME_LIMIT)) {
    1.47 +    assert(false, err_msg("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d",
    1.48 +           time.seconds(), iterations, nodes_size(), length));
    1.49      // Possible infinite build_connection_graph loop,
    1.50 -    // retry compilation without escape analysis.
    1.51 -    C->record_failure(C2Compiler::retry_no_escape_analysis());
    1.52 +    // bailout (no changes to ideal graph were made).
    1.53      _collecting = false;
    1.54      return false;
    1.55    }
    1.56  #undef CG_BUILD_ITER_LIMIT
    1.57 +#undef CG_BUILD_TIME_LIMIT
    1.58  
    1.59    // 5. Propagate escaped states.
    1.60    worklist.clear();
    1.61 @@ -2292,9 +2304,35 @@
    1.62          PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state();
    1.63          if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() &&
    1.64              (is_arraycopy || arg_esc < PointsToNode::ArgEscape)) {
    1.65 -
    1.66 +#ifdef ASSERT
    1.67            assert(aat == Type::TOP || aat == TypePtr::NULL_PTR ||
    1.68                   aat->isa_ptr() != NULL, "expecting an Ptr");
    1.69 +          if (!(is_arraycopy ||
    1.70 +                call->as_CallLeaf()->_name != NULL &&
    1.71 +                (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre")  == 0 ||
    1.72 +                 strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 ))
    1.73 +          ) {
    1.74 +            call->dump();
    1.75 +            assert(false, "EA: unexpected CallLeaf");
    1.76 +          }
    1.77 +#endif
    1.78 +          if (arg_esc < PointsToNode::ArgEscape) {
    1.79 +            set_escape_state(arg->_idx, PointsToNode::ArgEscape);
    1.80 +            Node* arg_base = arg;
    1.81 +            if (arg->is_AddP()) {
    1.82 +              //
    1.83 +              // The inline_native_clone() case when the arraycopy stub is called
    1.84 +              // after the allocation before Initialize and CheckCastPP nodes.
    1.85 +              // Or normal arraycopy for object arrays case.
    1.86 +              //
    1.87 +              // Set AddP's base (Allocate) as not scalar replaceable since
    1.88 +              // pointer to the base (with offset) is passed as argument.
    1.89 +              //
    1.90 +              arg_base = get_addp_base(arg);
    1.91 +              set_escape_state(arg_base->_idx, PointsToNode::ArgEscape);
    1.92 +            }
    1.93 +          }
    1.94 +
    1.95            bool arg_has_oops = aat->isa_oopptr() &&
    1.96                                (aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() ||
    1.97                                 (aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass()));
    1.98 @@ -2307,85 +2345,33 @@
    1.99            //   arraycopy(char[],0,Object*,0,size);
   1.100            //   arraycopy(Object*,0,char[],0,size);
   1.101            //
   1.102 -          // Don't add edges from dst's fields in such cases.
   1.103 +          // Do nothing special in such cases.
   1.104            //
   1.105 -          bool arg_is_arraycopy_dest = src_has_oops && is_arraycopy &&
   1.106 -                                       arg_has_oops && (i > TypeFunc::Parms);
   1.107 -#ifdef ASSERT
   1.108 -          if (!(is_arraycopy ||
   1.109 -                call->as_CallLeaf()->_name != NULL &&
   1.110 -                (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre")  == 0 ||
   1.111 -                 strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 ))
   1.112 -          ) {
   1.113 -            call->dump();
   1.114 -            assert(false, "EA: unexpected CallLeaf");
   1.115 -          }
   1.116 -#endif
   1.117 -          // Always process arraycopy's destination object since
   1.118 -          // we need to add all possible edges to references in
   1.119 -          // source object.
   1.120 -          if (arg_esc >= PointsToNode::ArgEscape &&
   1.121 -              !arg_is_arraycopy_dest) {
   1.122 -            continue;
   1.123 -          }
   1.124 -          set_escape_state(arg->_idx, PointsToNode::ArgEscape);
   1.125 -          Node* arg_base = arg;
   1.126 -          if (arg->is_AddP()) {
   1.127 -            //
   1.128 -            // The inline_native_clone() case when the arraycopy stub is called
   1.129 -            // after the allocation before Initialize and CheckCastPP nodes.
   1.130 -            // Or normal arraycopy for object arrays case.
   1.131 -            //
   1.132 -            // Set AddP's base (Allocate) as not scalar replaceable since
   1.133 -            // pointer to the base (with offset) is passed as argument.
   1.134 -            //
   1.135 -            arg_base = get_addp_base(arg);
   1.136 -          }
   1.137 -          VectorSet argset = *PointsTo(arg_base); // Clone set
   1.138 -          for( VectorSetI j(&argset); j.test(); ++j ) {
   1.139 -            uint pd = j.elem; // Destination object
   1.140 -            set_escape_state(pd, PointsToNode::ArgEscape);
   1.141 -
   1.142 -            if (arg_is_arraycopy_dest) {
   1.143 -              PointsToNode* ptd = ptnode_adr(pd);
   1.144 -              // Conservatively reference an unknown object since
   1.145 -              // not all source's fields/elements may be known.
   1.146 -              add_edge_from_fields(pd, _phantom_object, Type::OffsetBot);
   1.147 -
   1.148 -              Node *src = call->in(TypeFunc::Parms)->uncast();
   1.149 -              Node* src_base = src;
   1.150 -              if (src->is_AddP()) {
   1.151 -                src_base  = get_addp_base(src);
   1.152 -              }
   1.153 -              // Create edges from destination's fields to
   1.154 -              // everything known source's fields could point to.
   1.155 -              for( VectorSetI s(PointsTo(src_base)); s.test(); ++s ) {
   1.156 -                uint ps = s.elem;
   1.157 -                bool has_bottom_offset = false;
   1.158 -                for (uint fd = 0; fd < ptd->edge_count(); fd++) {
   1.159 -                  assert(ptd->edge_type(fd) == PointsToNode::FieldEdge, "expecting a field edge");
   1.160 -                  int fdi = ptd->edge_target(fd);
   1.161 -                  PointsToNode* pfd = ptnode_adr(fdi);
   1.162 -                  int offset = pfd->offset();
   1.163 -                  if (offset == Type::OffsetBot)
   1.164 -                    has_bottom_offset = true;
   1.165 -                  assert(offset != -1, "offset should be set");
   1.166 -                  add_deferred_edge_to_fields(fdi, ps, offset);
   1.167 -                }
   1.168 -                // Destination object may not have access (no field edge)
   1.169 -                // to fields which are accessed in source object.
   1.170 -                // As result no edges will be created to those source's
   1.171 -                // fields and escape state of destination object will
   1.172 -                // not be propagated to those fields.
   1.173 -                //
   1.174 -                // Mark source object as global escape except in
   1.175 -                // the case with Type::OffsetBot field (which is
   1.176 -                // common case for array elements access) when
   1.177 -                // edges are created to all source's fields.
   1.178 -                if (!has_bottom_offset) {
   1.179 -                  set_escape_state(ps, PointsToNode::GlobalEscape);
   1.180 -                }
   1.181 -              }
   1.182 +          if (is_arraycopy && (i > TypeFunc::Parms) &&
   1.183 +              src_has_oops && arg_has_oops) {
   1.184 +            // Destination object's fields reference an unknown object.
   1.185 +            Node* arg_base = arg;
   1.186 +            if (arg->is_AddP()) {
   1.187 +              arg_base = get_addp_base(arg);
   1.188 +            }
   1.189 +            for (VectorSetI s(PointsTo(arg_base)); s.test(); ++s) {
   1.190 +              uint ps = s.elem;
   1.191 +              set_escape_state(ps, PointsToNode::ArgEscape);
   1.192 +              add_edge_from_fields(ps, _phantom_object, Type::OffsetBot);
   1.193 +            }
   1.194 +            // Conservatively all values in source object fields globally escape
   1.195 +            // since we don't know if values in destination object fields
   1.196 +            // escape (it could be traced but it is too expensive).
   1.197 +            Node* src = call->in(TypeFunc::Parms)->uncast();
   1.198 +            Node* src_base = src;
   1.199 +            if (src->is_AddP()) {
   1.200 +              src_base  = get_addp_base(src);
   1.201 +            }
   1.202 +            for (VectorSetI s(PointsTo(src_base)); s.test(); ++s) {
   1.203 +              uint ps = s.elem;
   1.204 +              set_escape_state(ps, PointsToNode::ArgEscape);
   1.205 +              // Use OffsetTop to indicate fields global escape.
   1.206 +              add_edge_from_fields(ps, _phantom_object, Type::OffsetTop);
   1.207              }
   1.208            }
   1.209          }

mercurial