src/share/vm/opto/memnode.cpp

changeset 452
ff5961f4c095
parent 435
a61af66fc99e
child 464
d5fc211aea19
     1.1 --- a/src/share/vm/opto/memnode.cpp	Wed Dec 05 09:00:00 2007 -0800
     1.2 +++ b/src/share/vm/opto/memnode.cpp	Wed Dec 05 09:01:00 2007 -0800
     1.3 @@ -634,6 +634,46 @@
     1.4  Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const {
     1.5    Node* ld_adr = in(MemNode::Address);
     1.6  
     1.7 +  const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr();
     1.8 +  Compile::AliasType* atp = tp != NULL ? phase->C->alias_type(tp) : NULL;
     1.9 +  if (EliminateAutoBox && atp != NULL && atp->index() >= Compile::AliasIdxRaw &&
    1.10 +      atp->field() != NULL && !atp->field()->is_volatile()) {
    1.11 +    uint alias_idx = atp->index();
    1.12 +    bool final = atp->field()->is_final();
    1.13 +    Node* result = NULL;
    1.14 +    Node* current = st;
    1.15 +    // Skip through chains of MemBarNodes checking the MergeMems for
    1.16 +    // new states for the slice of this load.  Stop once any other
    1.17 +    // kind of node is encountered.  Loads from final memory can skip
    1.18 +    // through any kind of MemBar but normal loads shouldn't skip
    1.19 +    // through MemBarAcquire since the could allow them to move out of
    1.20 +    // a synchronized region.
    1.21 +    while (current->is_Proj()) {
    1.22 +      int opc = current->in(0)->Opcode();
    1.23 +      if ((final && opc == Op_MemBarAcquire) ||
    1.24 +          opc == Op_MemBarRelease || opc == Op_MemBarCPUOrder) {
    1.25 +        Node* mem = current->in(0)->in(TypeFunc::Memory);
    1.26 +        if (mem->is_MergeMem()) {
    1.27 +          MergeMemNode* merge = mem->as_MergeMem();
    1.28 +          Node* new_st = merge->memory_at(alias_idx);
    1.29 +          if (new_st == merge->base_memory()) {
    1.30 +            // Keep searching
    1.31 +            current = merge->base_memory();
    1.32 +            continue;
    1.33 +          }
    1.34 +          // Save the new memory state for the slice and fall through
    1.35 +          // to exit.
    1.36 +          result = new_st;
    1.37 +        }
    1.38 +      }
    1.39 +      break;
    1.40 +    }
    1.41 +    if (result != NULL) {
    1.42 +      st = result;
    1.43 +    }
    1.44 +  }
    1.45 +
    1.46 +
    1.47    // Loop around twice in the case Load -> Initialize -> Store.
    1.48    // (See PhaseIterGVN::add_users_to_worklist, which knows about this case.)
    1.49    for (int trip = 0; trip <= 1; trip++) {
    1.50 @@ -723,6 +763,168 @@
    1.51    return this;
    1.52  }
    1.53  
    1.54 +
    1.55 +// Returns true if the AliasType refers to the field that holds the
    1.56 +// cached box array.  Currently only handles the IntegerCache case.
    1.57 +static bool is_autobox_cache(Compile::AliasType* atp) {
    1.58 +  if (atp != NULL && atp->field() != NULL) {
    1.59 +    ciField* field = atp->field();
    1.60 +    ciSymbol* klass = field->holder()->name();
    1.61 +    if (field->name() == ciSymbol::cache_field_name() &&
    1.62 +        field->holder()->uses_default_loader() &&
    1.63 +        klass == ciSymbol::java_lang_Integer_IntegerCache()) {
    1.64 +      return true;
    1.65 +    }
    1.66 +  }
    1.67 +  return false;
    1.68 +}
    1.69 +
    1.70 +// Fetch the base value in the autobox array
    1.71 +static bool fetch_autobox_base(Compile::AliasType* atp, int& cache_offset) {
    1.72 +  if (atp != NULL && atp->field() != NULL) {
    1.73 +    ciField* field = atp->field();
    1.74 +    ciSymbol* klass = field->holder()->name();
    1.75 +    if (field->name() == ciSymbol::cache_field_name() &&
    1.76 +        field->holder()->uses_default_loader() &&
    1.77 +        klass == ciSymbol::java_lang_Integer_IntegerCache()) {
    1.78 +      assert(field->is_constant(), "what?");
    1.79 +      ciObjArray* array = field->constant_value().as_object()->as_obj_array();
    1.80 +      // Fetch the box object at the base of the array and get its value
    1.81 +      ciInstance* box = array->obj_at(0)->as_instance();
    1.82 +      ciInstanceKlass* ik = box->klass()->as_instance_klass();
    1.83 +      if (ik->nof_nonstatic_fields() == 1) {
    1.84 +        // This should be true nonstatic_field_at requires calling
    1.85 +        // nof_nonstatic_fields so check it anyway
    1.86 +        ciConstant c = box->field_value(ik->nonstatic_field_at(0));
    1.87 +        cache_offset = c.as_int();
    1.88 +      }
    1.89 +      return true;
    1.90 +    }
    1.91 +  }
    1.92 +  return false;
    1.93 +}
    1.94 +
    1.95 +// Returns true if the AliasType refers to the value field of an
    1.96 +// autobox object.  Currently only handles Integer.
    1.97 +static bool is_autobox_object(Compile::AliasType* atp) {
    1.98 +  if (atp != NULL && atp->field() != NULL) {
    1.99 +    ciField* field = atp->field();
   1.100 +    ciSymbol* klass = field->holder()->name();
   1.101 +    if (field->name() == ciSymbol::value_name() &&
   1.102 +        field->holder()->uses_default_loader() &&
   1.103 +        klass == ciSymbol::java_lang_Integer()) {
   1.104 +      return true;
   1.105 +    }
   1.106 +  }
   1.107 +  return false;
   1.108 +}
   1.109 +
   1.110 +
   1.111 +// We're loading from an object which has autobox behaviour.
   1.112 +// If this object is result of a valueOf call we'll have a phi
   1.113 +// merging a newly allocated object and a load from the cache.
   1.114 +// We want to replace this load with the original incoming
   1.115 +// argument to the valueOf call.
   1.116 +Node* LoadNode::eliminate_autobox(PhaseGVN* phase) {
   1.117 +  Node* base = in(Address)->in(AddPNode::Base);
   1.118 +  if (base->is_Phi() && base->req() == 3) {
   1.119 +    AllocateNode* allocation = NULL;
   1.120 +    int allocation_index = -1;
   1.121 +    int load_index = -1;
   1.122 +    for (uint i = 1; i < base->req(); i++) {
   1.123 +      allocation = AllocateNode::Ideal_allocation(base->in(i), phase);
   1.124 +      if (allocation != NULL) {
   1.125 +        allocation_index = i;
   1.126 +        load_index = 3 - allocation_index;
   1.127 +        break;
   1.128 +      }
   1.129 +    }
   1.130 +    LoadNode* load = NULL;
   1.131 +    if (allocation != NULL && base->in(load_index)->is_Load()) {
   1.132 +      load = base->in(load_index)->as_Load();
   1.133 +    }
   1.134 +    if (load != NULL && in(Memory)->is_Phi() && in(Memory)->in(0) == base->in(0)) {
   1.135 +      // Push the loads from the phi that comes from valueOf up
   1.136 +      // through it to allow elimination of the loads and the recovery
   1.137 +      // of the original value.
   1.138 +      Node* mem_phi = in(Memory);
   1.139 +      Node* offset = in(Address)->in(AddPNode::Offset);
   1.140 +
   1.141 +      Node* in1 = clone();
   1.142 +      Node* in1_addr = in1->in(Address)->clone();
   1.143 +      in1_addr->set_req(AddPNode::Base, base->in(allocation_index));
   1.144 +      in1_addr->set_req(AddPNode::Address, base->in(allocation_index));
   1.145 +      in1_addr->set_req(AddPNode::Offset, offset);
   1.146 +      in1->set_req(0, base->in(allocation_index));
   1.147 +      in1->set_req(Address, in1_addr);
   1.148 +      in1->set_req(Memory, mem_phi->in(allocation_index));
   1.149 +
   1.150 +      Node* in2 = clone();
   1.151 +      Node* in2_addr = in2->in(Address)->clone();
   1.152 +      in2_addr->set_req(AddPNode::Base, base->in(load_index));
   1.153 +      in2_addr->set_req(AddPNode::Address, base->in(load_index));
   1.154 +      in2_addr->set_req(AddPNode::Offset, offset);
   1.155 +      in2->set_req(0, base->in(load_index));
   1.156 +      in2->set_req(Address, in2_addr);
   1.157 +      in2->set_req(Memory, mem_phi->in(load_index));
   1.158 +
   1.159 +      in1_addr = phase->transform(in1_addr);
   1.160 +      in1 =      phase->transform(in1);
   1.161 +      in2_addr = phase->transform(in2_addr);
   1.162 +      in2 =      phase->transform(in2);
   1.163 +
   1.164 +      PhiNode* result = PhiNode::make_blank(base->in(0), this);
   1.165 +      result->set_req(allocation_index, in1);
   1.166 +      result->set_req(load_index, in2);
   1.167 +      return result;
   1.168 +    }
   1.169 +  } else if (base->is_Load()) {
   1.170 +    // Eliminate the load of Integer.value for integers from the cache
   1.171 +    // array by deriving the value from the index into the array.
   1.172 +    // Capture the offset of the load and then reverse the computation.
   1.173 +    Node* load_base = base->in(Address)->in(AddPNode::Base);
   1.174 +    if (load_base != NULL) {
   1.175 +      Compile::AliasType* atp = phase->C->alias_type(load_base->adr_type());
   1.176 +      intptr_t cache_offset;
   1.177 +      int shift = -1;
   1.178 +      Node* cache = NULL;
   1.179 +      if (is_autobox_cache(atp)) {
   1.180 +        shift  = exact_log2(type2aelembytes[T_OBJECT]);
   1.181 +        cache = AddPNode::Ideal_base_and_offset(load_base->in(Address), phase, cache_offset);
   1.182 +      }
   1.183 +      if (cache != NULL && base->in(Address)->is_AddP()) {
   1.184 +        Node* elements[4];
   1.185 +        int count = base->in(Address)->as_AddP()->unpack_offsets(elements, ARRAY_SIZE(elements));
   1.186 +        int cache_low;
   1.187 +        if (count > 0 && fetch_autobox_base(atp, cache_low)) {
   1.188 +          int offset = arrayOopDesc::base_offset_in_bytes(memory_type()) - (cache_low << shift);
   1.189 +          // Add up all the offsets making of the address of the load
   1.190 +          Node* result = elements[0];
   1.191 +          for (int i = 1; i < count; i++) {
   1.192 +            result = phase->transform(new (phase->C, 3) AddXNode(result, elements[i]));
   1.193 +          }
   1.194 +          // Remove the constant offset from the address and then
   1.195 +          // remove the scaling of the offset to recover the original index.
   1.196 +          result = phase->transform(new (phase->C, 3) AddXNode(result, phase->MakeConX(-offset)));
   1.197 +          if (result->Opcode() == Op_LShiftX && result->in(2) == phase->intcon(shift)) {
   1.198 +            // Peel the shift off directly but wrap it in a dummy node
   1.199 +            // since Ideal can't return existing nodes
   1.200 +            result = new (phase->C, 3) RShiftXNode(result->in(1), phase->intcon(0));
   1.201 +          } else {
   1.202 +            result = new (phase->C, 3) RShiftXNode(result, phase->intcon(shift));
   1.203 +          }
   1.204 +#ifdef _LP64
   1.205 +          result = new (phase->C, 2) ConvL2INode(phase->transform(result));
   1.206 +#endif
   1.207 +          return result;
   1.208 +        }
   1.209 +      }
   1.210 +    }
   1.211 +  }
   1.212 +  return NULL;
   1.213 +}
   1.214 +
   1.215 +
   1.216  //------------------------------Ideal------------------------------------------
   1.217  // If the load is from Field memory and the pointer is non-null, we can
   1.218  // zero out the control input.
   1.219 @@ -755,6 +957,17 @@
   1.220      }
   1.221    }
   1.222  
   1.223 +  if (EliminateAutoBox && can_reshape && in(Address)->is_AddP()) {
   1.224 +    Node* base = in(Address)->in(AddPNode::Base);
   1.225 +    if (base != NULL) {
   1.226 +      Compile::AliasType* atp = phase->C->alias_type(adr_type());
   1.227 +      if (is_autobox_object(atp)) {
   1.228 +        Node* result = eliminate_autobox(phase);
   1.229 +        if (result != NULL) return result;
   1.230 +      }
   1.231 +    }
   1.232 +  }
   1.233 +
   1.234    // Check for prior store with a different base or offset; make Load
   1.235    // independent.  Skip through any number of them.  Bail out if the stores
   1.236    // are in an endless dead cycle and report no progress.  This is a key
   1.237 @@ -858,6 +1071,17 @@
   1.238            // This can happen if a interface-typed array narrows to a class type.
   1.239            jt = _type;
   1.240          }
   1.241 +
   1.242 +        if (EliminateAutoBox) {
   1.243 +          // The pointers in the autobox arrays are always non-null
   1.244 +          Node* base = in(Address)->in(AddPNode::Base);
   1.245 +          if (base != NULL) {
   1.246 +            Compile::AliasType* atp = phase->C->alias_type(base->adr_type());
   1.247 +            if (is_autobox_cache(atp)) {
   1.248 +              return jt->join(TypePtr::NOTNULL)->is_ptr();
   1.249 +            }
   1.250 +          }
   1.251 +        }
   1.252          return jt;
   1.253        }
   1.254      }

mercurial