Mon, 29 Sep 2014 13:12:48 +0200
8038624: interpretedVFrame::expressions() must respect InterpreterOopMap for liveness
Reviewed-by: coleenp, minqi
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