8038624: interpretedVFrame::expressions() must respect InterpreterOopMap for liveness

Mon, 29 Sep 2014 13:12:48 +0200

author
mgronlun
date
Mon, 29 Sep 2014 13:12:48 +0200
changeset 7215
c204e2044c29
parent 7214
46ffdf376cb5
child 7216
13dbe89e447c

8038624: interpretedVFrame::expressions() must respect InterpreterOopMap for liveness
Reviewed-by: coleenp, minqi

src/share/vm/interpreter/oopMapCache.cpp file | annotate | diff | comparison | revisions
src/share/vm/interpreter/oopMapCache.hpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/vframe.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/vframe.hpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/interpreter/oopMapCache.cpp	Fri Sep 26 03:42:38 2014 -0700
     1.2 +++ b/src/share/vm/interpreter/oopMapCache.cpp	Mon Sep 29 13:12:48 2014 +0200
     1.3 @@ -180,7 +180,7 @@
     1.4    }
     1.5  }
     1.6  
     1.7 -bool InterpreterOopMap::is_empty() {
     1.8 +bool InterpreterOopMap::is_empty() const {
     1.9    bool result = _method == NULL;
    1.10    assert(_method != NULL || (_bci == 0 &&
    1.11      (_mask_size == 0 || _mask_size == USHRT_MAX) &&
    1.12 @@ -196,7 +196,7 @@
    1.13    for (int i = 0; i < N; i++) _bit_mask[i] = 0;
    1.14  }
    1.15  
    1.16 -void InterpreterOopMap::iterate_oop(OffsetClosure* oop_closure) {
    1.17 +void InterpreterOopMap::iterate_oop(OffsetClosure* oop_closure) const {
    1.18    int n = number_of_entries();
    1.19    int word_index = 0;
    1.20    uintptr_t value = 0;
    1.21 @@ -238,7 +238,7 @@
    1.22  #endif
    1.23  
    1.24  
    1.25 -void InterpreterOopMap::print() {
    1.26 +void InterpreterOopMap::print() const {
    1.27    int n = number_of_entries();
    1.28    tty->print("oop map for ");
    1.29    method()->print_value();
    1.30 @@ -469,7 +469,7 @@
    1.31    }
    1.32  }
    1.33  
    1.34 -inline unsigned int OopMapCache::hash_value_for(methodHandle method, int bci) {
    1.35 +inline unsigned int OopMapCache::hash_value_for(methodHandle method, int bci) const {
    1.36    // We use method->code_size() rather than method->identity_hash() below since
    1.37    // the mark may not be present if a pointer to the method is already reversed.
    1.38    return   ((unsigned int) bci)
    1.39 @@ -522,7 +522,7 @@
    1.40  
    1.41  void OopMapCache::lookup(methodHandle method,
    1.42                           int bci,
    1.43 -                         InterpreterOopMap* entry_for) {
    1.44 +                         InterpreterOopMap* entry_for) const {
    1.45    MutexLocker x(&_mut);
    1.46  
    1.47    OopMapCacheEntry* entry = NULL;
     2.1 --- a/src/share/vm/interpreter/oopMapCache.hpp	Fri Sep 26 03:42:38 2014 -0700
     2.2 +++ b/src/share/vm/interpreter/oopMapCache.hpp	Mon Sep 29 13:12:48 2014 +0200
     2.3 @@ -101,32 +101,31 @@
     2.4  
     2.5    // access methods
     2.6    Method*        method() const                  { return _method; }
     2.7 -  void           set_method(Method* v)         { _method = v; }
     2.8 +  void           set_method(Method* v)           { _method = v; }
     2.9    int            bci() const                     { return _bci; }
    2.10    void           set_bci(int v)                  { _bci = v; }
    2.11    int            mask_size() const               { return _mask_size; }
    2.12    void           set_mask_size(int v)            { _mask_size = v; }
    2.13 -  int            number_of_entries() const       { return mask_size() / bits_per_entry; }
    2.14    // Test bit mask size and return either the in-line bit mask or allocated
    2.15    // bit mask.
    2.16 -  uintptr_t*  bit_mask()                         { return (uintptr_t*)(mask_size() <= small_mask_limit ? (intptr_t)_bit_mask : _bit_mask[0]); }
    2.17 +  uintptr_t*  bit_mask() const                   { return (uintptr_t*)(mask_size() <= small_mask_limit ? (intptr_t)_bit_mask : _bit_mask[0]); }
    2.18  
    2.19    // return the word size of_bit_mask.  mask_size() <= 4 * MAX_USHORT
    2.20 -  size_t mask_word_size() {
    2.21 +  size_t mask_word_size() const {
    2.22      return (mask_size() + BitsPerWord - 1) / BitsPerWord;
    2.23    }
    2.24  
    2.25 -  uintptr_t entry_at(int offset)            { int i = offset * bits_per_entry; return bit_mask()[i / BitsPerWord] >> (i % BitsPerWord); }
    2.26 +  uintptr_t entry_at(int offset) const           { int i = offset * bits_per_entry; return bit_mask()[i / BitsPerWord] >> (i % BitsPerWord); }
    2.27  
    2.28 -  void set_expression_stack_size(int sz)    { _expression_stack_size = sz; }
    2.29 +  void set_expression_stack_size(int sz)         { _expression_stack_size = sz; }
    2.30  
    2.31  #ifdef ENABLE_ZAP_DEAD_LOCALS
    2.32 -  bool is_dead(int offset)                       { return (entry_at(offset) & (1 << dead_bit_number)) != 0; }
    2.33 +  bool is_dead(int offset) const                 { return (entry_at(offset) & (1 << dead_bit_number)) != 0; }
    2.34  #endif
    2.35  
    2.36    // Lookup
    2.37 -  bool match(methodHandle method, int bci)       { return _method == method() && _bci == bci; }
    2.38 -  bool is_empty();
    2.39 +  bool match(methodHandle method, int bci) const { return _method == method() && _bci == bci; }
    2.40 +  bool is_empty() const;
    2.41  
    2.42    // Initialization
    2.43    void initialize();
    2.44 @@ -141,12 +140,13 @@
    2.45    // in-line), allocate the space from a Resource area.
    2.46    void resource_copy(OopMapCacheEntry* from);
    2.47  
    2.48 -  void iterate_oop(OffsetClosure* oop_closure);
    2.49 -  void print();
    2.50 +  void iterate_oop(OffsetClosure* oop_closure) const;
    2.51 +  void print() const;
    2.52  
    2.53 -  bool is_oop  (int offset)                      { return (entry_at(offset) & (1 << oop_bit_number )) != 0; }
    2.54 +  int number_of_entries() const                  { return mask_size() / bits_per_entry; }
    2.55 +  bool is_oop (int offset) const                 { return (entry_at(offset) & (1 << oop_bit_number )) != 0; }
    2.56  
    2.57 -  int expression_stack_size()                    { return _expression_stack_size; }
    2.58 +  int expression_stack_size() const              { return _expression_stack_size; }
    2.59  
    2.60  #ifdef ENABLE_ZAP_DEAD_LOCALS
    2.61    void iterate_all(OffsetClosure* oop_closure, OffsetClosure* value_closure, OffsetClosure* dead_closure);
    2.62 @@ -161,10 +161,10 @@
    2.63  
    2.64    OopMapCacheEntry* _array;
    2.65  
    2.66 -  unsigned int hash_value_for(methodHandle method, int bci);
    2.67 +  unsigned int hash_value_for(methodHandle method, int bci) const;
    2.68    OopMapCacheEntry* entry_at(int i) const;
    2.69  
    2.70 -  Mutex _mut;
    2.71 +  mutable Mutex _mut;
    2.72  
    2.73    void flush();
    2.74  
    2.75 @@ -177,7 +177,7 @@
    2.76  
    2.77    // Returns the oopMap for (method, bci) in parameter "entry".
    2.78    // Returns false if an oop map was not found.
    2.79 -  void lookup(methodHandle method, int bci, InterpreterOopMap* entry);
    2.80 +  void lookup(methodHandle method, int bci, InterpreterOopMap* entry) const;
    2.81  
    2.82    // Compute an oop map without updating the cache or grabbing any locks (for debugging)
    2.83    static void compute_one_oop_map(methodHandle method, int bci, InterpreterOopMap* entry);
     3.1 --- a/src/share/vm/runtime/vframe.cpp	Fri Sep 26 03:42:38 2014 -0700
     3.2 +++ b/src/share/vm/runtime/vframe.cpp	Mon Sep 29 13:12:48 2014 +0200
     3.3 @@ -260,65 +260,156 @@
     3.4    return fr().interpreter_frame_method();
     3.5  }
     3.6  
     3.7 -StackValueCollection* interpretedVFrame::locals() const {
     3.8 -  int length = method()->max_locals();
     3.9 +static StackValue* create_stack_value_from_oop_map(const InterpreterOopMap& oop_mask,
    3.10 +                                                   int index,
    3.11 +                                                   const intptr_t* const addr) {
    3.12  
    3.13 -  if (method()->is_native()) {
    3.14 -    // If the method is native, max_locals is not telling the truth.
    3.15 -    // maxlocals then equals the size of parameters
    3.16 -    length = method()->size_of_parameters();
    3.17 +  assert(index >= 0 &&
    3.18 +         index < oop_mask.number_of_entries(), "invariant");
    3.19 +
    3.20 +  // categorize using oop_mask
    3.21 +  if (oop_mask.is_oop(index)) {
    3.22 +    // reference (oop) "r"
    3.23 +    Handle h(addr != NULL ? (*(oop*)addr) : (oop)NULL);
    3.24 +    return new StackValue(h);
    3.25 +  }
    3.26 +  // value (integer) "v"
    3.27 +  return new StackValue(addr != NULL ? *addr : 0);
    3.28 +}
    3.29 +
    3.30 +static bool is_in_expression_stack(const frame& fr, const intptr_t* const addr) {
    3.31 +  assert(addr != NULL, "invariant");
    3.32 +
    3.33 +  // Ensure to be 'inside' the expresion stack (i.e., addr >= sp for Intel).
    3.34 +  // In case of exceptions, the expression stack is invalid and the sp
    3.35 +  // will be reset to express this condition.
    3.36 +  if (frame::interpreter_frame_expression_stack_direction() > 0) {
    3.37 +    return addr <= fr.interpreter_frame_tos_address();
    3.38    }
    3.39  
    3.40 -  StackValueCollection* result = new StackValueCollection(length);
    3.41 +  return addr >= fr.interpreter_frame_tos_address();
    3.42 +}
    3.43  
    3.44 -  // Get oopmap describing oops and int for current bci
    3.45 +static void stack_locals(StackValueCollection* result,
    3.46 +                         int length,
    3.47 +                         const InterpreterOopMap& oop_mask,
    3.48 +                         const frame& fr) {
    3.49 +
    3.50 +  assert(result != NULL, "invariant");
    3.51 +
    3.52 +  for (int i = 0; i < length; ++i) {
    3.53 +    const intptr_t* const addr = fr.interpreter_frame_local_at(i);
    3.54 +    assert(addr != NULL, "invariant");
    3.55 +    assert(addr >= fr.sp(), "must be inside the frame");
    3.56 +
    3.57 +    StackValue* const sv = create_stack_value_from_oop_map(oop_mask, i, addr);
    3.58 +    assert(sv != NULL, "sanity check");
    3.59 +
    3.60 +    result->add(sv);
    3.61 +  }
    3.62 +}
    3.63 +
    3.64 +static void stack_expressions(StackValueCollection* result,
    3.65 +                              int length,
    3.66 +                              int max_locals,
    3.67 +                              const InterpreterOopMap& oop_mask,
    3.68 +                              const frame& fr) {
    3.69 +
    3.70 +  assert(result != NULL, "invariant");
    3.71 +
    3.72 +  for (int i = 0; i < length; ++i) {
    3.73 +    const intptr_t* addr = fr.interpreter_frame_expression_stack_at(i);
    3.74 +    assert(addr != NULL, "invariant");
    3.75 +    if (!is_in_expression_stack(fr, addr)) {
    3.76 +      // Need to ensure no bogus escapes.
    3.77 +      addr = NULL;
    3.78 +    }
    3.79 +
    3.80 +    StackValue* const sv = create_stack_value_from_oop_map(oop_mask,
    3.81 +                                                           i + max_locals,
    3.82 +                                                           addr);
    3.83 +    assert(sv != NULL, "sanity check");
    3.84 +
    3.85 +    result->add(sv);
    3.86 +  }
    3.87 +}
    3.88 +
    3.89 +StackValueCollection* interpretedVFrame::locals() const {
    3.90 +  return stack_data(false);
    3.91 +}
    3.92 +
    3.93 +StackValueCollection* interpretedVFrame::expressions() const {
    3.94 +  return stack_data(true);
    3.95 +}
    3.96 +
    3.97 +/*
    3.98 + * Worker routine for fetching references and/or values
    3.99 + * for a particular bci in the interpretedVFrame.
   3.100 + *
   3.101 + * Returns data for either "locals" or "expressions",
   3.102 + * using bci relative oop_map (oop_mask) information.
   3.103 + *
   3.104 + * @param expressions  bool switch controlling what data to return
   3.105 +                       (false == locals / true == expressions)
   3.106 + *
   3.107 + */
   3.108 +StackValueCollection* interpretedVFrame::stack_data(bool expressions) const {
   3.109 +
   3.110    InterpreterOopMap oop_mask;
   3.111 +  // oopmap for current bci
   3.112    if (TraceDeoptimization && Verbose) {
   3.113 -    methodHandle m_h(thread(), method());
   3.114 +    methodHandle m_h(Thread::current(), method());
   3.115      OopMapCache::compute_one_oop_map(m_h, bci(), &oop_mask);
   3.116    } else {
   3.117      method()->mask_for(bci(), &oop_mask);
   3.118    }
   3.119 -  // handle locals
   3.120 -  for(int i=0; i < length; i++) {
   3.121 -    // Find stack location
   3.122 -    intptr_t *addr = locals_addr_at(i);
   3.123  
   3.124 -    // Depending on oop/int put it in the right package
   3.125 -    StackValue *sv;
   3.126 -    if (oop_mask.is_oop(i)) {
   3.127 -      // oop value
   3.128 -      Handle h(*(oop *)addr);
   3.129 -      sv = new StackValue(h);
   3.130 -    } else {
   3.131 -      // integer
   3.132 -      sv = new StackValue(*addr);
   3.133 -    }
   3.134 -    assert(sv != NULL, "sanity check");
   3.135 -    result->add(sv);
   3.136 +  const int mask_len = oop_mask.number_of_entries();
   3.137 +
   3.138 +  // If the method is native, method()->max_locals() is not telling the truth.
   3.139 +  // For our purposes, max locals instead equals the size of parameters.
   3.140 +  const int max_locals = method()->is_native() ?
   3.141 +    method()->size_of_parameters() : method()->max_locals();
   3.142 +
   3.143 +  assert(mask_len >= max_locals, "invariant");
   3.144 +
   3.145 +  const int length = expressions ? mask_len - max_locals : max_locals;
   3.146 +  assert(length >= 0, "invariant");
   3.147 +
   3.148 +  StackValueCollection* const result = new StackValueCollection(length);
   3.149 +
   3.150 +  if (0 == length) {
   3.151 +    return result;
   3.152    }
   3.153 +
   3.154 +  if (expressions) {
   3.155 +    stack_expressions(result, length, max_locals, oop_mask, fr());
   3.156 +  } else {
   3.157 +    stack_locals(result, length, oop_mask, fr());
   3.158 +  }
   3.159 +
   3.160 +  assert(length == result->size(), "invariant");
   3.161 +
   3.162    return result;
   3.163  }
   3.164  
   3.165  void interpretedVFrame::set_locals(StackValueCollection* values) const {
   3.166    if (values == NULL || values->size() == 0) return;
   3.167  
   3.168 -  int length = method()->max_locals();
   3.169 -  if (method()->is_native()) {
   3.170 -    // If the method is native, max_locals is not telling the truth.
   3.171 -    // maxlocals then equals the size of parameters
   3.172 -    length = method()->size_of_parameters();
   3.173 -  }
   3.174 +  // If the method is native, max_locals is not telling the truth.
   3.175 +  // maxlocals then equals the size of parameters
   3.176 +  const int max_locals = method()->is_native() ?
   3.177 +    method()->size_of_parameters() : method()->max_locals();
   3.178  
   3.179 -  assert(length == values->size(), "Mismatch between actual stack format and supplied data");
   3.180 +  assert(max_locals == values->size(), "Mismatch between actual stack format and supplied data");
   3.181  
   3.182    // handle locals
   3.183 -  for (int i = 0; i < length; i++) {
   3.184 +  for (int i = 0; i < max_locals; i++) {
   3.185      // Find stack location
   3.186      intptr_t *addr = locals_addr_at(i);
   3.187  
   3.188      // Depending on oop/int put it in the right package
   3.189 -    StackValue *sv = values->at(i);
   3.190 +    const StackValue* const sv = values->at(i);
   3.191      assert(sv != NULL, "sanity check");
   3.192      if (sv->type() == T_OBJECT) {
   3.193        *(oop *) addr = (sv->get_obj())();
   3.194 @@ -328,46 +419,6 @@
   3.195    }
   3.196  }
   3.197  
   3.198 -StackValueCollection*  interpretedVFrame::expressions() const {
   3.199 -  int length = fr().interpreter_frame_expression_stack_size();
   3.200 -  if (method()->is_native()) {
   3.201 -    // If the method is native, there is no expression stack
   3.202 -    length = 0;
   3.203 -  }
   3.204 -
   3.205 -  int nof_locals = method()->max_locals();
   3.206 -  StackValueCollection* result = new StackValueCollection(length);
   3.207 -
   3.208 -  InterpreterOopMap oop_mask;
   3.209 -  // Get oopmap describing oops and int for current bci
   3.210 -  if (TraceDeoptimization && Verbose) {
   3.211 -    methodHandle m_h(method());
   3.212 -    OopMapCache::compute_one_oop_map(m_h, bci(), &oop_mask);
   3.213 -  } else {
   3.214 -    method()->mask_for(bci(), &oop_mask);
   3.215 -  }
   3.216 -  // handle expressions
   3.217 -  for(int i=0; i < length; i++) {
   3.218 -    // Find stack location
   3.219 -    intptr_t *addr = fr().interpreter_frame_expression_stack_at(i);
   3.220 -
   3.221 -    // Depending on oop/int put it in the right package
   3.222 -    StackValue *sv;
   3.223 -    if (oop_mask.is_oop(i + nof_locals)) {
   3.224 -      // oop value
   3.225 -      Handle h(*(oop *)addr);
   3.226 -      sv = new StackValue(h);
   3.227 -    } else {
   3.228 -      // integer
   3.229 -      sv = new StackValue(*addr);
   3.230 -    }
   3.231 -    assert(sv != NULL, "sanity check");
   3.232 -    result->add(sv);
   3.233 -  }
   3.234 -  return result;
   3.235 -}
   3.236 -
   3.237 -
   3.238  // ------------- cChunk --------------
   3.239  
   3.240  entryVFrame::entryVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread)
     4.1 --- a/src/share/vm/runtime/vframe.hpp	Fri Sep 26 03:42:38 2014 -0700
     4.2 +++ b/src/share/vm/runtime/vframe.hpp	Mon Sep 29 13:12:48 2014 +0200
     4.3 @@ -186,7 +186,7 @@
     4.4   private:
     4.5    static const int bcp_offset;
     4.6    intptr_t* locals_addr_at(int offset) const;
     4.7 -
     4.8 +  StackValueCollection* stack_data(bool expressions) const;
     4.9    // returns where the parameters starts relative to the frame pointer
    4.10    int start_of_parameters() const;
    4.11  

mercurial