1 /* 2 * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "runtime/interfaceSupport.inline.hpp" 26 #include "runtime/methodDetails.hpp" 27 #include "runtime/runtimeUpcalls.hpp" 28 29 GrowableArray<RuntimeUpcallInfo*>* RuntimeUpcalls::_upcalls[RuntimeUpcallType::numTypes]; 30 RuntimeUpcalls::State RuntimeUpcalls::_state = RuntimeUpcalls::Uninitialized; 31 32 bool runtimeUpcalls_open_registration() { 33 return RuntimeUpcalls::open_upcall_registration(); 34 } 35 36 bool RuntimeUpcalls::open_upcall_registration() { 37 assert(_state == Uninitialized, "upcalls are already open"); 38 for (int i = 0; i < RuntimeUpcallType::numTypes; i++) { 39 RuntimeUpcalls::_upcalls[i] = nullptr; 40 } 41 _state = Open; 42 return true; 43 } 44 45 void runtimeUpcalls_close_registration() { 46 RuntimeUpcalls::close_upcall_registration(); 47 } 48 49 void RuntimeUpcalls::close_upcall_registration() { 50 assert(_state == Open, "upcalls are not open"); 51 _state = Closed; 52 } 53 54 void RuntimeUpcalls::mark_for_upcalls(RuntimeUpcallType upcall_type, const methodHandle& method) { 55 if (_upcalls[upcall_type] != nullptr) { 56 MethodDetails method_details(method); 57 for(RuntimeUpcallInfo* info : *(_upcalls[upcall_type])) { 58 if(info->includes(method_details)) { 59 switch(upcall_type) { 60 case onMethodEntry: method->set_has_upcall_on_method_entry(true); break; 61 case onMethodExit: method->set_has_upcall_on_method_exit(true); break; 62 default: ShouldNotReachHere(); 63 } 64 break; 65 } 66 } 67 } 68 } 69 70 bool RuntimeUpcalls::register_upcall(RuntimeUpcallType upcall_type, RuntimeUpcallInfo* info) { 71 assert(upcall_type != onMethodExit, "Upcalls on method exit are not supported yet"); 72 assert(info != nullptr, "upcall info is null"); 73 if (_upcalls[upcall_type] == nullptr) { 74 _upcalls[upcall_type] = new (mtServiceability) GrowableArray<RuntimeUpcallInfo*>(1, mtServiceability); 75 } 76 info->set_index(_upcalls[upcall_type]->length()); 77 _upcalls[upcall_type]->append(info); 78 return true; 79 } 80 81 int RuntimeUpcalls::get_num_upcalls(RuntimeUpcallType upcall_type) { 82 return (_upcalls[upcall_type] == nullptr) ? 0 : _upcalls[upcall_type]->length(); 83 } 84 85 void RuntimeUpcalls::upcall_redirect(RuntimeUpcallType upcall_type, JavaThread* current, Method* method) { 86 MethodDetails method_details(method); 87 88 // This redirection occurs when there are more than one upcalls setup. Currently each method is marked 89 // to indicate either none, entry and/or exit upcalls (two bits total); then we have to iterate over 90 // all upcalls and test the method details to determine which upcalls to call. This is not optimal. 91 // One possible optimization is to use more bits to support more upcalls. The method flags currently use 18 92 // out of 32 bits, so there are still 14 bits available for use. We could set a limit of say 4-8 entry/exit 93 // upcalls combined, leaving 10-6 bits for other uses. This still requires a redirect here to determine 94 // which upcalls to call, but it would be more efficient than the current implementation as we'd avoid the 95 // method matching and simply map bits to indexes. 96 97 RuntimeUpcallInfo* upcall = get_first_upcall(upcall_type, method_details); 98 while (upcall != nullptr) { 99 upcall->upcall()(current); 100 upcall = get_next_upcall(upcall_type, method_details, upcall); 101 } 102 } 103 104 JRT_BLOCK_ENTRY(void, RuntimeUpcalls::on_method_entry_upcall_redirect(JavaThread* current, Method* method)) { 105 RuntimeUpcalls::upcall_redirect(onMethodEntry, current, method); 106 } 107 JRT_END 108 109 JRT_BLOCK_ENTRY(void, RuntimeUpcalls::on_method_exit_upcall_redirect(JavaThread* current, Method* method)) { 110 RuntimeUpcalls::upcall_redirect(onMethodExit, current, method); 111 } 112 JRT_END 113 114 //-------------------------------RuntimeUpcalls--------------------------------------- 115 116 void RuntimeUpcalls::install_upcalls(const methodHandle& method) { 117 for (int i = 0; i < RuntimeUpcallType::numTypes; i++) { 118 mark_for_upcalls(static_cast<RuntimeUpcallType>(i), method); 119 } 120 } 121 122 bool RuntimeUpcalls::register_upcall(RuntimeUpcallType upcall_type, const char* upcall_name, RuntimeUpcall upcall, RuntimeUpcallMethodFilterCallback method_filter_callback) 123 { 124 assert(upcall_type < numTypes, "invalid upcall type"); 125 assert(_state == Open, "upcalls are not open for registration"); 126 if (_state != Open) return false; 127 return register_upcall(upcall_type, RuntimeUpcallInfo::create(upcall_name, upcall, method_filter_callback)); 128 } 129 130 RuntimeUpcallInfo* RuntimeUpcalls::get_next_upcall(RuntimeUpcallType upcall_type, MethodDetails& method_details, RuntimeUpcallInfo* prev_upcall_info) { 131 assert(upcall_type < numTypes, "invalid upcall type"); 132 if (_upcalls[upcall_type] != nullptr) { 133 // simple case where there's only one upcall 134 if (_upcalls[upcall_type]->length() == 1) { 135 if (prev_upcall_info != nullptr) { 136 return nullptr; 137 } 138 RuntimeUpcallInfo* upcall = _upcalls[upcall_type]->at(0); 139 return upcall->includes(method_details) ? upcall : nullptr; 140 } 141 142 // Resume from where we left off, unless we are the last entry. 143 assert(prev_upcall_info == nullptr || (prev_upcall_info->get_index() >= 0 && prev_upcall_info->get_index() < _upcalls[upcall_type]->length()), "invalid upcall index"); 144 int index = (prev_upcall_info != nullptr) ? prev_upcall_info->get_index() + 1 : 0; 145 for (int i = index; i < _upcalls[upcall_type]->length(); i++) { 146 RuntimeUpcallInfo* upcall = _upcalls[upcall_type]->at(i); 147 if (upcall->includes(method_details)) { 148 return upcall; 149 } 150 } 151 } 152 153 return nullptr; 154 } 155 156 RuntimeUpcallInfo* RuntimeUpcalls::get_first_upcall(RuntimeUpcallType upcall_type, MethodDetails& method_details) { 157 return get_next_upcall(upcall_type, method_details, nullptr); 158 } 159 160 bool RuntimeUpcalls::does_upcall_need_method_parameter(address upcall_address) 161 { 162 // Redirect needs the method parameter for filtering. 163 if((upcall_address == CAST_FROM_FN_PTR(address, RuntimeUpcalls::on_method_entry_upcall_redirect)) || 164 (upcall_address == CAST_FROM_FN_PTR(address, RuntimeUpcalls::on_method_exit_upcall_redirect))) { 165 return true; 166 } 167 168 return false; 169 } 170 171 address RuntimeUpcalls::on_method_entry_upcall_address() 172 { 173 // Optimized case when there's only one upcall (no need to redirect). 174 if(_upcalls[onMethodEntry] != nullptr && _upcalls[onMethodEntry]->length() == 1) { 175 return _upcalls[onMethodEntry]->at(0)->upcall_address(); 176 } 177 178 return CAST_FROM_FN_PTR(address, RuntimeUpcalls::on_method_entry_upcall_redirect); 179 } 180 181 address RuntimeUpcalls::on_method_exit_upcall_address() 182 { 183 // Optimized case when there's only one upcall (no need to redirect). 184 if(_upcalls[onMethodExit] != nullptr && _upcalls[onMethodExit]->length() == 1) { 185 return _upcalls[onMethodExit]->at(0)->upcall_address(); 186 } 187 188 return CAST_FROM_FN_PTR(address, RuntimeUpcalls::on_method_exit_upcall_redirect); 189 } 190 191 const char* RuntimeUpcalls::get_name_for_upcall_address(address upcall_address) 192 { 193 for(int i = 0; i < RuntimeUpcallType::numTypes; i++) { 194 if (_upcalls[i] != nullptr) { 195 for (int j = 0; j < _upcalls[i]->length(); j++) { 196 RuntimeUpcallInfo* upcall = _upcalls[i]->at(j); 197 if (upcall->upcall_address() == upcall_address) { 198 return upcall->upcall_name(); 199 } 200 } 201 } 202 } 203 return nullptr; 204 }