1.1 --- a/src/share/vm/code/oopRecorder.hpp Fri Aug 31 16:39:35 2012 -0700 1.2 +++ b/src/share/vm/code/oopRecorder.hpp Sat Sep 01 13:25:18 2012 -0400 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 1998, 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 @@ -25,14 +25,15 @@ 1.11 #ifndef SHARE_VM_CODE_OOPRECORDER_HPP 1.12 #define SHARE_VM_CODE_OOPRECORDER_HPP 1.13 1.14 +#include "memory/universe.hpp" 1.15 #include "runtime/handles.hpp" 1.16 #include "utilities/growableArray.hpp" 1.17 1.18 -// Recording and retrieval of oop relocations in compiled code. 1.19 +// Recording and retrieval of either oop relocations or metadata in compiled code. 1.20 1.21 class CodeBlob; 1.22 1.23 -class OopRecorder : public ResourceObj { 1.24 +template <class T> class ValueRecorder : public StackObj { 1.25 public: 1.26 // A two-way mapping from positive indexes to oop handles. 1.27 // The zero index is reserved for a constant (sharable) null. 1.28 @@ -40,20 +41,21 @@ 1.29 1.30 // Use the given arena to manage storage, if not NULL. 1.31 // By default, uses the current ResourceArea. 1.32 - OopRecorder(Arena* arena = NULL); 1.33 + ValueRecorder(Arena* arena = NULL); 1.34 1.35 - // Generate a new index on which CodeBlob::oop_addr_at will work. 1.36 + // Generate a new index on which nmethod::oop_addr_at will work. 1.37 // allocate_index and find_index never return the same index, 1.38 // and allocate_index never returns the same index twice. 1.39 // In fact, two successive calls to allocate_index return successive ints. 1.40 - int allocate_index(jobject h) { 1.41 + int allocate_index(T h) { 1.42 return add_handle(h, false); 1.43 } 1.44 1.45 - // For a given jobject, this will return the same index repeatedly. 1.46 - // The index can later be given to oop_at to retrieve the oop. 1.47 - // However, the oop must not be changed via CodeBlob::oop_addr_at. 1.48 - int find_index(jobject h) { 1.49 + // For a given jobject or Metadata*, this will return the same index 1.50 + // repeatedly. The index can later be given to nmethod::oop_at or 1.51 + // metadata_at to retrieve the oop. 1.52 + // However, the oop must not be changed via nmethod::oop_addr_at. 1.53 + int find_index(T h) { 1.54 int index = maybe_find_index(h); 1.55 if (index < 0) { // previously unallocated 1.56 index = add_handle(h, true); 1.57 @@ -61,23 +63,26 @@ 1.58 return index; 1.59 } 1.60 1.61 - // variant of find_index which does not allocate if not found (yields -1) 1.62 - int maybe_find_index(jobject h); 1.63 + // returns the size of the generated oop/metadata table, for sizing the 1.64 + // CodeBlob. Must be called after all oops are allocated! 1.65 + int size(); 1.66 1.67 - // returns the size of the generated oop table, for sizing the CodeBlob. 1.68 - // must be called after all oops are allocated! 1.69 - int oop_size(); 1.70 + // Retrieve the value at a given index. 1.71 + T at(int index); 1.72 1.73 - // Retrieve the oop handle at a given index. 1.74 - jobject handle_at(int index); 1.75 - 1.76 - int element_count() { 1.77 + int count() { 1.78 + if (_handles == NULL) return 0; 1.79 // there is always a NULL virtually present as first object 1.80 return _handles->length() + first_index; 1.81 } 1.82 1.83 - // copy the generated oop table to nmethod 1.84 - void copy_to(nmethod* nm); // => nm->copy_oops(_handles) 1.85 + // Helper function; returns false for NULL or Universe::non_oop_word(). 1.86 + bool is_real(T h) { 1.87 + return h != NULL && h != (T)Universe::non_oop_word(); 1.88 + } 1.89 + 1.90 + // copy the generated table to nmethod 1.91 + void copy_values_to(nmethod* nm); 1.92 1.93 bool is_unused() { return _handles == NULL && !_complete; } 1.94 #ifdef ASSERT 1.95 @@ -85,10 +90,13 @@ 1.96 #endif 1.97 1.98 private: 1.99 + // variant of find_index which does not allocate if not found (yields -1) 1.100 + int maybe_find_index(T h); 1.101 + 1.102 // leaky hash table of handle => index, to help detect duplicate insertion 1.103 - class IndexCache: public ResourceObj { 1.104 - // This class is only used by the OopRecorder class. 1.105 - friend class OopRecorder; 1.106 + template <class X> class IndexCache : public ResourceObj { 1.107 + // This class is only used by the ValueRecorder class. 1.108 + friend class ValueRecorder; 1.109 enum { 1.110 _log_cache_size = 9, 1.111 _cache_size = (1<<_log_cache_size), 1.112 @@ -98,13 +106,13 @@ 1.113 _index_shift = _collision_bit_shift+1 1.114 }; 1.115 int _cache[_cache_size]; 1.116 - static juint cache_index(jobject handle) { 1.117 + static juint cache_index(X handle) { 1.118 juint ci = (int) (intptr_t) handle; 1.119 ci ^= ci >> (BitsPerByte*2); 1.120 ci += ci >> (BitsPerByte*1); 1.121 return ci & (_cache_size-1); 1.122 } 1.123 - int* cache_location(jobject handle) { 1.124 + int* cache_location(X handle) { 1.125 return &_cache[ cache_index(handle) ]; 1.126 } 1.127 static bool cache_location_collision(int* cloc) { 1.128 @@ -122,17 +130,14 @@ 1.129 IndexCache(); 1.130 }; 1.131 1.132 - // Helper function; returns false for NULL or Universe::non_oop_word(). 1.133 - inline bool is_real_jobject(jobject h); 1.134 - 1.135 void maybe_initialize(); 1.136 - int add_handle(jobject h, bool make_findable); 1.137 + int add_handle(T h, bool make_findable); 1.138 1.139 enum { null_index = 0, first_index = 1, index_cache_threshold = 20 }; 1.140 1.141 - GrowableArray<jobject>* _handles; // ordered list (first is always NULL) 1.142 + GrowableArray<T>* _handles; // ordered list (first is always NULL) 1.143 GrowableArray<int>* _no_finds; // all unfindable indexes; usually empty 1.144 - IndexCache* _indexes; // map: jobject -> its probable index 1.145 + IndexCache<T>* _indexes; // map: handle -> its probable index 1.146 Arena* _arena; 1.147 bool _complete; 1.148 1.149 @@ -141,4 +146,76 @@ 1.150 #endif 1.151 }; 1.152 1.153 +class OopRecorder : public ResourceObj { 1.154 + private: 1.155 + ValueRecorder<jobject> _oops; 1.156 + ValueRecorder<Metadata*> _metadata; 1.157 + public: 1.158 + OopRecorder(Arena* arena = NULL): _oops(arena), _metadata(arena) {} 1.159 + 1.160 + int allocate_oop_index(jobject h) { 1.161 + return _oops.allocate_index(h); 1.162 + } 1.163 + int find_index(jobject h) { 1.164 + return _oops.find_index(h); 1.165 + } 1.166 + jobject oop_at(int index) { 1.167 + return _oops.at(index); 1.168 + } 1.169 + int oop_size() { 1.170 + return _oops.size(); 1.171 + } 1.172 + int oop_count() { 1.173 + return _oops.count(); 1.174 + } 1.175 + bool is_real(jobject h) { 1.176 + return _oops.is_real(h); 1.177 + } 1.178 + 1.179 + int allocate_metadata_index(Metadata* oop) { 1.180 + return _metadata.allocate_index(oop); 1.181 + } 1.182 + int find_index(Metadata* h) { 1.183 + return _metadata.find_index(h); 1.184 + } 1.185 + Metadata* metadata_at(int index) { 1.186 + return _metadata.at(index); 1.187 + } 1.188 + int metadata_size() { 1.189 + return _metadata.size(); 1.190 + } 1.191 + int metadata_count() { 1.192 + return _metadata.count(); 1.193 + } 1.194 + bool is_real(Metadata* h) { 1.195 + return _metadata.is_real(h); 1.196 + } 1.197 + 1.198 + bool is_unused() { 1.199 + return _oops.is_unused() && _metadata.is_unused(); 1.200 + } 1.201 + 1.202 + void freeze() { 1.203 + _oops.size(); 1.204 + _metadata.size(); 1.205 + } 1.206 + 1.207 + void copy_values_to(nmethod* nm) { 1.208 + if (!_oops.is_unused()) { 1.209 + _oops.copy_values_to(nm); 1.210 + } 1.211 + if (!_metadata.is_unused()) { 1.212 + _metadata.copy_values_to(nm); 1.213 + } 1.214 + } 1.215 + 1.216 +#ifdef ASSERT 1.217 + bool is_complete() { 1.218 + assert(_oops.is_complete() == _metadata.is_complete(), "must agree"); 1.219 + return _oops.is_complete(); 1.220 + } 1.221 +#endif 1.222 +}; 1.223 + 1.224 + 1.225 #endif // SHARE_VM_CODE_OOPRECORDER_HPP